⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nicrtl.c

📁 avr上的RTOS
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) 2001-2004 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.4  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.3  2005/01/24 21:11:52  freckle * renamed NutEventPostFromIRQ into NutEventPostFromIrq * * Revision 1.2  2005/01/21 16:49:46  freckle * Seperated calls to NutEventPostAsync between Threads and IRQs * * Revision 1.1  2004/03/16 16:48:27  haraldkipp * Added Jan Dubiec's H8/300 port. * */#include <cfg/os.h>#include <string.h>#include <sys/nutconfig.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/nicrtl.h>#include "rtlregs.h"#ifdef NUTDEBUG#include <sys/osdebug.h>#include <net/netdebug.h>#endif/*! * \brief Read word from controller DMA port. */#define nic_read_dma() *((volatile u_short*) (base + NIC_IOPORT))/*! * \brief Write word to controller DMA port. */#define nic_write_dma(data) *((u_short*) (base + NIC_IOPORT)) = data/*! * \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. */#define NIC_TX_BUFFERS  2/*! * \brief Controller memory layout: * * 0x4000 - 0x4bff  3k bytes transmit buffer * 0x4c00 - 0x5fff  5k bytes receive buffer */#define NIC_FIRST_TX_PAGE   NIC_START_PAGE#define NIC_FIRST_RX_PAGE   (NIC_FIRST_TX_PAGE + NIC_TX_PAGES * NIC_TX_BUFFERS)/*! * \brief Standard sizing information */#define TX_PAGES 12             /* Allow for 2 back-to-back frames *//*! * \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 */};/*! * \brief Reset the Ethernet controller. * */static int NicReset(volatile u_char * base){    u_char i;    u_char j;    /*     * 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 = nic_read(NIC_RESET);        NutDelay(WAIT5);        nic_write(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 ((nic_read(NIC_PG0_ISR) & NIC_ISR_RST) != 0 && nic_read(NIC_PG0_RBCR0) == 0x50 && nic_read(NIC_PG0_RBCR1) == 0x70)                return 0;        }    }    return -1;}/* * Fires up the network interface. NIC interrupts * should have been disabled when calling this * function. */static int NicStart(volatile u_char * base, CONST u_char * mac){    u_char i;    if (NicReset(base))        return -1;    /*     * Mask all interrupts and clear any interrupt status flag to set the      * INT pin back to low.     */    nic_write(NIC_PG0_IMR, 0);    nic_write(NIC_PG0_ISR, 0xff);    /*     * During reset the nic loaded its initial configuration from an      * external eeprom. On the ethernut board we do not have any      * configuration eeprom, but simply tied the eeprom data line to      * high level. So we have to clear some bits in the configuration      * register. Switch to register page 3.     */    nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0 | NIC_CR_PS1);    /*     * The nic configuration registers are write protected unless both      * EEM bits are set to 1.     */    nic_write(NIC_PG3_EECR, NIC_EECR_EEM0 | NIC_EECR_EEM1);    /*     * Disable sleep and power down.     */    nic_write(NIC_PG3_CONFIG3, 0);    /*     * Network media had been set to 10Base2 by the virtual EEPROM and     * will be set now to auto detect. This will initiate a link test.     * We don't force 10BaseT, because this would disable the link test.     */    nic_write(NIC_PG3_CONFIG2, NIC_CONFIG2_BSELB);    /*     * Reenable write protection of the nic configuration registers     * and wait for link test to complete.     */    nic_write(NIC_PG3_EECR, 0);    NutDelay(255);    /*     * Switch to register page 0 and set data configuration register     * to byte-wide DMA transfers, normal operation (no loopback),     * send command not executed and 8 byte fifo threshold.     */    nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2);/*     nic_write(NIC_PG0_DCR, NIC_DCR_LS | NIC_DCR_FT1); */    nic_write(NIC_PG0_DCR, NIC_DCR_WTS | NIC_DCR_LS | NIC_DCR_FT1);    /*     * Clear remote dma byte count register.     */    nic_write(NIC_PG0_RBCR0, 0);    nic_write(NIC_PG0_RBCR1, 0);    /*     * Temporarily set receiver to monitor mode and transmitter to      * internal loopback mode. Incoming packets will not be stored      * in the nic ring buffer and no data will be send to the network.     */    nic_write(NIC_PG0_RCR, NIC_RCR_MON);    nic_write(NIC_PG0_TCR, NIC_TCR_LB0);    /*     * Configure the nic's ring buffer page layout.     * NIC_PG0_BNRY: Last page read.     * NIC_PG0_PSTART: First page of receiver buffer.     * NIC_PG0_PSTOP: Last page of receiver buffer.     */    nic_write(NIC_PG0_TPSR, NIC_FIRST_TX_PAGE);    nic_write(NIC_PG0_BNRY, NIC_STOP_PAGE - 1);    nic_write(NIC_PG0_PSTART, NIC_FIRST_RX_PAGE);    nic_write(NIC_PG0_PSTOP, NIC_STOP_PAGE);    /*     * Once again clear interrupt status register.     */    nic_write(NIC_PG0_ISR, 0xff);    /*     * Switch to register page 1 and copy our MAC address into the nic.      * We are still in stop mode.     */    nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0);    for (i = 0; i < 6; i++)        nic_write(NIC_PG1_PAR0 + i, mac[i]);    /*     * Clear multicast filter bits to disable all packets.     */    for (i = 0; i < 8; i++)        nic_write(NIC_PG1_MAR0 + i, 0);    /*     * Set current page pointer to one page after the boundary pointer.     */    nic_write(NIC_PG1_CURR, NIC_START_PAGE + TX_PAGES);    /*     * Switch back to register page 0, remaining in stop mode.     */    nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2);    /*     * Take receiver out of monitor mode and enable it for accepting      * broadcasts.     */    nic_write(NIC_PG0_RCR, NIC_RCR_AB);    /*     * Clear all interrupt status flags and enable interrupts.     */    nic_write(NIC_PG0_ISR, 0xff);    nic_write(NIC_PG0_IMR, NIC_IMR_PRXE | NIC_IMR_PTXE | NIC_IMR_RXEE | NIC_IMR_TXEE | NIC_IMR_OVWE);    /*     * Fire up the nic by clearing the stop bit and setting the start bit.      * To activate the local receive dma we must also take the nic out of     * the local loopback mode.     */    nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2);    nic_write(NIC_PG0_TCR, 0);    NutDelay(255);    return 0;}/*! * Complete remote DMA. */static void NicCompleteDma(volatile u_char * base){    u_char i;    /*     * Complete remote dma.     */    nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2);    /*     * Check that we have a DMA complete flag.     */    for (i = 0; i <= 20; i++)        if (nic_read(NIC_PG0_ISR) & NIC_ISR_RDC)            break;    /*     * Reset remote dma complete flag.     */    nic_write(NIC_PG0_ISR, NIC_ISR_RDC);}/*! * \brief Load a packet into the nic's transmit ring buffer. * * Interupts must have been disabled when calling this function. * * \param base NIC hardware base address. * \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. */static int NicPutPacket(volatile u_char * base, NETBUF * nb){    u_short sz;    u_short i;    u_short *p;    u_char padding = 0;    /*     * Calculate the number of bytes to be send. Do not     * send packets larger than 1518 bytes.     */    sz = nb->nb_dl.sz + nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz;    if (sz > 1518)        return -1;    /*     * The controller will not append pad bytes,     * so we have to do this.     */    if (sz < 60) {        padding = (u_char) (60 - sz);        sz = 60;    }    /*     * Set remote dma byte count     * and start address.     */    nic_write(NIC_PG0_RBCR0, sz);    nic_write(NIC_PG0_RBCR1, sz >> 8);    nic_write(NIC_PG0_RSAR0, 0);    nic_write(NIC_PG0_RSAR1, NIC_FIRST_TX_PAGE);    /*     * Peform the write.     */    nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD1);    /*     * Switch MCU data bus to 16-bit mode     */    NicMcu16bitBus();    /*     * Transfer the Ethernet frame.     */    p = nb->nb_dl.vp;    for (i = nb->nb_dl.sz >> 1; i; i--)        nic_write_dma(*p++);    p = nb->nb_nw.vp;    for (i = nb->nb_nw.sz >> 1; i; i--)        nic_write_dma(*p++);    p = nb->nb_tp.vp;    for (i = nb->nb_tp.sz >> 1; i; i--)        nic_write_dma(*p++);    p = nb->nb_ap.vp;    for (i = (nb->nb_ap.sz + 1) >> 1; i; i--)        nic_write_dma(*p++);    /*     * Add pad bytes.     */    if ((nb->nb_ap.sz & 0x0001) != 0)        padding--;    for (i = 0; i < (padding + 1) >> 1; i++)        nic_write_dma(0);    /*     * Switch MCU data bus to 8-bit mode     */    NicMcu8bitBus();    /*     * Complete remote dma.     */    NicCompleteDma(base);    /*     * Number of bytes to be transmitted.     */    nic_write(NIC_PG0_TBCR0, (sz & 0xff));    nic_write(NIC_PG0_TBCR1, ((sz >> 8) & 0xff));    /*     * First page of packet to be transmitted.     */    nic_write(NIC_PG0_TPSR, NIC_FIRST_TX_PAGE);    /*     * Start transmission.     */    nic_write(NIC_CR, NIC_CR_STA | NIC_CR_TXP | NIC_CR_RD2);    return 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(volatile u_char * base, u_char dflg){    NETBUF *nb = 0;    struct nic_pkt_header hdr;    u_short count;    u_char nextpg;    u_char bnry;    u_char curr;    u_short i;    u_short *buf;    /*     * Get the current page pointer. It points to the page where the NIC      * will start saving the next incoming packet.     */    nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2 | NIC_CR_PS0);    curr = nic_read(NIC_PG1_CURR);    nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2);    /*     * Get the pointer to the last page we read from. The following page     * is the one where we start reading. If it's equal to the current     * page pointer, then there's nothing to read. In this case we return

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -