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

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