Annotation of sys/dev/ic/am7990.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: am7990.c,v 1.41 2006/04/20 20:31:12 miod Exp $ */
! 2: /* $NetBSD: am7990.c,v 1.22 1996/10/13 01:37:19 christos Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1995 Charles M. Hannum. All rights reserved.
! 6: * Copyright (c) 1992, 1993
! 7: * The Regents of the University of California. All rights reserved.
! 8: *
! 9: * This code is derived from software contributed to Berkeley by
! 10: * Ralph Campbell and Rick Macklem.
! 11: *
! 12: * Redistribution and use in source and binary forms, with or without
! 13: * modification, are permitted provided that the following conditions
! 14: * are met:
! 15: * 1. Redistributions of source code must retain the above copyright
! 16: * notice, this list of conditions and the following disclaimer.
! 17: * 2. Redistributions in binary form must reproduce the above copyright
! 18: * notice, this list of conditions and the following disclaimer in the
! 19: * documentation and/or other materials provided with the distribution.
! 20: * 3. Neither the name of the University nor the names of its contributors
! 21: * may be used to endorse or promote products derived from this software
! 22: * without specific prior written permission.
! 23: *
! 24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 34: * SUCH DAMAGE.
! 35: *
! 36: * @(#)if_le.c 8.2 (Berkeley) 11/16/93
! 37: */
! 38:
! 39: #include "bpfilter.h"
! 40:
! 41: #include <sys/param.h>
! 42: #include <sys/systm.h>
! 43: #include <sys/mbuf.h>
! 44: #include <sys/syslog.h>
! 45: #include <sys/socket.h>
! 46: #include <sys/device.h>
! 47: #include <sys/malloc.h>
! 48: #include <sys/ioctl.h>
! 49: #include <sys/errno.h>
! 50:
! 51: #include <net/if.h>
! 52: #include <net/if_media.h>
! 53:
! 54: #ifdef INET
! 55: #include <netinet/in.h>
! 56: #include <netinet/if_ether.h>
! 57: #include <netinet/in_systm.h>
! 58: #include <netinet/in_var.h>
! 59: #include <netinet/ip.h>
! 60: #endif
! 61:
! 62: #if NBPFILTER > 0
! 63: #include <net/bpf.h>
! 64: #endif
! 65:
! 66: #include <dev/ic/am7990reg.h>
! 67: #include <dev/ic/am7990var.h>
! 68:
! 69: #ifdef LEDEBUG
! 70: void am7990_recv_print(struct am7990_softc *, int);
! 71: void am7990_xmit_print(struct am7990_softc *, int);
! 72: #endif
! 73:
! 74: integrate void am7990_rint(struct am7990_softc *);
! 75: integrate void am7990_tint(struct am7990_softc *);
! 76:
! 77: integrate int am7990_put(struct am7990_softc *, int, struct mbuf *);
! 78: integrate struct mbuf *am7990_get(struct am7990_softc *, int, int);
! 79: integrate void am7990_read(struct am7990_softc *, int, int);
! 80:
! 81: hide void am7990_shutdown(void *);
! 82:
! 83: #define ifp (&sc->sc_arpcom.ac_if)
! 84:
! 85: #if 0 /* XXX what do we do about this?! --thorpej */
! 86: static inline u_int16_t ether_cmp(void *, void *);
! 87:
! 88: /*
! 89: * Compare two Ether/802 addresses for equality, inlined and
! 90: * unrolled for speed. I'd love to have an inline assembler
! 91: * version of this... XXX: Who wanted that? mycroft?
! 92: * I wrote one, but the following is just as efficient.
! 93: * This expands to 10 short m68k instructions! -gwr
! 94: * Note: use this like bcmp()
! 95: */
! 96: static inline u_short
! 97: ether_cmp(one, two)
! 98: void *one, *two;
! 99: {
! 100: register u_int16_t *a = (u_short *) one;
! 101: register u_int16_t *b = (u_short *) two;
! 102: register u_int16_t diff;
! 103:
! 104: diff = *a++ - *b++;
! 105: diff |= *a++ - *b++;
! 106: diff |= *a++ - *b++;
! 107:
! 108: return (diff);
! 109: }
! 110:
! 111: #define ETHER_CMP ether_cmp
! 112: #endif /* XXX */
! 113:
! 114: #ifndef ETHER_CMP
! 115: #define ETHER_CMP(a, b) bcmp((a), (b), ETHER_ADDR_LEN)
! 116: #endif
! 117:
! 118: /*
! 119: * am7990 configuration driver. Attachments are provided by
! 120: * machine-dependent driver front-ends.
! 121: */
! 122: struct cfdriver le_cd = {
! 123: NULL, "le", DV_IFNET
! 124: };
! 125:
! 126: void
! 127: am7990_config(sc)
! 128: struct am7990_softc *sc;
! 129: {
! 130: int mem;
! 131:
! 132: /* Make sure the chip is stopped. */
! 133: am7990_stop(sc);
! 134:
! 135: /* Initialize ifnet structure. */
! 136: bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
! 137: ifp->if_softc = sc;
! 138: ifp->if_start = am7990_start;
! 139: ifp->if_ioctl = am7990_ioctl;
! 140: ifp->if_watchdog = am7990_watchdog;
! 141: ifp->if_flags =
! 142: IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
! 143: #ifdef LANCE_REVC_BUG
! 144: ifp->if_flags &= ~IFF_MULTICAST;
! 145: #endif
! 146: ifp->if_baudrate = IF_Mbps(10);
! 147: IFQ_SET_READY(&ifp->if_snd);
! 148:
! 149: ifp->if_capabilities = IFCAP_VLAN_MTU;
! 150:
! 151: /* Attach the interface. */
! 152: if_attach(ifp);
! 153: ether_ifattach(ifp);
! 154:
! 155: if (sc->sc_memsize > 262144)
! 156: sc->sc_memsize = 262144;
! 157:
! 158: switch (sc->sc_memsize) {
! 159: case 8192:
! 160: sc->sc_nrbuf = 4;
! 161: sc->sc_ntbuf = 1;
! 162: break;
! 163: case 16384:
! 164: sc->sc_nrbuf = 8;
! 165: sc->sc_ntbuf = 2;
! 166: break;
! 167: case 32768:
! 168: sc->sc_nrbuf = 16;
! 169: sc->sc_ntbuf = 4;
! 170: break;
! 171: case 65536:
! 172: sc->sc_nrbuf = 32;
! 173: sc->sc_ntbuf = 8;
! 174: break;
! 175: case 131072:
! 176: sc->sc_nrbuf = 64;
! 177: sc->sc_ntbuf = 16;
! 178: break;
! 179: case 262144:
! 180: sc->sc_nrbuf = 128;
! 181: sc->sc_ntbuf = 32;
! 182: break;
! 183: default:
! 184: panic("am7990_config: weird memory size %lu", sc->sc_memsize);
! 185: }
! 186:
! 187: printf(": address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
! 188: printf("%s: %d receive buffers, %d transmit buffers\n",
! 189: sc->sc_dev.dv_xname, sc->sc_nrbuf, sc->sc_ntbuf);
! 190:
! 191: sc->sc_sh = shutdownhook_establish(am7990_shutdown, sc);
! 192: if (sc->sc_sh == NULL)
! 193: panic("am7990_config: can't establish shutdownhook");
! 194:
! 195: mem = 0;
! 196: sc->sc_initaddr = mem;
! 197: mem += sizeof(struct leinit);
! 198: sc->sc_rmdaddr = mem;
! 199: mem += sizeof(struct lermd) * sc->sc_nrbuf;
! 200: sc->sc_tmdaddr = mem;
! 201: mem += sizeof(struct letmd) * sc->sc_ntbuf;
! 202: sc->sc_rbufaddr = mem;
! 203: mem += ETHER_MAX_DIX_LEN * sc->sc_nrbuf;
! 204: sc->sc_tbufaddr = mem;
! 205: mem += ETHER_MAX_DIX_LEN * sc->sc_ntbuf;
! 206: #ifdef notyet
! 207: if (mem > ...)
! 208: panic(...);
! 209: #endif
! 210: }
! 211:
! 212: void
! 213: am7990_reset(sc)
! 214: struct am7990_softc *sc;
! 215: {
! 216: int s;
! 217:
! 218: s = splnet();
! 219: am7990_init(sc);
! 220: splx(s);
! 221: }
! 222:
! 223: /*
! 224: * Set up the initialization block and the descriptor rings.
! 225: */
! 226: void
! 227: am7990_meminit(sc)
! 228: register struct am7990_softc *sc;
! 229: {
! 230: u_long a;
! 231: int bix;
! 232: struct leinit init;
! 233: struct lermd rmd;
! 234: struct letmd tmd;
! 235:
! 236: #if NBPFILTER > 0
! 237: if (ifp->if_flags & IFF_PROMISC)
! 238: init.init_mode = LE_MODE_NORMAL | LE_MODE_PROM;
! 239: else
! 240: #endif
! 241: init.init_mode = LE_MODE_NORMAL;
! 242: init.init_padr[0] =
! 243: (sc->sc_arpcom.ac_enaddr[1] << 8) | sc->sc_arpcom.ac_enaddr[0];
! 244: init.init_padr[1] =
! 245: (sc->sc_arpcom.ac_enaddr[3] << 8) | sc->sc_arpcom.ac_enaddr[2];
! 246: init.init_padr[2] =
! 247: (sc->sc_arpcom.ac_enaddr[5] << 8) | sc->sc_arpcom.ac_enaddr[4];
! 248: am7990_setladrf(&sc->sc_arpcom, init.init_ladrf);
! 249:
! 250: sc->sc_last_rd = 0;
! 251: sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0;
! 252:
! 253: a = sc->sc_addr + LE_RMDADDR(sc, 0);
! 254: init.init_rdra = a;
! 255: init.init_rlen = (a >> 16) | ((ffs(sc->sc_nrbuf) - 1) << 13);
! 256:
! 257: a = sc->sc_addr + LE_TMDADDR(sc, 0);
! 258: init.init_tdra = a;
! 259: init.init_tlen = (a >> 16) | ((ffs(sc->sc_ntbuf) - 1) << 13);
! 260:
! 261: (*sc->sc_copytodesc)(sc, &init, LE_INITADDR(sc), sizeof(init));
! 262:
! 263: /*
! 264: * Set up receive ring descriptors.
! 265: */
! 266: for (bix = 0; bix < sc->sc_nrbuf; bix++) {
! 267: a = sc->sc_addr + LE_RBUFADDR(sc, bix);
! 268: rmd.rmd0 = a;
! 269: rmd.rmd1_hadr = a >> 16;
! 270: rmd.rmd1_bits = LE_R1_OWN;
! 271: rmd.rmd2 = -ETHER_MAX_DIX_LEN | LE_XMD2_ONES;
! 272: rmd.rmd3 = 0;
! 273: (*sc->sc_copytodesc)(sc, &rmd, LE_RMDADDR(sc, bix),
! 274: sizeof(rmd));
! 275: }
! 276:
! 277: /*
! 278: * Set up transmit ring descriptors.
! 279: */
! 280: for (bix = 0; bix < sc->sc_ntbuf; bix++) {
! 281: a = sc->sc_addr + LE_TBUFADDR(sc, bix);
! 282: tmd.tmd0 = a;
! 283: tmd.tmd1_hadr = a >> 16;
! 284: tmd.tmd1_bits = 0;
! 285: tmd.tmd2 = 0 | LE_XMD2_ONES;
! 286: tmd.tmd3 = 0;
! 287: (*sc->sc_copytodesc)(sc, &tmd, LE_TMDADDR(sc, bix),
! 288: sizeof(tmd));
! 289: }
! 290: }
! 291:
! 292: void
! 293: am7990_stop(sc)
! 294: struct am7990_softc *sc;
! 295: {
! 296:
! 297: (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
! 298: }
! 299:
! 300: /*
! 301: * Initialization of interface; set up initialization block
! 302: * and transmit/receive descriptor rings.
! 303: */
! 304: void
! 305: am7990_init(sc)
! 306: register struct am7990_softc *sc;
! 307: {
! 308: register int timo;
! 309: u_long a;
! 310:
! 311: (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
! 312: DELAY(100);
! 313:
! 314: /* Newer LANCE chips have a reset register */
! 315: if (sc->sc_hwreset)
! 316: (*sc->sc_hwreset)(sc);
! 317:
! 318: /* Set the correct byte swapping mode, etc. */
! 319: (*sc->sc_wrcsr)(sc, LE_CSR3, sc->sc_conf3);
! 320:
! 321: /* Set up LANCE init block. */
! 322: am7990_meminit(sc);
! 323:
! 324: /* Give LANCE the physical address of its init block. */
! 325: a = sc->sc_addr + LE_INITADDR(sc);
! 326: (*sc->sc_wrcsr)(sc, LE_CSR1, a);
! 327: (*sc->sc_wrcsr)(sc, LE_CSR2, a >> 16);
! 328:
! 329: /* Try to initialize the LANCE. */
! 330: DELAY(100);
! 331: (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INIT);
! 332:
! 333: /* Wait for initialization to finish. */
! 334: for (timo = 100000; timo; timo--)
! 335: if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON)
! 336: break;
! 337:
! 338: if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) {
! 339: /* Start the LANCE. */
! 340: (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT |
! 341: LE_C0_IDON);
! 342: ifp->if_flags |= IFF_RUNNING;
! 343: ifp->if_flags &= ~IFF_OACTIVE;
! 344: ifp->if_timer = 0;
! 345: am7990_start(ifp);
! 346: } else
! 347: printf("%s: controller failed to initialize\n", sc->sc_dev.dv_xname);
! 348: if (sc->sc_hwinit)
! 349: (*sc->sc_hwinit)(sc);
! 350: }
! 351:
! 352: /*
! 353: * Routine to copy from mbuf chain to transmit buffer in
! 354: * network buffer memory.
! 355: */
! 356: integrate int
! 357: am7990_put(sc, boff, m)
! 358: struct am7990_softc *sc;
! 359: int boff;
! 360: register struct mbuf *m;
! 361: {
! 362: register struct mbuf *n;
! 363: register int len, tlen = 0;
! 364:
! 365: for (; m; m = n) {
! 366: len = m->m_len;
! 367: if (len == 0) {
! 368: MFREE(m, n);
! 369: continue;
! 370: }
! 371: (*sc->sc_copytobuf)(sc, mtod(m, caddr_t), boff, len);
! 372: boff += len;
! 373: tlen += len;
! 374: MFREE(m, n);
! 375: }
! 376: if (tlen < LEMINSIZE) {
! 377: (*sc->sc_zerobuf)(sc, boff, LEMINSIZE - tlen);
! 378: tlen = LEMINSIZE;
! 379: }
! 380: return (tlen);
! 381: }
! 382:
! 383: /*
! 384: * Pull data off an interface.
! 385: * Len is length of data, with local net header stripped.
! 386: * We copy the data into mbufs. When full cluster sized units are present
! 387: * we copy into clusters.
! 388: */
! 389: integrate struct mbuf *
! 390: am7990_get(sc, boff, totlen)
! 391: struct am7990_softc *sc;
! 392: int boff, totlen;
! 393: {
! 394: register struct mbuf *m;
! 395: struct mbuf *top, **mp;
! 396: int len, pad;
! 397:
! 398: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 399: if (m == 0)
! 400: return (0);
! 401: m->m_pkthdr.rcvif = ifp;
! 402: m->m_pkthdr.len = totlen;
! 403: pad = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header);
! 404: m->m_data += pad;
! 405: len = MHLEN - pad;
! 406: top = 0;
! 407: mp = ⊤
! 408:
! 409: while (totlen > 0) {
! 410: if (top) {
! 411: MGET(m, M_DONTWAIT, MT_DATA);
! 412: if (m == 0) {
! 413: m_freem(top);
! 414: return 0;
! 415: }
! 416: len = MLEN;
! 417: }
! 418: if (totlen >= MINCLSIZE) {
! 419: MCLGET(m, M_DONTWAIT);
! 420: if (m->m_flags & M_EXT) {
! 421: len = MCLBYTES;
! 422: if (!top) {
! 423: m->m_data += pad;
! 424: len -= pad;
! 425: }
! 426: }
! 427: }
! 428: m->m_len = len = min(totlen, len);
! 429: (*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), boff, len);
! 430: boff += len;
! 431: totlen -= len;
! 432: *mp = m;
! 433: mp = &m->m_next;
! 434: }
! 435:
! 436: return (top);
! 437: }
! 438:
! 439: /*
! 440: * Pass a packet to the higher levels.
! 441: */
! 442: integrate void
! 443: am7990_read(sc, boff, len)
! 444: register struct am7990_softc *sc;
! 445: int boff, len;
! 446: {
! 447: struct mbuf *m;
! 448: #ifdef LANCE_REVC_BUG
! 449: struct ether_header *eh;
! 450: #endif
! 451:
! 452: if (len <= sizeof(struct ether_header) ||
! 453: len > ETHERMTU + ETHER_VLAN_ENCAP_LEN + sizeof(struct ether_header)) {
! 454: #ifdef LEDEBUG
! 455: printf("%s: invalid packet size %d; dropping\n",
! 456: sc->sc_dev.dv_xname, len);
! 457: #endif
! 458: ifp->if_ierrors++;
! 459: return;
! 460: }
! 461:
! 462: /* Pull packet off interface. */
! 463: m = am7990_get(sc, boff, len);
! 464: if (m == 0) {
! 465: ifp->if_ierrors++;
! 466: return;
! 467: }
! 468:
! 469: ifp->if_ipackets++;
! 470:
! 471: #if NBPFILTER > 0
! 472: /*
! 473: * Check if there's a BPF listener on this interface.
! 474: * If so, hand off the raw packet to BPF.
! 475: */
! 476: if (ifp->if_bpf)
! 477: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
! 478: #endif
! 479:
! 480: #ifdef LANCE_REVC_BUG
! 481: /*
! 482: * The old LANCE (Rev. C) chips have a bug which causes
! 483: * garbage to be inserted in front of the received packet.
! 484: * The work-around is to ignore packets with an invalid
! 485: * destination address (garbage will usually not match).
! 486: * Of course, this precludes multicast support...
! 487: */
! 488: eh = mtod(m, struct ether_header *);
! 489: if (ETHER_CMP(eh->ether_dhost, sc->sc_arpcom.ac_enaddr) &&
! 490: ETHER_CMP(eh->ether_dhost, etherbroadcastaddr)) {
! 491: m_freem(m);
! 492: return;
! 493: }
! 494: #endif
! 495:
! 496: /* Pass the packet up. */
! 497: ether_input_mbuf(ifp, m);
! 498: }
! 499:
! 500: integrate void
! 501: am7990_rint(sc)
! 502: struct am7990_softc *sc;
! 503: {
! 504: register int bix;
! 505: int rp;
! 506: struct lermd rmd;
! 507:
! 508: bix = sc->sc_last_rd;
! 509:
! 510: /* Process all buffers with valid data. */
! 511: for (;;) {
! 512: rp = LE_RMDADDR(sc, bix);
! 513: (*sc->sc_copyfromdesc)(sc, &rmd, rp, sizeof(rmd));
! 514:
! 515: if (rmd.rmd1_bits & LE_R1_OWN)
! 516: break;
! 517:
! 518: if (rmd.rmd1_bits & LE_R1_ERR) {
! 519: if (rmd.rmd1_bits & LE_R1_ENP) {
! 520: #ifdef LEDEBUG
! 521: if ((rmd.rmd1_bits & LE_R1_OFLO) == 0) {
! 522: if (rmd.rmd1_bits & LE_R1_FRAM)
! 523: printf("%s: framing error\n",
! 524: sc->sc_dev.dv_xname);
! 525: if (rmd.rmd1_bits & LE_R1_CRC)
! 526: printf("%s: crc mismatch\n",
! 527: sc->sc_dev.dv_xname);
! 528: }
! 529: #endif
! 530: } else {
! 531: if (rmd.rmd1_bits & LE_R1_OFLO)
! 532: printf("%s: overflow\n",
! 533: sc->sc_dev.dv_xname);
! 534: }
! 535: if (rmd.rmd1_bits & LE_R1_BUFF)
! 536: printf("%s: receive buffer error\n",
! 537: sc->sc_dev.dv_xname);
! 538: ifp->if_ierrors++;
! 539: } else if ((rmd.rmd1_bits & (LE_R1_STP | LE_R1_ENP)) !=
! 540: (LE_R1_STP | LE_R1_ENP)) {
! 541: printf("%s: dropping chained buffer\n",
! 542: sc->sc_dev.dv_xname);
! 543: ifp->if_ierrors++;
! 544: } else {
! 545: #ifdef LEDEBUG1
! 546: if (sc->sc_debug)
! 547: am7990_recv_print(sc, sc->sc_last_rd);
! 548: #endif
! 549: am7990_read(sc, LE_RBUFADDR(sc, bix),
! 550: (int)rmd.rmd3 - 4);
! 551: }
! 552:
! 553: rmd.rmd1_bits = LE_R1_OWN;
! 554: rmd.rmd2 = -ETHER_MAX_DIX_LEN | LE_XMD2_ONES;
! 555: rmd.rmd3 = 0;
! 556: (*sc->sc_copytodesc)(sc, &rmd, rp, sizeof(rmd));
! 557:
! 558: #ifdef LEDEBUG1
! 559: if (sc->sc_debug)
! 560: printf("sc->sc_last_rd = %x, rmd: "
! 561: "ladr %04x, hadr %02x, flags %02x, "
! 562: "bcnt %04x, mcnt %04x\n",
! 563: sc->sc_last_rd,
! 564: rmd.rmd0, rmd.rmd1_hadr, rmd.rmd1_bits,
! 565: rmd.rmd2, rmd.rmd3);
! 566: #endif
! 567:
! 568: if (++bix == sc->sc_nrbuf)
! 569: bix = 0;
! 570: }
! 571:
! 572: sc->sc_last_rd = bix;
! 573: }
! 574:
! 575: integrate void
! 576: am7990_tint(sc)
! 577: register struct am7990_softc *sc;
! 578: {
! 579: register int bix;
! 580: struct letmd tmd;
! 581:
! 582: bix = sc->sc_first_td;
! 583:
! 584: for (;;) {
! 585: if (sc->sc_no_td <= 0)
! 586: break;
! 587:
! 588: (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, bix),
! 589: sizeof(tmd));
! 590:
! 591: #ifdef LEDEBUG
! 592: if (sc->sc_debug)
! 593: printf("trans tmd: "
! 594: "ladr %04x, hadr %02x, flags %02x, "
! 595: "bcnt %04x, mcnt %04x\n",
! 596: tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits,
! 597: tmd.tmd2, tmd.tmd3);
! 598: #endif
! 599:
! 600: if (tmd.tmd1_bits & LE_T1_OWN)
! 601: break;
! 602:
! 603: ifp->if_flags &= ~IFF_OACTIVE;
! 604:
! 605: if (tmd.tmd1_bits & LE_T1_ERR) {
! 606: if (tmd.tmd3 & LE_T3_BUFF)
! 607: printf("%s: transmit buffer error\n",
! 608: sc->sc_dev.dv_xname);
! 609: else if (tmd.tmd3 & LE_T3_UFLO)
! 610: printf("%s: underflow\n", sc->sc_dev.dv_xname);
! 611: if (tmd.tmd3 & (LE_T3_BUFF | LE_T3_UFLO)) {
! 612: am7990_reset(sc);
! 613: return;
! 614: }
! 615: if (tmd.tmd3 & LE_T3_LCAR) {
! 616: if (sc->sc_nocarrier)
! 617: (*sc->sc_nocarrier)(sc);
! 618: }
! 619: if (tmd.tmd3 & LE_T3_LCOL)
! 620: ifp->if_collisions++;
! 621: if (tmd.tmd3 & LE_T3_RTRY) {
! 622: printf("%s: excessive collisions, tdr %d\n",
! 623: sc->sc_dev.dv_xname,
! 624: tmd.tmd3 & LE_T3_TDR_MASK);
! 625: ifp->if_collisions += 16;
! 626: }
! 627: ifp->if_oerrors++;
! 628: } else {
! 629: if (tmd.tmd1_bits & LE_T1_ONE)
! 630: ifp->if_collisions++;
! 631: else if (tmd.tmd1_bits & LE_T1_MORE)
! 632: /* Real number is unknown. */
! 633: ifp->if_collisions += 2;
! 634: ifp->if_opackets++;
! 635: }
! 636:
! 637: if (++bix == sc->sc_ntbuf)
! 638: bix = 0;
! 639:
! 640: --sc->sc_no_td;
! 641: }
! 642:
! 643: sc->sc_first_td = bix;
! 644:
! 645: am7990_start(ifp);
! 646:
! 647: if (sc->sc_no_td == 0)
! 648: ifp->if_timer = 0;
! 649: }
! 650:
! 651: /*
! 652: * Controller interrupt.
! 653: */
! 654: int
! 655: am7990_intr(arg)
! 656: register void *arg;
! 657: {
! 658: register struct am7990_softc *sc = arg;
! 659: register u_int16_t isr;
! 660:
! 661: isr = (*sc->sc_rdcsr)(sc, LE_CSR0);
! 662: #ifdef LEDEBUG
! 663: if (sc->sc_debug){
! 664: printf("%s: am7990_intr entering with isr=%04x\n",
! 665: sc->sc_dev.dv_xname, isr);
! 666: printf(" isr: 0x%b\n", isr, LE_C0_BITS);
! 667: }
! 668: #endif
! 669: if ((isr & LE_C0_INTR) == 0)
! 670: return (0);
! 671:
! 672: /*
! 673: * After receiving an interrupt, we need to toggle the interrupt
! 674: * enable bit in order to keep receiving them (some chips works
! 675: * without this, some do not)
! 676: */
! 677: (*sc->sc_wrcsr)(sc, LE_CSR0, isr & ~LE_C0_INEA);
! 678: (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA);
! 679:
! 680: if (isr & LE_C0_ERR) {
! 681: if (isr & LE_C0_BABL) {
! 682: #ifdef LEDEBUG
! 683: printf("%s: babble\n", sc->sc_dev.dv_xname);
! 684: #endif
! 685: ifp->if_oerrors++;
! 686: }
! 687: #if 0
! 688: if (isr & LE_C0_CERR) {
! 689: printf("%s: collision error\n", sc->sc_dev.dv_xname);
! 690: ifp->if_collisions++;
! 691: }
! 692: #endif
! 693: if (isr & LE_C0_MISS) {
! 694: #ifdef LEDEBUG
! 695: printf("%s: missed packet\n", sc->sc_dev.dv_xname);
! 696: #endif
! 697: ifp->if_ierrors++;
! 698: }
! 699: if (isr & LE_C0_MERR) {
! 700: printf("%s: memory error\n", sc->sc_dev.dv_xname);
! 701: am7990_reset(sc);
! 702: return (1);
! 703: }
! 704: }
! 705:
! 706: if ((isr & LE_C0_RXON) == 0) {
! 707: printf("%s: receiver disabled\n", sc->sc_dev.dv_xname);
! 708: ifp->if_ierrors++;
! 709: am7990_reset(sc);
! 710: return (1);
! 711: }
! 712: if ((isr & LE_C0_TXON) == 0) {
! 713: printf("%s: transmitter disabled\n", sc->sc_dev.dv_xname);
! 714: ifp->if_oerrors++;
! 715: am7990_reset(sc);
! 716: return (1);
! 717: }
! 718:
! 719: if (isr & LE_C0_RINT)
! 720: am7990_rint(sc);
! 721: if (isr & LE_C0_TINT)
! 722: am7990_tint(sc);
! 723:
! 724: return (1);
! 725: }
! 726:
! 727: #undef ifp
! 728:
! 729: void
! 730: am7990_watchdog(ifp)
! 731: struct ifnet *ifp;
! 732: {
! 733: struct am7990_softc *sc = ifp->if_softc;
! 734:
! 735: log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
! 736: ++ifp->if_oerrors;
! 737:
! 738: am7990_reset(sc);
! 739: }
! 740:
! 741: /*
! 742: * Setup output on interface.
! 743: * Get another datagram to send off of the interface queue, and map it to the
! 744: * interface before starting the output.
! 745: * Called only at splnet or interrupt level.
! 746: */
! 747: void
! 748: am7990_start(ifp)
! 749: register struct ifnet *ifp;
! 750: {
! 751: register struct am7990_softc *sc = ifp->if_softc;
! 752: register int bix;
! 753: register struct mbuf *m;
! 754: struct letmd tmd;
! 755: int rp;
! 756: int len;
! 757:
! 758: if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
! 759: return;
! 760:
! 761: bix = sc->sc_last_td;
! 762:
! 763: for (;;) {
! 764: rp = LE_TMDADDR(sc, bix);
! 765: (*sc->sc_copyfromdesc)(sc, &tmd, rp, sizeof(tmd));
! 766:
! 767: if (tmd.tmd1_bits & LE_T1_OWN) {
! 768: ifp->if_flags |= IFF_OACTIVE;
! 769: printf("missing buffer, no_td = %d, last_td = %d\n",
! 770: sc->sc_no_td, sc->sc_last_td);
! 771: }
! 772:
! 773: IFQ_DEQUEUE(&ifp->if_snd, m);
! 774: if (m == 0)
! 775: break;
! 776:
! 777: #if NBPFILTER > 0
! 778: /*
! 779: * If BPF is listening on this interface, let it see the packet
! 780: * before we commit it to the wire.
! 781: */
! 782: if (ifp->if_bpf)
! 783: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
! 784: #endif
! 785:
! 786: /*
! 787: * Copy the mbuf chain into the transmit buffer.
! 788: */
! 789: len = am7990_put(sc, LE_TBUFADDR(sc, bix), m);
! 790:
! 791: #ifdef LEDEBUG
! 792: if (len > ETHERMTU + sizeof(struct ether_header))
! 793: printf("packet length %d\n", len);
! 794: #endif
! 795:
! 796: ifp->if_timer = 5;
! 797:
! 798: /*
! 799: * Init transmit registers, and set transmit start flag.
! 800: */
! 801: tmd.tmd1_bits = LE_T1_OWN | LE_T1_STP | LE_T1_ENP;
! 802: tmd.tmd2 = -len | LE_XMD2_ONES;
! 803: tmd.tmd3 = 0;
! 804:
! 805: (*sc->sc_copytodesc)(sc, &tmd, rp, sizeof(tmd));
! 806:
! 807: #ifdef LEDEBUG
! 808: if (sc->sc_debug)
! 809: am7990_xmit_print(sc, sc->sc_last_td);
! 810: #endif
! 811:
! 812: (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_TDMD);
! 813:
! 814: if (++bix == sc->sc_ntbuf)
! 815: bix = 0;
! 816:
! 817: if (++sc->sc_no_td == sc->sc_ntbuf) {
! 818: #ifdef LEDEBUG
! 819: printf("\nequal!\n");
! 820: #endif
! 821: ifp->if_flags |= IFF_OACTIVE;
! 822: break;
! 823: }
! 824:
! 825: }
! 826:
! 827: sc->sc_last_td = bix;
! 828: }
! 829:
! 830: /*
! 831: * Process an ioctl request.
! 832: */
! 833: int
! 834: am7990_ioctl(ifp, cmd, data)
! 835: register struct ifnet *ifp;
! 836: u_long cmd;
! 837: caddr_t data;
! 838: {
! 839: register struct am7990_softc *sc = ifp->if_softc;
! 840: struct ifaddr *ifa = (struct ifaddr *)data;
! 841: struct ifreq *ifr = (struct ifreq *)data;
! 842: int s, error = 0;
! 843:
! 844: s = splnet();
! 845:
! 846: if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
! 847: splx(s);
! 848: return error;
! 849: }
! 850:
! 851: switch (cmd) {
! 852:
! 853: case SIOCSIFADDR:
! 854: ifp->if_flags |= IFF_UP;
! 855:
! 856: switch (ifa->ifa_addr->sa_family) {
! 857: #ifdef INET
! 858: case AF_INET:
! 859: am7990_init(sc);
! 860: arp_ifinit(&sc->sc_arpcom, ifa);
! 861: break;
! 862: #endif
! 863: default:
! 864: am7990_init(sc);
! 865: break;
! 866: }
! 867: break;
! 868:
! 869: case SIOCSIFFLAGS:
! 870: if ((ifp->if_flags & IFF_UP) == 0 &&
! 871: (ifp->if_flags & IFF_RUNNING) != 0) {
! 872: /*
! 873: * If interface is marked down and it is running, then
! 874: * stop it.
! 875: */
! 876: am7990_stop(sc);
! 877: ifp->if_flags &= ~IFF_RUNNING;
! 878: } else if ((ifp->if_flags & IFF_UP) != 0 &&
! 879: (ifp->if_flags & IFF_RUNNING) == 0) {
! 880: /*
! 881: * If interface is marked up and it is stopped, then
! 882: * start it.
! 883: */
! 884: am7990_init(sc);
! 885: } else {
! 886: /*
! 887: * Reset the interface to pick up changes in any other
! 888: * flags that affect hardware registers.
! 889: */
! 890: /*am7990_stop(sc);*/
! 891: am7990_init(sc);
! 892: }
! 893: #ifdef LEDEBUG
! 894: if (ifp->if_flags & IFF_DEBUG)
! 895: sc->sc_debug = 1;
! 896: else
! 897: sc->sc_debug = 0;
! 898: #endif
! 899: break;
! 900:
! 901: case SIOCADDMULTI:
! 902: case SIOCDELMULTI:
! 903: error = (cmd == SIOCADDMULTI) ?
! 904: ether_addmulti(ifr, &sc->sc_arpcom) :
! 905: ether_delmulti(ifr, &sc->sc_arpcom);
! 906:
! 907: if (error == ENETRESET) {
! 908: /*
! 909: * Multicast list has changed; set the hardware filter
! 910: * accordingly.
! 911: */
! 912: if (ifp->if_flags & IFF_RUNNING)
! 913: am7990_reset(sc);
! 914: error = 0;
! 915: }
! 916: break;
! 917:
! 918: case SIOCGIFMEDIA:
! 919: case SIOCSIFMEDIA:
! 920: if (sc->sc_hasifmedia)
! 921: error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, cmd);
! 922: else
! 923: error = EINVAL;
! 924: break;
! 925:
! 926: default:
! 927: error = EINVAL;
! 928: break;
! 929: }
! 930:
! 931: splx(s);
! 932: return (error);
! 933: }
! 934:
! 935: hide void
! 936: am7990_shutdown(arg)
! 937: void *arg;
! 938: {
! 939:
! 940: am7990_stop((struct am7990_softc *)arg);
! 941: }
! 942:
! 943: #ifdef LEDEBUG
! 944: void
! 945: am7990_recv_print(sc, no)
! 946: struct am7990_softc *sc;
! 947: int no;
! 948: {
! 949: struct lermd rmd;
! 950: u_int16_t len;
! 951: struct ether_header eh;
! 952:
! 953: (*sc->sc_copyfromdesc)(sc, &rmd, LE_RMDADDR(sc, no), sizeof(rmd));
! 954: len = rmd.rmd3;
! 955: printf("%s: receive buffer %d, len = %d\n", sc->sc_dev.dv_xname, no,
! 956: len);
! 957: printf("%s: status %04x\n", sc->sc_dev.dv_xname,
! 958: (*sc->sc_rdcsr)(sc, LE_CSR0));
! 959: printf("%s: ladr %04x, hadr %02x, flags %02x, bcnt %04x, mcnt %04x\n",
! 960: sc->sc_dev.dv_xname,
! 961: rmd.rmd0, rmd.rmd1_hadr, rmd.rmd1_bits, rmd.rmd2, rmd.rmd3);
! 962: if (len >= sizeof(eh)) {
! 963: (*sc->sc_copyfrombuf)(sc, &eh, LE_RBUFADDR(sc, no), sizeof(eh));
! 964: printf("%s: dst %s", sc->sc_dev.dv_xname,
! 965: ether_sprintf(eh.ether_dhost));
! 966: printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
! 967: ntohs(eh.ether_type));
! 968: }
! 969: }
! 970:
! 971: void
! 972: am7990_xmit_print(sc, no)
! 973: struct am7990_softc *sc;
! 974: int no;
! 975: {
! 976: struct letmd tmd;
! 977: u_int16_t len;
! 978: struct ether_header eh;
! 979:
! 980: (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, no), sizeof(tmd));
! 981: len = -tmd.tmd2;
! 982: printf("%s: transmit buffer %d, len = %d\n", sc->sc_dev.dv_xname, no,
! 983: len);
! 984: printf("%s: status %04x\n", sc->sc_dev.dv_xname,
! 985: (*sc->sc_rdcsr)(sc, LE_CSR0));
! 986: printf("%s: ladr %04x, hadr %02x, flags %02x, bcnt %04x, mcnt %04x\n",
! 987: sc->sc_dev.dv_xname,
! 988: tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits, tmd.tmd2, tmd.tmd3);
! 989: if (len >= sizeof(eh)) {
! 990: (*sc->sc_copyfrombuf)(sc, &eh, LE_TBUFADDR(sc, no), sizeof(eh));
! 991: printf("%s: dst %s", sc->sc_dev.dv_xname,
! 992: ether_sprintf(eh.ether_dhost));
! 993: printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
! 994: ntohs(eh.ether_type));
! 995: }
! 996: }
! 997: #endif /* LEDEBUG */
! 998:
! 999: /*
! 1000: * Set up the logical address filter.
! 1001: */
! 1002: void
! 1003: am7990_setladrf(ac, af)
! 1004: struct arpcom *ac;
! 1005: u_int16_t *af;
! 1006: {
! 1007: struct ifnet *ifp = &ac->ac_if;
! 1008: struct ether_multi *enm;
! 1009: register u_int32_t crc;
! 1010: struct ether_multistep step;
! 1011:
! 1012: /*
! 1013: * Set up multicast address filter by passing all multicast addresses
! 1014: * through a crc generator, and then using the high order 6 bits as an
! 1015: * index into the 64 bit logical address filter. The high order bit
! 1016: * selects the word, while the rest of the bits select the bit within
! 1017: * the word.
! 1018: */
! 1019:
! 1020: if (ifp->if_flags & IFF_PROMISC)
! 1021: goto allmulti;
! 1022:
! 1023: af[0] = af[1] = af[2] = af[3] = 0x0000;
! 1024: ETHER_FIRST_MULTI(step, ac, enm);
! 1025: while (enm != NULL) {
! 1026: if (ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi)) {
! 1027: /*
! 1028: * We must listen to a range of multicast addresses.
! 1029: * For now, just accept all multicasts, rather than
! 1030: * trying to set only those filter bits needed to match
! 1031: * the range. (At this time, the only use of address
! 1032: * ranges is for IP multicast routing, for which the
! 1033: * range is big enough to require all bits set.)
! 1034: */
! 1035: goto allmulti;
! 1036: }
! 1037:
! 1038: crc = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN) >> 26;
! 1039:
! 1040: /* Set the corresponding bit in the filter. */
! 1041: af[crc >> 4] |= 1 << (crc & 0xf);
! 1042:
! 1043: ETHER_NEXT_MULTI(step, enm);
! 1044: }
! 1045: ifp->if_flags &= ~IFF_ALLMULTI;
! 1046: return;
! 1047:
! 1048: allmulti:
! 1049: ifp->if_flags |= IFF_ALLMULTI;
! 1050: af[0] = af[1] = af[2] = af[3] = 0xffff;
! 1051: }
! 1052:
! 1053:
! 1054: /*
! 1055: * Routines for accessing the transmit and receive buffers.
! 1056: * The various CPU and adapter configurations supported by this
! 1057: * driver require three different access methods for buffers
! 1058: * and descriptors:
! 1059: * (1) contig (contiguous data; no padding),
! 1060: * (2) gap2 (two bytes of data followed by two bytes of padding),
! 1061: * (3) gap16 (16 bytes of data followed by 16 bytes of padding).
! 1062: */
! 1063:
! 1064: /*
! 1065: * contig: contiguous data with no padding.
! 1066: *
! 1067: * Buffers may have any alignment.
! 1068: */
! 1069:
! 1070: void
! 1071: am7990_copytobuf_contig(sc, from, boff, len)
! 1072: struct am7990_softc *sc;
! 1073: void *from;
! 1074: int boff, len;
! 1075: {
! 1076: volatile caddr_t buf = sc->sc_mem;
! 1077:
! 1078: /*
! 1079: * Just call bcopy() to do the work.
! 1080: */
! 1081: bcopy(from, buf + boff, len);
! 1082: }
! 1083:
! 1084: void
! 1085: am7990_copyfrombuf_contig(sc, to, boff, len)
! 1086: struct am7990_softc *sc;
! 1087: void *to;
! 1088: int boff, len;
! 1089: {
! 1090: volatile caddr_t buf = sc->sc_mem;
! 1091:
! 1092: /*
! 1093: * Just call bcopy() to do the work.
! 1094: */
! 1095: bcopy(buf + boff, to, len);
! 1096: }
! 1097:
! 1098: void
! 1099: am7990_zerobuf_contig(sc, boff, len)
! 1100: struct am7990_softc *sc;
! 1101: int boff, len;
! 1102: {
! 1103: volatile caddr_t buf = sc->sc_mem;
! 1104:
! 1105: /*
! 1106: * Just let bzero() do the work
! 1107: */
! 1108: bzero(buf + boff, len);
! 1109: }
! 1110:
! 1111: #if 0
! 1112: /*
! 1113: * Examples only; duplicate these and tweak (if necessary) in
! 1114: * machine-specific front-ends.
! 1115: */
! 1116:
! 1117: /*
! 1118: * gap2: two bytes of data followed by two bytes of pad.
! 1119: *
! 1120: * Buffers must be 4-byte aligned. The code doesn't worry about
! 1121: * doing an extra byte.
! 1122: */
! 1123:
! 1124: void
! 1125: am7990_copytobuf_gap2(sc, fromv, boff, len)
! 1126: struct am7990_softc *sc;
! 1127: void *fromv;
! 1128: int boff;
! 1129: register int len;
! 1130: {
! 1131: volatile caddr_t buf = sc->sc_mem;
! 1132: register caddr_t from = fromv;
! 1133: register volatile u_int16_t *bptr;
! 1134:
! 1135: if (boff & 0x1) {
! 1136: /* handle unaligned first byte */
! 1137: bptr = ((volatile u_int16_t *)buf) + (boff - 1);
! 1138: *bptr = (*from++ << 8) | (*bptr & 0xff);
! 1139: bptr += 2;
! 1140: len--;
! 1141: } else
! 1142: bptr = ((volatile u_int16_t *)buf) + boff;
! 1143: while (len > 1) {
! 1144: *bptr = (from[1] << 8) | (from[0] & 0xff);
! 1145: bptr += 2;
! 1146: from += 2;
! 1147: len -= 2;
! 1148: }
! 1149: if (len == 1)
! 1150: *bptr = (u_int16_t)*from;
! 1151: }
! 1152:
! 1153: void
! 1154: am7990_copyfrombuf_gap2(sc, tov, boff, len)
! 1155: struct am7990_softc *sc;
! 1156: void *tov;
! 1157: int boff, len;
! 1158: {
! 1159: volatile caddr_t buf = sc->sc_mem;
! 1160: register caddr_t to = tov;
! 1161: register volatile u_int16_t *bptr;
! 1162: register u_int16_t tmp;
! 1163:
! 1164: if (boff & 0x1) {
! 1165: /* handle unaligned first byte */
! 1166: bptr = ((volatile u_int16_t *)buf) + (boff - 1);
! 1167: *to++ = (*bptr >> 8) & 0xff;
! 1168: bptr += 2;
! 1169: len--;
! 1170: } else
! 1171: bptr = ((volatile u_int16_t *)buf) + boff;
! 1172: while (len > 1) {
! 1173: tmp = *bptr;
! 1174: *to++ = tmp & 0xff;
! 1175: *to++ = (tmp >> 8) & 0xff;
! 1176: bptr += 2;
! 1177: len -= 2;
! 1178: }
! 1179: if (len == 1)
! 1180: *to = *bptr & 0xff;
! 1181: }
! 1182:
! 1183: void
! 1184: am7990_zerobuf_gap2(sc, boff, len)
! 1185: struct am7990_softc *sc;
! 1186: int boff, len;
! 1187: {
! 1188: volatile caddr_t buf = sc->sc_mem;
! 1189: register volatile u_int16_t *bptr;
! 1190:
! 1191: if ((unsigned)boff & 0x1) {
! 1192: bptr = ((volatile u_int16_t *)buf) + (boff - 1);
! 1193: *bptr &= 0xff;
! 1194: bptr += 2;
! 1195: len--;
! 1196: } else
! 1197: bptr = ((volatile u_int16_t *)buf) + boff;
! 1198: while (len > 0) {
! 1199: *bptr = 0;
! 1200: bptr += 2;
! 1201: len -= 2;
! 1202: }
! 1203: }
! 1204:
! 1205: /*
! 1206: * gap16: 16 bytes of data followed by 16 bytes of pad.
! 1207: *
! 1208: * Buffers must be 32-byte aligned.
! 1209: */
! 1210:
! 1211: void
! 1212: am7990_copytobuf_gap16(sc, fromv, boff, len)
! 1213: struct am7990_softc *sc;
! 1214: void *fromv;
! 1215: int boff;
! 1216: register int len;
! 1217: {
! 1218: volatile caddr_t buf = sc->sc_mem;
! 1219: register caddr_t from = fromv;
! 1220: register caddr_t bptr;
! 1221: register int xfer;
! 1222:
! 1223: bptr = buf + ((boff << 1) & ~0x1f);
! 1224: boff &= 0xf;
! 1225: xfer = min(len, 16 - boff);
! 1226: while (len > 0) {
! 1227: bcopy(from, bptr + boff, xfer);
! 1228: from += xfer;
! 1229: bptr += 32;
! 1230: boff = 0;
! 1231: len -= xfer;
! 1232: xfer = min(len, 16);
! 1233: }
! 1234: }
! 1235:
! 1236: void
! 1237: am7990_copyfrombuf_gap16(sc, tov, boff, len)
! 1238: struct am7990_softc *sc;
! 1239: void *tov;
! 1240: int boff, len;
! 1241: {
! 1242: volatile caddr_t buf = sc->sc_mem;
! 1243: register caddr_t to = tov;
! 1244: register caddr_t bptr;
! 1245: register int xfer;
! 1246:
! 1247: bptr = buf + ((boff << 1) & ~0x1f);
! 1248: boff &= 0xf;
! 1249: xfer = min(len, 16 - boff);
! 1250: while (len > 0) {
! 1251: bcopy(bptr + boff, to, xfer);
! 1252: to += xfer;
! 1253: bptr += 32;
! 1254: boff = 0;
! 1255: len -= xfer;
! 1256: xfer = min(len, 16);
! 1257: }
! 1258: }
! 1259:
! 1260: void
! 1261: am7990_zerobuf_gap16(sc, boff, len)
! 1262: struct am7990_softc *sc;
! 1263: int boff, len;
! 1264: {
! 1265: volatile caddr_t buf = sc->sc_mem;
! 1266: register caddr_t bptr;
! 1267: register int xfer;
! 1268:
! 1269: bptr = buf + ((boff << 1) & ~0x1f);
! 1270: boff &= 0xf;
! 1271: xfer = min(len, 16 - boff);
! 1272: while (len > 0) {
! 1273: bzero(bptr + boff, xfer);
! 1274: bptr += 32;
! 1275: boff = 0;
! 1276: len -= xfer;
! 1277: xfer = min(len, 16);
! 1278: }
! 1279: }
! 1280: #endif /* Example only */
CVSweb