📄 ax88796end.c
字号:
* ax88796EndLoad - initialize the driver and device
*
* This routine initializes the driver and the device to the operational state.
* All of the device specific parameters are passed in the initString.
*
* The string contains the target specific parameters like this:
*
* "unit:register addr:int vector:int level:shmem addr:shmem size:shmem width"
*
* RETURNS: An END object pointer or NULL on error.
*/
END_OBJ* ax88796EndLoad
(
char* initString, /* String to be parsed by the driver. */
void* pBSP /* for BSP group */
)
{
AX88796END_DEVICE *pDrvCtrl;
#ifdef DEBUG
printf ("ax88796EndLoad(%s)\n", initString);
printf ("\tinitString '%s'\n", initString ? initString : "");
printf ("\tpBSP '%s'\n", pBSP ? pBSP : "");
#endif
if (initString == NULL)
return (NULL);
if (initString[0] == '\0')
{
bcopy((char *)AX88796_DEV_NAME, initString, AX88796_DEV_NAME_LEN);
return (NULL);
}
/* allocate the device structure */
pDrvCtrl = (AX88796END_DEVICE *) calloc (sizeof(AX88796END_DEVICE), 1);
if (pDrvCtrl == NULL)
goto errorExit;
/* parse the init string, filling in the device structure */
if (ax88796Parse (pDrvCtrl, initString) == ERROR)
goto errorExit;
/* stop device */
SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_NODMA | CMD_PAGE0 | CMD_STOP);
/* select 8 bit width */
SYS_OUT_CHAR (pDrvCtrl, ENE_DCON, DCON_BUS_8);
/* Ask the BSP to provide the ethernet address. */
SYS_ENET_ADDR_GET (pDrvCtrl);
/* initialize the END parts of the structure */
if (END_OBJ_INIT (&pDrvCtrl->endObj, (DEV_OBJ *)pDrvCtrl, AX88796_DEV_NAME,
pDrvCtrl->unit, &ax88796FuncTable,
"ax88796 Enhanced Network Driver") == ERROR)
goto errorExit;
/* initialize the MIB2 parts of the structure */
if (END_MIB_INIT (&pDrvCtrl->endObj, M2_ifType_ethernet_csmacd,
&pDrvCtrl->enetAddr[0], 6, ETHERMTU,
END_SPEED) == ERROR)
goto errorExit;
/* Perform memory allocation/distribution */
if (ax88796MemInit (pDrvCtrl) == ERROR)
goto errorExit;
/* set the flags to indicate readiness */
END_OBJ_READY (&pDrvCtrl->endObj,
IFF_NOTRAILERS | IFF_MULTICAST | IFF_BROADCAST);
return (&pDrvCtrl->endObj);
errorExit:
if (pDrvCtrl != NULL)
free ((char *)pDrvCtrl);
return (NULL);
}
/******************************************************************************
*
* ax88796Parse - parse the init string
*
* Parse the input string. Fill in values in the driver control structure.
*
* The initialization string format is:
* .CS
* "unit:adrs:vecnum:intLvl:byteAccess:usePromEnetAddr:offset"
* .CE
*
* .IP <unit>
* Device unit number, a small integer.
* .IP <adrs>
* Base address
* .IP <vecNum>
* Interrupt vector number (used with sysIntConnect)
* .IP <intLvl>
* Interrupt level (used with sysLanIntEnable)
* .IP <byteAccess>
* Use 8-bit access mode.
* .IP <usePromEnetAddr>
* get ethernet address from PROM.
* .IP <offset>
* offset for memory alignment
* Set Configuration Register A. Defaults to reset value.
* .IP <configRegA>
* Set Configuration Register B. Defaults to reset value.
* .IP <configRegB>
* .LP
*
* RETURNS: OK or ERROR for invalid arguments.
*/
LOCAL STATUS ax88796Parse
(
AX88796END_DEVICE * pDrvCtrl,
char * initString
)
{
char* tok;
char* holder = NULL;
/* Parse the initString */
/* Unit number. */
tok = strtok_r (initString, ":", &holder);
if (tok == NULL)
return (ERROR);
pDrvCtrl->unit = atoi (tok);
/* Base address. */
tok = strtok_r (NULL, ":", &holder);
if (tok == NULL)
return (ERROR);
pDrvCtrl->base = strtoul (tok, NULL, 16);
/* Interrupt vector. */
tok = strtok_r (NULL, ":", &holder);
if (tok == NULL)
return (ERROR);
pDrvCtrl->ivec = strtoul (tok, NULL, 16);
/* Interrupt level. */
tok = strtok_r (NULL, ":", &holder);
if (tok == NULL)
return (ERROR);
pDrvCtrl->ilevel = strtoul (tok, NULL, 16);
/* 8-bit access. */
tok = strtok_r (NULL, ":", &holder);
if (tok == NULL)
return (ERROR);
pDrvCtrl->byteAccess = atoi (tok);
/* ethernet address from PROM. */
tok = strtok_r (NULL, ":", &holder);
if (tok == NULL)
return (ERROR);
pDrvCtrl->usePromEnetAddr = atoi (tok);
/* memory alignment offset */
tok = strtok_r (NULL, ":", &holder);
if (tok == NULL)
return (ERROR);
pDrvCtrl->offset = strtoul (tok, NULL, 16);
return (OK);
}
/*******************************************************************************
*
* ax88796MemInit - initialize memory for the chip
*
* This routine is highly specific to the device.
*
* RETURNS: OK or ERROR.
*/
LOCAL STATUS ax88796MemInit
(
AX88796END_DEVICE * pDrvCtrl /* device to be initialized */
)
{
M_CL_CONFIG eneMclBlkConfig;
CL_DESC clDesc; /* cluster description */
bzero ((char *)&eneMclBlkConfig, sizeof(eneMclBlkConfig));
bzero ((char *)&clDesc, sizeof(clDesc));
clDesc.clNum = 64;
clDesc.clSize = AX88796_BUFSIZ; /* allow for alignment */
clDesc.memSize = ((clDesc.clNum * (clDesc.clSize + 8)) + 4);
eneMclBlkConfig.mBlkNum = 16 * 8;
eneMclBlkConfig.clBlkNum = clDesc.clNum;
/*
* mBlk and cluster configuration memory size initialization
* memory size adjusted to hold the netPool pointer at the head.
*/
eneMclBlkConfig.memSize =
(eneMclBlkConfig.mBlkNum * (MSIZE + sizeof (long)))
+ (eneMclBlkConfig.clBlkNum * (CL_BLK_SZ + sizeof (long)));
eneMclBlkConfig.memArea = (char *) memalign(sizeof (long),
eneMclBlkConfig.memSize);
if (eneMclBlkConfig.memArea == NULL)
return (ERROR);
clDesc.memArea = (char *) malloc (clDesc.memSize);
if (clDesc.memArea == NULL)
return (ERROR);
pDrvCtrl->endObj.pNetPool = (NET_POOL_ID) malloc (sizeof(NET_POOL));
if (pDrvCtrl->endObj.pNetPool == NULL)
return (ERROR);
/* Initialize the net buffer pool with transmit buffers */
if (netPoolInit (pDrvCtrl->endObj.pNetPool, &eneMclBlkConfig,
&clDesc, 1, NULL) == ERROR)
return (ERROR);
/* Save the cluster pool id */
pDrvCtrl->clPoolId = clPoolIdGet (pDrvCtrl->endObj.pNetPool,
AX88796_BUFSIZ, FALSE);
return (OK);
}
/*******************************************************************************
*
* ax88796Ioctl - the driver I/O control routine
*
* Process an ioctl request.
*/
LOCAL int ax88796Ioctl
(
void* pCookie, /* device ptr */
int cmd,
caddr_t data
)
{
int error = 0;
long value;
AX88796END_DEVICE* pDrvCtrl = (AX88796END_DEVICE *) pCookie;
switch ((UINT) cmd)
{
case EIOCSADDR:
if (data == NULL)
return (EINVAL);
bcopy ((char *)data, (char *)END_HADDR(&pDrvCtrl->endObj),
END_HADDR_LEN(&pDrvCtrl->endObj));
break;
case EIOCGADDR:
if (data == NULL)
return (EINVAL);
bcopy ((char *)END_HADDR(&pDrvCtrl->endObj), (char *)data,
END_HADDR_LEN(&pDrvCtrl->endObj));
break;
case EIOCSFLAGS:
value = (long)data;
if (value < 0)
{
value = -value;
value--;
END_FLAGS_CLR (&pDrvCtrl->endObj, value);
}
else
END_FLAGS_SET (&pDrvCtrl->endObj, value);
ax88796Config (pDrvCtrl, TRUE);
break;
case EIOCGFLAGS:
*(int *)data = END_FLAGS_GET(&pDrvCtrl->endObj);
break;
case EIOCPOLLSTART:
ax88796PollStart (pDrvCtrl);
break;
case EIOCPOLLSTOP:
ax88796PollStop (pDrvCtrl);
break;
case EIOCGMIB2:
if (data == NULL)
return (EINVAL);
bcopy((char *)&pDrvCtrl->endObj.mib2Tbl, (char *)data,
sizeof(pDrvCtrl->endObj.mib2Tbl));
break;
case EIOCGFBUF:
if (data == NULL)
return (EINVAL);
#if 0
/* XXX */
*(int *)data = END_MIN_FBUF;
#endif
break;
default:
error = EINVAL;
}
return (error);
}
/*******************************************************************************
*
* ax88796Start - start the device
*
* This function calls BSP functions to connect interrupts and start the
* device running in interrupt mode.
*
* RETURNS: OK or ERROR
*
*/
LOCAL STATUS ax88796Start
(
void* pCookie
)
{
STATUS result;
AX88796END_DEVICE* pDrvCtrl = (AX88796END_DEVICE *) pCookie;
ENDLOGMSG (("ax88796Start\n", 0, 0, 0, 0, 0, 0));
SYS_INT_CONNECT (pDrvCtrl, ax88796Int, (int)pDrvCtrl, &result);
if (result == ERROR)
return (ERROR);
/* mark the interface as up (SPR #32034) */
END_FLAGS_SET (&pDrvCtrl->endObj, (IFF_UP | IFF_RUNNING));
/* Enable interrupts */
pDrvCtrl->imask = (pDrvCtrl->flags & END_POLLING) ? 0 : AX88796_ALL_INTS;
SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask);
SYS_INT_ENABLE (pDrvCtrl);
return (OK);
}
/******************************************************************************
*
* ax88796Config - reconfigure the interface under us.
*
* Reconfigure the interface setting promiscuous mode, and changing the
* multicast interface list.
*
* NOMANUAL
*/
LOCAL void ax88796Config
(
AX88796END_DEVICE *pDrvCtrl,
BOOL intEnable /* TRUE to enable interrupts */
)
{
UCHAR rxFilter; /* receiver configuration */
UCHAR pStart;
#ifdef DEBUG
static buf [256];
#endif
ENDLOGMSG (("ax88796Config: enter (intEnable=%d)\n",
intEnable, 0, 0, 0, 0, 0));
/* Disable device interrupts */
pDrvCtrl->imask = 0;
SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask);
/* Set up address filter for multicasting. */
if (END_MULTI_LST_CNT(&pDrvCtrl->endObj) > 0)
ax88796AddrFilterSet (pDrvCtrl);
/* preserve END_POLLING and OVERWRITE flags */
pDrvCtrl->flags &= (END_POLLING | END_OVERWRITE | END_OVERWRITE2);
/* 1. program Command Register for page 0 and for no DMA */
SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_NODMA | CMD_PAGE0 | CMD_STOP);
/* delay at least 1.5 ms */
delay (3000);
/* 2. initialize Data Configuration Register:
* 16-bit bus, burst mode, 8-deep FIFO.
* or
* 8-bit bus, burst mode, 8-deep FIFO.
*/
// if (pDrvCtrl->byteAccess)
SYS_OUT_CHAR (pDrvCtrl, ENE_DCON, DCON_BUS_8);
// else
// SYS_OUT_CHAR (pDrvCtrl, ENE_DCON, DCON_BUS16);
SYS_ENET_ADDR_GET (pDrvCtrl);
/* 3. clear Remote Byte Count Register */
SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR0, 0x00);
SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR1, 0x00);
/* 4. initialize Receive Configuration Register */
/* Always accept broadcast packets. */
rxFilter = RCON_INIT | RCON_BROAD;
/* Set multicast mode if it's asked for. */
if (END_MULTI_LST_CNT(&pDrvCtrl->endObj) > 0)
{
rxFilter |= RCON_GROUP;
}
ENDLOGMSG (("\tMulticast mode %s\n",
(rxFilter & RCON_GROUP) ? "on" : "off",
0, 0, 0, 0, 0));
SYS_OUT_CHAR (pDrvCtrl, ENE_RCON, rxFilter);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -