/* * 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 #include #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<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; } /*@}*/