lanc111.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2003-2006 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: lanc111.c,v $
00036  * Revision 1.7  2008/08/11 06:59:17  haraldkipp
00037  * BSD types replaced by stdint types (feature request #1282721).
00038  *
00039  * Revision 1.6  2007/05/02 11:22:51  haraldkipp
00040  * Added multicast table entry.
00041  *
00042  * Revision 1.5  2006/10/08 16:48:08  haraldkipp
00043  * Documentation fixed
00044  *
00045  * Revision 1.4  2006/06/28 14:30:19  haraldkipp
00046  * Post to the event queue on overflow interrupts.
00047  * Transmit event queue removed, because no one is listening.
00048  *
00049  * Revision 1.3  2005/10/24 18:02:34  haraldkipp
00050  * Fixes for ATmega103.
00051  *
00052  * Revision 1.2  2005/08/02 17:46:45  haraldkipp
00053  * Major API documentation update.
00054  *
00055  * Revision 1.1  2005/07/26 18:02:40  haraldkipp
00056  * Moved from dev.
00057  *
00058  * Revision 1.13  2005/04/30 16:42:41  chaac
00059  * Fixed bug in handling of NUTDEBUG. Added include for cfg/os.h. If NUTDEBUG
00060  * is defined in NutConf, it will make effect where it is used.
00061  *
00062  * Revision 1.12  2005/02/02 19:55:34  haraldkipp
00063  * If no Ethernet link was available on the LAN91C111, each outgoing packet
00064  * took 15 seconds and, even worse, the ouput routine doesn't return an error.
00065  * Now the first attempt to send a packet without Ethernet link will wait for
00066  * 5 seconds and subsequent attempts take 0.5 seconds only, always returning
00067  * an error.
00068  *
00069  * Revision 1.11  2005/01/24 21:11:49  freckle
00070  * renamed NutEventPostFromIRQ into NutEventPostFromIrq
00071  *
00072  * Revision 1.10  2005/01/22 19:24:11  haraldkipp
00073  * Changed AVR port configuration names from PORTx to AVRPORTx.
00074  *
00075  * Revision 1.9  2005/01/21 16:49:45  freckle
00076  * Seperated calls to NutEventPostAsync between Threads and IRQs
00077  *
00078  * Revision 1.8  2004/09/22 08:14:48  haraldkipp
00079  * Made configurable
00080  *
00081  * Revision 1.7  2004/03/08 11:14:17  haraldkipp
00082  * Added quick hack for fixed mode.
00083  *
00084  * Revision 1.6  2004/02/25 16:22:33  haraldkipp
00085  * Do not initialize MAC with all zeros
00086  *
00087  * Revision 1.5  2004/01/14 19:31:43  drsung
00088  * Speed improvement to NicWrite applied. Thanks to Kolja Waschk
00089  *
00090  * Revision 1.4  2003/11/06 09:26:50  haraldkipp
00091  * Removed silly line with hardcoded MAC, left over from testing
00092  *
00093  * Revision 1.3  2003/11/04 17:54:47  haraldkipp
00094  * PHY configuration timing changed again for reliable linking
00095  *
00096  * Revision 1.2  2003/11/03 17:12:53  haraldkipp
00097  * Allow linking with RTL8019 driver.
00098  * Links more reliable to 10 MBit networks now.
00099  * Reset MMU on allocation failures.
00100  * Some optimizations.
00101  *
00102  * Revision 1.1  2003/10/13 10:13:49  haraldkipp
00103  * First release
00104  *
00105  */
00106 
00107 #include <cfg/os.h>
00108 #include <cfg/arch/avr.h>
00109 
00110 #include <string.h>
00111 
00112 #include <sys/atom.h>
00113 #include <sys/heap.h>
00114 #include <sys/thread.h>
00115 #include <sys/event.h>
00116 #include <sys/timer.h>
00117 #include <sys/confnet.h>
00118 
00119 #include <netinet/if_ether.h>
00120 #include <net/ether.h>
00121 #include <net/if_var.h>
00122 
00123 #include <dev/irqreg.h>
00124 #include <dev/lanc111.h>
00125 
00126 #ifdef NUTDEBUG
00127 #include <stdio.h>
00128 #endif
00129 
00130 /*
00131  * Determine ports, which had not been explicitely configured.
00132  */
00133 #ifndef LANC111_BASE_ADDR
00134 #define LANC111_BASE_ADDR   0xC000
00135 #endif
00136 
00137 #ifndef LANC111_SIGNAL_IRQ
00138 #define LANC111_SIGNAL_IRQ  INT5
00139 #endif
00140 
00141 #ifdef LANC111_RESET_BIT
00142 
00143 #if (LANC111_RESET_AVRPORT == AVRPORTB)
00144 #define LANC111_RESET_PORT   PORTB
00145 #define LANC111_RESET_DDR    DDRB
00146 
00147 #elif (LANC111_RESET_AVRPORT == AVRPORTD)
00148 #define LANC111_RESET_PORT   PORTD
00149 #define LANC111_RESET_DDR    DDRD
00150 
00151 #elif (LANC111_RESET_AVRPORT == AVRPORTE)
00152 #define LANC111_RESET_PORT   PORTE
00153 #define LANC111_RESET_DDR    DDRE
00154 
00155 #elif (LANC111_RESET_AVRPORT == AVRPORTF)
00156 #define LANC111_RESET_PORT   PORTF
00157 #define LANC111_RESET_DDR    DDRF
00158 
00159 #endif /* LANC111_RESET_AVRPORT */
00160 
00161 #endif /* LANC111_RESET_BIT */
00162 
00163 /*
00164  * Determine interrupt settings.
00165  */
00166 #if (LANC111_SIGNAL_IRQ == INT0)
00167 #define LANC111_SIGNAL          sig_INTERRUPT0
00168 #define LANC111_SIGNAL_MODE()   sbi(EICRA, ISC00); sbi(EICRA, ISC01)
00169 
00170 #elif (LANC111_SIGNAL_IRQ == INT1)
00171 #define LANC111_SIGNAL          sig_INTERRUPT1
00172 #define LANC111_SIGNAL_MODE()   sbi(EICRA, ISC10); sbi(EICRA, ISC11)
00173 
00174 #elif (LANC111_SIGNAL_IRQ == INT2)
00175 #define LANC111_SIGNAL          sig_INTERRUPT2
00176 #define LANC111_SIGNAL_MODE()   sbi(EICRA, ISC20); sbi(EICRA, ISC21)
00177 
00178 #elif (LANC111_SIGNAL_IRQ == INT3)
00179 #define LANC111_SIGNAL          sig_INTERRUPT3
00180 #define LANC111_SIGNAL_MODE()   sbi(EICRA, ISC30); sbi(EICRA, ISC31)
00181 
00182 #elif (LANC111_SIGNAL_IRQ == INT4)
00183 #define LANC111_SIGNAL          sig_INTERRUPT4
00184 #define LANC111_SIGNAL_MODE()   sbi(EICR, ISC40); sbi(EICR, ISC41)
00185 
00186 #elif (LANC111_SIGNAL_IRQ == INT6)
00187 #define LANC111_SIGNAL          sig_INTERRUPT6
00188 #define LANC111_SIGNAL_MODE()   sbi(EICR, ISC60); sbi(EICR, ISC61)
00189 
00190 #elif (LANC111_SIGNAL_IRQ == INT7)
00191 #define LANC111_SIGNAL          sig_INTERRUPT7
00192 #define LANC111_SIGNAL_MODE()   sbi(EICR, ISC70); sbi(EICR, ISC71)
00193 
00194 #else
00195 #define LANC111_SIGNAL          sig_INTERRUPT5
00196 #define LANC111_SIGNAL_MODE()   sbi(EICR, ISC50); sbi(EICR, ISC51)
00197 
00198 #endif
00199 
00204 
00208 #define NIC_BSR         (LANC111_BASE_ADDR + 0x0E)
00209 
00213 #define NIC_TCR         (LANC111_BASE_ADDR + 0x00)
00214 
00215 #define TCR_SWFDUP      0x8000  
00216 #define TCR_EPH_LOOP    0x2000  
00217 #define TCR_STP_SQET    0x1000  
00218 #define TCR_FDUPLX      0x0800  
00219 #define TCR_MON_CSN     0x0400  
00220 #define TCR_NOCRC       0x0100  
00221 #define TCR_PAD_EN      0x0080  
00222 #define TCR_FORCOL      0x0004  
00223 #define TCR_LOOP        0x0002  
00224 #define TCR_TXENA       0x0001  
00230 #define NIC_EPHSR       (LANC111_BASE_ADDR + 0x02)
00231 
00235 #define NIC_RCR         (LANC111_BASE_ADDR + 0x04)
00236 
00237 #define RCR_SOFT_RST    0x8000  
00238 #define RCR_FILT_CAR    0x4000  
00239 #define RCR_ABORT_ENB   0x2000  
00240 #define RCR_STRIP_CRC   0x0200  
00241 #define RCR_RXEN        0x0100  
00242 #define RCR_ALMUL       0x0004  
00243 #define RCR_PRMS        0x0002  
00244 #define RCR_RX_ABORT    0x0001  
00249 #define NIC_ECR         (LANC111_BASE_ADDR + 0x06)
00250 
00254 #define NIC_MIR         (LANC111_BASE_ADDR + 0x08)
00255 
00259 #define NIC_RPCR        (LANC111_BASE_ADDR + 0x0A)
00260 
00261 #define RPCR_SPEED      0x2000  
00262 #define RPCR_DPLX       0x1000  
00263 #define RPCR_ANEG       0x0800  
00264 #define RPCR_LEDA_PAT   0x0000  
00265 #define RPCR_LEDB_PAT   0x0010  
00270 #define NIC_CR          (LANC111_BASE_ADDR + 0x00)
00271 
00272 #define CR_EPH_EN       0x8000  
00277 #define NIC_BAR         (LANC111_BASE_ADDR + 0x02)
00278 
00282 #define NIC_IAR         (LANC111_BASE_ADDR + 0x04)
00283 
00287 #define NIC_GPR         (LANC111_BASE_ADDR + 0x0A)
00288 
00292 #define NIC_CTR         (LANC111_BASE_ADDR + 0x0C)
00293 
00294 #define CTR_RCV_BAD     0x4000  
00295 #define CTR_AUTO_RELEASE 0x0800 
00300 #define NIC_MMUCR       (LANC111_BASE_ADDR + 0x00)
00301 
00302 #define MMUCR_BUSY      0x0001
00303 
00304 #define MMU_NOP         0
00305 #define MMU_ALO         (1<<5)
00306 #define MMU_RST         (2<<5)
00307 #define MMU_REM         (3<<5)
00308 #define MMU_TOP         (4<<5)
00309 #define MMU_PKT         (5<<5)
00310 #define MMU_ENQ         (6<<5)
00311 #define MMU_RTX         (7<<5)
00312 
00318 #define NIC_PNR         (LANC111_BASE_ADDR + 0x02)
00319 
00325 #define NIC_ARR         (LANC111_BASE_ADDR + 0x03)
00326 
00327 #define ARR_FAILED      0x80
00328 
00332 #define NIC_FIFO        (LANC111_BASE_ADDR + 0x04)
00333 
00337 #define NIC_PTR         (LANC111_BASE_ADDR + 0x06)
00338 
00339 #define PTR_RCV         0x8000  
00340 #define PTR_AUTO_INCR   0x4000  
00341 #define PTR_READ        0x2000  
00342 #define PTR_ETEN        0x1000  
00343 #define PTR_NOT_EMPTY   0x0800  
00348 #define NIC_DATA        (LANC111_BASE_ADDR + 0x08)
00349 
00353 #define NIC_IST         (LANC111_BASE_ADDR + 0x0C)
00354 
00358 #define NIC_ACK         (LANC111_BASE_ADDR + 0x0C)
00359 
00363 #define NIC_MSK         (LANC111_BASE_ADDR + 0x0D)
00364 
00365 #define INT_MD          0x80    
00366 #define INT_ERCV        0x40    
00367 #define INT_EPH         0x20    
00368 #define INT_RX_OVRN     0x10    
00369 #define INT_ALLOC       0x08    
00370 #define INT_TX_EMPTY    0x04    
00371 #define INT_TX          0x02    
00372 #define INT_RCV         0x01    
00377 #define NIC_MT          (LANC111_BASE_ADDR + 0x00)
00378 
00382 #define NIC_MGMT        (LANC111_BASE_ADDR + 0x08)
00383 
00384 #define MGMT_MDOE       0x08    
00385 #define MGMT_MCLK       0x04    
00386 #define MGMT_MDI        0x02    
00387 #define MGMT_MDO        0x01    
00392 #define NIC_REV         (LANC111_BASE_ADDR + 0x0A)
00393 
00397 #define NIC_ERCV        (LANC111_BASE_ADDR + 0x0C)
00398 
00402 #define NIC_PHYCR       0
00403 
00404 #define PHYCR_RST       0x8000  
00405 #define PHYCR_LPBK      0x4000  
00406 #define PHYCR_SPEED     0x2000  
00407 #define PHYCR_ANEG_EN   0x1000  
00408 #define PHYCR_PDN       0x0800  
00409 #define PHYCR_MII_DIS   0x0400  
00410 #define PHYCR_ANEG_RST  0x0200  
00411 #define PHYCR_DPLX      0x0100  
00412 #define PHYCR_COLST     0x0080  
00418 #define NIC_PHYSR       1
00419 
00420 #define PHYSR_CAP_T4    0x8000  
00421 #define PHYSR_CAP_TXF   0x4000  
00422 #define PHYSR_CAP_TXH   0x2000  
00423 #define PHYSR_CAP_TF    0x1000  
00424 #define PHYSR_CAP_TH    0x0800  
00425 #define PHYSR_CAP_SUPR  0x0040  
00426 #define PHYSR_ANEG_ACK  0x0020  
00427 #define PHYSR_REM_FLT   0x0010  
00428 #define PHYSR_CAP_ANEG  0x0008  
00429 #define PHYSR_LINK      0x0004  
00430 #define PHYSR_JAB       0x0002  
00431 #define PHYSR_EXREG     0x0001  
00437 #define NIC_PHYID1      2
00438 
00442 #define NIC_PHYID2      3
00443 
00447 #define NIC_PHYANAD     4
00448 
00449 #define PHYANAD_NP      0x8000  
00450 #define PHYANAD_ACK     0x4000  
00451 #define PHYANAD_RF      0x2000  
00452 #define PHYANAD_T4      0x0200  
00453 #define PHYANAD_TX_FDX  0x0100  
00454 #define PHYANAD_TX_HDX  0x0080  
00455 #define PHYANAD_10FDX   0x0040  
00456 #define PHYANAD_10_HDX  0x0020  
00457 #define PHYANAD_CSMA    0x0001  
00462 #define NIC_PHYANRC     5
00463 
00467 #define NIC_PHYCFR1     16
00468 
00472 #define NIC_PHYCFR2     17
00473 
00477 #define NIC_PHYSOR      18
00478 
00479 #define PHYSOR_INT      0x8000  
00480 #define PHYSOR_LNKFAIL  0x4000  
00481 #define PHYSOR_LOSSSYNC 0x2000  
00482 #define PHYSOR_CWRD     0x1000  
00483 #define PHYSOR_SSD      0x0800  
00484 #define PHYSOR_ESD      0x0400  
00485 #define PHYSOR_RPOL     0x0200  
00486 #define PHYSOR_JAB      0x0100  
00487 #define PHYSOR_SPDDET   0x0080  
00488 #define PHYSOR_DPLXDET  0x0040  
00493 #define NIC_PHYMSK      19
00494 
00495 #define PHYMSK_MINT     0x8000  
00496 #define PHYMSK_MLNKFAIL 0x4000  
00497 #define PHYMSK_MLOSSSYN 0x2000  
00498 #define PHYMSK_MCWRD    0x1000  
00499 #define PHYMSK_MSSD     0x0800  
00500 #define PHYMSK_MESD     0x0400  
00501 #define PHYMSK_MRPOL    0x0200  
00502 #define PHYMSK_MJAB     0x0100  
00503 #define PHYMSK_MSPDDT   0x0080  
00504 #define PHYMSK_MDPLDT   0x0040  
00508 #define MSBV(bit)       (1 << ((bit) - 8))
00509 
00510 #define nic_outlb(addr, val) (*(volatile uint8_t *)(addr) = (val))
00511 #define nic_outhb(addr, val) (*(volatile uint8_t *)((addr) + 1) = (val))
00512 #define nic_outwx(addr, val) (*(volatile uint16_t *)(addr) = (val))
00513 #define nic_outw(addr, val) { \
00514     *(volatile uint8_t *)(addr) = (uint8_t)(val); \
00515     *((volatile uint8_t *)(addr) + 1) = (uint8_t)((val) >> 8); \
00516 }
00517 
00518 #define nic_inlb(addr) (*(volatile uint8_t *)(addr))
00519 #define nic_inhb(addr) (*(volatile uint8_t *)((addr) + 1))
00520 #define nic_inw(addr) (*(volatile uint16_t *)(addr))
00521 
00522 #define nic_bs(bank)    nic_outlb(NIC_BSR, bank)
00523 
00528 struct _NICINFO {
00529     HANDLE volatile ni_rx_rdy;  
00530     uint16_t ni_tx_cnt;          
00531     uint32_t ni_rx_packets;       
00532     uint32_t ni_tx_packets;       
00533     uint32_t ni_interrupts;       
00534     uint32_t ni_overruns;         
00535     uint32_t ni_rx_frame_errors;  
00536     uint32_t ni_rx_crc_errors;    
00537     uint32_t ni_rx_missed_errors; 
00538 };
00539 
00543 typedef struct _NICINFO NICINFO;
00544 
00551 
00552 
00553 static HANDLE mutex;
00554 static HANDLE maq;
00555 
00566 static uint8_t NicPhyRegSelect(uint8_t reg, uint8_t we)
00567 {
00568     uint8_t rs;
00569     uint8_t msk;
00570     uint8_t i;
00571 
00572     nic_bs(3);
00573     rs = (nic_inlb(NIC_MGMT) & ~(MGMT_MCLK | MGMT_MDO)) | MGMT_MDOE;
00574 
00575     /* Send idle pattern. */
00576     for (i = 0; i < 33; i++) {
00577         nic_outlb(NIC_MGMT, rs | MGMT_MDO);
00578         nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);
00579     }
00580 
00581     /* Send start sequence. */
00582     nic_outlb(NIC_MGMT, rs);
00583     nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
00584     nic_outlb(NIC_MGMT, rs | MGMT_MDO);
00585     nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);
00586 
00587     /* Write or read mode. */
00588     if (we) {
00589         nic_outlb(NIC_MGMT, rs);
00590         nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
00591         nic_outlb(NIC_MGMT, rs | MGMT_MDO);
00592         nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);
00593     } else {
00594         nic_outlb(NIC_MGMT, rs | MGMT_MDO);
00595         nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);
00596         nic_outlb(NIC_MGMT, rs);
00597         nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
00598     }
00599 
00600     /* Send PHY address. Zero is used for the internal PHY. */
00601     for (i = 0; i < 5; i++) {
00602         nic_outlb(NIC_MGMT, rs);
00603         nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
00604     }
00605 
00606     /* Send PHY register number. */
00607     for (msk = 0x10; msk; msk >>= 1) {
00608         if (reg & msk) {
00609             nic_outlb(NIC_MGMT, rs | MGMT_MDO);
00610             nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);
00611         } else {
00612             nic_outlb(NIC_MGMT, rs);
00613             nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
00614         }
00615     }
00616     nic_outlb(NIC_MGMT, rs);
00617 
00618     return rs;
00619 }
00620 
00630 static uint16_t NicPhyRead(uint8_t reg)
00631 {
00632     uint16_t rc = 0;
00633     uint8_t rs;
00634     uint8_t i;
00635 
00636     /* Select register for reading. */
00637     rs = NicPhyRegSelect(reg, 0);
00638 
00639     /* Switch data direction. */
00640     rs &= ~MGMT_MDOE;
00641     nic_outlb(NIC_MGMT, rs);
00642     nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
00643 
00644     /* Clock data in. */
00645     for (i = 0; i < 16; i++) {
00646         nic_outlb(NIC_MGMT, rs);
00647         nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
00648         rc <<= 1;
00649         rc |= (nic_inlb(NIC_MGMT) & MGMT_MDI) != 0;
00650     }
00651 
00652     /* This will set the clock line to low. */
00653     nic_outlb(NIC_MGMT, rs);
00654 
00655     return rc;
00656 }
00657 
00666 static void NicPhyWrite(uint8_t reg, uint16_t val)
00667 {
00668     uint16_t msk;
00669     uint8_t rs;
00670 
00671     /* Select register for writing. */
00672     rs = NicPhyRegSelect(reg, 1);
00673 
00674     /* Switch data direction dummy. */
00675     nic_outlb(NIC_MGMT, rs | MGMT_MDO);
00676     nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);
00677     nic_outlb(NIC_MGMT, rs);
00678     nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
00679 
00680     /* Clock data out. */
00681     for (msk = 0x8000; msk; msk >>= 1) {
00682         if (val & msk) {
00683             nic_outlb(NIC_MGMT, rs | MGMT_MDO);
00684             nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);
00685         } else {
00686             nic_outlb(NIC_MGMT, rs);
00687             nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
00688         }
00689     }
00690 
00691     /* Set clock line low and output line int z-state. */
00692     nic_outlb(NIC_MGMT, rs & ~MGMT_MDOE);
00693 }
00694 
00700 static int NicPhyConfig(void)
00701 {
00702     uint16_t phy_sor;
00703     uint16_t phy_sr;
00704     uint16_t phy_to;
00705     uint16_t mode;
00706 
00707     /* 
00708      * Reset the PHY and wait until this self clearing bit
00709      * becomes zero. We sleep 63 ms before each poll and
00710      * give up after 3 retries. 
00711      */
00712     //printf("Reset PHY..");
00713     NicPhyWrite(NIC_PHYCR, PHYCR_RST);
00714     for (phy_to = 0;; phy_to++) {
00715         NutSleep(63);
00716         if ((NicPhyRead(NIC_PHYCR) & PHYCR_RST) == 0)
00717             break;
00718         if (phy_to > 3)
00719             return -1;
00720     }
00721     //printf("OK\n");
00722 
00723     /* Store PHY status output. */
00724     phy_sor = NicPhyRead(NIC_PHYSOR);
00725 
00726     /* Enable PHY interrupts. */
00727     NicPhyWrite(NIC_PHYMSK, PHYMSK_MLOSSSYN | PHYMSK_MCWRD | PHYMSK_MSSD |
00728                 PHYMSK_MESD | PHYMSK_MRPOL | PHYMSK_MJAB | PHYMSK_MSPDDT | PHYMSK_MDPLDT);
00729 
00730     /* Set RPC register. */
00731     mode = RPCR_ANEG | RPCR_LEDA_PAT | RPCR_LEDB_PAT;
00732     nic_bs(0);
00733     nic_outw(NIC_RPCR, mode);
00734 
00735 #ifdef NIC_FIXED
00736     /* Disable link. */
00737     phy_sr = NicPhyRead(NIC_PHYCFR1);
00738     NicPhyWrite(NIC_PHYCFR1, phy_sr | 0x8000);
00739     NutSleep(63);
00740 
00741     /* Set fixed capabilities. */
00742     NicPhyWrite(NIC_PHYCR, NIC_FIXED);
00743     nic_bs(0);
00744     nic_outw(NIC_RPCR, mode);
00745 
00746     /* Enable link. */
00747     phy_sr = NicPhyRead(NIC_PHYCFR1);
00748     NicPhyWrite(NIC_PHYCFR1, phy_sr & ~0x8000);
00749     phy_sr = NicPhyRead(NIC_PHYCFR1);
00750 
00751 #else
00752     /*
00753      * Advertise our capabilities, initiate auto negotiation
00754      * and wait until this has been completed.
00755      */
00756     //printf("Negotiate..");
00757     NicPhyWrite(NIC_PHYANAD, PHYANAD_TX_FDX | PHYANAD_TX_HDX | PHYANAD_10FDX | PHYANAD_10_HDX | PHYANAD_CSMA);
00758     NutSleep(63);
00759     for (phy_to = 0, phy_sr = 0;; phy_to++) {
00760         /* Give up after 10 seconds. */
00761         if (phy_to >= 1024)
00762             return -1;
00763         /* Restart auto negotiation every 4 seconds or on failures. */
00764         if ((phy_to & 127) == 0 /* || (phy_sr & PHYSR_REM_FLT) != 0 */ ) {
00765             NicPhyWrite(NIC_PHYCR, PHYCR_ANEG_EN | PHYCR_ANEG_RST);
00766             //printf("Restart..");
00767             NutSleep(63);
00768         }
00769         /* Check if we are done. */
00770         phy_sr = NicPhyRead(NIC_PHYSR);
00771         //printf("[SR %04X]", phy_sr);
00772         if (phy_sr & PHYSR_ANEG_ACK)
00773             break;
00774         NutSleep(63);
00775     }
00776     //printf("OK\n");
00777 #endif
00778 
00779     return 0;
00780 }
00781 
00792 static INLINE int NicMmuWait(uint16_t tmo)
00793 {
00794     while (tmo--) {
00795         if ((nic_inlb(NIC_MMUCR) & MMUCR_BUSY) == 0)
00796             break;
00797         NutDelay(1);
00798     }
00799     return tmo ? 0 : -1;
00800 }
00801 
00807 static int NicReset(void)
00808 {
00809 #ifdef LANC111_RESET_BIT
00810     sbi(LANC111_RESET_DDR, LANC111_RESET_BIT);
00811     sbi(LANC111_RESET_PORT, LANC111_RESET_BIT);
00812     NutDelay(WAIT100);
00813     cbi(LANC111_RESET_PORT, LANC111_RESET_BIT);
00814     NutDelay(WAIT250);
00815     NutDelay(WAIT250);
00816 #endif
00817 
00818     /* Disable all interrupts. */
00819     nic_outlb(NIC_MSK, 0);
00820 
00821     /* MAC and PHY software reset. */
00822     nic_bs(0);
00823     nic_outw(NIC_RCR, RCR_SOFT_RST);
00824 
00825     /* Enable Ethernet protocol handler. */
00826     nic_bs(1);
00827     nic_outw(NIC_CR, CR_EPH_EN);
00828 
00829     NutDelay(10);
00830 
00831     /* Disable transmit and receive. */
00832     nic_bs(0);
00833     nic_outw(NIC_RCR, 0);
00834     nic_outw(NIC_TCR, 0);
00835 
00836     /* Enable auto release. */
00837     nic_bs(1);
00838     nic_outw(NIC_CTR, CTR_AUTO_RELEASE);
00839 
00840     /* Reset MMU. */
00841     nic_bs(2);
00842     nic_outlb(NIC_MMUCR, MMU_RST);
00843     if (NicMmuWait(1000))
00844         return -1;
00845 
00846     return 0;
00847 }
00848 
00849 /*
00850  * Fires up the network interface. NIC interrupts
00851  * should have been disabled when calling this
00852  * function.
00853  *
00854  * \param mac Six byte unique MAC address.
00855  */
00856 static int NicStart(CONST uint8_t * mac)
00857 {
00858     uint8_t i;
00859 
00860     if (NicReset())
00861         return -1;
00862 
00863     /* Enable receiver. */
00864     nic_bs(3);
00865     nic_outlb(NIC_ERCV, 7);
00866     nic_bs(0);
00867     nic_outw(NIC_RCR, RCR_RXEN);
00868 
00869     /* Enable transmitter and padding. */
00870     nic_outw(NIC_TCR, TCR_PAD_EN | TCR_TXENA);
00871 
00872     /* Configure the PHY. */
00873     if (NicPhyConfig())
00874         return -1;
00875 
00876     /* Set MAC address. */
00877     //printf("Set MAC %02X%02X%02X%02X%02X%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
00878     nic_bs(1);
00879     for (i = 0; i < 6; i++)
00880         nic_outlb(NIC_IAR + i, mac[i]);
00881     //printf("OK\n");
00882 
00883     /* Enable interrupts. */
00884     nic_bs(2);
00885     nic_outlb(NIC_MSK, INT_ERCV | INT_RCV | INT_RX_OVRN);
00886 
00887     return 0;
00888 }
00889 
00890 /*
00891  * NIC interrupt entry.
00892  */
00893 static void NicInterrupt(void *arg)
00894 {
00895     uint8_t isr;
00896     uint8_t imr;
00897     NICINFO *ni = (NICINFO *) ((NUTDEVICE *) arg)->dev_dcb;
00898 
00899     ni->ni_interrupts++;
00900 
00901     /* Read the interrupt mask and disable all interrupts. */
00902     nic_bs(2);
00903     imr = nic_inlb(NIC_MSK);
00904     nic_outlb(NIC_MSK, 0);
00905 
00906     /* Read the interrupt status and acknowledge all interrupts. */
00907     isr = nic_inlb(NIC_IST);
00908     //printf("\n!%02X-%02X ", isr, imr);
00909     isr &= imr;
00910 
00911     /*
00912      * If this is a transmit interrupt, then a packet has been sent. 
00913      * So we can clear the transmitter busy flag and wake up the 
00914      * transmitter thread.
00915      */
00916     if (isr & INT_TX_EMPTY) {
00917         nic_outlb(NIC_ACK, INT_TX_EMPTY);
00918         imr &= ~INT_TX_EMPTY;
00919     }
00920     /* Transmit error. */
00921     else if (isr & INT_TX) {
00922         /* re-enable transmit */
00923         nic_bs(0);
00924         nic_outw(NIC_TCR, nic_inlb(NIC_TCR) | TCR_TXENA);
00925         nic_bs(2);
00926         nic_outlb(NIC_ACK, INT_TX);
00927         /* kill the packet */
00928         nic_outlb(NIC_MMUCR, MMU_PKT);
00929     }
00930 
00931 
00932     /*
00933      * If this is a receive interrupt, then wake up the receiver 
00934      * thread.
00935      */
00936     if (isr & INT_RX_OVRN) {
00937         nic_outlb(NIC_ACK, INT_RX_OVRN);
00938         //nic_outlb(NIC_MMUCR, MMU_TOP);
00939         NutEventPostFromIrq(&ni->ni_rx_rdy);
00940     }
00941     if (isr & INT_ERCV) {
00942         nic_outlb(NIC_ACK, INT_ERCV);
00943         NutEventPostFromIrq(&ni->ni_rx_rdy);
00944     }
00945     if (isr & INT_RCV) {
00946         nic_outlb(NIC_ACK, INT_RCV);
00947         imr &= ~INT_RCV;
00948         NutEventPostFromIrq(&ni->ni_rx_rdy);
00949     }
00950 
00951     if (isr & INT_ALLOC) {
00952         imr &= ~INT_ALLOC;
00953         NutEventPostFromIrq(&maq);
00954     }
00955     //printf(" -%02X-%02X- ", nic_inlb(NIC_IST), inb(PINE) & 0x20);
00956     nic_outlb(NIC_MSK, imr);
00957 }
00958 
00959 /*
00960  * Write data block to the NIC.
00961  */
00962 static void NicWrite(uint8_t * buf, uint16_t len)
00963 {
00964     register uint16_t l = len - 1;
00965     register uint8_t ih = (uint16_t) l >> 8;
00966     register uint8_t il = (uint8_t) l;
00967 
00968     if (!len)
00969         return;
00970 
00971     do {
00972         do {
00973             nic_outlb(NIC_DATA, *buf++);
00974         } while (il-- != 0);
00975     } while (ih-- != 0);
00976 }
00977 
00978 /*
00979  * Read data block from the NIC.
00980  */
00981 static void NicRead(uint8_t * buf, uint16_t len)
00982 {
00983     register uint16_t l = len - 1;
00984     register uint8_t ih = (uint16_t) l >> 8;
00985     register uint8_t il = (uint8_t) l;
00986 
00987     if (!len)
00988         return;
00989 
00990     do {
00991         do {
00992             *buf++ = nic_inlb(NIC_DATA);
00993         } while (il-- != 0);
00994     } while (ih-- != 0);
00995 }
00996 
01007 static NETBUF *NicGetPacket(void)
01008 {
01009     NETBUF *nb = 0;
01010     //uint8_t *buf;
01011     uint16_t fsw;
01012     uint16_t fbc;
01013 
01014     /* Check the fifo empty bit. If it is set, then there is 
01015        nothing in the receiver fifo. */
01016     nic_bs(2);
01017     if (nic_inw(NIC_FIFO) & 0x8000) {
01018         return 0;
01019     }
01020 
01021     /* Inialize pointer register. */
01022     nic_outw(NIC_PTR, PTR_READ | PTR_RCV | PTR_AUTO_INCR);
01023     _NOP();
01024     _NOP();
01025     _NOP();
01026     _NOP();
01027 
01028     /* Read status word and byte count. */
01029     fsw = nic_inw(NIC_DATA);
01030     fbc = nic_inw(NIC_DATA);
01031     //printf("[SW=%04X,BC=%04X]", fsw, fbc);
01032 
01033     /* Check for frame errors. */
01034     if (fsw & 0xAC00) {
01035         nb = (NETBUF *) 0xFFFF;
01036     }
01037     /* Check the byte count. */
01038     else if (fbc < 66 || fbc > 1524) {
01039         nb = (NETBUF *) 0xFFFF;
01040     }
01041 
01042     else {
01043         /* 
01044          * Allocate a NETBUF. 
01045          * Hack alert: Rev A chips never set the odd frame indicator.
01046          */
01047         fbc -= 3;
01048         nb = NutNetBufAlloc(0, NBAF_DATALINK, fbc);
01049 
01050         /* Perform the read. */
01051         if (nb)
01052             NicRead(nb->nb_dl.vp, fbc);
01053     }
01054 
01055     /* Release the packet. */
01056     nic_outlb(NIC_MMUCR, MMU_TOP);
01057 
01058     return nb;
01059 }
01060 
01075 static int NicPutPacket(NETBUF * nb)
01076 {
01077     uint16_t sz;
01078     uint8_t odd = 0;
01079     uint8_t imsk;
01080 
01081     //printf("[P]");
01082     /*
01083      * Calculate the number of bytes to be send. Do not send packets 
01084      * larger than the Ethernet maximum transfer unit. The MTU
01085      * consist of 1500 data bytes plus the 14 byte Ethernet header
01086      * plus 4 bytes CRC. We check the data bytes only.
01087      */
01088     if ((sz = nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz) > ETHERMTU)
01089         return -1;
01090 
01091     /* Disable all interrupts. */
01092     imsk = nic_inlb(NIC_MSK);
01093     nic_outlb(NIC_MSK, 0);
01094 
01095     /* Allocate packet buffer space. */
01096     nic_bs(2);
01097     nic_outlb(NIC_MMUCR, MMU_ALO);
01098     if (NicMmuWait(100))
01099         return -1;
01100 
01101     /* Enable interrupts including allocation success. */
01102     nic_outlb(NIC_MSK, imsk | INT_ALLOC);
01103 
01104     /* The MMU needs some time. Use it to calculate the byte count. */
01105     sz += nb->nb_dl.sz;
01106     sz += 6;
01107     if (sz & 1) {
01108         sz++;
01109         odd++;
01110     }
01111 
01112     /* Wait for allocation success. */
01113     while ((nic_inlb(NIC_IST) & INT_ALLOC) == 0) {
01114         if (NutEventWait(&maq, 125)) {
01115             nic_outlb(NIC_MMUCR, MMU_RST);
01116             NicMmuWait(1000);
01117             nic_outlb(NIC_MMUCR, MMU_ALO);
01118             if (NicMmuWait(100) || (nic_inlb(NIC_IST) & INT_ALLOC) == 0) {
01119                 if (NutEventWait(&maq, 125)) {
01120                     return -1;
01121                 }
01122             }
01123         }
01124     }
01125 
01126     /* Disable interrupts. */
01127     imsk = nic_inlb(NIC_MSK);
01128     nic_outlb(NIC_MSK, 0);
01129 
01130 
01131     nic_outlb(NIC_PNR, nic_inhb(NIC_PNR));
01132 
01133     nic_outw(NIC_PTR, 0x4000);
01134 
01135     /* Transfer control word. */
01136     nic_outlb(NIC_DATA, 0);
01137     nic_outlb(NIC_DATA, 0);
01138 
01139     /* Transfer the byte count. */
01140     nic_outw(NIC_DATA, sz);
01141 
01142     /* Transfer the Ethernet frame. */
01143     NicWrite(nb->nb_dl.vp, nb->nb_dl.sz);
01144     NicWrite(nb->nb_nw.vp, nb->nb_nw.sz);
01145     NicWrite(nb->nb_tp.vp, nb->nb_tp.sz);
01146     NicWrite(nb->nb_ap.vp, nb->nb_ap.sz);
01147 
01148     if (odd)
01149         nic_outlb(NIC_DATA, 0);
01150 
01151     /* Transfer the control word. */
01152     nic_outw(NIC_DATA, 0);
01153 
01154     /* Enqueue packet. */
01155     if (NicMmuWait(100))
01156         return -1;
01157     nic_outlb(NIC_MMUCR, MMU_ENQ);
01158 
01159     /* Enable interrupts. */
01160     imsk |= INT_TX | INT_TX_EMPTY;
01161     nic_outlb(NIC_MSK, imsk);
01162 
01163     return 0;
01164 }
01165 
01166 
01171 THREAD(NicRxLanc, arg)
01172 {
01173     NUTDEVICE *dev;
01174     IFNET *ifn;
01175     NICINFO *ni;
01176     NETBUF *nb;
01177     uint8_t imsk;
01178 
01179     dev = arg;
01180     ifn = (IFNET *) dev->dev_icb;
01181     ni = (NICINFO *) dev->dev_dcb;
01182 
01183     /*
01184      * This is a temporary hack. Due to a change in initialization,
01185      * we may not have got a MAC address yet. Wait until one has been
01186      * set.
01187      */
01188     for (;;) {
01189         if (*((uint32_t *) (ifn->if_mac)) && *((uint32_t *) (ifn->if_mac)) != 0xFFFFFFFFUL) {
01190             break;
01191         }
01192         NutSleep(63);
01193     }
01194 
01195     /*
01196      * Do not continue unless we managed to start the NIC. We are
01197      * trapped here if the Ethernet link cannot be established.
01198      * This happens, for example, if no Ethernet cable is plugged
01199      * in.
01200      */
01201     while(NicStart(ifn->if_mac)) {
01202         NutSleep(1000);
01203     }
01204 
01205     LANC111_SIGNAL_MODE();
01206     sbi(EIMSK, LANC111_SIGNAL_IRQ);
01207 
01208     NutEventPost(&mutex);
01209 
01210     /* Run at high priority. */
01211     NutThreadSetPriority(9);
01212 
01213     for (;;) {
01214 
01215         /*
01216          * Wait for the arrival of new packets or
01217          * check the receiver every two second.
01218          */
01219         NutEventWait(&ni->ni_rx_rdy, 2000);
01220 
01221         /*
01222          * Fetch all packets from the NIC's internal
01223          * buffer and pass them to the registered handler.
01224          */
01225         imsk = nic_inlb(NIC_MSK);
01226         nic_outlb(NIC_MSK, 0);
01227         while ((nb = NicGetPacket()) != 0) {
01228             if (nb != (NETBUF *) 0xFFFF) {
01229                 ni->ni_rx_packets++;
01230                 (*ifn->if_recv) (dev, nb);
01231             }
01232         }
01233         nic_outlb(NIC_MSK, imsk | INT_RCV | INT_ERCV);
01234     }
01235 }
01236 
01247 int LancOutput(NUTDEVICE * dev, NETBUF * nb)
01248 {
01249     static uint32_t mx_wait = 5000;
01250     int rc = -1;
01251     NICINFO *ni;
01252 
01253     /*
01254      * After initialization we are waiting for a long time to give
01255      * the PHY a chance to establish an Ethernet link.
01256      */
01257     if (NutEventWait(&mutex, mx_wait) == 0) {
01258         ni = (NICINFO *) dev->dev_dcb;
01259 
01260         if (NicPutPacket(nb) == 0) {
01261             ni->ni_tx_packets++;
01262             rc = 0;
01263             /* Ethernet works. Set a long waiting time in case we
01264                temporarly lose the link next time. */
01265             mx_wait = 5000;
01266         }
01267         NutEventPost(&mutex);
01268     }
01269     /*
01270      * Probably no Ethernet link. Significantly reduce the waiting
01271      * time, so following transmission will soon return an error.
01272      */
01273     else {
01274         mx_wait = 500;
01275     }
01276     return rc;
01277 }
01278 
01296 int LancInit(NUTDEVICE * dev)
01297 {
01298     /* Disable NIC interrupt and clear NICINFO structure. */
01299     cbi(EIMSK, LANC111_SIGNAL_IRQ);
01300     memset(dev->dev_dcb, 0, sizeof(NICINFO));
01301 
01302     /* Register interrupt handler and enable interrupts. */
01303     if (NutRegisterIrqHandler(&LANC111_SIGNAL, NicInterrupt, dev))
01304         return -1;
01305 
01306     /*
01307      * Start the receiver thread.
01308      */
01309     NutThreadCreate("rxi5", NicRxLanc, dev, 640);
01310 
01311     //NutSleep(500);
01312 
01313     return 0;
01314 }
01315 
01316 static NICINFO dcb_eth0;
01317 
01323 static IFNET ifn_eth0 = {
01324     IFT_ETHER,                  
01325     {0, 0, 0, 0, 0, 0},         
01326     0,                          
01327     0,                          
01328     0,                          
01329     ETHERMTU,                   
01330     0,                          
01331     0,                          
01332     0,                          
01333     NutEtherInput,              
01334     LancOutput,                 
01335     NutEtherOutput              
01336 };
01337 
01347 NUTDEVICE devSmsc111 = {
01348     0,                          /* Pointer to next device. */
01349     {'e', 't', 'h', '0', 0, 0, 0, 0, 0},        /* Unique device name. */
01350     IFTYP_NET,                  /* Type of device. */
01351     0,                          /* Base address. */
01352     0,                          /* First interrupt number. */
01353     &ifn_eth0,                  /* Interface control block. */
01354     &dcb_eth0,                  /* Driver control block. */
01355     LancInit,                   /* Driver initialization routine. */
01356     0,                          /* Driver specific control function. */
01357     0,                          /* Read from device. */
01358     0,                          /* Write to device. */
01359     0,                          /* Write from program space data to device. */
01360     0,                          /* Open a device or file. */
01361     0,                          /* Close a device or file. */
01362     0                           /* Request file size. */
01363 };
01364 

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