contiki/cpu/avr/dev/lanc111.c

1363 lines
40 KiB
C

#define INLINE
#define CONST const
#define NETBUF char
/*
* Copyright (C) 2003-2005 by egnite Software GmbH. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
* SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* For additional information see http://www.ethernut.de/
*
*/
/*
* $Log: lanc111.c,v $
* Revision 1.1 2006/06/17 22:41:21 adamdunkels
* Import of the contiki-2.x development code from the SICS internal CVS server
*
* Revision 1.1 2005/09/19 23:05:34 adam
* AVR device drivers
*
* Revision 1.1 2005/05/19 09:06:25 adam
* Very initial version of the LANC111 Ethernet driver, imported from Nut/OS code - does not work yet
*
* Revision 1.12 2005/02/02 19:55:34 haraldkipp
* If no Ethernet link was available on the LAN91C111, each outgoing packet
* took 15 seconds and, even worse, the ouput routine doesn't return an error.
* Now the first attempt to send a packet without Ethernet link will wait for
* 5 seconds and subsequent attempts take 0.5 seconds only, always returning
* an error.
*
* Revision 1.11 2005/01/24 21:11:49 freckle
* renamed NutEventPostFromIRQ into NutEventPostFromIrq
*
* Revision 1.10 2005/01/22 19:24:11 haraldkipp
* Changed AVR port configuration names from PORTx to AVRPORTx.
*
* Revision 1.9 2005/01/21 16:49:45 freckle
* Seperated calls to NutEventPostAsync between Threads and IRQs
*
* Revision 1.8 2004/09/22 08:14:48 haraldkipp
* Made configurable
*
* Revision 1.7 2004/03/08 11:14:17 haraldkipp
* Added quick hack for fixed mode.
*
* Revision 1.6 2004/02/25 16:22:33 haraldkipp
* Do not initialize MAC with all zeros
*
* Revision 1.5 2004/01/14 19:31:43 drsung
* Speed improvement to NicWrite applied. Thanks to Kolja Waschk
*
* Revision 1.4 2003/11/06 09:26:50 haraldkipp
* Removed silly line with hardcoded MAC, left over from testing
*
* Revision 1.3 2003/11/04 17:54:47 haraldkipp
* PHY configuration timing changed again for reliable linking
*
* Revision 1.2 2003/11/03 17:12:53 haraldkipp
* Allow linking with RTL8019 driver.
* Links more reliable to 10 MBit networks now.
* Reset MMU on allocation failures.
* Some optimizations.
*
* Revision 1.1 2003/10/13 10:13:49 haraldkipp
* First release
*
*/
#include "contiki.h"
#include <string.h>
#include <avr/io.h>
/*
* Determine ports, which had not been explicitely configured.
*/
#ifndef LANC111_BASE_ADDR
#define LANC111_BASE_ADDR 0xC000
#endif
#ifndef LANC111_SIGNAL_IRQ
#define LANC111_SIGNAL_IRQ INT5
#endif
#ifdef LANC111_RESET_BIT
#if (LANC111_RESET_AVRPORT == AVRPORTB)
#define LANC111_RESET_PORT PORTB
#define LANC111_RESET_DDR DDRB
#elif (LANC111_RESET_AVRPORT == AVRPORTD)
#define LANC111_RESET_PORT PORTD
#define LANC111_RESET_DDR DDRD
#elif (LANC111_RESET_AVRPORT == AVRPORTE)
#define LANC111_RESET_PORT PORTE
#define LANC111_RESET_DDR DDRE
#elif (LANC111_RESET_AVRPORT == AVRPORTF)
#define LANC111_RESET_PORT PORTF
#define LANC111_RESET_DDR DDRF
#endif /* LANC111_RESET_AVRPORT */
#endif /* LANC111_RESET_BIT */
/*
* Determine interrupt settings.
*/
#if (LANC111_SIGNAL_IRQ == INT0)
#define LANC111_SIGNAL sig_INTERRUPT0
#define LANC111_SIGNAL_MODE() sbi(EICRA, ISC00); sbi(EICRA, ISC01)
#elif (LANC111_SIGNAL_IRQ == INT1)
#define LANC111_SIGNAL sig_INTERRUPT1
#define LANC111_SIGNAL_MODE() sbi(EICRA, ISC10); sbi(EICRA, ISC11)
#elif (LANC111_SIGNAL_IRQ == INT2)
#define LANC111_SIGNAL sig_INTERRUPT2
#define LANC111_SIGNAL_MODE() sbi(EICRA, ISC20); sbi(EICRA, ISC21)
#elif (LANC111_SIGNAL_IRQ == INT3)
#define LANC111_SIGNAL sig_INTERRUPT3
#define LANC111_SIGNAL_MODE() sbi(EICRA, ISC30); sbi(EICRA, ISC31)
#elif (LANC111_SIGNAL_IRQ == INT4)
#define LANC111_SIGNAL sig_INTERRUPT4
#define LANC111_SIGNAL_MODE() sbi(EICRB, ISC40); sbi(EICRB, ISC41)
#elif (LANC111_SIGNAL_IRQ == INT6)
#define LANC111_SIGNAL sig_INTERRUPT6
#define LANC111_SIGNAL_MODE() sbi(EICRB, ISC60); sbi(EICRB, ISC61)
#elif (LANC111_SIGNAL_IRQ == INT7)
#define LANC111_SIGNAL sig_INTERRUPT7
#define LANC111_SIGNAL_MODE() sbi(EICRB, ISC70); sbi(EICRB, ISC71)
#else
#define LANC111_SIGNAL sig_INTERRUPT5
#define LANC111_SIGNAL_MODE() sbi(EICRB, ISC50); sbi(EICRB, ISC51)
#endif
/*!
* \addtogroup xgSmscRegs
*/
/*@{*/
/*!
* \brief Bank select register.
*/
#define NIC_BSR (LANC111_BASE_ADDR + 0x0E)
/*!
* \brief Bank 0 - Transmit control register.
*/
#define NIC_TCR (LANC111_BASE_ADDR + 0x00)
#define TCR_SWFDUP 0x8000 /*!< \ref NIC_TCR bit mask, enables full duplex. */
#define TCR_EPH_LOOP 0x2000 /*!< \ref NIC_TCR bit mask, enables internal loopback. */
#define TCR_STP_SQET 0x1000 /*!< \ref NIC_TCR bit mask, enables transmission stop on SQET error. */
#define TCR_FDUPLX 0x0800 /*!< \ref NIC_TCR bit mask, enables receiving own frames. */
#define TCR_MON_CSN 0x0400 /*!< \ref NIC_TCR bit mask, enables carrier monitoring. */
#define TCR_NOCRC 0x0100 /*!< \ref NIC_TCR bit mask, disables CRC transmission. */
#define TCR_PAD_EN 0x0080 /*!< \ref NIC_TCR bit mask, enables automatic padding. */
#define TCR_FORCOL 0x0004 /*!< \ref NIC_TCR bit mask, forces collision. */
#define TCR_LOOP 0x0002 /*!< \ref NIC_TCR bit mask, enables PHY loopback. */
#define TCR_TXENA 0x0001 /*!< \ref NIC_TCR bit mask, enables transmitter. */
/*!
* \brief Bank 0 - EPH status register.
*/
#define NIC_EPHSR (LANC111_BASE_ADDR + 0x02)
/*!
* \brief Bank 0 - Receive control register.
*/
#define NIC_RCR (LANC111_BASE_ADDR + 0x04)
#define RCR_SOFT_RST 0x8000 /*!< \ref NIC_RCR bit mask, activates software reset. */
#define RCR_FILT_CAR 0x4000 /*!< \ref NIC_RCR bit mask, enables carrier filter. */
#define RCR_ABORT_ENB 0x2000 /*!< \ref NIC_RCR bit mask, enables receive abort on collision. */
#define RCR_STRIP_CRC 0x0200 /*!< \ref NIC_RCR bit mask, strips CRC. */
#define RCR_RXEN 0x0100 /*!< \ref NIC_RCR bit mask, enables receiver. */
#define RCR_ALMUL 0x0004 /*!< \ref NIC_RCR bit mask, multicast frames accepted when set. */
#define RCR_PRMS 0x0002 /*!< \ref NIC_RCR bit mask, enables promiscuous mode. */
#define RCR_RX_ABORT 0x0001 /*!< \ref NIC_RCR bit mask, set when receive was aborted. */
/*!
* \brief Bank 0 - Counter register.
*/
#define NIC_ECR (LANC111_BASE_ADDR + 0x06)
/*!
* \brief Bank 0 - Memory information register.
*/
#define NIC_MIR (LANC111_BASE_ADDR + 0x08)
/*!
* \brief Bank 0 - Receive / PHY control register.
*/
#define NIC_RPCR (LANC111_BASE_ADDR + 0x0A)
#define RPCR_SPEED 0x2000 /*!< \ref NIC_RPCR bit mask, PHY operates at 100 Mbps. */
#define RPCR_DPLX 0x1000 /*!< \ref NIC_RPCR bit mask, PHY operates at full duplex mode. */
#define RPCR_ANEG 0x0800 /*!< \ref NIC_RPCR bit mask, sets PHY in auto-negotiation mode. */
#define RPCR_LEDA_PAT 0x0000 /*!< \ref NIC_RPCR bit mask for LEDA mode. */
#define RPCR_LEDB_PAT 0x0010 /*!< \ref NIC_RPCR bit mask for LEDB mode. */
/*!
* \brief Bank 1 - Configuration register.
*/
#define NIC_CR (LANC111_BASE_ADDR + 0x00)
#define CR_EPH_EN 0x8000 /*!< \ref NIC_CR bit mask, . */
/*!
* \brief Bank 1 - Base address register.
*/
#define NIC_BAR (LANC111_BASE_ADDR + 0x02)
/*!
* \brief Bank 1 - Individual address register.
*/
#define NIC_IAR (LANC111_BASE_ADDR + 0x04)
/*!
* \brief Bank 1 - General purpose register.
*/
#define NIC_GPR (LANC111_BASE_ADDR + 0x0A)
/*!
* \brief Bank 1 - Control register.
*/
#define NIC_CTR (LANC111_BASE_ADDR + 0x0C)
#define CTR_RCV_BAD 0x4000 /*!< \ref NIC_CTR bit mask. */
#define CTR_AUTO_RELEASE 0x0800 /*!< \ref NIC_CTR bit mask, transmit packets automatically released. */
/*!
* \brief Bank 2 - MMU command register.
*/
#define NIC_MMUCR (LANC111_BASE_ADDR + 0x00)
#define MMUCR_BUSY 0x0001
#define MMU_NOP 0
#define MMU_ALO (1<<5)
#define MMU_RST (2<<5)
#define MMU_REM (3<<5)
#define MMU_TOP (4<<5)
#define MMU_PKT (5<<5)
#define MMU_ENQ (6<<5)
#define MMU_RTX (7<<5)
/*!
* \brief Bank 2 - Packet number register.
*
* This byte register specifies the accessible transmit packet number.
*/
#define NIC_PNR (LANC111_BASE_ADDR + 0x02)
/*!
* \brief Bank 2 - Allocation result register.
*
* This byte register is updated upon a \ref MMU_ALO command.
*/
#define NIC_ARR (LANC111_BASE_ADDR + 0x03)
#define ARR_FAILED 0x80
/*!
* \brief Bank 2 - FIFO ports register.
*/
#define NIC_FIFO (LANC111_BASE_ADDR + 0x04)
/*!
* \brief Bank 2 - Pointer register.
*/
#define NIC_PTR (LANC111_BASE_ADDR + 0x06)
#define PTR_RCV 0x8000 /*! \ref NIC_PTR bit mask, specifies receive or transmit buffer. */
#define PTR_AUTO_INCR 0x4000 /*! \ref NIC_PTR bit mask, enables automatic pointer increment. */
#define PTR_READ 0x2000 /*! \ref NIC_PTR bit mask, indicates type of access. */
#define PTR_ETEN 0x1000 /*! \ref NIC_PTR bit mask, enables early transmit underrun detection. */
#define PTR_NOT_EMPTY 0x0800 /*! \ref NIC_PTR bit mask, set when write data fifo is not empty. */
/*!
* \brief Bank 2 - Data register.
*/
#define NIC_DATA (LANC111_BASE_ADDR + 0x08)
/*!
* \brief Bank 2 - Interrupt status register.
*/
#define NIC_IST (LANC111_BASE_ADDR + 0x0C)
/*!
* \brief Bank 2 - Interrupt acknowledge register.
*/
#define NIC_ACK (LANC111_BASE_ADDR + 0x0C)
/*!
* \brief Bank 2 - Interrupt mask register.
*/
#define NIC_MSK (LANC111_BASE_ADDR + 0x0D)
#define INT_MD 0x80 /*!< \ref PHY state change interrupt bit mask. */
#define INT_ERCV 0x40 /*!< \ref Early receive interrupt bit mask. */
#define INT_EPH 0x20 /*!< \ref Ethernet protocol interrupt bit mask. */
#define INT_RX_OVRN 0x10 /*!< \ref Receive overrun interrupt bit mask. */
#define INT_ALLOC 0x08 /*!< \ref Transmit allocation interrupt bit mask. */
#define INT_TX_EMPTY 0x04 /*!< \ref Transmitter empty interrupt bit mask. */
#define INT_TX 0x02 /*!< \ref Transmit complete interrupt bit mask. */
#define INT_RCV 0x01 /*!< \ref Receive interrupt bit mask. */
/*!
* \brief Bank 3 - Multicast table register.
*/
#define NIC_MT (LANC111_BASE_ADDR + 0x00)
/*!
* \brief Bank 3 - Management interface register.
*/
#define NIC_MGMT (LANC111_BASE_ADDR + 0x08)
#define MGMT_MDOE 0x08 /*!< \ref NIC_MGMT bit mask, enables MDO pin. */
#define MGMT_MCLK 0x04 /*!< \ref NIC_MGMT bit mask, drives MDCLK pin. */
#define MGMT_MDI 0x02 /*!< \ref NIC_MGMT bit mask, reflects MDI pin status. */
#define MGMT_MDO 0x01 /*!< \ref NIC_MGMT bit mask, drives MDO pin. */
/*!
* \brief Bank 3 - Revision register.
*/
#define NIC_REV (LANC111_BASE_ADDR + 0x0A)
/*!
* \brief Bank 3 - Early RCV register.
*/
#define NIC_ERCV (LANC111_BASE_ADDR + 0x0C)
/*!
* \brief PHY control register.
*/
#define NIC_PHYCR 0
#define PHYCR_RST 0x8000 /*!< \ref NIC_PHYCR bit mask, resets PHY. */
#define PHYCR_LPBK 0x4000 /*!< \ref NIC_PHYCR bit mask, . */
#define PHYCR_SPEED 0x2000 /*!< \ref NIC_PHYCR bit mask, . */
#define PHYCR_ANEG_EN 0x1000 /*!< \ref NIC_PHYCR bit mask, . */
#define PHYCR_PDN 0x0800 /*!< \ref NIC_PHYCR bit mask, . */
#define PHYCR_MII_DIS 0x0400 /*!< \ref NIC_PHYCR bit mask, . */
#define PHYCR_ANEG_RST 0x0200 /*!< \ref NIC_PHYCR bit mask, . */
#define PHYCR_DPLX 0x0100 /*!< \ref NIC_PHYCR bit mask, . */
#define PHYCR_COLST 0x0080 /*!< \ref NIC_PHYCR bit mask, . */
/*!
* \brief PHY status register.
*/
#define NIC_PHYSR 1
#define PHYSR_CAP_T4 0x8000 /*!< \ref NIC_PHYSR bit mask, indicates 100BASE-T4 capability. */
#define PHYSR_CAP_TXF 0x4000 /*!< \ref NIC_PHYSR bit mask, indicates 100BASE-TX full duplex capability. */
#define PHYSR_CAP_TXH 0x2000 /*!< \ref NIC_PHYSR bit mask, indicates 100BASE-TX half duplex capability. */
#define PHYSR_CAP_TF 0x1000 /*!< \ref NIC_PHYSR bit mask, indicates 10BASE-T full duplex capability. */
#define PHYSR_CAP_TH 0x0800 /*!< \ref NIC_PHYSR bit mask, indicates 10BASE-T half duplex capability. */
#define PHYSR_CAP_SUPR 0x0040 /*!< \ref NIC_PHYSR bit mask, indicates preamble suppression capability. */
#define PHYSR_ANEG_ACK 0x0020 /*!< \ref NIC_PHYSR bit mask, auto-negotiation completed. */
#define PHYSR_REM_FLT 0x0010 /*!< \ref NIC_PHYSR bit mask, remote fault detected. */
#define PHYSR_CAP_ANEG 0x0008 /*!< \ref NIC_PHYSR bit mask, indicates auto-negotiation capability. */
#define PHYSR_LINK 0x0004 /*!< \ref NIC_PHYSR bit mask, valid link status. */
#define PHYSR_JAB 0x0002 /*!< \ref NIC_PHYSR bit mask, jabber collision detected. */
#define PHYSR_EXREG 0x0001 /*!< \ref NIC_PHYSR bit mask, extended capabilities available. */
/*!
* \brief PHY identifier register 1.
*/
#define NIC_PHYID1 2
/*!
* \brief PHY identifier register 1.
*/
#define NIC_PHYID2 3
/*!
* \brief PHY auto-negotiation advertisement register.
*/
#define NIC_PHYANAD 4
#define PHYANAD_NP 0x8000 /*!< \ref NIC_PHYANAD bit mask, exchanging next page information. */
#define PHYANAD_ACK 0x4000 /*!< \ref NIC_PHYANAD bit mask, acknowledged. */
#define PHYANAD_RF 0x2000 /*!< \ref NIC_PHYANAD bit mask, remote fault. */
#define PHYANAD_T4 0x0200 /*!< \ref NIC_PHYANAD bit mask, indicates 100BASE-T4 capability. */
#define PHYANAD_TX_FDX 0x0100 /*!< \ref NIC_PHYANAD bit mask, indicates 100BASE-TX full duplex capability. */
#define PHYANAD_TX_HDX 0x0080 /*!< \ref NIC_PHYANAD bit mask, indicates 100BASE-TX half duplex capability. */
#define PHYANAD_10FDX 0x0040 /*!< \ref NIC_PHYANAD bit mask, indicates 10BASE-T full duplex capability. */
#define PHYANAD_10_HDX 0x0020 /*!< \ref NIC_PHYANAD bit mask, indicates 10BASE-T half duplex capability. */
#define PHYANAD_CSMA 0x0001 /*!< \ref NIC_PHYANAD bit mask, indicates 802.3 CSMA capability. */
/*!
* \brief PHY auto-negotiation remote end capability register.
*/
#define NIC_PHYANRC 5
/*!
* \brief PHY configuration register 1.
*/
#define NIC_PHYCFR1 16
/*!
* \brief PHY configuration register 2.
*/
#define NIC_PHYCFR2 17
/*!
* \brief PHY status output register.
*/
#define NIC_PHYSOR 18
#define PHYSOR_INT 0x8000 /*!< \ref NIC_PHYSOR bit mask, interrupt bits changed. */
#define PHYSOR_LNKFAIL 0x4000 /*!< \ref NIC_PHYSOR bit mask, link failure detected. */
#define PHYSOR_LOSSSYNC 0x2000 /*!< \ref NIC_PHYSOR bit mask, descrambler sync lost detected. */
#define PHYSOR_CWRD 0x1000 /*!< \ref NIC_PHYSOR bit mask, code word error detected. */
#define PHYSOR_SSD 0x0800 /*!< \ref NIC_PHYSOR bit mask, start of stream error detected. */
#define PHYSOR_ESD 0x0400 /*!< \ref NIC_PHYSOR bit mask, end of stream error detected. */
#define PHYSOR_RPOL 0x0200 /*!< \ref NIC_PHYSOR bit mask, reverse polarity detected. */
#define PHYSOR_JAB 0x0100 /*!< \ref NIC_PHYSOR bit mask, jabber detected. */
#define PHYSOR_SPDDET 0x0080 /*!< \ref NIC_PHYSOR bit mask, 100/10 speed detected. */
#define PHYSOR_DPLXDET 0x0040 /*!< \ref NIC_PHYSOR bit mask, duplex detected. */
/*!
* \brief PHY mask register.
*/
#define NIC_PHYMSK 19
#define PHYMSK_MINT 0x8000 /*!< \ref NIC_PHYMSK bit mask, enables \ref PHYSOR_INT interrupt. */
#define PHYMSK_MLNKFAIL 0x4000 /*!< \ref NIC_PHYMSK bit mask, enables \ref PHYSOR_LNKFAIL interrupt. */
#define PHYMSK_MLOSSSYN 0x2000 /*!< \ref NIC_PHYMSK bit mask, enables \ref PHYSOR_LOSSSYNC interrupt. */
#define PHYMSK_MCWRD 0x1000 /*!< \ref NIC_PHYMSK bit mask, enables \ref PHYSOR_CWRD interrupt. */
#define PHYMSK_MSSD 0x0800 /*!< \ref NIC_PHYMSK bit mask, enables \ref PHYSOR_SSD interrupt. */
#define PHYMSK_MESD 0x0400 /*!< \ref NIC_PHYMSK bit mask, enables \ref PHYSOR_ESD interrupt. */
#define PHYMSK_MRPOL 0x0200 /*!< \ref NIC_PHYMSK bit mask, enables \ref PHYSOR_RPOL interrupt. */
#define PHYMSK_MJAB 0x0100 /*!< \ref NIC_PHYMSK bit mask, enables \ref PHYSOR_JAB interrupt. */
#define PHYMSK_MSPDDT 0x0080 /*!< \ref NIC_PHYMSK bit mask, enables \ref PHYSOR_SPDDET interrupt. */
#define PHYMSK_MDPLDT 0x0040 /*!< \ref NIC_PHYMSK bit mask, enables \ref PHYSOR_DPLXDET interrupt. */
#define MSBV(bit) (1 << ((bit) - 8))
#define nic_outlb(addr, val) (*(volatile u8_t *)(addr) = (val))
#define nic_outhb(addr, val) (*(volatile u8_t *)((addr) + 1) = (val))
#define nic_outwx(addr, val) (*(volatile u16_t *)(addr) = (val))
#define nic_outw(addr, val) { \
*(volatile u8_t *)(addr) = (u8_t)(val); \
*((volatile u8_t *)(addr) + 1) = (u8_t)((val) >> 8); \
}
#define nic_inlb(addr) (*(volatile u8_t *)(addr))
#define nic_inhb(addr) (*(volatile u8_t *)((addr) + 1))
#define nic_inw(addr) (*(volatile u16_t *)(addr))
#define nic_bs(bank) nic_outlb(NIC_BSR, bank)
/*!
* \struct _NICINFO lanc111.h dev/lanc111.h
* \brief Network interface controller information structure.
*/
/*@}*/
/*!
* \addtogroup xgNicLanc111
*/
/*@{*/
/*!
* \brief Select specified PHY register for reading or writing.
*
* \note NIC interrupts must have been disabled before calling this routine.
*
* \param reg PHY register number.
* \param we Indicates type of access, 1 for write and 0 for read.
*
* \return Contents of the PHY interface rgister.
*/
static u8_t NicPhyRegSelect(u8_t reg, u8_t we)
{
u8_t rs;
u8_t msk;
u8_t i;
nic_bs(3);
rs = (nic_inlb(NIC_MGMT) & ~(MGMT_MCLK | MGMT_MDO)) | MGMT_MDOE;
/* Send idle pattern. */
for (i = 0; i < 33; i++) {
nic_outlb(NIC_MGMT, rs | MGMT_MDO);
nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);
}
/* Send start sequence. */
nic_outlb(NIC_MGMT, rs);
nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
nic_outlb(NIC_MGMT, rs | MGMT_MDO);
nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);
/* Write or read mode. */
if (we) {
nic_outlb(NIC_MGMT, rs);
nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
nic_outlb(NIC_MGMT, rs | MGMT_MDO);
nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);
} else {
nic_outlb(NIC_MGMT, rs | MGMT_MDO);
nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);
nic_outlb(NIC_MGMT, rs);
nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
}
/* Send PHY address. Zero is used for the internal PHY. */
for (i = 0; i < 5; i++) {
nic_outlb(NIC_MGMT, rs);
nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
}
/* Send PHY register number. */
for (msk = 0x10; msk; msk >>= 1) {
if (reg & msk) {
nic_outlb(NIC_MGMT, rs | MGMT_MDO);
nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);
} else {
nic_outlb(NIC_MGMT, rs);
nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
}
}
nic_outlb(NIC_MGMT, rs);
return rs;
}
/*!
* \brief Read contents of PHY register.
*
* \note NIC interrupts must have been disabled before calling this routine.
*
* \param reg PHY register number.
*
* \return Contents of the specified register.
*/
static u16_t NicPhyRead(u8_t reg)
{
u16_t rc = 0;
u8_t rs;
u8_t i;
/* Select register for reading. */
rs = NicPhyRegSelect(reg, 0);
/* Switch data direction. */
rs &= ~MGMT_MDOE;
nic_outlb(NIC_MGMT, rs);
nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
/* Clock data in. */
for (i = 0; i < 16; i++) {
nic_outlb(NIC_MGMT, rs);
nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
rc <<= 1;
rc |= (nic_inlb(NIC_MGMT) & MGMT_MDI) != 0;
}
/* This will set the clock line to low. */
nic_outlb(NIC_MGMT, rs);
return rc;
}
/*!
* \brief Write value to PHY register.
*
* \note NIC interrupts must have been disabled before calling this routine.
*
* \param reg PHY register number.
* \param val Value to write.
*/
static void NicPhyWrite(u8_t reg, u16_t val)
{
u16_t msk;
u8_t rs;
/* Select register for writing. */
rs = NicPhyRegSelect(reg, 1);
/* Switch data direction dummy. */
nic_outlb(NIC_MGMT, rs | MGMT_MDO);
nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);
nic_outlb(NIC_MGMT, rs);
nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
/* Clock data out. */
for (msk = 0x8000; msk; msk >>= 1) {
if (val & msk) {
nic_outlb(NIC_MGMT, rs | MGMT_MDO);
nic_outlb(NIC_MGMT, rs | MGMT_MDO | MGMT_MCLK);
} else {
nic_outlb(NIC_MGMT, rs);
nic_outlb(NIC_MGMT, rs | MGMT_MCLK);
}
}
/* Set clock line low and output line int z-state. */
nic_outlb(NIC_MGMT, rs & ~MGMT_MDOE);
}
/*!
* \brief Configure the internal PHY.
*
* Reset the PHY and initiate auto-negotiation.
*/
static int NicPhyConfig(void)
{
u16_t phy_sor;
u16_t phy_sr;
u16_t phy_to;
u16_t mode;
/*
* Reset the PHY and wait until this self clearing bit
* becomes zero. We sleep 63 ms before each poll and
* give up after 3 retries.
*/
//printf("Reset PHY..");
NicPhyWrite(NIC_PHYCR, PHYCR_RST);
for (phy_to = 0;; phy_to++) {
NutSleep(63);
if ((NicPhyRead(NIC_PHYCR) & PHYCR_RST) == 0)
break;
if (phy_to > 3)
return -1;
}
//printf("OK\n");
/* Store PHY status output. */
phy_sor = NicPhyRead(NIC_PHYSOR);
/* Enable PHY interrupts. */
NicPhyWrite(NIC_PHYMSK, PHYMSK_MLOSSSYN | PHYMSK_MCWRD | PHYMSK_MSSD |
PHYMSK_MESD | PHYMSK_MRPOL | PHYMSK_MJAB | PHYMSK_MSPDDT | PHYMSK_MDPLDT);
/* Set RPC register. */
mode = RPCR_ANEG | RPCR_LEDA_PAT | RPCR_LEDB_PAT;
nic_bs(0);
nic_outw(NIC_RPCR, mode);
#ifdef NIC_FIXED
/* Disable link. */
phy_sr = NicPhyRead(NIC_PHYCFR1);
NicPhyWrite(NIC_PHYCFR1, phy_sr | 0x8000);
NutSleep(63);
/* Set fixed capabilities. */
NicPhyWrite(NIC_PHYCR, NIC_FIXED);
nic_bs(0);
nic_outw(NIC_RPCR, mode);
/* Enable link. */
phy_sr = NicPhyRead(NIC_PHYCFR1);
NicPhyWrite(NIC_PHYCFR1, phy_sr & ~0x8000);
phy_sr = NicPhyRead(NIC_PHYCFR1);
#else
/*
* Advertise our capabilities, initiate auto negotiation
* and wait until this has been completed.
*/
//printf("Negotiate..");
NicPhyWrite(NIC_PHYANAD, PHYANAD_TX_FDX | PHYANAD_TX_HDX | PHYANAD_10FDX | PHYANAD_10_HDX | PHYANAD_CSMA);
NutSleep(63);
for (phy_to = 0, phy_sr = 0;; phy_to++) {
/* Give up after 10 seconds. */
if (phy_to >= 1024)
return -1;
/* Restart auto negotiation every 4 seconds or on failures. */
if ((phy_to & 127) == 0 /* || (phy_sr & PHYSR_REM_FLT) != 0 */ ) {
NicPhyWrite(NIC_PHYCR, PHYCR_ANEG_EN | PHYCR_ANEG_RST);
//printf("Restart..");
NutSleep(63);
}
/* Check if we are done. */
phy_sr = NicPhyRead(NIC_PHYSR);
//printf("[SR %04X]", phy_sr);
if (phy_sr & PHYSR_ANEG_ACK)
break;
NutSleep(63);
}
//printf("OK\n");
#endif
return 0;
}
/*!
* \brief Wait until MMU is ready.
*
* Poll the MMU command register until \ref MMUCR_BUSY
* is cleared.
*
* \param tmo Timeout in milliseconds.
*
* \return 0 on success or -1 on timeout.
*/
static INLINE int NicMmuWait(u16_t tmo)
{
while (tmo--) {
if ((nic_inlb(NIC_MMUCR) & MMUCR_BUSY) == 0)
break;
NutDelay(1);
}
return tmo ? 0 : -1;
}
/*!
* \brief Reset the Ethernet controller.
*
* \return 0 on success, -1 otherwise.
*/
static int NicReset(void)
{
#ifdef LANC111_RESET_BIT
sbi(LANC111_RESET_DDR, LANC111_RESET_BIT);
sbi(LANC111_RESET_PORT, LANC111_RESET_BIT);
NutDelay(WAIT100);
cbi(LANC111_RESET_PORT, LANC111_RESET_BIT);
NutDelay(WAIT250);
NutDelay(WAIT250);
#endif
/* Disable all interrupts. */
nic_outlb(NIC_MSK, 0);
/* MAC and PHY software reset. */
nic_bs(0);
nic_outw(NIC_RCR, RCR_SOFT_RST);
/* Enable Ethernet protocol handler. */
nic_bs(1);
nic_outw(NIC_CR, CR_EPH_EN);
NutDelay(10);
/* Disable transmit and receive. */
nic_bs(0);
nic_outw(NIC_RCR, 0);
nic_outw(NIC_TCR, 0);
/* Enable auto release. */
nic_bs(1);
nic_outw(NIC_CTR, CTR_AUTO_RELEASE);
/* Reset MMU. */
nic_bs(2);
nic_outlb(NIC_MMUCR, MMU_RST);
if (NicMmuWait(1000))
return -1;
return 0;
}
/*
* Fires up the network interface. NIC interrupts
* should have been disabled when calling this
* function.
*
* \param mac Six byte unique MAC address.
*/
static int NicStart(CONST u8_t * mac)
{
u8_t i;
if (NicReset())
return -1;
/* Enable receiver. */
nic_bs(3);
nic_outlb(NIC_ERCV, 7);
nic_bs(0);
nic_outw(NIC_RCR, RCR_RXEN);
/* Enable transmitter and padding. */
nic_outw(NIC_TCR, TCR_PAD_EN | TCR_TXENA);
/* Configure the PHY. */
if (NicPhyConfig())
return -1;
/* Set MAC address. */
//printf("Set MAC %02X%02X%02X%02X%02X%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
nic_bs(1);
for (i = 0; i < 6; i++)
nic_outlb(NIC_IAR + i, mac[i]);
//printf("OK\n");
/* Enable interrupts. */
nic_bs(2);
nic_outlb(NIC_MSK, INT_ERCV | INT_RCV | INT_RX_OVRN);
return 0;
}
/*
* NIC interrupt entry.
*/
#if 0
static void NicInterrupt(void *arg)
{
u8_t isr;
u8_t imr;
NICINFO *ni = (NICINFO *) ((NUTDEVICE *) arg)->dev_dcb;
ni->ni_interrupts++;
/* Read the interrupt mask and disable all interrupts. */
nic_bs(2);
imr = nic_inlb(NIC_MSK);
nic_outlb(NIC_MSK, 0);
/* Read the interrupt status and acknowledge all interrupts. */
isr = nic_inlb(NIC_IST);
//printf("\n!%02X-%02X ", isr, imr);
isr &= imr;
/*
* If this is a transmit interrupt, then a packet has been sent.
* So we can clear the transmitter busy flag and wake up the
* transmitter thread.
*/
if (isr & INT_TX_EMPTY) {
nic_outlb(NIC_ACK, INT_TX_EMPTY);
imr &= ~INT_TX_EMPTY;
NutEventPostFromIrq(&ni->ni_tx_rdy);
}
/* Transmit error. */
else if (isr & INT_TX) {
/* re-enable transmit */
nic_bs(0);
nic_outw(NIC_TCR, nic_inlb(NIC_TCR) | TCR_TXENA);
nic_bs(2);
nic_outlb(NIC_ACK, INT_TX);
/* kill the packet */
nic_outlb(NIC_MMUCR, MMU_PKT);
NutEventPostFromIrq(&ni->ni_tx_rdy);
}
/*
* If this is a receive interrupt, then wake up the receiver
* thread.
*/
if (isr & INT_RX_OVRN) {
nic_outlb(NIC_ACK, INT_RX_OVRN);
//nic_outlb(NIC_MMUCR, MMU_TOP);
}
if (isr & INT_ERCV) {
nic_outlb(NIC_ACK, INT_ERCV);
NutEventPostFromIrq(&ni->ni_rx_rdy);
}
if (isr & INT_RCV) {
nic_outlb(NIC_ACK, INT_RCV);
imr &= ~INT_RCV;
NutEventPostFromIrq(&ni->ni_rx_rdy);
}
if (isr & INT_ALLOC) {
imr &= ~INT_ALLOC;
NutEventPostFromIrq(&maq);
}
//printf(" -%02X-%02X- ", nic_inlb(NIC_IST), inb(PINE) & 0x20);
nic_outlb(NIC_MSK, imr);
}
#endif /* 0 */
/*
* Write data block to the NIC.
*/
static void NicWrite(u8_t * buf, u16_t len)
{
register u16_t l = len - 1;
register u8_t ih = (u16_t) l >> 8;
register u8_t il = (u8_t) l;
if (!len)
return;
do {
do {
nic_outlb(NIC_DATA, *buf++);
} while (il-- != 0);
} while (ih-- != 0);
}
/*
* Read data block from the NIC.
*/
static void NicRead(u8_t * buf, u16_t len)
{
register u16_t l = len - 1;
register u8_t ih = (u16_t) l >> 8;
register u8_t il = (u8_t) l;
if (!len)
return;
do {
do {
*buf++ = nic_inlb(NIC_DATA);
} while (il-- != 0);
} while (ih-- != 0);
}
/*!
* \brief Fetch the next packet out of the receive ring buffer.
*
* Nic interrupts must be disabled when calling this funtion.
*
* \return Pointer to an allocated ::NETBUF. If there is no
* no data available, then the function returns a
* null pointer. If the NIC's buffer seems to be
* corrupted, a pointer to 0xFFFF is returned.
*/
static NETBUF *NicGetPacket(void)
{
NETBUF *nb = 0;
//u8_t *buf;
u16_t fsw;
u16_t fbc;
/* Check the fifo empty bit. If it is set, then there is
nothing in the receiver fifo. */
nic_bs(2);
if (nic_inw(NIC_FIFO) & 0x8000) {
return 0;
}
/* Inialize pointer register. */
nic_outw(NIC_PTR, PTR_READ | PTR_RCV | PTR_AUTO_INCR);
_NOP();
_NOP();
_NOP();
_NOP();
/* Read status word and byte count. */
fsw = nic_inw(NIC_DATA);
fbc = nic_inw(NIC_DATA);
//printf("[SW=%04X,BC=%04X]", fsw, fbc);
/* Check for frame errors. */
if (fsw & 0xAC00) {
nb = (NETBUF *) 0xFFFF;
}
/* Check the byte count. */
else if (fbc < 66 || fbc > 1524) {
nb = (NETBUF *) 0xFFFF;
}
else {
/*
* Allocate a NETBUF.
* Hack alert: Rev A chips never set the odd frame indicator.
*/
fbc -= 3;
/* nb = NutNetBufAlloc(0, NBAF_DATALINK, fbc);*/
/* Perform the read. */
/* if (nb)
NicRead(nb->nb_dl.vp, fbc);*/
}
/* Release the packet. */
nic_outlb(NIC_MMUCR, MMU_TOP);
return nb;
}
/*!
* \brief Load a packet into the nic's transmit ring buffer.
*
* Interupts must have been disabled when calling this function.
*
* \param nb Network buffer structure containing the packet to be sent.
* The structure must have been allocated by a previous
* call NutNetBufAlloc(). This routine will automatically
* release the buffer in case of an error.
*
* \return 0 on success, -1 in case of any errors. Errors
* will automatically release the network buffer
* structure.
*/
#if 0
static int NicPutPacket(NETBUF * nb)
{
u16_t sz;
u8_t odd = 0;
u8_t imsk;
//printf("[P]");
/*
* Calculate the number of bytes to be send. Do not send packets
* larger than the Ethernet maximum transfer unit. The MTU
* consist of 1500 data bytes plus the 14 byte Ethernet header
* plus 4 bytes CRC. We check the data bytes only.
*/
if ((sz = nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz) > ETHERMTU)
return -1;
/* Disable all interrupts. */
imsk = nic_inlb(NIC_MSK);
nic_outlb(NIC_MSK, 0);
/* Allocate packet buffer space. */
nic_bs(2);
nic_outlb(NIC_MMUCR, MMU_ALO);
if (NicMmuWait(100))
return -1;
/* Enable interrupts including allocation success. */
nic_outlb(NIC_MSK, imsk | INT_ALLOC);
/* The MMU needs some time. Use it to calculate the byte count. */
sz += nb->nb_dl.sz;
sz += 6;
if (sz & 1) {
sz++;
odd++;
}
/* Wait for allocation success. */
while ((nic_inlb(NIC_IST) & INT_ALLOC) == 0) {
if (NutEventWait(&maq, 125)) {
nic_outlb(NIC_MMUCR, MMU_RST);
NicMmuWait(1000);
nic_outlb(NIC_MMUCR, MMU_ALO);
if (NicMmuWait(100) || (nic_inlb(NIC_IST) & INT_ALLOC) == 0) {
if (NutEventWait(&maq, 125)) {
return -1;
}
}
}
}
/* Disable interrupts. */
imsk = nic_inlb(NIC_MSK);
nic_outlb(NIC_MSK, 0);
nic_outlb(NIC_PNR, nic_inhb(NIC_PNR));
nic_outw(NIC_PTR, 0x4000);
/* Transfer control word. */
nic_outlb(NIC_DATA, 0);
nic_outlb(NIC_DATA, 0);
/* Transfer the byte count. */
nic_outw(NIC_DATA, sz);
/* Transfer the Ethernet frame. */
NicWrite(nb->nb_dl.vp, nb->nb_dl.sz);
NicWrite(nb->nb_nw.vp, nb->nb_nw.sz);
NicWrite(nb->nb_tp.vp, nb->nb_tp.sz);
NicWrite(nb->nb_ap.vp, nb->nb_ap.sz);
if (odd)
nic_outlb(NIC_DATA, 0);
/* Transfer the control word. */
nic_outw(NIC_DATA, 0);
/* Enqueue packet. */
if (NicMmuWait(100))
return -1;
nic_outlb(NIC_MMUCR, MMU_ENQ);
/* Enable interrupts. */
imsk |= INT_TX | INT_TX_EMPTY;
nic_outlb(NIC_MSK, imsk);
return 0;
}
#endif
/*! \fn NicRxLanc(void *arg)
* \brief NIC receiver thread.
*
*/
#if 1
PROCESS_THREAD(lanc111_process, ev, data)
/*THREAD(NicRxLanc, arg)*/
{
/* NUTDEVICE *dev;
IFNET *ifn;
NICINFO *ni;
NETBUF *nb;*/
u8_t imsk;
static struct etimer et;
/* dev = arg;
ifn = (IFNET *) dev->dev_icb;
ni = (NICINFO *) dev->dev_dcb;*/
/*
* This is a temporary hack. Due to a change in initialization,
* we may not have got a MAC address yet. Wait until one has been
* set.
*/
PROCESS_BEGIN();
/* while(*((u_long *) (ifn->if_mac)) &&
*((u_long *) (ifn->if_mac)) != 0xFFFFFFFFUL) {*/
while(0) {
etimer_set(&et, CLOCK_SECOND / 8);
PROCESS_WAIT_UNTIL(etimer_expired(&et));
}
/*
* Do not continue unless we managed to start the NIC. We are
* trapped here if the Ethernet link cannot be established.
* This happens, for example, if no Ethernet cable is plugged
* in.
*/
/* while(NicStart(ifn->if_mac)) {*/
while(0) {
/*NutSleep(1000);*/
etimer_set(&et, CLOCK_SECOND);
PROCESS_WAIT_UNTIL(etimer_expired(&et));
}
LANC111_SIGNAL_MODE();
sbi(EIMSK, LANC111_SIGNAL_IRQ);
/* NutEventPost(&mutex);*/
/* Run at high priority. */
/* NutThreadSetPriority(9);*/
for (;;) {
/*
* Wait for the arrival of new packets or
* check the receiver every two second.
*/
/* NutEventWait(&ni->ni_rx_rdy, 2000);*/
PROCESS_WAIT_EVENT();
/*
* Fetch all packets from the NIC's internal
* buffer and pass them to the registered handler.
*/
imsk = nic_inlb(NIC_MSK);
nic_outlb(NIC_MSK, 0);
/* while ((nb = NicGetPacket()) != 0) {
if (nb != (NETBUF *) 0xFFFF) {
ni->ni_rx_packets++;
(*ifn->if_recv) (dev, nb);
}
}*/
nic_outlb(NIC_MSK, imsk | INT_RCV | INT_ERCV);
}
PROCESS_END();
}
#endif /* 0 */
/*!
* \brief Send Ethernet packet.
*
* \param dev Identifies the device to use.
* \param nb Network buffer structure containing the packet to be sent.
* The structure must have been allocated by a previous
* call NutNetBufAlloc().
*
* \return 0 on success, -1 in case of any errors.
*/
#if 0
int LancOutput(NUTDEVICE * dev, NETBUF * nb)
{
static u_long mx_wait = 5000;
int rc = -1;
NICINFO *ni;
/*
* After initialization we are waiting for a long time to give
* the PHY a chance to establish an Ethernet link.
*/
if (NutEventWait(&mutex, mx_wait) == 0) {
ni = (NICINFO *) dev->dev_dcb;
if (NicPutPacket(nb) == 0) {
ni->ni_tx_packets++;
rc = 0;
/* Ethernet works. Set a long waiting time in case we
temporarly lose the link next time. */
mx_wait = 5000;
}
NutEventPost(&mutex);
}
/*
* Probably no Ethernet link. Significantly reduce the waiting
* time, so following transmission will soon return an error.
*/
else {
mx_wait = 500;
}
return rc;
}
#endif
#if 0
/*!
* \brief Initialize Ethernet hardware.
*
* Resets the LAN91C111 Ethernet controller, initializes all required
* hardware registers and starts a background thread for incoming
* Ethernet traffic.
*
* Applications should do not directly call this function. It is
* automatically executed during during device registration by
* NutRegisterDevice().
*
* If the network configuration hasn't been set by the application
* before registering the specified device, this function will
* call NutNetLoadConfig() to get the MAC address.
*
* \param dev Identifies the device to initialize.
*/
int LancInit(NUTDEVICE * dev)
{
/* Disable NIC interrupt and clear NICINFO structure. */
cbi(EIMSK, LANC111_SIGNAL_IRQ);
memset(dev->dev_dcb, 0, sizeof(NICINFO));
/* Register interrupt handler and enable interrupts. */
if (NutRegisterIrqHandler(&LANC111_SIGNAL, NicInterrupt, dev))
return -1;
/*
* Start the receiver thread.
*/
NutThreadCreate("rxi5", NicRxLanc, dev, 640);
//NutSleep(500);
return 0;
}
/*@}*/
/*!
* \addtogroup xgSmscDev
*/
/*@{*/
static NICINFO dcb_eth0;
/*!
* \brief Network interface information structure.
*
* Used to call.
*/
static IFNET ifn_eth0 = {
IFT_ETHER, /*!< \brief Interface type. */
{0, 0, 0, 0, 0, 0}, /*!< \brief Hardware net address. */
0, /*!< \brief IP address. */
0, /*!< \brief Remote IP address for point to point. */
0, /*!< \brief IP network mask. */
ETHERMTU, /*!< \brief Maximum size of a transmission unit. */
0, /*!< \brief Packet identifier. */
0, /*!< \brief Linked list of arp entries. */
NutEtherInput, /*!< \brief Routine to pass received data to, if_recv(). */
LancOutput, /*!< \brief Driver output routine, if_send(). */
NutEtherOutput /*!< \brief Media output routine, if_output(). */
};
/*!
* \brief Device information structure.
*
* A pointer to this structure must be passed to NutRegisterDevice()
* to bind this Ethernet device driver to the Nut/OS kernel.
* An application may then call NutNetIfConfig() with the name \em eth0
* of this driver to initialize the network interface.
*
*/
NUTDEVICE devSmsc111 = {
0, /* Pointer to next device. */
{'e', 't', 'h', '0', 0, 0, 0, 0, 0}, /* Unique device name. */
IFTYP_NET, /* Type of device. */
0, /* Base address. */
0, /* First interrupt number. */
&ifn_eth0, /* Interface control block. */
&dcb_eth0, /* Driver control block. */
LancInit, /* Driver initialization routine. */
0, /* Driver specific control function. */
0, /* Read from device. */
0, /* Write to device. */
0, /* Write from program space data to device. */
0, /* Open a device or file. */
0, /* Close a device or file. */
0 /* Request file size. */
};
/*@}*/
#endif
int
lanc111_init(void)
{
/* Disable NIC interrupt and clear NICINFO structure. */
cbi(EIMSK, LANC111_SIGNAL_IRQ);
/* Register interrupt handler and enable interrupts. */
/* if (NutRegisterIrqHandler(&LANC111_SIGNAL, NicInterrupt, dev))
return -1;*/
/*
* Start the receiver thread.
*/
/* NutThreadCreate("rxi5", NicRxLanc, dev, 640);*/
//NutSleep(500);
return 0;
}