⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 if_eihk.c

📁 Tornado 2.0.2 source code!vxworks的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	   );    return (OK);    }/********************************************************************************* eiReset - reset the ei interface** Mark interface as inactive and reset the chip.*/static void eiReset    (    int unit    )    {    DRV_CTRL *pDrvCtrl;    pDrvCtrl = & drvCtrl [unit];    pDrvCtrl->idr.ac_if.if_flags = 0;    sys596IntDisable (unit);                    /* disable ints from the dev */    sys596Port (unit, PORT_RESET, NULL);        /* reset the 596 chip */    }/********************************************************************************* eiIoctl - interface ioctl procedure** Process an interface ioctl request.*/static int eiIoctl    (    IDR     *pIDR,    int     cmd,    caddr_t data    )    {    int error;#ifdef EI_DEBUG    printf ("ei: ioctl: pIDR=%x cmd=%x data=%x\n", pIDR, cmd, data);#endif /* EI_DEBUG */    error = 0;    switch (cmd)        {        case SIOCSIFADDR:            ((struct arpcom *)pIDR)->ac_ipaddr = IA_SIN (data)->sin_addr;            arpwhohas (pIDR, &IA_SIN (data)->sin_addr);            break;        case SIOCSIFFLAGS:            /* Flags are set outside this module. No additional work to do. */            break;        default:            error = EINVAL;        }    return (error);    }#ifdef BSD43_DRIVER/********************************************************************************* eiOutput - interface output routine.** This is the entry point for packets arriving from protocols above.  This* routine merely calls our specific output routines that eventually lead* to a transmit to the network.** RETURNS: 0 or appropriate errno*/static int eiOutput    (    IDR *    pIDR,    MBUF *     pMbuf,    SOCK * pDestAddr    )    {#ifdef EI_DEBUG    printf ("ei: output: pIDR=%x pMbuf=%x pDestAddr=%x\n",            pIDR, pMbuf, pDestAddr);#endif /* EI_DEBUG */    return (ether_output ((IFNET *)pIDR, pMbuf, pDestAddr,            (FUNCPTR) eiTxStartup, pIDR));    }#endif/********************************************************************************* eiTxStartup - start output on the chip** Looks for any action on the queue, and begins output if there is anything* there.  This routine is called from several possible threads.  Each will be* described below.** The first, and most common thread, is when a user task requests the* transmission of data.  Under BSD 4.3, this will cause eiOutput() to be * called, which calls ether_output(), which will usually call this routine.* This routine will not be called if ether_output() finds that our interface * output queue is full. In this case, the outgoing data will be thrown out.* 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, and most obscure thread, is when the reception of certain* packets causes an immediate (attempted) response.  For example, ICMP echo* packets (ping), and ICMP "no listener on that port" notifications.  All* functions in this driver that handle the reception side are executed in the* context of netTask().  Always.  So, in the case being discussed, netTask() * will receive these certain packets, cause IP to be stimulated, and cause the* generation of a response to be sent.  We then find ourselves following the* thread explained in the second example, with the important distinction that* the context is that of netTask().** The third thread occurs when this routine runs out of TFDs and returns.  If* this occurs when our output queue is not empty, this routine would typically* not get called again until new output was requested.  Even worse, if the* output queue was also full, this routine would never get called again and* we would have a lock state.  It DOES happen.  To guard against this, the* transmit clean-up handler detects the out-of-TFDs state and calls this* function.  The clean-up handler also runs from netTask.** Note that this function is ALWAYS called between an splnet() and an splx().* This is true because netTask(), and ether_output() take care of* this when calling this function.  Therefore, no calls to these spl functions* are needed anywhere in this output thread.*/#ifdef BSD43_DRIVERstatic void eiTxStartup    (    int unit    )    {    DRV_CTRL * pDrvCtrl = & drvCtrl [unit];#elsestatic void eiTxStartup    (    DRV_CTRL * 	pDrvCtrl 	/* driver control structure */    )    {#endif    MBUF * pMbuf;    int length;    TFD * pTfd;    /*     * Loop until there are no more packets ready to send or we     * have insufficient resources left to send another one.     */    while (pDrvCtrl->idr.ac_if.if_snd.ifq_head)        {        /* get free tfd */        pTfd = (TFD *) eiQGet ((EI_LIST *)&pDrvCtrl->tfdQueue);        if (pTfd == NULL)            break;                              /* out of TFD's */        IF_DEQUEUE (&pDrvCtrl->idr.ac_if.if_snd, pMbuf);  /* dequeue a packet */        copy_from_mbufs ((ETH_HDR *)pTfd->enetHdr, pMbuf, length);        length = max (ETHERSMALL, length);        if ((etherOutputHookRtn != NULL) &&            (* etherOutputHookRtn) (&pDrvCtrl->idr,                                     (ETH_HDR *)pTfd->enetHdr, length))            continue;        pTfd->count = length & ~0xc000;     /* fill in length */        eiTxQPut (pDrvCtrl, pTfd);#ifndef BSD43_DRIVER    /* BSD 4.4 ether_output() doesn't bump statistic. */        pDrvCtrl->idr.ac_if.if_opackets++;#endif        }    }/********************************************************************************* eiInt - entry point for handling interrupts from the 82596** The interrupting events are acknowledged to the device, so that the device* will deassert its interrupt signal.  The amount of work done here is kept* to a minimum; the bulk of the work is defered to the netTask.  Several flags* are used here to synchronize with task level code and eliminate races.*/void eiInt    (    DRV_CTRL *pDrvCtrl    )    {    UINT16  event;    SCB *pScb;    int unit;    pScb = pDrvCtrl->pScb;    unit = pDrvCtrl->idr.ac_if.if_unit;    event = pScb->scbStatus & (SCB_S_CX | SCB_S_FR | SCB_S_CNA | SCB_S_RNR);#ifdef EI_DEBUG    logMsg ("ei: interrupt: event=%x\n", event, 0, 0, 0, 0, 0);#endif /* EI_DEBUG */    eiCommand (pDrvCtrl, event);                        /* ack the events */    sys596IntAck (unit);                                /* ack 596 interrupt */    /* Handle transmitter interrupt */    if (event & SCB_S_CNA)                              /* reclaim tx tfds */        {        pDrvCtrl->wdTxTimeout = 0;              /* reset timeout count */        if (pDrvCtrl->cleanQueue.head == NULL)      /* clean queue empty */            {            pDrvCtrl->cleanQueue.head = pDrvCtrl->cblQueue.head; /* new head */            pDrvCtrl->cleanQueue.tail = pDrvCtrl->cblQueue.tail; /* new tail */            }        else                                            /* concatenate queues */            {            pDrvCtrl->cleanQueue.tail->pNext =                        (EI_NODE*) pDrvCtrl->cblQueue.head;            pDrvCtrl->cleanQueue.tail = pDrvCtrl->cblQueue.tail;            }        if (!pDrvCtrl->txCleaning)                          /* not cleaning? */            {            pDrvCtrl->txCleaning = TRUE;                    /* set flag */            netJobAdd ((FUNCPTR) eiTxCleanQ, (int) pDrvCtrl, 0, 0, 0, 0);                            /* defer cleanup */            }        if (pDrvCtrl->txQueue.head != NULL)             /* anything to flush? */            eiTxQFlush (pDrvCtrl);                      /* flush the tx q */        else            pDrvCtrl->txIdle = TRUE;                    /* transmitter idle */        }    /* Handle receiver interrupt */    if (event & SCB_S_FR)	{	pDrvCtrl->wdRxTimeout = 0;                 	/* reset timeout count */	if (!(pDrvCtrl->rcvHandling))            {            pDrvCtrl->rcvHandling = TRUE;            (void) netJobAdd ((FUNCPTR) eiHandleRecvInt, (int) pDrvCtrl,0, 0, 0, 0);         /* netTask processes */	    }        }    }/********************************************************************************* eiTxCleanQ - checks errors in completed TFDs and moves TFDs to free queue** This routine is executed by netTask.  It "cleans" the TFDs on the clean-up* queue by checking each one for errors and then returning the TFD to the* "free TFD" queue.  The startup routine is sometimes called here to eliminate* the lock-out case where the driver input queue is full but there are no* TFDs available.*/static void eiTxCleanQ    (    DRV_CTRL *pDrvCtrl    )    {    TFD *pTfd;    BOOL needTxStart;    int unit;    unit = pDrvCtrl->idr.ac_if.if_unit;    do        {        pDrvCtrl->txCleaning = TRUE;        if (pDrvCtrl->tfdQueue.head == NULL)              /* tfd queue empty */            needTxStart = TRUE;                           /* set flag */        else            needTxStart = FALSE;        /* process transmitted frames */        while (1)            {            /* Get TFD. No ints allowed while manipulating this queue. */            sys596IntDisable (unit);            pTfd = (TFD*) eiQGet ((EI_LIST *)&pDrvCtrl->cleanQueue);            sys596IntEnable (unit);            if (pTfd == NULL)                break;            pDrvCtrl->idr.ac_if.if_collisions +=         /* add any colls */                (pTfd->status & CFD_S_RETRY) ? 16 :  /* excessive colls */                (pTfd->status & CFD_S_COLL_MASK);    /* some colls */            if (!(pTfd->status & CFD_S_OK))          /* packet not sent */                {                pDrvCtrl->idr.ac_if.if_oerrors++;        /* incr err count */                pDrvCtrl->idr.ac_if.if_opackets--;       /* decr sent count */                }            /* return to tfdQ */            eiQPut (unit,(EI_LIST *)&pDrvCtrl->tfdQueue, (EI_NODE*)pTfd);            }        if (needTxStart)                                  /* check flag */#ifdef BSD43_DRIVER            eiTxStartup (unit);#else            eiTxStartup (pDrvCtrl);#endif        pDrvCtrl->txCleaning = FALSE;        }    while (pDrvCtrl->cleanQueue.head != NULL);            /* check again */    }/********************************************************************************* eiHandleRecvInt - task level interrupt service for input packets** This routine is called at task level indirectly by the interrupt* service routine to do any message received processing.*/static void eiHandleRecvInt    (    DRV_CTRL *pDrvCtrl    )    {    RFD *pRfd;    do        {        pDrvCtrl->rcvHandling = TRUE;             /* interlock with eiInt() */        while ((pRfd = eiRxQGet (pDrvCtrl)) != NULL)            if (eiReceive (pDrvCtrl, pRfd) == OK)                eiRxQPut (pDrvCtrl, pRfd);        pDrvCtrl->rcvHandling = FALSE;            /* interlock with eiInt() */        }    while (eiRxQFull (pDrvCtrl));              /* make sure rx q still empty */    }/********************************************************************************* eiReceive - pass a received frame to the next layer up** Strips the Ethernet header and passes the packet to the appropriate* protocol.  The return value indicates if buffer loaning was used to hold* the data.  A return value of OK means that loaning was not done, and it

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -