Nut/OS  4.10.3
API Reference
nicrtl.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2005 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  *
00032  */
00033 
00034 /*
00035  * $Log$
00036  * Revision 1.7  2009/02/06 15:37:39  haraldkipp
00037  * Added stack space multiplier and addend. Adjusted stack space.
00038  *
00039  * Revision 1.6  2009/01/17 11:26:38  haraldkipp
00040  * Getting rid of two remaining BSD types in favor of stdint.
00041  * Replaced 'u_int' by 'unsinged int' and 'uptr_t' by 'uintptr_t'.
00042  *
00043  * Revision 1.5  2008/08/11 06:59:17  haraldkipp
00044  * BSD types replaced by stdint types (feature request #1282721).
00045  *
00046  * Revision 1.4  2006/06/27 01:42:56  hwmaier
00047  * Fixed bug related to edge triggered interrupt mode (RTL_IRQ_RISING_EDGE) in ISR.
00048  *
00049  * Revision 1.3  2006/03/02 23:57:12  hwmaier
00050  * Include cfg/dev.h added
00051  *
00052  * Revision 1.2  2006/01/11 08:33:30  hwmaier
00053  * Changes to make receiver thread's stack size configurable and honour
00054  * the NUT_THREAD_NICRXSTACK configuration setting
00055  *
00056  * Revision 1.1  2005/07/26 18:02:40  haraldkipp
00057  * Moved from dev.
00058  *
00059  * Revision 1.15  2005/04/30 16:42:41  chaac
00060  * Fixed bug in handling of NUTDEBUG. Added include for cfg/os.h. If NUTDEBUG
00061  * is defined in NutConf, it will make effect where it is used.
00062  *
00063  * Revision 1.14  2005/02/10 07:06:18  hwmaier
00064  * Changes to incorporate support for AT90CAN128 CPU
00065  *
00066  * Revision 1.13  2005/02/05 20:42:38  haraldkipp
00067  * Force compiler error for leftover debug prints.
00068  *
00069  * Revision 1.12  2005/01/24 21:11:50  freckle
00070  * renamed NutEventPostFromIRQ into NutEventPostFromIrq
00071  *
00072  * Revision 1.11  2005/01/22 19:24:46  haraldkipp
00073  * Changed AVR port configuration names from PORTx to AVRPORTx.
00074  *
00075  * Revision 1.10  2005/01/21 16:49:46  freckle
00076  * Seperated calls to NutEventPostAsync between Threads and IRQs
00077  *
00078  * Revision 1.9  2004/12/17 15:31:28  haraldkipp
00079  * Support of rising edge interrupts for hardware w/o inverter gate.
00080  * Fixed compilation issue for hardware with RTL reset port.
00081  * Thanks to FOCUS Software Engineering Pty Ltd.
00082  *
00083  * Revision 1.8  2004/09/10 10:36:01  haraldkipp
00084  * ICCAVR compile problems fixed
00085  *
00086  * Revision 1.7  2004/08/25 10:41:00  haraldkipp
00087  * Hardware dependent definitions are configurable. For performance reasons the
00088  * base address is not kept in a variable any longer. It is now a preprocessor
00089  * macro and the parameters during device registration are ignored. The speed
00090  * improvements provided by Kolja Waschk for the LAN91C111 had been implemented
00091  * here too. The driver will not touch a port anymore unless a reset port bit
00092  * had been configured. For Ethernut 1.1 bit 4 PORTE must be specified in the
00093  * configuration. Finally, an EEPROM emulation had been added, which can use
00094  * address bus bits instead of wasting additional port pins. The required
00095  * hardware has been implemented on Rev.-G Ethernut 1.3 boards. This fixes the
00096  * Realtek full duplex problem.
00097  *
00098  * Revision 1.6  2004/05/17 19:14:53  haraldkipp
00099  * Added Bengt Florin's RTL8019 driver mods
00100  *
00101  * Revision 1.5  2004/03/16 16:48:27  haraldkipp
00102  * Added Jan Dubiec's H8/300 port.
00103  *
00104  * Revision 1.4  2003/08/05 20:05:59  haraldkipp
00105  * Bugfix. Empty MAC address is FF, not 00
00106  *
00107  * Revision 1.3  2003/07/17 09:39:56  haraldkipp
00108  * Optimized controller feeding.
00109  * Ignore LSB of packet status.
00110  *
00111  * Revision 1.2  2003/05/15 14:09:16  haraldkipp
00112  * Much better performance under heavy traffic.
00113  *
00114  * Revision 1.1.1.1  2003/05/09 14:40:48  haraldkipp
00115  * Initial using 3.2.1
00116  *
00117  */
00118 
00119 #include <cfg/os.h>
00120 #include <cfg/arch/avr.h>
00121 #include <cfg/dev.h>
00122 
00123 #include <string.h>
00124 
00125 #include <sys/atom.h>
00126 #include <sys/heap.h>
00127 #include <sys/thread.h>
00128 #include <sys/event.h>
00129 #include <sys/timer.h>
00130 #include <sys/confnet.h>
00131 
00132 #include <net/ether.h>
00133 #include <net/if_var.h>
00134 
00135 #include <dev/irqreg.h>
00136 #include <dev/nicrtl.h>
00137 #include "rtlregs.h"
00138 
00139 #ifdef NUTDEBUG
00140 #include <sys/osdebug.h>
00141 #include <net/netdebug.h>
00142 #endif
00143 
00144 #ifndef NUT_THREAD_NICRXSTACK
00145 #define NUT_THREAD_NICRXSTACK   640
00146 #endif
00147 
00148 /*
00149  * Determine ports, which had not been explicitely configured.
00150  */
00151 #if (RTL_EESK_AVRPORT == AVRPORTB)
00152 #define RTL_EESK_PIN    PINB
00153 #define RTL_EESK_DDR    DDRB
00154 
00155 #elif (RTL_EESK_AVRPORT == AVRPORTC)
00156 #define RTL_EE_MEMBUS
00157 #define RTL_EESK_PIN    PINC
00158 #define RTL_EESK_DDR    DDRC
00159 
00160 #elif (RTL_EESK_AVRPORT == AVRPORTD)
00161 #define RTL_EESK_PIN    PIND
00162 #define RTL_EESK_DDR    DDRD
00163 
00164 #elif (RTL_EESK_AVRPORT == AVRPORTE)
00165 #define RTL_EESK_PIN    PINE
00166 #define RTL_EESK_DDR    DDRE
00167 
00168 #elif (RTL_EESK_AVRPORT == AVRPORTF)
00169 #define RTL_EESK_PIN    PINF
00170 #define RTL_EESK_DDR    DDRF
00171 
00172 #endif /* RTL_EESK_AVRPORT */
00173 
00174 #if (RTL_EEDO_AVRPORT == AVRPORTB)
00175 #define RTL_EEDO_PORT   PORTB
00176 #define RTL_EEDO_DDR    DDRB
00177 
00178 #elif (RTL_EEDO_AVRPORT == AVRPORTC)
00179 #define RTL_EE_MEMBUS
00180 #define RTL_EEDO_PORT   PORTC
00181 #define RTL_EEDO_DDR    DDRC
00182 
00183 #elif (RTL_EEDO_AVRPORT == AVRPORTD)
00184 #define RTL_EEDO_PORT   PORTD
00185 #define RTL_EEDO_DDR    DDRD
00186 
00187 #elif (RTL_EEDO_AVRPORT == AVRPORTE)
00188 #define RTL_EEDO_PORT   PORTE
00189 #define RTL_EEDO_DDR    DDRE
00190 
00191 #elif (RTL_EEDO_AVRPORT == AVRPORTF)
00192 #define RTL_EEDO_PORT   PORTF
00193 #define RTL_EEDO_DDR    DDRF
00194 
00195 #endif /* RTL_EEDO_AVRPORT */
00196 
00197 #if (RTL_EEMU_AVRPORT == AVRPORTB)
00198 #define RTL_EEMU_PORT   PORTB
00199 #define RTL_EEMU_DDR    DDRB
00200 
00201 #elif (RTL_EEMU_AVRPORT == AVRPORTC)
00202 #define RTL_EE_MEMBUS
00203 #define RTL_EEMU_PORT   PORTC
00204 #define RTL_EEMU_DDR    DDRC
00205 
00206 #elif (RTL_EEMU_AVRPORT == AVRPORTD)
00207 #define RTL_EEMU_PORT   PORTD
00208 #define RTL_EEMU_DDR    DDRD
00209 
00210 #elif (RTL_EEMU_AVRPORT == AVRPORTE)
00211 #define RTL_EEMU_PORT   PORTE
00212 #define RTL_EEMU_DDR    DDRE
00213 
00214 #elif (RTL_EEMU_AVRPORT == AVRPORTF)
00215 #define RTL_EEMU_PORT   PORTF
00216 #define RTL_EEMU_DDR    DDRF
00217 
00218 #endif /* RTL_EEMU_AVRPORT */
00219 
00220 #if (RTL_RESET_AVRPORT == AVRPORTB)
00221 #define RTL_RESET_PORT   PORTB
00222 #define RTL_RESET_DDR    DDRB
00223 
00224 #elif (RTL_RESET_AVRPORT == AVRPORTD)
00225 #define RTL_RESET_PORT   PORTD
00226 #define RTL_RESET_DDR    DDRD
00227 
00228 #elif (RTL_RESET_AVRPORT == AVRPORTE)
00229 #define RTL_RESET_PORT   PORTE
00230 #define RTL_RESET_DDR    DDRE
00231 
00232 #elif (RTL_RESET_AVRPORT == AVRPORTF)
00233 #define RTL_RESET_PORT   PORTF
00234 #define RTL_RESET_DDR    DDRF
00235 
00236 #endif /* RTL_RESET_AVRPORT */
00237 
00238 
00242 #if (RTL_SIGNAL_IRQ == INT0)
00243 #define RTL_SIGNAL sig_INTERRUPT0
00244 #ifdef __AVR_ENHANCED__
00245 #define RTL_RISING_EDGE_MODE()   sbi(EICRA, ISC00); sbi(EICRA, ISC01)
00246 #endif
00247 
00248 #elif (RTL_SIGNAL_IRQ == INT1)
00249 #define RTL_SIGNAL sig_INTERRUPT1
00250 #ifdef __AVR_ENHANCED__
00251 #define RTL_RISING_EDGE_MODE()   sbi(EICRA, ISC10); sbi(EICRA, ISC11)
00252 #endif
00253 
00254 #elif (RTL_SIGNAL_IRQ == INT2)
00255 #define RTL_SIGNAL sig_INTERRUPT2
00256 #ifdef __AVR_ENHANCED__
00257 #define RTL_RISING_EDGE_MODE()   sbi(EICRA, ISC20); sbi(EICRA, ISC21)
00258 #endif
00259 
00260 #elif (RTL_SIGNAL_IRQ == INT3)
00261 #define RTL_SIGNAL sig_INTERRUPT3
00262 #ifdef __AVR_ENHANCED__
00263 #define RTL_RISING_EDGE_MODE()   sbi(EICRA, ISC30); sbi(EICRA, ISC31)
00264 #endif
00265 
00266 #elif (RTL_SIGNAL_IRQ == INT4)
00267 #define RTL_SIGNAL sig_INTERRUPT4
00268 #ifdef __AVR_ENHANCED__
00269 #define RTL_RISING_EDGE_MODE()   sbi(EICRB, ISC40); sbi(EICRB, ISC41)
00270 #endif
00271 
00272 #elif (RTL_SIGNAL_IRQ == INT6)
00273 #define RTL_SIGNAL sig_INTERRUPT6
00274 #ifdef __AVR_ENHANCED__
00275 #define RTL_RISING_EDGE_MODE()   sbi(EICRB, ISC60); sbi(EICRB, ISC61)
00276 #endif
00277 
00278 #elif (RTL_SIGNAL_IRQ == INT7)
00279 #define RTL_SIGNAL sig_INTERRUPT7
00280 #ifdef __AVR_ENHANCED__
00281 #define RTL_RISING_EDGE_MODE()   sbi(EICRB, ISC70); sbi(EICRB, ISC71)
00282 #endif
00283 
00284 #else
00285 #define RTL_SIGNAL sig_INTERRUPT5
00286 #ifdef __AVR_ENHANCED__
00287 #define RTL_RISING_EDGE_MODE()   sbi(EICRB, ISC50); sbi(EICRB, ISC51)
00288 #endif
00289 
00290 #endif /* RTL_SIGNAL_IRQ */
00291 
00292 
00296 #define NIC_PAGE_SIZE   0x100
00297 
00301 #define NIC_START_PAGE  0x40
00302 
00306 #define NIC_STOP_PAGE   0x60
00307 
00313 #define NIC_TX_PAGES    6
00314 
00335 #define NIC_TX_BUFFERS      1
00336 
00337 #define NIC_FIRST_TX_PAGE   NIC_START_PAGE
00338 #define NIC_FIRST_RX_PAGE   (NIC_FIRST_TX_PAGE + NIC_TX_PAGES * NIC_TX_BUFFERS)
00339 
00340 #define NIC_CR_PAGE0 (0)
00341 #define NIC_CR_PAGE1 (NIC_CR_PS0)
00342 #define NIC_CR_PAGE2 (NIC_CR_PS1)
00343 #define NIC_CR_PAGE3 (NIC_CR_PS1 | NIC_CR_PS0)
00344 
00345 /*
00346  * This delay has been added by Bengt Florin and is used to minimize
00347  * the effect of the IORDY line during reads. Bengt contributed a
00348  * more versatile loop, which unfortunately wasn't portable to the
00349  * ImageCraft compiler.
00350  *
00351  * Both versions depend on the CPU clock and had been tested with
00352  * 14.7456 MHz.
00353  */
00354 static INLINE void Delay16Cycles(void)
00355 {
00356     _NOP();
00357     _NOP();
00358     _NOP();
00359     _NOP();
00360     _NOP();
00361     _NOP();
00362     _NOP();
00363     _NOP();
00364     _NOP();
00365     _NOP();
00366     _NOP();
00367     _NOP();
00368     _NOP();
00369     _NOP();
00370     _NOP();
00371     _NOP();
00372 }
00373 
00378 
00382 struct nic_pkt_header {
00383     uint8_t ph_status;           
00384     uint8_t ph_nextpg;           
00385     uint16_t ph_size;            
00386 };
00387 
00388 #define NICINB(reg)         (*((volatile uint8_t *)RTL_BASE_ADDR + reg))
00389 #define NICOUTB(reg, val)   (*((volatile uint8_t *)RTL_BASE_ADDR + reg) = val)
00390 
00395 static int NicReset(void)
00396 {
00397     uint8_t i;
00398     uint8_t j;
00399 
00400 /*
00401  * Toggle the hardware reset line. Since Ethernut version 1.3 the
00402  * hardware reset pin of the nic is no longer connected to bit 4
00403  * on port E, but wired to the board reset line.
00404  */
00405 #ifdef RTL_RESET_BIT
00406     sbi(RTL_RESET_DDR, RTL_RESET_BIT);
00407     sbi(RTL_RESET_PORT, RTL_RESET_BIT);
00408     NutDelay(WAIT100);
00409     cbi(RTL_RESET_PORT, RTL_RESET_BIT);
00410     NutDelay(WAIT250);
00411     NutDelay(WAIT250);
00412 #endif
00413 
00414     /*
00415      * Do the software reset by reading from the reset register followed
00416      * by writing to the reset register. Wait until the controller enters
00417      * the reset state.
00418      */
00419     for (j = 0; j < 20; j++) {
00420         i = NICINB(NIC_RESET);
00421         NutDelay(WAIT5);
00422         NICOUTB(NIC_RESET, i);
00423         for (i = 0; i < 20; i++) {
00424             NutDelay(WAIT50);
00425             /*
00426              * We got the reset bit. However, Ethernut 1.1 may
00427              * still fail because the NIC hasn't got it's hardware
00428              * reset and the data lines remain in tristate. So we
00429              * read noise instead of the register. To solve this
00430              * problem, we will verify the NIC's id.
00431              */
00432             if ((NICINB(NIC_PG0_ISR) & NIC_ISR_RST) != 0 &&     /* */
00433                 NICINB(NIC_PG0_RBCR0) == 0x50 &&        /* */
00434                 NICINB(NIC_PG0_RBCR1) == 0x70)
00435                 return 0;
00436         }
00437     }
00438     return -1;
00439 }
00440 
00441 static int DetectNicEeprom(void)
00442 {
00443 #ifdef RTL_EESK_BIT
00444     register unsigned int cnt = 0;
00445 
00446     NutEnterCritical();
00447 
00448     /*
00449      * Prepare the EEPROM emulation port bits. Configure the EEDO
00450      * and the EEMU lines as outputs and set both lines to high.
00451      */
00452     sbi(RTL_EEDO_PORT, RTL_EEDO_BIT);
00453     sbi(RTL_EEDO_DDR, RTL_EEDO_BIT);
00454 #ifdef RTL_EEMU_BIT
00455     sbi(RTL_EEMU_PORT, RTL_EEMU_BIT);
00456     sbi(RTL_EEMU_DDR, RTL_EEMU_BIT);
00457 #endif
00458     NutDelay(20);
00459 
00460     /*
00461      * Force the chip to re-read the EEPROM contents.
00462      */
00463     NICOUTB(NIC_CR, NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0 | NIC_CR_PS1);
00464     NICOUTB(NIC_PG3_EECR, NIC_EECR_EEM0);
00465 
00466     /*
00467      * No external memory access beyond this point.
00468      */
00469 #ifdef RTL_EE_MEMBUS
00470     /*
00471      * No external memory access beyond this point.
00472      */
00473 #ifdef __AVR_ENHANCED__
00474     /* On the ATmega 128 we release bits 5-7 as normal port pins. */
00475     outb(XMCRB, inb(XMCRB) | _BV(XMM0) | _BV(XMM1));
00476 #else
00477     /* On the ATmega 103 we have to disable the external memory interface. */
00478     cbi(MCUCR, SRE);
00479 #endif
00480 #endif
00481 
00482     /*
00483      * Check, if the chip toggles our EESK input. If not, we do not
00484      * have EEPROM emulation hardware.
00485      */
00486     if (bit_is_set(RTL_EESK_PIN, RTL_EESK_BIT)) {
00487         while (++cnt && bit_is_set(RTL_EESK_PIN, RTL_EESK_BIT));
00488     } else {
00489         while (++cnt && bit_is_clear(RTL_EESK_PIN, RTL_EESK_BIT));
00490     }
00491 
00492 #ifdef RTL_EE_MEMBUS
00493     /*
00494      * Enable memory interface.
00495      */
00496 #ifdef __AVR_ENHANCED__
00497     /* On the ATmega 128 we release bits 5-7 as normal port pins. */
00498     outb(XMCRB, inb(XMCRB) & ~(_BV(XMM0) | _BV(XMM1)));
00499 #else
00500     /* On the ATmega 103 we have to disable the external memory interface. */
00501     sbi(MCUCR, SRE);
00502 #endif
00503 #endif
00504 
00505     /* Reset port outputs to default. */
00506     cbi(RTL_EEDO_PORT, RTL_EEDO_BIT);
00507     cbi(RTL_EEDO_DDR, RTL_EEDO_BIT);
00508 #ifdef RTL_EEMU_BIT
00509     cbi(RTL_EEMU_PORT, RTL_EEMU_BIT);
00510     cbi(RTL_EEMU_DDR, RTL_EEMU_BIT);
00511 #endif
00512 
00513     /* Restore previous interrupt enable state. */
00514     NutExitCritical();
00515 
00516     /* Wait until controller ready. */
00517     while (NICINB(NIC_CR) != (NIC_CR_STP | NIC_CR_RD2));
00518 
00519     return cnt ? 0 : -1;
00520 #else
00521     return -1;
00522 #endif
00523 }
00524 
00525 #ifdef RTL_EESK_BIT
00526 /*
00527  * Emulated EEPROM contents.
00528  *
00529  * In jumper mode our influence is quite limited, only CONFIG3 and CONFIG4
00530  * can be modified.
00531  */
00532 static prog_char nic_eeprom[18] = {
00533     0xFF,                       /* CONFIG2: jPL1 jPL0   0      jBS4   jBS3   jBS2  jBS1  jBS0  */
00534     0xFF,                       /* CONFIG1: 1    jIRQS2 jIRQS1 jIRQS0 jIOS3  jIOS2 jIOS1 jIOS0 */
00535 
00536     0xFF,                       /* CONFIG4: -    -      -      -      -      -     -     IOMS  */
00537     0x30,                       /* CONFIG3  PNP  FUDUP  LEDS1  LEDS0  -      0     PWRDN ACTB  */
00538 
00539     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* MAC */
00540     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF      /* ID */
00541 };
00542 #endif
00543 
00553 static void EmulateNicEeprom(void)
00554 {
00555 #ifdef RTL_EESK_BIT
00556     register uint8_t clk;
00557     register uint8_t cnt;
00558     register uint8_t val;
00559 
00560     /*
00561      * Disable all interrupts. This routine requires critical timing
00562      * and optionally may disable the memory interface.
00563      */
00564     NutEnterCritical();
00565 
00566     /*
00567      * Prepare the EEPROM emulation port bits. Configure the EEDO and
00568      * the EEMU lines as outputs and set EEDO to low and EEMU to high.
00569      */
00570     cbi(RTL_EEDO_PORT, RTL_EEDO_BIT);
00571     sbi(RTL_EEDO_DDR, RTL_EEDO_BIT);
00572 #ifdef RTL_EEMU_BIT
00573     sbi(RTL_EEMU_PORT, RTL_EEMU_BIT);
00574     sbi(RTL_EEMU_DDR, RTL_EEMU_BIT);
00575 #endif
00576     NutDelay(20);
00577 
00578     /*
00579      * Start EEPROM configuration. Stop/abort any activity and select
00580      * configuration page 3. Setting bit EEM0 will force the controller
00581      * to read the EEPROM contents.
00582      */
00583 
00584     /* Select page 3, stop and abort/complete. */
00585     NICOUTB(NIC_CR, NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0 | NIC_CR_PS1);
00586     NICOUTB(NIC_PG3_EECR, NIC_EECR_EEM0);
00587 
00588     /*
00589      * We can avoid wasting port pins for EEPROM emulation by using the
00590      * upper bits of the address bus.
00591      */
00592 #ifdef RTL_EE_MEMBUS
00593     /*
00594      * No external memory access beyond this point.
00595      */
00596 #ifdef __AVR_ENHANCED__
00597     /* On the ATmega 128 we release bits 5-7 as normal port pins. */
00598     outb(XMCRB, inb(XMCRB) | _BV(XMM0) | _BV(XMM1));
00599 #else
00600     /* On the ATmega 103 we have to disable the external memory interface. */
00601     cbi(MCUCR, SRE);
00602 #endif
00603 #endif
00604 
00605     /*
00606      * Loop for all EEPROM words.
00607      */
00608     for (cnt = 0; cnt < sizeof(nic_eeprom);) {
00609 
00610         /*
00611          *
00612          * 1 start bit, always high
00613          * 2 op-code bits
00614          * 7 address bits
00615          * 1 dir change bit, always low
00616          */
00617         for (clk = 0; clk < 11; clk++) {
00618             while (bit_is_clear(RTL_EESK_PIN, RTL_EESK_BIT));
00619             while (bit_is_set(RTL_EESK_PIN, RTL_EESK_BIT));
00620         }
00621 
00622         /*
00623          * Shift out the high byte, MSB first. Our data changes at the EESK
00624          * rising edge. Data is sampled by the Realtek at the falling edge.
00625          */
00626         val = PRG_RDB(nic_eeprom + cnt);
00627         cnt++;
00628         for (clk = 0x80; clk; clk >>= 1) {
00629             while (bit_is_clear(RTL_EESK_PIN, RTL_EESK_BIT));
00630             if (val & clk)
00631                 sbi(RTL_EEDO_PORT, RTL_EEDO_BIT);
00632             while (bit_is_set(RTL_EESK_PIN, RTL_EESK_BIT));
00633             cbi(RTL_EEDO_PORT, RTL_EEDO_BIT);
00634         }
00635 
00636         /*
00637          * Shift out the low byte.
00638          */
00639         val = PRG_RDB(nic_eeprom + cnt);
00640         cnt++;
00641         for (clk = 0x80; clk; clk >>= 1) {
00642             while (bit_is_clear(RTL_EESK_PIN, RTL_EESK_BIT));
00643             if (val & clk)
00644                 sbi(RTL_EEDO_PORT, RTL_EEDO_BIT);
00645             while (bit_is_set(RTL_EESK_PIN, RTL_EESK_BIT));
00646             cbi(RTL_EEDO_PORT, RTL_EEDO_BIT);
00647         }
00648 
00649 
00650         /* 5 remaining clock cycles. */
00651         for (clk = 0; clk < 5; clk++) {
00652             while (bit_is_clear(RTL_EESK_PIN, RTL_EESK_BIT));
00653             while (bit_is_set(RTL_EESK_PIN, RTL_EESK_BIT));
00654         }
00655     }
00656 
00657 #ifdef RTL_EE_MEMBUS
00658     /*
00659      * Enable memory interface.
00660      */
00661 #ifdef __AVR_ENHANCED__
00662     /* On the ATmega 128 we release bits 5-7 as normal port pins. */
00663     outb(XMCRB, inb(XMCRB) & ~(_BV(XMM0) | _BV(XMM1)));
00664 #else
00665     /* On the ATmega 103 we have to disable the external memory interface. */
00666     sbi(MCUCR, SRE);
00667 #endif
00668 #endif
00669 
00670     /* Reset port outputs to default. */
00671     cbi(RTL_EEDO_DDR, RTL_EEDO_BIT);
00672 #ifdef RTL_EEMU_BIT
00673     cbi(RTL_EEMU_PORT, RTL_EEMU_BIT);
00674     cbi(RTL_EEMU_DDR, RTL_EEMU_BIT);
00675 #endif
00676 
00677     /* Restore previous interrupt enable state. */
00678     NutExitCritical();
00679 #endif
00680 }
00681 
00682 /*
00683  * Fires up the network interface. NIC interrupts
00684  * should have been disabled when calling this
00685  * function.
00686  */
00687 static int NicStart(CONST uint8_t * mac)
00688 {
00689     uint8_t i;
00690 
00691     if (NicReset()) {
00692         return -1;
00693     }
00694     if (DetectNicEeprom() == 0) {
00695         EmulateNicEeprom();
00696     }
00697 
00698     /*
00699      * Mask all interrupts and clear any interrupt status flag to set the
00700      * INT pin back to low.
00701      */
00702     NICOUTB(NIC_PG0_IMR, 0);
00703     NICOUTB(NIC_PG0_ISR, 0xff);
00704 
00705     /*
00706      * During reset the nic loaded its initial configuration from an
00707      * external eeprom. On the ethernut board we do not have any
00708      * configuration eeprom, but simply tied the eeprom data line to
00709      * high level. So we have to clear some bits in the configuration
00710      * register. Switch to register page 3.
00711      */
00712     NICOUTB(NIC_CR, NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0 | NIC_CR_PS1);
00713 
00714     /*
00715      * The nic configuration registers are write protected unless both
00716      * EEM bits are set to 1.
00717      */
00718     NICOUTB(NIC_PG3_EECR, NIC_EECR_EEM0 | NIC_EECR_EEM1);
00719 
00720     /*
00721      * Network media had been set to 10Base2 by the virtual EEPROM and
00722      * will be set now to auto detect. This will initiate a link test.
00723      * We don't force 10BaseT, because this would disable the link test.
00724      */
00725     NICOUTB(NIC_PG3_CONFIG2, NIC_CONFIG2_BSELB);
00726 
00727     /*
00728      * Disable sleep and power down.
00729      *
00730      * The virtual EEPROM (resistor tight to VCC) will set all bits of
00731      * CONFIG3 to 1. Unfortunately we are not able to modify the full
00732      * duplex bit. The only solution is to use a real EEPROM or emulate
00733      * one.
00734      */
00735     NICOUTB(NIC_PG3_CONFIG3, NIC_CONFIG3_LEDS1 | NIC_CONFIG3_LEDS1);
00736 
00737     /*
00738      * Reenable write protection of the nic configuration registers
00739      * and wait for link test to complete.
00740      */
00741     NICOUTB(NIC_PG3_EECR, 0);
00742     NutDelay(255);
00743 
00744     /*
00745      * Switch to register page 0 and set data configuration register
00746      * to byte-wide DMA transfers, normal operation (no loopback),
00747      * send command not executed and 8 byte fifo threshold.
00748      */
00749     NICOUTB(NIC_CR, NIC_CR_STP | NIC_CR_RD2);
00750     NICOUTB(NIC_PG0_DCR, NIC_DCR_LS | NIC_DCR_FT1);
00751 
00752     /*
00753      * Clear remote dma byte count register.
00754      */
00755     NICOUTB(NIC_PG0_RBCR0, 0);
00756     NICOUTB(NIC_PG0_RBCR1, 0);
00757 
00758     /*
00759      * Temporarily set receiver to monitor mode and transmitter to
00760      * internal loopback mode. Incoming packets will not be stored
00761      * in the nic ring buffer and no data will be send to the network.
00762      */
00763     NICOUTB(NIC_PG0_RCR, NIC_RCR_MON);
00764     NICOUTB(NIC_PG0_TCR, NIC_TCR_LB0);
00765 
00766     /*
00767      * Configure the nic's ring buffer page layout.
00768      * NIC_PG0_BNRY: Last page read.
00769      * NIC_PG0_PSTART: First page of receiver buffer.
00770      * NIC_PG0_PSTOP: Last page of receiver buffer.
00771      */
00772     NICOUTB(NIC_PG0_TPSR, NIC_FIRST_TX_PAGE);
00773     NICOUTB(NIC_PG0_BNRY, NIC_STOP_PAGE - 1);
00774     NICOUTB(NIC_PG0_PSTART, NIC_FIRST_RX_PAGE);
00775     NICOUTB(NIC_PG0_PSTOP, NIC_STOP_PAGE);
00776 
00777     /*
00778      * Once again clear interrupt status register.
00779      */
00780     NICOUTB(NIC_PG0_ISR, 0xff);
00781 
00782     /*
00783      * Switch to register page 1 and copy our MAC address into the nic.
00784      * We are still in stop mode.
00785      */
00786     NICOUTB(NIC_CR, NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0);
00787     for (i = 0; i < 6; i++)
00788         NICOUTB(NIC_PG1_PAR0 + i, mac[i]);
00789 
00790     /*
00791      * Clear multicast filter bits to disable all packets.
00792      */
00793     for (i = 0; i < 8; i++)
00794         NICOUTB(NIC_PG1_MAR0 + i, 0);
00795 
00796     /*
00797      * Set current page pointer to one page after the boundary pointer.
00798      */
00799     NICOUTB(NIC_PG1_CURR, NIC_FIRST_RX_PAGE);
00800 
00801     /*
00802      * Switch back to register page 0, remaining in stop mode.
00803      */
00804     NICOUTB(NIC_CR, NIC_CR_STP | NIC_CR_RD2);
00805 
00806     /*
00807      * Take receiver out of monitor mode and enable it for accepting
00808      * broadcasts.
00809      */
00810     NICOUTB(NIC_PG0_RCR, NIC_RCR_AB);
00811 
00812     /*
00813      * Clear all interrupt status flags and enable interrupts.
00814      */
00815     NICOUTB(NIC_PG0_ISR, 0xff);
00816     /* Note: transmitter if polled, thus no NIC_IMR_PTXE */
00817     NICOUTB(NIC_PG0_IMR, NIC_IMR_PRXE | NIC_IMR_RXEE | NIC_IMR_TXEE | NIC_IMR_OVWE);
00818 
00819     /*
00820      * Fire up the nic by clearing the stop bit and setting the start bit.
00821      * To activate the local receive dma we must also take the nic out of
00822      * the local loopback mode.
00823      */
00824     NICOUTB(NIC_CR, NIC_CR_STA | NIC_CR_RD2);
00825     NICOUTB(NIC_PG0_TCR, 0);
00826 
00827     NutDelay(255);
00828 
00829     return 0;
00830 }
00831 
00835 static void NicCompleteDma(void)
00836 {
00837     uint8_t i;
00838 
00839     /*
00840      * Complete remote dma.
00841      */
00842     NICOUTB(NIC_CR, NIC_CR_STA | NIC_CR_RD2);
00843 
00844     /*
00845      * Check that we have a DMA complete flag.
00846      */
00847     for (i = 0; i <= 20; i++)
00848         if (NICINB(NIC_PG0_ISR) & NIC_ISR_RDC)
00849             break;
00850 
00851     /*
00852      * Reset remote dma complete flag.
00853      */
00854     NICOUTB(NIC_PG0_ISR, NIC_ISR_RDC);
00855 }
00856 
00857 /*
00858  * Write data block to the NIC.
00859  */
00860 static void NicWrite(uint8_t * buf, uint16_t len)
00861 {
00862     register uint16_t l = len - 1;
00863     register uint8_t ih = (uint16_t) l >> 8;
00864     register uint8_t il = (uint8_t) l;
00865 
00866     if (!len)
00867         return;
00868 
00869     do {
00870         do {
00871             NICOUTB(NIC_IOPORT, *buf++);
00872         } while (il-- != 0);
00873     } while (ih-- != 0);
00874 }
00875 
00876 /*
00877  * Read data block from the NIC.
00878  */
00879 static void NicRead(uint8_t * buf, uint16_t len)
00880 {
00881     register uint16_t l = len - 1;
00882     register uint8_t ih = (uint16_t) l >> 8;
00883     register uint8_t il = (uint8_t) l;
00884 
00885     if (!len)
00886         return;
00887 
00888     do {
00889         do {
00890             *buf++ = NICINB(NIC_IOPORT);
00891         } while (il-- != 0);
00892     } while (ih-- != 0);
00893 }
00894 
00895 
00909 static int NicPutPacket(NETBUF * nb)
00910 {
00911     uint16_t sz;
00912     uint16_t i;
00913     uint8_t padding = 0;
00914 
00915     /*
00916      * Calculate the number of bytes to be send. Do not
00917      * send packets larger than 1514 bytes.
00918      *
00919      * The previous version was wrong by specifying a maximum
00920      * of 1518, because it didn't take the CRC into account,
00921      * which is generated by the hardware and automatically
00922      * appended. Thanks to Bengt Florin, who discovered this.
00923      */
00924     sz = nb->nb_dl.sz + nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz;
00925     if (sz > 1514)
00926         return -1;
00927 
00928     /*
00929      * The controller will not append pad bytes,
00930      * so we have to do this.
00931      */
00932     if (sz < 60) {
00933         padding = (uint8_t) (60 - sz);
00934         sz = 60;
00935     }
00936 
00937     /*
00938      * Bengt Florin introduces polling mode for the transmitter. Be
00939      * aware, that this may introduce other problems. If a high
00940      * priority thread is waiting for the transmitter, it may hold
00941      * the CPU for more than 1.2 milliseconds in worst cases.
00942      */
00943     while (NICINB(NIC_CR) & NIC_CR_TXP)
00944         NutThreadYield();
00945 
00946     /* we don't want to be interrupted by NIC owerflow */
00947     cbi(EIMSK, RTL_SIGNAL_IRQ);
00948 
00949     /*
00950      * Set remote dma byte count
00951      * and start address.
00952      */
00953     NICOUTB(NIC_PG0_RBCR0, sz);
00954     NICOUTB(NIC_PG0_RBCR1, sz >> 8);
00955     NICOUTB(NIC_PG0_RSAR0, 0);
00956     NICOUTB(NIC_PG0_RSAR1, NIC_FIRST_TX_PAGE);
00957 
00958     /*
00959      * Peform the write.
00960      */
00961     NICOUTB(NIC_CR, NIC_CR_STA | NIC_CR_RD1);
00962 
00963     /*
00964      * Transfer the Ethernet frame.
00965      */
00966     NicWrite(nb->nb_dl.vp, nb->nb_dl.sz);
00967     NicWrite(nb->nb_nw.vp, nb->nb_nw.sz);
00968     NicWrite(nb->nb_tp.vp, nb->nb_tp.sz);
00969     NicWrite(nb->nb_ap.vp, nb->nb_ap.sz);
00970 
00971     /*
00972      * Add pad bytes.
00973      */
00974     for (i = 0; i < padding; i++)
00975         NICOUTB(NIC_IOPORT, 0);
00976 
00977     /*
00978      * Complete remote dma.
00979      */
00980     NicCompleteDma();
00981 
00982     /*
00983      * Number of bytes to be transmitted.
00984      */
00985     NICOUTB(NIC_PG0_TBCR0, (sz & 0xff));
00986     NICOUTB(NIC_PG0_TBCR1, ((sz >> 8) & 0xff));
00987 
00988     /*
00989      * First page of packet to be transmitted.
00990      */
00991     NICOUTB(NIC_PG0_TPSR, NIC_FIRST_TX_PAGE);
00992 
00993     /*
00994      * Start transmission.
00995      */
00996     NICOUTB(NIC_CR, NIC_CR_STA | NIC_CR_TXP | NIC_CR_RD2);
00997 
00998     sbi(EIMSK, RTL_SIGNAL_IRQ);
00999 
01000     return 0;
01001 }
01002 
01013 static NETBUF *NicGetPacket(void)
01014 {
01015     NETBUF *nb = 0;
01016     struct nic_pkt_header hdr;
01017     uint16_t count;
01018     uint8_t *buf;
01019     uint8_t nextpg;
01020     uint8_t bnry;
01021     uint8_t curr;
01022     uint16_t i;
01023     uint8_t drop = 0;
01024 
01025     /* we don't want to be interrupted by NIC owerflow */
01026     cbi(EIMSK, RTL_SIGNAL_IRQ);
01027     /*
01028      * Get the current page pointer. It points to the page where the NIC
01029      * will start saving the next incoming packet.
01030      */
01031     NICOUTB(NIC_CR, NIC_CR_STA | NIC_CR_RD2 | NIC_CR_PS0);
01032     Delay16Cycles();
01033     curr = NICINB(NIC_PG1_CURR);
01034     NICOUTB(NIC_CR, NIC_CR_STA | NIC_CR_RD2);
01035 
01036     /*
01037      * Get the pointer to the last page we read from. The following page
01038      * is the one where we start reading. If it's equal to the current
01039      * page pointer, then there's nothing to read. In this case we return
01040      * a null pointer.
01041      */
01042     if ((bnry = NICINB(NIC_PG0_BNRY) + 1) >= NIC_STOP_PAGE)
01043         bnry = NIC_FIRST_RX_PAGE;
01044 
01045     if (bnry == curr) {
01046         sbi(EIMSK, RTL_SIGNAL_IRQ);
01047         return 0;
01048     }
01049 
01050     /*
01051      * Read the NIC specific packet header.
01052      */
01053     NICOUTB(NIC_PG0_RBCR0, sizeof(struct nic_pkt_header));
01054     NICOUTB(NIC_PG0_RBCR1, 0);
01055     NICOUTB(NIC_PG0_RSAR0, 0);
01056     NICOUTB(NIC_PG0_RSAR1, bnry);
01057     buf = (uint8_t *) & hdr;
01058     NICOUTB(NIC_CR, NIC_CR_STA | NIC_CR_RD0);
01059     Delay16Cycles();
01060     for (i = 0; i < sizeof(struct nic_pkt_header); i++)
01061         *buf++ = NICINB(NIC_IOPORT);
01062     NicCompleteDma();
01063 
01064     /*
01065      *  Check packet length. Silently discard packets of illegal size.
01066      */
01067     if (hdr.ph_size < 60 + sizeof(struct nic_pkt_header) ||     /* */
01068         hdr.ph_size > 1514 + sizeof(struct nic_pkt_header)) {
01069         drop = 1;
01070     }
01071 
01072     /*
01073      * Calculate the page of the next packet. If it differs from the
01074      * pointer in the packet header, we return with errorcode.
01075      */
01076     nextpg = bnry + (hdr.ph_size >> 8) + ((hdr.ph_size & 0xFF) != 0);
01077     if (nextpg >= NIC_STOP_PAGE) {
01078         nextpg -= NIC_STOP_PAGE;
01079         nextpg += NIC_FIRST_RX_PAGE;
01080     }
01081     if (nextpg != hdr.ph_nextpg) {
01082         uint8_t nextpg1 = nextpg + 1;
01083         if (nextpg1 >= NIC_STOP_PAGE) {
01084             nextpg1 -= NIC_STOP_PAGE;
01085             nextpg1 += NIC_FIRST_RX_PAGE;
01086         }
01087         if (nextpg1 != hdr.ph_nextpg) {
01088             sbi(EIMSK, RTL_SIGNAL_IRQ);
01089             return (NETBUF *) 0xFFFF;
01090         }
01091         nextpg = nextpg1;
01092     }
01093 
01094     /*
01095      * Check packet status. It should have set bit 0, but
01096      * even without this bit packets seem to be OK.
01097      */
01098     if (!drop && ((hdr.ph_status & 0x0E) == 0)) {
01099         /*
01100          * Allocate a NETBUF.
01101          * Omit the fcs.
01102          */
01103         count = hdr.ph_size - 4;
01104         if ((nb = NutNetBufAlloc(0, NBAF_DATALINK, count))) {
01105             /*
01106              * Set remote dma byte count and
01107              * start address. Don't read the
01108              * header again.
01109              */
01110             NICOUTB(NIC_PG0_RBCR0, count);
01111             NICOUTB(NIC_PG0_RBCR1, count >> 8);
01112             NICOUTB(NIC_PG0_RSAR0, sizeof(struct nic_pkt_header));
01113             NICOUTB(NIC_PG0_RSAR1, bnry);
01114 
01115             /*
01116              * Perform the read.
01117              */
01118             NICOUTB(NIC_CR, NIC_CR_STA | NIC_CR_RD0);
01119             Delay16Cycles();
01120             NicRead(nb->nb_dl.vp, count);
01121             NicCompleteDma();
01122         }
01123     }
01124 
01125     /*
01126      * Set boundary register to the last page we read.
01127      * This also drops packets with errors
01128      */
01129     if (--nextpg < NIC_FIRST_RX_PAGE)
01130         nextpg = NIC_STOP_PAGE - 1;
01131     NICOUTB(NIC_PG0_BNRY, nextpg);
01132 
01133     sbi(EIMSK, RTL_SIGNAL_IRQ);
01134     return nb;
01135 }
01136 
01137 /*
01138  * \brief Handle NIC overflows.
01139  *
01140  * When a receiver buffer overflow occurs, the NIC will defer any subsequent
01141  * action until properly restarted.
01142  *
01143  * This routine is called within interrupt context, which introduces a big
01144  * problem. It waits for the last transmission to finish, which may take
01145  * several milliseconds. Since Nut/OS 3.5, we do not support nested interrupts
01146  * on AVR systems anymore. So this routine may now increase interrupt
01147  * latency in an unacceptable way. The solution might be to handle overflows
01148  * in the receiver thread.
01149  *
01150  * In any case, this routines needs a major redesign. But it has been
01151  * tested in its current form to gracefully withstand ping floods. Thanks
01152  * to Bengt Florin for contributing his code, which provides much more
01153  * stability than its predecessor.
01154  */
01155 static uint8_t NicOverflow(void)
01156 {
01157     uint8_t cr;
01158     uint8_t resend = 0;
01159     uint8_t curr;
01160 
01161     /*
01162      * Wait for any transmission in progress. Save the command register,
01163      * so we can later determine, if NIC transmitter has been interrupted.
01164      * or reception in progress.
01165      */
01166     while (NICINB(NIC_CR) & NIC_CR_TXP);
01167     cr = NICINB(NIC_CR);
01168 
01169     /*
01170      * Get the current page pointer. It points to the page where the NIC
01171      * will start saving the next incoming packet.
01172      */
01173     NICOUTB(NIC_CR, NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0);
01174     curr = NICINB(NIC_PG1_CURR);
01175     NICOUTB(NIC_CR, NIC_CR_STP | NIC_CR_RD2);
01176 
01177     /* Clear remote byte count register. */
01178     NICOUTB(NIC_PG0_RBCR0, 0);
01179     NICOUTB(NIC_PG0_RBCR1, 0);
01180 
01181     /* Check for any incomplete transmission. */
01182     if ((cr & NIC_CR_TXP) && ((NICINB(NIC_PG0_ISR) & (NIC_ISR_PTX | NIC_ISR_TXE)) == 0)) {
01183         resend = 1;
01184     }
01185 
01186     /* Enter loopback mode and restart the NIC. */
01187     NICOUTB(NIC_PG0_TCR, NIC_TCR_LB0);
01188     NICOUTB(NIC_CR, NIC_CR_STA | NIC_CR_RD2);
01189 
01190     /*
01191      * Discard all packets from the receiver buffer. Set boundary
01192      * register to the last page we read.
01193      */
01194     if (--curr < NIC_FIRST_RX_PAGE) {
01195         curr = NIC_STOP_PAGE - 1;
01196     }
01197     NICOUTB(NIC_PG0_BNRY, curr);
01198 
01199     /* Switch from loopback to normal mode mode. */
01200     NICOUTB(NIC_PG0_TCR, 0);
01201 
01202     /* Re-invoke any interrupted transmission. */
01203     if (resend) {
01204         NICOUTB(NIC_CR, NIC_CR_STA | NIC_CR_TXP | NIC_CR_RD2);
01205     }
01206 
01207     /* Finally clear the overflow flag */
01208     NICOUTB(NIC_PG0_ISR, NIC_ISR_OVW);
01209     return resend;
01210 }
01211 
01212 
01213 /*
01214  * \brief NIC interrupt entry.
01215  */
01216 static void NicInterrupt(void *arg)
01217 {
01218     uint8_t isr;
01219     NICINFO *ni = (NICINFO *) ((NUTDEVICE *) arg)->dev_dcb;
01220 
01221     ni->ni_interrupts++;
01222 
01223 #ifdef RTL_IRQ_RISING_EDGE
01224     do
01225     {
01226 #endif 
01227     isr = NICINB(NIC_PG0_ISR);
01228     NICOUTB(NIC_PG0_ISR, isr);
01229 
01230     /*
01231      * Recover from receive buffer overflow. This may take some
01232      * time, so we enable global interrupts but keep NIC
01233      * interrupts disabled.
01234      */
01235     if (isr & NIC_ISR_OVW) {
01236         /* The AVR platform uses a dedicated interrupt stack, which
01237          * forbids interrupt nesting. */
01238 #if !defined(__AVR__)
01239         cbi(EIMSK, RTL_SIGNAL_IRQ);
01240         sei();
01241 #endif
01242         NicOverflow();
01243 #if !defined(__AVR__)
01244         cli();
01245         sbi(EIMSK, RTL_SIGNAL_IRQ);
01246 #endif
01247         ni->ni_rx_overruns++;
01248     } else {
01249         /*
01250          * If this is a transmit interrupt, then a packet has been sent.
01251          * So we can clear the transmitter busy flag and wake up the
01252          * transmitter thread.
01253          */
01254         if (isr & NIC_ISR_TXE)
01255             ni->ni_tx_errors++;
01256 
01257         /*
01258          * If this is a receive interrupt, then wake up the receiver
01259          * thread.
01260          */
01261         if (isr & NIC_ISR_PRX)
01262             NutEventPostFromIrq(&ni->ni_rx_rdy);
01263 
01264         if (isr & NIC_ISR_RXE) {
01265             ni->ni_rx_frame_errors += NICINB(NIC_PG0_CNTR0);
01266             ni->ni_rx_crc_errors += NICINB(NIC_PG0_CNTR1);
01267             ni->ni_rx_missed_errors += NICINB(NIC_PG0_CNTR2);
01268         }
01269     }
01270 #ifdef RTL_IRQ_RISING_EDGE
01271     /* Check that all unmasked interrupts are cleared before we
01272     * leave the ISR to assert the INT line goes back to low
01273     * and a new interrupt edge will be generated for following
01274     * interrupts.
01275     */
01276     }
01277     while (bit_is_set(PINE, RTL_SIGNAL_IRQ));
01278 #endif
01279 }
01280 
01287 THREAD(NicRx, arg)
01288 {
01289     NUTDEVICE *dev;
01290     IFNET *ifn;
01291     NICINFO *ni;
01292     NETBUF *nb;
01293 
01294     dev = arg;
01295     ifn = (IFNET *) dev->dev_icb;
01296     ni = (NICINFO *) dev->dev_dcb;
01297 
01298     NutThreadSetPriority(9);
01299     /*
01300      * This is a temporary hack. Due to a change in initialization,
01301      * we may not have got a MAC address yet. Wait until one has been
01302      * set.
01303      */
01304     if ((ifn->if_mac[0] & ifn->if_mac[1] & ifn->if_mac[2]) == 0xFF) {
01305         while ((ifn->if_mac[0] & ifn->if_mac[1] & ifn->if_mac[2]) == 0xFF)
01306             NutSleep(125);
01307         cbi(EIMSK, RTL_SIGNAL_IRQ);
01308         NicStart(ifn->if_mac);
01309         sbi(EIMSK, RTL_SIGNAL_IRQ);
01310     }
01311 
01312     while (1) {
01313         NutEventWait(&ni->ni_rx_rdy, 0);
01314         /*
01315          * Fetch all packets from the NIC's internal
01316          * buffer and pass them to the registered handler.
01317          */
01318         do {
01319             nb = NicGetPacket();
01320 
01321             /* The sanity check may fail because the controller is too busy.
01322                restart the NIC. */
01323             if ((uint16_t) nb == 0xFFFF) {
01324                 NicStart(ifn->if_mac);
01325                 ni->ni_rx_size_errors++;
01326             } else if (nb) {
01327                 ni->ni_rx_packets++;
01328                 (*ifn->if_recv) (dev, nb);
01329             }
01330         } while (nb);
01331     }
01332 }
01333 
01344 int NicOutput(NUTDEVICE * dev, NETBUF * nb)
01345 {
01346     int rc = -1;
01347     NICINFO *ni = (NICINFO *) dev->dev_dcb;
01348 
01349     if (NicPutPacket(nb) == 0) {
01350         ni->ni_tx_packets++;
01351         rc = 0;
01352     }
01353     return rc;
01354 }
01355 
01376 int NicInit(NUTDEVICE * dev)
01377 {
01378     IFNET *ifn;
01379     NICINFO *ni;
01380 
01381     /*
01382      * We need to know our MAC address. If no configuration is
01383      * available, load it now.
01384      */
01385     if (confnet.cd_size == 0)
01386         NutNetLoadConfig(dev->dev_name);
01387 
01388     ifn = dev->dev_icb;
01389     memcpy(ifn->if_mac, confnet.cdn_mac, 6);
01390     ni = (NICINFO *) dev->dev_dcb;
01391     memset(ni, 0, sizeof(NICINFO));
01392 
01393     /*
01394      * Start the receiver thread.
01395      */
01396     NutThreadCreate("rxi5", NicRx, dev, 
01397         (NUT_THREAD_NICRXSTACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD);
01398     NutSleep(WAIT500);
01399 
01400     /*
01401      * Register interrupt handler and enable interrupts.
01402      */
01403     if (NutRegisterIrqHandler(&RTL_SIGNAL, NicInterrupt, dev))
01404         return -1;
01405 
01406     cbi(EIMSK, RTL_SIGNAL_IRQ);
01407 #ifdef RTL_IRQ_RISING_EDGE
01408     /* Support of rising edge interrupts for HW w/o inverter gate */
01409     RTL_RISING_EDGE_MODE();
01410 #endif
01411 
01412     if (ifn->if_mac[0] | ifn->if_mac[1] | ifn->if_mac[2])
01413         if (NicStart(ifn->if_mac))
01414             return -1;
01415 
01416     sbi(EIMSK, RTL_SIGNAL_IRQ);
01417 
01418     return 0;
01419 }
01420 
01421