sc);
sc, sc->sc_dev.dv_xname);
struct mbuf *egget __P((struct eg_softc *, caddr_t, int));void egstop __P((struct eg_softc *));/* * Support stuff */	static inline voidegprintpcb(sc)	struct eg_softc *sc;{	int i;		for (i = 0; i < sc->eg_pcb[1] + 2; i++)		dprintf(("pcb[%2d] = %x\n", i, sc->eg_pcb[i]));}static inline voidegprintstat(b)	u_char b;{	dprintf(("%s %s %s %s %s %s %s\n", 		 (b & EG_STAT_HCRE)?"HCRE":"",		 (b & EG_STAT_ACRF)?"ACRF":"",		 (b & EG_STAT_DIR )?"DIR ":"",		 (b & EG_STAT_DONE)?"DONE":"",		 (b & EG_STAT_ASF3)?"ASF3":"",		 (b & EG_STAT_ASF2)?"ASF2":"",		 (b & EG_STAT_ASF1)?"ASF1":""));}static integoutPCB(sc, b)	struct eg_softc *sc;	u_char b;{	int i;	for (i=0; i < 4000; i++) {		if (inb(sc->eg_stat) & EG_STAT_HCRE) {			outb(sc->eg_cmd, b);			return 0;		}		delay(10);	}	dprintf(("egoutPCB failed\n"));	return 1;}	static integreadPCBstat(sc, statb)	struct eg_softc *sc;	u_char statb;{	int i;	for (i=0; i < 5000; i++) {		if ((inb(sc->eg_stat) & EG_PCB_STAT) != EG_PCB_NULL) 			break;		delay(10);	}	if ((inb(sc->eg_stat) & EG_PCB_STAT) == statb) 		return 0;	return 1;}static integreadPCBready(sc)	struct eg_softc *sc;{	int i;	for (i=0; i < 10000; i++) {		if (inb(sc->eg_stat) & EG_STAT_ACRF)			return 0;		delay(5);	}	dprintf(("PCB read not ready\n"));	return 1;}	static integwritePCB(sc)	struct eg_softc *sc;{	int i;	u_char len;	outb(sc->eg_ctl, (inb(sc->eg_ctl) & ~EG_PCB_STAT) | EG_PCB_NULL);	len = sc->eg_pcb[1] + 2;	for (i = 0; i < len; i++)		egoutPCB(sc, sc->eg_pcb[i]);		for (i=0; i < 4000; i++) {		if (inb(sc->eg_stat) & EG_STAT_HCRE)			break;		delay(10);	}	outb(sc->eg_ctl, (inb(sc->eg_ctl) & ~EG_PCB_STAT) | EG_PCB_DONE);	egoutPCB(sc, len);	if (egreadPCBstat(sc, EG_PCB_ACCEPT))		return 1;	return 0;}		static integreadPCB(sc)	struct eg_softc *sc;{	int i;	u_char b;		outb(sc->eg_ctl, (inb(sc->eg_ctl) & ~EG_PCB_STAT) | EG_PCB_NULL);	bzero(sc->eg_pcb, sizeof(sc->eg_pcb));	if (egreadPCBready(sc))		return 1;	sc->eg_pcb[0] = inb(sc->eg_cmd);		if (egreadPCBready(sc))		return 1;	sc->eg_pcb[1] = inb(sc->eg_cmd);	if (sc->eg_pcb[1] > 62) {		dprintf(("len %d too large\n", sc->eg_pcb[1]));		return 1;	}		for (i = 0; i < sc->eg_pcb[1]; i++) {		if (egreadPCBready(sc))			return 1;		sc->eg_pcb[2+i] = inb(sc->eg_cmd);	}	if (egreadPCBready(sc))		return 1;	if (egreadPCBstat(sc, EG_PCB_DONE))		return 1;	if ((b = inb(sc->eg_cmd)) != sc->eg_pcb[1] + 2) {		dprintf(("%d != %d\n", b, sc->eg_pcb[1] + 2));		return 1;	}	outb(sc->eg_ctl, (inb(sc->eg_ctl) & ~EG_PCB_STAT) | EG_PCB_ACCEPT);	return 0;}	/* * Real stuff */integprobe(parent, match, aux)	struct device *parent;	void *match, *aux;{	struct eg_softc *sc = match;	struct isa_attach_args *ia = aux;	int i;	if (ia->ia_iobase & ~0x07f0 != 0) {		dprintf(("Weird iobase %x\n", ia->ia_iobase));		return 0;	}		sc->eg_cmd = ia->ia_iobase + EG_COMMAND;	sc->eg_ctl = ia->ia_iobase + EG_CONTROL;	sc->eg_stat = ia->ia_iobase + EG_STATUS;	sc->eg_data = ia->ia_iobase + EG_DATA;	/* hard reset card */	outb(sc->eg_ctl, EG_CTL_RESET); 	outb(sc->eg_ctl, 0);	for (i = 0; i < 5000; i++) {		delay(1000);		if ((inb(sc->eg_stat) & EG_PCB_STAT) == EG_PCB_NULL) 			break;	}	if ((inb(sc->eg_stat) & EG_PCB_STAT) != EG_PCB_NULL) {		dprintf(("eg: Reset failed\n"));		return 0;	}	sc->eg_pcb[0] = EG_CMD_GETINFO; /* Get Adapter Info */	sc->eg_pcb[1] = 0;	if (egwritePCB(sc) != 0)		return 0;		if (egreadPCB(sc) != 0) {		egprintpcb(sc);		return 0;	}	if (sc->eg_pcb[0] != EG_RSP_GETINFO || /* Get Adapter Info Response */	    sc->eg_pcb[1] != 0x0a) {		egprintpcb(sc);		return 0;	}	sc->eg_rom_major = sc->eg_pcb[3];	sc->eg_rom_minor = sc->eg_pcb[2];	sc->eg_ram = sc->eg_pcb[6] | (sc->eg_pcb[7] << 8);		ia->ia_iosize = 0x08;	ia->ia_msize = 0;	return 1;}voidegattach(parent, self, aux)	struct device *parent, *self;	void *aux;{	struct eg_softc *sc = (void *)self;	struct isa_attach_args *ia = aux;	struct ifnet *ifp = &sc->sc_arpcom.ac_if;	int i;		egstop(sc);	sc->eg_pcb[0] = EG_CMD_GETEADDR; /* Get Station address */	sc->eg_pcb[1] = 0;	if (egwritePCB(sc) != 0) {		dprintf(("write error\n"));		return;	}		if (egreadPCB(sc) != 0) {		dprintf(("read error\n"));		egprintpcb(sc);		return;	}	/* check Get station address response */	if (sc->eg_pcb[0] != EG_RSP_GETEADDR || sc->eg_pcb[1] != 0x06) { 		dprintf(("parse error\n"));		egprintpcb(sc);		return;	}	bcopy(&sc->eg_pcb[2], sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);	printf(": ROM v%d.%02d %dk address %s\n",	    sc->eg_rom_major, sc->eg_rom_minor, sc->eg_ram,	    ether_sprintf(sc->sc_arpcom.ac_enaddr));	sc->eg_pcb[0] = EG_CMD_SETEADDR; /* Set station address */	if (egwritePCB(sc) != 0) {		dprintf(("write error2\n"));		return;	}	if (egreadPCB(sc) != 0) {		dprintf(("read error2\n"));		egprintpcb(sc);		return;	}	if (sc->eg_pcb[0] != EG_RSP_SETEADDR || sc->eg_pcb[1] != 0x02 ||	    sc->eg_pcb[2] != 0 || sc->eg_pcb[3] != 0) {		dprintf(("parse error2\n"));		egprintpcb(sc);		return;	}	/* Initialize ifnet structure. */	ifp->if_unit = sc->sc_dev.dv_unit;	ifp->if_name = egcd.cd_name;	ifp->if_start = egstart;	ifp->if_ioctl = egioctl;	ifp->if_watchdog = egwatchdog;	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;		/* Now we can attach the interface. */	if_attach(ifp);	ether_ifattach(ifp);	#if NBPFILTER > 0	bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));#endif	sc->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_NET, egintr,	    sc);}voideginit(sc)	register struct eg_softc *sc;{	register struct ifnet *ifp = &sc->sc_arpcom.ac_if;	/* soft reset the board */	outb(sc->eg_ctl, EG_CTL_FLSH);	delay(100);	outb(sc->eg_ctl, EG_CTL_ATTN);	delay(100);	outb(sc->eg_ctl, 0);	delay(200);	sc->eg_pcb[0] = EG_CMD_CONFIG82586; /* Configure 82586 */	sc->eg_pcb[1] = 2;	sc->eg_pcb[2] = 3; /* receive broadcast & multicast */	sc->eg_pcb[3] = 0;	if (egwritePCB(sc) != 0)		dprintf(("write error3\n"));	if (egreadPCB(sc) != 0) {		dprintf(("read error\n"));		egprintpcb(sc);	} else if (sc->eg_pcb[2] != 0 || sc->eg_pcb[3] != 0)		printf("%s: configure card command failed\n",		    sc->sc_dev.dv_xname);	if (sc->eg_inbuf == 0)		sc->eg_inbuf = malloc(EG_BUFLEN, M_TEMP, M_NOWAIT);	sc->eg_incount = 0;	if (sc->eg_outbuf == 0)		sc->eg_outbuf = malloc(EG_BUFLEN, M_TEMP, M_NOWAIT);	outb(sc->eg_ctl, EG_CTL_CMDE);	sc->eg_incount = 0;	egrecv(sc);	/* Interface is now `running', with no output active. */	ifp->if_flags |= IFF_RUNNING;	ifp->if_flags &= ~IFF_OACTIVE;	/* Attempt to start output, if any. */	egstart(ifp);}voidegrecv(sc)	struct eg_softc *sc;{	while (sc->eg_incount < EG_INLEN) {		sc->eg_pcb[0] = EG_CMD_RECVPACKET;		sc->eg_pcb[1] = 0x08;		sc->eg_pcb[2] = 0; /* address not used.. we send zero */		sc->eg_pcb[3] = 0;		sc->eg_pcb[4] = 0;		sc->eg_pcb[5] = 0;		sc->eg_pcb[6] = EG_BUFLEN; /* our buffer size */		sc->eg_pcb[7] = EG_BUFLEN >> 8;		sc->eg_pcb[8] = 0; /* timeout, 0 == none */		sc->eg_pcb[9] = 0;		if (egwritePCB(sc) != 0)			break;		sc->eg_incount++;	}}voidegstart(ifp)	struct ifnet *ifp;{	register struct eg_softc *sc = egcd.cd_devs[ifp->if_unit];	struct mbuf *m0, *m;	caddr_t buffer;	int len;	u_short *ptr;	/* Don't transmit if interface is busy or not running */	if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)		return;loop:	/* Dequeue the next datagram. */	IF_DEQUEUE(&ifp->if_snd, m0);	if (m0 == 0)		return;		ifp->if_flags |= IFF_OACTIVE;	/* We need to use m->m_pkthdr.len, so require the header */	if ((m0->m_flags & M_PKTHDR) == 0)		panic("egstart: no header mbuf");	len = max(m0->m_pkthdr.len, ETHER_MIN_LEN);#if NBPFILTER > 0	if (ifp->if_bpf)		bpf_mtap(ifp->if_bpf, m0);#endif	sc->eg_pcb[0] = EG_CMD_SENDPACKET;	sc->eg_pcb[1] = 0x06;	sc->eg_pcb[2] = 0; /* address not used, we send zero */	sc->eg_pcb[3] = 0;	sc->eg_pcb[4] = 0;	sc->eg_pcb[5] = 0;	sc->eg_pcb[6] = len; /* length of packet */	sc->eg_pcb[7] = len >> 8;	if (egwritePCB(sc) != 0) {		dprintf(("egwritePCB in egstart failed\n"));		ifp->if_oerrors++;		ifp->if_flags &= ~IFF_OACTIVE;		goto loop;	}	buffer = sc->eg_outbuf;	for (m = m0; m != 0; m = m->m_next) {		bcopy(mtod(m, caddr_t), buffer, m->m_len);		buffer += m->m_len;	}	/* set direction bit: host -> adapter */	outb(sc->eg_ctl, inb(sc->eg_ctl) & ~EG_CTL_DIR); 		for (ptr = (u_short *) sc->eg_outbuf; len > 0; len -= 2) {		outw(sc->eg_data, *ptr++);		while (!(inb(sc->eg_stat) & EG_STAT_HRDY))			; /* XXX need timeout here */	}		m_freem(m0);}integintr(arg)	void *arg;{	register struct eg_softc *sc = arg;	int i, len;	u_short *ptr;	while (inb(sc->eg_stat) & EG_STAT_ACRF) {		egreadPCB(sc);		switch (sc->eg_pcb[0]) {		case EG_RSP_RECVPACKET:			len = sc->eg_pcb[6] | (sc->eg_pcb[7] << 8);				/* Set direction bit : Adapter -> host */			outb(sc->eg_ctl, inb(sc->eg_ctl) | EG_CTL_DIR); 			for (ptr = (u_short *) sc->eg_inbuf; len > 0; len -= 2) {				while (!(inb(sc->eg_stat) & EG_STAT_HRDY))					;				*ptr++ = inw(sc->eg_data);			}			len = sc->eg_pcb[8] | (sc->eg_pcb[9] << 8);			egread(sc, sc->eg_inbuf, len);			sc->eg_incount--;			egrecv(sc);			break;		case EG_RSP_SENDPACKET:			if (sc->eg_pcb[6] || sc->eg_pcb[7]) {				dprintf(("packet dropped\n"));				sc->sc_arpcom.ac_if.if_oerrors++;			} else				sc->sc_arpcom.ac_if.if_opackets++;			sc->sc_arpcom.ac_if.if_collisions += sc->eg_pcb[8] & 0xf;			sc->sc_arpcom.ac_if.if_flags &= ~IFF_OACTIVE;			egstart(&sc->sc_arpcom.ac_if);			break;		case EG_RSP_GETSTATS:			dprintf(("Card Statistics\n"));			bcopy(&sc->eg_pcb[2], &i, sizeof(i));			dprintf(("Receive Packets %d\n", i));			bcopy(&sc->eg_pcb[6], &i, sizeof(i));			dprintf(("Transmit Packets %d\n", i));			dprintf(("CRC errors %d\n", *(short*) &sc->eg_pcb[10]));			dprintf(("alignment errors %d\n", *(short*) &sc->eg_pcb[12]));			dprintf(("no resources errors %d\n", *(short*) &sc->eg_pcb[14]));			dprintf(("overrun errors %d\n", *(short*) &sc->eg_pcb[16]));			break;					default:			dprintf(("egintr: Unknown response %x??\n",			    sc->eg_pcb[0]));			egprintpcb(sc);			break;		}	}	return 0;}/* * Pass a packet up to the higher levels. */voidegread(sc, buf, len)	struct eg_softc *sc;	caddr_t buf;	int len;{	struct ifnet *ifp = &sc->sc_arpcom.ac_if;	struct mbuf *m;	struct ether_header *eh;		if (len <= sizeof(struct ether_header) ||	    len > ETHER_MAX_LEN) {		printf("%s: invalid packet size %d; dropping\n",		    sc->sc_dev.dv_xname, len);		ifp->if_ierrors++;		return;	}	/* Pull packet off interface. */	m = egget(sc, buf, len);	if (m == 0) {		ifp->if_ierrors++;		return;	}	ifp->if_ipackets++;	/* We assume the header fit entirely in one mbuf. */	eh = mtod(m, struct ether_header *);#if NBPFILTER > 0	/*	 * Check if there's a BPF listener on this interface.	 * If so, hand off the raw packet to BPF.	 */	if (ifp->if_bpf) {		bpf_mtap(ifp->if_bpf, m);		/*		 * Note that the interface cannot be in promiscuous mode if		 * there are no BPF listeners.  And if we are in promiscuous		 * mode, we have to check if this packet is really ours.		 */		if ((ifp->if_flags & IFF_PROMISC) &&		    (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */		    bcmp(eh->ether_dhost, sc->sc_arpcom.ac_enaddr,			    sizeof(eh->ether_dhost)) != 0) {			m_freem(m);			return;		}	}#endif	/* We assume the header fit entirely in one mbuf. */	m_adj(m, sizeof(struct ether_header));	ether_input(ifp, eh, m);}/* * convert buf into mbufs */struct mbuf *egget(sc, buf, totlen)	struct eg_softc *sc;	caddr_t buf;	int totlen;{	struct ifnet *ifp = &sc->sc_arpcom.ac_if;	struct mbuf *top, **mp, *m;	int len;	MGETHDR(m, M_DONTWAIT, MT_DATA);	if (m == 0)		return 0;	m->m_pkthdr.rcvif = ifp;	m->m_pkthdr.len = totlen;	len = MHLEN;	top = 0;	mp = &top;	while (totlen > 0) {		if (top) {			MGET(m, M_DONTWAIT, MT_DATA);			if (m == 0) {				m_freem(top);				return 0;			}			len = MLEN;		}		if (totlen >= MINCLSIZE) {			MCLGET(m, M_DONTWAIT);			if (m->m_flags & M_EXT)				len = MCLBYTES;		}		m->m_len = len = min(totlen, len);		bcopy((caddr_t)buf, mtod(m, caddr_t), len);		buf += len;		totlen -= len;		*mp = m;		mp = &m->m_next;	}	return top;}