xref: /openbsd-src/sys/dev/isa/if_eg.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: if_eg.c,v 1.34 2013/11/15 16:46:27 brad Exp $	*/
2 /*	$NetBSD: if_eg.c,v 1.26 1996/05/12 23:52:27 mycroft Exp $	*/
3 
4 /*
5  * Copyright (c) 1993 Dean Huxley <dean@fsa.ca>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by Dean Huxley.
19  * 4. The name of Dean Huxley may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 /*
34  * Support for 3Com 3c505 Etherlink+ card.
35  */
36 
37 /* To do:
38  * - multicast
39  * - promiscuous
40  */
41 #include "bpfilter.h"
42 
43 #include <sys/types.h>
44 #include <sys/param.h>
45 #include <sys/mbuf.h>
46 #include <sys/socket.h>
47 #include <sys/ioctl.h>
48 #include <sys/errno.h>
49 #include <sys/syslog.h>
50 #include <sys/systm.h>
51 #include <sys/selinfo.h>
52 #include <sys/device.h>
53 
54 #include <net/if.h>
55 #include <net/if_dl.h>
56 #include <net/if_types.h>
57 #include <net/netisr.h>
58 
59 #ifdef INET
60 #include <netinet/in.h>
61 #include <netinet/in_systm.h>
62 #include <netinet/ip.h>
63 #include <netinet/if_ether.h>
64 #endif
65 
66 #if NBPFILTER > 0
67 #include <net/bpf.h>
68 #endif
69 
70 #include <machine/cpu.h>
71 #include <machine/intr.h>
72 
73 #include <dev/isa/isavar.h>
74 #include <dev/isa/if_egreg.h>
75 #include <dev/isa/elink.h>
76 
77 /* for debugging convenience */
78 #ifdef EGDEBUG
79 #define DPRINTF(x) printf x
80 #else
81 #define DPRINTF(x)
82 #endif
83 
84 #define EG_INLEN  	10
85 #define EG_BUFLEN	0x0670
86 
87 /*
88  * Ethernet software status per interface.
89  */
90 struct eg_softc {
91 	struct device sc_dev;
92 	void *sc_ih;
93 	bus_space_tag_t sc_bst;
94 	bus_space_handle_t sc_bsh;
95 	struct arpcom sc_arpcom;	/* Ethernet common part */
96 	u_char  eg_rom_major;		/* Cards ROM version (major number) */
97 	u_char  eg_rom_minor;		/* Cards ROM version (minor number) */
98 	short	eg_ram;			/* Amount of RAM on the card */
99 	u_char	eg_pcb[64];		/* Primary Command Block buffer */
100 	u_char  eg_incount;		/* Number of buffers currently used */
101 	u_char  *eg_inbuf;		/* Incoming packet buffer */
102 	u_char	*eg_outbuf;		/* Outgoing packet buffer */
103 };
104 
105 int egprobe(struct device *, void *, void *);
106 void egattach(struct device *, struct device *, void *);
107 
108 struct cfattach eg_ca = {
109 	sizeof(struct eg_softc), egprobe, egattach
110 };
111 
112 struct cfdriver eg_cd = {
113 	NULL, "eg", DV_IFNET
114 };
115 
116 int egintr(void *);
117 void eginit(struct eg_softc *);
118 int egioctl(struct ifnet *, u_long, caddr_t);
119 void egrecv(struct eg_softc *);
120 void egstart(struct ifnet *);
121 void egwatchdog(struct ifnet *);
122 void egreset(struct eg_softc *);
123 void egread(struct eg_softc *, caddr_t, int);
124 struct mbuf *egget(struct eg_softc *, caddr_t, int);
125 void egstop(struct eg_softc *);
126 
127 static __inline void egprintpcb(struct eg_softc *);
128 static __inline void egprintstat(u_char);
129 static int egoutPCB(struct eg_softc *, u_char);
130 static int egreadPCBstat(struct eg_softc *, u_char);
131 static int egreadPCBready(struct eg_softc *);
132 static int egwritePCB(struct eg_softc *);
133 static int egreadPCB(struct eg_softc *);
134 
135 /*
136  * Support stuff
137  */
138 
139 static __inline void
140 egprintpcb(struct eg_softc *sc)
141 {
142 	int i;
143 
144 	for (i = 0; i < sc->eg_pcb[1] + 2; i++)
145 		DPRINTF(("pcb[%2d] = %x\n", i, sc->eg_pcb[i]));
146 }
147 
148 
149 static __inline void
150 egprintstat(u_char b)
151 {
152 	DPRINTF(("%s %s %s %s %s %s %s\n",
153 	    (b & EG_STAT_HCRE)?"HCRE":"",
154 	    (b & EG_STAT_ACRF)?"ACRF":"",
155 	    (b & EG_STAT_DIR )?"DIR ":"",
156 	    (b & EG_STAT_DONE)?"DONE":"",
157 	    (b & EG_STAT_ASF3)?"ASF3":"",
158 	    (b & EG_STAT_ASF2)?"ASF2":"",
159 	    (b & EG_STAT_ASF1)?"ASF1":""));
160 }
161 
162 static int
163 egoutPCB(struct eg_softc *sc, u_char b)
164 {
165 	bus_space_tag_t bst = sc->sc_bst;
166 	bus_space_handle_t bsh = sc->sc_bsh;
167 	int i;
168 
169 	for (i = 0; i < 4000; i++) {
170 		if (bus_space_read_1(bst, bsh, EG_STATUS) & EG_STAT_HCRE) {
171 			bus_space_write_1(bst, bsh, EG_COMMAND, b);
172 			return 0;
173 		}
174 		delay(10);
175 	}
176 	DPRINTF(("egoutPCB failed\n"));
177 	return (1);
178 }
179 
180 static int
181 egreadPCBstat(struct eg_softc *sc, u_char statb)
182 {
183 	bus_space_tag_t bst = sc->sc_bst;
184 	bus_space_handle_t bsh = sc->sc_bsh;
185 	int i;
186 
187 	for (i=0; i < 5000; i++) {
188 		if ((bus_space_read_1(bst, bsh, EG_STATUS) & EG_PCB_STAT) !=
189 		    EG_PCB_NULL)
190 			break;
191 		delay(10);
192 	}
193 	if ((bus_space_read_1(bst, bsh, EG_STATUS) & EG_PCB_STAT) == statb)
194 		return (0);
195 	return (1);
196 }
197 
198 static int
199 egreadPCBready(struct eg_softc *sc)
200 {
201 	bus_space_tag_t bst = sc->sc_bst;
202 	bus_space_handle_t bsh = sc->sc_bsh;
203 	int i;
204 
205 	for (i=0; i < 10000; i++) {
206 		if (bus_space_read_1(bst, bsh, EG_STATUS) & EG_STAT_ACRF)
207 			return (0);
208 		delay(5);
209 	}
210 	DPRINTF(("PCB read not ready status %02x\n",
211 	    bus_space_read_1(bst, bsh, EG_STATUS)));
212 	return (1);
213 }
214 
215 static int
216 egwritePCB(struct eg_softc *sc)
217 {
218 	bus_space_tag_t bst = sc->sc_bst;
219 	bus_space_handle_t bsh = sc->sc_bsh;
220 	int i;
221 	u_char len;
222 
223 	bus_space_write_1(bst, bsh, EG_CONTROL,
224 	    (bus_space_read_1(bst, bsh, EG_CONTROL) & ~EG_PCB_STAT) |
225 	    EG_PCB_NULL);
226 
227 	len = sc->eg_pcb[1] + 2;
228 	for (i = 0; i < len; i++)
229 		egoutPCB(sc, sc->eg_pcb[i]);
230 
231 	for (i=0; i < 4000; i++) {
232 		if (bus_space_read_1(bst, bsh, EG_STATUS) & EG_STAT_HCRE)
233 			break;
234 		delay(10);
235 	}
236 
237 	bus_space_write_1(bst, bsh, EG_CONTROL,
238 	    (bus_space_read_1(bst, bsh, EG_CONTROL) & ~EG_PCB_STAT) |
239 	    EG_PCB_DONE);
240 
241 	egoutPCB(sc, len);
242 
243 	if (egreadPCBstat(sc, EG_PCB_ACCEPT))
244 		return (1);
245 	return (0);
246 }
247 
248 static int
249 egreadPCB(struct eg_softc *sc)
250 {
251 	bus_space_tag_t bst = sc->sc_bst;
252 	bus_space_handle_t bsh = sc->sc_bsh;
253 	int i;
254 	u_char b;
255 
256 	bus_space_write_1(bst, bsh, EG_CONTROL,
257 	    (bus_space_read_1(bst, bsh, EG_CONTROL) & ~EG_PCB_STAT) |
258 	    EG_PCB_NULL);
259 
260 	bzero(sc->eg_pcb, sizeof(sc->eg_pcb));
261 
262 	if (egreadPCBready(sc))
263 		return (1);
264 
265 	sc->eg_pcb[0] = bus_space_read_1(bst, bsh, EG_COMMAND);
266 
267 	if (egreadPCBready(sc))
268 		return (1);
269 
270 	sc->eg_pcb[1] = bus_space_read_1(bst, bsh, EG_COMMAND);
271 
272 	if (sc->eg_pcb[1] > 62) {
273 		DPRINTF(("len %d too large\n", sc->eg_pcb[1]));
274 		return (1);
275 	}
276 
277 	for (i = 0; i < sc->eg_pcb[1]; i++) {
278 		if (egreadPCBready(sc))
279 			return (1);
280 		sc->eg_pcb[2+i] = bus_space_read_1(bst, bsh, EG_COMMAND);
281 	}
282 	if (egreadPCBready(sc))
283 		return (1);
284 	if (egreadPCBstat(sc, EG_PCB_DONE))
285 		return (1);
286 	if ((b = bus_space_read_1(bst, bsh, EG_COMMAND)) != sc->eg_pcb[1] + 2) {
287 		DPRINTF(("%d != %d\n", b, sc->eg_pcb[1] + 2));
288 		return (1);
289 	}
290 
291 	bus_space_write_1(bst, bsh, EG_CONTROL,
292 	    (bus_space_read_1(bst, bsh, EG_CONTROL) & ~EG_PCB_STAT) |
293 	    EG_PCB_ACCEPT);
294 
295 	return (0);
296 }
297 
298 /*
299  * Real stuff
300  */
301 
302 int
303 egprobe(struct device *parent, void *match, void *aux)
304 {
305 	struct eg_softc *sc = match;
306 	struct isa_attach_args *ia = aux;
307 	bus_space_tag_t bst = sc->sc_bst = ia->ia_iot;
308 	bus_space_handle_t bsh;
309 	int i;
310 
311 	if ((ia->ia_iobase & ~0x07f0) != 0) {
312 		DPRINTF(("Weird iobase %x\n", ia->ia_iobase));
313 		return (0);
314 	}
315 
316 	if (bus_space_map(bst, ia->ia_iobase, EG_IO_PORTS, 0, &bsh)) {
317 		DPRINTF(("%s: can't map i/o space\n", sc->sc_dev.dv_xname));
318 		return (0);
319 	}
320 	sc->sc_bsh = bsh;
321 
322 	/* hard reset card */
323 	bus_space_write_1(bst, bsh, EG_CONTROL, EG_CTL_RESET);
324 	bus_space_write_1(bst, bsh, EG_CONTROL, 0);
325 	for (i = 0; i < 5000; i++) {
326 		delay(1000);
327 		if ((bus_space_read_1(bst, bsh, EG_STATUS) & EG_PCB_STAT) ==
328 		    EG_PCB_NULL)
329 			break;
330 	}
331 	if ((bus_space_read_1(bst, bsh, EG_STATUS) & EG_PCB_STAT) !=
332 	    EG_PCB_NULL) {
333 		DPRINTF(("eg: Reset failed\n"));
334 		goto lose;
335 	}
336 	sc->eg_pcb[0] = EG_CMD_GETINFO; /* Get Adapter Info */
337 	sc->eg_pcb[1] = 0;
338 	if (egwritePCB(sc) != 0)
339 		goto lose;
340 
341 	if (egreadPCB(sc) != 0) {
342 		egprintpcb(sc);
343 		goto lose;
344 	}
345 
346 	if (sc->eg_pcb[0] != EG_RSP_GETINFO || /* Get Adapter Info Response */
347 	    sc->eg_pcb[1] != 0x0a) {
348 		egprintpcb(sc);
349 		goto lose;
350 	}
351 	sc->eg_rom_major = sc->eg_pcb[3];
352 	sc->eg_rom_minor = sc->eg_pcb[2];
353 	sc->eg_ram = sc->eg_pcb[6] | (sc->eg_pcb[7] << 8);
354 
355 	ia->ia_iosize = 0x08;
356 	ia->ia_msize = 0;
357 	bus_space_unmap(bst, bsh, EG_IO_PORTS);
358 	return (1);
359 
360 lose:
361 	bus_space_unmap(bst, bsh, EG_IO_PORTS);
362 	return (0);
363 }
364 
365 void
366 egattach(struct device *parent, struct device *self, void *aux)
367 {
368 	struct eg_softc *sc = (void *)self;
369 	struct isa_attach_args *ia = aux;
370 	bus_space_tag_t bst = sc->sc_bst = ia->ia_iot;
371 	bus_space_handle_t bsh;
372 	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
373 
374 	if (bus_space_map(bst, ia->ia_iobase, EG_IO_PORTS, 0, &bsh)) {
375 		printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname);
376 		return;
377 	}
378 	sc->sc_bsh = bsh;
379 
380 	egstop(sc);
381 
382 	sc->eg_pcb[0] = EG_CMD_GETEADDR; /* Get Station address */
383 	sc->eg_pcb[1] = 0;
384 	if (egwritePCB(sc) != 0) {
385 		DPRINTF(("write error\n"));
386 		return;
387 	}
388 	if (egreadPCB(sc) != 0) {
389 		DPRINTF(("read error\n"));
390 		egprintpcb(sc);
391 		return;
392 	}
393 
394 	/* check Get station address response */
395 	if (sc->eg_pcb[0] != EG_RSP_GETEADDR || sc->eg_pcb[1] != 0x06) {
396 		DPRINTF(("parse error\n"));
397 		egprintpcb(sc);
398 		return;
399 	}
400 	bcopy(&sc->eg_pcb[2], sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
401 
402 	printf(": ROM v%d.%02d %dk address %s\n",
403 	    sc->eg_rom_major, sc->eg_rom_minor, sc->eg_ram,
404 	    ether_sprintf(sc->sc_arpcom.ac_enaddr));
405 
406 	sc->eg_pcb[0] = EG_CMD_SETEADDR; /* Set station address */
407 	if (egwritePCB(sc) != 0) {
408 		DPRINTF(("write error2\n"));
409 		return;
410 	}
411 	if (egreadPCB(sc) != 0) {
412 		DPRINTF(("read error2\n"));
413 		egprintpcb(sc);
414 		return;
415 	}
416 	if (sc->eg_pcb[0] != EG_RSP_SETEADDR || sc->eg_pcb[1] != 0x02 ||
417 	    sc->eg_pcb[2] != 0 || sc->eg_pcb[3] != 0) {
418 		DPRINTF(("parse error2\n"));
419 		egprintpcb(sc);
420 		return;
421 	}
422 
423 	/* Initialize ifnet structure. */
424 	bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
425 	ifp->if_softc = sc;
426 	ifp->if_start = egstart;
427 	ifp->if_ioctl = egioctl;
428 	ifp->if_watchdog = egwatchdog;
429 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
430 	IFQ_SET_READY(&ifp->if_snd);
431 
432 	/* Now we can attach the interface. */
433 	if_attach(ifp);
434 	ether_ifattach(ifp);
435 
436 	sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
437 	    IPL_NET, egintr, sc, sc->sc_dev.dv_xname);
438 }
439 
440 void
441 eginit(register struct eg_softc *sc)
442 {
443 	bus_space_tag_t bst = sc->sc_bst;
444 	bus_space_handle_t bsh = sc->sc_bsh;
445 	register struct ifnet *ifp = &sc->sc_arpcom.ac_if;
446 
447 	/* soft reset the board */
448 	bus_space_write_1(bst, bsh, EG_CONTROL, EG_CTL_FLSH);
449 	delay(100);
450 	bus_space_write_1(bst, bsh, EG_CONTROL, EG_CTL_ATTN);
451 	delay(100);
452 	bus_space_write_1(bst, bsh, EG_CONTROL, 0);
453 	delay(200);
454 
455 	sc->eg_pcb[0] = EG_CMD_CONFIG82586; /* Configure 82586 */
456 	sc->eg_pcb[1] = 2;
457 	sc->eg_pcb[2] = 3; /* receive broadcast & multicast */
458 	sc->eg_pcb[3] = 0;
459 	if (egwritePCB(sc) != 0)
460 		DPRINTF(("write error3\n"));
461 
462 	if (egreadPCB(sc) != 0) {
463 		DPRINTF(("read error3\n"));
464 		egprintpcb(sc);
465 	} else if (sc->eg_pcb[2] != 0 || sc->eg_pcb[3] != 0)
466 		printf("%s: configure card command failed\n",
467 		    sc->sc_dev.dv_xname);
468 
469 	if (sc->eg_inbuf == 0)
470 		sc->eg_inbuf = malloc(EG_BUFLEN, M_TEMP, M_NOWAIT);
471 	sc->eg_incount = 0;
472 
473 	if (sc->eg_outbuf == 0)
474 		sc->eg_outbuf = malloc(EG_BUFLEN, M_TEMP, M_NOWAIT);
475 
476 	bus_space_write_1(bst, bsh, EG_CONTROL, EG_CTL_CMDE);
477 
478 	sc->eg_incount = 0;
479 	egrecv(sc);
480 
481 	/* Interface is now `running', with no output active. */
482 	ifp->if_flags |= IFF_RUNNING;
483 	ifp->if_flags &= ~IFF_OACTIVE;
484 
485 	/* Attempt to start output, if any. */
486 	egstart(ifp);
487 }
488 
489 void
490 egrecv(struct eg_softc *sc)
491 {
492 	while (sc->eg_incount < EG_INLEN) {
493 		sc->eg_pcb[0] = EG_CMD_RECVPACKET;
494 		sc->eg_pcb[1] = 0x08;
495 		sc->eg_pcb[2] = 0; /* address not used.. we send zero */
496 		sc->eg_pcb[3] = 0;
497 		sc->eg_pcb[4] = 0;
498 		sc->eg_pcb[5] = 0;
499 		sc->eg_pcb[6] = EG_BUFLEN & 0xff; /* our buffer size */
500 		sc->eg_pcb[7] = (EG_BUFLEN >> 8) & 0xff;
501 		sc->eg_pcb[8] = 0; /* timeout, 0 == none */
502 		sc->eg_pcb[9] = 0;
503 		if (egwritePCB(sc) != 0)
504 			break;
505 		sc->eg_incount++;
506 	}
507 }
508 
509 void
510 egstart(struct ifnet *ifp)
511 {
512 	struct eg_softc *sc = ifp->if_softc;
513 	bus_space_tag_t bst = sc->sc_bst;
514 	bus_space_handle_t bsh = sc->sc_bsh;
515 	struct mbuf *m0, *m;
516 	caddr_t buffer;
517 	int len;
518 	u_short *ptr;
519 	u_int i;
520 
521 	/* Don't transmit if interface is busy or not running */
522 	if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
523 		return;
524 
525 loop:
526 	/* Dequeue the next datagram. */
527 	IFQ_DEQUEUE(&ifp->if_snd, m0);
528 	if (m0 == 0)
529 		return;
530 
531 	ifp->if_flags |= IFF_OACTIVE;
532 
533 	/* We need to use m->m_pkthdr.len, so require the header */
534 	if ((m0->m_flags & M_PKTHDR) == 0)
535 		panic("egstart: no header mbuf");
536 	len = max(m0->m_pkthdr.len, ETHER_MIN_LEN);
537 
538 #if NBPFILTER > 0
539 	if (ifp->if_bpf)
540 		bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
541 #endif
542 
543 	sc->eg_pcb[0] = EG_CMD_SENDPACKET;
544 	sc->eg_pcb[1] = 0x06;
545 	sc->eg_pcb[2] = 0; /* address not used, we send zero */
546 	sc->eg_pcb[3] = 0;
547 	sc->eg_pcb[4] = 0;
548 	sc->eg_pcb[5] = 0;
549 	sc->eg_pcb[6] = len; /* length of packet */
550 	sc->eg_pcb[7] = len >> 8;
551 	if (egwritePCB(sc) != 0) {
552 		DPRINTF(("egwritePCB in egstart failed\n"));
553 		ifp->if_oerrors++;
554 		ifp->if_flags &= ~IFF_OACTIVE;
555 		m_freem(m0);
556 		goto loop;
557 	}
558 
559 	buffer = sc->eg_outbuf;
560 	for (m = m0; m != 0; m = m->m_next) {
561 		bcopy(mtod(m, caddr_t), buffer, m->m_len);
562 		buffer += m->m_len;
563 	}
564 	if (len > m0->m_pkthdr.len)
565 		bzero(buffer, len - m0->m_pkthdr.len);
566 
567 	/* set direction bit: host -> adapter */
568 	bus_space_write_1(bst, bsh, EG_CONTROL,
569 	    bus_space_read_1(bst, bsh, EG_CONTROL) & ~EG_CTL_DIR);
570 
571 	for (ptr = (u_short *)sc->eg_outbuf; len > 0; len -= 2) {
572 		bus_space_write_2(bst, bsh, EG_DATA, *ptr++);
573 		for (i = 10000; i != 0; i--) {
574 			if (bus_space_read_1(bst, bsh, EG_STATUS) & EG_STAT_HRDY)
575 				break;
576 			delay(10);
577 		}
578 		if (i == 0) {
579 			printf("%s: start failed\n", sc->sc_dev.dv_xname);
580 			break;
581 		}
582 	}
583 
584 	m_freem(m0);
585 }
586 
587 int
588 egintr(void *arg)
589 {
590 	struct eg_softc *sc = arg;
591 	bus_space_tag_t bst = sc->sc_bst;
592 	bus_space_handle_t bsh = sc->sc_bsh;
593 	int ret = 0;
594 	int i, len;
595 	u_short *ptr;
596 
597 	while (bus_space_read_1(bst, bsh, EG_STATUS) & EG_STAT_ACRF) {
598 		ret = 1;
599 		egreadPCB(sc);
600 		switch (sc->eg_pcb[0]) {
601 		case EG_RSP_RECVPACKET:
602 			len = sc->eg_pcb[6] | (sc->eg_pcb[7] << 8);
603 
604 			/* Set direction bit : Adapter -> host */
605 			bus_space_write_1(bst, bsh, EG_CONTROL,
606 			    bus_space_read_1(bst, bsh, EG_CONTROL) |
607 			    EG_CTL_DIR);
608 
609 			for (ptr = (u_short *)sc->eg_inbuf; len > 0; len -= 2) {
610 				for (i = 10000; i != 0; i--) {
611 					if (bus_space_read_1(bst, bsh, EG_STATUS) & EG_STAT_HRDY)
612 						break;
613 					delay(10);
614 				}
615 				if (i == 0) {
616 					printf("%s: receive failed\n",
617 					    sc->sc_dev.dv_xname);
618 					break;
619 				}
620 				*ptr++ = bus_space_read_2(bst, bsh, EG_DATA);
621 			}
622 
623 			if (len <= 0) {
624 				len = sc->eg_pcb[8] | (sc->eg_pcb[9] << 8);
625 				egread(sc, sc->eg_inbuf, len);
626 
627 				sc->eg_incount--;
628 				egrecv(sc);
629 			}
630 			break;
631 
632 		case EG_RSP_SENDPACKET:
633 			if (sc->eg_pcb[6] || sc->eg_pcb[7]) {
634 				DPRINTF(("packet dropped\n"));
635 				sc->sc_arpcom.ac_if.if_oerrors++;
636 			} else
637 				sc->sc_arpcom.ac_if.if_opackets++;
638 			sc->sc_arpcom.ac_if.if_collisions +=
639 			    sc->eg_pcb[8] & 0xf;
640 			sc->sc_arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
641 			egstart(&sc->sc_arpcom.ac_if);
642 			break;
643 
644 		case EG_RSP_GETSTATS:
645 			DPRINTF(("Card Statistics\n"));
646 			bcopy(&sc->eg_pcb[2], &i, sizeof(i));
647 			DPRINTF(("Receive Packets %d\n", i));
648 			bcopy(&sc->eg_pcb[6], &i, sizeof(i));
649 			DPRINTF(("Transmit Packets %d\n", i));
650 			DPRINTF(("CRC errors %d\n", *(short *)&sc->eg_pcb[10]));
651 			DPRINTF(("alignment errors %d\n",
652 			    *(short *)&sc->eg_pcb[12]));
653 			DPRINTF(("no resources errors %d\n",
654 			    *(short *)&sc->eg_pcb[14]));
655 			DPRINTF(("overrun errors %d\n",
656 			    *(short *)&sc->eg_pcb[16]));
657 			break;
658 
659 		default:
660 			DPRINTF(("egintr: Unknown response %x??\n",
661 			    sc->eg_pcb[0]));
662 			egprintpcb(sc);
663 			break;
664 		}
665 	}
666 
667 	return (ret);
668 }
669 
670 /*
671  * Pass a packet up to the higher levels.
672  */
673 void
674 egread(struct eg_softc *sc, caddr_t buf, int len)
675 {
676 	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
677 	struct mbuf *m;
678 
679 	if (len <= sizeof(struct ether_header) ||
680 	    len > ETHER_MAX_LEN) {
681 		printf("%s: invalid packet size %d; dropping\n",
682 		    sc->sc_dev.dv_xname, len);
683 		ifp->if_ierrors++;
684 		return;
685 	}
686 
687 	/* Pull packet off interface. */
688 	m = egget(sc, buf, len);
689 	if (m == 0) {
690 		ifp->if_ierrors++;
691 		return;
692 	}
693 
694 	ifp->if_ipackets++;
695 
696 #if NBPFILTER > 0
697 	/*
698 	 * Check if there's a BPF listener on this interface.
699 	 * If so, hand off the raw packet to BPF.
700 	 */
701 	if (ifp->if_bpf)
702 		bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
703 #endif
704 
705 	ether_input_mbuf(ifp, m);
706 }
707 
708 /*
709  * convert buf into mbufs
710  */
711 struct mbuf *
712 egget(struct eg_softc *sc, caddr_t buf, int totlen)
713 {
714 	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
715 	struct mbuf *top, **mp, *m;
716 	int len;
717 
718 	MGETHDR(m, M_DONTWAIT, MT_DATA);
719 	if (m == 0)
720 		return (0);
721 	m->m_pkthdr.rcvif = ifp;
722 	m->m_pkthdr.len = totlen;
723 	len = MHLEN;
724 	top = 0;
725 	mp = &top;
726 
727 	while (totlen > 0) {
728 		if (top) {
729 			MGET(m, M_DONTWAIT, MT_DATA);
730 			if (m == 0) {
731 				m_freem(top);
732 				return (0);
733 			}
734 			len = MLEN;
735 		}
736 		if (totlen >= MINCLSIZE) {
737 			MCLGET(m, M_DONTWAIT);
738 			if (m->m_flags & M_EXT)
739 				len = MCLBYTES;
740 		}
741 		m->m_len = len = min(totlen, len);
742 		bcopy((caddr_t)buf, mtod(m, caddr_t), len);
743 		buf += len;
744 		totlen -= len;
745 		*mp = m;
746 		mp = &m->m_next;
747 	}
748 
749 	return (top);
750 }
751 
752 int
753 egioctl(register struct ifnet *ifp, u_long cmd, caddr_t data)
754 {
755 	struct eg_softc *sc = ifp->if_softc;
756 	struct ifaddr *ifa = (struct ifaddr *)data;
757 	int s, error = 0;
758 
759 	s = splnet();
760 
761 	switch (cmd) {
762 	case SIOCSIFADDR:
763 		ifp->if_flags |= IFF_UP;
764 
765 		switch (ifa->ifa_addr->sa_family) {
766 #ifdef INET
767 		case AF_INET:
768 			eginit(sc);
769 			arp_ifinit(&sc->sc_arpcom, ifa);
770 			break;
771 #endif
772 		default:
773 			eginit(sc);
774 			break;
775 		}
776 		break;
777 
778 	case SIOCSIFFLAGS:
779 		if ((ifp->if_flags & IFF_UP) == 0 &&
780 		    (ifp->if_flags & IFF_RUNNING) != 0) {
781 			/*
782 			 * If interface is marked down and it is running, then
783 			 * stop it.
784 			 */
785 			egstop(sc);
786 			ifp->if_flags &= ~IFF_RUNNING;
787 		} else if ((ifp->if_flags & IFF_UP) != 0 &&
788 			   (ifp->if_flags & IFF_RUNNING) == 0) {
789 			/*
790 			 * If interface is marked up and it is stopped, then
791 			 * start it.
792 			 */
793 			eginit(sc);
794 		} else {
795 			sc->eg_pcb[0] = EG_CMD_GETSTATS;
796 			sc->eg_pcb[1] = 0;
797 			if (egwritePCB(sc) != 0)
798 				DPRINTF(("write error\n"));
799 			/*
800 			 * XXX deal with flags changes:
801 			 * IFF_MULTICAST, IFF_PROMISC,
802 			 * IFF_LINK0, IFF_LINK1,
803 			 */
804 		}
805 		break;
806 
807 	default:
808 		error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data);
809 	}
810 
811 	splx(s);
812 	return (error);
813 }
814 
815 void
816 egreset(struct eg_softc *sc)
817 {
818 	int s;
819 
820 	DPRINTF(("egreset()\n"));
821 	s = splnet();
822 	egstop(sc);
823 	eginit(sc);
824 	splx(s);
825 }
826 
827 void
828 egwatchdog(struct ifnet *ifp)
829 {
830 	struct eg_softc *sc = ifp->if_softc;
831 
832 	log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
833 	sc->sc_arpcom.ac_if.if_oerrors++;
834 
835 	egreset(sc);
836 }
837 
838 void
839 egstop(register struct eg_softc *sc)
840 {
841 	bus_space_tag_t bst = sc->sc_bst;
842 	bus_space_handle_t bsh = sc->sc_bsh;
843 
844 	bus_space_write_1(bst, bsh, EG_CONTROL, 0);
845 }
846