📄 lanc111.c
字号:
nic_outlb(NIC_ACK, INT_TX_EMPTY); imr &= ~INT_TX_EMPTY; NutEventPostFromIrq(&ni->ni_tx_rdy); } /* Transmit error. */ else if (isr & INT_TX) { /* re-enable transmit */ nic_bs(0); nic_outw(NIC_TCR, nic_inlb(NIC_TCR) | TCR_TXENA); nic_bs(2); nic_outlb(NIC_ACK, INT_TX); /* kill the packet */ nic_outlb(NIC_MMUCR, MMU_PKT); NutEventPostFromIrq(&ni->ni_tx_rdy); } /* * If this is a receive interrupt, then wake up the receiver * thread. */ if (isr & INT_RX_OVRN) { nic_outlb(NIC_ACK, INT_RX_OVRN); //nic_outlb(NIC_MMUCR, MMU_TOP); } if (isr & INT_ERCV) { nic_outlb(NIC_ACK, INT_ERCV); NutEventPostFromIrq(&ni->ni_rx_rdy); } if (isr & INT_RCV) { nic_outlb(NIC_ACK, INT_RCV); imr &= ~INT_RCV; NutEventPostFromIrq(&ni->ni_rx_rdy); } if (isr & INT_ALLOC) { imr &= ~INT_ALLOC; NutEventPostFromIrq(&maq); } //printf(" -%02X-%02X- ", nic_inlb(NIC_IST), inb(PINE) & 0x20); nic_outlb(NIC_MSK, imr);}/* * Write data block to the NIC. */static void NicWrite(u_char * buf, u_short len){ register u_short l = len - 1; register u_char ih = (u_short) l >> 8; register u_char il = (u_char) l; if (!len) return; do { do { nic_outlb(NIC_DATA, *buf++); } while (il-- != 0); } while (ih-- != 0);}/* * Read data block from the NIC. */static void NicRead(u_char * buf, u_short len){ register u_short l = len - 1; register u_char ih = (u_short) l >> 8; register u_char il = (u_char) l; if (!len) return; do { do { *buf++ = nic_inlb(NIC_DATA); } while (il-- != 0); } while (ih-- != 0);}/*! * \brief Fetch the next packet out of the receive ring buffer. * * Nic interrupts must be disabled when calling this funtion. * * \return Pointer to an allocated ::NETBUF. If there is no * no data available, then the function returns a * null pointer. If the NIC's buffer seems to be * corrupted, a pointer to 0xFFFF is returned. */static NETBUF *NicGetPacket(void){ NETBUF *nb = 0; //u_char *buf; u_short fsw; u_short fbc; /* Check the fifo empty bit. If it is set, then there is nothing in the receiver fifo. */ nic_bs(2); if (nic_inw(NIC_FIFO) & 0x8000) { return 0; } /* Inialize pointer register. */ nic_outw(NIC_PTR, PTR_READ | PTR_RCV | PTR_AUTO_INCR); _NOP(); _NOP(); _NOP(); _NOP(); /* Read status word and byte count. */ fsw = nic_inw(NIC_DATA); fbc = nic_inw(NIC_DATA); //printf("[SW=%04X,BC=%04X]", fsw, fbc); /* Check for frame errors. */ if (fsw & 0xAC00) { nb = (NETBUF *) 0xFFFF; } /* Check the byte count. */ else if (fbc < 66 || fbc > 1524) { nb = (NETBUF *) 0xFFFF; } else { /* * Allocate a NETBUF. * Hack alert: Rev A chips never set the odd frame indicator. */ fbc -= 3; nb = NutNetBufAlloc(0, NBAF_DATALINK, fbc); /* Perform the read. */ if (nb) NicRead(nb->nb_dl.vp, fbc); } /* Release the packet. */ nic_outlb(NIC_MMUCR, MMU_TOP); return nb;}/*! * \brief Load a packet into the nic's transmit ring buffer. * * Interupts must have been disabled when calling this function. * * \param nb Network buffer structure containing the packet to be sent. * The structure must have been allocated by a previous * call NutNetBufAlloc(). This routine will automatically * release the buffer in case of an error. * * \return 0 on success, -1 in case of any errors. Errors * will automatically release the network buffer * structure. */static int NicPutPacket(NETBUF * nb){ u_short sz; u_char odd = 0; u_char imsk; //printf("[P]"); /* * Calculate the number of bytes to be send. Do not send packets * larger than the Ethernet maximum transfer unit. The MTU * consist of 1500 data bytes plus the 14 byte Ethernet header * plus 4 bytes CRC. We check the data bytes only. */ if ((sz = nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz) > ETHERMTU) return -1; /* Disable all interrupts. */ imsk = nic_inlb(NIC_MSK); nic_outlb(NIC_MSK, 0); /* Allocate packet buffer space. */ nic_bs(2); nic_outlb(NIC_MMUCR, MMU_ALO); if (NicMmuWait(100)) return -1; /* Enable interrupts including allocation success. */ nic_outlb(NIC_MSK, imsk | INT_ALLOC); /* The MMU needs some time. Use it to calculate the byte count. */ sz += nb->nb_dl.sz; sz += 6; if (sz & 1) { sz++; odd++; } /* Wait for allocation success. */ while ((nic_inlb(NIC_IST) & INT_ALLOC) == 0) { if (NutEventWait(&maq, 125)) { nic_outlb(NIC_MMUCR, MMU_RST); NicMmuWait(1000); nic_outlb(NIC_MMUCR, MMU_ALO); if (NicMmuWait(100) || (nic_inlb(NIC_IST) & INT_ALLOC) == 0) { if (NutEventWait(&maq, 125)) { return -1; } } } } /* Disable interrupts. */ imsk = nic_inlb(NIC_MSK); nic_outlb(NIC_MSK, 0); nic_outlb(NIC_PNR, nic_inhb(NIC_PNR)); nic_outw(NIC_PTR, 0x4000); /* Transfer control word. */ nic_outlb(NIC_DATA, 0); nic_outlb(NIC_DATA, 0); /* Transfer the byte count. */ nic_outw(NIC_DATA, sz); /* Transfer the Ethernet frame. */ NicWrite(nb->nb_dl.vp, nb->nb_dl.sz); NicWrite(nb->nb_nw.vp, nb->nb_nw.sz); NicWrite(nb->nb_tp.vp, nb->nb_tp.sz); NicWrite(nb->nb_ap.vp, nb->nb_ap.sz); if (odd) nic_outlb(NIC_DATA, 0); /* Transfer the control word. */ nic_outw(NIC_DATA, 0); /* Enqueue packet. */ if (NicMmuWait(100)) return -1; nic_outlb(NIC_MMUCR, MMU_ENQ); /* Enable interrupts. */ imsk |= INT_TX | INT_TX_EMPTY; nic_outlb(NIC_MSK, imsk); return 0;}/*! \fn NicRxLanc(void *arg) * \brief NIC receiver thread. * */THREAD(NicRxLanc, arg){ NUTDEVICE *dev; IFNET *ifn; NICINFO *ni; NETBUF *nb; u_char imsk; dev = arg; ifn = (IFNET *) dev->dev_icb; ni = (NICINFO *) dev->dev_dcb; /* * This is a temporary hack. Due to a change in initialization, * we may not have got a MAC address yet. Wait until one has been * set. */ for (;;) { if (*((u_long *) (ifn->if_mac)) && *((u_long *) (ifn->if_mac)) != 0xFFFFFFFFUL) { break; } NutSleep(63); } /* * Do not continue unless we managed to start the NIC. We are * trapped here if the Ethernet link cannot be established. * This happens, for example, if no Ethernet cable is plugged * in. */ while(NicStart(ifn->if_mac)) { NutSleep(1000); } LANC111_SIGNAL_MODE(); sbi(EIMSK, LANC111_SIGNAL_IRQ); NutEventPost(&mutex); /* Run at high priority. */ NutThreadSetPriority(9); for (;;) { /* * Wait for the arrival of new packets or * check the receiver every two second. */ NutEventWait(&ni->ni_rx_rdy, 2000); /* * Fetch all packets from the NIC's internal * buffer and pass them to the registered handler. */ imsk = nic_inlb(NIC_MSK); nic_outlb(NIC_MSK, 0); while ((nb = NicGetPacket()) != 0) { if (nb != (NETBUF *) 0xFFFF) { ni->ni_rx_packets++; (*ifn->if_recv) (dev, nb); } } nic_outlb(NIC_MSK, imsk | INT_RCV | INT_ERCV); }}/*! * \brief Send Ethernet packet. * * \param dev Identifies the device to use. * \param nb Network buffer structure containing the packet to be sent. * The structure must have been allocated by a previous * call NutNetBufAlloc(). * * \return 0 on success, -1 in case of any errors. */int LancOutput(NUTDEVICE * dev, NETBUF * nb){ static u_long mx_wait = 5000; int rc = -1; NICINFO *ni; /* * After initialization we are waiting for a long time to give * the PHY a chance to establish an Ethernet link. */ if (NutEventWait(&mutex, mx_wait) == 0) { ni = (NICINFO *) dev->dev_dcb; if (NicPutPacket(nb) == 0) { ni->ni_tx_packets++; rc = 0; /* Ethernet works. Set a long waiting time in case we temporarly lose the link next time. */ mx_wait = 5000; } NutEventPost(&mutex); } /* * Probably no Ethernet link. Significantly reduce the waiting * time, so following transmission will soon return an error. */ else { mx_wait = 500; } return rc;}/*! * \brief Initialize Ethernet hardware. * * Resets the LAN91C111 Ethernet controller, initializes all required * hardware registers and starts a background thread for incoming * Ethernet traffic. * * Applications should do not directly call this function. It is * automatically executed during during device registration by * NutRegisterDevice(). * * If the network configuration hasn't been set by the application * before registering the specified device, this function will * call NutNetLoadConfig() to get the MAC address. * * \param dev Identifies the device to initialize. */int LancInit(NUTDEVICE * dev){ /* Disable NIC interrupt and clear NICINFO structure. */ cbi(EIMSK, LANC111_SIGNAL_IRQ); memset(dev->dev_dcb, 0, sizeof(NICINFO)); /* Register interrupt handler and enable interrupts. */ if (NutRegisterIrqHandler(&LANC111_SIGNAL, NicInterrupt, dev)) return -1; /* * Start the receiver thread. */ NutThreadCreate("rxi5", NicRxLanc, dev, 640); //NutSleep(500); return 0;}static NICINFO dcb_eth0;/*! * \brief Network interface information structure. * * Used to call. */static IFNET ifn_eth0 = { IFT_ETHER, /*!< \brief Interface type. */ {0, 0, 0, 0, 0, 0}, /*!< \brief Hardware net address. */ 0, /*!< \brief IP address. */ 0, /*!< \brief Remote IP address for point to point. */ 0, /*!< \brief IP network mask. */ ETHERMTU, /*!< \brief Maximum size of a transmission unit. */ 0, /*!< \brief Packet identifier. */ 0, /*!< \brief Linked list of arp entries. */ NutEtherInput, /*!< \brief Routine to pass received data to, if_recv(). */ LancOutput, /*!< \brief Driver output routine, if_send(). */ NutEtherOutput /*!< \brief Media output routine, if_output(). */};/*! * \brief Device information structure. * * A pointer to this structure must be passed to NutRegisterDevice() * to bind this Ethernet device driver to the Nut/OS kernel. * An application may then call NutNetIfConfig() with the name \em eth0 * of this driver to initialize the network interface. * */NUTDEVICE devSmsc111 = { 0, /* Pointer to next device. */ {'e', 't', 'h', '0', 0, 0, 0, 0, 0}, /* Unique device name. */ IFTYP_NET, /* Type of device. */ 0, /* Base address. */ 0, /* First interrupt number. */ &ifn_eth0, /* Interface control block. */ &dcb_eth0, /* Driver control block. */ LancInit, /* Driver initialization routine. */ 0, /* Driver specific control function. */ 0, /* Read from device. */ 0, /* Write to device. */ 0, /* Write from program space data to device. */ 0, /* Open a device or file. */ 0, /* Close a device or file. */ 0 /* Request file size. */};/*@}*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -