📄 ne2000end.c
字号:
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); }/********************************************************************************* ne2000MemInit - initialize memory for the chip** This routine is highly specific to the device. ** RETURNS: OK or ERROR.*/LOCAL STATUS ne2000MemInit ( NE2000END_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 = 32; clDesc.clSize = NE2000_BUFSIZ; /* allow for alignment */ clDesc.memSize = ((clDesc.clNum * (clDesc.clSize + 8)) + 4); eneMclBlkConfig.mBlkNum = 16 * 4; 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, NE2000_BUFSIZ, FALSE); return (OK); }/********************************************************************************* ne2000Ioctl - the driver I/O control routine** Process an ioctl request.*/LOCAL int ne2000Ioctl ( void* pCookie, /* device ptr */ int cmd, caddr_t data ) { int error = 0; long value; NE2000END_DEVICE* pDrvCtrl = (NE2000END_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 - 1); END_FLAGS_CLR (&pDrvCtrl->endObj, value); } else END_FLAGS_SET (&pDrvCtrl->endObj, value); ne2000Config (pDrvCtrl, TRUE); break; case EIOCGFLAGS: *(int *)data = END_FLAGS_GET(&pDrvCtrl->endObj); break; case EIOCPOLLSTART: ne2000PollStart (pDrvCtrl); break; case EIOCPOLLSTOP: ne2000PollStop (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); }/********************************************************************************* ne2000Start - 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 ne2000Start ( void* pCookie ) { STATUS result; NE2000END_DEVICE* pDrvCtrl = (NE2000END_DEVICE *) pCookie; ENDLOGMSG (("ne2000Start\n", 0, 0, 0, 0, 0, 0)); SYS_INT_CONNECT (pDrvCtrl, ne2000Int, (int)pDrvCtrl, &result); if (result == ERROR) return (ERROR); /* Enable interrupts */ pDrvCtrl->imask = (pDrvCtrl->flags & END_POLLING) ? 0 : NE2000_ALL_INTS; SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask); SYS_INT_ENABLE (pDrvCtrl); return (OK); }/******************************************************************************** ne2000Config - reconfigure the interface under us.** Reconfigure the interface setting promiscuous mode, and changing the* multicast interface list.** NOMANUAL*/LOCAL void ne2000Config ( NE2000END_DEVICE *pDrvCtrl, BOOL intEnable /* TRUE to enable interrupts */ ) { UCHAR rxFilter; /* receiver configuration */ ENDLOGMSG (("ne2000Config: 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) ne2000AddrFilterSet (pDrvCtrl); /* TODO - shutdown device completely */ /* TODO - reset all device counters/pointers, etc. */ /* preserve END_POLLING and OVERWRITE flags */ pDrvCtrl->flags &= (END_POLLING | END_OVERWRITE | END_OVERWRITE2); /* TODO - initialize the hardware according to flags */ /* 1. program Command Register for page 0 and for no DMA */ SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_NODMA | CMD_PAGE0 | CMD_STOP); /* 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_BSIZE1 | 0x08); else SYS_OUT_CHAR (pDrvCtrl, ENE_DCON, DCON_BSIZE1 | DCON_BUS16 | 0x08); 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_BROAD; /* Set multicast mode if it's asked for. */ if (END_MULTI_LST_CNT(&pDrvCtrl->endObj) > 0) rxFilter |= RCON_GROUP; /* Set promiscuous mode if it's asked for. */ if (END_FLAGS_GET(&pDrvCtrl->endObj) & IFF_PROMISC) rxFilter |= RCON_PROM; ENDLOGMSG (("\tPromiscuous mode %s\n", (rxFilter & RCON_PROM) ? "on" : "off", 0, 0, 0, 0, 0)); SYS_OUT_CHAR (pDrvCtrl, ENE_RCON, rxFilter); /* 5. place the ENE in LOOPBACK mode 1 or 2 */ SYS_OUT_CHAR (pDrvCtrl, ENE_TCON, TCON_LB1); /* 6. initialize Receive Buffer Ring */ SYS_OUT_CHAR (pDrvCtrl, ENE_RSTART, NE2000_PSTART); SYS_OUT_CHAR (pDrvCtrl, ENE_RSTOP, NE2000_PSTOP); SYS_OUT_CHAR (pDrvCtrl, ENE_BOUND, NE2000_PSTART); /* 7. clear Interrupt Status Register */ SYS_OUT_CHAR (pDrvCtrl, ENE_INTSTAT, (char)0xff); /* 8. initialize Interrupt Mask Register */ pDrvCtrl->imask = 0; SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask); /* 9. program Command Register for page 1 */ SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_PAGE1 | CMD_STOP); /* i) initialize physical address registers */ SYS_OUT_CHAR (pDrvCtrl, ENE_STA0, pDrvCtrl->enetAddr[0]); SYS_OUT_CHAR (pDrvCtrl, ENE_STA1, pDrvCtrl->enetAddr[1]); SYS_OUT_CHAR (pDrvCtrl, ENE_STA2, pDrvCtrl->enetAddr[2]); SYS_OUT_CHAR (pDrvCtrl, ENE_STA3, pDrvCtrl->enetAddr[3]); SYS_OUT_CHAR (pDrvCtrl, ENE_STA4, pDrvCtrl->enetAddr[4]); SYS_OUT_CHAR (pDrvCtrl, ENE_STA5, pDrvCtrl->enetAddr[5]); ENDLOGMSG (("enet addr %02x:%02x:%02x:%02x:%02x:%02x\n", pDrvCtrl->enetAddr[0] & 0xff, pDrvCtrl->enetAddr[1] & 0xff, pDrvCtrl->enetAddr[2] & 0xff, pDrvCtrl->enetAddr[3] & 0xff, pDrvCtrl->enetAddr[4] & 0xff, pDrvCtrl->enetAddr[5] & 0xff)); /* ii) initialize multicast address registers */ ne2000AddrFilterSet (pDrvCtrl); SYS_OUT_CHAR (pDrvCtrl, ENE_MAR0, pDrvCtrl->mcastFilter[0]); SYS_OUT_CHAR (pDrvCtrl, ENE_MAR1, pDrvCtrl->mcastFilter[1]); SYS_OUT_CHAR (pDrvCtrl, ENE_MAR2, pDrvCtrl->mcastFilter[2]); SYS_OUT_CHAR (pDrvCtrl, ENE_MAR3, pDrvCtrl->mcastFilter[3]); SYS_OUT_CHAR (pDrvCtrl, ENE_MAR4, pDrvCtrl->mcastFilter[4]); SYS_OUT_CHAR (pDrvCtrl, ENE_MAR5, pDrvCtrl->mcastFilter[5]); SYS_OUT_CHAR (pDrvCtrl, ENE_MAR6, pDrvCtrl->mcastFilter[6]); SYS_OUT_CHAR (pDrvCtrl, ENE_MAR7, pDrvCtrl->mcastFilter[7]);#ifdef DEBUG { static char buf[256]; sprintf(buf, "enet mcast %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", pDrvCtrl->mcastFilter[0] & 0xff, pDrvCtrl->mcastFilter[1] & 0xff, pDrvCtrl->mcastFilter[2] & 0xff, pDrvCtrl->mcastFilter[3] & 0xff, pDrvCtrl->mcastFilter[4] & 0xff, pDrvCtrl->mcastFilter[5] & 0xff, pDrvCtrl->mcastFilter[6] & 0xff, pDrvCtrl->mcastFilter[7] & 0xff); ENDLOGMSG ((buf)); }#endif /* iii) initialize current page pointer */ SYS_OUT_CHAR (pDrvCtrl, ENE_CURR, NE2000_PSTART + 1); pDrvCtrl->nextPacket = NE2000_PSTART + 1; /* set memory parameters */ SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_NODMA | CMD_PAGE2 | CMD_STOP); SYS_OUT_CHAR (pDrvCtrl, ENE_ENH, 0x00); /* 0 wait states */ SYS_OUT_CHAR (pDrvCtrl, ENE_BLOCK, 0x00); /* 0x00xxxx */ /* 10. put the ENE in START mode */ SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_NODMA | CMD_PAGE0 | CMD_START); /* 11. initialize Transmit Configuration Register */ SYS_OUT_CHAR (pDrvCtrl, ENE_TCON, 0x00); ENDLOGMSG (("ne2000Config: done\n", 0, 0, 0, 0, 0, 0)); pDrvCtrl->imask = ((pDrvCtrl->flags & END_POLLING) ? 0 : NE2000_ALL_INTS); /* Only actually enable interrupts if not polling */ if (intEnable) SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask); }/********************************************************************************* ne2000OverwriteRecover - recover from receive buffer ring overflow** This procedure is mandated by National Semiconductor as the only safe* way to recover from an Overwrite Warning Error. The first two steps* of their procedure, reading the Command Register and stopping the NIC,* were accomplished in the interrupt handler. The rest occurs here.** This routine is scheduled to run in the net task since it must delay* to allow the STOP command to take effect.*/LOCAL void ne2000OverwriteRecover ( NE2000END_DEVICE *pDrvCtrl, UCHAR cmdStatus ) { UCHAR stat; BOOL reSend; ENDLOGMSG (("ne2000OverwriteRecover: enter (flags=%x, imask=%x)\n", pDrvCtrl->flags,pDrvCtrl->imask,0,0,0,0)); /* We shouldn't get here without the OVERWRITE flags set */ if (!(pDrvCtrl->flags & END_OVERWRITE2)) { ENDLOGMSG (("ne2000OverwriteRecover: bad flags\n", 0,0,0,0,0,0));#ifdef DEBUG SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, 0); taskSuspend (0);#else return;#endif } /* 1. read the TXP bit in the command register (already in cmdStatus) */ /* 2. issue the STOP command (done in the interrupt handler) */ /* 3. delay at least 1.6 milliseconds (1/625 second) */ taskDelay ((sysClkRateGet() + 624)/ 625); /* we are now supposedly sure the NIC is stopped */ /* 4. clear Remote Byte Count Register */ SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR0, 0x00); SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR1, 0x00); /* 5. read the stored value of the TXP bit (in cmdStatus) */ if ((cmdStatus & CMD_TXP) == 0) reSend = FALSE; else { SYS_IN_CHAR (pDrvCtrl, ENE_INTSTAT, &stat); if ((stat & (ISTAT_PTX | ISTAT_TXE)) == 0) { /* transmit was in progress but probably deferring */ reSend = TRUE; } else { /* transmit was completed (probably), don't repeat it */ reSend = FALSE; } } /* 6. place the NIC in loopback mode */ SYS_OUT_CHAR (pDrvCtrl, ENE_TCON, TCON_LB1); /* 7. issue the START command to the NIC */ SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_NODMA | CMD_PAGE0 | CMD_START); /* 8. remove one or more packets from the receive buffer ring */ /* clear overwrite flag */ pDrvCtrl->flags &= ~END_OVERWRITE; pDrvCtrl->current = ne2000GetCurr (pDrvCtrl); ne2000HandleRcvInt (pDrvCtrl); /* 9. reset the overwrite warning bit in the ISR */ /* reset all active interrupt conditions */ SYS_IN_CHAR (pDrvCtrl, ENE_INTSTAT, &stat); SYS_OUT_CHAR (pDrvCtrl, ENE_INTSTAT, stat); /* 10. take the NIC out of loopback */ SYS_OUT_CHAR (pDrvCtrl, ENE_TCON, 0x00); /* 10a. re-enable all device interrupts */ pDrvCtrl->imask = NE2000_ALL_INTS; SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask); /* 11. if need to resend, do so, otherwise if anything queued, send that */ pDrvCtrl->flags &= ~END_OVERWRITE2; if (reSend) SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_TXP); else muxTxRestart (&pDrvCtrl->endObj); ENDLOGMSG (("ne2000OverwriteRecover: done (flags=%x, imask=%x)\n", pDrvCtrl->flags,pDrvCtrl->imask,0,0,0,0)); }/********************************************************************************* ne2000Int - handle controller interrupt** This routine is called at interrupt level in response to an interrupt from* the controller.** RETURNS: N/A.*/LOCAL void ne2000Int ( NE2000END_DEVICE *pDrvCtrl ) { UCHAR val; UCHAR intStat; UCHAR txStat; UCHAR rxStat; pDrvCtrl->stats.interrupts++; /* Read status and Acknowlegde interrupt */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -