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