/* sysNet.c.c - Kontron KTGM45 platform system-dependent library */

/* Copyright 2010 Kontron Modular Computers GmbH */

/* Copyright 2001-2006 Wind River Systems, Inc. */

/*
modification history
--------------------
02d,06aug10,edv  add check if INCLUDE_IPDHCPC component is included for dhcp configuration
02c,05aug10,kpn  dhcp support added to sysEthInit
02a,14jun10,frb  ajusted to Kontron KTQ45
01e,17jan07,wap  Remove old NE2000 END driver
01d,04sep06,tor  Make VxBus the default, remove non-VxBus support
01c,06feb06,pmr  HEND support no longer uses this file.
01b,23apr02,pai  Made DEC and GEI END driver config names consistent with
                 other END driver config names.
01a,24oct01,pai  written.
*/

/*
DESCRIPTION
This library contains BSP-specific routines for network subsystems,
including network interface card device driver configuration and
support routines.  Generic network interface drivers are not provided
in source code form.  As a result, this module does not #include the
actual device drivers via the C-preprocessor.

Note that the routines implemented in this file will not necessarily
be included in future versions of Wind River Systems' Intel Architecture
BSPs.

SEE ALSO:
.pG "Configuration"
*/

#include "versionK.h"

KONTRON_VERSION(sysNet_c,02d)			/* version identifier */

/* includes */

#ifdef  INCLUDE_END
#ifdef INCLUDE_ENE_END
#   include "sysNe2000End.c"            /* ne2000End support routines   */
#endif
#endif  /* INCLUDE_END */


#if defined(INCLUDE_PCI_BUS)            /* PCI Ethernet Device Support Code */


/* typedefs */

typedef STATUS (* INIT_FUNCPTR) (UINT32, UINT32, UINT32, UINT32, UINT32, UINT8);

typedef struct vendIdDesc               /* VEND_ID_DESC */
    {
    UINT32              vendorId;       /* PCI Vendor ID */
    INIT_FUNCPTR        pPciInitRtn;    /* associated pciInit() routine */

    } VEND_ID_DESC;


/* locals */

/* This table maps END PCI driver initialization routines to
 * the PCI Vendor IDs for supported (tested) device types.
 */

LOCAL VEND_ID_DESC vendorIdEnet [] =
    {
    #if defined(INCLUDE_DEC21X40_END)
    {DEC_PCI_VENDOR_ID,      sysDec21x40PciInit},
    #endif /* INCLUDE_DEC21X40_END */

    {0xffffffff, NULL}        /* last entry */
    };



/*******************************************************************************
*
* sysNetPciInit - initialize PCI network devices
*
* This routine invokes the driver or BSP-specific PCI initialization routine
* for a Network Class, Ethernet Subclass, device specified by the <pciBus>,
* <pciDevice>, and <pciFunc> parameters.
*
* The interface is constructed such that this function can be invoked
* via pciConfigForeachFunc().  Internally, this routine tests the 24-bit
* PCI class code value (class/subclass/prog_if) to ensure that the
* specified function is an ethernet controller.
*
* INTERNAL
* This callback will terminate pciConfigForeachFunc() if it returns ERROR.
* So, this routine returns OK always such that a failure to config one
* ethernet device will not prevent attempts to initialize other ethernet
* devices.
*
* RETURNS: OK always.
*
* NOMANUAL
*/
STATUS sysNetPciInit
    (
    UINT32              pciBus,        /* store a PCI bus number */
    UINT32              pciDevice,     /* store a PCI device number */
    UINT32              pciFunc,       /* store a PCI function number */
    void *              pArg           /* reserved argument */
    )
    {
    UINT32              classCodeReg;  /* store a 24-bit PCI class code */


    pciConfigInLong (pciBus, pciDevice, pciFunc, PCI_CFG_REVISION,
                     &classCodeReg);

    if (((classCodeReg >> 8) & 0x00ffffff) == PCI_NET_ETHERNET_CLASS)
        {
        UINT32        vendorId;    /* store a PCI vendor ID */
        UINT32        deviceId;    /* store a PCI device ID */
        UINT8         revisionId;  /* store a PCI revision ID */
        int           i;           /* index Vendor ID --> pciInit() table */


        /* get the PCI Vendor and Device IDs */

        pciConfigInLong (pciBus, pciDevice, pciFunc,
                         PCI_CFG_VENDOR_ID, &vendorId);

        /* get the PCI Revision ID */

        pciConfigInByte (pciBus, pciDevice, pciFunc,
                         PCI_CFG_REVISION, &revisionId);

        /* test for driver support of the specified Ethernet function */

        deviceId = ((vendorId >> 16) & 0x0000ffff);
        vendorId = (vendorId & 0x0000ffff);

        /* find & exec. a PCI initialization routine for the device */

        for (i = 0; (vendorIdEnet[i].pPciInitRtn) != NULL; ++i)
            {
            if ((vendorId == vendorIdEnet[i].vendorId) &&
                (*(vendorIdEnet[i].pPciInitRtn))
                (pciBus, pciDevice, pciFunc,
                 vendorId, deviceId, revisionId) == OK)
                {
                /* initialized the device - move on */

                return OK;
                }
            }
        }

    return (OK);
    }

#endif /* INCLUDE_PCI_BUS */


#if (defined(INCLUDE_DEC21X40_END) || defined(INCLUDE_ENE_END))

