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

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/