| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483 |
- /*
- * Copyright (C) 2001-2004 by egnite Software GmbH
- * Copyright (C) 2010 by egnite 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 THE COPYRIGHT HOLDERS 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 THE
- * COPYRIGHT OWNER 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/
- *
- * -
- * Portions Copyright (c) 1993 by Digital Equipment Corporation.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies, and that
- * the name of Digital Equipment Corporation not be used in advertising or
- * publicity pertaining to distribution of the document or software without
- * specific, written prior permission.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
- * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
- * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- * SOFTWARE.
- */
- /*
- * $Id: ether.c 4115 2012-04-12 21:06:13Z olereinhardt $
- */
- #include <string.h>
- #include <avr/io.h>
- #include "config.h"
- #include "rtlregs.h"
- #include "util.h"
- #include "eboot.h"
- #include "arp.h"
- #include "ether.h"
- /*!
- * \addtogroup xgStack
- */
- /*@{*/
- #define NIC_PAGE_SIZE 0x100
- #define NIC_START_PAGE 0x40
- #define NIC_STOP_PAGE 0x60
- #define NIC_TX_PAGES 6
- #define NIC_TX_BUFFERS 2
- #define NIC_FIRST_TX_PAGE NIC_START_PAGE
- #define NIC_FIRST_RX_PAGE (NIC_FIRST_TX_PAGE + NIC_TX_PAGES * NIC_TX_BUFFERS)
- #define TX_PAGES 12
- unsigned char EEPROM_read(unsigned int uiAddress)
- {
- /* Wait for completion of previous write */
- #if defined(__AVR_ATmega2561__)
- while(EECR & (1<<EEPE));
- #else
- while(EECR & (1<<EEWE));
- #endif
- /* Set up address register */
- EEAR = uiAddress;
- /* Start eeprom read by writing EERE */
- EECR |= (1<<EERE);
- /* Return data from data register */
- return EEDR;
- }
- /*!
- * 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 */
- };
- static void EmulateNicEeprom(void)
- {
- register u_int cnt;
- /*
- * Prepare the EEPROM emulation port bits. Configure the EEDO
- * and the EEMU lines as outputs and set both lines to high.
- */
- PORTC = 0xC0;
- DDRC = 0xC0;
- Delay(20);
- /*
- * Force the chip to re-read the EEPROM contents.
- */
- NIC_CR = NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0 | NIC_CR_PS1;
- NIC_PG3_EECR = NIC_EECR_EEM0;
- /*
- * No external memory access beyond this point.
- */
- #if defined(__AVR_ATmega2561__) || defined(__AVR_AT90CAN128__)
- XMCRA &= ~_BV(SRE);
- #else
- MCUCR &= ~_BV(SRE);
- #endif
- /*
- * Loop until the chip stops toggling our EESK input.
- */
- do {
- cnt = 0;
- if(bit_is_set(PINC, 5)) {
- while(++cnt && bit_is_set(PINC, 5));
- }
- else {
- while(++cnt && bit_is_clear(PINC, 5));
- }
- } while(cnt);
- /*
- * Enable memory interface.
- */
- #if defined(__AVR_ATmega2561__) || defined(__AVR_AT90CAN128__)
- XMCRA |= _BV(SRE);
- #else
- MCUCR |= _BV(SRE);
- #endif
- /* Reset port outputs to default. */
- PORTC = 0x00;
- DDRC = 0x00;
- /* Wait until controller ready. */
- while(NIC_CR != (NIC_CR_STP | NIC_CR_RD2));
- }
- /*!
- * \brief Initialize the NIC.
- *
- * For further description of the initialization
- * please refer to the original Ethernut code.
- */
- int NicInit(void)
- {
- u_char c;
- /*
- * Enable external data and address
- * bus.
- */
- #if defined(__AVR_ATmega2561__) || defined(__AVR_AT90CAN128__)
- XMCRA = (_BV(SRE) | _BV(SRW10));
- #else
- MCUCR = (_BV(SRE) | _BV(SRW));
- #endif
- c = NIC_RESET;
- Delay(5);
- NIC_RESET = c;
- Delay(1000);
- EmulateNicEeprom();
- NIC_PG0_IMR = 0;
- NIC_PG0_ISR = 0xff;
- NIC_CR = NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0 | NIC_CR_PS1;
- NIC_PG3_EECR = NIC_EECR_EEM0 | NIC_EECR_EEM1;
- NIC_PG3_CONFIG3 = 0;
- NIC_PG3_CONFIG2 = NIC_CONFIG2_BSELB;
- NIC_PG3_EECR = 0;
- Delay(200);
- NIC_CR = NIC_CR_STP | NIC_CR_RD2;
- NIC_PG0_DCR = NIC_DCR_LS | NIC_DCR_FT1;
- NIC_PG0_RBCR0 = 0;
- NIC_PG0_RBCR1 = 0;
- NIC_PG0_RCR = NIC_RCR_MON;
- NIC_PG0_TCR = NIC_TCR_LB0;
- NIC_PG0_TPSR = NIC_FIRST_TX_PAGE;
- NIC_PG0_BNRY = NIC_STOP_PAGE - 1;
- NIC_PG0_PSTART = NIC_FIRST_RX_PAGE;
- NIC_PG0_PSTOP = NIC_STOP_PAGE;
- NIC_PG0_ISR = 0xff;
- NIC_CR = NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0;
- NIC_PG1_PAR0 = confnet.cdn_mac[0];
- NIC_PG1_PAR1 = confnet.cdn_mac[1];
- NIC_PG1_PAR2 = confnet.cdn_mac[2];
- NIC_PG1_PAR3 = confnet.cdn_mac[3];
- NIC_PG1_PAR4 = confnet.cdn_mac[4];
- NIC_PG1_PAR5 = confnet.cdn_mac[5];
- NIC_PG1_MAR0 = 0;
- NIC_PG1_MAR1 = 0;
- NIC_PG1_MAR2 = 0;
- NIC_PG1_MAR3 = 0;
- NIC_PG1_MAR4 = 0;
- NIC_PG1_MAR5 = 0;
- NIC_PG1_MAR6 = 0;
- NIC_PG1_MAR7 = 0;
- NIC_PG1_CURR = NIC_START_PAGE + TX_PAGES;
- NIC_CR = NIC_CR_STP | NIC_CR_RD2;
- NIC_PG0_RCR = NIC_RCR_AB;
- NIC_PG0_ISR = 0xff;
- NIC_PG0_IMR = 0;
- NIC_CR = NIC_CR_STA | NIC_CR_RD2;
- NIC_PG0_TCR = 0;
- Delay(1000);
- return 0;
- }
- /*!
- * \brief Send an Ethernet frame.
- *
- * \param dmac Destination MAC address.
- * \param type Frame type.
- * \param len Frame size.
- *
- * \return 0 on success, -1 otherwise.
- */
- int EtherOutput(u_char * dmac, u_short type, u_short len)
- {
- u_short i;
- u_short sz;
- u_char *cp;
- ETHERHDR *eh;
- if (type == ETHERTYPE_ARP) {
- eh = &arpframe.eth_hdr;
- cp = (u_char *) & arpframe;
- } else {
- eh = &sframe.eth_hdr;
- cp = (u_char *) & sframe;
- }
- for (i = 0; i < 6; i++)
- eh->ether_shost[i] = confnet.cdn_mac[i];
- if (dmac) {
- for (i = 0; i < 6; i++)
- eh->ether_dhost[i] = dmac[i];
- } else {
- for (i = 0; i < 6; i++)
- eh->ether_dhost[i] = 0xFF;
- }
- eh->ether_type = type;
- if ((len += sizeof(ETHERHDR)) < 60)
- sz = 60;
- else
- sz = len;
- NIC_CR = NIC_CR_STA | NIC_CR_RD2;
- NIC_PG0_RBCR0 = (u_char) sz;
- NIC_PG0_RBCR1 = (u_char) (sz >> 8);
- NIC_PG0_RSAR0 = 0;
- NIC_PG0_RSAR1 = NIC_FIRST_TX_PAGE;
- NIC_CR = NIC_CR_STA | NIC_CR_RD1;
- /*
- * Transfer frame.
- */
- for (i = 0; i < len; i++)
- NIC_IOPORT = *cp++;
- for (i = len; i < sz; i++)
- NIC_IOPORT = 0;
- /*
- * Complete remote dma.
- */
- NIC_CR = NIC_CR_STA | NIC_CR_RD2;
- for (i = 0; i <= 20; i++)
- if (NIC_PG0_ISR & NIC_ISR_RDC)
- break;
- NIC_PG0_ISR = NIC_ISR_RDC;
- /*
- * Number of bytes to be transmitted.
- */
- NIC_PG0_TBCR0 = (sz & 0xff);
- NIC_PG0_TBCR1 = ((sz >> 8) & 0xff);
- /*
- * First page of packet to be transmitted.
- */
- NIC_PG0_TPSR = NIC_FIRST_TX_PAGE;
- /*
- * Start transmission.
- */
- NIC_CR = NIC_CR_STA | NIC_CR_TXP | NIC_CR_RD2;
- /*
- * Wait until transmission is completed or aborted.
- */
- while (NIC_CR & NIC_CR_TXP);
- return 0;
- }
- /*!
- * \brief Receive an Ethernet frame.
- *
- * \param tms Return with timeout after the specified
- * number of waiting loops. On a 14 Mhz ATmega
- * this value represents approximately the number
- * of milliseconds to wait.
- *
- * \return The number of bytes received, 0 on timeout
- * or -1 in case of a failure.
- */
- int EtherInput(u_short type, u_short tms)
- {
- int rc = 0;
- u_short maxl = 0;
- u_char isr = 0;
- struct nic_pkt_header hdr;
- u_char *buf;
- u_char bnry;
- u_char curr;
- u_short i;
- u_char wtc;
- while (tms && rc == 0) {
- /*
- * Wait until frame received, timeout or receiver error.
- */
- for (wtc = 1; tms; wtc++) {
- isr = NIC_PG0_ISR;
- if (isr & NIC_ISR_RXE) {
- return -1;
- }
- if (isr & NIC_ISR_PRX) {
- break;
- }
- if (wtc == 0)
- tms--;
- }
- if ((isr & NIC_ISR_PRX) == 0) {
- NIC_PG0_ISR = isr;
- break;
- }
- /*
- * Get the current page pointer. It points to the page where the NIC
- * will start saving the next incoming packet.
- */
- NIC_CR = NIC_CR_STA | NIC_CR_RD2 | NIC_CR_PS0;
- curr = NIC_PG1_CURR;
- 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.
- */
- if ((bnry = NIC_PG0_BNRY + 1) >= NIC_STOP_PAGE)
- bnry = NIC_FIRST_RX_PAGE;
- if (bnry == curr) {
- NIC_PG0_ISR = isr;
- continue;
- }
- /*
- * Read the NIC specific packet header.
- */
- NIC_PG0_RBCR0 = sizeof(struct nic_pkt_header);
- NIC_PG0_RBCR1 = 0;
- NIC_PG0_RSAR0 = 0;
- NIC_PG0_RSAR1 = bnry;
- buf = (u_char *) & hdr;
- NIC_CR = NIC_CR_STA | NIC_CR_RD0;
- for (i = 0; i < sizeof(struct nic_pkt_header); i++)
- *buf++ = NIC_IOPORT;
- /*
- * Complete remote dma.
- */
- NIC_CR = NIC_CR_STA | NIC_CR_RD2;
- for (i = 0; i <= 20; i++) {
- if (NIC_PG0_ISR & NIC_ISR_RDC)
- break;
- }
- NIC_PG0_ISR = NIC_ISR_RDC;
- /*
- * Check frame length. If it's outside limits, we assume
- * that the NIC is corrupted. Reset and retry.
- */
- if (hdr.ph_size < 60 + sizeof(struct nic_pkt_header) || hdr.ph_size > 1518 + sizeof(struct nic_pkt_header)) {
- NicInit();
- continue;
- }
- /*
- * Check packet status.
- */
- if ((hdr.ph_status & 0x0F) == 1) {
- rc = hdr.ph_size - sizeof(struct nic_pkt_header);
- /*
- * Set remote dma byte count and
- * start address. Don't read the
- * header again.
- */
- NIC_PG0_RBCR0 = (u_char) rc;
- NIC_PG0_RBCR1 = (u_char) ((u_short) rc >> 8);
- NIC_PG0_RSAR0 = sizeof(struct nic_pkt_header);
- NIC_PG0_RSAR1 = bnry;
- /*
- * Perform the read.
- */
- NIC_CR = NIC_CR_STA | NIC_CR_RD0;
- buf = (u_char *) & rframe;
- maxl = sizeof(rframe) < (u_short)rc ? sizeof(rframe) : (u_short)rc;
- for (i = 0; i < maxl; i++) {
- *buf++ = NIC_IOPORT;
- }
- for (; i < (u_short) rc; i++)
- NIC_IOPORT;
- /*
- * Complete remote dma.
- */
- NIC_CR = NIC_CR_STA | NIC_CR_RD2;
- for (i = 0; i <= 20; i++) {
- if (NIC_PG0_ISR & NIC_ISR_RDC)
- break;
- }
- NIC_PG0_ISR = NIC_ISR_RDC;
- }
- /*
- * Set boundary register to the last page we read.
- */
- if (--hdr.ph_nextpg < NIC_FIRST_RX_PAGE)
- hdr.ph_nextpg = NIC_STOP_PAGE - 1;
- NIC_PG0_BNRY = hdr.ph_nextpg;
- /*
- * Handle incoming ARP requests.
- */
- if (rframe.eth_hdr.ether_type != type) {
- if (rframe.eth_hdr.ether_type == ETHERTYPE_ARP)
- ArpRespond();
- rc = 0;
- }
- }
- return rc;
- }
- /*@}*/
|