⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 if_ne.c

📁 很好的一个嵌入式linux平台下的bootloader
💻 C
📖 第 1 页 / 共 2 页
字号:
/*- * 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 *//* * NE-1000/NE-2000 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. *//* #define NEDEBUG */#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>#ifdef PROM#include "pci/device.h"#else#include <sys/device.h>#endif#include <net/if.h>#include <net/netisr.h>#include <net/route.h>#if NBPFILTER > 0#include <net/bpf.h>#include <net/bpfdesc.h>#endif#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#ifdef PMON#include <machine/endian.h>#include "mips.h"#include "sbd.h"#else#include <i386/isa/isavar.h>#include <i386/isa/icu.h>#include <machine/cpu.h>#endif#include "if_nereg.h"#ifdef NEDEBUG#define dprintf(x)	printf x#else#define dprintf(x)#endif#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 {#ifndef PROM	struct	device ne_dev;		/* base device (must be first) */	struct	isadev ne_id;		/* ISA device */	struct	intrhand ne_ih;		/* interrupt vectoring */	#endif	struct	arpcom ns_ac;		/* Ethernet common part */#define	ns_if	ns_ac.ac_if		/* network-visible interface */#define	sc_addr	ns_ac.ac_enaddr		/* hardware Ethernet address */	int	ns_base;		/* the board base address */	int	ns_ba;			/* byte addr in buffer ram of inc pkt */	int	ns_cur;			/* current page being filled */	int	ns_ifoldflags;		/* previous if_flags */	u_char	ns_ne1000;		/* true if the board is NE1000 */	u_char	ns_tbuf;		/* start of TX buffer (pages) */	u_char	ns_rbuf;		/* begin of RX ring (pages) */	u_char	ns_rbufend;		/* end of RX ring (pages) */	struct	prhdr	ns_ph;		/* hardware header of incoming packet*/	struct	ether_header ns_eh;	/* header of incoming packet */	char	ns_pb[2048 /*ETHERMTU+sizeof(long)*/];};/* * Prototypes */#ifdef PROMint neprobe __P((struct device *, void *, void *));#elseint neprobe __P((struct device *, struct cfdata *, void *));#endifvoid neattach __P((struct device *, struct device *, void *));int neintr __P((struct ne_softc *));int neinit __P((int));int nestart __P((struct ifnet *));int neioctl __P((struct ifnet *, int, caddr_t));static nememtest __P((int, int, int));void nefetch __P((int, int, caddr_t, int, int));void neput __P((int, int, caddr_t, int, int));void nerecv __P((struct ne_softc *));void neread __P((struct ne_softc *, char *, int));struct mbuf *neget __P((caddr_t, int, int, struct ifnet *));struct cfdriver necd =#ifdef PROM    { NULL, "en", neprobe, neattach, DV_IFNET, sizeof(struct ne_softc) };#else    { NULL, "ne", neprobe, neattach, DV_NET, sizeof(struct ne_softc) };#endif#ifdef PROMstruct isa_attach_args {    unsigned int ia_iobase;    unsigned int ia_iosize;    unsigned int ia_unit;    void	*ia_aux;};#define outb(base, v)		isa_outb(base, v)#define outsb(base, addr, len)	isa_outsb(base, addr, len)#define inb(base) 		isa_inb(base)#define insb(base, addr, len)	isa_insb(base, addr, len)#define inw(base) 		isa_inw(base)#define insw(base, addr, len)	isa_insw(base, addr, len)#define outw(base,  v)		isa_outw(base,  v)#define outsw(base, addr, len)	isa_outsw(base, addr, len)#endif/* * Probe routine *//* ARGSUSED */neprobe(parent, data, aux)	struct device *parent;#ifdef PROM	void *data;#else	struct cfdata *data;#endif	void *aux;{	void neforceintr(); 	struct cfdata *cf = data;	register struct isa_attach_args *ia = (struct isa_attach_args *) aux;	register nec = ia->ia_iobase;	int val, i;#ifdef lint	neintr(0);#endif#ifndef PROM	if (isa_portcheck(nec, NE_NPORT) == 0) {		aprint_debug("port range overlaps existing, ");		return (0);	}#endif	/*	 * Check configuration parameters	 */	if (!NE_IOBASEVALID(nec)) {		printf("ne%d: invalid i/o base address %x\n", cf->cf_unit, nec);		return (0);	}	/*	 * Reset the board and check its existence	 */	dprintf(("ne%d: port %x RESET\n", nec, cf->cf_unit));	val = inb(nec+ne_reset);	DELAY(10000);	outb(nec+ne_reset, val);	outb(nec+ds_cmd, DSCM_STOP|DSCM_NODMA);		dprintf(("ne%d: WAIT FOR RES", cf->cf_unit));	i = 100000;	while ((inb(nec+ds0_isr)&DSIS_RESET) == 0 && i-- > 0)		;	dprintf(("-- res=%d\n", i));	if (i < 0)		return (0);	/* Reset interrupts */	outb(nec+ds0_isr, 0xff);	/* 	 * Select NE1000 params -- byte transfers, burst mode, FIFO at 8 bytes.	 */	outb(nec+ds0_dcr, DSDC_BMS|DSDC_FT1);	outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);	DELAY(100);	if (inb(nec+ds_cmd) != (DSCM_NODMA|DSCM_PG0|DSCM_STOP))		return (0);	/*	 * Try to touch NE-2000 memory.  Use NE-1000 (byte-mode) transfer,	 * as word mode wedges an NE-1000.	 */	ia->ia_aux = (void *) 0;	/* NE-2000 by default */	dprintf(("TRY NE2000"));	outb(nec+ds0_dcr, DSDC_BMS|DSDC_FT1);	if (nememtest(nec, 1, NE2000_TBUF)) {		dprintf((" TRY NE1000"));		if (nememtest(nec, 1, NE1000_TBUF)) {			/*			 * Last chance: try NE-2000 with word transfers.			 * Some "compatibles" don't do byte transfers.			 */			dprintf(("TRY NE2000 word-mode"));			outb(nec+ds0_dcr, DSDC_WTS|DSDC_BMS|DSDC_FT1);			if (nememtest(nec, 0, NE2000_TBUF)) {#ifdef PROM				printf("mem test failed, ");#else				aprint_debug("mem test failed, ");#endif				dprintf(("OOPS\n"));				return (0);			}		} else			/* It's NE-1000 */			ia->ia_aux = (void *)1;	}	dprintf(("OK\n"));#ifndef PROM	/*	 * Find out IRQ if unknown	 */	if (ia->ia_irq == IRQUNK) {		ia->ia_irq = isa_discoverintr(neforceintr, aux);		outb(nec+ds0_imr, 0);		if (ffs(ia->ia_irq) - 1 == 0)			return (0);	}#endif	ia->ia_iosize = NE_NPORT;	return (1);}/* * Test on-board memory at the specified address, returning 0 if good. */staticnememtest(nec, ne1000, addr)	register int nec;	int ne1000;	int addr;{	static char test_pattern[32] = "*** This is a test pattern ***";	char testbuf[32];	dprintf((" -- PUT --"));	neput(nec, ne1000, test_pattern, addr, sizeof(test_pattern));	dprintf((" FETCH -- "));	nefetch(nec, ne1000, testbuf, addr, sizeof(test_pattern));	return (bcmp(testbuf, test_pattern, sizeof(test_pattern)));}#ifndef PROM/* * force the card to interrupt (tell us where it is) for autoconfiguration */ voidneforceintr(arg)	void *arg;{	int s;	register nec = ((struct isa_attach_args *) arg)->ia_iobase;	s = splhigh();	/* init chip 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);	outb(nec+ds0_dcr, DSDC_BMS|DSDC_FT1);	outb(nec+ds0_tcr, 0);	outb(nec+ds0_rcr, DSRC_MON);	outb(nec+ds0_tpsr, 0);	outb(nec+ds0_pstart, NE1000_RBUF / DS_PGSIZE);	outb(nec+ds0_pstop, NE1000_RBUFEND / DS_PGSIZE);	outb(nec+ds0_bnry, NE1000_RBUF / DS_PGSIZE);	outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);	outb(nec+ds1_curr,  NE1000_RBUF / DS_PGSIZE);	outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);	outb(nec+ds0_rcr, DSRC_AB);	outb(nec+ds0_imr, 0xff);	outb(nec+ds0_tbcr0, ETHER_MIN_LEN);	outb(nec+ds0_tbcr1, 0);	outb(nec+ds0_tpsr, NE1000_TBUF / DS_PGSIZE);	outb(nec+ds_cmd, DSCM_TRANS|DSCM_NODMA|DSCM_START);	splx(s);}#endif/* * 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. *//* ARGSUSED */voidneattach(parent, self, aux)	struct device *parent, *self;	void *aux;{	register struct ne_softc *ns = (struct ne_softc *) self;	register struct isa_attach_args *ia = (struct isa_attach_args *) aux;	register nec = ia->ia_iobase;#ifdef PROM	int unit = ia->ia_unit;#else	int unit = ns->ne_dev.dv_unit;#endif	register struct ifnet *ifp = &ns->ns_if;	int i;	/*	 * Set up NE1000/NE2000 stuff	 */	ns->ns_base = nec;	outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);	if ((int)(ia->ia_aux)) {		ns->ns_ne1000 = 1;		ns->ns_tbuf = NE1000_TBUF / DS_PGSIZE;		ns->ns_rbuf = NE1000_RBUF / DS_PGSIZE;		ns->ns_rbufend = NE1000_RBUFEND / DS_PGSIZE;		outb(nec+ds0_dcr, DSDC_BMS|DSDC_FT1);	} else {		/* Setup NE2000 params */		ns->ns_ne1000 = 0;		ns->ns_tbuf = NE2000_TBUF / DS_PGSIZE;		ns->ns_rbuf = NE2000_RBUF / DS_PGSIZE;		ns->ns_rbufend = NE2000_RBUFEND / DS_PGSIZE;		outb(nec+ds0_dcr, DSDC_WTS|DSDC_BMS|DSDC_FT1);	}	/*	 * Make sure the board is silent and	 * prepare for extracting the PROM address	 */	outb(nec+ds0_rcr, DSRC_MON);	outb(nec+ds0_imr, 0);	outb(nec+ds0_isr, 0);	outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);	/*	 * Extract board address	 */	dprintf(("ne%d: EXTRACT ADDR\n", unit));	nefetch(nec, ns->ns_ne1000, ns->ns_pb, 0, 2 * ETHER_ADDR_LEN);	if (ns->ns_ne1000)		for (i = 0; i < ETHER_ADDR_LEN; i++)			ns->sc_addr[i] = ns->ns_pb[i];	else		for (i = 0; i < ETHER_ADDR_LEN; i++)			ns->sc_addr[i] = ((u_short *)(ns->ns_pb))[i];	/*	 * Initialize interface structure	 */	ifp->if_unit = unit;	ifp->if_name = necd.cd_name;	ifp->if_mtu = ETHERMTU;#ifndef IFF_MULTICAST#define IFF_MULTICAST 0#endif	ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX |	    IFF_NOTRAILERS;	ifp->if_init = neinit;	ifp->if_start = nestart;	ifp->if_ioctl = neioctl;	ifp->if_watchdog = 0;	ether_attach(ifp);#ifdef PROM	printf(": NE-%c000 Ethernet, address %s\n", 	       ns->ns_ne1000 ? '1' : '2',	       ether_sprintf(ns->sc_addr));#else	printf(": NE-%c000", ns->ns_ne1000 ? '1' : '2');	aprint_naive(" Ethernet");	aprint_normal(", address %s", ether_sprintf(ns->sc_addr));	printf("\n");#endif#if NBPFILTER > 0	bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));#endif#ifndef PROM	isa_establish(&ns->ne_id, &ns->ne_dev);	ns->ne_ih.ih_fun = neintr;	ns->ne_ih.ih_arg = (void *)ns;	intr_establish(ia->ia_irq, &ns->ne_ih, DV_NET);#endif}/* * Initialization of interface; set up initialization block * and transmit/receive descriptor rings. */neinit(unit)	int unit;{	register struct ne_softc *ns = necd.cd_devs[unit];	struct ifnet *ifp = &ns->ns_if;	int s;	register nec = ns->ns_base;	register i; 	if (ifp->if_addrlist == (struct ifaddr *) 0) 		return (0);	if ((ifp->if_flags & IFF_RUNNING) && ifp->if_flags == ns->ns_ifoldflags)		return (0);	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->sc_addr[i]);	/* clr logical address hash filter for now */	for (i = 0; i < 8; i++)		outb(nec+ds1_mar0+i, 0xff);	/*	 * Init DS8390	 */	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);	outb(nec+ds0_dcr, ns->ns_ne1000 ?	    DSDC_BMS|DSDC_FT1 : 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, ns->ns_rbuf);	outb(nec+ds0_pstop, ns->ns_rbufend);	outb(nec+ds0_bnry, ns->ns_rbuf);	outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);	outb(nec+ds1_curr, ns->ns_rbuf);	outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);	if (ifp->if_flags & IFF_PROMISC)		outb(nec+ds0_rcr, DSRC_AB|DSRC_AM|DSRC_PRO);#if IFF_MULTICAST > 0	else if (ns->ns_ac.ac_multiaddrs != 0 || ifp->if_flags & IFF_ALLMULTI)		outb(nec+ds0_rcr, DSRC_AB|DSRC_AM);#endif	else		outb(nec+ds0_rcr, DSRC_AB);	outb(nec+ds0_imr, 0xff);	ns->ns_cur = ns->ns_rbuf;	ns->ns_if.if_flags &= ~IFF_OACTIVE;	ns->ns_if.if_flags |= IFF_RUNNING;	nestart(ifp);	splx(s);}/* * Setup output on interface. * Get another datagram to send off of the interface queue, * and copy 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 = necd.cd_devs[ifp->if_unit];	register nec = ns->ns_base;	struct mbuf *m0, *m;	u_char cmd, oddword[2];	int len;	IF_DEQUEUE(&ns->ns_if.if_snd, m0);	if (m0 == 0)		return (0);	ns->ns_if.if_flags |= IFF_OACTIVE;	/* prevent entering nestart */	#if NBPFILTER > 0	/*	 * Feed outgoing packet to bpf	 */	if (ns->ns_if.if_bpf)		bpf_mtap(ns->ns_if.if_bpf, m0);#endif	/*	 * Calculate the length of a packet.	 * XXX should use m->m_hdr.len.	 */	for (len = 0, m = m0; m != 0; m = m->m_next)		len += m->m_len;	if ((len & 01) && !ns->ns_ne1000)		len++;	/* Setup for remote dma */	cmd = inb(nec+ds_cmd);	outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);	outb(nec+ds0_isr, DSIS_RDC);	outb(nec+ds0_rbcr0, len);	outb(nec+ds0_rbcr1, len >> 8);	outb(nec+ds0_rsar0, 0);	outb(nec+ds0_rsar1, ns->ns_tbuf);	outb(nec+ds_cmd, DSCM_RWRITE|DSCM_PG0|DSCM_START);		/*	 * Push out data from each mbuf, watching out	 * for 0 length mbufs and odd-length mbufs (on ne2000).	 */	if (ns->ns_ne1000) {		for (m = m0; m != 0; m = m->m_next) {			if (m->m_len == 0)				continue;			outsb(nec+ne_data, m->m_data, m->m_len);		}	} else {		for (m = m0; m != 0; ) {			if (m->m_len >= 2)				outsw(nec+ne_data, m->m_data, m->m_len / 2);			if (m->m_len & 1) {				oddword[0] = *(mtod(m, caddr_t) + m->m_len - 1);				if (m = m->m_next) {					oddword[1] = *(mtod(m, caddr_t));					m->m_data++;					m->m_len--;				} else					oddword[1] = 0;				outsw(nec+ne_data, oddword, 1);		/* "outw" */			} else				m = m->m_next;		}	}	/* Wait till done, then shutdown feature */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -