Annotation of sys/dev/usb/ueagle.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ueagle.c,v 1.21 2007/06/14 10:11:15 mbalmer Exp $ */
! 2:
! 3: /*-
! 4: * Copyright (c) 2003-2006
! 5: * Damien Bergamini <damien.bergamini@free.fr>
! 6: *
! 7: * Permission to use, copy, modify, and distribute this software for any
! 8: * purpose with or without fee is hereby granted, provided that the above
! 9: * copyright notice and this permission notice appear in all copies.
! 10: *
! 11: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 12: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 13: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 14: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 15: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 16: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 17: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 18: */
! 19:
! 20: /*-
! 21: * Driver for Analog Devices Eagle chipset.
! 22: * http://www.analog.com/
! 23: */
! 24:
! 25: #include "bpfilter.h"
! 26:
! 27: #include <sys/param.h>
! 28: #include <sys/sysctl.h>
! 29: #include <sys/sockio.h>
! 30: #include <sys/mbuf.h>
! 31: #include <sys/kernel.h>
! 32: #include <sys/socket.h>
! 33: #include <sys/systm.h>
! 34: #include <sys/malloc.h>
! 35: #include <sys/device.h>
! 36: #include <sys/kthread.h>
! 37:
! 38: #include <net/bpf.h>
! 39: #include <net/if.h>
! 40: #include <net/if_atm.h>
! 41: #include <net/if_media.h>
! 42:
! 43: #ifdef INET
! 44: #include <netinet/in.h>
! 45: #include <netinet/if_atm.h>
! 46: #include <netinet/if_ether.h>
! 47: #endif
! 48:
! 49: #include <dev/usb/usb.h>
! 50: #include <dev/usb/usbdi.h>
! 51: #include <dev/usb/usbdi_util.h>
! 52: #include <dev/usb/ezload.h>
! 53: #include <dev/usb/usbdevs.h>
! 54:
! 55: #include <dev/usb/ueaglereg.h>
! 56: #include <dev/usb/ueaglevar.h>
! 57:
! 58: #ifdef USB_DEBUG
! 59: #define DPRINTF(x) do { if (ueagledebug > 0) printf x; } while (0)
! 60: #define DPRINTFN(n, x) do { if (ueagledebug >= (n)) printf x; } while (0)
! 61: int ueagledebug = 0;
! 62: #else
! 63: #define DPRINTF(x)
! 64: #define DPRINTFN(n, x)
! 65: #endif
! 66:
! 67: /* various supported device vendors/products */
! 68: static const struct ueagle_type {
! 69: struct usb_devno dev;
! 70: const char *fw;
! 71: } ueagle_devs[] = {
! 72: { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEI }, NULL },
! 73: { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEI_NF }, "ueagleI" },
! 74: { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEII }, NULL },
! 75: { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEII_NF }, "ueagleII" },
! 76: { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEIIC }, NULL },
! 77: { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEIIC_NF }, "ueagleII" },
! 78: { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEIII }, NULL },
! 79: { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEIII_NF }, "ueagleIII" },
! 80: { { USB_VENDOR_USR, USB_PRODUCT_USR_HEINEKEN_A }, NULL },
! 81: { { USB_VENDOR_USR, USB_PRODUCT_USR_HEINEKEN_A_NF }, "ueagleI" },
! 82: { { USB_VENDOR_USR, USB_PRODUCT_USR_HEINEKEN_B }, NULL },
! 83: { { USB_VENDOR_USR, USB_PRODUCT_USR_HEINEKEN_B_NF }, "ueagleI" },
! 84: { { USB_VENDOR_USR, USB_PRODUCT_USR_MILLER_A }, NULL },
! 85: { { USB_VENDOR_USR, USB_PRODUCT_USR_MILLER_A_NF }, "ueagleI" },
! 86: { { USB_VENDOR_USR, USB_PRODUCT_USR_MILLER_B }, NULL },
! 87: { { USB_VENDOR_USR, USB_PRODUCT_USR_MILLER_B_NF }, "ueagleI" }
! 88: };
! 89: #define ueagle_lookup(v, p) \
! 90: ((struct ueagle_type *)usb_lookup(ueagle_devs, v, p))
! 91:
! 92: void ueagle_attachhook(void *);
! 93: int ueagle_getesi(struct ueagle_softc *, uint8_t *);
! 94: void ueagle_loadpage(void *);
! 95: void ueagle_request(struct ueagle_softc *, uint16_t, uint16_t,
! 96: void *, int);
! 97: #ifdef USB_DEBUG
! 98: void ueagle_dump_cmv(struct ueagle_softc *, struct ueagle_cmv *);
! 99: #endif
! 100: int ueagle_cr(struct ueagle_softc *, uint32_t, uint16_t,
! 101: uint32_t *);
! 102: int ueagle_cw(struct ueagle_softc *, uint32_t, uint16_t, uint32_t);
! 103: int ueagle_stat(struct ueagle_softc *);
! 104: void ueagle_stat_thread(void *);
! 105: int ueagle_boot(struct ueagle_softc *);
! 106: void ueagle_swap_intr(struct ueagle_softc *, struct ueagle_swap *);
! 107: void ueagle_cmv_intr(struct ueagle_softc *, struct ueagle_cmv *);
! 108: void ueagle_intr(usbd_xfer_handle, usbd_private_handle,
! 109: usbd_status);
! 110: uint32_t ueagle_crc_update(uint32_t, uint8_t *, int);
! 111: void ueagle_push_cell(struct ueagle_softc *, uint8_t *);
! 112: void ueagle_rxeof(usbd_xfer_handle, usbd_private_handle,
! 113: usbd_status);
! 114: void ueagle_txeof(usbd_xfer_handle, usbd_private_handle,
! 115: usbd_status);
! 116: int ueagle_encap(struct ueagle_softc *, struct mbuf *);
! 117: void ueagle_start(struct ifnet *);
! 118: int ueagle_open_vcc(struct ueagle_softc *,
! 119: struct atm_pseudoioctl *);
! 120: int ueagle_close_vcc(struct ueagle_softc *,
! 121: struct atm_pseudoioctl *);
! 122: int ueagle_ioctl(struct ifnet *, u_long, caddr_t);
! 123: int ueagle_open_pipes(struct ueagle_softc *);
! 124: void ueagle_close_pipes(struct ueagle_softc *);
! 125: int ueagle_init(struct ifnet *);
! 126: void ueagle_stop(struct ifnet *, int);
! 127:
! 128: int ueagle_match(struct device *, void *, void *);
! 129: void ueagle_attach(struct device *, struct device *, void *);
! 130: int ueagle_detach(struct device *, int);
! 131: int ueagle_activate(struct device *, enum devact);
! 132:
! 133: struct cfdriver ueagle_cd = {
! 134: NULL, "ueagle", DV_DULL
! 135: };
! 136:
! 137: const struct cfattach ueagle_ca = {
! 138: sizeof(struct ueagle_softc),
! 139: ueagle_match,
! 140: ueagle_attach,
! 141: ueagle_detach,
! 142: ueagle_activate,
! 143: };
! 144:
! 145: int
! 146: ueagle_match(struct device *parent, void *match, void *aux)
! 147: {
! 148: struct usb_attach_arg *uaa = aux;
! 149:
! 150: if (uaa->iface != NULL)
! 151: return UMATCH_NONE;
! 152:
! 153: return (ueagle_lookup(uaa->vendor, uaa->product) != NULL) ?
! 154: UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
! 155: }
! 156:
! 157: void
! 158: ueagle_attachhook(void *xsc)
! 159: {
! 160: char *firmwares[2];
! 161: struct ueagle_softc *sc = xsc;
! 162:
! 163: firmwares[0] = (char *)sc->fw;
! 164: firmwares[1] = NULL;
! 165:
! 166: if (ezload_downloads_and_reset(sc->sc_udev, firmwares) != 0) {
! 167: printf("%s: could not download firmware\n",
! 168: sc->sc_dev.dv_xname);
! 169: return;
! 170: }
! 171: }
! 172:
! 173: void
! 174: ueagle_attach(struct device *parent, struct device *self, void *aux)
! 175: {
! 176: struct ueagle_softc *sc = (struct ueagle_softc *)self;
! 177: struct usb_attach_arg *uaa = aux;
! 178: struct ifnet *ifp = &sc->sc_if;
! 179: char *devinfop;
! 180: uint8_t addr[ETHER_ADDR_LEN];
! 181:
! 182: sc->sc_udev = uaa->device;
! 183: printf("\n");
! 184:
! 185: /*
! 186: * Pre-firmware modems must be flashed and reset first. They will
! 187: * automatically detach themselves from the bus and reattach later
! 188: * with a new product Id.
! 189: */
! 190: sc->fw = ueagle_lookup(uaa->vendor, uaa->product)->fw;
! 191: if (sc->fw != NULL) {
! 192: if (rootvp == NULL)
! 193: mountroothook_establish(ueagle_attachhook, sc);
! 194: else
! 195: ueagle_attachhook(sc);
! 196:
! 197: /* processing of pre-firmware modems ends here */
! 198: return;
! 199: }
! 200:
! 201: devinfop = usbd_devinfo_alloc(sc->sc_udev, 0);
! 202: printf("%s: %s\n", sc->sc_dev.dv_xname, devinfop);
! 203: usbd_devinfo_free(devinfop);
! 204:
! 205: if (usbd_set_config_no(sc->sc_udev, UEAGLE_CONFIG_NO, 0) != 0) {
! 206: printf("%s: could not set configuration no\n",
! 207: sc->sc_dev.dv_xname);
! 208: return;
! 209: }
! 210:
! 211: if (ueagle_getesi(sc, addr) != 0) {
! 212: printf("%s: could not read end system identifier\n",
! 213: sc->sc_dev.dv_xname);
! 214: return;
! 215: }
! 216:
! 217: printf("%s: address: %02x:%02x:%02x:%02x:%02x:%02x\n",
! 218: sc->sc_dev.dv_xname, addr[0], addr[1], addr[2], addr[3],
! 219: addr[4], addr[5]);
! 220:
! 221: usb_init_task(&sc->sc_swap_task, ueagle_loadpage, sc);
! 222:
! 223: ifp->if_softc = sc;
! 224: ifp->if_flags = IFF_SIMPLEX;
! 225: ifp->if_init = ueagle_init;
! 226: ifp->if_ioctl = ueagle_ioctl;
! 227: ifp->if_start = ueagle_start;
! 228: IFQ_SET_READY(&ifp->if_snd);
! 229: memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
! 230:
! 231: if_attach(ifp);
! 232: atm_ifattach(ifp);
! 233:
! 234: /* override default MTU value (9180 is too large for us) */
! 235: ifp->if_mtu = UEAGLE_IFMTU;
! 236:
! 237: #if NBPFILTER > 0
! 238: bpfattach(&ifp->if_bpf, ifp, DLT_RAW, 0);
! 239: #endif
! 240:
! 241: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
! 242: &sc->sc_dev);
! 243: }
! 244:
! 245: int
! 246: ueagle_detach(struct device *self, int flags)
! 247: {
! 248: struct ueagle_softc *sc = (struct ueagle_softc *)self;
! 249: struct ifnet *ifp = &sc->sc_if;
! 250:
! 251: if (sc->fw != NULL)
! 252: return 0; /* shortcut for pre-firmware devices */
! 253:
! 254: sc->gone = 1;
! 255: ueagle_stop(ifp, 1);
! 256:
! 257: /* wait for stat thread to exit properly */
! 258: if (sc->stat_thread != NULL) {
! 259: DPRINTFN(3, ("%s: waiting for stat thread to exit\n",
! 260: sc->sc_dev.dv_xname));
! 261:
! 262: tsleep(sc->stat_thread, PZERO, "ueaglestat", 0);
! 263:
! 264: DPRINTFN(3, ("%s: stat thread exited properly\n",
! 265: sc->sc_dev.dv_xname));
! 266: }
! 267:
! 268: if_detach(ifp);
! 269:
! 270: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
! 271: &sc->sc_dev);
! 272:
! 273: return 0;
! 274: }
! 275:
! 276: /*
! 277: * Retrieve the device End System Identifier (MAC address).
! 278: */
! 279: int
! 280: ueagle_getesi(struct ueagle_softc *sc, uint8_t *addr)
! 281: {
! 282: usb_string_descriptor_t us;
! 283: usbd_status error;
! 284: uint16_t c;
! 285: int i, len;
! 286:
! 287: error = usbd_get_string_desc(sc->sc_udev, UEAGLE_ESISTR, 0, &us, &len);
! 288: if (error != 0)
! 289: return error;
! 290:
! 291: if (us.bLength < (6 + 1) * 2)
! 292: return 1;
! 293:
! 294: for (i = 0; i < 6 * 2; i++) {
! 295: if ((c = UGETW(us.bString[i])) & 0xff00)
! 296: return 1; /* not 8-bit clean */
! 297:
! 298: if (i & 1)
! 299: addr[i / 2] <<= 4;
! 300: else
! 301: addr[i / 2] = 0;
! 302:
! 303: if (c >= '0' && c <= '9')
! 304: addr[i / 2] |= c - '0';
! 305: else if (c >= 'a' && c <= 'f')
! 306: addr[i / 2] |= c - 'a' + 10;
! 307: else if (c >= 'A' && c <= 'F')
! 308: addr[i / 2] |= c - 'A' + 10;
! 309: else
! 310: return 1;
! 311: }
! 312:
! 313: return 0;
! 314: }
! 315:
! 316: void
! 317: ueagle_loadpage(void *xsc)
! 318: {
! 319: struct ueagle_softc *sc = xsc;
! 320: usbd_xfer_handle xfer;
! 321: struct ueagle_block_info bi;
! 322: uint16_t pageno = sc->pageno;
! 323: uint16_t ovl = sc->ovl;
! 324: uint8_t pagecount, blockcount;
! 325: uint16_t blockaddr, blocksize;
! 326: uint32_t pageoffset;
! 327: uint8_t *p;
! 328: int i;
! 329:
! 330: p = sc->dsp;
! 331: pagecount = *p++;
! 332:
! 333: if (pageno >= pagecount) {
! 334: printf("%s: invalid page number %u requested\n",
! 335: sc->sc_dev.dv_xname, pageno);
! 336: return;
! 337: }
! 338:
! 339: p += 4 * pageno;
! 340: pageoffset = UGETDW(p);
! 341: if (pageoffset == 0)
! 342: return;
! 343:
! 344: p = sc->dsp + pageoffset;
! 345: blockcount = *p++;
! 346:
! 347: DPRINTF(("%s: sending %u blocks for fw page %u\n",
! 348: sc->sc_dev.dv_xname, blockcount, pageno));
! 349:
! 350: if ((xfer = usbd_alloc_xfer(sc->sc_udev)) == NULL) {
! 351: printf("%s: could not allocate xfer\n",
! 352: sc->sc_dev.dv_xname);
! 353: return;
! 354: }
! 355:
! 356: USETW(bi.wHdr, UEAGLE_BLOCK_INFO_HDR);
! 357: USETW(bi.wOvl, ovl);
! 358: USETW(bi.wOvlOffset, ovl | 0x8000);
! 359:
! 360: for (i = 0; i < blockcount; i++) {
! 361: blockaddr = UGETW(p); p += 2;
! 362: blocksize = UGETW(p); p += 2;
! 363:
! 364: USETW(bi.wSize, blocksize);
! 365: USETW(bi.wAddress, blockaddr);
! 366: USETW(bi.wLast, (i == blockcount - 1) ? 1 : 0);
! 367:
! 368: /* send block info through the IDMA pipe */
! 369: usbd_setup_xfer(xfer, sc->pipeh_idma, sc, &bi, sizeof bi, 0,
! 370: UEAGLE_IDMA_TIMEOUT, NULL);
! 371: if (usbd_sync_transfer(xfer) != 0) {
! 372: printf("%s: could not transfer block info\n",
! 373: sc->sc_dev.dv_xname);
! 374: break;
! 375: }
! 376:
! 377: /* send block data through the IDMA pipe */
! 378: usbd_setup_xfer(xfer, sc->pipeh_idma, sc, p, blocksize, 0,
! 379: UEAGLE_IDMA_TIMEOUT, NULL);
! 380: if (usbd_sync_transfer(xfer) != 0) {
! 381: printf("%s: could not transfer block data\n",
! 382: sc->sc_dev.dv_xname);
! 383: break;
! 384: }
! 385:
! 386: p += blocksize;
! 387: }
! 388:
! 389: usbd_free_xfer(xfer);
! 390: }
! 391:
! 392: void
! 393: ueagle_request(struct ueagle_softc *sc, uint16_t val, uint16_t index,
! 394: void *data, int len)
! 395: {
! 396: usb_device_request_t req;
! 397: usbd_status error;
! 398:
! 399: req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
! 400: req.bRequest = UEAGLE_REQUEST;
! 401: USETW(req.wValue, val);
! 402: USETW(req.wIndex, index);
! 403: USETW(req.wLength, len);
! 404:
! 405: error = usbd_do_request_async(sc->sc_udev, &req, data);
! 406: if (error != USBD_NORMAL_COMPLETION && error != USBD_IN_PROGRESS)
! 407: printf("%s: could not send request\n", sc->sc_dev.dv_xname);
! 408: }
! 409:
! 410: #ifdef USB_DEBUG
! 411: void
! 412: ueagle_dump_cmv(struct ueagle_softc *sc, struct ueagle_cmv *cmv)
! 413: {
! 414: printf(" Preamble: 0x%04x\n", UGETW(cmv->wPreamble));
! 415: printf(" Destination: %s (0x%02x)\n",
! 416: (cmv->bDst == UEAGLE_HOST) ? "Host" : "Modem", cmv->bDst);
! 417: printf(" Type: %u\n", cmv->bFunction >> 4);
! 418: printf(" Subtype: %u\n", cmv->bFunction & 0xf);
! 419: printf(" Index: %u\n", UGETW(cmv->wIndex));
! 420: printf(" Address: %c%c%c%c.%u\n",
! 421: cmv->dwSymbolicAddress[1], cmv->dwSymbolicAddress[0],
! 422: cmv->dwSymbolicAddress[3], cmv->dwSymbolicAddress[2],
! 423: UGETW(cmv->wOffsetAddress));
! 424: printf(" Data: 0x%08x\n", UGETDATA(cmv->dwData));
! 425: }
! 426: #endif
! 427:
! 428: int
! 429: ueagle_cr(struct ueagle_softc *sc, uint32_t address, uint16_t offset,
! 430: uint32_t *data)
! 431: {
! 432: struct ueagle_cmv cmv;
! 433: usbd_status error;
! 434: int s;
! 435:
! 436: USETW(cmv.wPreamble, UEAGLE_CMV_PREAMBLE);
! 437: cmv.bDst = UEAGLE_MODEM;
! 438: cmv.bFunction = UEAGLE_CR;
! 439: USETW(cmv.wIndex, sc->index);
! 440: USETW(cmv.wOffsetAddress, offset);
! 441: USETDW(cmv.dwSymbolicAddress, address);
! 442: USETDATA(cmv.dwData, 0);
! 443:
! 444: #ifdef USB_DEBUG
! 445: if (ueagledebug >= 15) {
! 446: printf("%s: reading CMV\n", sc->sc_dev.dv_xname);
! 447: ueagle_dump_cmv(sc, &cmv);
! 448: }
! 449: #endif
! 450:
! 451: s = splusb();
! 452:
! 453: ueagle_request(sc, UEAGLE_SETBLOCK, UEAGLE_MPTXSTART, &cmv, sizeof cmv);
! 454:
! 455: /* wait at most 2 seconds for an answer */
! 456: error = tsleep(UEAGLE_COND_CMV(sc), PZERO, "cmv", 2 * hz);
! 457: if (error != 0) {
! 458: printf("%s: timeout waiting for CMV ack\n",
! 459: sc->sc_dev.dv_xname);
! 460: splx(s);
! 461: return error;
! 462: }
! 463:
! 464: *data = sc->data;
! 465: splx(s);
! 466:
! 467: return 0;
! 468: }
! 469:
! 470: int
! 471: ueagle_cw(struct ueagle_softc *sc, uint32_t address, uint16_t offset,
! 472: uint32_t data)
! 473: {
! 474: struct ueagle_cmv cmv;
! 475: usbd_status error;
! 476: int s;
! 477:
! 478: USETW(cmv.wPreamble, UEAGLE_CMV_PREAMBLE);
! 479: cmv.bDst = UEAGLE_MODEM;
! 480: cmv.bFunction = UEAGLE_CW;
! 481: USETW(cmv.wIndex, sc->index);
! 482: USETW(cmv.wOffsetAddress, offset);
! 483: USETDW(cmv.dwSymbolicAddress, address);
! 484: USETDATA(cmv.dwData, data);
! 485:
! 486: #ifdef USB_DEBUG
! 487: if (ueagledebug >= 15) {
! 488: printf("%s: writing CMV\n", sc->sc_dev.dv_xname);
! 489: ueagle_dump_cmv(sc, &cmv);
! 490: }
! 491: #endif
! 492:
! 493: s = splusb();
! 494:
! 495: ueagle_request(sc, UEAGLE_SETBLOCK, UEAGLE_MPTXSTART, &cmv, sizeof cmv);
! 496:
! 497: /* wait at most 2 seconds for an answer */
! 498: error = tsleep(UEAGLE_COND_CMV(sc), PZERO, "cmv", 2 * hz);
! 499: if (error != 0) {
! 500: printf("%s: timeout waiting for CMV ack\n",
! 501: sc->sc_dev.dv_xname);
! 502: splx(s);
! 503: return error;
! 504: }
! 505:
! 506: splx(s);
! 507:
! 508: return 0;
! 509: }
! 510:
! 511: int
! 512: ueagle_stat(struct ueagle_softc *sc)
! 513: {
! 514: struct ifnet *ifp = &sc->sc_if;
! 515: uint32_t data;
! 516: usbd_status error;
! 517: #define CR(sc, address, offset, data) do { \
! 518: if ((error = ueagle_cr(sc, address, offset, data)) != 0) \
! 519: return error; \
! 520: } while (0)
! 521:
! 522: CR(sc, UEAGLE_CMV_STAT, 0, &sc->stats.phy.status);
! 523: switch ((sc->stats.phy.status >> 8) & 0xf) {
! 524: case 0: /* idle */
! 525: DPRINTFN(3, ("%s: waiting for synchronization\n",
! 526: sc->sc_dev.dv_xname));
! 527: return ueagle_cw(sc, UEAGLE_CMV_CNTL, 0, 2);
! 528:
! 529: case 1: /* initialization */
! 530: DPRINTFN(3, ("%s: initializing\n", sc->sc_dev.dv_xname));
! 531: return ueagle_cw(sc, UEAGLE_CMV_CNTL, 0, 2);
! 532:
! 533: case 2: /* operational */
! 534: DPRINTFN(4, ("%s: operational\n", sc->sc_dev.dv_xname));
! 535: break;
! 536:
! 537: default: /* fail ... */
! 538: DPRINTFN(3, ("%s: synchronization failed\n",
! 539: sc->sc_dev.dv_xname));
! 540: ueagle_init(ifp);
! 541: return 1;
! 542: }
! 543:
! 544: CR(sc, UEAGLE_CMV_DIAG, 1, &sc->stats.phy.flags);
! 545: if (sc->stats.phy.flags & 0x10) {
! 546: DPRINTF(("%s: delineation LOSS\n", sc->sc_dev.dv_xname));
! 547: sc->stats.phy.status = 0;
! 548: ueagle_init(ifp);
! 549: return 1;
! 550: }
! 551:
! 552: CR(sc, UEAGLE_CMV_RATE, 0, &data);
! 553: sc->stats.phy.dsrate = ((data >> 16) & 0x1ff) * 32;
! 554: sc->stats.phy.usrate = (data & 0xff) * 32;
! 555:
! 556: CR(sc, UEAGLE_CMV_DIAG, 23, &data);
! 557: sc->stats.phy.attenuation = (data & 0xff) / 2;
! 558:
! 559: CR(sc, UEAGLE_CMV_DIAG, 3, &sc->stats.atm.cells_crc_errors);
! 560: CR(sc, UEAGLE_CMV_DIAG, 22, &sc->stats.phy.dserror);
! 561: CR(sc, UEAGLE_CMV_DIAG, 25, &sc->stats.phy.dsmargin);
! 562: CR(sc, UEAGLE_CMV_DIAG, 46, &sc->stats.phy.userror);
! 563: CR(sc, UEAGLE_CMV_DIAG, 49, &sc->stats.phy.usmargin);
! 564: CR(sc, UEAGLE_CMV_DIAG, 51, &sc->stats.phy.rxflow);
! 565: CR(sc, UEAGLE_CMV_DIAG, 52, &sc->stats.phy.txflow);
! 566: CR(sc, UEAGLE_CMV_DIAG, 54, &sc->stats.phy.dsunc);
! 567: CR(sc, UEAGLE_CMV_DIAG, 58, &sc->stats.phy.usunc);
! 568: CR(sc, UEAGLE_CMV_INFO, 8, &sc->stats.phy.vidco);
! 569: CR(sc, UEAGLE_CMV_INFO, 14, &sc->stats.phy.vidcpe);
! 570:
! 571: if (sc->pipeh_tx != NULL)
! 572: return 0;
! 573:
! 574: return ueagle_open_pipes(sc);
! 575: #undef CR
! 576: }
! 577:
! 578: void
! 579: ueagle_stat_thread(void *arg)
! 580: {
! 581: struct ueagle_softc *sc = arg;
! 582:
! 583: for (;;) {
! 584: if (ueagle_stat(sc) != 0)
! 585: break;
! 586:
! 587: usbd_delay_ms(sc->sc_udev, 5000);
! 588: }
! 589:
! 590: wakeup(sc->stat_thread);
! 591:
! 592: kthread_exit(0);
! 593: }
! 594:
! 595: int
! 596: ueagle_boot(struct ueagle_softc *sc)
! 597: {
! 598: uint16_t zero = 0; /* ;-) */
! 599: usbd_status error;
! 600: #define CW(sc, address, offset, data) do { \
! 601: if ((error = ueagle_cw(sc, address, offset, data)) != 0) \
! 602: return error; \
! 603: } while (0)
! 604:
! 605: ueagle_request(sc, UEAGLE_SETMODE, UEAGLE_BOOTIDMA, NULL, 0);
! 606: ueagle_request(sc, UEAGLE_SETMODE, UEAGLE_STARTRESET, NULL, 0);
! 607:
! 608: usbd_delay_ms(sc->sc_udev, 200);
! 609:
! 610: ueagle_request(sc, UEAGLE_SETMODE, UEAGLE_ENDRESET, NULL, 0);
! 611: ueagle_request(sc, UEAGLE_SET2183DATA, UEAGLE_MPTXMAILBOX, &zero, 2);
! 612: ueagle_request(sc, UEAGLE_SET2183DATA, UEAGLE_MPRXMAILBOX, &zero, 2);
! 613: ueagle_request(sc, UEAGLE_SET2183DATA, UEAGLE_SWAPMAILBOX, &zero, 2);
! 614:
! 615: usbd_delay_ms(sc->sc_udev, 1000);
! 616:
! 617: sc->pageno = 0;
! 618: sc->ovl = 0;
! 619: ueagle_loadpage(sc);
! 620:
! 621: /* wait until modem reaches operationnal state */
! 622: error = tsleep(UEAGLE_COND_READY(sc), PZERO | PCATCH, "boot", 10 * hz);
! 623: if (error != 0) {
! 624: printf("%s: timeout waiting for operationnal state\n",
! 625: sc->sc_dev.dv_xname);
! 626: return error;
! 627: }
! 628:
! 629: CW(sc, UEAGLE_CMV_CNTL, 0, 1);
! 630:
! 631: /* send configuration options */
! 632: CW(sc, UEAGLE_CMV_OPTN, 0, UEAGLE_OPTN0);
! 633: CW(sc, UEAGLE_CMV_OPTN, 2, UEAGLE_OPTN2);
! 634: CW(sc, UEAGLE_CMV_OPTN, 7, UEAGLE_OPTN7);
! 635:
! 636: /* continue with synchronization */
! 637: CW(sc, UEAGLE_CMV_CNTL, 0, 2);
! 638:
! 639: return kthread_create(ueagle_stat_thread, sc, &sc->stat_thread,
! 640: sc->sc_dev.dv_xname);
! 641: #undef CW
! 642: }
! 643:
! 644: void
! 645: ueagle_swap_intr(struct ueagle_softc *sc, struct ueagle_swap *swap)
! 646: {
! 647: #define rotbr(v, n) ((v) >> (n) | (v) << (8 - (n)))
! 648: sc->pageno = swap->bPageNo;
! 649: sc->ovl = rotbr(swap->bOvl, 4);
! 650:
! 651: usb_add_task(sc->sc_udev, &sc->sc_swap_task);
! 652: #undef rotbr
! 653: }
! 654:
! 655: /*
! 656: * This function handles spontaneous CMVs and CMV acknowledgements sent by the
! 657: * modem on the interrupt pipe.
! 658: */
! 659: void
! 660: ueagle_cmv_intr(struct ueagle_softc *sc, struct ueagle_cmv *cmv)
! 661: {
! 662: #ifdef USB_DEBUG
! 663: if (ueagledebug >= 15) {
! 664: printf("%s: receiving CMV\n", sc->sc_dev.dv_xname);
! 665: ueagle_dump_cmv(sc, cmv);
! 666: }
! 667: #endif
! 668:
! 669: if (UGETW(cmv->wPreamble) != UEAGLE_CMV_PREAMBLE) {
! 670: printf("%s: received CMV with invalid preamble\n",
! 671: sc->sc_dev.dv_xname);
! 672: return;
! 673: }
! 674:
! 675: if (cmv->bDst != UEAGLE_HOST) {
! 676: printf("%s: received CMV with bad direction\n",
! 677: sc->sc_dev.dv_xname);
! 678: return;
! 679: }
! 680:
! 681: /* synchronize our current CMV index with the modem */
! 682: sc->index = UGETW(cmv->wIndex) + 1;
! 683:
! 684: switch (cmv->bFunction) {
! 685: case UEAGLE_MODEMREADY:
! 686: wakeup(UEAGLE_COND_READY(sc));
! 687: break;
! 688:
! 689: case UEAGLE_CR_ACK:
! 690: sc->data = UGETDATA(cmv->dwData);
! 691: /* FALLTHROUGH */
! 692: case UEAGLE_CW_ACK:
! 693: wakeup(UEAGLE_COND_CMV(sc));
! 694: break;
! 695: }
! 696: }
! 697:
! 698: void
! 699: ueagle_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
! 700: {
! 701: struct ueagle_softc *sc = priv;
! 702: struct ueagle_intr *intr;
! 703:
! 704: if (status != USBD_NORMAL_COMPLETION) {
! 705: if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
! 706: return;
! 707:
! 708: printf("%s: abnormal interrupt status: %s\n",
! 709: sc->sc_dev.dv_xname, usbd_errstr(status));
! 710:
! 711: if (status == USBD_STALLED)
! 712: usbd_clear_endpoint_stall_async(sc->pipeh_intr);
! 713:
! 714: return;
! 715: }
! 716:
! 717: intr = (struct ueagle_intr *)sc->ibuf;
! 718: switch (UGETW(intr->wInterrupt)) {
! 719: case UEAGLE_INTR_SWAP:
! 720: ueagle_swap_intr(sc, (struct ueagle_swap *)(intr + 1));
! 721: break;
! 722:
! 723: case UEAGLE_INTR_CMV:
! 724: ueagle_cmv_intr(sc, (struct ueagle_cmv *)(intr + 1));
! 725: break;
! 726:
! 727: default:
! 728: printf("%s: caught unknown interrupt\n",
! 729: sc->sc_dev.dv_xname);
! 730: }
! 731: }
! 732:
! 733: static const uint32_t ueagle_crc32_table[256] = {
! 734: 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc,
! 735: 0x17c56b6b, 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f,
! 736: 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a,
! 737: 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
! 738: 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8,
! 739: 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
! 740: 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e,
! 741: 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
! 742: 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84,
! 743: 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027,
! 744: 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022,
! 745: 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
! 746: 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077,
! 747: 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c,
! 748: 0x2e003dc5, 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1,
! 749: 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
! 750: 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb,
! 751: 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
! 752: 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d,
! 753: 0x40d816ba, 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
! 754: 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f,
! 755: 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044,
! 756: 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689,
! 757: 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
! 758: 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683,
! 759: 0xd1799b34, 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59,
! 760: 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c,
! 761: 0x774bb0eb, 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
! 762: 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e,
! 763: 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
! 764: 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48,
! 765: 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
! 766: 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2,
! 767: 0xe6ea3d65, 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601,
! 768: 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604,
! 769: 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
! 770: 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6,
! 771: 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad,
! 772: 0x81b02d74, 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7,
! 773: 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
! 774: 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd,
! 775: 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
! 776: 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b,
! 777: 0x0fdc1bec, 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
! 778: 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679,
! 779: 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12,
! 780: 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af,
! 781: 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
! 782: 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5,
! 783: 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06,
! 784: 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03,
! 785: 0xb1f740b4
! 786: };
! 787:
! 788: uint32_t
! 789: ueagle_crc_update(uint32_t crc, uint8_t *buf, int len)
! 790: {
! 791: for (; len != 0; len--, buf++)
! 792: crc = ueagle_crc32_table[(crc >> 24) ^ *buf] ^ (crc << 8);
! 793:
! 794: return crc;
! 795: }
! 796:
! 797: /*
! 798: * Reassembly part of the software ATM AAL5 SAR.
! 799: */
! 800: void
! 801: ueagle_push_cell(struct ueagle_softc *sc, uint8_t *cell)
! 802: {
! 803: struct ueagle_vcc *vcc = &sc->vcc;
! 804: struct ifnet *ifp;
! 805: struct mbuf *m;
! 806: uint32_t crc;
! 807: uint16_t pdulen, totlen;
! 808: int s;
! 809:
! 810: sc->stats.atm.cells_received++;
! 811:
! 812: if (!(vcc->flags & UEAGLE_VCC_ACTIVE) ||
! 813: ATM_CH_GETVPI(cell) != vcc->vpi ||
! 814: ATM_CH_GETVCI(cell) != vcc->vci) {
! 815: sc->stats.atm.vcc_no_conn++;
! 816: return;
! 817: }
! 818:
! 819: if (vcc->flags & UEAGLE_VCC_DROP) {
! 820: if (ATM_CH_ISLASTCELL(cell)) {
! 821: vcc->flags &= ~UEAGLE_VCC_DROP;
! 822: sc->stats.atm.cspdus_dropped++;
! 823: }
! 824:
! 825: sc->stats.atm.cells_dropped++;
! 826: return;
! 827: }
! 828:
! 829: if (vcc->m == NULL) {
! 830: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 831: if (m == NULL) {
! 832: vcc->flags |= UEAGLE_VCC_DROP;
! 833: return;
! 834: }
! 835:
! 836: MCLGET(m, M_DONTWAIT);
! 837: if (!(m->m_flags & M_EXT)) {
! 838: vcc->flags |= UEAGLE_VCC_DROP;
! 839: m_freem(m);
! 840: return;
! 841: }
! 842:
! 843: vcc->m = m;
! 844: vcc->dst = mtod(m, uint8_t *);
! 845: vcc->limit = vcc->dst + MCLBYTES - ATM_CELL_PAYLOAD_SIZE;
! 846: }
! 847:
! 848: if (vcc->dst > vcc->limit) {
! 849: vcc->flags |= UEAGLE_VCC_DROP;
! 850: sc->stats.atm.cells_dropped++;
! 851: goto fail;
! 852: }
! 853:
! 854: memcpy(vcc->dst, cell + ATM_CELL_HEADER_SIZE, ATM_CELL_PAYLOAD_SIZE);
! 855: vcc->dst += ATM_CELL_PAYLOAD_SIZE;
! 856:
! 857: if (!ATM_CH_ISLASTCELL(cell))
! 858: return;
! 859:
! 860: /*
! 861: * Handle the last cell of the AAL5 CPCS-PDU.
! 862: */
! 863: m = vcc->m;
! 864:
! 865: totlen = vcc->dst - mtod(m, uint8_t *);
! 866: pdulen = AAL5_TR_GETPDULEN(cell);
! 867:
! 868: if (totlen < pdulen + AAL5_TRAILER_SIZE) {
! 869: sc->stats.atm.cspdus_dropped++;
! 870: goto fail;
! 871: }
! 872:
! 873: if (totlen >= pdulen + ATM_CELL_PAYLOAD_SIZE + AAL5_TRAILER_SIZE) {
! 874: sc->stats.atm.cspdus_dropped++;
! 875: goto fail;
! 876: }
! 877:
! 878: crc = ueagle_crc_update(CRC_INITIAL, mtod(m, uint8_t *), totlen);
! 879: if (crc != CRC_MAGIC) {
! 880: sc->stats.atm.cspdus_crc_errors++;
! 881: goto fail;
! 882: }
! 883:
! 884: /* finalize mbuf */
! 885: ifp = &sc->sc_if;
! 886: m->m_pkthdr.rcvif = ifp;
! 887: m->m_pkthdr.len = m->m_len = pdulen;
! 888:
! 889: sc->stats.atm.cspdus_received++;
! 890:
! 891: s = splnet();
! 892:
! 893: #if NBPFILTER > 0
! 894: if (ifp->if_bpf != NULL)
! 895: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
! 896: #endif
! 897:
! 898: /* send the AAL5 CPCS-PDU to the ATM layer */
! 899: ifp->if_ipackets++;
! 900: atm_input(ifp, &vcc->aph, m, vcc->rxhand);
! 901: vcc->m = NULL;
! 902:
! 903: splx(s);
! 904:
! 905: return;
! 906:
! 907: fail: m_freem(vcc->m);
! 908: vcc->m = NULL;
! 909: }
! 910:
! 911: void
! 912: ueagle_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv,
! 913: usbd_status status)
! 914: {
! 915: struct ueagle_isoreq *req = priv;
! 916: struct ueagle_softc *sc = req->sc;
! 917: uint32_t count;
! 918: uint8_t *p;
! 919: int i;
! 920:
! 921: if (status == USBD_CANCELLED)
! 922: return;
! 923:
! 924: for (i = 0; i < UEAGLE_NISOFRMS; i++) {
! 925: count = req->frlengths[i];
! 926: p = req->offsets[i];
! 927:
! 928: while (count >= ATM_CELL_SIZE) {
! 929: ueagle_push_cell(sc, p);
! 930: p += ATM_CELL_SIZE;
! 931: count -= ATM_CELL_SIZE;
! 932: }
! 933: #ifdef DIAGNOSTIC
! 934: if (count > 0) {
! 935: printf("%s: truncated cell (%u bytes)\n",
! 936: sc->sc_dev.dv_xname, count);
! 937: }
! 938: #endif
! 939: req->frlengths[i] = sc->isize;
! 940: }
! 941:
! 942: usbd_setup_isoc_xfer(req->xfer, sc->pipeh_rx, req, req->frlengths,
! 943: UEAGLE_NISOFRMS, USBD_NO_COPY, ueagle_rxeof);
! 944: usbd_transfer(xfer);
! 945: }
! 946:
! 947: void
! 948: ueagle_txeof(usbd_xfer_handle xfer, usbd_private_handle priv,
! 949: usbd_status status)
! 950: {
! 951: struct ueagle_txreq *req = priv;
! 952: struct ueagle_softc *sc = req->sc;
! 953: struct ifnet *ifp = &sc->sc_if;
! 954: int s;
! 955:
! 956: if (status != USBD_NORMAL_COMPLETION) {
! 957: if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
! 958: return;
! 959:
! 960: printf("%s: could not transmit buffer: %s\n",
! 961: sc->sc_dev.dv_xname, usbd_errstr(status));
! 962:
! 963: if (status == USBD_STALLED)
! 964: usbd_clear_endpoint_stall_async(sc->pipeh_tx);
! 965:
! 966: ifp->if_oerrors++;
! 967: return;
! 968: }
! 969:
! 970: s = splnet();
! 971:
! 972: ifp->if_opackets++;
! 973: ifp->if_flags &= ~IFF_OACTIVE;
! 974: ueagle_start(ifp);
! 975:
! 976: splx(s);
! 977: }
! 978:
! 979: /*
! 980: * Segmentation part of the software ATM AAL5 SAR.
! 981: */
! 982: int
! 983: ueagle_encap(struct ueagle_softc *sc, struct mbuf *m0)
! 984: {
! 985: struct ueagle_vcc *vcc = &sc->vcc;
! 986: struct ueagle_txreq *req;
! 987: struct mbuf *m;
! 988: uint8_t *src, *dst;
! 989: uint32_t crc;
! 990: int n, cellleft, mleft;
! 991: usbd_status error;
! 992:
! 993: req = &sc->txreqs[0];
! 994:
! 995: m_adj(m0, sizeof (struct atm_pseudohdr));
! 996:
! 997: dst = req->buf;
! 998: cellleft = 0;
! 999: crc = CRC_INITIAL;
! 1000:
! 1001: for (m = m0; m != NULL; m = m->m_next) {
! 1002: src = mtod(m, uint8_t *);
! 1003: mleft = m->m_len;
! 1004:
! 1005: crc = ueagle_crc_update(crc, src, mleft);
! 1006:
! 1007: if (cellleft != 0) {
! 1008: n = min(mleft, cellleft);
! 1009:
! 1010: memcpy(dst, src, n);
! 1011: dst += n;
! 1012: src += n;
! 1013: cellleft -= n;
! 1014: mleft -= n;
! 1015: }
! 1016:
! 1017: while (mleft >= ATM_CELL_PAYLOAD_SIZE) {
! 1018: memcpy(dst, vcc->ch, ATM_CELL_HEADER_SIZE);
! 1019: dst += ATM_CELL_HEADER_SIZE;
! 1020: memcpy(dst, src, ATM_CELL_PAYLOAD_SIZE);
! 1021: dst += ATM_CELL_PAYLOAD_SIZE;
! 1022: src += ATM_CELL_PAYLOAD_SIZE;
! 1023: mleft -= ATM_CELL_PAYLOAD_SIZE;
! 1024: sc->stats.atm.cells_transmitted++;
! 1025: }
! 1026:
! 1027: if (mleft != 0) {
! 1028: memcpy(dst, vcc->ch, ATM_CELL_HEADER_SIZE);
! 1029: dst += ATM_CELL_HEADER_SIZE;
! 1030: memcpy(dst, src, mleft);
! 1031: dst += mleft;
! 1032: cellleft = ATM_CELL_PAYLOAD_SIZE - mleft;
! 1033: sc->stats.atm.cells_transmitted++;
! 1034: }
! 1035: }
! 1036:
! 1037: /*
! 1038: * If there is not enough space to put the AAL5 trailer into this cell,
! 1039: * pad the content of this cell with zeros and create a new cell which
! 1040: * will contain no data except the AAL5 trailer itself.
! 1041: */
! 1042: if (cellleft < AAL5_TRAILER_SIZE) {
! 1043: memset(dst, 0, cellleft);
! 1044: crc = ueagle_crc_update(crc, dst, cellleft);
! 1045: dst += cellleft;
! 1046:
! 1047: memcpy(dst, vcc->ch, ATM_CELL_HEADER_SIZE);
! 1048: dst += ATM_CELL_HEADER_SIZE;
! 1049: cellleft = ATM_CELL_PAYLOAD_SIZE;
! 1050: sc->stats.atm.cells_transmitted++;
! 1051: }
! 1052:
! 1053: /*
! 1054: * Fill the AAL5 CPCS-PDU trailer.
! 1055: */
! 1056: memset(dst, 0, cellleft - AAL5_TRAILER_SIZE);
! 1057:
! 1058: /* src now points to the beginning of the last cell */
! 1059: src = dst + cellleft - ATM_CELL_SIZE;
! 1060: ATM_CH_SETPTFLAGS(src, 1);
! 1061:
! 1062: AAL5_TR_SETCPSUU(src, 0);
! 1063: AAL5_TR_SETCPI(src, 0);
! 1064: AAL5_TR_SETPDULEN(src, m0->m_pkthdr.len);
! 1065:
! 1066: crc = ~ueagle_crc_update(crc, dst, cellleft - 4);
! 1067: AAL5_TR_SETCRC(src, crc);
! 1068:
! 1069: usbd_setup_xfer(req->xfer, sc->pipeh_tx, req, req->buf,
! 1070: dst + cellleft - req->buf, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
! 1071: UEAGLE_TX_TIMEOUT, ueagle_txeof);
! 1072:
! 1073: error = usbd_transfer(req->xfer);
! 1074: if (error != USBD_NORMAL_COMPLETION && error != USBD_IN_PROGRESS)
! 1075: return error;
! 1076:
! 1077: sc->stats.atm.cspdus_transmitted++;
! 1078:
! 1079: return 0;
! 1080: }
! 1081:
! 1082: void
! 1083: ueagle_start(struct ifnet *ifp)
! 1084: {
! 1085: struct ueagle_softc *sc = ifp->if_softc;
! 1086: struct mbuf *m0;
! 1087:
! 1088: /* nothing goes out until modem is synchronized and VCC is opened */
! 1089: if (!(sc->vcc.flags & UEAGLE_VCC_ACTIVE))
! 1090: return;
! 1091:
! 1092: if (sc->pipeh_tx == NULL)
! 1093: return;
! 1094:
! 1095: IFQ_POLL(&ifp->if_snd, m0);
! 1096: if (m0 == NULL)
! 1097: return;
! 1098: IFQ_DEQUEUE(&ifp->if_snd, m0);
! 1099:
! 1100: if (ueagle_encap(sc, m0) != 0) {
! 1101: m_freem(m0);
! 1102: return;
! 1103: }
! 1104:
! 1105: #if NBPFILTER > 0
! 1106: if (ifp->if_bpf != NULL)
! 1107: bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
! 1108: #endif
! 1109:
! 1110: m_freem(m0);
! 1111:
! 1112: ifp->if_flags |= IFF_OACTIVE;
! 1113: }
! 1114:
! 1115: int
! 1116: ueagle_open_vcc(struct ueagle_softc *sc, struct atm_pseudoioctl *api)
! 1117: {
! 1118: struct ueagle_vcc *vcc = &sc->vcc;
! 1119:
! 1120: DPRINTF(("%s: opening ATM VCC\n", sc->sc_dev.dv_xname));
! 1121:
! 1122: vcc->vpi = ATM_PH_VPI(&api->aph);
! 1123: vcc->vci = ATM_PH_VCI(&api->aph);
! 1124: vcc->rxhand = api->rxhand;
! 1125: vcc->m = NULL;
! 1126: vcc->aph = api->aph;
! 1127: vcc->flags = UEAGLE_VCC_ACTIVE;
! 1128:
! 1129: /* pre-calculate cell headers (HEC field is set by hardware) */
! 1130: ATM_CH_FILL(vcc->ch, 0, vcc->vpi, vcc->vci, 0, 0, 0);
! 1131:
! 1132: return 0;
! 1133: }
! 1134:
! 1135: int
! 1136: ueagle_close_vcc(struct ueagle_softc *sc, struct atm_pseudoioctl *api)
! 1137: {
! 1138: DPRINTF(("%s: closing ATM VCC\n", sc->sc_dev.dv_xname));
! 1139:
! 1140: sc->vcc.flags &= ~UEAGLE_VCC_ACTIVE;
! 1141:
! 1142: return 0;
! 1143: }
! 1144:
! 1145: int
! 1146: ueagle_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
! 1147: {
! 1148: struct ueagle_softc *sc = ifp->if_softc;
! 1149: struct atm_pseudoioctl *api;
! 1150: struct ifaddr *ifa;
! 1151: struct ifreq *ifr;
! 1152: int s, error = 0;
! 1153:
! 1154: s = splnet();
! 1155:
! 1156: switch (cmd) {
! 1157: case SIOCSIFADDR:
! 1158: ifa = (struct ifaddr *)data;
! 1159: ifp->if_flags |= IFF_UP;
! 1160:
! 1161: ueagle_init(ifp);
! 1162: #ifdef INET
! 1163: ifa->ifa_rtrequest = atm_rtrequest;
! 1164: #endif
! 1165: break;
! 1166:
! 1167: case SIOCSIFFLAGS:
! 1168: if (ifp->if_flags & IFF_UP) {
! 1169: if (!(ifp->if_flags & IFF_RUNNING))
! 1170: ueagle_init(ifp);
! 1171: } else {
! 1172: if (ifp->if_flags & IFF_RUNNING)
! 1173: ueagle_stop(ifp, 1);
! 1174: }
! 1175: break;
! 1176:
! 1177: case SIOCSIFMTU:
! 1178: ifr = (struct ifreq *)data;
! 1179:
! 1180: if (ifr->ifr_mtu > UEAGLE_IFMTU)
! 1181: error = EINVAL;
! 1182: else
! 1183: ifp->if_mtu = ifr->ifr_mtu;
! 1184: break;
! 1185:
! 1186: case SIOCATMENA:
! 1187: api = (struct atm_pseudoioctl *)data;
! 1188: error = ueagle_open_vcc(sc, api);
! 1189: break;
! 1190:
! 1191: case SIOCATMDIS:
! 1192: api = (struct atm_pseudoioctl *)data;
! 1193: error = ueagle_close_vcc(sc, api);
! 1194: break;
! 1195:
! 1196: default:
! 1197: error = EINVAL;
! 1198: }
! 1199:
! 1200: splx(s);
! 1201:
! 1202: return error;
! 1203: }
! 1204:
! 1205: int
! 1206: ueagle_open_pipes(struct ueagle_softc *sc)
! 1207: {
! 1208: usb_endpoint_descriptor_t *edesc;
! 1209: usbd_interface_handle iface;
! 1210: struct ueagle_txreq *txreq;
! 1211: struct ueagle_isoreq *isoreq;
! 1212: usbd_status error;
! 1213: uint8_t *buf;
! 1214: int i, j;
! 1215:
! 1216: error = usbd_device2interface_handle(sc->sc_udev, UEAGLE_US_IFACE_NO,
! 1217: &iface);
! 1218: if (error != 0) {
! 1219: printf("%s: could not get tx interface handle\n",
! 1220: sc->sc_dev.dv_xname);
! 1221: goto fail;
! 1222: }
! 1223:
! 1224: error = usbd_open_pipe(iface, UEAGLE_TX_PIPE, USBD_EXCLUSIVE_USE,
! 1225: &sc->pipeh_tx);
! 1226: if (error != 0) {
! 1227: printf("%s: could not open tx pipe\n", sc->sc_dev.dv_xname);
! 1228: goto fail;
! 1229: }
! 1230:
! 1231: for (i = 0; i < UEAGLE_TX_LIST_CNT; i++) {
! 1232: txreq = &sc->txreqs[i];
! 1233:
! 1234: txreq->sc = sc;
! 1235:
! 1236: txreq->xfer = usbd_alloc_xfer(sc->sc_udev);
! 1237: if (txreq->xfer == NULL) {
! 1238: printf("%s: could not allocate tx xfer\n",
! 1239: sc->sc_dev.dv_xname);
! 1240: error = ENOMEM;
! 1241: goto fail;
! 1242: }
! 1243:
! 1244: txreq->buf = usbd_alloc_buffer(txreq->xfer, UEAGLE_TXBUFLEN);
! 1245: if (txreq->buf == NULL) {
! 1246: printf("%s: could not allocate tx buffer\n",
! 1247: sc->sc_dev.dv_xname);
! 1248: error = ENOMEM;
! 1249: goto fail;
! 1250: }
! 1251: }
! 1252:
! 1253: error = usbd_device2interface_handle(sc->sc_udev, UEAGLE_DS_IFACE_NO,
! 1254: &iface);
! 1255: if (error != 0) {
! 1256: printf("%s: could not get rx interface handle\n",
! 1257: sc->sc_dev.dv_xname);
! 1258: goto fail;
! 1259: }
! 1260:
! 1261: /* XXX: alternative interface number sould depend on downrate */
! 1262: error = usbd_set_interface(iface, 8);
! 1263: if (error != 0) {
! 1264: printf("%s: could not set rx alternative interface\n",
! 1265: sc->sc_dev.dv_xname);
! 1266: goto fail;
! 1267: }
! 1268:
! 1269: edesc = usbd_get_endpoint_descriptor(iface, UEAGLE_RX_PIPE);
! 1270: if (edesc == NULL) {
! 1271: printf("%s: could not get rx endpoint descriptor\n",
! 1272: sc->sc_dev.dv_xname);
! 1273: error = EIO;
! 1274: goto fail;
! 1275: }
! 1276:
! 1277: sc->isize = UGETW(edesc->wMaxPacketSize);
! 1278:
! 1279: error = usbd_open_pipe(iface, UEAGLE_RX_PIPE, USBD_EXCLUSIVE_USE,
! 1280: &sc->pipeh_rx);
! 1281: if (error != 0) {
! 1282: printf("%s: could not open rx pipe\n", sc->sc_dev.dv_xname);
! 1283: goto fail;
! 1284: }
! 1285:
! 1286: for (i = 0; i < UEAGLE_NISOREQS; i++) {
! 1287: isoreq = &sc->isoreqs[i];
! 1288:
! 1289: isoreq->sc = sc;
! 1290:
! 1291: isoreq->xfer = usbd_alloc_xfer(sc->sc_udev);
! 1292: if (isoreq->xfer == NULL) {
! 1293: printf("%s: could not allocate rx xfer\n",
! 1294: sc->sc_dev.dv_xname);
! 1295: error = ENOMEM;
! 1296: goto fail;
! 1297: }
! 1298:
! 1299: buf = usbd_alloc_buffer(isoreq->xfer,
! 1300: sc->isize * UEAGLE_NISOFRMS);
! 1301: if (buf == NULL) {
! 1302: printf("%s: could not allocate rx buffer\n",
! 1303: sc->sc_dev.dv_xname);
! 1304: error = ENOMEM;
! 1305: goto fail;
! 1306: }
! 1307:
! 1308: for (j = 0; j < UEAGLE_NISOFRMS; j++) {
! 1309: isoreq->frlengths[j] = sc->isize;
! 1310: isoreq->offsets[j] = buf + j * sc->isize;
! 1311: }
! 1312:
! 1313: usbd_setup_isoc_xfer(isoreq->xfer, sc->pipeh_rx, isoreq,
! 1314: isoreq->frlengths, UEAGLE_NISOFRMS, USBD_NO_COPY,
! 1315: ueagle_rxeof);
! 1316: usbd_transfer(isoreq->xfer);
! 1317: }
! 1318:
! 1319: ueagle_request(sc, UEAGLE_SETMODE, UEAGLE_LOOPBACKOFF, NULL, 0);
! 1320:
! 1321: return 0;
! 1322:
! 1323: fail: ueagle_close_pipes(sc);
! 1324: return error;
! 1325: }
! 1326:
! 1327: void
! 1328: ueagle_close_pipes(struct ueagle_softc *sc)
! 1329: {
! 1330: int i;
! 1331:
! 1332: ueagle_request(sc, UEAGLE_SETMODE, UEAGLE_LOOPBACKON, NULL, 0);
! 1333:
! 1334: /* free Tx resources */
! 1335: if (sc->pipeh_tx != NULL) {
! 1336: usbd_abort_pipe(sc->pipeh_tx);
! 1337: usbd_close_pipe(sc->pipeh_tx);
! 1338: sc->pipeh_tx = NULL;
! 1339: }
! 1340:
! 1341: for (i = 0; i < UEAGLE_TX_LIST_CNT; i++) {
! 1342: if (sc->txreqs[i].xfer != NULL) {
! 1343: usbd_free_xfer(sc->txreqs[i].xfer);
! 1344: sc->txreqs[i].xfer = NULL;
! 1345: }
! 1346: }
! 1347:
! 1348: /* free Rx resources */
! 1349: if (sc->pipeh_rx != NULL) {
! 1350: usbd_abort_pipe(sc->pipeh_rx);
! 1351: usbd_close_pipe(sc->pipeh_rx);
! 1352: sc->pipeh_rx = NULL;
! 1353: }
! 1354:
! 1355: for (i = 0; i < UEAGLE_NISOREQS; i++) {
! 1356: if (sc->isoreqs[i].xfer != NULL) {
! 1357: usbd_free_xfer(sc->isoreqs[i].xfer);
! 1358: sc->isoreqs[i].xfer = NULL;
! 1359: }
! 1360: }
! 1361: }
! 1362:
! 1363: int
! 1364: ueagle_init(struct ifnet *ifp)
! 1365: {
! 1366: struct ueagle_softc *sc = ifp->if_softc;
! 1367: usbd_interface_handle iface;
! 1368: usbd_status error;
! 1369: size_t len;
! 1370:
! 1371: ueagle_stop(ifp, 0);
! 1372:
! 1373: error = usbd_device2interface_handle(sc->sc_udev, UEAGLE_US_IFACE_NO,
! 1374: &iface);
! 1375: if (error != 0) {
! 1376: printf("%s: could not get idma interface handle\n",
! 1377: sc->sc_dev.dv_xname);
! 1378: goto fail;
! 1379: }
! 1380:
! 1381: error = usbd_open_pipe(iface, UEAGLE_IDMA_PIPE, USBD_EXCLUSIVE_USE,
! 1382: &sc->pipeh_idma);
! 1383: if (error != 0) {
! 1384: printf("%s: could not open idma pipe\n",
! 1385: sc->sc_dev.dv_xname);
! 1386: goto fail;
! 1387: }
! 1388:
! 1389: error = usbd_device2interface_handle(sc->sc_udev, UEAGLE_INTR_IFACE_NO,
! 1390: &iface);
! 1391: if (error != 0) {
! 1392: printf("%s: could not get interrupt interface handle\n",
! 1393: sc->sc_dev.dv_xname);
! 1394: goto fail;
! 1395: }
! 1396:
! 1397: error = loadfirmware("ueagle-dsp", &sc->dsp, &len);
! 1398: if (error != 0) {
! 1399: printf("%s: could not load firmware\n", sc->sc_dev.dv_xname);
! 1400: goto fail;
! 1401: }
! 1402:
! 1403: error = usbd_open_pipe_intr(iface, UEAGLE_INTR_PIPE, USBD_SHORT_XFER_OK,
! 1404: &sc->pipeh_intr, sc, sc->ibuf, UEAGLE_INTR_MAXSIZE, ueagle_intr,
! 1405: UEAGLE_INTR_INTERVAL);
! 1406: if (error != 0) {
! 1407: printf("%s: could not open interrupt pipe\n",
! 1408: sc->sc_dev.dv_xname);
! 1409: goto fail;
! 1410: }
! 1411:
! 1412: error = ueagle_boot(sc);
! 1413: if (error != 0) {
! 1414: printf("%s: could not boot modem\n", sc->sc_dev.dv_xname);
! 1415: goto fail;
! 1416: }
! 1417:
! 1418: /*
! 1419: * Opening of tx and rx pipes if deferred after synchronization is
! 1420: * established.
! 1421: */
! 1422:
! 1423: ifp->if_flags |= IFF_RUNNING;
! 1424: ifp->if_flags &= ~IFF_OACTIVE;
! 1425:
! 1426: return 0;
! 1427:
! 1428: fail: ueagle_stop(ifp, 1);
! 1429: return error;
! 1430: }
! 1431:
! 1432: void
! 1433: ueagle_stop(struct ifnet *ifp, int disable)
! 1434: {
! 1435: struct ueagle_softc *sc = ifp->if_softc;
! 1436:
! 1437: /* stop any pending task */
! 1438: usb_rem_task(sc->sc_udev, &sc->sc_swap_task);
! 1439:
! 1440: /* free Tx and Rx resources */
! 1441: ueagle_close_pipes(sc);
! 1442:
! 1443: /* free firmware */
! 1444: if (sc->dsp != NULL) {
! 1445: free(sc->dsp, M_DEVBUF);
! 1446: sc->dsp = NULL;
! 1447: }
! 1448:
! 1449: /* free interrupt resources */
! 1450: if (sc->pipeh_intr != NULL) {
! 1451: usbd_abort_pipe(sc->pipeh_intr);
! 1452: usbd_close_pipe(sc->pipeh_intr);
! 1453: sc->pipeh_intr = NULL;
! 1454: }
! 1455:
! 1456: /* free IDMA resources */
! 1457: if (sc->pipeh_idma != NULL) {
! 1458: usbd_abort_pipe(sc->pipeh_idma);
! 1459: usbd_close_pipe(sc->pipeh_idma);
! 1460: sc->pipeh_idma = NULL;
! 1461: }
! 1462:
! 1463: /* reset statistics */
! 1464: memset(&sc->stats, 0, sizeof (struct ueagle_stats));
! 1465:
! 1466: ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
! 1467: }
! 1468:
! 1469: int
! 1470: ueagle_activate(struct device *self, enum devact act)
! 1471: {
! 1472: struct ueagle_softc *sc = (struct ueagle_softc *)self;
! 1473:
! 1474: switch (act) {
! 1475: case DVACT_ACTIVATE:
! 1476: break;
! 1477:
! 1478: case DVACT_DEACTIVATE:
! 1479: sc->gone = 1;
! 1480: break;
! 1481: }
! 1482:
! 1483: return 0;
! 1484: }
CVSweb