Main Page   Modules   Alphabetical List   Data Structures   File List   Data Fields   Related Pages  

C:/proj/src/ethernut/nut/eboot/ether.c

00001 /*
00002  * Copyright (C) 2001-2002 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. All advertising materials mentioning features or use of this
00014  *    software must display the following acknowledgement:
00015  *
00016  *    This product includes software developed by egnite Software GmbH
00017  *    and its contributors.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00020  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00021  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00022  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00023  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00024  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00025  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00026  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00027  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00028  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00029  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00030  * SUCH DAMAGE.
00031  *
00032  * For additional information see http://www.ethernut.de/
00033  *
00034  * -
00035  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
00036  *
00037  * Permission to use, copy, modify, and distribute this software for any
00038  * purpose with or without fee is hereby granted, provided that the above
00039  * copyright notice and this permission notice appear in all copies, and that
00040  * the name of Digital Equipment Corporation not be used in advertising or
00041  * publicity pertaining to distribution of the document or software without
00042  * specific, written prior permission.
00043  * 
00044  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
00045  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
00046  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
00047  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
00048  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
00049  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
00050  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00051  * SOFTWARE.
00052  */
00053 
00054 /*
00055  * $Log: ether.c,v $
00056  * Revision 1.1  2002/08/01 17:34:30  harald
00057  * First check in
00058  *
00059  */
00060 
00061 #include <string.h>
00062 #include <io.h>
00063 
00064 #include "rtlregs.h"
00065 #include "util.h"
00066 #include "eboot.h"
00067 #include "arp.h"
00068 #include "ether.h"
00069 
00070 /*!
00071  * \addtogroup xgStack
00072  */
00073 /*@{*/
00074 
00075 #define NIC_PAGE_SIZE       0x100
00076 #define NIC_START_PAGE      0x40
00077 #define NIC_STOP_PAGE       0x60
00078 #define NIC_TX_PAGES        6
00079 #define NIC_TX_BUFFERS      2
00080 #define NIC_FIRST_TX_PAGE   NIC_START_PAGE
00081 #define NIC_FIRST_RX_PAGE   (NIC_FIRST_TX_PAGE + NIC_TX_PAGES * NIC_TX_BUFFERS)
00082 #define TX_PAGES            12
00083 
00084 u_char mac[6] = { 0x00,0x06,0x98,0x00,0x00,0x00 };
00085 
00086 volatile u_char *base = (u_char *)0x8300;
00087 
00088 /*!
00089  * Realtek packet header.
00090  */
00091 struct nic_pkt_header {
00092     u_char ph_status;     /*!< \brief Status, contents of RSR register */
00093     u_char ph_nextpg;     /*!< \brief Page for next packet */
00094     u_short ph_size;      /*!< \brief Size of header and packet in octets */
00095 };
00096 
00097 /*!
00098  * \brief Reset the NIC.
00099  *
00100  * \return 0 on success, -1 otherwise.
00101  */
00102 static int NicReset(void)
00103 {
00104     u_char i;
00105     u_char j;
00106 
00107     for(j = 0; j < 20; j++) {
00108         i = nic_read(NIC_RESET);
00109         Delay(500);
00110         nic_write(NIC_RESET, i);
00111         for(i = 0; i < 20; i++) {
00112             Delay(5000);
00113             if(nic_read(NIC_PG0_ISR) & NIC_ISR_RST)
00114                 return 0;
00115         }
00116     }
00117     return -1;
00118 }
00119 
00120 /*!
00121  * \brief Initialize the NIC.
00122  *
00123  * For further description of the initialization
00124  * please refer to the original Ethernut code.
00125  */
00126 void NicInit(void)
00127 {
00128     u_short i;
00129 
00130     /*
00131      * Enable external data and address
00132      * bus.
00133      */
00134     outp(BV(SRE) | BV(SRW), MCUCR);
00135 
00136 
00137     if(NicReset())
00138         return;
00139 
00140     nic_write(NIC_PG0_IMR, 0);
00141     nic_write(NIC_PG0_ISR, 0xff);
00142     nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0 | NIC_CR_PS1);
00143     nic_write(NIC_PG3_EECR, NIC_EECR_EEM0 | NIC_EECR_EEM1);
00144     nic_write(NIC_PG3_CONFIG3, 0);
00145     nic_write(NIC_PG3_CONFIG2, NIC_CONFIG2_BSELB);
00146     nic_write(NIC_PG3_EECR, 0);
00147     Delay(50000);
00148     nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2);
00149     nic_write(NIC_PG0_DCR, NIC_DCR_LS | NIC_DCR_FT1);
00150     nic_write(NIC_PG0_RBCR0, 0);
00151     nic_write(NIC_PG0_RBCR1, 0);
00152     nic_write(NIC_PG0_RCR, NIC_RCR_MON);
00153     nic_write(NIC_PG0_TCR, NIC_TCR_LB0);
00154     nic_write(NIC_PG0_TPSR, NIC_FIRST_TX_PAGE);
00155     nic_write(NIC_PG0_BNRY, NIC_STOP_PAGE - 1);
00156     nic_write(NIC_PG0_PSTART, NIC_FIRST_RX_PAGE);
00157     nic_write(NIC_PG0_PSTOP, NIC_STOP_PAGE);
00158     nic_write(NIC_PG0_ISR, 0xff);
00159     nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0);
00160     for(i = 0; i < 6; i++)
00161         nic_write(NIC_PG1_PAR0 + i, mac[i]);
00162     for(i = 0; i < 8; i++)
00163         nic_write(NIC_PG1_MAR0 + i, 0);
00164     nic_write(NIC_PG1_CURR, NIC_START_PAGE + TX_PAGES);
00165     nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2);
00166     nic_write(NIC_PG0_RCR, NIC_RCR_AB);
00167     nic_write(NIC_PG0_ISR, 0xff);
00168     nic_write(NIC_PG0_IMR, 0);
00169     nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2);
00170     nic_write(NIC_PG0_TCR, 0);
00171     Delay(2000000);
00172 }
00173 
00174 /*!
00175  * \brief Send an Ethernet frame.
00176  *
00177  * \param dmac Destination MAC address.
00178  * \param type Frame type.
00179  * \param len  Frame size.
00180  *
00181  * \return 0 on success, -1 otherwise.
00182  */
00183 int EtherOutput(u_char *dmac, u_short type, u_short len)
00184 {
00185     u_short i;
00186     u_short sz;
00187     u_char *cp;
00188     ETHERHDR *eh;
00189 #if 0
00190     u_char isr;
00191 #endif
00192 
00193     if(type == ETHERTYPE_ARP) {
00194         eh = &arpframe.eth_hdr;
00195         cp = (u_char *)&arpframe;
00196     }
00197     else {
00198         eh = &sframe.eth_hdr;
00199         cp = (u_char *)&sframe;
00200     }
00201 
00202     for(i = 0; i < 6; i++)
00203         eh->ether_shost[i] = mac[i];
00204     if(dmac) {
00205         for(i = 0; i < 6; i++)
00206             eh->ether_dhost[i] = dmac[i];
00207     }
00208     else {
00209         for(i = 0; i < 6; i++)
00210             eh->ether_dhost[i] = 0xFF;
00211     }
00212     eh->ether_type = type;
00213     if((len += sizeof(ETHERHDR)) < 60)
00214         sz = 60;
00215     else
00216         sz = len;
00217 
00218     nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2);  
00219     nic_write(NIC_PG0_RBCR0, (u_char)sz);
00220     nic_write(NIC_PG0_RBCR1, (u_char)(sz >> 8));
00221     nic_write(NIC_PG0_RSAR0, 0);
00222     nic_write(NIC_PG0_RSAR1, NIC_FIRST_TX_PAGE);
00223     
00224     nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD1);
00225     
00226     /*
00227      * Transfer frame.
00228      */
00229     for(i = 0; i < len; i++, cp++)
00230         nic_write(NIC_IOPORT, *cp);
00231     for(i = len; i < sz; i++)
00232         nic_write(NIC_IOPORT, 0);
00233     
00234     /*
00235      * Complete remote dma.
00236      */
00237     nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2);
00238     for(i = 0; i <= 20; i++)
00239         if(nic_read(NIC_PG0_ISR) & NIC_ISR_RDC)
00240             break;
00241     nic_write(NIC_PG0_ISR, NIC_ISR_RDC);
00242         
00243     /*
00244      * Number of bytes to be transmitted.
00245      */
00246     nic_write(NIC_PG0_TBCR0, (sz & 0xff));
00247     nic_write(NIC_PG0_TBCR1, ((sz >> 8) & 0xff));
00248         
00249     /*
00250      * First page of packet to be transmitted.
00251      */
00252     nic_write(NIC_PG0_TPSR, NIC_FIRST_TX_PAGE);
00253         
00254     /*
00255      * Start transmission.
00256      */
00257     nic_write(NIC_CR, NIC_CR_STA | NIC_CR_TXP | NIC_CR_RD2);
00258 
00259     /*
00260      * Wait until transmission is completed or aborted.
00261      */
00262 
00263     while(nic_read(NIC_CR) & NIC_CR_TXP);
00264 
00265     return 0;
00266 }
00267 
00268 /*!
00269  * \brief Receive an Ethernet frame.
00270  *
00271  * \param tms  Return with timeout after the specified
00272  *             number of waiting loops. On a 14 Mhz ATmega
00273  *             this value represents approximately the number
00274  *             of milliseconds to wait.
00275  *
00276  * \return The number of bytes received, 0 on timeout 
00277  *         or -1 in case of a failure.
00278  */
00279 int EtherInput(u_short type, u_short tms)
00280 {
00281     int rc = 0;
00282     u_char isr = 0;
00283     struct nic_pkt_header hdr;
00284     u_char *buf;
00285     u_char nextpg;
00286     u_char bnry;
00287     u_char curr;
00288     u_short i;
00289     u_char wtc;
00290     
00291     while(tms && rc == 0) {
00292         for(wtc = 1; tms; wtc++) {
00293             isr = nic_read(NIC_PG0_ISR);
00294             if(isr & NIC_ISR_RXE) {
00295                 return -1;
00296             }
00297             if(isr & NIC_ISR_PRX) {
00298                 break;
00299             }
00300             if(wtc == 0)
00301                 tms--;
00302         }
00303         
00304         /*
00305          * Any frame received?
00306          */
00307         if((isr & NIC_ISR_PRX) == 0) {
00308             nic_write(NIC_PG0_ISR, isr);
00309             break;
00310         }
00311         
00312         /*
00313          * Get the current page pointer. It points to the page where the NIC 
00314          * will start saving the next incoming packet.
00315          */
00316         nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2 | NIC_CR_PS0);
00317         curr = nic_read(NIC_PG1_CURR);
00318         nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2);
00319         
00320         /*
00321          * Get the pointer to the last page we read from. The following page
00322          * is the one where we start reading. If it's equal to the current
00323          * page pointer, then there's nothing to read. In this case we return
00324          * a null pointer.
00325          */
00326         if((bnry = nic_read(NIC_PG0_BNRY) + 1) >= NIC_STOP_PAGE)
00327             bnry = NIC_FIRST_RX_PAGE;
00328         if(bnry == curr) {
00329             nic_write(NIC_PG0_ISR, isr);
00330             continue;
00331         }
00332         
00333         /*
00334          * Read the NIC specific packet header.
00335          */
00336         nic_write(NIC_PG0_RBCR0, sizeof(struct nic_pkt_header));
00337         nic_write(NIC_PG0_RBCR1, 0);
00338         nic_write(NIC_PG0_RSAR0, 0);
00339         nic_write(NIC_PG0_RSAR1, bnry);
00340         buf = (u_char *)&hdr;
00341         nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD0);
00342         for(i = 0; i < sizeof(struct nic_pkt_header); i++)
00343             *buf++ = nic_read(NIC_IOPORT);
00344         
00345         /*
00346          * Complete remote dma.
00347          */
00348         nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2);
00349         for(i = 0; i <= 20; i++) {
00350             if(nic_read(NIC_PG0_ISR) & NIC_ISR_RDC)
00351                 break;
00352         }
00353         nic_write(NIC_PG0_ISR, NIC_ISR_RDC);
00354         
00355         /*
00356          *  Check packet length.
00357          */
00358         if(hdr.ph_size < 60 + sizeof(struct nic_pkt_header) ||
00359             hdr.ph_size > 1518 + sizeof(struct nic_pkt_header)) {
00360             return 0;
00361         }
00362         
00363         /*
00364          * Calculate the page of the next packet. If it differs from the
00365          * pointer in the packet header, we discard the whole buffer
00366          * and return a null pointer.
00367          */
00368         nextpg = bnry + (hdr.ph_size >> 8) + ((hdr.ph_size & 0xFF) != 0);
00369         if(nextpg >= NIC_STOP_PAGE) {
00370             nextpg -= NIC_STOP_PAGE;
00371             nextpg += NIC_FIRST_RX_PAGE;
00372         }
00373         if(nextpg != hdr.ph_nextpg) {
00374             u_char nextpg1 = nextpg + 1;
00375             
00376             if(nextpg1 >= NIC_STOP_PAGE) {
00377                 nextpg1 -= NIC_STOP_PAGE;
00378                 nextpg1 += NIC_FIRST_RX_PAGE;
00379             }
00380             if(nextpg1 != hdr.ph_nextpg) {
00381                 nic_write(NIC_PG0_ISR, isr);
00382                 break;
00383             }
00384             nextpg = nextpg1;
00385         }
00386         
00387         /*
00388          * Check packet status.
00389          */
00390         if((hdr.ph_status & 0x0F) == 1) {
00391             rc = hdr.ph_size - sizeof(struct nic_pkt_header);
00392             
00393             /*
00394              * Set remote dma byte count and
00395              * start address. Don't read the
00396              * header again.
00397              */
00398             nic_write(NIC_PG0_RBCR0, (u_char)rc);
00399             nic_write(NIC_PG0_RBCR1, (u_char)((u_short)rc >> 8));
00400             nic_write(NIC_PG0_RSAR0, sizeof(struct nic_pkt_header));
00401             nic_write(NIC_PG0_RSAR1, bnry);
00402             
00403             /*
00404             * Perform the read.
00405             */
00406             nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD0);
00407             buf = (u_char *)&rframe;
00408             for(i = 0; i < rc; i++)
00409                 *buf++ = nic_read(NIC_IOPORT);
00410             
00411             /*
00412              * Complete remote dma.
00413              */
00414             nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2);
00415             for(i = 0; i <= 20; i++) {
00416                 if(nic_read(NIC_PG0_ISR) & NIC_ISR_RDC)
00417                     break;
00418             }
00419             nic_write(NIC_PG0_ISR, NIC_ISR_RDC);
00420         }
00421         
00422         /*
00423          * Set boundary register to the last page we read.
00424          */
00425         if(--nextpg < NIC_FIRST_RX_PAGE)
00426             nextpg = NIC_STOP_PAGE - 1;
00427         nic_write(NIC_PG0_BNRY, nextpg);        
00428         
00429         /*
00430          * Handle incoming ARP requests.
00431          */
00432         if(rframe.eth_hdr.ether_type != type) {
00433             if(rframe.eth_hdr.ether_type == ETHERTYPE_ARP)
00434                 ArpRespond();
00435             rc = 0;
00436         }
00437     }
00438     return rc;
00439 }
00440 
00441 /*@}*/

© 2002 by egnite Software GmbH - visit http://www.ethernut.de/