Nut/OS  4.10.3
API Reference
dm9000e.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 by egnite GmbH. All rights reserved.
00003  * Copyright (C) 2003-2005 by egnite Software GmbH. All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. Neither the name of the copyright holders nor the names of
00015  *    contributors may be used to endorse or promote products derived
00016  *    from this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00019  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00020  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00021  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00022  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00023  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00024  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00025  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00026  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00027  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00028  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00029  * SUCH DAMAGE.
00030  *
00031  * For additional information see http://www.ethernut.de/
00032  *
00033  */
00034 
00035 /*
00036  * $Log$
00037  * Revision 1.12  2009/02/06 15:37:39  haraldkipp
00038  * Added stack space multiplier and addend. Adjusted stack space.
00039  *
00040  * Revision 1.11  2008/08/28 11:12:15  haraldkipp
00041  * Added interface flags, which will be required to implement Ethernet ioctl
00042  * functions.
00043  *
00044  * Revision 1.10  2008/08/11 06:59:07  haraldkipp
00045  * BSD types replaced by stdint types (feature request #1282721).
00046  *
00047  * Revision 1.9  2008/02/15 17:09:44  haraldkipp
00048  * Added support for the Elektor Internet Radio.
00049  *
00050  * Revision 1.8  2007/08/17 11:43:46  haraldkipp
00051  * Enable multicast.
00052  *
00053  * Revision 1.7  2007/05/24 07:26:44  haraldkipp
00054  * Added some delay befor reading the status of the received packet. Fixes
00055  * bug #1672527, thanks to Andreas Helmcke.
00056  *
00057  * Revision 1.6  2007/05/02 11:22:51  haraldkipp
00058  * Added multicast table entry.
00059  *
00060  * Revision 1.5  2006/06/28 17:10:15  haraldkipp
00061  * Include more general header file for ARM.
00062  *
00063  * Revision 1.4  2006/03/16 19:04:48  haraldkipp
00064  * Adding a short delay before reading the status word makes it work with
00065  * compiler optimization. On receiver overflow interrupts the chip is
00066  * declared insane. The output routine will no more enter NutEventWait()
00067  * on insane chips.
00068  *
00069  * Revision 1.3  2006/03/02 19:51:16  haraldkipp
00070  * Replaced GCC specific inline specifications with their portable
00071  * counterparts.
00072  *
00073  * Revision 1.2  2006/01/23 17:33:14  haraldkipp
00074  * Possible memory alignment problem may start network interface too early.
00075  *
00076  * Revision 1.1  2005/10/24 08:49:05  haraldkipp
00077  * Initial check in.
00078  *
00079  */
00080 
00081 #include <cfg/os.h>
00082 #include <arch/arm.h>
00083 
00084 #include <string.h>
00085 #include <stdlib.h>
00086 
00087 #include <sys/atom.h>
00088 #include <sys/heap.h>
00089 #include <sys/thread.h>
00090 #include <sys/event.h>
00091 #include <sys/timer.h>
00092 #include <sys/confnet.h>
00093 
00094 #include <netinet/if_ether.h>
00095 #include <net/ether.h>
00096 #include <net/if_var.h>
00097 
00098 #include <dev/irqreg.h>
00099 #include <dev/dm9000e.h>
00100 
00101 /* WARNING: Variadic macros are C99 and may fail with C89 compilers. */
00102 #ifdef NUTDEBUG
00103 #include <stdio.h>
00104 #define DMPRINTF(args,...) printf(args,##__VA_ARGS__)
00105 #else
00106 #define DMPRINTF(args,...)
00107 #endif
00108 
00109 #ifndef NUT_THREAD_NICRXSTACK
00110 /* arm-elf-gcc size optimized code used 160 bytes. */
00111 #define NUT_THREAD_NICRXSTACK   384
00112 #endif
00113 
00114 /*
00115  * Determine ports, which had not been explicitely configured.
00116  */
00117 #if defined(ETHERNUT3)
00118 
00119 #ifndef NIC_BASE_ADDR
00120 #define NIC_BASE_ADDR   0x20000000
00121 #endif
00122 
00123 #ifndef NIC_SIGNAL_IRQ
00124 #define NIC_SIGNAL_IRQ  INT1
00125 #endif
00126 
00127 #ifndef NIC_SIGNAL_PDR
00128 #define NIC_SIGNAL_PDR  PIO_PDR
00129 #endif
00130 
00131 #ifndef NIC_SIGNAL_BIT
00132 #define NIC_SIGNAL_BIT  10
00133 #endif
00134 
00135 #elif defined(ELEKTOR_IR1)
00136 
00137 #ifndef NIC_BASE_ADDR
00138 #define NIC_BASE_ADDR   0x30000000
00139 #endif
00140 
00141 #ifndef NIC_SIGNAL_IRQ
00142 #define NIC_SIGNAL_IRQ  INT0
00143 #endif
00144 
00145 #ifndef NIC_SIGNAL_PDR
00146 #define NIC_SIGNAL_PDR  PIOB_PDR
00147 #endif
00148 
00149 #ifndef NIC_SIGNAL_XSR
00150 #define NIC_SIGNAL_XSR  PIOB_ASR
00151 #endif
00152 
00153 #ifndef NIC_SIGNAL_BIT
00154 #define NIC_SIGNAL_BIT  PB20_IRQ0_A
00155 #endif
00156 
00157 #endif
00158 
00159 #ifdef NIC_BASE_ADDR
00160 
00161 #ifndef NIC_DATA_ADDR
00162 #define NIC_DATA_ADDR   (NIC_BASE_ADDR + 4)
00163 #endif
00164 
00165 #define INT0    0
00166 #define INT1    1
00167 #define INT2    2
00168 #define INT3    3
00169 #define INT4    4
00170 #define INT5    5
00171 #define INT6    6
00172 #define INT7    7
00173 
00174 #ifdef NIC_RESET_BIT
00175 
00176 #if (NIC_RESET_AVRPORT == AVRPORTB)
00177 #define NIC_RESET_PORT   PORTB
00178 #define NIC_RESET_DDR    DDRB
00179 
00180 #elif (NIC_RESET_AVRPORT == AVRPORTD)
00181 #define NIC_RESET_PORT   PORTD
00182 #define NIC_RESET_DDR    DDRD
00183 
00184 #elif (NIC_RESET_AVRPORT == AVRPORTE)
00185 #define NIC_RESET_PORT   PORTE
00186 #define NIC_RESET_DDR    DDRE
00187 
00188 #elif (NIC_RESET_AVRPORT == AVRPORTF)
00189 #define NIC_RESET_PORT   PORTF
00190 #define NIC_RESET_DDR    DDRF
00191 
00192 #endif                          /* NIC_RESET_AVRPORT */
00193 
00194 #endif                          /* NIC_RESET_BIT */
00195 
00196 /*
00197  * Determine interrupt settings.
00198  * DOES NOT WORK
00199  */
00200 #if (NIC_SIGNAL_IRQ == INT0)
00201 #define NIC_SIGNAL          sig_INTERRUPT0
00202 
00203 #elif (NIC_SIGNAL_IRQ == INT2)
00204 #define NIC_SIGNAL          sig_INTERRUPT2
00205 
00206 #elif (NIC_SIGNAL_IRQ == INT3)
00207 #define NIC_SIGNAL          sig_INTERRUPT3
00208 
00209 #elif (NIC_SIGNAL_IRQ == INT4)
00210 #define NIC_SIGNAL          sig_INTERRUPT4
00211 
00212 #elif (NIC_SIGNAL_IRQ == INT5)
00213 #define NIC_SIGNAL          sig_INTERRUPT5
00214 
00215 #elif (NIC_SIGNAL_IRQ == INT6)
00216 #define NIC_SIGNAL          sig_INTERRUPT6
00217 
00218 #elif (NIC_SIGNAL_IRQ == INT7)
00219 #define NIC_SIGNAL          sig_INTERRUPT7
00220 
00221 #else
00222 #define NIC_SIGNAL          sig_INTERRUPT1
00223 
00224 #endif
00225 
00230 
00231 #define NIC_NCR     0x00        /* Network control register (0x00). */
00232 #define NIC_NCR_LBM     0x06    /* Loopback mode. */
00233 #define NIC_NCR_LBNORM  0x00    /* Normal mode. */
00234 #define NIC_NCR_LBMAC   0x02    /* MAC loopback. */
00235 #define NIC_NCR_LBPHY   0x04    /* PHY loopback. */
00236 #define NIC_NCR_RST     0x01    /* Software reset, auto clear. */
00237 
00238 #define NIC_NSR     0x01        /* Network status register (0x00). */
00239 #define NIC_NSR_SPEED   0x80
00240 #define NIC_NSR_LINKST  0x40
00241 #define NIC_NSR_WAKEST  0x20
00242 #define NIC_NSR_TX2END  0x08
00243 #define NIC_NSR_TX1END  0x04
00244 #define NIC_NSR_RXOV    0x02
00245 
00246 #define NIC_TCR     0x02        /* TX control register (0x00). */
00247 #define NIC_TCR_TXREQ    0x01   /* TX request */
00248 
00249 #define NIC_TSR1    0x03        /* TX status register I (0x00). */
00250 
00251 #define NIC_TSR2    0x04        /* TX status register II (0x00). */
00252 
00253 #define NIC_RCR     0x05        /* RX control register (0x00). */
00254 #define NIC_RCR_DIS_LONG 0x20   /* Discard long packets. */
00255 #define NIC_RCR_DIS_CRC 0x10    /* Discard CRC error packets. */
00256 #define NIC_RCR_ALL             0x08    /* Pass all multicast */
00257 #define NIC_RCR_PRMSC   0x02    /* Enable promiscuous mode. */
00258 #define NIC_RCR_RXEN    0x01    /* Enable receiver. */
00259 
00260 #define NIC_RSR     0x06        /* RX status register (0x00). */
00261 #define NIC_RSR_ERRORS  0xBF    /* Error bit mask. */
00262 #define NIC_RSR_RF      0x80    /* Runt frame. */
00263 #define NIC_RSR_MF      0x40    /* Multicast frame. */
00264 #define NIC_RSR_LCS     0x20    /* Late collision. */
00265 #define NIC_RSR_RWTO    0x10    /* Receiver watchdog time out. */
00266 #define NIC_RSR_PLE     0x08    /* Physical layer error. */
00267 #define NIC_RSR_AE      0x04    /* Alignment error. */
00268 #define NIC_RSR_CE      0x02    /* CRC error. */
00269 #define NIC_RSR_FOE     0x01    /* FIFO overflow error. */
00270 
00271 #define NIC_ROCR    0x07        /* Receive overflow counter register (0x00). */
00272 
00273 #define NIC_BPTR    0x08        /* Back pressure threshold register (0x37). */
00274 
00275 #define NIC_FCTR    0x09        /* Flow control threshold register (0x38). */
00276 
00277 #define NIC_FCR     0x0A        /* RX flow control register (0x00). */
00278 
00279 #define NIC_EPCR    0x0B        /* EEPROM and PHY control register. */
00280 
00281 #define NIC_EPAR    0x0C        /* EEPROM and PHY address register. */
00282 
00283 #define NIC_EPDRL   0x0D        /* EEPROM and PHY low byte data register. */
00284 
00285 #define NIC_EPDRH   0x0E        /* EEPROM and PHY high byte data register. */
00286 
00287 #define NIC_WCR     0x0F        /* Wake up control register (0x00). */
00288 
00289 #define NIC_PAR     0x10        /* 6 byte physical address register. */
00290 
00291 #define NIC_MAR     0x16        /* 8 byte multicast address register. */
00292 
00293 #define NIC_GPCR    0x1E        /* General purpose control register (?). */
00294 
00295 #define NIC_GPR     0x1F        /* General purpose register (?). */
00296 
00297 #define NIC_TRPA    0x22        /* 2 byte TX SRAM read pointer address, low/high (0x0000). */
00298 
00299 #define NIC_RWPA    0x24        /* 2 byte RX SRAM write pointer address, low/high (0x0000). */
00300 
00301 #define NIC_VID     0x28        /* 2 byte vendor ID (0x0A46). */
00302 
00303 #define NIC_PID     0x2A        /* 2 byte product ID (0x0900). */
00304 
00305 #define NIC_CHIPR   0x2C        /* Chip revision (0x00). */
00306 
00307 #define NIC_SMCR    0x2F        /* Special mode register (0x00). */
00308 
00309 #define NIC_MRCMDX  0xF0        /* Memory data read command w/o increment (?). */
00310 
00311 #define NIC_MRCMD   0xF2        /* Memory data read command with increment (?). */
00312 
00313 #define NIC_MRR     0xF4        /* 2 byte memory data read register, low/high (?). */
00314 
00315 #define NIC_MWCMDX  0xF6        /* Memory data write command register w/o increment (?). */
00316 
00317 #define NIC_MWCMD   0xF8        /* Memory data write command register with increment (?). */
00318 
00319 #define NIC_MWR     0xFA        /* Memory data write command register with increment (?). */
00320 
00321 #define NIC_TXPL    0xFC        /* 2 byte TX packet length register. (?). */
00322 
00323 #define NIC_ISR     0xFE        /* Interrupt status register (0x00). */
00324 #define NIC_ISR_IOM     0xC0    /* I/O mode mask */
00325 #define NIC_ISR_M16     0x00    /* 16-bit I/O mode */
00326 #define NIC_ISR_M32     0x40    /* 32-bit I/O mode */
00327 #define NIC_ISR_M8      0x80    /* 8-bit I/O mode */
00328 #define NIC_ISR_ROOS    0x08    /* Receiver overflow counter interrupt. */
00329 #define NIC_ISR_ROS     0x04    /* Receiver overflow interrupt. */
00330 #define NIC_ISR_PTS     0x02    /* Transmitter interrupt. */
00331 #define NIC_ISR_PRS     0x01    /* Receiver interrupt. */
00332 
00333 #define NIC_IMR     0xFF        /* Interrupt mask register (0x00). */
00334 #define NIC_IMR_PAR     0x80    /* Enable read/write pointer wrap around. */
00335 #define NIC_IMR_ROOM    0x08    /* Enable receiver overflow counter interrupts. */
00336 #define NIC_IMR_ROM     0x04    /* Enable receiver overflow interrupts. */
00337 #define NIC_IMR_PTM     0x02    /* Enable transmitter interrupts. */
00338 #define NIC_IMR_PRM     0x01    /* Enable receiver interrupts. */
00339 
00340 #define NIC_PHY_BMCR    0x00    /* Basic mode control register. */
00341 
00342 #define NIC_PHY_BMSR    0x01    /* Basic mode status register. */
00343 #define NIC_PHY_BMSR_ANCOMPL    0x0020  /* Auto negotiation complete. */
00344 #define NIC_PHY_BMSR_LINKSTAT   0x0004  /* Link status. */
00345 
00346 #define NIC_PHY_ID1     0x02    /* PHY identifier register 1. */
00347 
00348 #define NIC_PHY_ID2     0x03    /* PHY identifier register 2. */
00349 
00350 #define NIC_PHY_ANAR    0x04    /* Auto negotiation advertisement register. */
00351 
00352 #define NIC_PHY_ANLPAR  0x05    /* Auto negotiation link partner availability register. */
00353 
00354 #define NIC_PHY_ANER    0x06    /* Auto negotiation expansion register. */
00355 
00356 #define NIC_PHY_DSCR    0x10    /* Davicom specified configuration register. */
00357 
00358 #define NIC_PHY_DSCSR   0x11    /* Davicom specified configuration and status register. */
00359 
00360 #define NIC_PHY_10BTCSR 0x12    /* 10BASE-T configuration and status register. */
00361 
00365 struct _NICINFO {
00366 #ifdef NUT_PERFMON
00367     uint32_t ni_rx_packets;       
00368     uint32_t ni_tx_packets;       
00369     uint32_t ni_overruns;         
00370     uint32_t ni_rx_frame_errors;  
00371     uint32_t ni_rx_crc_errors;    
00372     uint32_t ni_rx_missed_errors; 
00373 #endif
00374     HANDLE volatile ni_rx_rdy;  
00375     HANDLE volatile ni_tx_rdy;  
00376     HANDLE ni_mutex;            
00377     volatile int ni_tx_queued;  
00378     volatile int ni_tx_quelen;  
00379     volatile int ni_insane;     
00380     int ni_iomode;              
00381     uint8_t ni_mar[8];          
00382 };
00383 
00387 typedef struct _NICINFO NICINFO;
00388 
00395 
00396 
00397 /*
00398  * ether_crc32_le based on FreeBSD code from if_ethersubr.c
00399  */
00400 static const uint32_t crctab[] = {
00401     0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
00402     0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
00403     0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
00404     0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
00405 };
00406 
00407 static uint32_t ether_crc32_le(const uint8_t *buf, uint8_t len)
00408 {
00409    uint32_t crc;
00410    uint8_t i;
00411 
00412    crc = 0xffffffff; /* initial value */
00413 
00414    for (i = 0; i < len; i++) {
00415       crc ^= buf[i];
00416       crc = (crc >> 4) ^ crctab[crc & 0xf];
00417       crc = (crc >> 4) ^ crctab[crc & 0xf];
00418    }
00419 
00420    return (crc);
00421 }
00422 
00423 static INLINE void nic_outb(uint8_t reg, uint8_t val)
00424 {
00425     outb(NIC_BASE_ADDR, reg);
00426     outb(NIC_DATA_ADDR, val);
00427 }
00428 
00429 static INLINE uint8_t nic_inb(uint16_t reg)
00430 {
00431     outb(NIC_BASE_ADDR, reg);
00432     return inb(NIC_DATA_ADDR);
00433 }
00434 
00442 static uint16_t phy_inw(uint8_t reg)
00443 {
00444     /* Select PHY register */
00445     nic_outb(NIC_EPAR, 0x40 | reg);
00446 
00447     /* PHY read command. */
00448     nic_outb(NIC_EPCR, 0x0C);
00449     NutDelay(1);
00450     nic_outb(NIC_EPCR, 0x00);
00451 
00452     /* Get data from PHY data register. */
00453     return ((uint16_t) nic_inb(NIC_EPDRH) << 8) | (uint16_t) nic_inb(NIC_EPDRL);
00454 }
00455 
00464 static void phy_outw(uint8_t reg, uint16_t val)
00465 {
00466     /* Select PHY register */
00467     nic_outb(NIC_EPAR, 0x40 | reg);
00468 
00469     /* Store value in PHY data register. */
00470     nic_outb(NIC_EPDRL, (uint8_t) val);
00471     nic_outb(NIC_EPDRH, (uint8_t) (val >> 8));
00472 
00473     /* PHY write command. */
00474     nic_outb(NIC_EPCR, 0x0A);
00475     NutDelay(1);
00476     nic_outb(NIC_EPCR, 0x00);
00477 }
00478 
00479 static int NicPhyInit(void)
00480 {
00481     /* Restart auto negotiation. */
00482     phy_outw(NIC_PHY_ANAR, 0x01E1);
00483     phy_outw(NIC_PHY_BMCR, 0x1200);
00484 
00485     nic_outb(NIC_GPCR, 1);
00486     nic_outb(NIC_GPR, 0);
00487 
00488     return 0;
00489 }
00490 
00496 static int NicReset(void)
00497 {
00498     /* Hardware reset. */
00499 #ifdef undef_NIC_RESET_BIT
00500     sbi(NIC_RESET_DDR, NIC_RESET_BIT);
00501     sbi(NIC_RESET_PORT, NIC_RESET_BIT);
00502     NutDelay(WAIT100);
00503     cbi(NIC_RESET_PORT, NIC_RESET_BIT);
00504     NutDelay(WAIT250);
00505     NutDelay(WAIT250);
00506 #else
00507     /* Software reset. */
00508     nic_outb(NIC_NCR, NIC_NCR_RST | NIC_NCR_LBMAC);
00509     NutDelay(1);
00510     /* FIXME: Delay required. */
00511 #endif
00512     DMPRINTF("\n*DMRES*\n");
00513     return NicPhyInit();
00514 }
00515 
00516 /*
00517  * NIC interrupt entry.
00518  */
00519 static void NicInterrupt(void *arg)
00520 {
00521     uint_fast8_t isr;
00522     NICINFO *ni = (NICINFO *) ((NUTDEVICE *) arg)->dev_dcb;
00523 
00524     /* Read interrupt status and disable interrupts. */
00525     isr = nic_inb(NIC_ISR);
00526     DMPRINTF("*DMIRQ %02x:", isr);
00527 
00528     /* Receiver interrupt. */
00529     if (isr & NIC_ISR_PRS) {
00530         DMPRINTF("RX*");
00531         nic_outb(NIC_ISR, NIC_ISR_PRS);
00532         NutEventPostFromIrq(&ni->ni_rx_rdy);
00533     }
00534 
00535     /* Transmitter interrupt. */
00536     if (isr & NIC_ISR_PTS) {
00537         DMPRINTF("TX*");
00538         if (ni->ni_tx_queued) {
00539             if (ni->ni_tx_quelen) {
00540                 /* Initiate transfer of a queued packet. */
00541                 nic_outb(NIC_TXPL, (uint8_t) ni->ni_tx_quelen);
00542                 nic_outb(NIC_TXPL + 1, (uint8_t) (ni->ni_tx_quelen >> 8));
00543                 ni->ni_tx_quelen = 0;
00544                 nic_outb(NIC_TCR, NIC_TCR_TXREQ);
00545             }
00546             ni->ni_tx_queued--;
00547         }
00548         nic_outb(NIC_ISR, NIC_ISR_PTS);
00549         NutEventPostFromIrq(&ni->ni_tx_rdy);
00550     }
00551 
00552     /* Receiver overflow interrupt. */
00553     if (isr & NIC_ISR_ROS) {
00554         DMPRINTF("OVI*");
00555         nic_outb(NIC_ISR, NIC_ISR_ROS);
00556         ni->ni_insane = 1;
00557         NutEventPostFromIrq(&ni->ni_rx_rdy);
00558     }
00559 
00560     /* Receiver overflow counter interrupt. */
00561     if (isr & NIC_ISR_ROOS) {
00562         DMPRINTF("OVC*");
00563         nic_outb(NIC_ISR, NIC_ISR_ROOS);
00564         NutEventPostFromIrq(&ni->ni_rx_rdy);
00565     }
00566 
00567     if( ni->ni_insane)
00568         DMPRINTF("INS\n");
00569     else
00570         DMPRINTF("\n");
00571 }
00572 
00578 static void NicWrite8(uint8_t * buf, uint16_t len)
00579 {
00580     while (len--) {
00581         outb(NIC_DATA_ADDR, *buf);
00582         buf++;
00583     }
00584 }
00585 
00591 static void NicWrite16(uint8_t * buf, uint16_t len)
00592 {
00593     uint16_t *wp = (uint16_t *) buf;
00594 
00595     len = (len + 1) / 2;
00596     while (len--) {
00597         outw(NIC_DATA_ADDR, *wp);
00598         wp++;
00599     }
00600 }
00601 
00607 static void NicRead8(uint8_t * buf, uint16_t len)
00608 {
00609     while (len--) {
00610         *buf++ = inb(NIC_DATA_ADDR);
00611     }
00612 }
00613 
00619 static void NicRead16(uint8_t * buf, uint16_t len)
00620 {
00621     uint16_t *wp = (uint16_t *) buf;
00622 
00623     len = (len + 1) / 2;
00624     while (len--) {
00625         *wp++ = inw(NIC_DATA_ADDR);
00626     }
00627 }
00628 
00637 static int NicGetPacket(NICINFO * ni, NETBUF ** nbp)
00638 {
00639     int rc = -1;
00640     uint16_t fsw;
00641     uint16_t fbc;
00642 
00643     *nbp = NULL;
00644 
00645     /* Disable NIC interrupts. */
00646     NutIrqDisable(&NIC_SIGNAL);
00647 
00648     /*
00649      * Read the status word w/o auto increment. If zero, no packet is
00650      * available. Otherwise it should be set to one. Any other value
00651      * indicates a weird chip crying for reset.
00652      */
00653     nic_inb(NIC_MRCMDX);
00654     /* Add some delay befor reading the status of the received packet. */
00655     _NOP(); _NOP(); _NOP(); _NOP();
00656     fsw = inb(NIC_DATA_ADDR);
00657     if (fsw > 1) {
00658         ni->ni_insane = 1;
00659     } else if (fsw) {
00660         /* Now read status word and byte count with auto increment. */
00661         outb(NIC_BASE_ADDR, NIC_MRCMD);
00662         if (ni->ni_iomode == NIC_ISR_M16) {
00663             fsw = inw(NIC_DATA_ADDR);
00664             _NOP(); _NOP(); _NOP(); _NOP();
00665             fbc = inw(NIC_DATA_ADDR);
00666         } else {
00667             fsw = inb(NIC_DATA_ADDR) + ((uint16_t) inb(NIC_DATA_ADDR) << 8);
00668             _NOP(); _NOP(); _NOP(); _NOP();
00669             fbc = inb(NIC_DATA_ADDR) + ((uint16_t) inb(NIC_DATA_ADDR) << 8);
00670         }
00671 
00672         /*
00673          * Receiving long packets is unexpected, because we disabled
00674          * this during initialization. Let's declare the chip insane.
00675          * Short packets will be handled by the caller.
00676          */
00677         if (fbc > 1536) {
00678             ni->ni_insane = 1;
00679         } else {
00680             /*
00681              * The high byte of the status word contains a copy of the
00682              * receiver status register.
00683              */
00684             fsw >>= 8;
00685             fsw &= NIC_RSR_ERRORS;
00686 #ifdef NUT_PERMON
00687             /* Update statistics. */
00688             if (fsw) {
00689                 if (RxStatus & NIC_RSR_CE) {
00690                     ni->ni_crc_errors++;
00691                 } else if (RxStatus & NIC_RSR_FOE) {
00692                     ni->ni_overruns++;
00693                 } else {
00694                     ni->ni_rx_missed_errors++;
00695                 }
00696             } else {
00697                 ni->ni_rx_packets++;
00698             }
00699 #endif
00700             /*
00701              * If we got an error packet or failed to allocated the
00702              * buffer, then silently discard the packet.
00703              */
00704             if (fsw || (*nbp = NutNetBufAlloc(0, NBAF_DATALINK, fbc - 4)) == NULL) {
00705                 if (ni->ni_iomode == NIC_ISR_M16) {
00706                     fbc = (fbc + 1) / 2;
00707                     while (fbc--) {
00708                         fsw = inw(NIC_DATA_ADDR);
00709                     }
00710                 } else {
00711                     while (fbc--) {
00712                         fsw = inb(NIC_DATA_ADDR);
00713                     }
00714                 }
00715             } else {
00716                 if (ni->ni_iomode == NIC_ISR_M16) {
00717                     /* Read packet data from 16 bit bus. */
00718                     NicRead16((*nbp)->nb_dl.vp, (*nbp)->nb_dl.sz);
00719                     /* Read packet CRC. */
00720                     fsw = inw(NIC_DATA_ADDR);
00721                     fsw = inw(NIC_DATA_ADDR);
00722                 } else {
00723                     /* Read packet data from 8 bit bus. */
00724                     NicRead8((*nbp)->nb_dl.vp, (*nbp)->nb_dl.sz);
00725                     /* Read packet CRC. */
00726                     fsw = inb(NIC_DATA_ADDR);
00727                     fsw = inb(NIC_DATA_ADDR);
00728                     fsw = inb(NIC_DATA_ADDR);
00729                     fsw = inb(NIC_DATA_ADDR);
00730                 }
00731                 /* Return success. */
00732                 rc = 0;
00733             }
00734         }
00735     }
00736 
00737     /* Enable NIC interrupts if the chip is sane. */
00738     if (ni->ni_insane == 0) {
00739         NutIrqEnable(&NIC_SIGNAL);
00740     }
00741     return rc;
00742 }
00743 
00756 static int NicPutPacket(NICINFO * ni, NETBUF * nb)
00757 {
00758     int rc = -1;
00759     uint16_t sz;
00760 
00761     /*
00762      * Calculate the number of bytes to be send. Do not send packets
00763      * larger than the Ethernet maximum transfer unit. The MTU
00764      * consist of 1500 data bytes plus the 14 byte Ethernet header
00765      * plus 4 bytes CRC. We check the data bytes only.
00766      */
00767     if ((sz = nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz) > ETHERMTU) {
00768         return -1;
00769     }
00770     sz += nb->nb_dl.sz;
00771     if (sz & 1) {
00772         sz++;
00773     }
00774 
00775     /* Disable interrupts. */
00776     NutIrqDisable(&NIC_SIGNAL);
00777 
00778     /* TODO: Check for link. */
00779     if (ni->ni_insane == 0) {
00780         /* Enable data write. */
00781         outb(NIC_BASE_ADDR, NIC_MWCMD);
00782 
00783         /* Transfer the Ethernet frame. */
00784         if (ni->ni_iomode == NIC_ISR_M16) {
00785             NicWrite16(nb->nb_dl.vp, nb->nb_dl.sz);
00786             NicWrite16(nb->nb_nw.vp, nb->nb_nw.sz);
00787             NicWrite16(nb->nb_tp.vp, nb->nb_tp.sz);
00788             NicWrite16(nb->nb_ap.vp, nb->nb_ap.sz);
00789         } else {
00790             NicWrite8(nb->nb_dl.vp, nb->nb_dl.sz);
00791             NicWrite8(nb->nb_nw.vp, nb->nb_nw.sz);
00792             NicWrite8(nb->nb_tp.vp, nb->nb_tp.sz);
00793             NicWrite8(nb->nb_ap.vp, nb->nb_ap.sz);
00794         }
00795 
00796         /* If no packet is queued, start the transmission. */
00797         if (ni->ni_tx_queued == 0) {
00798             nic_outb(NIC_TXPL, (uint8_t) sz);
00799             nic_outb(NIC_TXPL + 1, (uint8_t) (sz >> 8));
00800             nic_outb(NIC_TCR, NIC_TCR_TXREQ);
00801         }
00802         /* ...otherwise mark this packet queued. */
00803         else {
00804             ni->ni_tx_quelen = sz;
00805         }
00806         ni->ni_tx_queued++;
00807         rc = 0;
00808 #ifdef NUT_PERFMON
00809         ni->ni_tx_packets++;
00810 #endif
00811     }
00812 
00813     /* Enable interrupts. */
00814     NutIrqEnable(&NIC_SIGNAL);
00815 
00816     /* If the controller buffer is filled with two packets, then
00817        wait for the first being sent out. */
00818     if (rc == 0 && ni->ni_tx_queued > 1) {
00819         NutEventWait(&ni->ni_tx_rdy, 500);
00820     }
00821     return rc;
00822 }
00823 
00829 static void NicUpdateMCHardware(NICINFO *ni)
00830 {
00831     int i;
00832 
00833     /* Enable broadcast receive. */
00834     ni->ni_mar[7] |= 0x80;
00835     
00836     /* Set multicast address register */
00837     for (i = 0; i < 7; i++) {
00838         nic_outb(NIC_MAR + i, ni->ni_mar[i]);
00839     }
00840 }
00841 
00849 static int NicStart(CONST uint8_t * mac, NICINFO * ni)
00850 {
00851     int i;
00852     int link_wait = 20;
00853 
00854     /* Power up the PHY. */
00855     nic_outb(NIC_GPR, 0);
00856     NutDelay(5);
00857 
00858     /* Software reset with MAC loopback. */
00859     nic_outb(NIC_NCR, NIC_NCR_RST | NIC_NCR_LBMAC);
00860     NutDelay(5);
00861     nic_outb(NIC_NCR, NIC_NCR_RST | NIC_NCR_LBMAC);
00862     NutDelay(5);
00863 
00864     /*
00865      * PHY power down followed by PHY power up. This should activate
00866      * the auto sense link.
00867      */
00868     nic_outb(NIC_GPR, 1);
00869     nic_outb(NIC_GPR, 0);
00870 
00871     /* Set MAC address. */
00872     for (i = 0; i < 6; i++) {
00873         nic_outb(NIC_PAR + i, mac[i]);
00874     }
00875 
00876     /* Set multicast address register */
00877     NicUpdateMCHardware(ni);    
00878 
00879     /* Clear interrupts. */
00880     nic_outb(NIC_ISR, NIC_ISR_ROOS | NIC_ISR_ROS | NIC_ISR_PTS | NIC_ISR_PRS);
00881 
00882     /* Enable late collision retries on the DM9000A. */
00883     if (nic_inb(NIC_CHIPR) == 0x19) {
00884         nic_outb(0x2D, 0x40);
00885     }
00886 
00887     /* Enable receiver. */
00888     nic_outb(NIC_RCR, NIC_RCR_DIS_LONG | NIC_RCR_DIS_CRC | NIC_RCR_RXEN | NIC_RCR_ALL);
00889 
00890     /* Wait for link. */
00891     for (link_wait = 20;; link_wait--) {
00892         if (phy_inw(NIC_PHY_BMSR) & NIC_PHY_BMSR_ANCOMPL) {
00893             break;
00894         }
00895         if (link_wait == 0) {
00896             return -1;
00897         }
00898         NutSleep(200);
00899     }
00900 
00901     /* Enable interrupts. */
00902     nic_outb(NIC_IMR, NIC_IMR_PAR | NIC_IMR_PTM | NIC_IMR_PRM);
00903 
00904     return 0;
00905 }
00906 
00911 THREAD(NicRxLanc, arg)
00912 {
00913     NUTDEVICE *dev;
00914     IFNET *ifn;
00915     NICINFO *ni;
00916     NETBUF *nb;
00917 
00918     dev = arg;
00919     ifn = (IFNET *) dev->dev_icb;
00920     ni = (NICINFO *) dev->dev_dcb;
00921 
00922     /*
00923      * This is a temporary hack. Due to a change in initialization,
00924      * we may not have got a MAC address yet. Wait until a valid one
00925      * has been set.
00926      */
00927     while (!ETHER_IS_UNICAST(ifn->if_mac)) {
00928         NutSleep(10);
00929     }
00930 
00931     /*
00932      * Do not continue unless we managed to start the NIC. We are
00933      * trapped here if the Ethernet link cannot be established.
00934      * This happens, for example, if no Ethernet cable is plugged
00935      * in.
00936      */
00937     while (NicStart(ifn->if_mac, ni)) {
00938         NutSleep(1000);
00939     }
00940 
00941     /* Initialize the access mutex. */
00942     NutEventPost(&ni->ni_mutex);
00943 
00944     /* Run at high priority. */
00945     NutThreadSetPriority(9);
00946 
00947     /* Enable interrupts. */
00948 #ifdef NIC_SIGNAL_XSR
00949     outr(NIC_SIGNAL_XSR, _BV(NIC_SIGNAL_BIT));
00950 #if defined(ELEKTOR_IR1)
00951     /* Ugly code alarm: Should be configurable. */
00952     outr(PMC_PCER, _BV(IRQ0_ID));
00953 #endif
00954 #endif
00955     outr(NIC_SIGNAL_PDR, _BV(NIC_SIGNAL_BIT));
00956     NutIrqEnable(&NIC_SIGNAL);
00957 #if defined(ELEKTOR_IR1)
00958     /* Ugly code alarm: Should be configurable. */
00959     NutIrqSetMode(&NIC_SIGNAL, NUT_IRQMODE_HIGHLEVEL);
00960 #endif
00961 
00962     for (;;) {
00963         /*
00964          * Wait for the arrival of new packets or poll the receiver
00965          * every two seconds.
00966          */
00967         NutEventWait(&ni->ni_rx_rdy, 2000);
00968 
00969         /*
00970          * Fetch all packets from the NIC's internal buffer and pass
00971          * them to the registered handler.
00972          */
00973         while (NicGetPacket(ni, &nb) == 0) {
00974 
00975             /* Discard short packets. */
00976             if (nb->nb_dl.sz < 60) {
00977                 NutNetBufFree(nb);
00978             } else {
00979                 (*ifn->if_recv) (dev, nb);
00980             }
00981         }
00982 
00983         /* We got a weird chip, try to restart it. */
00984         while (ni->ni_insane) {
00985             if (NicStart(ifn->if_mac, ni) == 0) {
00986                 ni->ni_insane = 0;
00987                 ni->ni_tx_queued = 0;
00988                 ni->ni_tx_quelen = 0;
00989                 NutIrqEnable(&NIC_SIGNAL);
00990             } else {
00991                 NutSleep(1000);
00992             }
00993         }
00994     }
00995 }
00996 
01007 int DmOutput(NUTDEVICE * dev, NETBUF * nb)
01008 {
01009     static uint32_t mx_wait = 5000;
01010     int rc = -1;
01011     NICINFO *ni = (NICINFO *) dev->dev_dcb;
01012 
01013     /*
01014      * After initialization we are waiting for a long time to give
01015      * the PHY a chance to establish an Ethernet link.
01016      */
01017     while (rc) {
01018         if (ni->ni_insane) {
01019             break;
01020         }
01021         if (NutEventWait(&ni->ni_mutex, mx_wait)) {
01022             break;
01023         }
01024 
01025         /* Check for packet queue space. */
01026         if (ni->ni_tx_queued > 1) {
01027             if (NutEventWait(&ni->ni_tx_rdy, 500)) {
01028                 /* No queue space. Release the lock and give up. */
01029                 NutEventPost(&ni->ni_mutex);
01030                 break;
01031             }
01032         } else if (NicPutPacket(ni, nb) == 0) {
01033             /* Ethernet works. Set a long waiting time in case we
01034                temporarly lose the link next time. */
01035             rc = 0;
01036             mx_wait = 5000;
01037         }
01038         NutEventPost(&ni->ni_mutex);
01039     }
01040     /*
01041      * Probably no Ethernet link. Significantly reduce the waiting
01042      * time, so following transmission will soon return an error.
01043      */
01044     if (rc) {
01045         mx_wait = 500;
01046     }
01047     return rc;
01048 }
01049 
01067 int DmInit(NUTDEVICE * dev)
01068 {
01069     uint32_t id;
01070     NICINFO *ni = (NICINFO *) dev->dev_dcb;
01071 
01072 #if defined(ELEKTOR_IR1)
01073     
01074     /* @@MF: "Power on reset" the Ethernet controller */
01075     outr(PIOC_SODR, _BV(PC17_NANDOE_B));
01076     outr(PIOC_PER,  _BV(PC17_NANDOE_B));
01077     outr(PIOC_OER,  _BV(PC17_NANDOE_B));
01078     outr(PIOC_CODR, _BV(PC17_NANDOE_B));
01079     NutDelay(WAIT250);
01080     NutDelay(WAIT250);
01081     NutDelay(WAIT250);
01082     NutDelay(WAIT250);
01083     outr(PIOC_SODR, _BV(PC17_NANDOE_B));
01084     NutDelay(WAIT250);
01085     NutDelay(WAIT250);
01086     NutDelay(WAIT250);
01087     NutDelay(WAIT250);
01088     /**************************************************/
01089 
01090     outr(PIOA_BSR, _BV(PA20_NCS2_B));
01091     outr(PIOA_PDR, _BV(PA20_NCS2_B));
01092     outr(PIOC_BSR, _BV(PC16_NWAIT_B) | _BV(PC21_NWR0_B) | _BV(PC22_NRD_B));
01093     outr(PIOC_PDR, _BV(PC16_NWAIT_B) | _BV(PC21_NWR0_B) | _BV(PC22_NRD_B));
01094 
01095     outr(SMC_CSR(2)
01096         , (1 << SMC_NWS_LSB)
01097         | SMC_WSEN
01098         | (2 << SMC_TDF_LSB)
01099         | SMC_BAT
01100         | SMC_DBW_16
01101         | (1 << SMC_RWSETUP_LSB)
01102         | (1 << SMC_RWHOLD_LSB)
01103         );
01104 #endif
01105 
01106     /* Probe chip by verifying the identifier registers. */
01107     id = (uint32_t) nic_inb(NIC_VID);
01108     id |= (uint32_t) nic_inb(NIC_VID + 1) << 8;
01109     id |= (uint32_t) nic_inb(NIC_PID) << 16;
01110     id |= (uint32_t) nic_inb(NIC_PID + 1) << 24;
01111     if (id != 0x90000A46) {
01112         return -1;
01113     }
01114 
01115     /* Reset chip. */
01116     if (NicReset()) {
01117         return -1;
01118     }
01119 
01120     /* Clear NICINFO structure. */
01121     memset(ni, 0, sizeof(NICINFO));
01122 
01123     /* Determine bus mode. We do not support 32 bit access. */
01124     ni->ni_iomode = nic_inb(NIC_ISR) & NIC_ISR_IOM;
01125     if (ni->ni_iomode == NIC_ISR_M32) {
01126         return -1;
01127     }
01128 
01129     /* Register interrupt handler. */
01130     if (NutRegisterIrqHandler(&NIC_SIGNAL, NicInterrupt, dev)) {
01131         return -1;
01132     }
01133 
01134     /* Start the receiver thread. */
01135     if (NutThreadCreate("rxi1", NicRxLanc, dev,
01136         (NUT_THREAD_NICRXSTACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD) == NULL) {
01137         return -1;
01138     }
01139     return 0;
01140 }
01141 
01142 static int DmIOCtl(NUTDEVICE * dev, int req, void *conf)
01143 {
01144     int rc = 0;
01145     int i;
01146     IFNET *nif = (IFNET *) dev->dev_icb;
01147     NICINFO *ni = (NICINFO *) dev->dev_dcb;
01148     uint32_t index;
01149     uint32_t ip_addr;
01150     MCASTENTRY *mcast;
01151     MCASTENTRY *mcast_prev;
01152     MCASTENTRY *mcast_next;
01153     
01154     uint8_t mac[6];
01155 
01156     switch (req) {
01157         /* Set interface address */ 
01158         case SIOCSIFADDR:
01159             /* Set interface hardware address. */
01160             memcpy(nif->if_mac, conf, sizeof(nif->if_mac));
01161             break;
01162     
01163         /* Add multicast address */
01164         case SIOCADDMULTI:
01165             ip_addr = *((uint32_t*)conf);
01166             
01167             /* Test if the address is still in the list */
01168             mcast = nif->if_mcast;
01169             while(mcast)
01170             {
01171                 if (ip_addr == mcast->mca_ip)
01172                 {
01173                     /* The address is still in the list, do nothing */
01174                     return -1;
01175                 }
01176                 mcast = mcast->mca_next;
01177             }
01178            
01179             /* Create MAC address */ 
01180             mac[0] = 0x01;
01181             mac[1] = 0x00;
01182             mac[2] = 0x5E;
01183             mac[3] = ((uint8_t*)conf)[1] & 0x7f;
01184             mac[4] = ((uint8_t*)conf)[2];
01185             mac[5] = ((uint8_t*)conf)[3];
01186             
01187             mcast = malloc(sizeof(MCASTENTRY));
01188             if (mcast != NULL) {
01189                 /* Calculate MAR index, range 0...63 */
01190                 index  = ether_crc32_le(&mac[0], 6);
01191                 index &= 0x3F;
01192             
01193                 /* Set multicast bit */            
01194                 ni->ni_mar[index / 8] |= (1 << (index % 8));
01195                 
01196                 /* Add new mcast to the mcast list */
01197                 memcpy(mcast->mca_ha, mac, 6);
01198                 mcast->mca_ip = *((uint32_t*)conf);
01199                 mcast->mca_next = nif->if_mcast;
01200                 nif->if_mcast = mcast;
01201                 
01202                 /* Update the MC hardware */
01203                 NicUpdateMCHardware(ni);
01204             }
01205             else {
01206                 rc = -1;
01207             }    
01208             break;
01209         
01210         /* Delete multicast address */    
01211         case SIOCDELMULTI:
01212             ip_addr = *((uint32_t*)conf);
01213 
01214             /* Test if the address is still in the list */
01215             mcast = nif->if_mcast;
01216             mcast_prev = mcast;
01217             while(mcast)
01218             {
01219                 if (ip_addr == mcast->mca_ip)
01220                 {
01221                     /* The address is in the list, leave the loop */
01222                     break;
01223                 }
01224                 mcast_prev = mcast;
01225                 mcast = mcast->mca_next;
01226             }
01227 
01228             if (NULL == mcast)
01229             {
01230                 /* The address is not in the list */
01231                 return -1;
01232             }
01233             
01234             /* 
01235              * Remove the address from the list 
01236              */
01237             mcast_next = mcast->mca_next;  
01238              
01239             /* Check if the first element must be removed */ 
01240             if (nif->if_mcast == mcast)
01241             {
01242                 /* 
01243                  * The element is the first one 
01244                  */
01245                 
01246                 /* The first element is now the "next" element */
01247                 nif->if_mcast = mcast_next;
01248                 free(mcast); 
01249             } else {
01250                 /*
01251                  * The element is in the middle of the list 
01252                  */
01253                  
01254                 /* The next element of the previous is the "next" element */
01255                 mcast_prev->mca_next = mcast_next;
01256                 free(mcast); 
01257             }
01258             
01259             /*
01260              * Clear the multicast filter, and rebuild it
01261              */
01262             
01263             /* Clear */ 
01264             for (i = 0; i < 7; i++) {
01265                 ni->ni_mar[i] = 0;
01266             }
01267              
01268             /* Rebuild  */  
01269             mcast = nif->if_mcast;
01270             while(mcast)
01271             {
01272                 /* Calculate MAR index, range 0...63 */
01273                 index  = ether_crc32_le(&mcast->mca_ha[0], 6);
01274                 index &= 0x3F;
01275             
01276                 /* Set multicast bit */            
01277                 ni->ni_mar[index / 8] |= (1 << (index % 8));
01278             
01279                 mcast = mcast->mca_next;
01280             }
01281             
01282             /* Update the MC hardware */
01283             NicUpdateMCHardware(ni);
01284             break;  
01285               
01286         default:
01287             rc = -1;
01288             break;
01289     }    
01290     
01291     return rc;
01292 }
01293 
01294 
01295 static NICINFO dcb_eth0;
01296 
01302 static IFNET ifn_eth0 = {
01303     IFT_ETHER,                  
01304     0,                          
01305     {0, 0, 0, 0, 0, 0},         
01306     0,                          
01307     0,                          
01308     0,                          
01309     ETHERMTU,                   
01310     0,                          
01311     0,                          
01312     0,                          
01313     NutEtherInput,              
01314     DmOutput,                   
01315     NutEtherOutput,             
01316     0                           
01317 };
01318 
01328 NUTDEVICE devDM9000E = {
01329     0,                          
01330     {'e', 't', 'h', '0', 0, 0, 0, 0, 0},        
01331     IFTYP_NET,                  
01332     0,                          
01333     0,                          
01334     &ifn_eth0,                  
01335     &dcb_eth0,                  
01336     DmInit,                     
01337     DmIOCtl,                    
01338     0,                          
01339     0,                          
01340 #ifdef __HARVARD_ARCH__
01341     0,                          
01342 #endif
01343     0,                          
01344     0,                          
01345     0                           
01346 };
01347 
01348 #endif /* NIC_BASE_ADDR */
01349