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