📄 if_mbc.c
字号:
{ pDrvCtrl->lPool[counter] = loanBuf + (counter * RX_BUF_SIZE); pDrvCtrl->refCnt[counter] = 0; pDrvCtrl->pRefCnt[counter] = & pDrvCtrl->refCnt[counter]; } /* reset the chip */ mbcReset (unit); /* publish the Interface Data Record */#ifdef BSD43_DRIVER ether_attach (& pDrvCtrl->idr.ac_if, unit, MBC_IFNAME, (FUNCPTR) mbcInit, (FUNCPTR) mbcIoctl, (FUNCPTR) mbcOutput, (FUNCPTR) mbcReset);#else ether_attach ( &pDrvCtrl->idr.ac_if, unit, MBC_IFNAME, (FUNCPTR) mbcInit, (FUNCPTR) mbcIoctl, (FUNCPTR) ether_output, (FUNCPTR) mbcReset ); pDrvCtrl->idr.ac_if.if_start = (FUNCPTR)mbcStartOutput;#endif mbcInit (unit); return (OK); }/********************************************************************************* mbcInit - initialize the MBC network device** This routine marks the interface as down, then configures and initializes* the chip. It sets up the transmit and receive buffer descriptor (BD)* rings, initializes registers, and enables interrupts. Finally, it marks* the interface as up and running. It does not touch the receive loaner* buffer stack.** This routine is called from the driver attach routine.** The complement of this routine is mbcReset(). Once a unit is reset by* mbcReset(), it may be re-initialized to a running state by this routine.** RETURNS: OK if successful, otherwise ERROR.** SEE ALSO: mbcIoctl(), mbcReset()**/LOCAL STATUS mbcInit ( int unit /* unit number */ ) { DRV_CTRL * pDrvCtrl; MBC_BD * pBd; volatile char * pDevBase; UINT8 enetAddr[ENET_ADDR_SIZE]; UINT16 regValue; int counter; /* sanity check the unit number */ if (unit < 0 || unit >= MAX_UNITS) return (ERROR); pDrvCtrl = & drvCtrl[unit]; /* ensure single invocation */ if (pDrvCtrl->initialized) return (OK); pDevBase = pDrvCtrl->ether.pDevBase; /* mark the device as down */ pDrvCtrl->idr.ac_if.if_flags &= ~(IFF_UP | IFF_RUNNING); /* take the device out of reset state */ MBC_REG_WRITE (pDevBase, MBC_ECNTL, MBC_ECNTL_RES_OFF); /* set up transmit buffer descriptors */ pDrvCtrl->ether.txBdNext = 0; pBd = pDrvCtrl->ether.txBdBase; for (counter = pDrvCtrl->ether.txBdNum; counter; counter--, pBd++) pBd->statusMode = (MBC_TXBD_I | MBC_TXBD_L | MBC_TXBD_TC); /* turn on the `wrap' bit on the last buffer descriptor */ pBd--; pBd->statusMode |= MBC_TXBD_W; /* set up the receive buffer descriptors */ pDrvCtrl->ether.rxBdNext = 0; pBd = pDrvCtrl->ether.rxBdBase; for (counter = pDrvCtrl->ether.rxBdNum; counter; counter--, pBd++) pBd->statusMode = (MBC_RXBD_E | MBC_RXBD_I); /* turn on the `wrap' bit on the last buffer descriptor */ pBd--; pBd->statusMode |= MBC_RXBD_W; /* set the interrupt vector number */ MBC_REG_WRITE (pDevBase, MBC_IVEC, pDrvCtrl->inum); /* set BD size and other DMA parameters */ regValue = pDrvCtrl->dmaParms; regValue |= (pDrvCtrl->ether.bdSize << MBC_EDMA_BDS_SHFT); MBC_REG_WRITE (pDevBase, MBC_EDMA, regValue); /* * set the operating mode to, no internal loopback, no full duplex, and * no hearbeat control. */ MBC_REG_WRITE (pDevBase, MBC_ECFG, 0); /* * set address control to, no hash enable, no index enable, no multicast, * no physical address rejection, and promiscuous mode, if needed. */ regValue = 0; if (pDrvCtrl->idr.ac_if.if_flags & IFF_PROMISC) regValue |= MBC_AR_PROM; MBC_REG_WRITE (pDevBase, MBC_AR, regValue); /* set max receive frame size */ MBC_REG_WRITE (pDevBase, MBC_EMRBLR, FRAME_MAX); /* get ethernet address for this device */ if (sysEnetAddrGet (unit, (UINT8 *) enetAddr) == ERROR) return (ERROR); /* copy in correct byte sequence */ for (counter=0; counter < ENET_ADDR_SIZE; counter++) pDrvCtrl->idr.ac_enaddr[ENET_ADDR_SIZE - counter - 1] = enetAddr[counter]; /* install the ethernet address */ bcopy ((char *) pDrvCtrl->idr.ac_enaddr, (char *) (pDrvCtrl->ether.pDevBase + MBC_ARTAB), ENET_ADDR_SIZE); /* set rest of the AR entries to broadcast address */ regValue=0xffff; for (counter = 1; counter < MBC_ARTAB_SIZE; counter++) { MBC_REG_WRITE (pDevBase, MBC_ARTAB + (counter * 8), regValue); MBC_REG_WRITE (pDevBase, MBC_ARTAB + (counter * 8) + 2, regValue); MBC_REG_WRITE (pDevBase, MBC_ARTAB + (counter * 8) + 4, regValue); } /* enable interrupts - clear events and set mask */ MBC_REG_WRITE (pDevBase, MBC_IEVNT, 0xffff); MBC_REG_WRITE (pDevBase, MBC_IMASK, MBC_IMASK_RXF | MBC_IMASK_EBE); /* set interface flags - mark device as `up' */ pDrvCtrl->idr.ac_if.if_flags |= IFF_UP | IFF_RUNNING | IFF_NOTRAILERS; /* mark device as initialized */ pDrvCtrl->initialized = TRUE; /* enable the device */ MBC_REG_UPDATE (pDevBase, MBC_ECNTL, MBC_ECNTL_ENBL); /* start sending enqueued packets */#ifdef BSD43_DRIVER (void) netJobAdd ((FUNCPTR) mbcStartOutput, unit, 0, 0, 0, 0); #else (void) netJobAdd ((FUNCPTR) mbcStartOutput, (int)pDrvCtrl, 0, 0, 0, 0); #endif return (OK); }#ifdef BSD43_DRIVER/********************************************************************************* mbcOutput - network interface output routine** This routine simply calls ether_output(). ether_output() resolves * the hardware addresses and calls mbcStartOutput() with the unit number* passed as an argument.** RETURNS: OK if successful, otherwise errno.*/LOCAL int mbcOutput ( IFNET * pIfNet, /* pointer to IFNET structure */ MBUF * pMbuf, /* mbuf chain for output */ SOCK * pSock /* sock ptr for destination */ ) { DRV_CTRL * pDrvCtrl = & drvCtrl[pIfNet->if_unit]; return (ether_output (pIfNet, pMbuf, pSock, (FUNCPTR) mbcStartOutput, & pDrvCtrl->idr)); }#endif/********************************************************************************* mbcStartOutput - output packet to network interface device** mbcStartOutput() takes a packet from the network interface output queue,* copies the mbuf chain into an interface buffer, and sends the packet over* the interface. etherOutputHookRtns are supported.** Collision stats are collected in this routine from previously sent BDs.* These BDs will not be examined until after the transmitter has cycled the* ring, coming upon the BD after it has been sent. Thus, collision stat* collection will be delayed a full cycle through the Tx ring.** This routine is called under several possible scenarios. Each one will be* described below.** The first, and most common, is when a user task requests the transmission of* data. Under BSD 4.3, this results in a call to mbcOutput(), which in turn* calls ether_output(). The routine, ether_output(), will make a call to* mbcStartOutput() if our interface output queue is not full, otherwise, the* outgoing data is discarded. BSD 4.4 uses a slightly different model, in* which the generic ether_output() routine is called directly, followed by* a call to this routine.** The second scenario is when this routine, while executing runs out of free* Tx BDs, turns on transmit interrupts and exits. When the next BD is* transmitted, an interrupt occurs and the ISR does a netJobAdd of the routine* which executes in the context of netTask() and continues sending packets* from the interface output queue. ** The third scenario is when the device is reset, typically when the * promiscuous mode is altered; which results in a call to mbcInit(). This * resets the device, does a netJobAdd() of this routine to enable transmitting * queued packets.** RETURNS: N/A*/#ifdef BSD43_DRIVERLOCAL void mbcStartOutput ( int unit /* unit number */ ) { DRV_CTRL * pDrvCtrl = & drvCtrl[unit];#elseLOCAL void mbcStartOutput ( DRV_CTRL * pDrvCtrl /* driver control structure */ ) { int unit = pDrvCtrl->idr.ac_if.if_unit;#endif volatile char * pDevBase = pDrvCtrl->ether.pDevBase; MBUF * pMbuf; /* mbuf pointer */ int length; MBC_BD * pTxBd; UINT8 * pad; UINT8 txBdMax = pDrvCtrl->ether.txBdNum - 2; if (txBdMax == 0) txBdMax++; /* * Loop until: * a) there are no more packets ready to send * b) we have insufficient resources left to send another one * c) txBdMax packets have been sent, so that the * transmitter on the rev 0.1 chip is not choked. */ while (pDrvCtrl->idr.ac_if.if_snd.ifq_head != NULL) { pTxBd = & pDrvCtrl->ether.txBdBase[pDrvCtrl->ether.txBdNext]; /* check if a transmit buffer descriptor is available */ if ((pTxBd->statusMode & MBC_TXBD_R) || (txBdMax == 0)) { /* if no BD available, enable interrupt to see when one is free */ wdStart (pDrvCtrl->wdId, WD_TIMEOUT, (FUNCPTR) mbcDeviceRestart, unit); MBC_INTR_ENABLE (pDevBase, MBC_IEVNT_TXF); break; } IF_DEQUEUE (& pDrvCtrl->idr.ac_if.if_snd, pMbuf); copy_from_mbufs (pTxBd->dataPointer, pMbuf, length); /* initial hardware version does not support padding */ if (length < FRAME_MIN) { pad = pTxBd->dataPointer + length; for (; length != FRAME_MIN; length++, pad++) *pad = 0x88; } /* call hook if one is connected */ if ((etherOutputHookRtn == NULL) || ((* etherOutputHookRtn) (& pDrvCtrl->idr.ac_if, pTxBd->dataPointer, length) == 0)) { /* add in collision stats from previously sent BDs */ pDrvCtrl->idr.ac_if.if_collisions += ((pTxBd->statusMode & MBC_TXBD_RC) >> MBC_TXBD_RC_SHFT); /* add in transmission failures */ if (pTxBd->statusMode & MBC_TXBD_ERRS) { pDrvCtrl->idr.ac_if.if_oerrors++; pDrvCtrl->idr.ac_if.if_opackets--; } /* since hook did not grab the frame, send packet */ pTxBd->dataLength = length; pTxBd->statusMode &= ~(MBC_TXBD_ERRS|MBC_TXBD_RC); pTxBd->statusMode |= MBC_TXBD_R; /* incr BD count */ pDrvCtrl->ether.txBdNext = (pDrvCtrl->ether.txBdNext + 1) % pDrvCtrl->ether.txBdNum;#ifndef BSD43_DRIVER /* BSD 4.4 ether_output() doesn't bump statistic. */ pDrvCtrl->idr.ac_if.if_opackets++;#endif } txBdMax --; } }/********************************************************************************* mbcIoctl - network interface control routine** This routine implements the network interface control functions.* It handles SIOCSIFADDR and SIOCSIFFLAGS commands.** RETURNS: OK if successful, otherwise EINVAL.*/LOCAL int mbcIoctl ( IFNET * pIfNet, /* pointer to IFNET structure */ int cmd, /* command to process */ caddr_t data /* pointer to data */ ) { DRV_CTRL * pDrvCtrl = & drvCtrl[pIfNet->if_unit]; int error = 0; /* error value */ int s = splimp (); /* sem not taken in calling routines */ BOOL promiscReq; /* requested promisc state */ BOOL promiscCur; /* current promisc state */ switch (cmd) { case SIOCSIFADDR: /* set interface address */ ((struct arpcom *)pIfNet)->ac_ipaddr = IA_SIN (data)->sin_addr; arpwhohas (pIfNet, &IA_SIN (data)->sin_addr); break; case SIOCSIFFLAGS: /* process request, if promisc mode needs change */ promiscReq = ((pDrvCtrl->idr.ac_if.if_flags & IFF_PROMISC) ? TRUE : FALSE); promiscCur = ((MBC_REG_READ (pDrvCtrl->ether.pDevBase, MBC_AR) & MBC_AR_PROM) ? TRUE : FALSE); if ((promiscReq && (!promiscCur)) || ((!promiscReq) && promiscCur)) { mbcDeviceRestart (pIfNet->if_unit); } break; default: error = EINVAL; } splx (s); return (error); }/********************************************************************************* mbcReset - network interface reset routine** This routine marks the interface as down and resets the device. This* includes disabling interrupts, stopping the transmitter and receiver.** The complement of this rotuine is mbcInit(). Once a unit is reset by this* routine, it can be re-initialized to a running state by mbcInit().** RETURNS: N/A*/LOCAL void mbcReset ( int unit /* unit number */ ) { DRV_CTRL * pDrvCtrl; int counter = 0xffff; if (unit < 0 || unit >= MAX_UNITS) /* sanity check the unit number */ return; pDrvCtrl = & drvCtrl[unit]; /* Disable interrupts */ MBC_REG_WRITE (pDrvCtrl->ether.pDevBase, MBC_IMASK, 0x0); /* clear pending `graceful stop complete' event, and start one */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -