📄 if_ne.c
字号:
/*- * Copyright (c) 1990, 1991 William F. Jolitz. * Copyright (c) 1990, 1993 * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. * * @(#)if_ne.c 8.1 (Berkeley) 6/11/93 *//* * NE2000 Ethernet driver * * Parts inspired from Tim Tucker's if_wd driver for the wd8003, * insight on the ne2000 gained from Robert Clements PC/FTP driver. */#include "ne.h"#if NNE > 0#include <sys/param.h>#include <sys/systm.h>#include <sys/mbuf.h>#include <sys/buf.h>#include <sys/protosw.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <sys/errno.h>#include <sys/syslog.h>#include <net/if.h>#include <net/netisr.h>#include <net/route.h>#ifdef INET#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/in_var.h>#include <netinet/ip.h>#include <netinet/if_ether.h>#endif#ifdef NS#include <netns/ns.h>#include <netns/ns_if.h>#endif#include <i386/isa/isa_device.h>#include <i386/isa/if_nereg.h>#include <i386/isa/icu.h>int neprobe(), neattach(), neintr();int nestart(),neinit(), ether_output(), neioctl();struct isa_driver nedriver = { neprobe, neattach, "ne",};struct mbuf *neget();#define ETHER_MIN_LEN 64#define ETHER_MAX_LEN 1536/* * Ethernet software status per interface. * * Each interface is referenced by a network interface structure, * ns_if, which the routing code uses to locate the interface. * This structure contains the output queue for the interface, its address, ... */struct ne_softc { struct arpcom ns_ac; /* Ethernet common part */#define ns_if ns_ac.ac_if /* network-visible interface */#define ns_addr ns_ac.ac_enaddr /* hardware Ethernet address */ int ns_flags;#define DSF_LOCK 1 /* block re-entering enstart */ int ns_oactive ; int ns_mask ; int ns_ba; /* byte addr in buffer ram of inc pkt */ int ns_cur; /* current page being filled */ struct prhdr ns_ph; /* hardware header of incoming packet*/ struct ether_header ns_eh; /* header of incoming packet */ u_char ns_pb[2048 /*ETHERMTU+sizeof(long)*/];} ne_softc[NNE] ;#define ENBUFSIZE (sizeof(struct ether_header) + ETHERMTU + 2 + ETHER_MIN_LEN)int nec;u_short boarddata[16]; neprobe(dvp) struct isa_device *dvp;{ int val,i,s; register struct ne_softc *ns = &ne_softc[0];#ifdef lint neintr(0);#endif nec = dvp->id_iobase; s = splimp(); /* Reset the bastard */ val = inb(nec+ne_reset); DELAY(2000000); outb(nec+ne_reset,val); outb(nec+ds_cmd, DSCM_STOP|DSCM_NODMA); i = 1000000; while ((inb(nec+ds0_isr)&DSIS_RESET) == 0 && i-- > 0); if (i < 0) return (0); outb(nec+ds0_isr, 0xff); /* Word Transfers, Burst Mode Select, Fifo at 8 bytes */ outb(nec+ds0_dcr, DSDC_WTS|DSDC_BMS|DSDC_FT1); outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP); DELAY(10000); /* Check cmd reg and fail if not right */ if ((i=inb(nec+ds_cmd)) != (DSCM_NODMA|DSCM_PG0|DSCM_STOP)) return(0); outb(nec+ds0_tcr, 0); outb(nec+ds0_rcr, DSRC_MON); outb(nec+ds0_pstart, RBUF/DS_PGSIZE); outb(nec+ds0_pstop, RBUFEND/DS_PGSIZE); outb(nec+ds0_bnry, RBUFEND/DS_PGSIZE); outb(nec+ds0_imr, 0); outb(nec+ds0_isr, 0); outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP); outb(nec+ds1_curr, RBUF/DS_PGSIZE); outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);#ifdef NEDEBUG#define PAT(n) (0xa55a + 37*(n))#define RCON 37 { int i, rom, pat; rom=1; printf("ne ram "); for (i = 0; i < 0xfff0; i+=4) { pat = PAT(i); neput(&pat,i,4); nefetch(&pat,i,4); if (pat == PAT(i)) { if (rom) { rom=0; printf(" %x", i); } } else { if (!rom) { rom=1; printf("..%x ", i); } } pat=0; neput(&pat,i,4); } printf("\n"); }#endif /* Extract board address */ nefetch ((caddr_t)boarddata, 0, sizeof(boarddata)); for(i=0; i < 6; i++) ns->ns_addr[i] = boarddata[i]; splx(s); return (1);}/* * Fetch from onboard ROM/RAM */nefetch (up, ad, len) caddr_t up; { u_char cmd; cmd = inb(nec+ds_cmd); outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START); /* Setup remote dma */ outb (nec+ds0_isr, DSIS_RDC); outb (nec+ds0_rbcr0, len); outb (nec+ds0_rbcr1, len>>8); outb (nec+ds0_rsar0, ad); outb (nec+ds0_rsar1, ad>>8); /* Execute & extract from card */ outb (nec+ds_cmd, DSCM_RREAD|DSCM_PG0|DSCM_START); insw (nec+ne_data, up, len/2); /* Wait till done, then shutdown feature */ while ((inb (nec+ds0_isr) & DSIS_RDC) == 0) ; outb (nec+ds0_isr, DSIS_RDC); outb (nec+ds_cmd, cmd);}/* * Put to onboard RAM */neput (up, ad, len) caddr_t up; { u_char cmd; cmd = inb(nec+ds_cmd); outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START); /* Setup for remote dma */ outb (nec+ds0_isr, DSIS_RDC); if(len&1) len++; /* roundup to words */ outb (nec+ds0_rbcr0, len); outb (nec+ds0_rbcr1, len>>8); outb (nec+ds0_rsar0, ad); outb (nec+ds0_rsar1, ad>>8); /* Execute & stuff to card */ outb (nec+ds_cmd, DSCM_RWRITE|DSCM_PG0|DSCM_START); outsw (nec+ne_data, up, len/2); /* Wait till done, then shutdown feature */ while ((inb (nec+ds0_isr) & DSIS_RDC) == 0) ; outb (nec+ds0_isr, DSIS_RDC); outb (nec+ds_cmd, cmd);}/* * Reset of interface. */nereset(unit, uban) int unit, uban;{ if (unit >= NNE) return; printf("ne%d: reset\n", unit); ne_softc[unit].ns_flags &= ~DSF_LOCK; neinit(unit);} /* * Interface exists: make available by filling in network interface * record. System will initialize the interface when it is ready * to accept packets. We get the ethernet address here. */neattach(dvp) struct isa_device *dvp;{ int unit = dvp->id_unit; register struct ne_softc *ns = &ne_softc[unit]; register struct ifnet *ifp = &ns->ns_if; ifp->if_unit = unit; ifp->if_name = nedriver.name ; ifp->if_mtu = ETHERMTU; printf (" ethernet address %s", ether_sprintf(ns->ns_addr)) ; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS; ifp->if_init = neinit; ifp->if_output = ether_output; ifp->if_start = nestart; ifp->if_ioctl = neioctl; ifp->if_reset = nereset; ifp->if_watchdog = 0; if_attach(ifp);}/* * Initialization of interface; set up initialization block * and transmit/receive descriptor rings. */neinit(unit) int unit;{ register struct ne_softc *ns = &ne_softc[unit]; struct ifnet *ifp = &ns->ns_if; int s; register i; char *cp; if (ifp->if_addrlist == (struct ifaddr *)0) return; if (ifp->if_flags & IFF_RUNNING) return; s = splimp(); /* set physical address on ethernet */ outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP); for (i=0 ; i < 6 ; i++) outb(nec+ds1_par0+i,ns->ns_addr[i]); /* clr logical address hash filter for now */ for (i=0 ; i < 8 ; i++) outb(nec+ds1_mar0+i,0xff); /* init regs */ outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP); outb (nec+ds0_rbcr0, 0); outb (nec+ds0_rbcr1, 0); outb (nec+ds0_imr, 0); outb (nec+ds0_isr, 0xff); /* Word Transfers, Burst Mode Select, Fifo at 8 bytes */ outb(nec+ds0_dcr, DSDC_WTS|DSDC_BMS|DSDC_FT1); outb(nec+ds0_tcr, 0); outb (nec+ds0_rcr, DSRC_MON); outb (nec+ds0_tpsr, 0); outb(nec+ds0_pstart, RBUF/DS_PGSIZE); outb(nec+ds0_pstop, RBUFEND/DS_PGSIZE); outb(nec+ds0_bnry, RBUF/DS_PGSIZE); outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP); outb(nec+ds1_curr, RBUF/DS_PGSIZE); ns->ns_cur = RBUF/DS_PGSIZE; outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START); outb (nec+ds0_rcr, DSRC_AB); outb(nec+ds0_dcr, DSDC_WTS|DSDC_BMS|DSDC_FT1); outb (nec+ds0_imr, 0xff); ns->ns_if.if_flags |= IFF_RUNNING; ns->ns_oactive = 0; ns->ns_mask = ~0; nestart(ifp); splx(s);}/* * Setup output on interface. * Get another datagram to send off of the interface queue, * and map it to the interface before starting the output. * called only at splimp or interrupt level. */nestart(ifp) struct ifnet *ifp;{ register struct ne_softc *ns = &ne_softc[ifp->if_unit]; struct mbuf *m0, *m; int buffer; int len = 0, i, total,t; /* * The DS8390 has only one transmit buffer, if it is busy we * must wait until the transmit interrupt completes. */ outb(nec+ds_cmd,DSCM_NODMA|DSCM_START); if (ns->ns_flags & DSF_LOCK) return; if (inb(nec+ds_cmd) & DSCM_TRANS) return; if ((ns->ns_if.if_flags & IFF_RUNNING) == 0) return; IF_DEQUEUE(&ns->ns_if.if_snd, m); if (m == 0) return; /* * Copy the mbuf chain into the transmit buffer */ ns->ns_flags |= DSF_LOCK; /* prevent entering nestart */ buffer = TBUF; len = i = 0; t = 0; for (m0 = m; m != 0; m = m->m_next) t += m->m_len; m = m0; total = t; for (m0 = m; m != 0; ) { if (m->m_len&1 && t > m->m_len) { neput(mtod(m, caddr_t), buffer, m->m_len - 1); t -= m->m_len - 1; buffer += m->m_len - 1; m->m_data += m->m_len - 1; m->m_len = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -