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