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 2761 2009-10-18 18:11:36Z 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_sor;
00297     uint16_t phy_sr;
00298     uint16_t phy_to;
00299     uint16_t mode;
00300 
00301     /* 
00302      * Reset the PHY and wait until this self clearing bit
00303      * becomes zero. We sleep 63 ms before each poll and
00304      * give up after 3 retries. 
00305      */
00306     NicPhyWrite(LAN91_PHYCR, LAN91_PHYCR_RST);
00307     for (phy_to = 0;; phy_to++) {
00308         NutSleep(63);
00309         if ((NicPhyRead(LAN91_PHYCR) & LAN91_PHYCR_RST) == 0)
00310             break;
00311         if (phy_to > 3)
00312             return -1;
00313     }
00314 
00315     /* Store PHY status output. */
00316     phy_sor = NicPhyRead(LAN91_PHYSOR);
00317 
00318     /* Enable PHY interrupts. */
00319     NicPhyWrite(LAN91_PHYMSK, LAN91_PHYMSK_MLOSSSYN | LAN91_PHYMSK_MCWRD | LAN91_PHYMSK_MSSD |
00320                 LAN91_PHYMSK_MESD | LAN91_PHYMSK_MRPOL | LAN91_PHYMSK_MJAB | LAN91_PHYMSK_MSPDDT | LAN91_PHYMSK_MDPLDT);
00321 
00322     /* Set RPC register. */
00323     mode = LAN91_RPCR_ANEG | LAN91_RPCR_LEDA_PAT | LAN91_RPCR_LEDB_PAT;
00324     nic_bs(0);
00325     nic_outw(LAN91_RPCR, mode);
00326 
00327 #ifdef LAN91_FIXED
00328     /* Disable link. */
00329     phy_sr = NicPhyRead(LAN91_PHYCFR1);
00330     NicPhyWrite(LAN91_PHYCFR1, phy_sr | 0x8000);
00331     NutSleep(63);
00332 
00333     /* Set fixed capabilities. */
00334     NicPhyWrite(LAN91_PHYCR, LAN91_FIXED);
00335     nic_bs(0);
00336     nic_outw(LAN91_RPCR, mode);
00337 
00338     /* Enable link. */
00339     phy_sr = NicPhyRead(LAN91_PHYCFR1);
00340     NicPhyWrite(LAN91_PHYCFR1, phy_sr & ~0x8000);
00341     phy_sr = NicPhyRead(LAN91_PHYCFR1);
00342 
00343 #else
00344     /*
00345      * Advertise our capabilities, initiate auto negotiation
00346      * and wait until this has been completed.
00347      */
00348     NicPhyWrite(LAN91_PHYANAD, LAN91_PHYANAD_TX_FDX | LAN91_PHYANAD_TX_HDX | LAN91_PHYANAD_10FDX | LAN91_PHYANAD_10_HDX | LAN91_PHYANAD_CSMA);
00349     NutSleep(63);
00350     for (phy_to = 0, phy_sr = 0;; phy_to++) {
00351         /* Give up after 10 seconds. */
00352         if (phy_to >= 1024)
00353             return -1;
00354         /* Restart auto negotiation every 4 seconds or on failures. */
00355         if ((phy_to & 127) == 0 /* || (phy_sr & LAN91_PHYSR_REM_FLT) != 0 */ ) {
00356             NicPhyWrite(LAN91_PHYCR, LAN91_PHYCR_ANEG_EN | LAN91_PHYCR_ANEG_RST);
00357             NutSleep(63);
00358         }
00359         /* Check if we are done. */
00360         phy_sr = NicPhyRead(LAN91_PHYSR);
00361         if (phy_sr & LAN91_PHYSR_ANEG_ACK)
00362             break;
00363         NutSleep(63);
00364     }
00365 #endif
00366 
00367     return 0;
00368 }
00369 
00380 static INLINE int NicMmuWait(uint_fast16_t tmo)
00381 {
00382     while (tmo--) {
00383         if ((nic_inlb(LAN91_MMUCR) & LAN91_MMUCR_BUSY) == 0)
00384             break;
00385         NutDelay(1);
00386     }
00387     return tmo ? 0 : -1;
00388 }
00389 
00395 static int NicReset(void)
00396 {
00397 #ifdef LAN91_RESET_BIT
00398     GpioPinConfigSet(LAN91_RESET_GPIO_BANK, LAN91_RESET_GPIO_BIT, GPIO_CFG_OUTPUT);
00399     GpioPinSet(LAN91_RESET_GPIO_BANK, LAN91_RESET_GPIO_BIT, 1);
00400     NutDelay(10);
00401     GpioPinSet(LAN91_RESET_GPIO_BANK, LAN91_RESET_GPIO_BIT, 0);
00402     NutDelay(100);
00403 #endif
00404 
00405     /* Disable all interrupts. */
00406     nic_outlb(LAN91_MSK, 0);
00407 
00408     /* MAC and PHY software reset. */
00409     nic_bs(0);
00410     nic_outw(LAN91_RCR, LAN91_RCR_SOFT_RST);
00411 
00412     /* Enable Ethernet protocol handler. */
00413     nic_bs(1);
00414     nic_outw(LAN91_CR, LAN91_CR_EPH_EN);
00415 
00416     NutDelay(10);
00417 
00418     /* Disable transmit and receive. */
00419     nic_bs(0);
00420     nic_outw(LAN91_RCR, 0);
00421     nic_outw(LAN91_TCR, 0);
00422 
00423     /* Enable auto release. */
00424     nic_bs(1);
00425     nic_outw(LAN91_CTR, LAN91_CTR_AUTO_RELEASE);
00426 
00427     /* Reset MMU. */
00428     nic_bs(2);
00429     nic_outlb(LAN91_MMUCR, LAN91_MMU_RST);
00430     if (NicMmuWait(1000))
00431         return -1;
00432 
00433     return 0;
00434 }
00435 
00436 /*
00437  * Fires up the network interface. NIC interrupts
00438  * should have been disabled when calling this
00439  * function.
00440  *
00441  * \param mac Six byte unique MAC address.
00442  */
00443 static int NicStart(CONST uint8_t * mac)
00444 {
00445     uint_fast8_t i;
00446 
00447     if (NicReset())
00448         return -1;
00449 
00450     /* Enable receiver. */
00451     nic_bs(3);
00452     nic_outlb(LAN91_ERCV, 7);
00453     nic_bs(0);
00454     nic_outw(LAN91_RCR, LAN91_RCR_RXEN);
00455 
00456     /* Enable transmitter and padding. */
00457     nic_outw(LAN91_TCR, LAN91_TCR_PAD_EN | LAN91_TCR_TXENA);
00458 
00459     /* Configure the PHY. */
00460     if (NicPhyConfig())
00461         return -1;
00462 
00463     /* Set MAC address. */
00464     nic_bs(1);
00465     for (i = 0; i < 6; i++)
00466         nic_outlb(LAN91_IAR + i, mac[i]);
00467 
00468     /* Enable interrupts. */
00469     nic_bs(2);
00470     nic_outlb(LAN91_MSK, LAN91_INT_ERCV | LAN91_INT_RCV | LAN91_INT_RX_OVRN);
00471 
00472     return 0;
00473 }
00474 
00475 #if defined(LAN91_SIGNAL)
00476 /*
00477  * NIC interrupt entry.
00478  */
00479 static void NicInterrupt(void *arg)
00480 {
00481     uint8_t isr;
00482     uint8_t imr;
00483     NICINFO *ni = (NICINFO *) ((NUTDEVICE *) arg)->dev_dcb;
00484 
00485 #ifdef NUT_PERFMON
00486     ni->ni_interrupts++;
00487 #endif
00488     /* Read the interrupt mask and disable all interrupts. */
00489     nic_bs(2);
00490     imr = nic_inlb(LAN91_MSK);
00491     nic_outlb(LAN91_MSK, 0);
00492 
00493     /* Read the interrupt status and acknowledge all interrupts. */
00494     isr = nic_inlb(LAN91_IST);
00495     isr &= imr;
00496 
00497     /*
00498      * If this is a transmit interrupt, then a packet has been sent. 
00499      * So we can clear the transmitter busy flag and wake up the 
00500      * transmitter thread.
00501      */
00502     if (isr & LAN91_INT_TX_EMPTY) {
00503         nic_outlb(LAN91_ACK, LAN91_INT_TX_EMPTY);
00504         imr &= ~LAN91_INT_TX_EMPTY;
00505     }
00506     /* Transmit error. */
00507     else if (isr & LAN91_INT_TX) {
00508         /* re-enable transmit */
00509         nic_bs(0);
00510         nic_outw(LAN91_TCR, nic_inlb(LAN91_TCR) | LAN91_TCR_TXENA);
00511         nic_bs(2);
00512         nic_outlb(LAN91_ACK, LAN91_INT_TX);
00513         /* kill the packet */
00514         nic_outlb(LAN91_MMUCR, LAN91_MMU_PKT);
00515     }
00516 
00517 
00518     /*
00519      * If this is a receive interrupt, then wake up the receiver 
00520      * thread.
00521      */
00522     if (isr & LAN91_INT_RX_OVRN) {
00523         nic_outlb(LAN91_ACK, LAN91_INT_RX_OVRN);
00524         NutEventPostFromIrq(&ni->ni_rx_rdy);
00525     }
00526     if (isr & LAN91_INT_ERCV) {
00527         nic_outlb(LAN91_ACK, LAN91_INT_ERCV);
00528         NutEventPostFromIrq(&ni->ni_rx_rdy);
00529     }
00530     if (isr & LAN91_INT_RCV) {
00531         nic_outlb(LAN91_ACK, LAN91_INT_RCV);
00532         imr &= ~LAN91_INT_RCV;
00533         NutEventPostFromIrq(&ni->ni_rx_rdy);
00534     }
00535 
00536     if (isr & LAN91_INT_ALLOC) {
00537         imr &= ~LAN91_INT_ALLOC;
00538         NutEventPostFromIrq(&maq);
00539     }
00540     nic_outlb(LAN91_MSK, imr);
00541 }
00542 #endif
00543 
00544 /*
00545  * Write data block to the NIC.
00546  */
00547 static void NicWrite(uint8_t * buf, uint16_t len)
00548 {
00549     register uint16_t l = len - 1;
00550     register uint8_t ih = (uint16_t) l >> 8;
00551     register uint8_t il = (uint8_t) l;
00552 
00553     if (!len)
00554         return;
00555 
00556     do {
00557         do {
00558             nic_outlb(LAN91_DATA, *buf++);
00559         } while (il-- != 0);
00560     } while (ih-- != 0);
00561 }
00562 
00563 /*
00564  * Read data block from the NIC.
00565  */
00566 static void NicRead(uint8_t * buf, uint16_t len)
00567 {
00568     register uint16_t l = len - 1;
00569     register uint8_t ih = (uint16_t) l >> 8;
00570     register uint8_t il = (uint8_t) l;
00571 
00572     if (!len)
00573         return;
00574 
00575     do {
00576         do {
00577             *buf++ = nic_inlb(LAN91_DATA);
00578         } while (il-- != 0);
00579     } while (ih-- != 0);
00580 }
00581 
00592 static NETBUF *NicGetPacket(void)
00593 {
00594     NETBUF *nb = 0;
00595     uint16_t fsw;
00596     uint16_t fbc;
00597 
00598     /* Check the fifo empty bit. If it is set, then there is 
00599        nothing in the receiver fifo. */
00600     nic_bs(2);
00601     if (nic_inw(LAN91_FIFO) & 0x8000) {
00602         return 0;
00603     }
00604 
00605     /* Inialize pointer register. */
00606     nic_outw(LAN91_PTR, LAN91_PTR_READ | LAN91_PTR_RCV | LAN91_PTR_AUTO_INCR);
00607     _NOP();
00608     _NOP();
00609     _NOP();
00610     _NOP();
00611 
00612     /* Read status word and byte count. */
00613     fsw = nic_inw(LAN91_DATA);
00614     fbc = nic_inw(LAN91_DATA);
00615 
00616     /* Check for frame errors. */
00617     if (fsw & 0xAC00) {
00618         nb = (NETBUF *) 0xFFFF;
00619     }
00620     /* Check the byte count. */
00621     else if (fbc < 66 || fbc > 1524) {
00622         nb = (NETBUF *) 0xFFFF;
00623     }
00624 
00625     else {
00626         /* 
00627          * Allocate a NETBUF. 
00628          * Hack alert: Rev A chips never set the odd frame indicator.
00629          */
00630         fbc -= 3;
00631         nb = NutNetBufAlloc(0, NBAF_DATALINK, fbc);
00632 
00633         /* Perform the read. */
00634         if (nb)
00635             NicRead(nb->nb_dl.vp, fbc);
00636     }
00637 
00638     /* Release the packet. */
00639     nic_outlb(LAN91_MMUCR, LAN91_MMU_TOP);
00640 
00641     return nb;
00642 }
00643 
00658 static int NicPutPacket(NETBUF * nb)
00659 {
00660     uint16_t sz;
00661     uint_fast8_t odd = 0;
00662     uint8_t imsk;
00663 
00664     /*
00665      * Calculate the number of bytes to be send. Do not send packets 
00666      * larger than the Ethernet maximum transfer unit. The MTU
00667      * consist of 1500 data bytes plus the 14 byte Ethernet header
00668      * plus 4 bytes CRC. We check the data bytes only.
00669      */
00670     if ((sz = nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz) > ETHERMTU)
00671         return -1;
00672 
00673     /* Disable all interrupts. */
00674     imsk = nic_inlb(LAN91_MSK);
00675     nic_outlb(LAN91_MSK, 0);
00676 
00677     /* Allocate packet buffer space. */
00678     nic_bs(2);
00679     nic_outlb(LAN91_MMUCR, LAN91_MMU_ALO);
00680     if (NicMmuWait(100))
00681         return -1;
00682 
00683     /* Enable interrupts including allocation success. */
00684     nic_outlb(LAN91_MSK, imsk | LAN91_INT_ALLOC);
00685 
00686     /* The MMU needs some time. Use it to calculate the byte count. */
00687     sz += nb->nb_dl.sz;
00688     sz += 6;
00689     if (sz & 1) {
00690         sz++;
00691         odd++;
00692     }
00693 
00694     /* Wait for allocation success. */
00695     while ((nic_inlb(LAN91_IST) & LAN91_INT_ALLOC) == 0) {
00696         if (NutEventWait(&maq, 125)) {
00697             nic_outlb(LAN91_MMUCR, LAN91_MMU_RST);
00698             NicMmuWait(1000);
00699             nic_outlb(LAN91_MMUCR, LAN91_MMU_ALO);
00700             if (NicMmuWait(100) || (nic_inlb(LAN91_IST) & LAN91_INT_ALLOC) == 0) {
00701                 if (NutEventWait(&maq, 125)) {
00702                     return -1;
00703                 }
00704             }
00705         }
00706     }
00707 
00708     /* Disable interrupts. */
00709     imsk = nic_inlb(LAN91_MSK);
00710     nic_outlb(LAN91_MSK, 0);
00711 
00712 
00713     nic_outlb(LAN91_PNR, nic_inhb(LAN91_PNR));
00714 
00715     nic_outw(LAN91_PTR, 0x4000);
00716 
00717     /* Transfer control word. */
00718     nic_outlb(LAN91_DATA, 0);
00719     nic_outlb(LAN91_DATA, 0);
00720 
00721     /* Transfer the byte count. */
00722     nic_outw(LAN91_DATA, sz);
00723 
00724     /* Transfer the Ethernet frame. */
00725     NicWrite(nb->nb_dl.vp, nb->nb_dl.sz);
00726     NicWrite(nb->nb_nw.vp, nb->nb_nw.sz);
00727     NicWrite(nb->nb_tp.vp, nb->nb_tp.sz);
00728     NicWrite(nb->nb_ap.vp, nb->nb_ap.sz);
00729 
00730     if (odd)
00731         nic_outlb(LAN91_DATA, 0);
00732 
00733     /* Transfer the control word. */
00734     nic_outw(LAN91_DATA, 0);
00735 
00736     /* Enqueue packet. */
00737     if (NicMmuWait(100))
00738         return -1;
00739     nic_outlb(LAN91_MMUCR, LAN91_MMU_ENQ);
00740 
00741     /* Enable interrupts. */
00742     imsk |= LAN91_INT_TX | LAN91_INT_TX_EMPTY;
00743     nic_outlb(LAN91_MSK, imsk);
00744 
00745     return 0;
00746 }
00747 
00748 
00753 THREAD(NicRxLanc, arg)
00754 {
00755     NUTDEVICE *dev;
00756     IFNET *ifn;
00757     NICINFO *ni;
00758     NETBUF *nb;
00759     uint8_t imsk;
00760 
00761     dev = arg;
00762     ifn = (IFNET *) dev->dev_icb;
00763     ni = (NICINFO *) dev->dev_dcb;
00764 
00765     /*
00766      * This is a temporary hack. Due to a change in initialization,
00767      * we may not have got a MAC address yet. Wait until a valid one
00768      * has been set.
00769      */
00770     while (!ETHER_IS_UNICAST(ifn->if_mac)) {
00771         NutSleep(10);
00772     }
00773 
00774     /*
00775      * Do not continue unless we managed to start the NIC. We are
00776      * trapped here if the Ethernet link cannot be established.
00777      * This happens, for example, if no Ethernet cable is plugged
00778      * in.
00779      */
00780     while(NicStart(ifn->if_mac)) {
00781         NutSleep(1000);
00782     }
00783 
00784 #ifdef LAN91_SIGNAL
00785     NutIrqSetMode(&LAN91_SIGNAL, NUT_IRQMODE_RISINGEDGE);
00786     NutIrqEnable(&LAN91_SIGNAL);
00787 #endif
00788 
00789     NutEventPost(&mutex);
00790 
00791     /* Run at high priority. */
00792     NutThreadSetPriority(9);
00793 
00794     for (;;) {
00795         /*
00796          * Wait for the arrival of new packets or
00797          * check the receiver every two second.
00798          */
00799         NutEventWait(&ni->ni_rx_rdy, LAN91_RX_POLLTIME);
00800 
00801         /*
00802          * Fetch all packets from the NIC's internal
00803          * buffer and pass them to the registered handler.
00804          */
00805         imsk = nic_inlb(LAN91_MSK);
00806         nic_outlb(LAN91_MSK, 0);
00807         while ((nb = NicGetPacket()) != 0) {
00808             if (nb != (NETBUF *) 0xFFFF) {
00809 #ifdef NUT_PERFMON
00810                 ni->ni_rx_packets++;
00811 #endif
00812                 (*ifn->if_recv) (dev, nb);
00813             }
00814         }
00815         nic_outlb(LAN91_MSK, imsk | LAN91_INT_RCV | LAN91_INT_ERCV);
00816     }
00817 }
00818 
00829 static int Lan91Output(NUTDEVICE * dev, NETBUF * nb)
00830 {
00831     static uint_fast16_t mx_wait = LAN91_TX_POLLTIME;
00832     int rc = -1;
00833     NICINFO *ni;
00834 
00835     /*
00836      * After initialization we are waiting for a long time to give
00837      * the PHY a chance to establish an Ethernet link.
00838      */
00839     if (NutEventWait(&mutex, mx_wait) == 0) {
00840         ni = (NICINFO *) dev->dev_dcb;
00841 
00842         if (NicPutPacket(nb) == 0) {
00843 #ifdef NUT_PERFMON
00844             ni->ni_tx_packets++;
00845 #endif
00846             rc = 0;
00847             /* Ethernet works. Set a long waiting time in case we
00848                temporarly lose the link next time. */
00849             mx_wait = LAN91_TX_POLLTIME;
00850         }
00851         NutEventPost(&mutex);
00852     }
00853 #if defined(LAN91_SIGNAL)
00854     /*
00855      * Probably no Ethernet link. Significantly reduce the waiting
00856      * time, so following transmission will soon return an error.
00857      */
00858     else {
00859         mx_wait = 500;
00860     }
00861 #endif
00862     return rc;
00863 }
00864 
00882 static int Lan91Init(NUTDEVICE * dev)
00883 {
00884     /* Disable NIC interrupt and clear NICINFO structure. */
00885 #ifdef LAN91_SIGNAL
00886     NutIrqDisable(&LAN91_SIGNAL);
00887 #endif
00888     memset(dev->dev_dcb, 0, sizeof(NICINFO));
00889 
00890 #ifdef LAN91_SIGNAL
00891     /* Register interrupt handler and enable interrupts. */
00892     if (NutRegisterIrqHandler(&LAN91_SIGNAL, NicInterrupt, dev))
00893         return -1;
00894 #endif
00895 
00896     /*
00897      * Start the receiver thread.
00898      */
00899     NutThreadCreate("lan91rx", NicRxLanc, dev, 640);
00900 
00901     return 0;
00902 }
00903 
00904 static int Lan91IOCtl(NUTDEVICE * dev, int req, void *conf)
00905 {
00906     int rc = 0;
00907     uint32_t *lvp = (uint32_t *) conf;
00908     IFNET *nif = (IFNET *) dev->dev_icb;
00909 
00910     switch (req) {
00911     case SIOCSIFFLAGS:
00912         /* Set interface flags. */
00913         if (*lvp & IFF_UP) {
00914             if ((nif->if_flags & IFF_UP) == 0) {
00915                 /* Start interface. */
00916             }
00917         } else if (nif->if_flags & IFF_UP) {
00918             /* Stop interface. */
00919         }
00920         break;
00921     case SIOCGIFFLAGS:
00922         /* Get interface flags. */
00923         *lvp = nif->if_flags;
00924         break;
00925     case SIOCSIFADDR:
00926         /* Set interface hardware address. */
00927         memcpy(nif->if_mac, conf, sizeof(nif->if_mac));
00928         break;
00929     case SIOCGIFADDR:
00930         /* Get interface hardware address. */
00931         memcpy(conf, nif->if_mac, sizeof(nif->if_mac));
00932         break;
00933     default:
00934         rc = -1;
00935         break;
00936     }
00937     return rc;
00938 }
00939 
00940 static NICINFO dcb_eth0;
00941 
00947 static IFNET ifn_eth0 = {
00948     IFT_ETHER,          
00949     0,                  
00950     {0, 0, 0, 0, 0, 0}, 
00951     0,                  
00952     0,                  
00953     0,                  
00954     ETHERMTU,           
00955     0,                  
00956     0,                  
00957     0,                  
00958     NutEtherInput,      
00959     Lan91Output,        
00960     NutEtherOutput,     
00961     NULL                
00962 };
00963 
00973 NUTDEVICE devLan91 = {
00974     0,          /* Pointer to next device. */
00975     {'e', 't', 'h', '0', 0, 0, 0, 0, 0},        /* Unique device name. */
00976     IFTYP_NET,  /* Type of device. */
00977     0,          /* Base address. */
00978     0,          /* First interrupt number. */
00979     &ifn_eth0,  /* Interface control block. */
00980     &dcb_eth0,  /* Driver control block. */
00981     Lan91Init,  /* Driver initialization routine. */
00982     Lan91IOCtl, /* Driver specific control function. */
00983     0,          /* Read from device. */
00984     0,          /* Write to device. */
00985 #ifdef __HARVARD_ARCH__
00986     0,          /* Write from program space data to device. */
00987 #endif
00988     0,          /* Open a device or file. */
00989     0,          /* Close a device or file. */
00990     0           /* Request file size. */
00991 };
00992 

© 2000-2010 by contributors - visit http://www.ethernut.de/