Nut/OS  4.10.3
API Reference
dm9000.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008-2011 by egnite GmbH
00003  * Copyright (C) 2003-2005 by egnite Software 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  * $Id$
00038  */
00039 
00040 #include <cfg/os.h>
00041 #include <arch/arm.h>
00042 #include <dev/board.h>
00043 
00044 #include <string.h>
00045 #include <stdlib.h>
00046 
00047 #include <sys/atom.h>
00048 #include <sys/heap.h>
00049 #include <sys/thread.h>
00050 #include <sys/event.h>
00051 #include <sys/timer.h>
00052 #include <sys/confnet.h>
00053 
00054 #include <netinet/if_ether.h>
00055 #include <net/ether.h>
00056 #include <net/if_var.h>
00057 
00058 #include <dev/irqreg.h>
00059 #include <dev/dm9000.h>
00060 
00061 #ifdef NUTDEBUG
00062 #include <stdio.h>
00063 #endif
00064 
00065 #ifndef NUT_THREAD_NICRXSTACK
00066 #define NUT_THREAD_NICRXSTACK   384
00067 #endif
00068 
00069 #if !defined(NIC_DATA_ADDR) && defined(NIC_BASE_ADDR)
00070 #define NIC_DATA_ADDR   (NIC_BASE_ADDR + 4)
00071 #endif
00072 
00073 #define INT0    0
00074 #define INT1    1
00075 #define INT2    2
00076 #define INT3    3
00077 #define INT4    4
00078 #define INT5    5
00079 #define INT6    6
00080 #define INT7    7
00081 
00082 #ifdef NIC_RESET_BIT
00083 
00084 #if (NIC_RESET_AVRPORT == AVRPORTB)
00085 #define NIC_RESET_PORT   PORTB
00086 #define NIC_RESET_DDR    DDRB
00087 
00088 #elif (NIC_RESET_AVRPORT == AVRPORTD)
00089 #define NIC_RESET_PORT   PORTD
00090 #define NIC_RESET_DDR    DDRD
00091 
00092 #elif (NIC_RESET_AVRPORT == AVRPORTE)
00093 #define NIC_RESET_PORT   PORTE
00094 #define NIC_RESET_DDR    DDRE
00095 
00096 #elif (NIC_RESET_AVRPORT == AVRPORTF)
00097 #define NIC_RESET_PORT   PORTF
00098 #define NIC_RESET_DDR    DDRF
00099 
00100 #endif /* NIC_RESET_AVRPORT */
00101 
00102 #endif /* NIC_RESET_BIT */
00103 
00104 /*
00105  * Determine interrupt settings.
00106  * DOES NOT WORK
00107  */
00108 #if (NIC_SIGNAL_IRQ == INT0)
00109 #define NIC_SIGNAL          sig_INTERRUPT0
00110 
00111 #elif (NIC_SIGNAL_IRQ == INT2)
00112 #define NIC_SIGNAL          sig_INTERRUPT2
00113 
00114 #elif (NIC_SIGNAL_IRQ == INT3)
00115 #define NIC_SIGNAL          sig_INTERRUPT3
00116 
00117 #elif (NIC_SIGNAL_IRQ == INT4)
00118 #define NIC_SIGNAL          sig_INTERRUPT4
00119 
00120 #elif (NIC_SIGNAL_IRQ == INT5)
00121 #define NIC_SIGNAL          sig_INTERRUPT5
00122 
00123 #elif (NIC_SIGNAL_IRQ == INT6)
00124 #define NIC_SIGNAL          sig_INTERRUPT6
00125 
00126 #elif (NIC_SIGNAL_IRQ == INT7)
00127 #define NIC_SIGNAL          sig_INTERRUPT7
00128 
00129 #else
00130 #define NIC_SIGNAL          sig_INTERRUPT1
00131 
00132 #endif
00133 
00138 
00139 #define NIC_NCR     0x00        /* Network control register (0x00). */
00140 #define NIC_NCR_LBM     0x06    /* Loopback mode. */
00141 #define NIC_NCR_LBNORM  0x00    /* Normal mode. */
00142 #define NIC_NCR_LBMAC   0x02    /* MAC loopback. */
00143 #define NIC_NCR_LBPHY   0x04    /* PHY loopback. */
00144 #define NIC_NCR_RST     0x01    /* Software reset, auto clear. */
00145 
00146 #define NIC_NSR     0x01        /* Network status register (0x00). */
00147 #define NIC_NSR_SPEED   0x80
00148 #define NIC_NSR_LINKST  0x40
00149 #define NIC_NSR_WAKEST  0x20
00150 #define NIC_NSR_TX2END  0x08
00151 #define NIC_NSR_TX1END  0x04
00152 #define NIC_NSR_RXOV    0x02
00153 
00154 #define NIC_TCR     0x02        /* TX control register (0x00). */
00155 #define NIC_TCR_TXREQ    0x01   /* TX request */
00156 
00157 #define NIC_TSR1    0x03        /* TX status register I (0x00). */
00158 
00159 #define NIC_TSR2    0x04        /* TX status register II (0x00). */
00160 
00161 #define NIC_RCR     0x05        /* RX control register (0x00). */
00162 #define NIC_RCR_DIS_LONG 0x20   /* Discard long packets. */
00163 #define NIC_RCR_DIS_CRC 0x10    /* Discard CRC error packets. */
00164 #define NIC_RCR_ALL             0x08    /* Pass all multicast */
00165 #define NIC_RCR_PRMSC   0x02    /* Enable promiscuous mode. */
00166 #define NIC_RCR_RXEN    0x01    /* Enable receiver. */
00167 
00168 #define NIC_RSR     0x06        /* RX status register (0x00). */
00169 #define NIC_RSR_ERRORS  0xBF    /* Error bit mask. */
00170 #define NIC_RSR_RF      0x80    /* Runt frame. */
00171 #define NIC_RSR_MF      0x40    /* Multicast frame. */
00172 #define NIC_RSR_LCS     0x20    /* Late collision. */
00173 #define NIC_RSR_RWTO    0x10    /* Receiver watchdog time out. */
00174 #define NIC_RSR_PLE     0x08    /* Physical layer error. */
00175 #define NIC_RSR_AE      0x04    /* Alignment error. */
00176 #define NIC_RSR_CE      0x02    /* CRC error. */
00177 #define NIC_RSR_FOE     0x01    /* FIFO overflow error. */
00178 
00179 #define NIC_ROCR    0x07        /* Receive overflow counter register (0x00). */
00180 
00181 #define NIC_BPTR    0x08        /* Back pressure threshold register (0x37). */
00182 
00183 #define NIC_FCTR    0x09        /* Flow control threshold register (0x38). */
00184 
00185 #define NIC_FCR     0x0A        /* RX flow control register (0x00). */
00186 
00187 #define NIC_EPCR    0x0B        /* EEPROM and PHY control register. */
00188 
00189 #define NIC_EPAR    0x0C        /* EEPROM and PHY address register. */
00190 
00191 #define NIC_EPDRL   0x0D        /* EEPROM and PHY low byte data register. */
00192 
00193 #define NIC_EPDRH   0x0E        /* EEPROM and PHY high byte data register. */
00194 
00195 #define NIC_WCR     0x0F        /* Wake up control register (0x00). */
00196 
00197 #define NIC_PAR     0x10        /* 6 byte physical address register. */
00198 
00199 #define NIC_MAR     0x16        /* 8 byte multicast address register. */
00200 
00201 #define NIC_GPCR    0x1E        /* General purpose control register (?). */
00202 
00203 #define NIC_GPR     0x1F        /* General purpose register (?). */
00204 
00205 #define NIC_TRPA    0x22        /* 2 byte TX SRAM read pointer address, low/high (0x0000). */
00206 
00207 #define NIC_RWPA    0x24        /* 2 byte RX SRAM write pointer address, low/high (0x0000). */
00208 
00209 #define NIC_VID     0x28        /* 2 byte vendor ID (0x0A46). */
00210 
00211 #define NIC_PID     0x2A        /* 2 byte product ID (0x0900). */
00212 
00213 #define NIC_CHIPR   0x2C        /* Chip revision (0x00). */
00214 
00215 #define NIC_SMCR    0x2F        /* Special mode register (0x00). */
00216 
00217 #define NIC_MRCMDX  0xF0        /* Memory data read command w/o increment (?). */
00218 
00219 #define NIC_MRCMD   0xF2        /* Memory data read command with increment (?). */
00220 
00221 #define NIC_MRR     0xF4        /* 2 byte memory data read register, low/high (?). */
00222 
00223 #define NIC_MWCMDX  0xF6        /* Memory data write command register w/o increment (?). */
00224 
00225 #define NIC_MWCMD   0xF8        /* Memory data write command register with increment (?). */
00226 
00227 #define NIC_MWR     0xFA        /* Memory data write command register with increment (?). */
00228 
00229 #define NIC_TXPL    0xFC        /* 2 byte TX packet length register. (?). */
00230 
00231 #define NIC_ISR     0xFE        /* Interrupt status register (0x00). */
00232 #define NIC_ISR_IOM     0xC0    /* I/O mode mask */
00233 #define NIC_ISR_M16     0x00    /* 16-bit I/O mode */
00234 #define NIC_ISR_M32     0x40    /* 32-bit I/O mode */
00235 #define NIC_ISR_M8      0x80    /* 8-bit I/O mode */
00236 #define NIC_ISR_ROOS    0x08    /* Receiver overflow counter interrupt. */
00237 #define NIC_ISR_ROS     0x04    /* Receiver overflow interrupt. */
00238 #define NIC_ISR_PTS     0x02    /* Transmitter interrupt. */
00239 #define NIC_ISR_PRS     0x01    /* Receiver interrupt. */
00240 
00241 #define NIC_IMR     0xFF        /* Interrupt mask register (0x00). */
00242 #define NIC_IMR_PAR     0x80    /* Enable read/write pointer wrap around. */
00243 #define NIC_IMR_ROOM    0x08    /* Enable receiver overflow counter interrupts. */
00244 #define NIC_IMR_ROM     0x04    /* Enable receiver overflow interrupts. */
00245 #define NIC_IMR_PTM     0x02    /* Enable transmitter interrupts. */
00246 #define NIC_IMR_PRM     0x01    /* Enable receiver interrupts. */
00247 
00248 #define NIC_PHY_BMCR    0x00    /* Basic mode control register. */
00249 
00250 #define NIC_PHY_BMSR    0x01    /* Basic mode status register. */
00251 #define NIC_PHY_BMSR_ANCOMPL    0x0020  /* Auto negotiation complete. */
00252 #define NIC_PHY_BMSR_LINKSTAT   0x0004  /* Link status. */
00253 
00254 #define NIC_PHY_ID1     0x02    /* PHY identifier register 1. */
00255 
00256 #define NIC_PHY_ID2     0x03    /* PHY identifier register 2. */
00257 
00258 #define NIC_PHY_ANAR    0x04    /* Auto negotiation advertisement register. */
00259 
00260 #define NIC_PHY_ANLPAR  0x05    /* Auto negotiation link partner availability register. */
00261 
00262 #define NIC_PHY_ANER    0x06    /* Auto negotiation expansion register. */
00263 
00264 #define NIC_PHY_DSCR    0x10    /* Davicom specified configuration register. */
00265 
00266 #define NIC_PHY_DSCSR   0x11    /* Davicom specified configuration and status register. */
00267 
00268 #define NIC_PHY_10BTCSR 0x12    /* 10BASE-T configuration and status register. */
00269 
00273 struct _NICINFO {
00274 #ifdef NUT_PERFMON
00275     uint32_t ni_rx_packets;         
00276     uint32_t ni_tx_packets;         
00277     uint32_t ni_overruns;           
00278     uint32_t ni_rx_frame_errors;    
00279     uint32_t ni_rx_crc_errors;      
00280     uint32_t ni_rx_missed_errors;   
00281 #endif
00282     HANDLE volatile ni_rx_rdy;  
00283     HANDLE volatile ni_tx_rdy;  
00284     HANDLE ni_mutex;            
00285     volatile int ni_tx_queued;  
00286     volatile int ni_tx_quelen;  
00287     volatile int ni_insane;     
00288     int ni_iomode;              
00289     uint8_t ni_mar[8];          
00290 };
00291 
00295 typedef struct _NICINFO NICINFO;
00296 
00303 
00304 /*
00305  * ether_crc32_le based on FreeBSD code from if_ethersubr.c
00306  */
00307 static const uint32_t crctab[] = {
00308     0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
00309     0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
00310     0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
00311     0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
00312 };
00313 
00314 static uint32_t ether_crc32_le(const uint8_t * buf, uint8_t len)
00315 {
00316     uint32_t crc;
00317     uint8_t i;
00318 
00319     /* Set initial value. */
00320     crc = 0xffffffff;
00321 
00322     for (i = 0; i < len; i++) {
00323         crc ^= buf[i];
00324         crc = (crc >> 4) ^ crctab[crc & 0xf];
00325         crc = (crc >> 4) ^ crctab[crc & 0xf];
00326     }
00327 
00328     return crc;
00329 }
00330 
00331 static INLINE void nic_outb(uint8_t reg, uint8_t val)
00332 {
00333 #ifdef NIC_BASE_ADDR
00334     outb(NIC_BASE_ADDR, reg);
00335     outb(NIC_DATA_ADDR, val);
00336 #endif
00337 }
00338 
00339 static INLINE uint8_t nic_inb(uint16_t reg)
00340 {
00341 #ifdef NIC_BASE_ADDR
00342     outb(NIC_BASE_ADDR, reg);
00343     return inb(NIC_DATA_ADDR);
00344 #else
00345     return 0;
00346 #endif
00347 }
00348 
00356 static uint16_t phy_inw(uint8_t reg)
00357 {
00358     /* Select PHY register */
00359     nic_outb(NIC_EPAR, 0x40 | reg);
00360 
00361     /* PHY read command. */
00362     nic_outb(NIC_EPCR, 0x0C);
00363     NutDelay(1);
00364     nic_outb(NIC_EPCR, 0x00);
00365 
00366     /* Get data from PHY data register. */
00367     return ((uint16_t) nic_inb(NIC_EPDRH) << 8) | (uint16_t) nic_inb(NIC_EPDRL);
00368 }
00369 
00378 static void phy_outw(uint8_t reg, uint16_t val)
00379 {
00380     /* Select PHY register */
00381     nic_outb(NIC_EPAR, 0x40 | reg);
00382 
00383     /* Store value in PHY data register. */
00384     nic_outb(NIC_EPDRL, (uint8_t) val);
00385     nic_outb(NIC_EPDRH, (uint8_t) (val >> 8));
00386 
00387     /* PHY write command. */
00388     nic_outb(NIC_EPCR, 0x0A);
00389     NutDelay(1);
00390     nic_outb(NIC_EPCR, 0x00);
00391 }
00392 
00393 static int NicPhyInit(void)
00394 {
00395     /* Restart auto negotiation. */
00396     phy_outw(NIC_PHY_ANAR, 0x01E1);
00397     phy_outw(NIC_PHY_BMCR, 0x1200);
00398 
00399     nic_outb(NIC_GPCR, 1);
00400     nic_outb(NIC_GPR, 0);
00401 
00402     return 0;
00403 }
00404 
00410 static int NicReset(void)
00411 {
00412     /* Hardware reset. */
00413 #ifdef undef_NIC_RESET_BIT
00414     sbi(NIC_RESET_DDR, NIC_RESET_BIT);
00415     sbi(NIC_RESET_PORT, NIC_RESET_BIT);
00416     NutDelay(WAIT100);
00417     cbi(NIC_RESET_PORT, NIC_RESET_BIT);
00418     NutDelay(WAIT250);
00419     NutDelay(WAIT250);
00420 #else
00421     /* Software reset. */
00422     nic_outb(NIC_NCR, NIC_NCR_RST | NIC_NCR_LBMAC);
00423     NutDelay(1);
00424     /* FIXME: Delay required. */
00425 #endif
00426 
00427     return NicPhyInit();
00428 }
00429 
00430 /*
00431  * NIC interrupt entry.
00432  */
00433 static void NicInterrupt(void *arg)
00434 {
00435     uint8_t isr;
00436     NICINFO *ni = (NICINFO *) ((NUTDEVICE *) arg)->dev_dcb;
00437 
00438     /* Read interrupt status and disable interrupts. */
00439     isr = nic_inb(NIC_ISR);
00440 
00441     /* Receiver interrupt. */
00442     if (isr & NIC_ISR_PRS) {
00443         nic_outb(NIC_ISR, NIC_ISR_PRS);
00444         NutEventPostFromIrq(&ni->ni_rx_rdy);
00445     }
00446 
00447     /* Transmitter interrupt. */
00448     if (isr & NIC_ISR_PTS) {
00449         if (ni->ni_tx_queued) {
00450             if (ni->ni_tx_quelen) {
00451                 /* Initiate transfer of a queued packet. */
00452                 nic_outb(NIC_TXPL, (uint8_t) ni->ni_tx_quelen);
00453                 nic_outb(NIC_TXPL + 1, (uint8_t) (ni->ni_tx_quelen >> 8));
00454                 ni->ni_tx_quelen = 0;
00455                 nic_outb(NIC_TCR, NIC_TCR_TXREQ);
00456             }
00457             ni->ni_tx_queued--;
00458         }
00459         nic_outb(NIC_ISR, NIC_ISR_PTS);
00460         NutEventPostFromIrq(&ni->ni_tx_rdy);
00461     }
00462 
00463     /* Receiver overflow interrupt. */
00464     if (isr & NIC_ISR_ROS) {
00465         nic_outb(NIC_ISR, NIC_ISR_ROS);
00466         ni->ni_insane = 1;
00467         NutEventPostFromIrq(&ni->ni_rx_rdy);
00468     }
00469 
00470     /* Receiver overflow counter interrupt. */
00471     if (isr & NIC_ISR_ROOS) {
00472         nic_outb(NIC_ISR, NIC_ISR_ROOS);
00473         NutEventPostFromIrq(&ni->ni_rx_rdy);
00474     }
00475 }
00476 
00477 #ifdef NIC_BASE_ADDR
00478 
00483 static void NicWrite8(uint8_t * buf, uint16_t len)
00484 {
00485     while (len--) {
00486         outb(NIC_DATA_ADDR, *buf);
00487         buf++;
00488     }
00489 }
00490 
00496 static void NicWrite16(uint8_t * buf, uint16_t len)
00497 {
00498     uint16_t *wp = (uint16_t *) buf;
00499 
00500     len = (len + 1) / 2;
00501     while (len--) {
00502         outw(NIC_DATA_ADDR, *wp);
00503         wp++;
00504     }
00505 }
00506 
00512 static void NicRead8(uint8_t * buf, uint16_t len)
00513 {
00514     while (len--) {
00515         *buf++ = inb(NIC_DATA_ADDR);
00516     }
00517 }
00518 
00524 static void NicRead16(uint8_t * buf, uint16_t len)
00525 {
00526     uint16_t *wp = (uint16_t *) buf;
00527 
00528     len = (len + 1) / 2;
00529     while (len--) {
00530         *wp++ = inw(NIC_DATA_ADDR);
00531     }
00532 }
00533 #endif /* NIC_BASE_ADDR */
00534 
00543 static int NicGetPacket(NICINFO * ni, NETBUF ** nbp)
00544 {
00545     int rc = -1;
00546 #ifdef NIC_BASE_ADDR
00547     uint16_t fsw;
00548     uint16_t fbc;
00549 
00550     *nbp = NULL;
00551 
00552     /* Disable NIC interrupts. */
00553     NutIrqDisable(&NIC_SIGNAL);
00554 
00555     /*
00556      * Read the status word w/o auto increment. If zero, no packet is
00557      * available. Otherwise it should be set to one. Any other value
00558      * indicates a weird chip crying for reset.
00559      */
00560     nic_inb(NIC_MRCMDX);
00561     /* Add some delay before reading the status of the received packet. */
00562     _NOP();
00563     _NOP();
00564     _NOP();
00565     _NOP();
00566     fsw = inb(NIC_DATA_ADDR);
00567     if (fsw > 1) {
00568         ni->ni_insane = 1;
00569     } else if (fsw) {
00570         /* Now read status word and byte count with auto increment. */
00571         outb(NIC_BASE_ADDR, NIC_MRCMD);
00572         if (ni->ni_iomode == NIC_ISR_M16) {
00573             fsw = inw(NIC_DATA_ADDR);
00574             _NOP();
00575             _NOP();
00576             _NOP();
00577             _NOP();
00578             fbc = inw(NIC_DATA_ADDR);
00579         } else {
00580             fsw = inb(NIC_DATA_ADDR) + ((uint16_t) inb(NIC_DATA_ADDR) << 8);
00581             _NOP();
00582             _NOP();
00583             _NOP();
00584             _NOP();
00585             fbc = inb(NIC_DATA_ADDR) + ((uint16_t) inb(NIC_DATA_ADDR) << 8);
00586         }
00587 
00588         /*
00589          * Receiving long packets is unexpected, because we disabled
00590          * this during initialization. Let's declare the chip insane.
00591          * Short packets will be handled by the caller.
00592          */
00593         if (fbc > 1536) {
00594             ni->ni_insane = 1;
00595         } else {
00596             /*
00597              * The high byte of the status word contains a copy of the
00598              * receiver status register.
00599              */
00600             fsw >>= 8;
00601             fsw &= NIC_RSR_ERRORS;
00602 #ifdef NUT_PERMON
00603             /* Update statistics. */
00604             if (fsw) {
00605                 if (RxStatus & NIC_RSR_CE) {
00606                     ni->ni_crc_errors++;
00607                 } else if (RxStatus & NIC_RSR_FOE) {
00608                     ni->ni_overruns++;
00609                 } else {
00610                     ni->ni_rx_missed_errors++;
00611                 }
00612             } else {
00613                 ni->ni_rx_packets++;
00614             }
00615 #endif
00616             /*
00617              * If we got an error packet or failed to allocated the
00618              * buffer, then silently discard the packet.
00619              */
00620             if (fsw || (*nbp = NutNetBufAlloc(0, NBAF_DATALINK, fbc - 4)) == NULL) {
00621                 if (ni->ni_iomode == NIC_ISR_M16) {
00622                     fbc = (fbc + 1) / 2;
00623                     while (fbc--) {
00624                         fsw = inw(NIC_DATA_ADDR);
00625                     }
00626                 } else {
00627                     while (fbc--) {
00628                         fsw = inb(NIC_DATA_ADDR);
00629                     }
00630                 }
00631             } else {
00632                 if (ni->ni_iomode == NIC_ISR_M16) {
00633                     /* Read packet data from 16 bit bus. */
00634                     NicRead16((*nbp)->nb_dl.vp, (*nbp)->nb_dl.sz);
00635                     /* Read packet CRC. */
00636                     fsw = inw(NIC_DATA_ADDR);
00637                     fsw = inw(NIC_DATA_ADDR);
00638                 } else {
00639                     /* Read packet data from 8 bit bus. */
00640                     NicRead8((*nbp)->nb_dl.vp, (*nbp)->nb_dl.sz);
00641                     /* Read packet CRC. */
00642                     fsw = inb(NIC_DATA_ADDR);
00643                     fsw = inb(NIC_DATA_ADDR);
00644                     fsw = inb(NIC_DATA_ADDR);
00645                     fsw = inb(NIC_DATA_ADDR);
00646                 }
00647                 /* Return success. */
00648                 rc = 0;
00649             }
00650         }
00651     }
00652 
00653     /* Enable NIC interrupts if the chip is sane. */
00654     if (ni->ni_insane == 0) {
00655         NutIrqEnable(&NIC_SIGNAL);
00656     }
00657 #endif
00658     return rc;
00659 }
00660 
00673 static int NicPutPacket(NICINFO * ni, NETBUF * nb)
00674 {
00675     int rc = -1;
00676 #ifdef NIC_BASE_ADDR
00677     uint16_t sz;
00678 
00679     /*
00680      * Calculate the number of bytes to be send. Do not send packets
00681      * larger than the Ethernet maximum transfer unit. The MTU
00682      * consist of 1500 data bytes plus the 14 byte Ethernet header
00683      * plus 4 bytes CRC. We check the data bytes only.
00684      */
00685     if ((sz = nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz) > ETHERMTU) {
00686         return -1;
00687     }
00688     sz += nb->nb_dl.sz;
00689     if (sz & 1) {
00690         sz++;
00691     }
00692 
00693     /* Disable interrupts. */
00694     NutIrqDisable(&NIC_SIGNAL);
00695 
00696     /* TODO: Check for link. */
00697     if (ni->ni_insane == 0) {
00698         /* Enable data write. */
00699         outb(NIC_BASE_ADDR, NIC_MWCMD);
00700 
00701         /* Transfer the Ethernet frame. */
00702         if (ni->ni_iomode == NIC_ISR_M16) {
00703             NicWrite16(nb->nb_dl.vp, nb->nb_dl.sz);
00704             NicWrite16(nb->nb_nw.vp, nb->nb_nw.sz);
00705             NicWrite16(nb->nb_tp.vp, nb->nb_tp.sz);
00706             NicWrite16(nb->nb_ap.vp, nb->nb_ap.sz);
00707         } else {
00708             NicWrite8(nb->nb_dl.vp, nb->nb_dl.sz);
00709             NicWrite8(nb->nb_nw.vp, nb->nb_nw.sz);
00710             NicWrite8(nb->nb_tp.vp, nb->nb_tp.sz);
00711             NicWrite8(nb->nb_ap.vp, nb->nb_ap.sz);
00712         }
00713 
00714         /* If no packet is queued, start the transmission. */
00715         if (ni->ni_tx_queued == 0) {
00716             nic_outb(NIC_TXPL, (uint8_t) sz);
00717             nic_outb(NIC_TXPL + 1, (uint8_t) (sz >> 8));
00718             nic_outb(NIC_TCR, NIC_TCR_TXREQ);
00719         }
00720         /* ...otherwise mark this packet queued. */
00721         else {
00722             ni->ni_tx_quelen = sz;
00723         }
00724         ni->ni_tx_queued++;
00725         rc = 0;
00726 #ifdef NUT_PERFMON
00727         ni->ni_tx_packets++;
00728 #endif
00729     }
00730 
00731     /* Enable interrupts. */
00732     NutIrqEnable(&NIC_SIGNAL);
00733 
00734     /* If the controller buffer is filled with two packets, then
00735        wait for the first being sent out. */
00736     if (rc == 0 && ni->ni_tx_queued > 1) {
00737         NutEventWait(&ni->ni_tx_rdy, 500);
00738     }
00739 #endif
00740     return rc;
00741 }
00742 
00748 static void NicUpdateMCHardware(NICINFO * ni)
00749 {
00750     int i;
00751 
00752     /* Enable broadcast receive. */
00753     ni->ni_mar[7] |= 0x80;
00754 
00755     /* Set multicast address register */
00756     for (i = 0; i < 7; i++) {
00757         nic_outb(NIC_MAR + i, ni->ni_mar[i]);
00758     }
00759 }
00760 
00768 static int NicStart(CONST uint8_t * mac, NICINFO * ni)
00769 {
00770     int i;
00771     int link_wait = 20;
00772 
00773     /* Power up the PHY. */
00774     nic_outb(NIC_GPR, 0);
00775     NutDelay(5);
00776 
00777     /* Software reset with MAC loopback. */
00778     nic_outb(NIC_NCR, NIC_NCR_RST | NIC_NCR_LBMAC);
00779     NutDelay(5);
00780     nic_outb(NIC_NCR, NIC_NCR_RST | NIC_NCR_LBMAC);
00781     NutDelay(5);
00782 
00783     /*
00784      * PHY power down followed by PHY power up. This should activate
00785      * the auto sense link.
00786      */
00787     nic_outb(NIC_GPR, 1);
00788     nic_outb(NIC_GPR, 0);
00789 
00790     /* Set MAC address. */
00791     for (i = 0; i < 6; i++) {
00792         nic_outb(NIC_PAR + i, mac[i]);
00793     }
00794 
00795     /* Set multicast address register */
00796     NicUpdateMCHardware(ni);
00797 
00798     /* Clear interrupts. */
00799     nic_outb(NIC_ISR, NIC_ISR_ROOS | NIC_ISR_ROS | NIC_ISR_PTS | NIC_ISR_PRS);
00800 
00801     /* Enable late collision retries on the DM9000A. */
00802     if (nic_inb(NIC_CHIPR) == 0x19) {
00803         nic_outb(0x2D, 0x40);
00804     }
00805 
00806     /* Enable receiver. */
00807     nic_outb(NIC_RCR, NIC_RCR_DIS_LONG | NIC_RCR_DIS_CRC | NIC_RCR_RXEN | NIC_RCR_ALL);
00808 
00809     /* Wait for link. */
00810     for (link_wait = 20;; link_wait--) {
00811         if (phy_inw(NIC_PHY_BMSR) & NIC_PHY_BMSR_ANCOMPL) {
00812             break;
00813         }
00814         if (link_wait == 0) {
00815             return -1;
00816         }
00817         NutSleep(200);
00818     }
00819 
00820     /* Enable interrupts. */
00821     nic_outb(NIC_IMR, NIC_IMR_PAR | NIC_IMR_PTM | NIC_IMR_PRM);
00822 
00823     return 0;
00824 }
00825 
00830 THREAD(NicRxLanc, arg)
00831 {
00832     NUTDEVICE *dev;
00833     IFNET *ifn;
00834     NICINFO *ni;
00835     NETBUF *nb;
00836 
00837     dev = arg;
00838     ifn = (IFNET *) dev->dev_icb;
00839     ni = (NICINFO *) dev->dev_dcb;
00840 
00841     /*
00842      * This is a temporary hack. Due to a change in initialization,
00843      * we may not have got a MAC address yet. Wait until a valid one
00844      * has been set.
00845      */
00846     while (ETHER_IS_ZERO(ifn->if_mac) || ETHER_IS_BROADCAST(ifn->if_mac)) {
00847         NutSleep(10);
00848     }
00849 
00850     /*
00851      * Do not continue unless we managed to start the NIC. We are
00852      * trapped here if the Ethernet link cannot be established.
00853      * This happens, for example, if no Ethernet cable is plugged
00854      * in.
00855      */
00856     while (NicStart(ifn->if_mac, ni)) {
00857         NutSleep(1000);
00858     }
00859 
00860     /* Initialize the access mutex. */
00861     NutEventPost(&ni->ni_mutex);
00862 
00863     /* Run at high priority. */
00864     NutThreadSetPriority(9);
00865 
00866     /* Enable interrupts. */
00867 #ifdef NIC_SIGNAL_XSR
00868     outr(NIC_SIGNAL_XSR, _BV(NIC_SIGNAL_BIT));
00869 #if defined(ELEKTOR_IR1)
00870     /* Ugly code alarm: Should be configurable. */
00871     outr(PMC_PCER, _BV(IRQ0_ID));
00872 #endif
00873 #endif
00874 #ifdef NIC_SIGNAL_BIT
00875     outr(NIC_SIGNAL_PDR, _BV(NIC_SIGNAL_BIT));
00876 #endif
00877     NutIrqEnable(&NIC_SIGNAL);
00878 #if defined(ELEKTOR_IR1)
00879     /* Ugly code alarm: Should be configurable. */
00880     NutIrqSetMode(&NIC_SIGNAL, NUT_IRQMODE_HIGHLEVEL);
00881 #endif
00882 
00883     for (;;) {
00884         /*
00885          * Wait for the arrival of new packets or poll the receiver
00886          * every two seconds.
00887          */
00888         NutEventWait(&ni->ni_rx_rdy, 2000);
00889 
00890         /*
00891          * Fetch all packets from the NIC's internal buffer and pass
00892          * them to the registered handler.
00893          */
00894         while (NicGetPacket(ni, &nb) == 0) {
00895 
00896             /* Discard short packets. */
00897             if (nb->nb_dl.sz < 60) {
00898                 NutNetBufFree(nb);
00899             } else {
00900                 (*ifn->if_recv) (dev, nb);
00901             }
00902         }
00903 
00904         /* We got a weird chip, try to restart it. */
00905         while (ni->ni_insane) {
00906             if (NicStart(ifn->if_mac, ni) == 0) {
00907                 ni->ni_insane = 0;
00908                 ni->ni_tx_queued = 0;
00909                 ni->ni_tx_quelen = 0;
00910                 NutIrqEnable(&NIC_SIGNAL);
00911             } else {
00912                 NutSleep(1000);
00913             }
00914         }
00915     }
00916 }
00917 
00928 int DmOutput(NUTDEVICE * dev, NETBUF * nb)
00929 {
00930     static uint32_t mx_wait = 5000;
00931     int rc = -1;
00932     NICINFO *ni = (NICINFO *) dev->dev_dcb;
00933 
00934     /*
00935      * After initialization we are waiting for a long time to give
00936      * the PHY a chance to establish an Ethernet link.
00937      */
00938     while (rc) {
00939         if (ni->ni_insane) {
00940             break;
00941         }
00942         if (NutEventWait(&ni->ni_mutex, mx_wait)) {
00943             break;
00944         }
00945 
00946         /* Check for packet queue space. */
00947         if (ni->ni_tx_queued > 1) {
00948             if (NutEventWait(&ni->ni_tx_rdy, 500)) {
00949                 /* No queue space. Release the lock and give up. */
00950                 NutEventPost(&ni->ni_mutex);
00951                 break;
00952             }
00953         } else if (NicPutPacket(ni, nb) == 0) {
00954             /* Ethernet works. Set a long waiting time in case we
00955                temporarly lose the link next time. */
00956             rc = 0;
00957             mx_wait = 5000;
00958         }
00959         NutEventPost(&ni->ni_mutex);
00960     }
00961     /*
00962      * Probably no Ethernet link. Significantly reduce the waiting
00963      * time, so following transmission will soon return an error.
00964      */
00965     if (rc) {
00966         mx_wait = 500;
00967     }
00968     return rc;
00969 }
00970 
00988 int DmInit(NUTDEVICE * dev)
00989 {
00990     uint32_t id;
00991     NICINFO *ni = (NICINFO *) dev->dev_dcb;
00992 
00993     /* Probe chip by verifying the identifier registers. */
00994     id = (uint32_t) nic_inb(NIC_VID);
00995     id |= (uint32_t) nic_inb(NIC_VID + 1) << 8;
00996     id |= (uint32_t) nic_inb(NIC_PID) << 16;
00997     id |= (uint32_t) nic_inb(NIC_PID + 1) << 24;
00998     if (id != 0x90000A46) {
00999         return -1;
01000     }
01001 
01002     /* Reset chip. */
01003     if (NicReset()) {
01004         return -1;
01005     }
01006 
01007     /* Clear NICINFO structure. */
01008     memset(ni, 0, sizeof(NICINFO));
01009 
01010     /* Determine bus mode. We do not support 32 bit access. */
01011     ni->ni_iomode = nic_inb(NIC_ISR) & NIC_ISR_IOM;
01012     if (ni->ni_iomode == NIC_ISR_M32) {
01013         return -1;
01014     }
01015 
01016     /* Register interrupt handler. */
01017     if (NutRegisterIrqHandler(&NIC_SIGNAL, NicInterrupt, dev)) {
01018         return -1;
01019     }
01020 
01021     /* Start the receiver thread. */
01022     if (NutThreadCreate("rxi1", NicRxLanc, dev,
01023         (NUT_THREAD_NICRXSTACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD) == NULL) {
01024         return -1;
01025     }
01026     return 0;
01027 }
01028 
01029 static int DmIOCtl(NUTDEVICE * dev, int req, void *conf)
01030 {
01031     int rc = 0;
01032     int i;
01033     IFNET *nif = (IFNET *) dev->dev_icb;
01034     NICINFO *ni = (NICINFO *) dev->dev_dcb;
01035     uint32_t index;
01036     uint32_t ip_addr;
01037     MCASTENTRY *mcast;
01038     MCASTENTRY *mcast_prev;
01039     MCASTENTRY *mcast_next;
01040 
01041     uint8_t mac[6];
01042 
01043     switch (req) {
01044     case SIOCSIFADDR:
01045         /* Set interface hardware address. */
01046         memcpy(nif->if_mac, conf, sizeof(nif->if_mac));
01047         break;
01048 
01049     case SIOCADDMULTI:
01050         /* Add multicast address. */
01051         ip_addr = *((uint32_t *) conf);
01052         /* Test if the address is still in the list */
01053         mcast = nif->if_mcast;
01054         while (mcast) {
01055             if (ip_addr == mcast->mca_ip) {
01056                 /* The address is still in the list, do nothing */
01057                 return -1;
01058             }
01059             mcast = mcast->mca_next;
01060         }
01061         /* Create MAC address */
01062         mac[0] = 0x01;
01063         mac[1] = 0x00;
01064         mac[2] = 0x5E;
01065         mac[3] = ((uint8_t *) conf)[1] & 0x7f;
01066         mac[4] = ((uint8_t *) conf)[2];
01067         mac[5] = ((uint8_t *) conf)[3];
01068         mcast = malloc(sizeof(MCASTENTRY));
01069         if (mcast) {
01070             /* Calculate MAR index, range 0...63 */
01071             index = ether_crc32_le(&mac[0], 6);
01072             index &= 0x3F;
01073             /* Set multicast bit */
01074             ni->ni_mar[index / 8] |= (1 << (index % 8));
01075             /* Add new mcast to the mcast list */
01076             memcpy(mcast->mca_ha, mac, 6);
01077             mcast->mca_ip = *((uint32_t *) conf);
01078             mcast->mca_next = nif->if_mcast;
01079             nif->if_mcast = mcast;
01080             /* Update the MC hardware */
01081             NicUpdateMCHardware(ni);
01082         } else {
01083             rc = -1;
01084         }
01085         break;
01086 
01087     case SIOCDELMULTI:
01088         /* Delete multicast address. */
01089         ip_addr = *((uint32_t *) conf);
01090 
01091         /* Test if the address is still in the list */
01092         mcast = nif->if_mcast;
01093         mcast_prev = mcast;
01094         while (mcast) {
01095             if (ip_addr == mcast->mca_ip) {
01096                 /* The address is in the list, leave the loop */
01097                 break;
01098             }
01099             mcast_prev = mcast;
01100             mcast = mcast->mca_next;
01101         }
01102         if (NULL == mcast) {
01103             /* The address is not in the list */
01104             return -1;
01105         }
01106 
01107         /*
01108          * Remove the address from the list
01109          */
01110         mcast_next = mcast->mca_next;
01111 
01112         /* Check if the first element must be removed */
01113         if (nif->if_mcast == mcast) {
01114             /* The element is the first one. The first element is now
01115                the "next" element */
01116             nif->if_mcast = mcast_next;
01117             free(mcast);
01118         } else {
01119             /* The element is in the middle of the list. The next
01120                element of the previous is the "next" element */
01121             mcast_prev->mca_next = mcast_next;
01122             free(mcast);
01123         }
01124 
01125         /* Clear the multicast filter. */
01126         for (i = 0; i < 7; i++) {
01127             ni->ni_mar[i] = 0;
01128         }
01129         /* Rebuild the multicast filter. */
01130         mcast = nif->if_mcast;
01131         while (mcast) {
01132             /* Calculate MAR index, range 0...63 */
01133             index = ether_crc32_le(&mcast->mca_ha[0], 6);
01134             index &= 0x3F;
01135             /* Set multicast bit */
01136             ni->ni_mar[index / 8] |= (1 << (index % 8));
01137             mcast = mcast->mca_next;
01138         }
01139         /* Update the MC hardware */
01140         NicUpdateMCHardware(ni);
01141         break;
01142 
01143     default:
01144         rc = -1;
01145         break;
01146     }
01147 
01148     return rc;
01149 }
01150 
01151 static NICINFO dcb_eth0;
01152 
01158 static IFNET ifn_eth0 = {
01159     IFT_ETHER,                  
01160     0,                          
01161     {0, 0, 0, 0, 0, 0},         
01162     0,                          
01163     0,                          
01164     0,                          
01165     ETHERMTU,                   
01166     0,                          
01167     0,                          
01168     0,                          
01169     NutEtherInput,              
01170     DmOutput,                   
01171     NutEtherOutput              
01172 };
01173 
01183 NUTDEVICE devDm9000 = {
01184     0,                          
01185     {'e', 't', 'h', '0', 0, 0, 0, 0, 0},        
01186     IFTYP_NET,                  
01187     0,                          
01188     0,                          
01189     &ifn_eth0,                  
01190     &dcb_eth0,                  
01191     DmInit,                     
01192     DmIOCtl,                    
01193     0,                          
01194     0,                          
01195 #ifdef __HARVARD_ARCH__
01196     0,                          
01197 #endif
01198     0,                          
01199     0,                          
01200     0                           
01201 };
01202