Nut/OS  4.10.3
API Reference
lan91.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2003-2006 by egnite Software GmbH.
00003  * Copyright (C) 2008 by egnite GmbH.
00004  *
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted provided that the following conditions
00009  * are met:
00010  *
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  * 3. Neither the name of the copyright holders nor the names of
00017  *    contributors may be used to endorse or promote products derived
00018  *    from this software without specific prior written permission.
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00021  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00023  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00024  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00025  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00026  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00027  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00028  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00029  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00030  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00031  * SUCH DAMAGE.
00032  *
00033  * For additional information see http://www.ethernut.de/
00034  *
00035  */
00036 
00037 /*
00038  * $Id: lan91.c 3376 2011-04-26 14:11:50Z haraldkipp $
00039  */
00040 
00041 #include <string.h>
00042 
00043 #include <cfg/os.h>
00044 #include <sys/atom.h>
00045 #include <sys/heap.h>
00046 #include <sys/thread.h>
00047 #include <sys/event.h>
00048 #include <sys/timer.h>
00049 #include <sys/confnet.h>
00050 
00051 #include <netinet/if_ether.h>
00052 #include <net/ether.h>
00053 #include <net/if.h>
00054 #include <net/if_var.h>
00055 
00056 #include <cfg/arch/gpio.h>
00057 #include <dev/irqreg.h>
00058 #include <dev/lan91.h>
00059 
00060 #ifdef NUTDEBUG
00061 #include <stdio.h>
00062 #endif
00063 
00064 /*
00065  * Determine interrupt settings.
00066  */
00067 #if (LAN91_SIGNAL_IRQ == INT0)
00068 #define LAN91_SIGNAL          sig_INTERRUPT0
00069 #elif (LAN91_SIGNAL_IRQ == INT1)
00070 #define LAN91_SIGNAL          sig_INTERRUPT1
00071 #elif (LAN91_SIGNAL_IRQ == INT2)
00072 #define LAN91_SIGNAL          sig_INTERRUPT2
00073 #elif (LAN91_SIGNAL_IRQ == INT3)
00074 #define LAN91_SIGNAL          sig_INTERRUPT3
00075 #elif (LAN91_SIGNAL_IRQ == INT4)
00076 #define LAN91_SIGNAL          sig_INTERRUPT4
00077 #elif (LAN91_SIGNAL_IRQ == INT5)
00078 #define LAN91_SIGNAL          sig_INTERRUPT5
00079 #elif (LAN91_SIGNAL_IRQ == INT6)
00080 #define LAN91_SIGNAL          sig_INTERRUPT6
00081 #elif (LAN91_SIGNAL_IRQ == INT7)
00082 #define LAN91_SIGNAL          sig_INTERRUPT7
00083 #endif
00084 
00085 /*
00086  * Determine poll timers.
00087  */
00088 #if !defined(LAN91_RX_POLLTIME)
00089 #if defined(LAN91_SIGNAL)
00090 #define LAN91_RX_POLLTIME   2000
00091 #else
00092 #define LAN91_RX_POLLTIME   200
00093 #endif
00094 #endif
00095 
00096 #if !defined(LAN91_TX_POLLTIME)
00097 #if defined(LAN91_SIGNAL)
00098 #define LAN91_TX_POLLTIME   5000
00099 #else
00100 #define LAN91_TX_POLLTIME   200
00101 #endif
00102 #endif
00103 
00104 
00109 
00110 #define nic_outlb(addr, val) (*(volatile uint8_t *)(addr) = (val))
00111 #define nic_outhb(addr, val) (*(volatile uint8_t *)((addr) + 1) = (val))
00112 #define nic_outwx(addr, val) (*(volatile uint16_t *)(addr) = (val))
00113 #define nic_outw(addr, val) { \
00114     *(volatile uint8_t *)(addr) = (uint8_t)(val); \
00115     *((volatile uint8_t *)(addr) + 1) = (uint8_t)((val) >> 8); \
00116 }
00117 
00118 #define nic_inlb(addr) (*(volatile uint8_t *)(addr))
00119 #define nic_inhb(addr) (*(volatile uint8_t *)((addr) + 1))
00120 #define nic_inw(addr) (*(volatile uint16_t *)(addr))
00121 
00122 #define nic_bs(bank)    nic_outlb(LAN91_BSR, bank)
00123 
00128 struct _NICINFO {
00129     HANDLE volatile ni_rx_rdy;      
00130     uint16_t ni_tx_cnt;             
00131 #ifdef NUT_PERFMON
00132     uint32_t ni_rx_packets;         
00133     uint32_t ni_tx_packets;         
00134     uint32_t ni_interrupts;         
00135     uint32_t ni_overruns;           
00136     uint32_t ni_rx_frame_errors;    
00137     uint32_t ni_rx_crc_errors;      
00138     uint32_t ni_rx_missed_errors;   
00139 #endif
00140 };
00141 
00145 typedef struct _NICINFO NICINFO;
00146 
00147 static HANDLE mutex;
00148 static HANDLE maq;
00149 
00160 static uint8_t NicPhyRegSelect(uint8_t reg, uint8_t we)
00161 {
00162     uint8_t rs;
00163     uint8_t msk;
00164     uint_fast8_t i;
00165 
00166     nic_bs(3);
00167     rs = (nic_inlb(LAN91_MGMT) & ~(LAN91_MGMT_MCLK | LAN91_MGMT_MDO)) | LAN91_MGMT_MDOE;
00168 
00169     /* Send idle pattern. */
00170     for (i = 0; i < 33; i++) {
00171         nic_outlb(LAN91_MGMT, rs | LAN91_MGMT_MDO);
00172         nic_outlb(LAN91_MGMT, rs | LAN91_MGMT_MDO | LAN91_MGMT_MCLK);
00173     }
00174 
00175     /* Send start sequence. */
00176     nic_outlb(LAN91_MGMT, rs);
00177     nic_outlb(LAN91_MGMT, rs | LAN91_MGMT_MCLK);
00178     nic_outlb(LAN91_MGMT, rs | LAN91_MGMT_MDO);
00179     nic_outlb(LAN91_MGMT, rs | LAN91_MGMT_MDO | LAN91_MGMT_MCLK);
00180 
00181     /* Write or read mode. */
00182     if (we) {
00183         nic_outlb(LAN91_MGMT, rs);
00184         nic_outlb(LAN91_MGMT, rs | LAN91_MGMT_MCLK);
00185         nic_outlb(LAN91_MGMT, rs | LAN91_MGMT_MDO);
00186         nic_outlb(LAN91_MGMT, rs | LAN91_MGMT_MDO | LAN91_MGMT_MCLK);
00187     } else {
00188         nic_outlb(LAN91_MGMT, rs | LAN91_MGMT_MDO);
00189         nic_outlb(LAN91_MGMT, rs | LAN91_MGMT_MDO | LAN91_MGMT_MCLK);
00190         nic_outlb(LAN91_MGMT, rs);
00191         nic_outlb(LAN91_MGMT, rs | LAN91_MGMT_MCLK);
00192     }
00193 
00194     /* Send PHY address. Zero is used for the internal PHY. */
00195     for (i = 0; i < 5; i++) {
00196         nic_outlb(LAN91_MGMT, rs);
00197         nic_outlb(LAN91_MGMT, rs | LAN91_MGMT_MCLK);
00198     }
00199 
00200     /* Send PHY register number. */
00201     for (msk = 0x10; msk; msk >>= 1) {
00202         if (reg & msk) {
00203             nic_outlb(LAN91_MGMT, rs | LAN91_MGMT_MDO);
00204             nic_outlb(LAN91_MGMT, rs | LAN91_MGMT_MDO | LAN91_MGMT_MCLK);
00205         } else {
00206             nic_outlb(LAN91_MGMT, rs);
00207             nic_outlb(LAN91_MGMT, rs | LAN91_MGMT_MCLK);
00208         }
00209     }
00210     nic_outlb(LAN91_MGMT, rs);
00211 
00212     return rs;
00213 }
00214 
00224 static uint16_t NicPhyRead(uint8_t reg)
00225 {
00226     uint16_t rc = 0;
00227     uint8_t rs;
00228     uint_fast8_t i;
00229 
00230     /* Select register for reading. */
00231     rs = NicPhyRegSelect(reg, 0);
00232 
00233     /* Switch data direction. */
00234     rs &= ~LAN91_MGMT_MDOE;
00235     nic_outlb(LAN91_MGMT, rs);
00236     nic_outlb(LAN91_MGMT, rs | LAN91_MGMT_MCLK);
00237 
00238     /* Clock data in. */
00239     for (i = 0; i < 16; i++) {
00240         nic_outlb(LAN91_MGMT, rs);
00241         nic_outlb(LAN91_MGMT, rs | LAN91_MGMT_MCLK);
00242         rc <<= 1;
00243         rc |= (nic_inlb(LAN91_MGMT) & LAN91_MGMT_MDI) != 0;
00244     }
00245 
00246     /* This will set the clock line to low. */
00247     nic_outlb(LAN91_MGMT, rs);
00248 
00249     return rc;
00250 }
00251 
00260 static void NicPhyWrite(uint8_t reg, uint16_t val)
00261 {
00262     uint16_t msk;
00263     uint8_t rs;
00264 
00265     /* Select register for writing. */
00266     rs = NicPhyRegSelect(reg, 1);
00267 
00268     /* Switch data direction dummy. */
00269     nic_outlb(LAN91_MGMT, rs | LAN91_MGMT_MDO);
00270     nic_outlb(LAN91_MGMT, rs | LAN91_MGMT_MDO | LAN91_MGMT_MCLK);
00271     nic_outlb(LAN91_MGMT, rs);
00272     nic_outlb(LAN91_MGMT, rs | LAN91_MGMT_MCLK);
00273 
00274     /* Clock data out. */
00275     for (msk = 0x8000; msk; msk >>= 1) {
00276         if (val & msk) {
00277             nic_outlb(LAN91_MGMT, rs | LAN91_MGMT_MDO);
00278             nic_outlb(LAN91_MGMT, rs | LAN91_MGMT_MDO | LAN91_MGMT_MCLK);
00279         } else {
00280             nic_outlb(LAN91_MGMT, rs);
00281             nic_outlb(LAN91_MGMT, rs | LAN91_MGMT_MCLK);
00282         }
00283     }
00284 
00285     /* Set clock line low and output line int z-state. */
00286     nic_outlb(LAN91_MGMT, rs & ~LAN91_MGMT_MDOE);
00287 }
00288 
00294 static int NicPhyConfig(void)
00295 {
00296     uint16_t phy_sr;
00297     uint16_t phy_to;
00298     uint16_t mode;
00299 
00300     /* 
00301      * Reset the PHY and wait until this self clearing bit
00302      * becomes zero. We sleep 63 ms before each poll and
00303      * give up after 3 retries. 
00304      */
00305     NicPhyWrite(LAN91_PHYCR, LAN91_PHYCR_RST);
00306     for (phy_to = 0;; phy_to++) {
00307         NutSleep(63);
00308         if ((NicPhyRead(LAN91_PHYCR) & LAN91_PHYCR_RST) == 0)
00309             break;
00310         if (phy_to > 3)
00311             return -1;
00312     }
00313 
00314     /* Enable PHY interrupts. */
00315     NicPhyWrite(LAN91_PHYMSK, LAN91_PHYMSK_MLOSSSYN | LAN91_PHYMSK_MCWRD | LAN91_PHYMSK_MSSD |
00316                 LAN91_PHYMSK_MESD | LAN91_PHYMSK_MRPOL | LAN91_PHYMSK_MJAB | LAN91_PHYMSK_MSPDDT | LAN91_PHYMSK_MDPLDT);
00317 
00318     /* Set RPC register. */
00319     mode = LAN91_RPCR_ANEG | LAN91_RPCR_LEDA_PAT | LAN91_RPCR_LEDB_PAT;
00320     nic_bs(0);
00321     nic_outw(LAN91_RPCR, mode);
00322 
00323 #ifdef LAN91_FIXED
00324     /* Disable link. */
00325     phy_sr = NicPhyRead(LAN91_PHYCFR1);
00326     NicPhyWrite(LAN91_PHYCFR1, phy_sr | 0x8000);
00327     NutSleep(63);
00328 
00329     /* Set fixed capabilities. */
00330     NicPhyWrite(LAN91_PHYCR, LAN91_FIXED);
00331     nic_bs(0);
00332     nic_outw(LAN91_RPCR, mode);
00333 
00334     /* Enable link. */
00335     phy_sr = NicPhyRead(LAN91_PHYCFR1);
00336     NicPhyWrite(LAN91_PHYCFR1, phy_sr & ~0x8000);
00337     phy_sr = NicPhyRead(LAN91_PHYCFR1);
00338 
00339 #else
00340     /*
00341      * Advertise our capabilities, initiate auto negotiation
00342      * and wait until this has been completed.
00343      */
00344     NicPhyWrite(LAN91_PHYANAD, LAN91_PHYANAD_TX_FDX | LAN91_PHYANAD_TX_HDX | LAN91_PHYANAD_10FDX | LAN91_PHYANAD_10_HDX | LAN91_PHYANAD_CSMA);
00345     NutSleep(63);
00346     for (phy_to = 0, phy_sr = 0;; phy_to++) {
00347         /* Give up after 10 seconds. */
00348         if (phy_to >= 1024)
00349             return -1;
00350         /* Restart auto negotiation every 4 seconds or on failures. */
00351         if ((phy_to & 127) == 0 /* || (phy_sr & LAN91_PHYSR_REM_FLT) != 0 */ ) {
00352             NicPhyWrite(LAN91_PHYCR, LAN91_PHYCR_ANEG_EN | LAN91_PHYCR_ANEG_RST);
00353             NutSleep(63);
00354         }
00355         /* Check if we are done. */
00356         phy_sr = NicPhyRead(LAN91_PHYSR);
00357         if (phy_sr & LAN91_PHYSR_ANEG_ACK)
00358             break;
00359         NutSleep(63);
00360     }
00361 #endif
00362 
00363     return 0;
00364 }
00365 
00376 static INLINE int NicMmuWait(uint_fast16_t tmo)
00377 {
00378     while (tmo--) {
00379         if ((nic_inlb(LAN91_MMUCR) & LAN91_MMUCR_BUSY) == 0)
00380             break;
00381         NutDelay(1);
00382     }
00383     return tmo ? 0 : -1;
00384 }
00385 
00391 static int NicReset(void)
00392 {
00393 #ifdef LAN91_RESET_BIT
00394     GpioPinConfigSet(LAN91_RESET_GPIO_BANK, LAN91_RESET_GPIO_BIT, GPIO_CFG_OUTPUT);
00395     GpioPinSet(LAN91_RESET_GPIO_BANK, LAN91_RESET_GPIO_BIT, 1);
00396     NutDelay(10);
00397     GpioPinSet(LAN91_RESET_GPIO_BANK, LAN91_RESET_GPIO_BIT, 0);
00398     NutDelay(100);
00399 #endif
00400 
00401     /* Disable all interrupts. */
00402     nic_outlb(LAN91_MSK, 0);
00403 
00404     /* MAC and PHY software reset. */
00405     nic_bs(0);
00406     nic_outw(LAN91_RCR, LAN91_RCR_SOFT_RST);
00407 
00408     /* Enable Ethernet protocol handler. */
00409     nic_bs(1);
00410     nic_outw(LAN91_CR, LAN91_CR_EPH_EN);
00411 
00412     NutDelay(10);
00413 
00414     /* Disable transmit and receive. */
00415     nic_bs(0);
00416     nic_outw(LAN91_RCR, 0);
00417     nic_outw(LAN91_TCR, 0);
00418 
00419     /* Enable auto release. */
00420     nic_bs(1);
00421     nic_outw(LAN91_CTR, LAN91_CTR_AUTO_RELEASE);
00422 
00423     /* Reset MMU. */
00424     nic_bs(2);
00425     nic_outlb(LAN91_MMUCR, LAN91_MMU_RST);
00426     if (NicMmuWait(1000))
00427         return -1;
00428 
00429     return 0;
00430 }
00431 
00432 /*
00433  * Fires up the network interface. NIC interrupts
00434  * should have been disabled when calling this
00435  * function.
00436  *
00437  * \param mac Six byte unique MAC address.
00438  */
00439 static int NicStart(CONST uint8_t * mac)
00440 {
00441     uint_fast8_t i;
00442 
00443     if (NicReset())
00444         return -1;
00445 
00446     /* Enable receiver. */
00447     nic_bs(3);
00448     nic_outlb(LAN91_ERCV, 7);
00449     nic_bs(0);
00450     nic_outw(LAN91_RCR, LAN91_RCR_RXEN);
00451 
00452     /* Enable transmitter and padding. */
00453     nic_outw(LAN91_TCR, LAN91_TCR_PAD_EN | LAN91_TCR_TXENA);
00454 
00455     /* Configure the PHY. */
00456     if (NicPhyConfig())
00457         return -1;
00458 
00459     /* Set MAC address. */
00460     nic_bs(1);
00461     for (i = 0; i < 6; i++)
00462         nic_outlb(LAN91_IAR + i, mac[i]);
00463 
00464     /* Enable interrupts. */
00465     nic_bs(2);
00466     nic_outlb(LAN91_MSK, LAN91_INT_ERCV | LAN91_INT_RCV | LAN91_INT_RX_OVRN);
00467 
00468     return 0;
00469 }
00470 
00471 #if defined(LAN91_SIGNAL)
00472 /*
00473  * NIC interrupt entry.
00474  */
00475 static void NicInterrupt(void *arg)
00476 {
00477     uint8_t isr;
00478     uint8_t imr;
00479     NICINFO *ni = (NICINFO *) ((NUTDEVICE *) arg)->dev_dcb;
00480 
00481 #ifdef NUT_PERFMON
00482     ni->ni_interrupts++;
00483 #endif
00484     /* Read the interrupt mask and disable all interrupts. */
00485     nic_bs(2);
00486     imr = nic_inlb(LAN91_MSK);
00487     nic_outlb(LAN91_MSK, 0);
00488 
00489     /* Read the interrupt status and acknowledge all interrupts. */
00490     isr = nic_inlb(LAN91_IST);
00491     isr &= imr;
00492 
00493     /*
00494      * If this is a transmit interrupt, then a packet has been sent. 
00495      * So we can clear the transmitter busy flag and wake up the 
00496      * transmitter thread.
00497      */
00498     if (isr & LAN91_INT_TX_EMPTY) {
00499         nic_outlb(LAN91_ACK, LAN91_INT_TX_EMPTY);
00500         imr &= ~LAN91_INT_TX_EMPTY;
00501     }
00502     /* Transmit error. */
00503     else if (isr & LAN91_INT_TX) {
00504         /* re-enable transmit */
00505         nic_bs(0);
00506         nic_outw(LAN91_TCR, nic_inlb(LAN91_TCR) | LAN91_TCR_TXENA);
00507         nic_bs(2);
00508         nic_outlb(LAN91_ACK, LAN91_INT_TX);
00509         /* kill the packet */
00510         nic_outlb(LAN91_MMUCR, LAN91_MMU_PKT);
00511     }
00512 
00513 
00514     /*
00515      * If this is a receive interrupt, then wake up the receiver 
00516      * thread.
00517      */
00518     if (isr & LAN91_INT_RX_OVRN) {
00519         nic_outlb(LAN91_ACK, LAN91_INT_RX_OVRN);
00520         NutEventPostFromIrq(&ni->ni_rx_rdy);
00521     }
00522     if (isr & LAN91_INT_ERCV) {
00523         nic_outlb(LAN91_ACK, LAN91_INT_ERCV);
00524         NutEventPostFromIrq(&ni->ni_rx_rdy);
00525     }
00526     if (isr & LAN91_INT_RCV) {
00527         nic_outlb(LAN91_ACK, LAN91_INT_RCV);
00528         imr &= ~LAN91_INT_RCV;
00529         NutEventPostFromIrq(&ni->ni_rx_rdy);
00530     }
00531 
00532     if (isr & LAN91_INT_ALLOC) {
00533         imr &= ~LAN91_INT_ALLOC;
00534         NutEventPostFromIrq(&maq);
00535     }
00536     nic_outlb(LAN91_MSK, imr);
00537 }
00538 #endif
00539 
00540 /*
00541  * Write data block to the NIC.
00542  */
00543 static void NicWrite(uint8_t * buf, uint16_t len)
00544 {
00545     register uint16_t l = len - 1;
00546     register uint8_t ih = (uint16_t) l >> 8;
00547     register uint8_t il = (uint8_t) l;
00548 
00549     if (!len)
00550         return;
00551 
00552     do {
00553         do {
00554             nic_outlb(LAN91_DATA, *buf++);
00555         } while (il-- != 0);
00556     } while (ih-- != 0);
00557 }
00558 
00559 /*
00560  * Read data block from the NIC.
00561  */
00562 static void NicRead(uint8_t * buf, uint16_t len)
00563 {
00564     register uint16_t l = len - 1;
00565     register uint8_t ih = (uint16_t) l >> 8;
00566     register uint8_t il = (uint8_t) l;
00567 
00568     if (!len)
00569         return;
00570 
00571     do {
00572         do {
00573             *buf++ = nic_inlb(LAN91_DATA);
00574         } while (il-- != 0);
00575     } while (ih-- != 0);
00576 }
00577 
00588 static NETBUF *NicGetPacket(void)
00589 {
00590     NETBUF *nb = 0;
00591     uint16_t fsw;
00592     uint16_t fbc;
00593 
00594     /* Check the fifo empty bit. If it is set, then there is 
00595        nothing in the receiver fifo. */
00596     nic_bs(2);
00597     if (nic_inw(LAN91_FIFO) & 0x8000) {
00598         return 0;
00599     }
00600 
00601     /* Inialize pointer register. */
00602     nic_outw(LAN91_PTR, LAN91_PTR_READ | LAN91_PTR_RCV | LAN91_PTR_AUTO_INCR);
00603     _NOP();
00604     _NOP();
00605     _NOP();
00606     _NOP();
00607 
00608     /* Read status word and byte count. */
00609     fsw = nic_inw(LAN91_DATA);
00610     fbc = nic_inw(LAN91_DATA);
00611 
00612     /* Check for frame errors. */
00613     if (fsw & 0xAC00) {
00614         nb = (NETBUF *) 0xFFFF;
00615     }
00616     /* Check the byte count. */
00617     else if (fbc < 66 || fbc > 1524) {
00618         nb = (NETBUF *) 0xFFFF;
00619     }
00620 
00621     else {
00622         /* 
00623          * Allocate a NETBUF. 
00624          * Hack alert: Rev A chips never set the odd frame indicator.
00625          */
00626         fbc -= 3;
00627         nb = NutNetBufAlloc(0, NBAF_DATALINK, fbc);
00628 
00629         /* Perform the read. */
00630         if (nb)
00631             NicRead(nb->nb_dl.vp, fbc);
00632     }
00633 
00634     /* Release the packet. */
00635     nic_outlb(LAN91_MMUCR, LAN91_MMU_TOP);
00636 
00637     return nb;
00638 }
00639 
00654 static int NicPutPacket(NETBUF * nb)
00655 {
00656     uint16_t sz;
00657     uint_fast8_t odd = 0;
00658     uint8_t imsk;
00659 
00660     /*
00661      * Calculate the number of bytes to be send. Do not send packets 
00662      * larger than the Ethernet maximum transfer unit. The MTU
00663      * consist of 1500 data bytes plus the 14 byte Ethernet header
00664      * plus 4 bytes CRC. We check the data bytes only.
00665      */
00666     if ((sz = nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz) > ETHERMTU)
00667         return -1;
00668 
00669     /* Disable all interrupts. */
00670     imsk = nic_inlb(LAN91_MSK);
00671     nic_outlb(LAN91_MSK, 0);
00672 
00673     /* Allocate packet buffer space. */
00674     nic_bs(2);
00675     nic_outlb(LAN91_MMUCR, LAN91_MMU_ALO);
00676     if (NicMmuWait(100))
00677         return -1;
00678 
00679     /* Enable interrupts including allocation success. */
00680     nic_outlb(LAN91_MSK, imsk | LAN91_INT_ALLOC);
00681 
00682     /* The MMU needs some time. Use it to calculate the byte count. */
00683     sz += nb->nb_dl.sz;
00684     sz += 6;
00685     if (sz & 1) {
00686         sz++;
00687         odd++;
00688     }
00689 
00690     /* Wait for allocation success. */
00691     while ((nic_inlb(LAN91_IST) & LAN91_INT_ALLOC) == 0) {
00692         if (NutEventWait(&maq, 125)) {
00693             nic_outlb(LAN91_MMUCR, LAN91_MMU_RST);
00694             NicMmuWait(1000);
00695             nic_outlb(LAN91_MMUCR, LAN91_MMU_ALO);
00696             if (NicMmuWait(100) || (nic_inlb(LAN91_IST) & LAN91_INT_ALLOC) == 0) {
00697                 if (NutEventWait(&maq, 125)) {
00698                     return -1;
00699                 }
00700             }
00701         }
00702     }
00703 
00704     /* Disable interrupts. */
00705     imsk = nic_inlb(LAN91_MSK);
00706     nic_outlb(LAN91_MSK, 0);
00707 
00708 
00709     nic_outlb(LAN91_PNR, nic_inhb(LAN91_PNR));
00710 
00711     nic_outw(LAN91_PTR, 0x4000);
00712 
00713     /* Transfer control word. */
00714     nic_outlb(LAN91_DATA, 0);
00715     nic_outlb(LAN91_DATA, 0);
00716 
00717     /* Transfer the byte count. */
00718     nic_outw(LAN91_DATA, sz);
00719 
00720     /* Transfer the Ethernet frame. */
00721     NicWrite(nb->nb_dl.vp, nb->nb_dl.sz);
00722     NicWrite(nb->nb_nw.vp, nb->nb_nw.sz);
00723     NicWrite(nb->nb_tp.vp, nb->nb_tp.sz);
00724     NicWrite(nb->nb_ap.vp, nb->nb_ap.sz);
00725 
00726     if (odd)
00727         nic_outlb(LAN91_DATA, 0);
00728 
00729     /* Transfer the control word. */
00730     nic_outw(LAN91_DATA, 0);
00731 
00732     /* Enqueue packet. */
00733     if (NicMmuWait(100))
00734         return -1;
00735     nic_outlb(LAN91_MMUCR, LAN91_MMU_ENQ);
00736 
00737     /* Enable interrupts. */
00738     imsk |= LAN91_INT_TX | LAN91_INT_TX_EMPTY;
00739     nic_outlb(LAN91_MSK, imsk);
00740 
00741     return 0;
00742 }
00743 
00744 
00749 THREAD(NicRxLanc, arg)
00750 {
00751     NUTDEVICE *dev;
00752     IFNET *ifn;
00753     NICINFO *ni;
00754     NETBUF *nb;
00755     uint8_t imsk;
00756 
00757     dev = arg;
00758     ifn = (IFNET *) dev->dev_icb;
00759     ni = (NICINFO *) dev->dev_dcb;
00760 
00761     /*
00762      * This is a temporary hack. Due to a change in initialization,
00763      * we may not have got a MAC address yet. Wait until a valid one
00764      * has been set.
00765      */
00766     while (!ETHER_IS_UNICAST(ifn->if_mac)) {
00767         NutSleep(10);
00768     }
00769 
00770     /*
00771      * Do not continue unless we managed to start the NIC. We are
00772      * trapped here if the Ethernet link cannot be established.
00773      * This happens, for example, if no Ethernet cable is plugged
00774      * in.
00775      */
00776     while(NicStart(ifn->if_mac)) {
00777         NutSleep(1000);
00778     }
00779 
00780 #ifdef LAN91_SIGNAL
00781     NutIrqSetMode(&LAN91_SIGNAL, NUT_IRQMODE_RISINGEDGE);
00782     NutIrqEnable(&LAN91_SIGNAL);
00783 #endif
00784 
00785     NutEventPost(&mutex);
00786 
00787     /* Run at high priority. */
00788     NutThreadSetPriority(9);
00789 
00790     for (;;) {
00791         /*
00792          * Wait for the arrival of new packets or
00793          * check the receiver every two second.
00794          */
00795         NutEventWait(&ni->ni_rx_rdy, LAN91_RX_POLLTIME);
00796 
00797         /*
00798          * Fetch all packets from the NIC's internal
00799          * buffer and pass them to the registered handler.
00800          */
00801         imsk = nic_inlb(LAN91_MSK);
00802         nic_outlb(LAN91_MSK, 0);
00803         while ((nb = NicGetPacket()) != 0) {
00804             if (nb != (NETBUF *) 0xFFFF) {
00805 #ifdef NUT_PERFMON
00806                 ni->ni_rx_packets++;
00807 #endif
00808                 (*ifn->if_recv) (dev, nb);
00809             }
00810         }
00811         nic_outlb(LAN91_MSK, imsk | LAN91_INT_RCV | LAN91_INT_ERCV);
00812     }
00813 }
00814 
00825 static int Lan91Output(NUTDEVICE * dev, NETBUF * nb)
00826 {
00827     static uint_fast16_t mx_wait = LAN91_TX_POLLTIME;
00828     int rc = -1;
00829 
00830     /*
00831      * After initialization we are waiting for a long time to give
00832      * the PHY a chance to establish an Ethernet link.
00833      */
00834     if (NutEventWait(&mutex, mx_wait) == 0) {
00835 
00836         if (NicPutPacket(nb) == 0) {
00837 #ifdef NUT_PERFMON
00838             NICINFO *ni = (NICINFO *) dev->dev_dcb;
00839             ni->ni_tx_packets++;
00840 #endif
00841             rc = 0;
00842             /* Ethernet works. Set a long waiting time in case we
00843                temporarly lose the link next time. */
00844             mx_wait = LAN91_TX_POLLTIME;
00845         }
00846         NutEventPost(&mutex);
00847     }
00848 #if defined(LAN91_SIGNAL)
00849     /*
00850      * Probably no Ethernet link. Significantly reduce the waiting
00851      * time, so following transmission will soon return an error.
00852      */
00853     else {
00854         mx_wait = 500;
00855     }
00856 #endif
00857     return rc;
00858 }
00859 
00877 static int Lan91Init(NUTDEVICE * dev)
00878 {
00879     /* Disable NIC interrupt and clear NICINFO structure. */
00880 #ifdef LAN91_SIGNAL
00881     NutIrqDisable(&LAN91_SIGNAL);
00882 #endif
00883     memset(dev->dev_dcb, 0, sizeof(NICINFO));
00884 
00885 #ifdef LAN91_SIGNAL
00886     /* Register interrupt handler and enable interrupts. */
00887     if (NutRegisterIrqHandler(&LAN91_SIGNAL, NicInterrupt, dev))
00888         return -1;
00889 #endif
00890 
00891     /*
00892      * Start the receiver thread.
00893      */
00894     NutThreadCreate("lan91rx", NicRxLanc, dev, 640);
00895 
00896     return 0;
00897 }
00898 
00899 static int Lan91IOCtl(NUTDEVICE * dev, int req, void *conf)
00900 {
00901     int rc = 0;
00902     uint32_t *lvp = (uint32_t *) conf;
00903     IFNET *nif = (IFNET *) dev->dev_icb;
00904 
00905     switch (req) {
00906     case SIOCSIFFLAGS:
00907         /* Set interface flags. */
00908         if (*lvp & IFF_UP) {
00909             if ((nif->if_flags & IFF_UP) == 0) {
00910                 /* Start interface. */
00911             }
00912         } else if (nif->if_flags & IFF_UP) {
00913             /* Stop interface. */
00914         }
00915         break;
00916     case SIOCGIFFLAGS:
00917         /* Get interface flags. */
00918         *lvp = nif->if_flags;
00919         break;
00920     case SIOCSIFADDR:
00921         /* Set interface hardware address. */
00922         memcpy(nif->if_mac, conf, sizeof(nif->if_mac));
00923         break;
00924     case SIOCGIFADDR:
00925         /* Get interface hardware address. */
00926         memcpy(conf, nif->if_mac, sizeof(nif->if_mac));
00927         break;
00928     default:
00929         rc = -1;
00930         break;
00931     }
00932     return rc;
00933 }
00934 
00935 static NICINFO dcb_eth0;
00936 
00942 static IFNET ifn_eth0 = {
00943     IFT_ETHER,          
00944     0,                  
00945     {0, 0, 0, 0, 0, 0}, 
00946     0,                  
00947     0,                  
00948     0,                  
00949     ETHERMTU,           
00950     0,                  
00951     0,                  
00952     0,                  
00953     NutEtherInput,      
00954     Lan91Output,        
00955     NutEtherOutput,     
00956     NULL                
00957 };
00958 
00968 NUTDEVICE devLan91 = {
00969     0,          /* Pointer to next device. */
00970     {'e', 't', 'h', '0', 0, 0, 0, 0, 0},        /* Unique device name. */
00971     IFTYP_NET,  /* Type of device. */
00972     0,          /* Base address. */
00973     0,          /* First interrupt number. */
00974     &ifn_eth0,  /* Interface control block. */
00975     &dcb_eth0,  /* Driver control block. */
00976     Lan91Init,  /* Driver initialization routine. */
00977     Lan91IOCtl, /* Driver specific control function. */
00978     0,          /* Read from device. */
00979     0,          /* Write to device. */
00980 #ifdef __HARVARD_ARCH__
00981     0,          /* Write from program space data to device. */
00982 #endif
00983     0,          /* Open a device or file. */
00984     0,          /* Close a device or file. */
00985     0           /* Request file size. */
00986 };
00987