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

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