/*******************************************************************************
*
* sysLanIntEnable - enable 21x4x or Ne2000 ethernet device interrupts
*
* This routine enables DEC 21x4x or Ne2000 interrupts.  This may involve
* operations on interrupt control hardware.
*
* NOTE
* This is a legacy END driver support routine.  Early END driver
* implementations tended to use identical names for external support
* routines defined in the BSP.  As a result, a BSP configuration that
* selects such drivers for a build will fail with multiple definitions
* if the routine is defined separately for each driver.  Such namespace
* collisions will be resolved in future versions of the Wind River END
* drivers.
*
* RETURNS: Ok or ERROR for invalid arguments.
*/
STATUS sysLanIntEnable
    (
    int level        /* interrupt level to enable */
    )
    {
    return (sysIntEnablePIC (level));
    }

/*******************************************************************************
*
* sysLanIntDisable - disable 21x4x or Ne2000 ethernet device interrupts
*
* This routine disables DEC 21x4x or Ne2000 interrupts.  This may involve
* operations on interrupt control hardware.
*
* NOTE
* This is a legacy END driver support routine.  Early END driver
* implementations tended to use identical names for external support
* routines defined in the BSP.  As a result, a BSP configuration that
* selects such drivers for a build will fail with multiple definitions
* if the routine is defined separately for each driver.  Such namespace
* collisions will be resolved in future versions of the Wind River END
* drivers.
*
* RETURNS: OK or ERROR for invalid arguments.
*/
STATUS sysLanIntDisable
    (
    int level        /* interrupt level to disable */
    )
    {
    return (sysIntDisablePIC (level));
    }

#endif /* INCLUDE_DEC21X40_END || INCLUDE_ENE_END */

/***** dea: from Kontron *********/
#ifdef PRJ_BUILD

#include <bootLib.h>
#include <ipProto.h>
#include <stdio.h>
#include <ipcom_err.h>

#include "versionK.h"

KONTRON_VERSION(sysNet_c,01q)			/* version identifier */

/* imports */

IMPORT int ipcom_run_cmd (char *cmd_str);

/*******************************************************************************
*
* isBootLine - check if the interface is specified in the boot parameters
*
* This function checks if the passed interface is specified, either as boot
* device or in the other field of the boot parameters.
*
* RETURNS: TRUE, or FALSE if the interface is not part of the boot parameters
*
*/

LOCAL STATUS isBootLine
(
	char* name
)
{
	BOOT_PARAMS bootParams;
	char bootDevName [BOOT_DEV_LEN];
	char otherField  [BOOT_OTHER_LEN];

	/* get the boot parameters */
	bootStringToStruct(sysBootLine, &bootParams);

	/* get the boot device name */
	sprintf(bootDevName, "%s%d", bootParams.bootDev, bootParams.unitNum);

	/* interface name specified as boot device ? */
	if (strcmp(bootDevName, name) == 0)
		return TRUE;

	/* get content of the other field */
	sprintf(otherField, "%s", bootParams.other);

	/* interface name specified in the other field ? */
	if (strcmp(otherField, name) == 0)
		return TRUE;

	return FALSE;
}

/*******************************************************************************
*
* sysEthInit - attach the TCP/IP protocol to an END device
*
* This routine attaches the TCP/IP protocol to the passed END device.
* Furthermore it sets the network mask and internet address of the interface to
* the passed values.
*
* RETURNS: OK or ERROR
*
*/

STATUS sysEthInit
(
	char* pDevice,		/* device name */
	int   unit,			/* unit number of device */
	char* pIfAddress,	/* internet address to assign to interface */
	UINT   netMask		/* subnet mask for the interface (e.g. 0xffffff00) */
)
{
	char ifName [BOOT_DEV_LEN];
	char command [256];
	int netMaskBits = 32;
	int retval;

	/* check length of device name */
	if (strlen (pDevice) > BOOT_DEV_LEN)
	{
		printErr (
		"sysEthInit: device name '%s' too long\n", pDevice);
		return (ERROR);
	}

	/* build interface name */
 	sprintf (ifName, "%s%d", pDevice, unit);

    /* if the unit is the bootline, then no overwriting of the bootline settings */
	if ((isBootLine(ifName)) == TRUE)
	{
       return (OK);
	}

	if (ipAttach (unit, pDevice) == ERROR)
	{
		printErr (
		"sysEthInit: can't attach TCP/IP interface %s unit %d\n", pDevice, unit);
		return (ERROR);
	}

	while (((netMask & 0x00000001) != 1) && (netMaskBits != 0))
	{
		netMask = netMask >> 1;
		netMaskBits = netMaskBits - 1;
	}

	/* build command */
	if (!strcmp (pIfAddress, "dhcp")) {
#ifdef INCLUDE_IPDHCPC	
		sprintf (command, "ifconfig -silent %s inet dhcp", ifName);
#else
		printErr (
		"sysEthInit: interface %s unit %d: no DHCP client is not configured, (no component INCLUDE_IPDHCPC)\n",
		    pDevice, unit);
#endif
	} else {
		sprintf (command, "ifconfig -silent %s inet %s/%d", ifName, pIfAddress,
			netMaskBits);
	}

	retval = ipcom_run_cmd (command);
	if (retval != IPCOM_SUCCESS)
	{
		printErr (
		"sysEthInit: can't set network address on interface %s\n", ifName);
		return (ERROR);
	}

	/* build command */
	sprintf (command, "ifconfig -silent %s up", ifName);

	retval = ipcom_run_cmd (command);
	if (retval != IPCOM_SUCCESS)
	{
		printErr (
		"sysEthInit: can't get up network interface %s\n", ifName);
		return (ERROR);
	}

	return (OK);
}
#endif
