📄 if_cs.c
字号:
/* Issue the command to read the offset within the EEPROM */ csPacketPageW (pCs, CS_PKTPG_EEPROM_CMD, offset | CS_EEPROM_CMD_READ); /* Wait until the command is completed */ for (ix=0; ix<CS_MAXLOOP; ix++) if (!(csPacketPageR (pCs, CS_PKTPG_SELF_ST) & CS_SELF_ST_SI_BUSY)) break; if (ix == CS_MAXLOOP) { printf ("\ncs0 - Can not read from EEPROM\n"); return (ERROR); } /* Get the EEPROM data from the EEPROM data register */ *pValue = csPacketPageR (pCs, CS_PKTPG_EEPROM_DATA); return (OK); }/********************************************************************************* csInit - resets and then initializes the CS8900 chip** This routine is a major entry point and is called to initialize this network* interface driver. This routine may be called several times for each* operating system reboot to dynamically bring the network interface driver* to an up and running state. This routine is called by the protocol stack,* the set_if_addr() routine, and the csIoctl() routine.** RETURNS: OK or ERROR*/LOCAL STATUS csInit ( int unit ) { FAST CS_SOFTC *pCs = &cs_softc[unit]; if (unit >= MAXUNITS) return (ERROR); /* Mark the interface as down */ pCs->arpCom.ac_if.if_flags &= ~(IFF_UP | IFF_RUNNING); /* Enable debugging */ /* pCs->arpCom.ac_if.if_flags |= IFF_DEBUG; */ csError (pCs, "Initializing interface"); /* Reset the chip */ if (csChipReset (pCs) == ERROR) { csError (pCs, "Can not reset the chip"); return (ERROR); } /* Initialize the chip */ csChipInit (pCs); /* Mark the interface as up and running */ pCs->arpCom.ac_if.if_flags |= (IFF_UP | IFF_RUNNING); return (OK); }/********************************************************************************* csReset - resets the CS8900 chip.** This routine is a major entry point and is called by the protocol stack to* shut down this network interface driver. This routine may be called several* times for each operating system reboot to dynamically bring the network* interface driver to a non-running state.** RETURNS: N/A*/LOCAL void csReset ( int unit ) { FAST CS_SOFTC *pCs = &cs_softc[unit]; if (unit >= MAXUNITS) return; csError (pCs, "Resetting interface"); /* Mark the interface as down */ pCs->arpCom.ac_if.if_flags &= ~IFF_RUNNING; /* Reset the chip */ csChipReset (pCs); }/********************************************************************************* csIoctl - ioctl for interface** This routine is a major entry point and is called by the protocol stack to* modify characteristics of this network interface driver. There are many* network interface ioctl commands, but this driver only supports two of them:* Set Interface Address and Set Interface Flags.** RETURNS: OK if successful, otherwise errno.*/LOCAL int csIoctl ( struct ifnet *pIf, int command, char *pData ) { FAST CS_SOFTC *pCs = &cs_softc[pIf->if_unit]; int result = OK; /* Assume everything will go OK */ int state = splnet(); switch (command) { case SIOCSIFADDR: /* Set interface address (IP address) */ csError (pCs, "Ioctl: Set interface address"); result = set_if_addr (pIf, pData, (UCHAR *)pCs->arpCom.ac_enaddr); /* Note: set_if_addr () calls csInit() */ break; case SIOCSIFFLAGS: /* Set interface flags */ csError (pCs, "Ioctl: Set interface flags"); if (pIf->if_flags & IFF_UP) { /* Mark the interface as up and running */ pCs->arpCom.ac_if.if_flags |= (IFF_UP | IFF_RUNNING); /* Initialize the interface */ csInit (pIf->if_unit); } else /* The interface is down */ { /* Mark the interface as down */ pCs->arpCom.ac_if.if_flags &= ~(IFF_UP | IFF_RUNNING); /* Reset the chip */ csChipReset (pCs); } break; default: result = EINVAL; /* Invalid argument */ break; } splx (state); return (result); }/********************************************************************************* csChipReset - resets the CS8900 chip** This routine resets the CS8900 chip.** RETURNS: OK or ERROR*/LOCAL STATUS csChipReset ( CS_SOFTC *pCs ) { int intState; int ix; UCHAR temp; /* Disable interrupts at the CPU so reset command is atomic */ intState = intLock (); /* INT LOCK */ /* We are now resetting the chip * A spurious interrupt is generated by the chip when it is reset. * This variable informs the interrupt handler to ignore this interrupt. */ pCs->resetting = TRUE; /* Issue a reset command to the chip */ csPacketPageW (pCs, CS_PKTPG_SELF_CTL, CS_SELF_CTL_RESET); /* Re-enable interrupts at the CPU */ intUnlock (intState); /* INT UNLOCK */ /* The chip is always in IO mode after a reset */ pCs->inMemoryMode = FALSE; /* If transmission was in progress, it is not now */ pCs->txInProgress = FALSE; /* Delay for 125 micro-seconds (one eighth of a second) */ CS_MSEC_DELAY(125); /* Transition SBHE to switch chip from 8-bit to 16-bit */ CS_IN_BYTE (pCs->ioAddr + CS_PORT_PKTPG_PTR, &temp); CS_IN_BYTE (pCs->ioAddr + CS_PORT_PKTPG_PTR + 1, &temp); CS_IN_BYTE (pCs->ioAddr + CS_PORT_PKTPG_PTR, &temp); CS_IN_BYTE (pCs->ioAddr + CS_PORT_PKTPG_PTR + 1, &temp); /* Wait until the EEPROM is not busy */ for (ix=0; ix<CS_MAXLOOP; ix++) if (!(csPacketPageR (pCs, CS_PKTPG_SELF_ST) & CS_SELF_ST_SI_BUSY)) break; if (ix == CS_MAXLOOP) return (ERROR); /* Wait until initialization is done */ for (ix=0; ix<CS_MAXLOOP; ix++) if (csPacketPageR (pCs, CS_PKTPG_SELF_ST) & CS_SELF_ST_INIT_DONE) break; if (ix == CS_MAXLOOP) return (ERROR); /* Reset is no longer in progress */ pCs->resetting = FALSE; return (OK); }/********************************************************************************* csChipInit - initializes the CS8900 chip** This routine uses the instance global variables in the cs_softc structure to* initialize the CS8900 chip.** RETURNS: N/A*/LOCAL void csChipInit ( CS_SOFTC *pCs ) { USHORT busCtl; USHORT selfCtl; CS_IA *pIA; /* If memory mode is enabled */ if (pCs->configFlags & CS_CFGFLG_MEM_MODE) { /* If external logic is present for address decoding */ if (csPacketPageR (pCs, CS_PKTPG_SELF_ST) & CS_SELF_ST_EL_PRES) { /* Program the external logic to decode address bits SA20-SA23 */ csPacketPageW (pCs, CS_PKTPG_EEPROM_CMD, ((UINT)(pCs->pPacketPage)>>20) | CS_EEPROM_CMD_ELSEL); } /* Setup chip for memory mode */ csPacketPageW (pCs, CS_PKTPG_MEM_BASE, (UINT)(pCs->pPacketPage)&0xFFFF); csPacketPageW (pCs, CS_PKTPG_MEM_BASE+2, (UINT)(pCs->pPacketPage)>>16); busCtl = CS_BUS_CTL_MEM_MODE; if (pCs->configFlags & CS_CFGFLG_USE_SA) busCtl |= CS_BUS_CTL_USE_SA; csPacketPageW (pCs, CS_PKTPG_BUS_CTL, busCtl); /* We are in memory mode now! */ pCs->inMemoryMode = TRUE; } /* If IOCHRDY is enabled then clear the bit in the busCtl register */ busCtl = csPacketPageR (pCs, CS_PKTPG_BUS_CTL); if (pCs->configFlags & CS_CFGFLG_IOCHRDY) csPacketPageW (pCs, CS_PKTPG_BUS_CTL, busCtl & ~CS_BUS_CTL_IOCHRDY); else csPacketPageW (pCs, CS_PKTPG_BUS_CTL, busCtl | CS_BUS_CTL_IOCHRDY); /* Set the Line Control register to match the media type */ if (pCs->mediaType == CS_MEDIA_10BASET) csPacketPageW (pCs, CS_PKTPG_LINE_CTL, CS_LINE_CTL_10BASET); else csPacketPageW (pCs, CS_PKTPG_LINE_CTL, CS_LINE_CTL_AUI_ONLY); /* Set the BSTATUS/HC1 pin to be used as HC1 */ /* HC1 is used to enable the DC/DC converter */ selfCtl = CS_SELF_CTL_HC1E; /* If the media type is 10Base2 */ if (pCs->mediaType == CS_MEDIA_10BASE2) { /* Enable the DC/DC converter * If the DC/DC converter has a low enable * Set the HCB1 bit, which causes the HC1 pin to go low */ if ((pCs->configFlags & CS_CFGFLG_DCDC_POL) == 0) selfCtl |= CS_SELF_CTL_HCB1; } else /* Media type is 10BaseT or AUI */ { /* Disable the DC/DC converter * If the DC/DC converter has a high enable * Set the HCB1 bit, which causes the HC1 pin to go low */ if ((pCs->configFlags & CS_CFGFLG_DCDC_POL) != 0) selfCtl |= CS_SELF_CTL_HCB1; } csPacketPageW (pCs, CS_PKTPG_SELF_CTL, selfCtl); /* If media type is 10BaseT */ if (pCs->mediaType == CS_MEDIA_10BASET) { /* If full duplex mode then set the FDX bit in TestCtl register */ if (pCs->configFlags & CS_CFGFLG_FDX) csPacketPageW (pCs, CS_PKTPG_TEST_CTL, CS_TEST_CTL_FDX); } /* Initialize the config and control registers */ csPacketPageW (pCs, CS_PKTPG_RX_CFG, CS_RX_CFG_ALL_IE); csPacketPageW (pCs, CS_PKTPG_RX_CTL, CS_RX_CTL_RX_OK_A | CS_RX_CTL_IND_A | CS_RX_CTL_BCAST_A); csPacketPageW (pCs, CS_PKTPG_TX_CFG, CS_TX_CFG_ALL_IE); csPacketPageW (pCs, CS_PKTPG_BUF_CFG, CS_BUF_CFG_RX_MISS_IE); /* Put Ethernet address into the Individual Address register */ pIA = (CS_IA *)pCs->arpCom.ac_enaddr; csPacketPageW (pCs, CS_PKTPG_IND_ADDR, pIA->word[0]); csPacketPageW (pCs, CS_PKTPG_IND_ADDR+2, pIA->word[1]); csPacketPageW (pCs, CS_PKTPG_IND_ADDR+4, pIA->word[2]); /* Set the interrupt level in the chip */ if (pCs->intLevel == 5) csPacketPageW (pCs, CS_PKTPG_INT_NUM, 3); else csPacketPageW (pCs, CS_PKTPG_INT_NUM, (pCs->intLevel) - 10); /* Enable reception and transmission of frames */ csPacketPageW (pCs, CS_PKTPG_LINE_CTL, csPacketPageR (pCs, CS_PKTPG_LINE_CTL) | CS_LINE_CTL_RX_ON | CS_LINE_CTL_TX_ON); /* Enable interrupt at the chip */ csPacketPageW (pCs, CS_PKTPG_BUS_CTL, csPacketPageR (pCs, CS_PKTPG_BUS_CTL) | CS_BUS_CTL_INT_ENBL); }#ifdef BSD43_DRIVER/********************************************************************************* csOutput - ethernet output routine** This routine is a major entry point and is called by the protocol stack to* transmit a packet across the LAN. The packet data is passed to this routine* in a chain of mbuf structures.** This routine calls the ether_output() routine, which in turn calls the* csStartOutput() routine. The ether_output() routine resolves the destination* IP address to it's Ethernet address, builds an Ethernet header and prepends* the Ethernet header to the mbuf chain. The mbuf chain is added to the end* of the network interface driver's transmit queue. If the network interface* NOTRAILERS flag is clear (trailers enabled), then the ether_output() routine* converts the packet data to the trailers format. Finally, the ether_output()* routine calls the csStartOutput() routine begin transmission of the packet.** RETURNS: OK if successful, otherwise errno.*/LOCAL int csOutput ( struct ifnet *pIf, struct mbuf *pMbufChain, SOCKADDR *pDst ) { FAST CS_SOFTC *pCs = &cs_softc[pIf->if_unit]; return (ether_output (pIf, pMbufChain, pDst, (FUNCPTR)csStartOutput, &pCs->arpCom)); }/********************************************************************************* csStartOutput - copy a packet to the interface** This routine is called to start the transmission of the packet at the head* of the transmit queue. This routine is called by the ether_output() routine* when a new packet is added to the transmit queue and this routine is called* by csIntrTx() via netTask() when a previous packet transmission is* completed. This routine is always executed at task time (never at interrupt* time).** Note: This network interface driver does not support output hook routines,* because to do so requires that an image of the transmit packet be built in* memory before the image is copied to the CS8900 chip. It is much more* efficient to copy the image directly from the mbuf chain to the CS8900 chip.* However, this network interface driver does support input hook routines.** RETURNS: N/A*/LOCAL void csStartOutput ( int unit ) { FAST CS_SOFTC *pCs = &cs_softc[unit];#else /* BSD43_DRIVER */LOCAL void csStartOutput ( CS_SOFTC * pCs /* pointer to control structure */ ) {#endif /* BSD43_DRIVER */ FAST struct mbuf *pMbuf; struct mbuf *pMbufChain; struct ifqueue *pTxQueue; USHORT busStatus; USHORT length; int intState;#ifdef BSD43_DRIVER if (unit >= MAXUNITS) return;#endif /* BSD43_DRIVER */ pTxQueue = &pCs->arpCom.ac_if.if_snd; /* Note the maximum depth of the transmit queue */ if (pTxQueue->ifq_len > pCs->maxTxDepth) pCs->maxTxDepth = pTxQueue->ifq_len; /* Don't interrupt a transmission in progress */ if (pCs->txInProgress) return; /* Disable interrupts at the CPU so disabling chip interrupt is atomic */ intState = intLock (); /* INT LOCK */ /* Disable interrupt at the chip so transmit sequence is not disturbed */ csPacketPageW (pCs, CS_PKTPG_BUS_CTL, csPacketPageR (pCs, CS_PKTPG_BUS_CTL) & ~CS_BUS_CTL_INT_ENBL); /* Re-enable interrupts at the CPU */ intUnlock (intState); /* INT UNLOCK */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -