📄 nicrtl.c
字号:
/* * Copyright (C) 2001-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: nicrtl.c,v $ * Revision 1.1 2005/07/26 18:02:40 haraldkipp * Moved from dev. * * Revision 1.15 2005/04/30 16:42:41 chaac * Fixed bug in handling of NUTDEBUG. Added include for cfg/os.h. If NUTDEBUG * is defined in NutConf, it will make effect where it is used. * * Revision 1.14 2005/02/10 07:06:18 hwmaier * Changes to incorporate support for AT90CAN128 CPU * * Revision 1.13 2005/02/05 20:42:38 haraldkipp * Force compiler error for leftover debug prints. * * Revision 1.12 2005/01/24 21:11:50 freckle * renamed NutEventPostFromIRQ into NutEventPostFromIrq * * Revision 1.11 2005/01/22 19:24:46 haraldkipp * Changed AVR port configuration names from PORTx to AVRPORTx. * * Revision 1.10 2005/01/21 16:49:46 freckle * Seperated calls to NutEventPostAsync between Threads and IRQs * * Revision 1.9 2004/12/17 15:31:28 haraldkipp * Support of rising edge interrupts for hardware w/o inverter gate. * Fixed compilation issue for hardware with RTL reset port. * Thanks to FOCUS Software Engineering Pty Ltd. * * Revision 1.8 2004/09/10 10:36:01 haraldkipp * ICCAVR compile problems fixed * * Revision 1.7 2004/08/25 10:41:00 haraldkipp * Hardware dependent definitions are configurable. For performance reasons the * base address is not kept in a variable any longer. It is now a preprocessor * macro and the parameters during device registration are ignored. The speed * improvements provided by Kolja Waschk for the LAN91C111 had been implemented * here too. The driver will not touch a port anymore unless a reset port bit * had been configured. For Ethernut 1.1 bit 4 PORTE must be specified in the * configuration. Finally, an EEPROM emulation had been added, which can use * address bus bits instead of wasting additional port pins. The required * hardware has been implemented on Rev.-G Ethernut 1.3 boards. This fixes the * Realtek full duplex problem. * * Revision 1.6 2004/05/17 19:14:53 haraldkipp * Added Bengt Florin's RTL8019 driver mods * * Revision 1.5 2004/03/16 16:48:27 haraldkipp * Added Jan Dubiec's H8/300 port. * * Revision 1.4 2003/08/05 20:05:59 haraldkipp * Bugfix. Empty MAC address is FF, not 00 * * Revision 1.3 2003/07/17 09:39:56 haraldkipp * Optimized controller feeding. * Ignore LSB of packet status. * * Revision 1.2 2003/05/15 14:09:16 haraldkipp * Much better performance under heavy traffic. * * Revision 1.1.1.1 2003/05/09 14:40:48 haraldkipp * Initial using 3.2.1 * */#include <cfg/os.h>#include <cfg/arch/avr.h>#include <string.h>#include <sys/atom.h>#include <sys/heap.h>#include <sys/thread.h>#include <sys/event.h>#include <sys/timer.h>#include <sys/confnet.h>#include <net/ether.h>#include <net/if_var.h>#include <dev/irqreg.h>#include <dev/nicrtl.h>#include "rtlregs.h"#ifdef NUTDEBUG#include <sys/osdebug.h>#include <net/netdebug.h>#endif/* * Determine ports, which had not been explicitely configured. */#if (RTL_EESK_AVRPORT == AVRPORTB)#define RTL_EESK_PIN PINB#define RTL_EESK_DDR DDRB#elif (RTL_EESK_AVRPORT == AVRPORTC)#define RTL_EE_MEMBUS#define RTL_EESK_PIN PINC#define RTL_EESK_DDR DDRC#elif (RTL_EESK_AVRPORT == AVRPORTD)#define RTL_EESK_PIN PIND#define RTL_EESK_DDR DDRD#elif (RTL_EESK_AVRPORT == AVRPORTE)#define RTL_EESK_PIN PINE#define RTL_EESK_DDR DDRE#elif (RTL_EESK_AVRPORT == AVRPORTF)#define RTL_EESK_PIN PINF#define RTL_EESK_DDR DDRF#endif /* RTL_EESK_AVRPORT */#if (RTL_EEDO_AVRPORT == AVRPORTB)#define RTL_EEDO_PORT PORTB#define RTL_EEDO_DDR DDRB#elif (RTL_EEDO_AVRPORT == AVRPORTC)#define RTL_EE_MEMBUS#define RTL_EEDO_PORT PORTC#define RTL_EEDO_DDR DDRC#elif (RTL_EEDO_AVRPORT == AVRPORTD)#define RTL_EEDO_PORT PORTD#define RTL_EEDO_DDR DDRD#elif (RTL_EEDO_AVRPORT == AVRPORTE)#define RTL_EEDO_PORT PORTE#define RTL_EEDO_DDR DDRE#elif (RTL_EEDO_AVRPORT == AVRPORTF)#define RTL_EEDO_PORT PORTF#define RTL_EEDO_DDR DDRF#endif /* RTL_EEDO_AVRPORT */#if (RTL_EEMU_AVRPORT == AVRPORTB)#define RTL_EEMU_PORT PORTB#define RTL_EEMU_DDR DDRB#elif (RTL_EEMU_AVRPORT == AVRPORTC)#define RTL_EE_MEMBUS#define RTL_EEMU_PORT PORTC#define RTL_EEMU_DDR DDRC#elif (RTL_EEMU_AVRPORT == AVRPORTD)#define RTL_EEMU_PORT PORTD#define RTL_EEMU_DDR DDRD#elif (RTL_EEMU_AVRPORT == AVRPORTE)#define RTL_EEMU_PORT PORTE#define RTL_EEMU_DDR DDRE#elif (RTL_EEMU_AVRPORT == AVRPORTF)#define RTL_EEMU_PORT PORTF#define RTL_EEMU_DDR DDRF#endif /* RTL_EEMU_AVRPORT */#if (RTL_RESET_AVRPORT == AVRPORTB)#define RTL_RESET_PORT PORTB#define RTL_RESET_DDR DDRB#elif (RTL_RESET_AVRPORT == AVRPORTD)#define RTL_RESET_PORT PORTD#define RTL_RESET_DDR DDRD#elif (RTL_RESET_AVRPORT == AVRPORTE)#define RTL_RESET_PORT PORTE#define RTL_RESET_DDR DDRE#elif (RTL_RESET_AVRPORT == AVRPORTF)#define RTL_RESET_PORT PORTF#define RTL_RESET_DDR DDRF#endif /* RTL_RESET_AVRPORT *//*! * \brief Interrupt used. */#if (RTL_SIGNAL_IRQ == INT0)#define RTL_SIGNAL sig_INTERRUPT0#ifdef __AVR_ENHANCED__#define RTL_RISING_EDGE_MODE() sbi(EICRA, ISC00); sbi(EICRA, ISC01)#endif#elif (RTL_SIGNAL_IRQ == INT1)#define RTL_SIGNAL sig_INTERRUPT1#ifdef __AVR_ENHANCED__#define RTL_RISING_EDGE_MODE() sbi(EICRA, ISC10); sbi(EICRA, ISC11)#endif#elif (RTL_SIGNAL_IRQ == INT2)#define RTL_SIGNAL sig_INTERRUPT2#ifdef __AVR_ENHANCED__#define RTL_RISING_EDGE_MODE() sbi(EICRA, ISC20); sbi(EICRA, ISC21)#endif#elif (RTL_SIGNAL_IRQ == INT3)#define RTL_SIGNAL sig_INTERRUPT3#ifdef __AVR_ENHANCED__#define RTL_RISING_EDGE_MODE() sbi(EICRA, ISC30); sbi(EICRA, ISC31)#endif#elif (RTL_SIGNAL_IRQ == INT4)#define RTL_SIGNAL sig_INTERRUPT4#ifdef __AVR_ENHANCED__#define RTL_RISING_EDGE_MODE() sbi(EICRB, ISC40); sbi(EICRB, ISC41)#endif#elif (RTL_SIGNAL_IRQ == INT6)#define RTL_SIGNAL sig_INTERRUPT6#ifdef __AVR_ENHANCED__#define RTL_RISING_EDGE_MODE() sbi(EICRB, ISC60); sbi(EICRB, ISC61)#endif#elif (RTL_SIGNAL_IRQ == INT7)#define RTL_SIGNAL sig_INTERRUPT7#ifdef __AVR_ENHANCED__#define RTL_RISING_EDGE_MODE() sbi(EICRB, ISC70); sbi(EICRB, ISC71)#endif#else#define RTL_SIGNAL sig_INTERRUPT5#ifdef __AVR_ENHANCED__#define RTL_RISING_EDGE_MODE() sbi(EICRB, ISC50); sbi(EICRB, ISC51)#endif#endif /* RTL_SIGNAL_IRQ *//*! * \brief Size of a single ring buffer page. */#define NIC_PAGE_SIZE 0x100/*! * \brief First ring buffer page address. */#define NIC_START_PAGE 0x40/*! * \brief Last ring buffer page address plus 1. */#define NIC_STOP_PAGE 0x60/*! * \brief Number of pages in a single transmit buffer. * * This should be at least the MTU size. */#define NIC_TX_PAGES 6/*! * \brief Number of transmit buffers. * * The initial value had been 2. The idea was to use two alternating * buffers. However, this had never been implemented and we took over * Bengt Florin's change, defining 1 transmit buffer only and give * more buffer space to the receiver. * * The controller memory layout is now * * - 0x4000..0x45ff 1.5K bytes transmit buffer * - 0x4600..0x5fff 6.5K bytes receive buffer * * The routines are still not using the buffers in an optimal way, * as transmission is limited to 1 packet at a time. In fact several * smaller packets would fit into the 1.5 kByte buffer. On the other * hand, filling the buffer with more than one transmission packet * may result in other bad effects, like pulling the IORDY line more * often. */#define NIC_TX_BUFFERS 1#define NIC_FIRST_TX_PAGE NIC_START_PAGE#define NIC_FIRST_RX_PAGE (NIC_FIRST_TX_PAGE + NIC_TX_PAGES * NIC_TX_BUFFERS)#define NIC_CR_PAGE0 (0)#define NIC_CR_PAGE1 (NIC_CR_PS0)#define NIC_CR_PAGE2 (NIC_CR_PS1)#define NIC_CR_PAGE3 (NIC_CR_PS1 | NIC_CR_PS0)/* * This delay has been added by Bengt Florin and is used to minimize * the effect of the IORDY line during reads. Bengt contributed a * more versatile loop, which unfortunately wasn't portable to the * ImageCraft compiler. * * Both versions depend on the CPU clock and had been tested with * 14.7456 MHz. */static INLINE void Delay16Cycles(void){ _NOP(); _NOP(); _NOP(); _NOP(); _NOP(); _NOP(); _NOP(); _NOP(); _NOP(); _NOP(); _NOP(); _NOP(); _NOP(); _NOP(); _NOP(); _NOP();}/*! * \addtogroup xgNicRtl *//*@{*//*! * Realtek packet header. */struct nic_pkt_header { u_char ph_status; /*!< \brief Status, contents of RSR register */ u_char ph_nextpg; /*!< \brief Page for next packet */ u_short ph_size; /*!< \brief Size of header and packet in octets */};#define NICINB(reg) (*((volatile u_char *)RTL_BASE_ADDR + reg))#define NICOUTB(reg, val) (*((volatile u_char *)RTL_BASE_ADDR + reg) = val)/*! * \brief Reset the Ethernet controller. * */static int NicReset(void){ u_char i; u_char j;/* * Toggle the hardware reset line. Since Ethernut version 1.3 the * hardware reset pin of the nic is no longer connected to bit 4 * on port E, but wired to the board reset line. */#ifdef RTL_RESET_BIT sbi(RTL_RESET_DDR, RTL_RESET_BIT); sbi(RTL_RESET_PORT, RTL_RESET_BIT); NutDelay(WAIT100); cbi(RTL_RESET_PORT, RTL_RESET_BIT); NutDelay(WAIT250); NutDelay(WAIT250);#endif /* * Do the software reset by reading from the reset register followed * by writing to the reset register. Wait until the controller enters * the reset state. */ for (j = 0; j < 20; j++) { i = NICINB(NIC_RESET); NutDelay(WAIT5); NICOUTB(NIC_RESET, i); for (i = 0; i < 20; i++) { NutDelay(WAIT50); /* * We got the reset bit. However, Ethernut 1.1 may * still fail because the NIC hasn't got it's hardware * reset and the data lines remain in tristate. So we * read noise instead of the register. To solve this * problem, we will verify the NIC's id. */ if ((NICINB(NIC_PG0_ISR) & NIC_ISR_RST) != 0 && /* */ NICINB(NIC_PG0_RBCR0) == 0x50 && /* */ NICINB(NIC_PG0_RBCR1) == 0x70) return 0; } } return -1;}static int DetectNicEeprom(void){#ifdef RTL_EESK_BIT register u_int cnt = 0; NutEnterCritical(); /* * Prepare the EEPROM emulation port bits. Configure the EEDO * and the EEMU lines as outputs and set both lines to high. */ sbi(RTL_EEDO_PORT, RTL_EEDO_BIT); sbi(RTL_EEDO_DDR, RTL_EEDO_BIT);#ifdef RTL_EEMU_BIT sbi(RTL_EEMU_PORT, RTL_EEMU_BIT); sbi(RTL_EEMU_DDR, RTL_EEMU_BIT);#endif NutDelay(20); /* * Force the chip to re-read the EEPROM contents. */ NICOUTB(NIC_CR, NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0 | NIC_CR_PS1); NICOUTB(NIC_PG3_EECR, NIC_EECR_EEM0); /* * No external memory access beyond this point. */#ifdef RTL_EE_MEMBUS /* * No external memory access beyond this point. */#ifdef __AVR_ENHANCED__ /* On the ATmega 128 we release bits 5-7 as normal port pins. */ outb(XMCRB, inb(XMCRB) | _BV(XMM0) | _BV(XMM1));#else /* On the ATmega 103 we have to disable the external memory interface. */ cbi(MCUCR, SRE);#endif#endif /* * Check, if the chip toggles our EESK input. If not, we do not * have EEPROM emulation hardware. */ if (bit_is_set(RTL_EESK_PIN, RTL_EESK_BIT)) { while (++cnt && bit_is_set(RTL_EESK_PIN, RTL_EESK_BIT));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -