📄 dm9000e.c
字号:
/* * 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: dm9000e.c,v $ * Revision 1.1 2005/10/24 08:49:05 haraldkipp * Initial check in. * */#include <cfg/os.h>#include <arch/arm/at91.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 <netinet/if_ether.h>#include <net/ether.h>#include <net/if_var.h>#include <dev/irqreg.h>#include <dev/dm9000e.h>#ifdef NUTDEBUG#include <stdio.h>#endif#ifndef NUT_THREAD_NICRXSTACK#define NUT_THREAD_NICRXSTACK 768#endif/* * Determine ports, which had not been explicitely configured. */#ifndef NIC_BASE_ADDR#define NIC_BASE_ADDR 0x20000000#endif#ifndef NIC_DATA_ADDR#define NIC_DATA_ADDR (NIC_BASE_ADDR + 4)#endif#define INT0 0#define INT1 1#define INT2 2#define INT3 3#define INT4 4#define INT5 5#define INT6 6#define INT7 7#ifndef NIC_SIGNAL_IRQ#define NIC_SIGNAL_IRQ INT1#endif#ifdef NIC_RESET_BIT#if (NIC_RESET_AVRPORT == AVRPORTB)#define NIC_RESET_PORT PORTB#define NIC_RESET_DDR DDRB#elif (NIC_RESET_AVRPORT == AVRPORTD)#define NIC_RESET_PORT PORTD#define NIC_RESET_DDR DDRD#elif (NIC_RESET_AVRPORT == AVRPORTE)#define NIC_RESET_PORT PORTE#define NIC_RESET_DDR DDRE#elif (NIC_RESET_AVRPORT == AVRPORTF)#define NIC_RESET_PORT PORTF#define NIC_RESET_DDR DDRF#endif /* NIC_RESET_AVRPORT */#endif /* NIC_RESET_BIT *//* * Determine interrupt settings. * DOES NOT WORK */#if (NIC_SIGNAL_IRQ == INT0)#define NIC_SIGNAL sig_INTERRUPT0#elif (NIC_SIGNAL_IRQ == INT2)#define NIC_SIGNAL sig_INTERRUPT2#elif (NIC_SIGNAL_IRQ == INT3)#define NIC_SIGNAL sig_INTERRUPT3#elif (NIC_SIGNAL_IRQ == INT4)#define NIC_SIGNAL sig_INTERRUPT4#elif (NIC_SIGNAL_IRQ == INT5)#define NIC_SIGNAL sig_INTERRUPT5#elif (NIC_SIGNAL_IRQ == INT6)#define NIC_SIGNAL sig_INTERRUPT6#elif (NIC_SIGNAL_IRQ == INT7)#define NIC_SIGNAL sig_INTERRUPT7#else#define NIC_SIGNAL sig_INTERRUPT1#endif/*! * \addtogroup xgDm9000eRegs *//*@{*/#define NIC_NCR 0x00 /* Network control register (0x00). */#define NIC_NCR_LBM 0x06 /* Loopback mode. */#define NIC_NCR_LBNORM 0x00 /* Normal mode. */#define NIC_NCR_LBMAC 0x02 /* MAC loopback. */#define NIC_NCR_LBPHY 0x04 /* PHY loopback. */#define NIC_NCR_RST 0x01 /* Software reset, auto clear. */#define NIC_NSR 0x01 /* Network status register (0x00). */#define NIC_NSR_SPEED 0x80#define NIC_NSR_LINKST 0x40#define NIC_NSR_WAKEST 0x20#define NIC_NSR_TX2END 0x08#define NIC_NSR_TX1END 0x04#define NIC_NSR_RXOV 0x02#define NIC_TCR 0x02 /* TX control register (0x00). */#define NIC_TCR_TXREQ 0x01 /* TX request */#define NIC_TSR1 0x03 /* TX status register I (0x00). */#define NIC_TSR2 0x04 /* TX status register II (0x00). */#define NIC_RCR 0x05 /* RX control register (0x00). */#define NIC_RCR_DIS_LONG 0x20 /* Discard long packets. */#define NIC_RCR_DIS_CRC 0x10 /* Discard CRC error packets. */#define NIC_RCR_PRMSC 0x02 /* Enable promiscuous mode. */#define NIC_RCR_RXEN 0x01 /* Enable receiver. */#define NIC_RSR 0x06 /* RX status register (0x00). */#define NIC_RSR_ERRORS 0xBF /* Error bit mask. */#define NIC_RSR_RF 0x80 /* Runt frame. */#define NIC_RSR_MF 0x40 /* Multicast frame. */#define NIC_RSR_LCS 0x20 /* Late collision. */#define NIC_RSR_RWTO 0x10 /* Receiver watchdog time out. */#define NIC_RSR_PLE 0x08 /* Physical layer error. */#define NIC_RSR_AE 0x04 /* Alignment error. */#define NIC_RSR_CE 0x02 /* CRC error. */#define NIC_RSR_FOE 0x01 /* FIFO overflow error. */#define NIC_ROCR 0x07 /* Receive overflow counter register (0x00). */#define NIC_BPTR 0x08 /* Back pressure threshold register (0x37). */#define NIC_FCTR 0x09 /* Flow control threshold register (0x38). */#define NIC_FCR 0x0A /* RX flow control register (0x00). */#define NIC_EPCR 0x0B /* EEPROM and PHY control register. */#define NIC_EPAR 0x0C /* EEPROM and PHY address register. */#define NIC_EPDRL 0x0D /* EEPROM and PHY low byte data register. */#define NIC_EPDRH 0x0E /* EEPROM and PHY high byte data register. */#define NIC_WCR 0x0F /* Wake up control register (0x00). */#define NIC_PAR 0x10 /* 6 byte physical address register. */#define NIC_MAR 0x16 /* 8 byte multicast address register. */#define NIC_GPCR 0x1E /* General purpose control register (?). */#define NIC_GPR 0x1F /* General purpose register (?). */#define NIC_TRPA 0x22 /* 2 byte TX SRAM read pointer address, low/high (0x0000). */#define NIC_RWPA 0x24 /* 2 byte RX SRAM write pointer address, low/high (0x0000). */#define NIC_VID 0x28 /* 2 byte vendor ID (0x0A46). */#define NIC_PID 0x2A /* 2 byte product ID (0x0900). */#define NIC_CHIPR 0x2C /* Chip revision (0x00). */#define NIC_SMCR 0x2F /* Special mode register (0x00). */#define NIC_MRCMDX 0xF0 /* Memory data read command w/o increment (?). */#define NIC_MRCMD 0xF2 /* Memory data read command with increment (?). */#define NIC_MRR 0xF4 /* 2 byte memory data read register, low/high (?). */#define NIC_MWCMDX 0xF6 /* Memory data write command register w/o increment (?). */#define NIC_MWCMD 0xF8 /* Memory data write command register with increment (?). */#define NIC_MWR 0xFA /* Memory data write command register with increment (?). */#define NIC_TXPL 0xFC /* 2 byte TX packet length register. (?). */#define NIC_ISR 0xFE /* Interrupt status register (0x00). */#define NIC_ISR_IOM 0xC0 /* I/O mode mask */#define NIC_ISR_M16 0x00 /* 16-bit I/O mode */#define NIC_ISR_M32 0x40 /* 32-bit I/O mode */#define NIC_ISR_M8 0x80 /* 8-bit I/O mode */#define NIC_ISR_ROOS 0x08 /* Receiver overflow counter interrupt. */#define NIC_ISR_ROS 0x04 /* Receiver overflow interrupt. */#define NIC_ISR_PTS 0x02 /* Transmitter interrupt. */#define NIC_ISR_PRS 0x01 /* Receiver interrupt. */#define NIC_IMR 0xFF /* Interrupt mask register (0x00). */#define NIC_IMR_PAR 0x80 /* Enable read/write pointer wrap around. */#define NIC_IMR_ROOM 0x08 /* Enable receiver overflow counter interrupts. */#define NIC_IMR_ROM 0x04 /* Enable receiver overflow interrupts. */#define NIC_IMR_PTM 0x02 /* Enable transmitter interrupts. */#define NIC_IMR_PRM 0x01 /* Enable receiver interrupts. */#define NIC_PHY_BMCR 0x00 /* Basic mode control register. */#define NIC_PHY_BMSR 0x01 /* Basic mode status register. */#define NIC_PHY_BMSR_ANCOMPL 0x0020 /* Auto negotiation complete. */#define NIC_PHY_BMSR_LINKSTAT 0x0004 /* Link status. */#define NIC_PHY_ID1 0x02 /* PHY identifier register 1. */#define NIC_PHY_ID2 0x03 /* PHY identifier register 2. */#define NIC_PHY_ANAR 0x04 /* Auto negotiation advertisement register. */#define NIC_PHY_ANLPAR 0x05 /* Auto negotiation link partner availability register. */#define NIC_PHY_ANER 0x06 /* Auto negotiation expansion register. */#define NIC_PHY_DSCR 0x10 /* Davicom specified configuration register. */#define NIC_PHY_DSCSR 0x11 /* Davicom specified configuration and status register. */#define NIC_PHY_10BTCSR 0x12 /* 10BASE-T configuration and status register. *//*! * \brief Network interface controller information structure. */struct _NICINFO {#ifdef NUT_PERFMON u_long ni_rx_packets; /*!< Number of packets received. */ u_long ni_tx_packets; /*!< Number of packets sent. */ u_long ni_overruns; /*!< Number of packet overruns. */ u_long ni_rx_frame_errors; /*!< Number of frame errors. */ u_long ni_rx_crc_errors; /*!< Number of CRC errors. */ u_long ni_rx_missed_errors; /*!< Number of missed packets. */#endif HANDLE volatile ni_rx_rdy; /*!< Receiver event queue. */ HANDLE volatile ni_tx_rdy; /*!< Transmitter event queue. */ HANDLE ni_mutex; /*!< Access mutex semaphore. */ volatile int ni_tx_queued; /*!< Number of packets in transmission queue. */ volatile int ni_tx_quelen; /*!< Number of bytes in transmission queue not sent. */ int ni_insane; /*!< Set by error detection. */ int ni_iomode; /*!< 8 or 16 bit access. 32 bit is not supported. */};/*! * \brief Network interface controller information type. */typedef struct _NICINFO NICINFO;/*@}*//*! * \addtogroup xgNicDm9000e *//*@{*/static inline void nic_outb(u_char reg, u_char val){ outb(NIC_BASE_ADDR, reg); outb(NIC_DATA_ADDR, val);}static inline u_char nic_inb(u_short reg){ outb(NIC_BASE_ADDR, reg); return inb(NIC_DATA_ADDR);}/*! * \brief Read contents of PHY register. * * \param reg PHY register number. * * \return Contents of the specified register. */static u_short phy_inw(u_char reg){ /* Select PHY register */ nic_outb(NIC_EPAR, 0x40 | reg); /* PHY read command. */ nic_outb(NIC_EPCR, 0x0C); NutDelay(1); nic_outb(NIC_EPCR, 0x00); /* Get data from PHY data register. */ return ((u_short) nic_inb(NIC_EPDRH) << 8) | (u_short) nic_inb(NIC_EPDRL);}/*! * \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 phy_outw(u_char reg, u_short val){ /* Select PHY register */ nic_outb(NIC_EPAR, 0x40 | reg); /* Store value in PHY data register. */ nic_outb(NIC_EPDRL, (u_char) val); nic_outb(NIC_EPDRH, (u_char) (val >> 8)); /* PHY write command. */ nic_outb(NIC_EPCR, 0x0A); NutDelay(1); nic_outb(NIC_EPCR, 0x00);}static int NicPhyInit(void){ /* Restart auto negotiation. */ phy_outw(NIC_PHY_ANAR, 0x01E1); phy_outw(NIC_PHY_BMCR, 0x1200); nic_outb(NIC_GPCR, 1); nic_outb(NIC_GPR, 0); return 0;}/*! * \brief Reset the Ethernet controller. * * \return 0 on success, -1 otherwise. */static int NicReset(void){ /* Hardware reset. */#ifdef undef_NIC_RESET_BIT sbi(NIC_RESET_DDR, NIC_RESET_BIT); sbi(NIC_RESET_PORT, NIC_RESET_BIT); NutDelay(WAIT100); cbi(NIC_RESET_PORT, NIC_RESET_BIT); NutDelay(WAIT250); NutDelay(WAIT250);#else /* Software reset. */ nic_outb(NIC_NCR, NIC_NCR_RST | NIC_NCR_LBMAC); NutDelay(1); /* FIXME: Delay required. */#endif return NicPhyInit();}/* * NIC interrupt entry. */static void NicInterrupt(void *arg){ u_char isr; NICINFO *ni = (NICINFO *) ((NUTDEVICE *) arg)->dev_dcb; /* Read interrupt status and disable interrupts. */ isr = nic_inb(NIC_ISR); /* Receiver interrupt. */ if (isr & NIC_ISR_PRS) { nic_outb(NIC_ISR, NIC_ISR_PRS); NutEventPostFromIrq(&ni->ni_rx_rdy); } /* Transmitter interrupt. */ if (isr & NIC_ISR_PTS) { if (ni->ni_tx_queued) { if (ni->ni_tx_quelen) { /* Initiate transfer of a queued packet. */ nic_outb(NIC_TXPL, (u_char) ni->ni_tx_quelen); nic_outb(NIC_TXPL + 1, (u_char) (ni->ni_tx_quelen >> 8)); ni->ni_tx_quelen = 0; nic_outb(NIC_TCR, NIC_TCR_TXREQ); } ni->ni_tx_queued--; } nic_outb(NIC_ISR, NIC_ISR_PTS); NutEventPostFromIrq(&ni->ni_tx_rdy); } /* Receiver overflow interrupt. */ if (isr & NIC_ISR_ROS) { nic_outb(NIC_ISR, NIC_ISR_ROS); NutEventPostFromIrq(&ni->ni_rx_rdy); } /* Receiver overflow counter interrupt. */ if (isr & NIC_ISR_ROOS) { nic_outb(NIC_ISR, NIC_ISR_ROOS); NutEventPostFromIrq(&ni->ni_rx_rdy); }}/*! * \brief Write data block to the NIC. * * NIC interrupts must be disabled when calling this function. */static void NicWrite8(u_char * buf, u_short len){ while (len--) { outb(NIC_DATA_ADDR, *buf); buf++; }}/*! * \brief Write data block to the NIC. * * NIC interrupts must be disabled when calling this function. */static void NicWrite16(u_char * buf, u_short len){ u_short *wp = (u_short *) buf; len = (len + 1) / 2; while (len--) { outw(NIC_DATA_ADDR, *wp); wp++; }}/*! * \brief Read data block from the NIC. * * NIC interrupts must be disabled when calling this function. */static void NicRead8(u_char * buf, u_short len){ while (len--) { *buf++ = inb(NIC_DATA_ADDR); }}/*! * \brief Read data block from the NIC. * * NIC interrupts must be disabled when calling this function. */static void NicRead16(u_char * buf, u_short len){ u_short *wp = (u_short *) buf;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -