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