📄 dm9kend.c
字号:
LOCAL STATUS dm9kSend ( DM9K_DRV_CTRL * pDrvCtrl, /* device to be initialized */ M_BLK_ID pMblk /* data to send */ ) { char * pBuf; UINT16 index,i; UINT16 len = 0,tmpLen; /* check device mode */ if (pDrvCtrl->flags & DM9K_POLLING) { netMblkClChainFree (pMblk); errno = EINVAL; return (ERROR); } /* * Obtain exclusive access to transmitter. This is necessary because * we might have more than one stack transmitting at once. */ END_TX_SEM_TAKE (&pDrvCtrl->endObj, WAIT_FOREVER); /* Advance our management index (first) */ index = pDrvCtrl->tmdIndex; pBuf = (char *)(pDrvCtrl->pTxMemBase); if (pBuf == NULL) { DRV_LOG (DRV_DEBUG_TX, "Error\n", (int)pBuf, index, 3, 4, 5, 6); pDrvCtrl->txBlocked = TRUE; END_TX_SEM_GIVE (&pDrvCtrl->endObj); return (END_ERR_BLOCK); } /* copy and release the packet */ len = netMblkToBufCopy (pMblk, pBuf, NULL); netMblkClChainFree (pMblk); /* flush the cache, if necessary */ CACHE_DMA_FLUSH(pBuf, len); if (len < ETHERSMALL) { /* Pad to ETHERSMALL with zeros, required by H/W */ bzero (&pBuf[len], ETHERSMALL - len); len = ETHERSMALL; } /* Disable all interrupt */ regWriteByte(DM9KS_IMR, DM9KS_DISINTR); /*----------------------------------------------*/ /* Write data into SRAM trigger */ OUT_WORD(DM9KS_ADDR_PORT, DM9KS_MWCMD);// udelay(10); tmpLen = (len + 1) / 2; for (i = 0; i < tmpLen; i++) { OUT_WORD(DM9KS_DATA_PORT, ((UINT16 *)pBuf)[i]); } /* Set TX length to reg. 0xfc & 0xfd */ regWriteByte(DM9KS_TXPLL, (len & 0xff)); regWriteByte(DM9KS_TXPLH, (len >> 8) & 0xff); /* Request for transmitting */ regWriteByte(DM9KS_TCR, 0x1); /* Cleared after TX complete*/ /* Re-enable interrupt */ regWriteByte(DM9KS_IMR, DM9KS_REGFF); /*----------------------------------------------*/ /* Advance our management index */ index = (pDrvCtrl->tmdIndex + 1) & (pDrvCtrl->tringSize - 1); pDrvCtrl->tmdIndex = index; pDrvCtrl->tmdLastIndex = (pDrvCtrl->tmdLastIndex + 1) & (pDrvCtrl->tringSize - 1); /* Bump the statistic counter. */ END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_UCAST, +1); END_TX_SEM_GIVE (&pDrvCtrl->endObj); DRV_LOG (DRV_DEBUG_TX, "dm9kSend Done\n", 1, 2, 3, 4, 5, 6); return (OK); }/********************************************************************************* dm9kIoctl - the driver I/O control routine** Process an ioctl request.** RETURNS OK or ERROR value*/LOCAL int dm9kIoctl ( DM9K_DRV_CTRL * pDrvCtrl, /* device to be initialized */ int cmd, /* ioctl command to execute */ caddr_t data /* data to get or set */ ) { long value; int error = 0; switch (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--; /* HELP: WHY ??? */ END_FLAGS_CLR (&pDrvCtrl->endObj, value); } else { END_FLAGS_SET (&pDrvCtrl->endObj, value); } dm9kConfig (pDrvCtrl); break; case EIOCGFLAGS: *(int *)data = END_FLAGS_GET (&pDrvCtrl->endObj); break; case EIOCMULTIADD: error = dm9kMCastAddrAdd (pDrvCtrl, (char *) data); break; case EIOCMULTIDEL: error = dm9kMCastAddrDel (pDrvCtrl, (char *) data); break; case EIOCMULTIGET: error = dm9kMCastAddrGet (pDrvCtrl, (MULTI_TABLE *) data); break; case EIOCPOLLSTART: error = dm9kPollStart (pDrvCtrl); break; case EIOCPOLLSTOP: error = dm9kPollStop (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); *(int *)data = DM9K_MIN_FBUF; break; case EIOCGMWIDTH: if (data == NULL) return (EINVAL); *(int *)data = 4; break; case EIOCGHDRLEN: if (data == NULL) return (EINVAL); *(int *)data = 14; break; default: error = EINVAL; } return (error); }/********************************************************************************* dm9kReset - hardware reset of chip (stop it)** This routine is responsible for resetting the device and switching into* 32 bit mode.** RETURNS: OK/ERROR*/LOCAL int dm9kReset ( DM9K_DRV_CTRL * pDrvCtrl /* device to be initialized */ ) { DRV_LOG (DRV_DEBUG_LOAD, "dm9kReset\n", 1, 2, 3, 4, 5, 6); /* setup Rx memory pointers */ pDrvCtrl->rmdIndex = 0; /* setup Tx memory pointers */ pDrvCtrl->tmdIndex = 0; pDrvCtrl->tmdLastIndex = 0; /* SYS_WB_FLUSH();*/ return (OK); }/********************************************************************************* dm9kRestartSetup - setup memory descriptors and turn on chip** This routine initializes all the shared memory structures and turns on* the chip.** RETURNS OK/ERROR*/LOCAL STATUS dm9kRestartSetup ( DM9K_DRV_CTRL * pDrvCtrl /* device to be initialized */ ) { DRV_LOG (DRV_DEBUG_LOAD, "dm9kRestartSetup\n", 1, 2, 3, 4, 5, 6); /* reset the device */ dm9kReset (pDrvCtrl); DRV_LOG (DRV_DEBUG_LOAD, "Memory setup complete\n", 1, 2, 3, 4, 5, 6); /* reconfigure the device */ dm9kConfig (pDrvCtrl); return (OK); }/********************************************************************************* dm9kRestart - restart the device after a fatal error** This routine takes care of all the messy details of a restart. The device* is reset and re-initialized. The driver state is re-synchronized.** RETURNS: N/A*/LOCAL void dm9kRestart ( DM9K_DRV_CTRL * pDrvCtrl /* device to be initialized */ ) { dm9kRestartSetup (pDrvCtrl); /* set the flags to indicate readiness */ END_OBJ_READY (&pDrvCtrl->endObj, IFF_UP | IFF_RUNNING | IFF_NOTRAILERS | IFF_BROADCAST | IFF_MULTICAST); return; }/*----------------------------------------** Set PHY operationg mode*/ static void dm9k_set_PHY_mode(DM9K_DRV_CTRL * pDrvCtrl) { /* Auto-negotiation & Restart Auto-negotiation */ UINT16 phy_reg0 = 0x1200; /* Default flow control disable*/ UINT16 phy_reg4 = 0x01e1; if ( !(pDrvCtrl->op_mode & DM9KS_AUTO) ) // op_mode didn't auto sense */ { switch(pDrvCtrl->op_mode) { case DM9KS_10MHD: phy_reg4 = 0x21; phy_reg0 = 0x1000; break; case DM9KS_10MFD: phy_reg4 = 0x41; phy_reg0 = 0x1100; break; case DM9KS_100MHD: phy_reg4 = 0x81; phy_reg0 = 0x3000; break; case DM9KS_100MFD: phy_reg4 = 0x101; phy_reg0 = 0x3100; break; default: break; } // end of switch } // end of if phy_write(0, phy_reg0); phy_write(4, phy_reg4); }/******************************************************************************** dm9kConfig - reconfigure the interface under us.** Reconfigure the interface setting promiscuous mode, and changing the* multicast interface list.** RETURNS: N/A*/LOCAL void dm9kConfig ( DM9K_DRV_CTRL * pDrvCtrl /* device to be initialized */ ) { UINT8 i; DRV_LOG (DRV_DEBUG_LOAD, "dm9kConfig\n", 1, 2, 3, 4, 5, 6); /* Set promiscuous mode if it's asked for. */ if (END_FLAGS_GET (&pDrvCtrl->endObj) & IFF_PROMISC) { DRV_LOG (DRV_DEBUG_LOAD, "Setting promiscuous mode on!\n", 1, 2, 3, 4, 5, 6); /* chip will be in promiscuous mode */ pDrvCtrl->flags |= DM9K_PROMISCUOUS_FLAG; } else { DRV_LOG (DRV_DEBUG_LOAD, "Setting promiscuous mode off!\n", 1, 2, 3, 4, 5, 6); pDrvCtrl->flags &= ~DM9K_PROMISCUOUS_FLAG; } /* Set up address filter for multicasting. */ if (END_MULTI_LST_CNT (&pDrvCtrl->endObj) > 0) { dm9kAddrFilterSet (pDrvCtrl); } /* Enable transmit and receive */ regWriteByte(DM9KS_GPCR, 1); /* set the internal PHY power-on, GPIOs normal, and wait 2ms */ regWriteByte(DM9KS_GPR, 1); /* Power-Down PHY */ udelay(50); regWriteByte(DM9KS_GPR, 0); /* GPR (reg_1Fh)bit GPIO0=0 pre-activate PHY */ udelay(50); /* wait 2ms for PHY power-on ready */ /* do a software reset and wait 20us */ regWriteByte(DM9KS_NCR, 3); udelay(50); /* wait 20us at least for software reset ok */ regWriteByte(DM9KS_NCR, 3); /* NCR (reg_00h) bit[0] RST=1 & Loopback=1, reset on */ udelay(50); /* wait 20us at least for software reset ok */ /* I/O mode */ pDrvCtrl->io_mode = regReadByte(DM9KS_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */ /* Set PHY */ pDrvCtrl->op_mode = media_mode; dm9k_set_PHY_mode(pDrvCtrl); /* set MAC address in PAR register */ /* added by HL */ for (i=0;i<6;i++) { regWriteByte(DM9KS_PAR0+i,pDrvCtrl->enetAddr[i]); } /* Program operating register */ regWriteByte(DM9KS_OTCR, 0x80); regWriteByte(DM9KS_NCR, 0); regWriteByte(DM9KS_TCR, 0x0); /* !!!disable PAD CRC appends */ regWriteByte(DM9KS_TCR2, 0x80); /* LED mode 2 */ regWriteByte(DM9KS_BPTR, 0x3f); /* Less 3kb, 600us */ regWriteByte(DM9KS_SMCR, 0); /* Special Mode disabled */ regReadByte(DM9KS_NSR); /* clear TX status */ regWriteByte(DM9KS_ISR, 0x0f); /* Clear interrupt status */ return; }/******************************************************************************** dm9kAddrFilterSet - set the address filter for multicast addresses** This routine goes through all of the multicast addresses on the list* of addresses (added with the dm9kAddrAdd() routine) and sets the* device's filter correctly.** RETURNS: N/A*/LOCAL void dm9kAddrFilterSet ( DM9K_DRV_CTRL * pDrvCtrl /* device to be initialized */ ) { ETHER_MULTI * pCurr; UINT8 * pCp; UINT8 byte; UINT32 crc; int len; int count; UINT32 hash_val; UINT16 i, oft, hash_table[4]; /* Set Node address */ for (i = 0, oft = DM9KS_PAR0; i < 6; i++, oft++) regWriteByte(oft, pDrvCtrl->enetAddr[i]); /* Clear Hash Table */ for (i = 0; i < 4; i++) hash_table[i] = 0x0; /* broadcast address */ hash_table[3] = 0x8000; pCurr = END_MULTI_LST_FIRST (&pDrvCtrl->endObj); while (pCurr != NULL) { pCp = (UINT8 *)&pCurr->addr; crc = 0xffffffff; for (len = DM9K_LA_LEN; --len >= 0;) { byte = *pCp++; for (count = 0; count < DM9K_LAF_LEN; count++) { if ((byte & 0x01) ^ (crc & 0x01)) { crc >>= 1; crc = crc ^ DM9K_CRC_POLYNOMIAL; } else { crc >>= 1; } byte >>= 1; } } hash_val = crc & 0x3f; hash_table[hash_val/16] = (UINT16) 1 << (hash_val %16); /* can be dangerous */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -