if_ep.c revision 1264
1234370Sjasone/*
2234370Sjasone * Copyright (c) 1993 Herb Peyerl <hpeyerl@novatel.ca>
3234370Sjasone * All rights reserved.
4234370Sjasone *
5234370Sjasone * Redistribution and use in source and binary forms, with or without
6234370Sjasone * modification, are permitted provided that the following conditions
7234370Sjasone * are met:
8234370Sjasone * 1. Redistributions of source code must retain the above copyright
9234370Sjasone *    notice, this list of conditions and the following disclaimer.
10234370Sjasone * 2. The name of the author may not be used to endorse or promote products
11234658Sdim *    derived from this software withough specific prior written permission
12234658Sdim *
13234370Sjasone * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14234370Sjasone * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15234370Sjasone * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16235238Sjasone * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17234370Sjasone * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18234370Sjasone * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19234370Sjasone * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20234370Sjasone * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21234370Sjasone * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22234370Sjasone * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23234370Sjasone *
24234370Sjasone *	From: if_ep.c,v 1.9 1994/01/25 10:46:29 deraadt Exp $
25234370Sjasone *	$Id: if_ep.c,v 1.7 1994/02/03 11:51:06 davidg Exp $
26234370Sjasone */
27234370Sjasone/*
28234370Sjasone * TODO:
29234370Sjasone *	Multi-509 configs.
30234370Sjasone *	don't pass unit into epstop.
31234370Sjasone *	epintr returns an int for magnum. 0=not for me. 1=for me. -1=whoknows?
32234370Sjasone *	deallocate mbufs when ifconfig'd down.
33234370Sjasone */
34234370Sjasone#include "ep.h"
35234370Sjasone#if NEP > 0
36234370Sjasone
37234370Sjasone#include "bpfilter.h"
38234370Sjasone
39234370Sjasone#include "sys/param.h"
40242844Sjasone#if defined(__FreeBSD__)
41242844Sjasone#include "sys/systm.h"
42234370Sjasone#include "sys/kernel.h"
43234370Sjasone#endif
44234370Sjasone#include "sys/mbuf.h"
45234370Sjasone#include "sys/socket.h"
46234370Sjasone#include "sys/ioctl.h"
47234370Sjasone#include "sys/errno.h"
48234370Sjasone#include "sys/syslog.h"
49234370Sjasone#if defined(__NetBSD__)
50234370Sjasone#include "sys/select.h"
51234370Sjasone#endif
52234370Sjasone
53234370Sjasone#include "net/if.h"
54234370Sjasone#include "net/if_dl.h"
55234370Sjasone#include "net/if_types.h"
56234370Sjasone
57234370Sjasone#ifdef INET
58234370Sjasone#include "netinet/in.h"
59234370Sjasone#include "netinet/in_systm.h"
60235238Sjasone#include "netinet/in_var.h"
61235238Sjasone#include "netinet/ip.h"
62235238Sjasone#include "netinet/if_ether.h"
63235238Sjasone#endif
64235238Sjasone
65235238Sjasone#ifdef NS
66235238Sjasone#include "netns/ns.h"
67235238Sjasone#include "netns/ns_if.h"
68235238Sjasone#endif
69235238Sjasone
70235238Sjasone#if NBPFILTER > 0
71235238Sjasone#include "net/bpf.h"
72235238Sjasone#include "net/bpfdesc.h"
73235238Sjasone#endif
74235238Sjasone
75235238Sjasone#include "machine/pio.h"
76235238Sjasone
77235238Sjasone#include "i386/isa/isa.h"
78234370Sjasone#include "i386/isa/isa_device.h"
79235238Sjasone#include "i386/isa/icu.h"
80234370Sjasone#include "i386/isa/if_epreg.h"
81234370Sjasone
82234370Sjasone#define ETHER_MIN_LEN	64
83234370Sjasone#define ETHER_MAX_LEN	1518
84234370Sjasone#define ETHER_ADDR_LEN	6
85234370Sjasone
86234370Sjasone/*
87234370Sjasone * Ethernet software status per interface.
88234370Sjasone */
89234370Sjasonestruct ep_softc {
90234370Sjasone	struct arpcom arpcom;		/* Ethernet common part		*/
91234370Sjasone	short   ep_io_addr;		/* i/o bus address		*/
92234370Sjasone	char    ep_connectors;		/* Connectors on this card.	*/
93234370Sjasone#define MAX_MBS  4			/* # of mbufs we keep around	*/
94234370Sjasone	struct mbuf *mb[MAX_MBS];	/* spare mbuf storage.		*/
95234370Sjasone	int     next_mb;		/* Which mbuf to use next. 	*/
96234370Sjasone	int     last_mb;		/* Last mbuf.			*/
97234370Sjasone	int     tx_start_thresh;	/* Current TX_start_thresh.	*/
98234370Sjasone	caddr_t bpf;			/* BPF  "magic cookie"		*/
99234370Sjasone}       ep_softc[NEP];
100234370Sjasone
101234370Sjasonestatic int epprobe __P((struct isa_device *));
102234370Sjasonestatic int epattach __P((struct isa_device *));
103234370Sjasonestatic int epioctl __P((struct ifnet * ifp, int, caddr_t));
104234370Sjasone
105234370Sjasonevoid epinit __P((int));
106234370Sjasonevoid epintr __P((int));
107234370Sjasonevoid epmbufqueue __P((caddr_t, int));
108234370Sjasonevoid epread __P((struct ep_softc *));
109234370Sjasonevoid epreset __P((int));
110234370Sjasonevoid epstart __P((struct ifnet *));
111234370Sjasonevoid epstop __P((int));
112234370Sjasonevoid epwatchdog __P((int));
113234370Sjasone
114234370Sjasonestruct isa_driver epdriver = {
115234370Sjasone	epprobe,
116234370Sjasone	epattach,
117234370Sjasone	"ep"
118234370Sjasone};
119234370Sjasone
120234370Sjasonestatic int send_ID_sequence __P((u_short));
121234370Sjasonestatic u_short get_eeprom_data __P((int, int));
122234370Sjasonestatic int is_eeprom_busy __P((struct isa_device *));
123234370Sjasone
124234370Sjasone/*
125234370Sjasone * Rudimentary support for multiple cards is here but is not
126234370Sjasone * currently handled.  In the future we will have to add code
127234370Sjasone * for tagging the cards for later activation.  We wanna do something
128234370Sjasone * about the id_port.  We're limited due to current config procedure.
129234370Sjasone * Magnum config holds promise of a fix but we'll have to wait a bit.
130234370Sjasone */
131234370Sjasoneint
132234370Sjasoneepprobe(is)
133234370Sjasone	struct isa_device *is;
134234370Sjasone{
135234370Sjasone	struct ep_softc *sc = &ep_softc[is->id_unit];
136234370Sjasone	u_short k;
137234370Sjasone	int     id_port = 0x100;	/* XXX */
138234370Sjasone
139234370Sjasone	outw(BASE + EP_COMMAND, GLOBAL_RESET);
140234370Sjasone	DELAY(1000);
141234370Sjasone	outb(id_port, 0xc0);	/* Global reset to id_port. */
142234370Sjasone	DELAY(1000);
143234370Sjasone	send_ID_sequence(id_port);
144234370Sjasone	DELAY(1000);
145234370Sjasone
146234370Sjasone	/*
147234370Sjasone	 * MFG_ID should have 0x6d50.
148234370Sjasone	 * PROD_ID should be 0x9[0-f]50
149234370Sjasone	 */
150234370Sjasone	k = get_eeprom_data(id_port, EEPROM_MFG_ID);
151234370Sjasone	if (k != MFG_ID)
152242844Sjasone		return (0);
153234370Sjasone	k = get_eeprom_data(id_port, EEPROM_PROD_ID);
154234370Sjasone	if ((k & 0xf0ff) != (PROD_ID & 0xf0ff))
155234370Sjasone		return (0);
156242844Sjasone
157234370Sjasone	k = get_eeprom_data(id_port, EEPROM_ADDR_CFG);	/* get addr cfg */
158234370Sjasone	k = (k & 0x1f) * 0x10 + 0x200;			/* decode base addr. */
159242844Sjasone	if (k != (u_short)is->id_iobase)
160234370Sjasone		return (0);
161234370Sjasone
162234370Sjasone	k = get_eeprom_data(id_port, EEPROM_RESOURCE_CFG);
163234370Sjasone	k >>= 12;
164234370Sjasone	if (is->id_irq != (1 << ((k == 2) ? 9 : k)))
165234370Sjasone		return (0);
166234370Sjasone
167234370Sjasone	outb(id_port, ACTIVATE_ADAPTER_TO_CONFIG);
168242844Sjasone
169234370Sjasone	return (0x10);		/* 16 bytes of I/O space used. */
170234370Sjasone}
171234370Sjasone
172234370Sjasonestatic int
173234370Sjasoneepattach(is)
174234370Sjasone	struct isa_device *is;
175234370Sjasone{
176234370Sjasone	struct ep_softc *sc = &ep_softc[is->id_unit];
177234370Sjasone	struct ifnet *ifp = &sc->arpcom.ac_if;
178234370Sjasone	u_short i;
179234370Sjasone	struct ifaddr *ifa;
180234370Sjasone	struct sockaddr_dl *sdl;
181234370Sjasone
182242844Sjasone	sc->ep_io_addr = is->id_iobase;
183242844Sjasone
184234370Sjasone	printf("ep%d: ", is->id_unit);
185234370Sjasone
186234370Sjasone	sc->ep_connectors = 0;
187234370Sjasone	i = inw(is->id_iobase + EP_W0_CONFIG_CTRL);
188234370Sjasone	if (i & IS_AUI) {
189234370Sjasone		printf("aui");
190234370Sjasone		sc->ep_connectors |= AUI;
191234370Sjasone	}
192234370Sjasone	if (i & IS_BNC) {
193234370Sjasone		if (sc->ep_connectors)
194234370Sjasone			printf("/");
195234370Sjasone		printf("bnc");
196234370Sjasone		sc->ep_connectors |= BNC;
197234370Sjasone	}
198234370Sjasone	if (i & IS_UTP) {
199234370Sjasone		if (sc->ep_connectors)
200234370Sjasone			printf("/");
201234370Sjasone		printf("utp");
202234370Sjasone		sc->ep_connectors |= UTP;
203234370Sjasone	}
204234370Sjasone	if (!sc->ep_connectors)
205234370Sjasone		printf("no connectors!");
206234370Sjasone
207234370Sjasone	/*
208234370Sjasone	 * Read the station address from the eeprom
209234370Sjasone	 */
210234370Sjasone	for (i = 0; i < 3; i++) {
211234370Sjasone		u_short *p;
212242844Sjasone		GO_WINDOW(0);
213234370Sjasone		if (is_eeprom_busy(is))
214234370Sjasone			return(0);
215234370Sjasone		outw(BASE + EP_W0_EEPROM_COMMAND, READ_EEPROM | i);
216234370Sjasone		if (is_eeprom_busy(is))
217234370Sjasone			return(0);
218234370Sjasone		p =(u_short *)&sc->arpcom.ac_enaddr[i*2];
219234370Sjasone		*p = htons(inw(BASE + EP_W0_EEPROM_DATA));
220234370Sjasone		GO_WINDOW(2);
221242844Sjasone		outw(BASE + EP_W2_ADDR_0 + (i * 2), ntohs(*p));
222234370Sjasone	}
223234370Sjasone	printf(" address %s\n", ether_sprintf(sc->arpcom.ac_enaddr));
224234370Sjasone
225234370Sjasone	ifp->if_unit = is->id_unit;
226234370Sjasone	ifp->if_name = "ep";
227234370Sjasone	ifp->if_mtu = ETHERMTU;
228234370Sjasone	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
229234370Sjasone	ifp->if_init = epinit;
230234370Sjasone	ifp->if_output = ether_output;
231234370Sjasone	ifp->if_start = epstart;
232234370Sjasone	ifp->if_ioctl = epioctl;
233234370Sjasone	ifp->if_watchdog = epwatchdog;
234234370Sjasone
235234370Sjasone	if_attach(ifp);
236234370Sjasone
237234370Sjasone	/*
238234370Sjasone	 * Fill the hardware address into ifa_addr if we find an
239234370Sjasone	 * AF_LINK entry. We need to do this so bpf's can get the hardware
240234370Sjasone	 * addr of this card. netstat likes this too!
241234370Sjasone	 */
242234370Sjasone	ifa = ifp->if_addrlist;
243234370Sjasone	while ((ifa != 0) && (ifa->ifa_addr != 0) &&
244234370Sjasone	    (ifa->ifa_addr->sa_family != AF_LINK))
245234370Sjasone		ifa = ifa->ifa_next;
246234370Sjasone
247234370Sjasone	if ((ifa != 0) && (ifa->ifa_addr != 0)) {
248234370Sjasone		sdl = (struct sockaddr_dl *) ifa->ifa_addr;
249234370Sjasone		sdl->sdl_type = IFT_ETHER;
250234370Sjasone		sdl->sdl_alen = ETHER_ADDR_LEN;
251234370Sjasone		sdl->sdl_slen = 0;
252234370Sjasone		bcopy(sc->arpcom.ac_enaddr, LLADDR(sdl), ETHER_ADDR_LEN);
253234370Sjasone	}
254234370Sjasone#if NBPFILTER > 0
255234370Sjasone	bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
256234370Sjasone#endif
257235238Sjasone	return 1;
258235238Sjasone}
259235238Sjasone
260235238Sjasone
261235238Sjasone/*
262234370Sjasone * The order in here seems important. Otherwise we may not receive
263242844Sjasone * interrupts. ?!
264234370Sjasone */
265234370Sjasonevoid
266234370Sjasoneepinit(unit)
267242844Sjasone	int     unit;
268242844Sjasone{
269242844Sjasone	register struct ep_softc *sc = &ep_softc[unit];
270234370Sjasone	register struct ifnet *ifp = &sc->arpcom.ac_if;
271234370Sjasone	int     s, i;
272234370Sjasone
273234370Sjasone	if (ifp->if_addrlist == (struct ifaddr *) 0)
274234370Sjasone		return;
275234370Sjasone
276234370Sjasone	s = splimp();
277234370Sjasone	while (inb(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
278234370Sjasone		;
279234370Sjasone
280234370Sjasone	GO_WINDOW(0);
281234370Sjasone
282234370Sjasone	/* Disable the card */
283234370Sjasone	outw(BASE + EP_W0_CONFIG_CTRL, 0);
284234370Sjasone
285234370Sjasone	/* Enable the card */
286234370Sjasone	outw(BASE + EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ);
287234370Sjasone
288234370Sjasone	GO_WINDOW(2);
289234370Sjasone
290234370Sjasone	/* Reload the ether_addr. */
291234370Sjasone	for (i = 0; i < 6; i++)
292234370Sjasone		outb(BASE + EP_W2_ADDR_0 + i, sc->arpcom.ac_enaddr[i]);
293234370Sjasone
294234370Sjasone	outw(BASE + EP_COMMAND, RX_RESET);
295234370Sjasone	outw(BASE + EP_COMMAND, TX_RESET);
296234370Sjasone
297234370Sjasone	/* Window 1 is operating window */
298234370Sjasone	GO_WINDOW(1);
299234370Sjasone	for (i = 0; i < 31; i++)
300234370Sjasone		inb(BASE + EP_W1_TX_STATUS);
301234370Sjasone
302234370Sjasone 	/* get rid of stray intr's */
303234370Sjasone	outw(BASE + EP_COMMAND, ACK_INTR | 0xff);
304234370Sjasone
305234370Sjasone	outw(BASE + EP_COMMAND, SET_RD_0_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
306234370Sjasone	    S_TX_COMPLETE | S_TX_AVAIL);
307234370Sjasone	outw(BASE + EP_COMMAND, SET_INTR_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
308234370Sjasone	    S_TX_COMPLETE | S_TX_AVAIL);
309234370Sjasone
310234370Sjasone	outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL |
311234370Sjasone	    FIL_GROUP | FIL_BRDCST);
312234370Sjasone
313234370Sjasone	/*
314234370Sjasone	 * you can `ifconfig (link0|-link0) ep0' to get the following
315234370Sjasone	 * behaviour:
316234370Sjasone	 *	-link0	disable AUI/UTP. enable BNC.
317234370Sjasone	 *	link0	disable BNC. enable AUI. if the card has a UTP
318234370Sjasone	 *		connector, that is enabled too. not sure, but it
319234370Sjasone	 * 		seems you have to be careful to not plug things
320234370Sjasone	 *		into both AUI & UTP.
321234370Sjasone	 */
322234370Sjasone#if defined(__NetBSD__)
323234370Sjasone	if (!(ifp->if_flags & IFF_LINK0) && (sc->ep_connectors & BNC)) {
324234370Sjasone#else
325234370Sjasone	if (!(ifp->if_flags & IFF_ALTPHYS) && (sc->ep_connectors & BNC)) {
326234370Sjasone#endif
327234370Sjasone		outw(BASE + EP_COMMAND, START_TRANSCEIVER);
328234370Sjasone		DELAY(1000);
329234370Sjasone	}
330234370Sjasone#if defined(__NetBSD__)
331234370Sjasone	if ((ifp->if_flags & IFF_LINK0) && (sc->ep_connectors & UTP)) {
332234370Sjasone#else
333234370Sjasone	if ((ifp->if_flags & IFF_ALTPHYS) && (sc->ep_connectors & UTP)) {
334234370Sjasone#endif
335234370Sjasone		GO_WINDOW(4);
336234370Sjasone		outw(BASE + EP_W4_MEDIA_TYPE, ENABLE_UTP);
337234370Sjasone		GO_WINDOW(1);
338234370Sjasone	}
339234370Sjasone
340234370Sjasone	outw(BASE + EP_COMMAND, RX_ENABLE);
341234370Sjasone	outw(BASE + EP_COMMAND, TX_ENABLE);
342234370Sjasone
343234370Sjasone	ifp->if_flags |= IFF_RUNNING;
344234370Sjasone	ifp->if_flags &= ~IFF_OACTIVE;	/* just in case */
345234370Sjasone	sc->tx_start_thresh = 20;	/* probably a good starting point. */
346234370Sjasone	/*
347234370Sjasone	 * Store up a bunch of mbuf's for use later. (MAX_MBS). First we
348234370Sjasone	 * free up any that we had in case we're being called from intr or
349234370Sjasone	 * somewhere else.
350234370Sjasone	 */
351234370Sjasone	sc->last_mb = 0;
352234370Sjasone	sc->next_mb = 0;
353234370Sjasone	epmbufqueue((caddr_t)sc, 0);
354234370Sjasone
355234370Sjasone	epstart(ifp);
356234370Sjasone
357234370Sjasone	splx(s);
358234370Sjasone}
359234370Sjasone
360234370Sjasonestatic const char padmap[] = {0, 3, 2, 1};
361234370Sjasone
362234370Sjasonevoid
363234370Sjasoneepstart(ifp)
364234370Sjasone	struct ifnet *ifp;
365234370Sjasone{
366234370Sjasone	register struct ep_softc *sc = &ep_softc[ifp->if_unit];
367234370Sjasone	struct mbuf *m, *top;
368234370Sjasone	int     s, len, pad;
369234370Sjasone
370234370Sjasone	s = splimp();
371234370Sjasone	if (sc->arpcom.ac_if.if_flags & IFF_OACTIVE) {
372234370Sjasone		splx(s);
373234370Sjasone		return;
374234370Sjasone	}
375234370Sjasone
376234370Sjasonestartagain:
377234370Sjasone	/* Sneak a peek at the next packet */
378234370Sjasone	m = sc->arpcom.ac_if.if_snd.ifq_head;
379234370Sjasone	if (m == 0) {
380234370Sjasone		splx(s);
381234370Sjasone		return;
382234370Sjasone	}
383234370Sjasone#if 0
384234370Sjasone	len = m->m_pkthdr.len;
385234370Sjasone#else
386234370Sjasone	for (len = 0, top = m; m; m = m->m_next)
387242844Sjasone		len += m->m_len;
388242844Sjasone#endif
389242844Sjasone
390242844Sjasone	pad = padmap[len & 3];
391242844Sjasone
392242844Sjasone	/*
393242844Sjasone	 * The 3c509 automatically pads short packets to minimum ethernet
394242844Sjasone	 * length, but we drop packets that are too large. Perhaps we should
395242844Sjasone	 * truncate them instead?
396242844Sjasone	 */
397242844Sjasone	if (len + pad > ETHER_MAX_LEN) {
398242844Sjasone		/* packet is obviously too large: toss it */
399242844Sjasone		++sc->arpcom.ac_if.if_oerrors;
400242844Sjasone		IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);
401242844Sjasone		m_freem(m);
402242844Sjasone		goto readcheck;
403234370Sjasone	}
404234370Sjasone
405234370Sjasone	if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) {
406234370Sjasone		/* no room in FIFO */
407234370Sjasone		outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | (len + pad + 4));
408234370Sjasone		sc->arpcom.ac_if.if_flags |= IFF_OACTIVE;
409234370Sjasone		splx(s);
410234370Sjasone		return;
411234370Sjasone	}
412234370Sjasone	IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);
413234370Sjasone	if (m == 0) {		/* not really needed */
414234370Sjasone		splx(s);
415234370Sjasone		return;
416234370Sjasone	}
417234370Sjasone	outw(BASE + EP_COMMAND, SET_TX_START_THRESH |
418234370Sjasone	    (len / 4 + sc->tx_start_thresh));
419234370Sjasone
420235238Sjasone	outw(BASE + EP_W1_TX_PIO_WR_1, len);
421234370Sjasone	outw(BASE + EP_W1_TX_PIO_WR_1, 0xffff);	/* Second dword meaningless */
422234370Sjasone
423235238Sjasone	for (top = m; m != 0; m = m->m_next) {
424234370Sjasone		outsw(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len/2);
425235238Sjasone		if (m->m_len & 1)
426234370Sjasone			outb(BASE + EP_W1_TX_PIO_WR_1,
427235238Sjasone			    *(mtod(m, caddr_t) + m->m_len - 1));
428234370Sjasone	}
429234370Sjasone	while (pad--)
430234370Sjasone		outb(BASE + EP_W1_TX_PIO_WR_1, 0);	/* Padding */
431234370Sjasone
432234370Sjasone#if NBPFILTER > 0
433234370Sjasone	if (sc->bpf) {
434234370Sjasone		u_short etype;
435234370Sjasone		int     off, datasize, resid;
436234370Sjasone		struct ether_header *eh;
437234370Sjasone		struct trailer_header {
438235238Sjasone			u_short ether_type;
439235238Sjasone			u_short ether_residual;
440235238Sjasone		}       trailer_header;
441234370Sjasone		char    ether_packet[ETHER_MAX_LEN];
442234370Sjasone		char   *ep;
443234370Sjasone
444234370Sjasone		ep = ether_packet;
445234370Sjasone
446234370Sjasone		/*
447234370Sjasone		 * We handle trailers below:
448234370Sjasone		 * Copy ether header first, then residual data,
449234370Sjasone		 * then data. Put all this in a temporary buffer
450234370Sjasone		 * 'ether_packet' and send off to bpf. Since the
451234370Sjasone		 * system has generated this packet, we assume
452234370Sjasone		 * that all of the offsets in the packet are
453234370Sjasone		 * correct; if they're not, the system will almost
454234370Sjasone		 * certainly crash in m_copydata.
455234370Sjasone		 * We make no assumptions about how the data is
456234370Sjasone		 * arranged in the mbuf chain (i.e. how much
457234370Sjasone		 * data is in each mbuf, if mbuf clusters are
458234370Sjasone		 * used, etc.), which is why we use m_copydata
459234370Sjasone		 * to get the ether header rather than assume
460234370Sjasone		 * that this is located in the first mbuf.
461234370Sjasone		 */
462234370Sjasone		/* copy ether header */
463234370Sjasone		m_copydata(top, 0, sizeof(struct ether_header), ep);
464234370Sjasone		eh = (struct ether_header *) ep;
465234370Sjasone		ep += sizeof(struct ether_header);
466234370Sjasone		eh->ether_type = etype = ntohs(eh->ether_type);
467234370Sjasone		if (etype >= ETHERTYPE_TRAIL &&
468234370Sjasone		    etype < ETHERTYPE_TRAIL + ETHERTYPE_NTRAILER) {
469234370Sjasone			datasize = ((etype - ETHERTYPE_TRAIL) << 9);
470234370Sjasone			off = datasize + sizeof(struct ether_header);
471234370Sjasone
472234370Sjasone			/* copy trailer_header into a data structure */
473234370Sjasone			m_copydata(top, off, sizeof(struct trailer_header),
474234370Sjasone			    (caddr_t)&trailer_header.ether_type);
475234370Sjasone
476234370Sjasone			/* copy residual data */
477234370Sjasone			resid = trailer_header.ether_residual -
478234543Sjasone			    sizeof(struct trailer_header);
479234370Sjasone			resid = ntohs(resid);
480234370Sjasone			m_copydata(top, off + sizeof(struct trailer_header),
481234370Sjasone			    resid, ep);
482234370Sjasone			ep += resid;
483234370Sjasone
484234370Sjasone			/* copy data */
485234370Sjasone			m_copydata(top, sizeof(struct ether_header),
486234370Sjasone			    datasize, ep);
487234370Sjasone			ep += datasize;
488234370Sjasone
489234370Sjasone			/* restore original ether packet type */
490234370Sjasone			eh->ether_type = trailer_header.ether_type;
491234370Sjasone
492234370Sjasone			bpf_tap(sc->bpf, ether_packet, ep - ether_packet);
493234370Sjasone		} else
494234370Sjasone			bpf_mtap(sc->bpf, top);
495234370Sjasone	}
496234370Sjasone#endif
497234370Sjasone
498234370Sjasone	m_freem(top);
499234370Sjasone	++sc->arpcom.ac_if.if_opackets;
500234370Sjasone
501234543Sjasone	/*
502234370Sjasone	 * Is another packet coming in? We don't want to overflow the
503234370Sjasone	 * tiny RX fifo.
504234370Sjasone	 */
505234370Sjasonereadcheck:
506235238Sjasone	if (inw(BASE + EP_W1_RX_STATUS) & RX_BYTES_MASK) {
507234370Sjasone		splx(s);
508235238Sjasone		return;
509234370Sjasone	}
510234370Sjasone	goto startagain;
511234370Sjasone}
512234370Sjasone
513234370Sjasonevoid
514234370Sjasoneepintr(unit)
515234370Sjasone	int     unit;
516234370Sjasone{
517234370Sjasone	int     status, i;
518234370Sjasone	register struct ep_softc *sc = &ep_softc[unit];
519234370Sjasone	struct ifnet *ifp = &sc->arpcom.ac_if;
520234370Sjasone	struct mbuf *m;
521234370Sjasone
522234543Sjasone	status = 0;
523234370Sjasonecheckintr:
524234370Sjasone	status = inw(BASE + EP_STATUS) &
525234370Sjasone	    (S_TX_COMPLETE | S_TX_AVAIL | S_RX_COMPLETE | S_CARD_FAILURE);
526234370Sjasone	if (status == 0) {
527235238Sjasone		/* No interrupts. */
528234370Sjasone		outw(BASE + EP_COMMAND, C_INTR_LATCH);
529235238Sjasone		return;
530234370Sjasone	}
531234370Sjasone	/* important that we do this first. */
532234370Sjasone	outw(BASE + EP_COMMAND, ACK_INTR | status);
533234370Sjasone
534234370Sjasone	if (status & S_TX_AVAIL) {
535234370Sjasone		status &= ~S_TX_AVAIL;
536234370Sjasone		inw(BASE + EP_W1_FREE_TX);
537234370Sjasone		sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
538234370Sjasone		epstart(&sc->arpcom.ac_if);
539234370Sjasone	}
540234370Sjasone	if (status & S_RX_COMPLETE) {
541234370Sjasone		status &= ~S_RX_COMPLETE;
542234370Sjasone		epread(sc);
543234370Sjasone	}
544234543Sjasone	if (status & S_CARD_FAILURE) {
545234370Sjasone		printf("ep%d: reset (status: %x)\n", unit, status);
546234370Sjasone		outw(BASE + EP_COMMAND, C_INTR_LATCH);
547234370Sjasone		epinit(unit);
548234370Sjasone		return;
549234370Sjasone	}
550234370Sjasone	if (status & S_TX_COMPLETE) {
551234370Sjasone		status &= ~S_TX_COMPLETE;
552234370Sjasone		/*
553234370Sjasone		 * We need to read TX_STATUS until we get a 0 status in
554234543Sjasone		 * order to turn off the interrupt flag.
555234370Sjasone		 */
556234370Sjasone		while ((i = inb(BASE + EP_W1_TX_STATUS)) & TXS_COMPLETE) {
557234370Sjasone			outw(BASE + EP_W1_TX_STATUS, 0x0);
558234370Sjasone			if (i & (TXS_MAX_COLLISION | TXS_JABBER | TXS_UNDERRUN)) {
559234370Sjasone				if (i & TXS_MAX_COLLISION)
560234370Sjasone					++sc->arpcom.ac_if.if_collisions;
561234370Sjasone				if (i & (TXS_JABBER | TXS_UNDERRUN)) {
562234543Sjasone					outw(BASE + EP_COMMAND, TX_RESET);
563234370Sjasone					if (i & TXS_UNDERRUN) {
564242844Sjasone						if (sc->tx_start_thresh < ETHER_MAX_LEN) {
565242844Sjasone							sc->tx_start_thresh += 20;
566242844Sjasone							outw(BASE + EP_COMMAND,
567242844Sjasone							    SET_TX_START_THRESH |
568242844Sjasone							    sc->tx_start_thresh);
569242844Sjasone						}
570242844Sjasone					}
571242844Sjasone				}
572242844Sjasone				outw(BASE + EP_COMMAND, TX_ENABLE);
573242844Sjasone				++sc->arpcom.ac_if.if_oerrors;
574242844Sjasone			}
575242844Sjasone		}
576242844Sjasone		epstart(ifp);
577242844Sjasone	}
578242844Sjasone	goto checkintr;
579242844Sjasone}
580242844Sjasone
581242844Sjasonevoid
582242844Sjasoneepread(sc)
583242844Sjasone	register struct ep_softc *sc;
584242844Sjasone{
585242844Sjasone	struct ether_header *eh;
586242844Sjasone	struct mbuf *mcur, *m, *m0, *top;
587242844Sjasone	int     totlen, lenthisone;
588234543Sjasone	int     save_totlen;
589234543Sjasone	u_short etype;
590234543Sjasone	int     off, resid;
591234370Sjasone	int     count, spinwait;
592234543Sjasone	int     i;
593234370Sjasone
594234543Sjasone	totlen = inw(BASE + EP_W1_RX_STATUS);
595234543Sjasone	off = 0;
596234370Sjasone	top = 0;
597234543Sjasone
598234543Sjasone	if (totlen & ERR_RX) {
599234370Sjasone		++sc->arpcom.ac_if.if_ierrors;
600234370Sjasone		goto out;
601234543Sjasone	}
602234370Sjasone	save_totlen = totlen &= RX_BYTES_MASK;	/* Lower 11 bits = RX bytes. */
603234370Sjasone
604242844Sjasone	m = sc->mb[sc->next_mb];
605234370Sjasone	sc->mb[sc->next_mb] = 0;
606234370Sjasone
607234543Sjasone	if (m == 0) {
608234370Sjasone		MGETHDR(m, M_DONTWAIT, MT_DATA);
609234370Sjasone		if (m == 0)
610234543Sjasone			goto out;
611234370Sjasone	} else {
612234543Sjasone		/* Convert one of our saved mbuf's */
613234370Sjasone		sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
614234370Sjasone		m->m_data = m->m_pktdat;
615234370Sjasone		m->m_flags = M_PKTHDR;
616234543Sjasone	}
617234543Sjasone
618234543Sjasone	top = m0 = m;		/* We assign top so we can "goto out" */
619234543Sjasone#define EROUND  ((sizeof(struct ether_header) + 3) & ~3)
620234370Sjasone#define EOFF    (EROUND - sizeof(struct ether_header))
621234543Sjasone	m0->m_data += EOFF;
622234370Sjasone	/* Read what should be the header. */
623234543Sjasone	insw(BASE + EP_W1_RX_PIO_RD_1,
624234370Sjasone	    mtod(m0, caddr_t), sizeof(struct ether_header) / 2);
625234543Sjasone	m->m_len = sizeof(struct ether_header);
626234370Sjasone	totlen -= sizeof(struct ether_header);
627234543Sjasone	/*
628234543Sjasone 	 * mostly deal with trailer here.  (untested)
629234543Sjasone	 * We do this in a couple of parts.  First we check for a trailer, if
630234370Sjasone	 * we have one we convert the mbuf back to a regular mbuf and set the offset and
631234370Sjasone	 * subtract sizeof(struct ether_header) from the pktlen.
632234370Sjasone	 * After we've read the packet off the interface (all except for the trailer
633234370Sjasone	 * header, we then get a header mbuf, read the trailer into it, and fix up
634234370Sjasone	 * the mbuf pointer chain.
635234370Sjasone	 */
636234370Sjasone	eh = mtod(m, struct ether_header *);
637234370Sjasone	eh->ether_type = etype = ntohs((u_short) eh->ether_type);
638234370Sjasone	if (etype >= ETHERTYPE_TRAIL &&
639234370Sjasone	    etype < ETHERTYPE_TRAIL + ETHERTYPE_NTRAILER) {
640234370Sjasone		m->m_data = m->m_dat;	/* Convert back to regular mbuf.  */
641234370Sjasone		m->m_flags = 0;		/* This sucks but non-trailers are the norm */
642234370Sjasone		off = (etype - ETHERTYPE_TRAIL) * 512;
643234370Sjasone		if (off >= ETHERMTU) {
644234370Sjasone			m_freem(m);
645234370Sjasone			return;		/* sanity */
646234370Sjasone		}
647234370Sjasone		totlen -= sizeof(struct ether_header);	/* We don't read the trailer */
648234370Sjasone		m->m_data += 2 * sizeof(u_short);	/* Get rid of type & len */
649234370Sjasone	}
650234370Sjasone	while (totlen > 0) {
651234370Sjasone		lenthisone = min(totlen, M_TRAILINGSPACE(m));
652234370Sjasone		if (lenthisone == 0) {	/* no room in this one */
653234370Sjasone			mcur = m;
654234370Sjasone			m = sc->mb[sc->next_mb];
655234370Sjasone			sc->mb[sc->next_mb] = 0;
656234370Sjasone			if (!m) {
657234370Sjasone				MGET(m, M_DONTWAIT, MT_DATA);
658234370Sjasone				if (m == 0)
659234370Sjasone					goto out;
660234370Sjasone			} else {
661234370Sjasone				timeout(epmbufqueue, (caddr_t)sc, 0);
662234370Sjasone				sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
663234370Sjasone			}
664234370Sjasone			if (totlen >= MINCLSIZE)
665234370Sjasone				MCLGET(m, M_DONTWAIT);
666234370Sjasone			m->m_len = 0;
667234370Sjasone			mcur->m_next = m;
668234370Sjasone			lenthisone = min(totlen, M_TRAILINGSPACE(m));
669234370Sjasone		}
670234370Sjasone		insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len,
671234370Sjasone		    lenthisone / 2);
672234370Sjasone		m->m_len += lenthisone;
673234370Sjasone		if (lenthisone & 1)
674234370Sjasone			*(mtod(m, caddr_t) + m->m_len - 1) = inb(BASE + EP_W1_RX_PIO_RD_1);
675234370Sjasone		totlen -= lenthisone;
676235238Sjasone	}
677235238Sjasone	if (off) {
678234370Sjasone		top = sc->mb[sc->next_mb];
679234370Sjasone		sc->mb[sc->next_mb] = 0;
680234370Sjasone		if (top == 0) {
681234370Sjasone			MGETHDR(m, M_DONTWAIT, MT_DATA);
682234370Sjasone			if (top == 0)
683234370Sjasone				goto out;
684234370Sjasone		} else {
685234370Sjasone			/* Convert one of our saved mbuf's */
686234370Sjasone			sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
687234370Sjasone			top->m_data = top->m_pktdat;
688234370Sjasone			top->m_flags = M_PKTHDR;
689234370Sjasone		}
690234370Sjasone		insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len,
691234370Sjasone		    sizeof(struct ether_header));
692234370Sjasone		top->m_next = m0;
693234370Sjasone		top->m_len = sizeof(struct ether_header);
694234370Sjasone		/* XXX Accomodate for type and len from beginning of trailer */
695234370Sjasone		top->m_pkthdr.len = save_totlen - (2 * sizeof(u_short));
696234370Sjasone	} else {
697234370Sjasone		top = m0;
698234370Sjasone		top->m_pkthdr.len = save_totlen;
699234370Sjasone	}
700234370Sjasone
701234569Sjasone	top->m_pkthdr.rcvif = &sc->arpcom.ac_if;
702234370Sjasone	outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
703234370Sjasone	while (inb(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
704234370Sjasone		;
705234370Sjasone	++sc->arpcom.ac_if.if_ipackets;
706234370Sjasone#if NBPFILTER > 0
707234370Sjasone	if (sc->bpf) {
708234370Sjasone		bpf_mtap(sc->bpf, top);
709234370Sjasone
710234370Sjasone		/*
711234370Sjasone		 * Note that the interface cannot be in promiscuous mode if
712234370Sjasone		 * there are no BPF listeners.  And if we are in promiscuous
713234370Sjasone		 * mode, we have to check if this packet is really ours.
714234370Sjasone		 */
715234370Sjasone		if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) &&
716234370Sjasone		    (eh->ether_dhost[0] & 1) == 0 &&
717234370Sjasone		    bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
718234370Sjasone			 sizeof(eh->ether_dhost)) != 0 &&
719234370Sjasone		    bcmp(eh->ether_dhost, etherbroadcastaddr,
720234370Sjasone			 sizeof(eh->ether_dhost)) != 0) {
721234370Sjasone			m_freem(top);
722234370Sjasone			return;
723234370Sjasone		}
724234370Sjasone	}
725234370Sjasone#endif
726234370Sjasone	m_adj(top, sizeof(struct ether_header));
727234370Sjasone	ether_input(&sc->arpcom.ac_if, eh, top);
728234370Sjasone	return;
729234370Sjasone
730234370Sjasoneout:	outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
731234370Sjasone	while (inb(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
732234370Sjasone		;
733242844Sjasone	if (top)
734234370Sjasone		m_freem(top);
735242844Sjasone
736234370Sjasone	return;
737234370Sjasone}
738234370Sjasone
739234370Sjasone
740234370Sjasone/*
741234370Sjasone * Look familiar?
742234370Sjasone */
743234370Sjasonestatic int
744234370Sjasoneepioctl(ifp, cmd, data)
745234370Sjasone	register struct ifnet *ifp;
746234370Sjasone	int     cmd;
747234370Sjasone	caddr_t data;
748234370Sjasone{
749234370Sjasone	register struct ifaddr *ifa = (struct ifaddr *) data;
750234370Sjasone	struct ep_softc *sc = &ep_softc[ifp->if_unit];
751234370Sjasone	struct ifreq *ifr = (struct ifreq *) data;
752234370Sjasone	int s, error = 0;
753234370Sjasone
754234370Sjasone	switch (cmd) {
755234370Sjasone	case SIOCSIFADDR:
756234370Sjasone		ifp->if_flags |= IFF_UP;
757234370Sjasone		switch (ifa->ifa_addr->sa_family) {
758234370Sjasone#ifdef INET
759234370Sjasone		case AF_INET:
760234370Sjasone			epinit(ifp->if_unit);	/* before arpwhohas */
761234370Sjasone			((struct arpcom *) ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr;
762234370Sjasone			arpwhohas((struct arpcom *) ifp, &IA_SIN(ifa)->sin_addr);
763234370Sjasone			break;
764234370Sjasone#endif
765234370Sjasone#ifdef NS
766234370Sjasone		case AF_NS:
767234370Sjasone		{
768234370Sjasone			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
769234370Sjasone
770234370Sjasone			if (ns_nullhost(*ina))
771234370Sjasone				ina->x_host =
772234370Sjasone					*(union ns_host *)(sc->arpcom.ac_enaddr);
773234370Sjasone			else {
774234370Sjasone				ifp->if_flags &= ~IFF_RUNNING;
775234370Sjasone				bcopy((caddr_t) ina->x_host.c_host,
776234370Sjasone					(caddr_t)sc->arpcom.ac_enaddr,
777234370Sjasone					sizeof(sc->arpcom.ac_enaddr));
778234370Sjasone			}
779234370Sjasone			epinit(ifp->if_unit);
780234370Sjasone			break;
781234370Sjasone		}
782234370Sjasone#endif
783234370Sjasone		default:
784234370Sjasone			epinit(ifp->if_unit);
785234370Sjasone			break;
786234370Sjasone		}
787234370Sjasone		break;
788234370Sjasone	case SIOCSIFFLAGS:
789234370Sjasone		if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) {
790234370Sjasone			ifp->if_flags &= ~IFF_RUNNING;
791234370Sjasone			epstop(ifp->if_unit);
792234370Sjasone			break;
793242844Sjasone		}
794234370Sjasone		if (ifp->if_flags & IFF_UP && (ifp->if_flags & IFF_RUNNING) == 0)
795234370Sjasone			epinit(ifp->if_unit);
796234370Sjasone		break;
797234370Sjasone#ifdef notdef
798234370Sjasone	case SIOCGHWADDR:
799242844Sjasone		bcopy((caddr_t) sc->sc_addr, (caddr_t) &ifr->ifr_data,
800242844Sjasone		    sizeof(sc->sc_addr));
801234370Sjasone		break;
802242844Sjasone#endif
803234370Sjasone	default:
804242844Sjasone		error = EINVAL;
805234370Sjasone	}
806234370Sjasone	return (error);
807242844Sjasone}
808234370Sjasone
809234370Sjasonevoid
810234370Sjasoneepreset(unit)
811234370Sjasone	int     unit;
812234370Sjasone{
813234370Sjasone	int s = splimp();
814234370Sjasone
815234370Sjasone	epstop(unit);
816242844Sjasone	epinit(unit);
817234370Sjasone	splx(s);
818234370Sjasone	return;
819234370Sjasone}
820234370Sjasone
821234370Sjasonevoid
822234370Sjasoneepwatchdog(unit)
823234370Sjasone	int     unit;
824234370Sjasone{
825234370Sjasone	struct ep_softc *sc = &ep_softc[unit];
826234370Sjasone
827234370Sjasone	log(LOG_ERR, "ep%d: watchdog\n", unit);
828234370Sjasone	++sc->arpcom.ac_if.if_oerrors;
829234370Sjasone
830234370Sjasone	epreset(unit);
831234370Sjasone}
832234370Sjasone
833234370Sjasonevoid
834234370Sjasoneepstop(unit)
835234370Sjasone	int     unit;
836234370Sjasone{
837235238Sjasone	struct ep_softc *sc = &ep_softc[unit];
838234370Sjasone
839234370Sjasone	outw(BASE + EP_COMMAND, RX_DISABLE);
840234370Sjasone	outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
841234370Sjasone	while (inb(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
842234370Sjasone		;
843234370Sjasone	outw(BASE + EP_COMMAND, TX_DISABLE);
844234370Sjasone	outw(BASE + EP_COMMAND, STOP_TRANSCEIVER);
845234370Sjasone	outw(BASE + EP_COMMAND, RX_RESET);
846234370Sjasone	outw(BASE + EP_COMMAND, TX_RESET);
847234370Sjasone	outw(BASE + EP_COMMAND, C_INTR_LATCH);
848234370Sjasone	outw(BASE + EP_COMMAND, SET_RD_0_MASK);
849234370Sjasone	outw(BASE + EP_COMMAND, SET_INTR_MASK);
850234370Sjasone	outw(BASE + EP_COMMAND, SET_RX_FILTER);
851234370Sjasone	return;
852234370Sjasone}
853234370Sjasone
854234370Sjasone
855234370Sjasone/*
856234370Sjasone * This is adapted straight from the book. There's probably a better way.
857234370Sjasone */
858234370Sjasonestatic int
859234370Sjasonesend_ID_sequence(port)
860234370Sjasone	u_short port;
861234370Sjasone{
862234370Sjasone	char    cx, al;
863234370Sjasone
864234370Sjasone	cx = 0x0ff;
865234370Sjasone	al = 0x0ff;
866234370Sjasone
867234370Sjasone	outb(port, 0x0);
868234370Sjasone	DELAY(1000);
869234370Sjasone	outb(port, 0x0);
870234370Sjasone	DELAY(1000);
871234370Sjasone
872234370Sjasoneloop1:	cx--;
873234370Sjasone	outb(port, al);
874234370Sjasone	if (!(al & 0x80)) {
875235238Sjasone		al = al << 1;
876234370Sjasone		goto loop1;
877234370Sjasone	}
878234370Sjasone	al = al << 1;
879234370Sjasone	al ^= 0xcf;
880234370Sjasone	if (cx)
881234370Sjasone		goto loop1;
882234370Sjasone
883234370Sjasone	return(1);
884234370Sjasone}
885234370Sjasone
886234370Sjasone
887234370Sjasone/*
888234370Sjasone * We get eeprom data from the id_port given an offset into the
889234370Sjasone * eeprom.  Basically; after the ID_sequence is sent to all of
890234370Sjasone * the cards; they enter the ID_CMD state where they will accept
891234370Sjasone * command requests. 0x80-0xbf loads the eeprom data.  We then
892234370Sjasone * read the port 16 times and with every read; the cards check
893234370Sjasone * for contention (ie: if one card writes a 0 bit and another
894234370Sjasone * writes a 1 bit then the host sees a 0. At the end of the cycle;
895234370Sjasone * each card compares the data on the bus; if there is a difference
896234370Sjasone * then that card goes into ID_WAIT state again). In the meantime;
897234370Sjasone * one bit of data is returned in the AX register which is conveniently
898234370Sjasone * returned to us by inb().  Hence; we read 16 times getting one
899234370Sjasone * bit of data with each read.
900234370Sjasone */
901234370Sjasonestatic u_short
902234370Sjasoneget_eeprom_data(id_port, offset)
903234370Sjasone	int     id_port;
904234370Sjasone	int     offset;
905234370Sjasone{
906234370Sjasone	int     i, data = 0;
907234370Sjasone	outb(id_port, 0x80 + offset);
908234370Sjasone	DELAY(1000);
909234370Sjasone	for (i = 0; i < 16; i++)
910234370Sjasone		data = (data << 1) | (inw(id_port) & 1);
911234370Sjasone	return (data);
912234370Sjasone}
913234370Sjasone
914234370Sjasonestatic int
915234370Sjasoneis_eeprom_busy(is)
916234370Sjasone	struct isa_device *is;
917234370Sjasone{
918234370Sjasone	int     i = 0, j;
919234370Sjasone	register struct ep_softc *sc = &ep_softc[is->id_unit];
920234370Sjasone
921234370Sjasone	while (i++ < 100) {
922234370Sjasone		j = inw(BASE + EP_W0_EEPROM_COMMAND);
923234370Sjasone		if (j & EEPROM_BUSY)
924234370Sjasone			DELAY(100);
925234370Sjasone		else
926234370Sjasone			break;
927234370Sjasone	}
928234370Sjasone	if (i >= 100) {
929234370Sjasone		printf("\nep%d: eeprom failed to come ready.\n", is->id_unit);
930234370Sjasone		return (1);
931234370Sjasone	}
932234370Sjasone	if (j & EEPROM_TST_MODE) {
933234370Sjasone		printf("\nep%d: 3c509 in test mode. Erase pencil mark!\n", is->id_unit);
934234370Sjasone		return (1);
935234370Sjasone	}
936234370Sjasone	return (0);
937234370Sjasone}
938234370Sjasone
939234370Sjasonevoid
940234370Sjasoneepmbufqueue(sp, dummy_arg)
941234370Sjasone	caddr_t sp;
942234370Sjasone	int dummy_arg;
943234370Sjasone{
944234370Sjasone	struct ep_softc *sc = (struct ep_softc *)sp;
945234370Sjasone	int     i;
946234370Sjasone
947234370Sjasone	if (sc->mb[sc->last_mb])
948234370Sjasone		return;
949234370Sjasone	i = sc->last_mb;
950234370Sjasone	do {
951234370Sjasone		MGET(sc->mb[i], M_DONTWAIT, MT_DATA);
952234370Sjasone		if (!sc->mb[i])
953234370Sjasone			break;
954234370Sjasone		i = (i + 1) % MAX_MBS;
955234370Sjasone	} while (i != sc->next_mb);
956234370Sjasone	sc->last_mb = i;
957234370Sjasone	return;
958234370Sjasone}
959234370Sjasone
960234370Sjasone#endif /* NEP > 0 */
961234370Sjasone