📄 if_we.c
字号:
/*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Tim L. Tucker. * * 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_we.c 8.1 (Berkeley) 6/11/93 *//* * Modification history * * 8/28/89 - Initial version(if_wd.c), Tim L Tucker */ #include "we.h"#if NWE > 0/* * Western Digital 8003 ethernet/starlan adapter * * Supports the following interface cards: * WD8003E, WD8003EBT, WD8003S, WD8003SBT, WD8013EBT * * The Western Digital card is one of many AT/MCA ethernet interfaces * based on the National DS8390 Network Interface chip set. */#include <sys/param.h>#include <sys/mbuf.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>#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/if_wereg.h>#include <i386/isa/isa_device.h> /* * This constant should really be 60 because the we adds 4 bytes of crc. * However when set to 60 our packets are ignored by deuna's , 3coms are * okay ?????????????????????????????????????????? */#define ETHER_MIN_LEN 64#define ETHER_ADDR_LEN 6#define ETHER_HDR_SIZE 14 /* * Ethernet software status per interface. * * Each interface is referenced by a network interface structure, * qe_if, which the routing code uses to locate the interface. * This structure contains the output queue for the interface, its address, ... */struct we_softc { struct arpcom we_ac; /* Ethernet common part */#define we_if we_ac.ac_if /* network-visible interface */#define we_addr we_ac.ac_enaddr /* hardware Ethernet address */ u_char we_flags; /* software state */#define WDF_RUNNING 0x01#define WDF_TXBUSY 0x02 u_char we_type; /* interface type code */ u_short we_vector; /* interrupt vector */ short we_io_ctl_addr; /* i/o bus address, control */ short we_io_nic_addr; /* i/o bus address, DS8390 */ caddr_t we_vmem_addr; /* card RAM virtual memory base */ u_long we_vmem_size; /* card RAM bytes */ caddr_t we_vmem_ring; /* receive ring RAM vaddress */ caddr_t we_vmem_end; /* receive ring RAM end */} we_softc[NWE];int weprobe(), weattach(), weintr(), westart();int weinit(), ether_output(), weioctl(), wereset(), wewatchdog();struct isa_driver wedriver = { weprobe, weattach, "we",}; /* * Probe the WD8003 to see if it's there */weprobe(is) struct isa_device *is;{ register int i; register struct we_softc *sc = &we_softc[is->id_unit]; union we_mem_sel wem; u_char sum; /* * Here we check the card ROM, if the checksum passes, and the * type code and ethernet address check out, then we know we have * a wd8003 card. * * Autoconfiguration: No warning message is printed on error. */ for (sum = 0, i = 0; i < 8; ++i) sum += inb(is->id_iobase + WD_ROM_OFFSET + i); if (sum != WD_CHECKSUM) return (0); sc->we_type = inb(is->id_iobase + WD_ROM_OFFSET + 6); if ((sc->we_type != WD_ETHER) && (sc->we_type != WD_STARLAN) && (sc->we_type != WD_ETHER2)) return (0); /* * Setup card RAM area and i/o addresses * Kernel Virtual to segment C0000-DFFFF????? */ sc->we_io_ctl_addr = is->id_iobase; sc->we_io_nic_addr = sc->we_io_ctl_addr + WD_NIC_OFFSET; sc->we_vector = is->id_irq; sc->we_vmem_addr = (caddr_t)is->id_maddr; sc->we_vmem_size = is->id_msize; sc->we_vmem_ring = sc->we_vmem_addr + (WD_PAGE_SIZE * WD_TXBUF_SIZE); sc->we_vmem_end = sc->we_vmem_addr + is->id_msize; /* * Save board ROM station address */ for (i = 0; i < ETHER_ADDR_LEN; ++i) sc->we_addr[i] = inb(sc->we_io_ctl_addr + WD_ROM_OFFSET + i); /* * Mapin interface memory, setup memory select register */ /* wem.ms_addr = (u_long)sc->we_vmem_addr >> 13; */ wem.ms_addr = (u_long)(0xd0000)>> 13; wem.ms_enable = 1; wem.ms_reset = 0; outb(sc->we_io_ctl_addr, wem.ms_byte); /* * clear interface memory, then sum to make sure its valid */ for (i = 0; i < sc->we_vmem_size; ++i) sc->we_vmem_addr[i] = 0x0; for (sum = 0, i = 0; i < sc->we_vmem_size; ++i) sum += sc->we_vmem_addr[i]; if (sum != 0x0) { printf("we%d: wd8003 dual port RAM address error\n", is->id_unit); return (0); } return (WD_IO_PORTS);} /* * Interface exists: make available by filling in network interface * record. System will initialize the interface when it is ready * to accept packets. */weattach(is) struct isa_device *is;{ register struct we_softc *sc = &we_softc[is->id_unit]; register struct ifnet *ifp = &sc->we_if; union we_command wecmd; wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); wecmd.cs_stp = 1; wecmd.cs_sta = 0; wecmd.cs_ps = 0; outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); /* * Initialize ifnet structure */ ifp->if_unit = is->id_unit; ifp->if_name = "we" ; ifp->if_mtu = ETHERMTU; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS ; ifp->if_init = weinit; ifp->if_output = ether_output; ifp->if_start = westart; ifp->if_ioctl = weioctl; ifp->if_reset = wereset; ifp->if_watchdog = wewatchdog; if_attach(ifp); /* * Banner... */ printf(" %s address %s", ((sc->we_type != WD_STARLAN) ? "ethernet" : "starlan"), ether_sprintf(sc->we_addr));} /* * Reset of interface. */wereset(unit, uban) int unit, uban;{ if (unit >= NWE) return; printf("we%d: reset\n", unit);/* we_softc[unit].we_flags &= ~WDF_RUNNING; */ weinit(unit);} /* * Take interface offline. */westop(unit) int unit;{ register struct we_softc *sc = &we_softc[unit]; union we_command wecmd; int s; /* * Shutdown DS8390 */ s = splimp(); wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); wecmd.cs_stp = 1; wecmd.cs_sta = 0; wecmd.cs_ps = 0; outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); (void) splx(s);}wewatchdog(unit) { log(LOG_WARNING,"we%d: soft reset\n", unit); westop(unit); weinit(unit);}static Bdry;/* * Initialization of interface (really just DS8390). */weinit(unit) int unit;{ register struct we_softc *sc = &we_softc[unit]; register struct ifnet *ifp = &sc->we_if; union we_command wecmd; int i, s; /* address not known */ if (ifp->if_addrlist == (struct ifaddr *)0) return; /* already running */ /*if (ifp->if_flags & IFF_RUNNING) return; */ /* * Initialize DS8390 in order given in NSC NIC manual. * this is stock code...please see the National manual for details. */ s = splhigh();Bdry = 0; wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); wecmd.cs_stp = 1; wecmd.cs_sta = 0; wecmd.cs_ps = 0; outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); outb(sc->we_io_nic_addr + WD_P0_DCR, WD_D_CONFIG); outb(sc->we_io_nic_addr + WD_P0_RBCR0, 0); outb(sc->we_io_nic_addr + WD_P0_RBCR1, 0); outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_MON); outb(sc->we_io_nic_addr + WD_P0_TCR, WD_T_CONFIG); outb(sc->we_io_nic_addr + WD_P0_TPSR, 0); outb(sc->we_io_nic_addr + WD_P0_PSTART, WD_TXBUF_SIZE); outb(sc->we_io_nic_addr + WD_P0_PSTOP, sc->we_vmem_size / WD_PAGE_SIZE); outb(sc->we_io_nic_addr + WD_P0_BNRY, WD_TXBUF_SIZE); outb(sc->we_io_nic_addr + WD_P0_ISR, 0xff); outb(sc->we_io_nic_addr + WD_P0_IMR, WD_I_CONFIG); wecmd.cs_ps = 1; outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); for (i = 0; i < ETHER_ADDR_LEN; ++i) outb(sc->we_io_nic_addr + WD_P1_PAR0 + i, sc->we_addr[i]); for (i = 0; i < ETHER_ADDR_LEN; ++i) /* == broadcast addr */ outb(sc->we_io_nic_addr + WD_P1_MAR0 + i, 0xff); outb(sc->we_io_nic_addr + WD_P1_CURR, WD_TXBUF_SIZE); wecmd.cs_ps = 0; wecmd.cs_stp = 0; wecmd.cs_sta = 1; wecmd.cs_rd = 0x4; outb(sc->we_io_nic_addr + WD_P1_COMMAND, wecmd.cs_byte); outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_CONFIG); /* * Take the interface out of reset, program the vector, * enable interrupts, and tell the world we are up. */ ifp->if_flags |= IFF_RUNNING; sc->we_flags &= ~WDF_TXBUSY; (void) splx(s); westart(ifp);} /* * Start output on interface. */westart(ifp) struct ifnet *ifp;{ register struct we_softc *sc = &we_softc[ifp->if_unit]; struct mbuf *m0, *m; register caddr_t buffer; int len, s; union we_command wecmd; /* * The DS8390 has only one transmit buffer, if it is busy we * must wait until the transmit interrupt completes. */ s = splhigh(); if (sc->we_flags & WDF_TXBUSY) { (void) splx(s); return; } IF_DEQUEUE(&sc->we_if.if_snd, m); if (m == 0) { (void) splx(s); return; } sc->we_flags |= WDF_TXBUSY; (void) splx(s); /* * Copy the mbuf chain into the transmit buffer */ buffer = sc->we_vmem_addr; len = 0; for (m0 = m; m != 0; m = m->m_next) { bcopy(mtod(m, caddr_t), buffer, m->m_len); buffer += m->m_len; len += m->m_len; } m_freem(m0); /* * Init transmit length registers, and set transmit start flag. */ s = splhigh(); len = MAX(len, ETHER_MIN_LEN); wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); wecmd.cs_ps = 0; outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); outb(sc->we_io_nic_addr + WD_P0_TBCR0, len & 0xff); outb(sc->we_io_nic_addr + WD_P0_TBCR1, len >> 8); wecmd.cs_txp = 1; outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); (void) splx(s);} /* * Ethernet interface interrupt processor */weintr(unit) int unit;{ register struct we_softc *sc = &we_softc[unit]; union we_command wecmd; union we_interrupt weisr; int nloops = 10; unit =0; /* disable onboard interrupts, then get interrupt status */ wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); wecmd.cs_ps = 0; outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); weisr.is_byte = inb(sc->we_io_nic_addr + WD_P0_ISR);loop: outb(sc->we_io_nic_addr + WD_P0_ISR, weisr.is_byte); /* transmit error */ if (weisr.is_txe) { /* need to read these registers to clear status */ sc->we_if.if_collisions += inb(sc->we_io_nic_addr + WD_P0_TBCR0); ++sc->we_if.if_oerrors; } /* receiver error */ if (weisr.is_rxe) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -