Annotation of sys/dev/usb/ubt.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ubt.c,v 1.8 2007/06/14 10:11:15 mbalmer Exp $ */
! 2:
! 3: /*-
! 4: * Copyright (c) 2006 Itronix Inc.
! 5: * All rights reserved.
! 6: *
! 7: * Written by Iain Hibbert for Itronix Inc.
! 8: *
! 9: * Redistribution and use in source and binary forms, with or without
! 10: * modification, are permitted provided that the following conditions
! 11: * are met:
! 12: * 1. Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: * 2. Redistributions in binary form must reproduce the above copyright
! 15: * notice, this list of conditions and the following disclaimer in the
! 16: * documentation and/or other materials provided with the distribution.
! 17: * 3. The name of Itronix Inc. may not be used to endorse
! 18: * or promote products derived from this software without specific
! 19: * prior written permission.
! 20: *
! 21: * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
! 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 23: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 24: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
! 25: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
! 26: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
! 27: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
! 28: * ON ANY THEORY OF LIABILITY, WHETHER IN
! 29: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 30: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 31: * POSSIBILITY OF SUCH DAMAGE.
! 32: */
! 33: /*
! 34: * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
! 35: * All rights reserved.
! 36: *
! 37: * This code is derived from software contributed to The NetBSD Foundation
! 38: * by Lennart Augustsson (lennart@augustsson.net) and
! 39: * David Sainty (David.Sainty@dtsp.co.nz).
! 40: *
! 41: * Redistribution and use in source and binary forms, with or without
! 42: * modification, are permitted provided that the following conditions
! 43: * are met:
! 44: * 1. Redistributions of source code must retain the above copyright
! 45: * notice, this list of conditions and the following disclaimer.
! 46: * 2. Redistributions in binary form must reproduce the above copyright
! 47: * notice, this list of conditions and the following disclaimer in the
! 48: * documentation and/or other materials provided with the distribution.
! 49: * 3. All advertising materials mentioning features or use of this software
! 50: * must display the following acknowledgement:
! 51: * This product includes software developed by the NetBSD
! 52: * Foundation, Inc. and its contributors.
! 53: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 54: * contributors may be used to endorse or promote products derived
! 55: * from this software without specific prior written permission.
! 56: *
! 57: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 58: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 59: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 60: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 61: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 62: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 63: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 64: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 65: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 66: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 67: * POSSIBILITY OF SUCH DAMAGE.
! 68: */
! 69: /*
! 70: * This driver originally written by Lennart Augustsson and David Sainty,
! 71: * but was mostly rewritten for the NetBSD Bluetooth protocol stack by
! 72: * Iain Hibbert for Itronix, Inc using the FreeBSD ng_ubt.c driver as a
! 73: * reference.
! 74: */
! 75:
! 76: #include <sys/cdefs.h>
! 77:
! 78: #include <sys/param.h>
! 79: #include <sys/device.h>
! 80: #include <sys/ioctl.h>
! 81: #include <sys/kernel.h>
! 82: #include <sys/malloc.h>
! 83: #include <sys/mbuf.h>
! 84: #include <sys/proc.h>
! 85: #include <sys/sysctl.h>
! 86: #include <sys/systm.h>
! 87:
! 88: #include <dev/usb/usb.h>
! 89: #include <dev/usb/usbdi.h>
! 90: #include <dev/usb/usbdi_util.h>
! 91: #include <dev/usb/usbdevs.h>
! 92:
! 93: #include <netbt/bluetooth.h>
! 94: #include <netbt/hci.h>
! 95:
! 96: /*******************************************************************************
! 97: *
! 98: * debugging stuff
! 99: */
! 100: #undef DPRINTF
! 101: #undef DPRINTFN
! 102:
! 103: #ifdef UBT_DEBUG
! 104: int ubt_debug = UBT_DEBUG;
! 105:
! 106: #define DPRINTF(fmt, args...) do { \
! 107: if (ubt_debug) \
! 108: printf("%s: "fmt, __func__ , ##args); \
! 109: } while (/* CONSTCOND */0)
! 110:
! 111: #define DPRINTFN(n, fmt, args...) do { \
! 112: if (ubt_debug > (n)) \
! 113: printf("%s: "fmt, __func__ , ##args); \
! 114: } while (/* CONSTCOND */0)
! 115:
! 116: #else
! 117: #define DPRINTF(...)
! 118: #define DPRINTFN(...)
! 119: #endif
! 120:
! 121: /*******************************************************************************
! 122: *
! 123: * ubt softc structure
! 124: *
! 125: */
! 126:
! 127: /* buffer sizes */
! 128: /*
! 129: * NB: although ACL packets can extend to 65535 bytes, most devices
! 130: * have max_acl_size at much less (largest I have seen is 384)
! 131: */
! 132: #define UBT_BUFSIZ_CMD (HCI_CMD_PKT_SIZE - 1)
! 133: #define UBT_BUFSIZ_ACL (2048 - 1)
! 134: #define UBT_BUFSIZ_EVENT (HCI_EVENT_PKT_SIZE - 1)
! 135:
! 136: /* Transmit timeouts */
! 137: #define UBT_CMD_TIMEOUT USBD_DEFAULT_TIMEOUT
! 138: #define UBT_ACL_TIMEOUT USBD_DEFAULT_TIMEOUT
! 139:
! 140: /*
! 141: * ISOC transfers
! 142: *
! 143: * xfer buffer size depends on the frame size, and the number
! 144: * of frames per transfer is fixed, as each frame should be
! 145: * 1ms worth of data. This keeps the rate that xfers complete
! 146: * fairly constant. We use multiple xfers to keep the hardware
! 147: * busy
! 148: */
! 149: #define UBT_NXFERS 3 /* max xfers to queue */
! 150: #define UBT_NFRAMES 10 /* frames per xfer */
! 151:
! 152: struct ubt_isoc_xfer {
! 153: struct ubt_softc *softc;
! 154: usbd_xfer_handle xfer;
! 155: uint8_t *buf;
! 156: uint16_t size[UBT_NFRAMES];
! 157: int busy;
! 158: };
! 159:
! 160: struct ubt_softc {
! 161: struct device sc_dev;
! 162: usbd_device_handle sc_udev;
! 163: int sc_refcnt;
! 164: int sc_dying;
! 165:
! 166: /* Control Interface */
! 167: usbd_interface_handle sc_iface0;
! 168:
! 169: /* Commands (control) */
! 170: usbd_xfer_handle sc_cmd_xfer;
! 171: uint8_t *sc_cmd_buf;
! 172:
! 173: /* Events (interrupt) */
! 174: int sc_evt_addr; /* endpoint address */
! 175: usbd_pipe_handle sc_evt_pipe;
! 176: uint8_t *sc_evt_buf;
! 177:
! 178: /* ACL data (in) */
! 179: int sc_aclrd_addr; /* endpoint address */
! 180: usbd_pipe_handle sc_aclrd_pipe; /* read pipe */
! 181: usbd_xfer_handle sc_aclrd_xfer; /* read xfer */
! 182: uint8_t *sc_aclrd_buf; /* read buffer */
! 183: int sc_aclrd_busy; /* reading */
! 184:
! 185: /* ACL data (out) */
! 186: int sc_aclwr_addr; /* endpoint address */
! 187: usbd_pipe_handle sc_aclwr_pipe; /* write pipe */
! 188: usbd_xfer_handle sc_aclwr_xfer; /* write xfer */
! 189: uint8_t *sc_aclwr_buf; /* write buffer */
! 190:
! 191: /* ISOC interface */
! 192: usbd_interface_handle sc_iface1; /* ISOC interface */
! 193: struct sysctllog *sc_log; /* sysctl log */
! 194: int sc_config; /* current config no */
! 195: int sc_alt_config; /* no of alternates */
! 196:
! 197: /* SCO data (in) */
! 198: int sc_scord_addr; /* endpoint address */
! 199: usbd_pipe_handle sc_scord_pipe; /* read pipe */
! 200: int sc_scord_size; /* frame length */
! 201: struct ubt_isoc_xfer sc_scord[UBT_NXFERS];
! 202: struct mbuf *sc_scord_mbuf; /* current packet */
! 203:
! 204: /* SCO data (out) */
! 205: int sc_scowr_addr; /* endpoint address */
! 206: usbd_pipe_handle sc_scowr_pipe; /* write pipe */
! 207: int sc_scowr_size; /* frame length */
! 208: struct ubt_isoc_xfer sc_scowr[UBT_NXFERS];
! 209: struct mbuf *sc_scowr_mbuf; /* current packet */
! 210:
! 211: /* Protocol structure */
! 212: struct hci_unit sc_unit;
! 213:
! 214: /* Successfully attached */
! 215: int sc_ok;
! 216: };
! 217:
! 218: /*
! 219: * Bluetooth unit/USB callback routines
! 220: */
! 221: int ubt_enable(struct hci_unit *);
! 222: void ubt_disable(struct hci_unit *);
! 223:
! 224: void ubt_xmit_cmd_start(struct hci_unit *);
! 225: void ubt_xmit_cmd_complete(usbd_xfer_handle,
! 226: usbd_private_handle, usbd_status);
! 227:
! 228: void ubt_xmit_acl_start(struct hci_unit *);
! 229: void ubt_xmit_acl_complete(usbd_xfer_handle,
! 230: usbd_private_handle, usbd_status);
! 231:
! 232: void ubt_xmit_sco_start(struct hci_unit *);
! 233: void ubt_xmit_sco_start1(struct ubt_softc *, struct ubt_isoc_xfer *);
! 234: void ubt_xmit_sco_complete(usbd_xfer_handle,
! 235: usbd_private_handle, usbd_status);
! 236:
! 237: void ubt_recv_event(usbd_xfer_handle,
! 238: usbd_private_handle, usbd_status);
! 239:
! 240: void ubt_recv_acl_start(struct ubt_softc *);
! 241: void ubt_recv_acl_complete(usbd_xfer_handle,
! 242: usbd_private_handle, usbd_status);
! 243:
! 244: void ubt_recv_sco_start1(struct ubt_softc *, struct ubt_isoc_xfer *);
! 245: void ubt_recv_sco_complete(usbd_xfer_handle,
! 246: usbd_private_handle, usbd_status);
! 247:
! 248: int ubt_match(struct device *, void *, void *);
! 249: void ubt_attach(struct device *, struct device *, void *);
! 250: int ubt_detach(struct device *, int);
! 251: int ubt_activate(struct device *, enum devact);
! 252:
! 253: struct cfdriver ubt_cd = {
! 254: NULL, "ubt", DV_DULL
! 255: };
! 256:
! 257: const struct cfattach ubt_ca = {
! 258: sizeof(struct ubt_softc),
! 259: ubt_match,
! 260: ubt_attach,
! 261: ubt_detach,
! 262: ubt_activate,
! 263: };
! 264:
! 265: static int ubt_set_isoc_config(struct ubt_softc *);
! 266: static void ubt_abortdealloc(struct ubt_softc *);
! 267:
! 268: /*
! 269: * Match against the whole device, since we want to take
! 270: * both interfaces. If a device should be ignored then add
! 271: *
! 272: * { VendorID, ProductID }
! 273: *
! 274: * to the ubt_ignore list.
! 275: */
! 276: static const struct usb_devno ubt_ignore[] = {
! 277: { USB_VENDOR_BROADCOM, USB_PRODUCT_BROADCOM_BCM2033 },
! 278: { USB_VENDOR_BROADCOM, USB_PRODUCT_BROADCOM_BCM2033NF },
! 279: { 0, 0 } /* end of list */
! 280: };
! 281:
! 282: int
! 283: ubt_match(struct device *parent, void *match, void *aux)
! 284: {
! 285:
! 286: struct usb_attach_arg *uaa = aux;
! 287: usb_device_descriptor_t *dd = usbd_get_device_descriptor(uaa->device);
! 288:
! 289: DPRINTFN(50, "ubt_match\n");
! 290:
! 291: if (usb_lookup(ubt_ignore, uaa->vendor, uaa->product))
! 292: return UMATCH_NONE;
! 293:
! 294: if (dd->bDeviceClass == UDCLASS_WIRELESS
! 295: && dd->bDeviceSubClass == UDSUBCLASS_RF
! 296: && dd->bDeviceProtocol == UDPROTO_BLUETOOTH)
! 297: return UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO;
! 298:
! 299: return UMATCH_NONE;
! 300: }
! 301:
! 302:
! 303: void
! 304: ubt_attach(struct device *parent, struct device *self, void *aux)
! 305: {
! 306: struct ubt_softc *sc = (struct ubt_softc *)self;
! 307: struct usb_attach_arg *uaa = aux;
! 308: usb_config_descriptor_t *cd;
! 309: usb_endpoint_descriptor_t *ed;
! 310: char *devinfop;
! 311: int err;
! 312: uint8_t count, i;
! 313:
! 314: DPRINTFN(50, "ubt_attach: sc=%p\n", sc);
! 315:
! 316: sc->sc_udev = uaa->device;
! 317:
! 318: devinfop = usbd_devinfo_alloc(sc->sc_udev, 0);
! 319: printf("\n%s: %s\n", sc->sc_dev.dv_xname, devinfop);
! 320: usbd_devinfo_free(devinfop);
! 321:
! 322: /*
! 323: * Move the device into the configured state
! 324: */
! 325: err = usbd_set_config_index(sc->sc_udev, 0, 1);
! 326: if (err) {
! 327: printf("%s: failed to set configuration idx 0: %s\n",
! 328: sc->sc_dev.dv_xname, usbd_errstr(err));
! 329:
! 330: return;
! 331: }
! 332:
! 333: /*
! 334: * Interface 0 must have 3 endpoints
! 335: * 1) Interrupt endpoint to receive HCI events
! 336: * 2) Bulk IN endpoint to receive ACL data
! 337: * 3) Bulk OUT endpoint to send ACL data
! 338: */
! 339: err = usbd_device2interface_handle(sc->sc_udev, 0, &sc->sc_iface0);
! 340: if (err) {
! 341: printf("%s: Could not get interface 0 handle %s (%d)\n",
! 342: sc->sc_dev.dv_xname, usbd_errstr(err), err);
! 343:
! 344: return;
! 345: }
! 346:
! 347: sc->sc_evt_addr = -1;
! 348: sc->sc_aclrd_addr = -1;
! 349: sc->sc_aclwr_addr = -1;
! 350:
! 351: count = 0;
! 352: (void)usbd_endpoint_count(sc->sc_iface0, &count);
! 353:
! 354: for (i = 0 ; i < count ; i++) {
! 355: int dir, type;
! 356:
! 357: ed = usbd_interface2endpoint_descriptor(sc->sc_iface0, i);
! 358: if (ed == NULL) {
! 359: printf("%s: could not read endpoint descriptor %d\n",
! 360: sc->sc_dev.dv_xname, i);
! 361:
! 362: return;
! 363: }
! 364:
! 365: dir = UE_GET_DIR(ed->bEndpointAddress);
! 366: type = UE_GET_XFERTYPE(ed->bmAttributes);
! 367:
! 368: if (dir == UE_DIR_IN && type == UE_INTERRUPT)
! 369: sc->sc_evt_addr = ed->bEndpointAddress;
! 370: else if (dir == UE_DIR_IN && type == UE_BULK)
! 371: sc->sc_aclrd_addr = ed->bEndpointAddress;
! 372: else if (dir == UE_DIR_OUT && type == UE_BULK)
! 373: sc->sc_aclwr_addr = ed->bEndpointAddress;
! 374: }
! 375:
! 376: if (sc->sc_evt_addr == -1) {
! 377: printf("%s: missing INTERRUPT endpoint on interface 0\n",
! 378: sc->sc_dev.dv_xname);
! 379:
! 380: return;
! 381: }
! 382: if (sc->sc_aclrd_addr == -1) {
! 383: printf("%s: missing BULK IN endpoint on interface 0\n",
! 384: sc->sc_dev.dv_xname);
! 385:
! 386: return;
! 387: }
! 388: if (sc->sc_aclwr_addr == -1) {
! 389: printf("%s: missing BULK OUT endpoint on interface 0\n",
! 390: sc->sc_dev.dv_xname);
! 391:
! 392: return;
! 393: }
! 394:
! 395: /*
! 396: * Interface 1 must have 2 endpoints
! 397: * 1) Isochronous IN endpoint to receive SCO data
! 398: * 2) Isochronous OUT endpoint to send SCO data
! 399: *
! 400: * and will have several configurations, which can be selected
! 401: * via a sysctl variable. We select config 0 to start, which
! 402: * means that no SCO data will be available.
! 403: */
! 404: err = usbd_device2interface_handle(sc->sc_udev, 1, &sc->sc_iface1);
! 405: if (err) {
! 406: printf("%s: Could not get interface 1 handle %s (%d)\n",
! 407: sc->sc_dev.dv_xname, usbd_errstr(err), err);
! 408:
! 409: return;
! 410: }
! 411:
! 412: cd = usbd_get_config_descriptor(sc->sc_udev);
! 413: if (cd == NULL) {
! 414: printf("%s: could not get config descriptor\n",
! 415: sc->sc_dev.dv_xname);
! 416:
! 417: return;
! 418: }
! 419:
! 420: sc->sc_alt_config = usbd_get_no_alts(cd, 1);
! 421:
! 422: /* set initial config */
! 423: err = ubt_set_isoc_config(sc);
! 424: if (err) {
! 425: printf("%s: ISOC config failed\n",
! 426: sc->sc_dev.dv_xname);
! 427:
! 428: return;
! 429: }
! 430:
! 431: /* Attach HCI */
! 432: sc->sc_unit.hci_softc = self;
! 433: sc->sc_unit.hci_devname = sc->sc_dev.dv_xname;
! 434: sc->sc_unit.hci_enable = ubt_enable;
! 435: sc->sc_unit.hci_disable = ubt_disable;
! 436: sc->sc_unit.hci_start_cmd = ubt_xmit_cmd_start;
! 437: sc->sc_unit.hci_start_acl = ubt_xmit_acl_start;
! 438: sc->sc_unit.hci_start_sco = ubt_xmit_sco_start;
! 439: sc->sc_unit.hci_ipl = IPL_USB; /* XXX: IPL_SOFTUSB ?? */
! 440: hci_attach(&sc->sc_unit);
! 441:
! 442: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
! 443: &sc->sc_dev);
! 444:
! 445: sc->sc_ok = 1;
! 446:
! 447: return;
! 448: }
! 449:
! 450: int
! 451: ubt_detach(struct device *self, int flags)
! 452: {
! 453: struct ubt_softc *sc = (struct ubt_softc *)self;
! 454: int s;
! 455:
! 456: DPRINTF("sc=%p flags=%d\n", sc, flags);
! 457:
! 458: sc->sc_dying = 1;
! 459:
! 460: if (!sc->sc_ok)
! 461: return 0;
! 462:
! 463: /* Detach HCI interface */
! 464: hci_detach(&sc->sc_unit);
! 465:
! 466: /*
! 467: * Abort all pipes. Causes processes waiting for transfer to wake.
! 468: *
! 469: * Actually, hci_detach() above will call ubt_disable() which may
! 470: * call ubt_abortdealloc(), but lets be sure since doing it twice
! 471: * wont cause an error.
! 472: */
! 473: ubt_abortdealloc(sc);
! 474:
! 475: /* wait for all processes to finish */
! 476: s = splusb();
! 477: if (sc->sc_refcnt-- > 0)
! 478: usb_detach_wait(&sc->sc_dev);
! 479:
! 480: splx(s);
! 481:
! 482: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
! 483: &sc->sc_dev);
! 484:
! 485: DPRINTFN(1, "driver detached\n");
! 486:
! 487: return 0;
! 488: }
! 489:
! 490: int
! 491: ubt_activate(struct device *self, enum devact act)
! 492: {
! 493: struct ubt_softc *sc = (struct ubt_softc *)self;
! 494: int error = 0;
! 495:
! 496: DPRINTFN(1, "ubt_activate: sc=%p, act=%d\n", sc, act);
! 497:
! 498: switch (act) {
! 499: case DVACT_ACTIVATE:
! 500: return EOPNOTSUPP;
! 501: break;
! 502:
! 503: case DVACT_DEACTIVATE:
! 504: sc->sc_dying = 1;
! 505: break;
! 506: }
! 507: return error;
! 508: }
! 509:
! 510: /* set ISOC configuration */
! 511: int
! 512: ubt_set_isoc_config(struct ubt_softc *sc)
! 513: {
! 514: usb_endpoint_descriptor_t *ed;
! 515: int rd_addr, wr_addr, rd_size, wr_size;
! 516: uint8_t count, i;
! 517: int err;
! 518:
! 519: err = usbd_set_interface(sc->sc_iface1, sc->sc_config);
! 520: if (err != USBD_NORMAL_COMPLETION) {
! 521: printf(
! 522: "%s: Could not set config %d on ISOC interface. %s (%d)\n",
! 523: sc->sc_dev.dv_xname, sc->sc_config, usbd_errstr(err), err);
! 524:
! 525: return err == USBD_IN_USE ? EBUSY : EIO;
! 526: }
! 527:
! 528: /*
! 529: * We wont get past the above if there are any pipes open, so no
! 530: * need to worry about buf/xfer/pipe deallocation. If we get an
! 531: * error after this, the frame quantities will be 0 and no SCO
! 532: * data will be possible.
! 533: */
! 534:
! 535: sc->sc_scord_size = rd_size = 0;
! 536: sc->sc_scord_addr = rd_addr = -1;
! 537:
! 538: sc->sc_scowr_size = wr_size = 0;
! 539: sc->sc_scowr_addr = wr_addr = -1;
! 540:
! 541: count = 0;
! 542: (void)usbd_endpoint_count(sc->sc_iface1, &count);
! 543:
! 544: for (i = 0 ; i < count ; i++) {
! 545: ed = usbd_interface2endpoint_descriptor(sc->sc_iface1, i);
! 546: if (ed == NULL) {
! 547: printf("%s: could not read endpoint descriptor %d\n",
! 548: sc->sc_dev.dv_xname, i);
! 549:
! 550: return EIO;
! 551: }
! 552:
! 553: DPRINTFN(5, "%s: endpoint type %02x (%02x) addr %02x (%s)\n",
! 554: sc->sc_dev.dv_xname,
! 555: UE_GET_XFERTYPE(ed->bmAttributes),
! 556: UE_GET_ISO_TYPE(ed->bmAttributes),
! 557: ed->bEndpointAddress,
! 558: UE_GET_DIR(ed->bEndpointAddress) ? "in" : "out");
! 559:
! 560: if (UE_GET_XFERTYPE(ed->bmAttributes) != UE_ISOCHRONOUS)
! 561: continue;
! 562:
! 563: if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) {
! 564: rd_addr = ed->bEndpointAddress;
! 565: rd_size = UGETW(ed->wMaxPacketSize);
! 566: } else {
! 567: wr_addr = ed->bEndpointAddress;
! 568: wr_size = UGETW(ed->wMaxPacketSize);
! 569: }
! 570: }
! 571:
! 572: if (rd_addr == -1) {
! 573: printf(
! 574: "%s: missing ISOC IN endpoint on interface config %d\n",
! 575: sc->sc_dev.dv_xname, sc->sc_config);
! 576:
! 577: return ENOENT;
! 578: }
! 579: if (wr_addr == -1) {
! 580: printf(
! 581: "%s: missing ISOC OUT endpoint on interface config %d\n",
! 582: sc->sc_dev.dv_xname, sc->sc_config);
! 583:
! 584: return ENOENT;
! 585: }
! 586:
! 587: #ifdef DIAGNOSTIC
! 588: if (rd_size > MLEN) {
! 589: printf("%s: rd_size=%d exceeds MLEN\n",
! 590: sc->sc_dev.dv_xname, rd_size);
! 591:
! 592: return EOVERFLOW;
! 593: }
! 594:
! 595: if (wr_size > MLEN) {
! 596: printf("%s: wr_size=%d exceeds MLEN\n",
! 597: sc->sc_dev.dv_xname, wr_size);
! 598:
! 599: return EOVERFLOW;
! 600: }
! 601: #endif
! 602:
! 603: sc->sc_scord_size = rd_size;
! 604: sc->sc_scord_addr = rd_addr;
! 605:
! 606: sc->sc_scowr_size = wr_size;
! 607: sc->sc_scowr_addr = wr_addr;
! 608:
! 609: return 0;
! 610: }
! 611:
! 612: void
! 613: ubt_abortdealloc(struct ubt_softc *sc)
! 614: {
! 615: int i;
! 616:
! 617: DPRINTFN(1, "sc=%p\n", sc);
! 618:
! 619: /* Abort all pipes */
! 620: if (sc->sc_evt_pipe != NULL) {
! 621: usbd_abort_pipe(sc->sc_evt_pipe);
! 622: usbd_close_pipe(sc->sc_evt_pipe);
! 623: sc->sc_evt_pipe = NULL;
! 624: }
! 625:
! 626: if (sc->sc_aclrd_pipe != NULL) {
! 627: usbd_abort_pipe(sc->sc_aclrd_pipe);
! 628: usbd_close_pipe(sc->sc_aclrd_pipe);
! 629: sc->sc_aclrd_pipe = NULL;
! 630: }
! 631:
! 632: if (sc->sc_aclwr_pipe != NULL) {
! 633: usbd_abort_pipe(sc->sc_aclwr_pipe);
! 634: usbd_close_pipe(sc->sc_aclwr_pipe);
! 635: sc->sc_aclwr_pipe = NULL;
! 636: }
! 637:
! 638: if (sc->sc_scord_pipe != NULL) {
! 639: usbd_abort_pipe(sc->sc_scord_pipe);
! 640: usbd_close_pipe(sc->sc_scord_pipe);
! 641: sc->sc_scord_pipe = NULL;
! 642: }
! 643:
! 644: if (sc->sc_scowr_pipe != NULL) {
! 645: usbd_abort_pipe(sc->sc_scowr_pipe);
! 646: usbd_close_pipe(sc->sc_scowr_pipe);
! 647: sc->sc_scowr_pipe = NULL;
! 648: }
! 649:
! 650: /* Free event buffer */
! 651: if (sc->sc_evt_buf != NULL) {
! 652: free(sc->sc_evt_buf, M_USBDEV);
! 653: sc->sc_evt_buf = NULL;
! 654: }
! 655:
! 656: /* Free all xfers and xfer buffers (implicit) */
! 657: if (sc->sc_cmd_xfer != NULL) {
! 658: usbd_free_xfer(sc->sc_cmd_xfer);
! 659: sc->sc_cmd_xfer = NULL;
! 660: sc->sc_cmd_buf = NULL;
! 661: }
! 662:
! 663: if (sc->sc_aclrd_xfer != NULL) {
! 664: usbd_free_xfer(sc->sc_aclrd_xfer);
! 665: sc->sc_aclrd_xfer = NULL;
! 666: sc->sc_aclrd_buf = NULL;
! 667: }
! 668:
! 669: if (sc->sc_aclwr_xfer != NULL) {
! 670: usbd_free_xfer(sc->sc_aclwr_xfer);
! 671: sc->sc_aclwr_xfer = NULL;
! 672: sc->sc_aclwr_buf = NULL;
! 673: }
! 674:
! 675: for (i = 0 ; i < UBT_NXFERS ; i++) {
! 676: if (sc->sc_scord[i].xfer != NULL) {
! 677: usbd_free_xfer(sc->sc_scord[i].xfer);
! 678: sc->sc_scord[i].xfer = NULL;
! 679: sc->sc_scord[i].buf = NULL;
! 680: }
! 681:
! 682: if (sc->sc_scowr[i].xfer != NULL) {
! 683: usbd_free_xfer(sc->sc_scowr[i].xfer);
! 684: sc->sc_scowr[i].xfer = NULL;
! 685: sc->sc_scowr[i].buf = NULL;
! 686: }
! 687: }
! 688:
! 689: /* Free partial SCO packets */
! 690: if (sc->sc_scord_mbuf != NULL) {
! 691: m_freem(sc->sc_scord_mbuf);
! 692: sc->sc_scord_mbuf = NULL;
! 693: }
! 694:
! 695: if (sc->sc_scowr_mbuf != NULL) {
! 696: m_freem(sc->sc_scowr_mbuf);
! 697: sc->sc_scowr_mbuf = NULL;
! 698: }
! 699: }
! 700:
! 701: /*******************************************************************************
! 702: *
! 703: * Bluetooth Unit/USB callbacks
! 704: *
! 705: * All of this will be called at the IPL_ we specified above
! 706: */
! 707: int
! 708: ubt_enable(struct hci_unit *unit)
! 709: {
! 710: struct ubt_softc *sc = (struct ubt_softc *)unit->hci_softc;
! 711: usbd_status err;
! 712: int i, error;
! 713:
! 714: DPRINTFN(1, "sc=%p\n", sc);
! 715:
! 716: if (unit->hci_flags & BTF_RUNNING)
! 717: return 0;
! 718:
! 719: /* Events */
! 720: sc->sc_evt_buf = malloc(UBT_BUFSIZ_EVENT, M_USBDEV, M_NOWAIT);
! 721: if (sc->sc_evt_buf == NULL) {
! 722: error = ENOMEM;
! 723: goto bad;
! 724: }
! 725: err = usbd_open_pipe_intr(sc->sc_iface0,
! 726: sc->sc_evt_addr,
! 727: USBD_SHORT_XFER_OK,
! 728: &sc->sc_evt_pipe,
! 729: sc,
! 730: sc->sc_evt_buf,
! 731: UBT_BUFSIZ_EVENT,
! 732: ubt_recv_event,
! 733: USBD_DEFAULT_INTERVAL);
! 734: if (err != USBD_NORMAL_COMPLETION) {
! 735: error = EIO;
! 736: goto bad;
! 737: }
! 738:
! 739: /* Commands */
! 740: sc->sc_cmd_xfer = usbd_alloc_xfer(sc->sc_udev);
! 741: if (sc->sc_cmd_xfer == NULL) {
! 742: error = ENOMEM;
! 743: goto bad;
! 744: }
! 745: sc->sc_cmd_buf = usbd_alloc_buffer(sc->sc_cmd_xfer, UBT_BUFSIZ_CMD);
! 746: if (sc->sc_cmd_buf == NULL) {
! 747: error = ENOMEM;
! 748: goto bad;
! 749: }
! 750:
! 751: /* ACL read */
! 752: err = usbd_open_pipe(sc->sc_iface0, sc->sc_aclrd_addr,
! 753: USBD_EXCLUSIVE_USE, &sc->sc_aclrd_pipe);
! 754: if (err != USBD_NORMAL_COMPLETION) {
! 755: error = EIO;
! 756: goto bad;
! 757: }
! 758: sc->sc_aclrd_xfer = usbd_alloc_xfer(sc->sc_udev);
! 759: if (sc->sc_aclrd_xfer == NULL) {
! 760: error = ENOMEM;
! 761: goto bad;
! 762: }
! 763: sc->sc_aclrd_buf = usbd_alloc_buffer(sc->sc_aclrd_xfer, UBT_BUFSIZ_ACL);
! 764: if (sc->sc_aclrd_buf == NULL) {
! 765: error = ENOMEM;
! 766: goto bad;
! 767: }
! 768: sc->sc_aclrd_busy = 0;
! 769: ubt_recv_acl_start(sc);
! 770:
! 771: /* ACL write */
! 772: err = usbd_open_pipe(sc->sc_iface0, sc->sc_aclwr_addr,
! 773: USBD_EXCLUSIVE_USE, &sc->sc_aclwr_pipe);
! 774: if (err != USBD_NORMAL_COMPLETION) {
! 775: error = EIO;
! 776: goto bad;
! 777: }
! 778: sc->sc_aclwr_xfer = usbd_alloc_xfer(sc->sc_udev);
! 779: if (sc->sc_aclwr_xfer == NULL) {
! 780: error = ENOMEM;
! 781: goto bad;
! 782: }
! 783: sc->sc_aclwr_buf = usbd_alloc_buffer(sc->sc_aclwr_xfer, UBT_BUFSIZ_ACL);
! 784: if (sc->sc_aclwr_buf == NULL) {
! 785: error = ENOMEM;
! 786: goto bad;
! 787: }
! 788:
! 789: /* SCO read */
! 790: if (sc->sc_scord_size > 0) {
! 791: err = usbd_open_pipe(sc->sc_iface1, sc->sc_scord_addr,
! 792: USBD_EXCLUSIVE_USE, &sc->sc_scord_pipe);
! 793: if (err != USBD_NORMAL_COMPLETION) {
! 794: error = EIO;
! 795: goto bad;
! 796: }
! 797:
! 798: for (i = 0 ; i < UBT_NXFERS ; i++) {
! 799: sc->sc_scord[i].xfer = usbd_alloc_xfer(sc->sc_udev);
! 800: if (sc->sc_scord[i].xfer == NULL) {
! 801: error = ENOMEM;
! 802: goto bad;
! 803: }
! 804: sc->sc_scord[i].buf = usbd_alloc_buffer(sc->sc_scord[i].xfer,
! 805: sc->sc_scord_size * UBT_NFRAMES);
! 806: if (sc->sc_scord[i].buf == NULL) {
! 807: error = ENOMEM;
! 808: goto bad;
! 809: }
! 810: sc->sc_scord[i].softc = sc;
! 811: sc->sc_scord[i].busy = 0;
! 812: ubt_recv_sco_start1(sc, &sc->sc_scord[i]);
! 813: }
! 814: }
! 815:
! 816: /* SCO write */
! 817: if (sc->sc_scowr_size > 0) {
! 818: err = usbd_open_pipe(sc->sc_iface1, sc->sc_scowr_addr,
! 819: USBD_EXCLUSIVE_USE, &sc->sc_scowr_pipe);
! 820: if (err != USBD_NORMAL_COMPLETION) {
! 821: error = EIO;
! 822: goto bad;
! 823: }
! 824:
! 825: for (i = 0 ; i < UBT_NXFERS ; i++) {
! 826: sc->sc_scowr[i].xfer = usbd_alloc_xfer(sc->sc_udev);
! 827: if (sc->sc_scowr[i].xfer == NULL) {
! 828: error = ENOMEM;
! 829: goto bad;
! 830: }
! 831: sc->sc_scowr[i].buf = usbd_alloc_buffer(sc->sc_scowr[i].xfer,
! 832: sc->sc_scowr_size * UBT_NFRAMES);
! 833: if (sc->sc_scowr[i].buf == NULL) {
! 834: error = ENOMEM;
! 835: goto bad;
! 836: }
! 837: sc->sc_scowr[i].softc = sc;
! 838: sc->sc_scowr[i].busy = 0;
! 839: }
! 840: }
! 841:
! 842: unit->hci_flags &= ~BTF_XMIT;
! 843: unit->hci_flags |= BTF_RUNNING;
! 844: return 0;
! 845:
! 846: bad:
! 847: ubt_abortdealloc(sc);
! 848: return error;
! 849: }
! 850:
! 851: void
! 852: ubt_disable(struct hci_unit *unit)
! 853: {
! 854: struct ubt_softc *sc = (struct ubt_softc *)unit->hci_softc;
! 855:
! 856: DPRINTFN(1, "sc=%p\n", sc);
! 857:
! 858: if ((unit->hci_flags & BTF_RUNNING) == 0)
! 859: return;
! 860:
! 861: ubt_abortdealloc(sc);
! 862:
! 863: unit->hci_flags &= ~BTF_RUNNING;
! 864: }
! 865:
! 866: void
! 867: ubt_xmit_cmd_start(struct hci_unit *unit)
! 868: {
! 869: struct ubt_softc *sc = (struct ubt_softc *)unit->hci_softc;
! 870: usb_device_request_t req;
! 871: usbd_status status;
! 872: struct mbuf *m;
! 873: int len;
! 874:
! 875: if (sc->sc_dying)
! 876: return;
! 877:
! 878: if (IF_IS_EMPTY(&unit->hci_cmdq))
! 879: return;
! 880:
! 881: IF_DEQUEUE(&unit->hci_cmdq, m);
! 882:
! 883: DPRINTFN(15, "%s: xmit CMD packet (%d bytes)\n",
! 884: unit->hci_devname, m->m_pkthdr.len);
! 885:
! 886: sc->sc_refcnt++;
! 887: unit->hci_flags |= BTF_XMIT_CMD;
! 888:
! 889: len = m->m_pkthdr.len - 1;
! 890: m_copydata(m, 1, len, sc->sc_cmd_buf);
! 891: m_freem(m);
! 892:
! 893: memset(&req, 0, sizeof(req));
! 894: req.bmRequestType = UT_WRITE_CLASS_DEVICE;
! 895: USETW(req.wLength, len);
! 896:
! 897: usbd_setup_default_xfer(sc->sc_cmd_xfer,
! 898: sc->sc_udev,
! 899: unit,
! 900: UBT_CMD_TIMEOUT,
! 901: &req,
! 902: sc->sc_cmd_buf,
! 903: len,
! 904: USBD_NO_COPY | USBD_FORCE_SHORT_XFER,
! 905: ubt_xmit_cmd_complete);
! 906:
! 907: status = usbd_transfer(sc->sc_cmd_xfer);
! 908:
! 909: KASSERT(status != USBD_NORMAL_COMPLETION);
! 910:
! 911: if (status != USBD_IN_PROGRESS) {
! 912: DPRINTF("usbd_transfer status=%s (%d)\n",
! 913: usbd_errstr(status), status);
! 914:
! 915: sc->sc_refcnt--;
! 916: unit->hci_flags &= ~BTF_XMIT_CMD;
! 917: }
! 918: }
! 919:
! 920: void
! 921: ubt_xmit_cmd_complete(usbd_xfer_handle xfer,
! 922: usbd_private_handle h, usbd_status status)
! 923: {
! 924: struct hci_unit *unit = h;
! 925: struct ubt_softc *sc = (struct ubt_softc *)unit->hci_softc;
! 926: uint32_t count;
! 927:
! 928: DPRINTFN(15, "%s: CMD complete status=%s (%d)\n",
! 929: unit->hci_devname, usbd_errstr(status), status);
! 930:
! 931: unit->hci_flags &= ~BTF_XMIT_CMD;
! 932:
! 933: if (--sc->sc_refcnt < 0) {
! 934: DPRINTF("sc_refcnt=%d\n", sc->sc_refcnt);
! 935: usb_detach_wakeup(&sc->sc_dev);
! 936: return;
! 937: }
! 938:
! 939: if (sc->sc_dying) {
! 940: DPRINTF("sc_dying\n");
! 941: return;
! 942: }
! 943:
! 944: if (status != USBD_NORMAL_COMPLETION) {
! 945: DPRINTF("status=%s (%d)\n",
! 946: usbd_errstr(status), status);
! 947:
! 948: unit->hci_stats.err_tx++;
! 949: return;
! 950: }
! 951:
! 952: usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
! 953: unit->hci_stats.cmd_tx++;
! 954: unit->hci_stats.byte_tx += count;
! 955:
! 956: ubt_xmit_cmd_start(unit);
! 957: }
! 958:
! 959: void
! 960: ubt_xmit_acl_start(struct hci_unit *unit)
! 961: {
! 962: struct ubt_softc *sc = (struct ubt_softc *)unit->hci_softc;
! 963: struct mbuf *m;
! 964: usbd_status status;
! 965: int len;
! 966:
! 967: if (sc->sc_dying)
! 968: return;
! 969:
! 970: if (IF_IS_EMPTY(&unit->hci_acltxq) == NULL)
! 971: return;
! 972:
! 973: sc->sc_refcnt++;
! 974: unit->hci_flags |= BTF_XMIT_ACL;
! 975:
! 976: IF_DEQUEUE(&unit->hci_acltxq, m);
! 977:
! 978: DPRINTFN(15, "%s: xmit ACL packet (%d bytes)\n",
! 979: unit->hci_devname, m->m_pkthdr.len);
! 980:
! 981: len = m->m_pkthdr.len - 1;
! 982: if (len > UBT_BUFSIZ_ACL) {
! 983: DPRINTF("%s: truncating ACL packet (%d => %d)!\n",
! 984: unit->hci_devname, len, UBT_BUFSIZ_ACL);
! 985:
! 986: len = UBT_BUFSIZ_ACL;
! 987: }
! 988:
! 989: m_copydata(m, 1, len, sc->sc_aclwr_buf);
! 990: m_freem(m);
! 991:
! 992: unit->hci_stats.acl_tx++;
! 993: unit->hci_stats.byte_tx += len;
! 994:
! 995: usbd_setup_xfer(sc->sc_aclwr_xfer,
! 996: sc->sc_aclwr_pipe,
! 997: unit,
! 998: sc->sc_aclwr_buf,
! 999: len,
! 1000: USBD_NO_COPY | USBD_FORCE_SHORT_XFER,
! 1001: UBT_ACL_TIMEOUT,
! 1002: ubt_xmit_acl_complete);
! 1003:
! 1004: status = usbd_transfer(sc->sc_aclwr_xfer);
! 1005:
! 1006: KASSERT(status != USBD_NORMAL_COMPLETION);
! 1007:
! 1008: if (status != USBD_IN_PROGRESS) {
! 1009: DPRINTF("usbd_transfer status=%s (%d)\n",
! 1010: usbd_errstr(status), status);
! 1011:
! 1012: sc->sc_refcnt--;
! 1013: unit->hci_flags &= ~BTF_XMIT_ACL;
! 1014: }
! 1015: }
! 1016:
! 1017: void
! 1018: ubt_xmit_acl_complete(usbd_xfer_handle xfer,
! 1019: usbd_private_handle h, usbd_status status)
! 1020: {
! 1021: struct hci_unit *unit = h;
! 1022: struct ubt_softc *sc = (struct ubt_softc *)unit->hci_softc;
! 1023:
! 1024: DPRINTFN(15, "%s: ACL complete status=%s (%d)\n",
! 1025: unit->hci_devname, usbd_errstr(status), status);
! 1026:
! 1027: unit->hci_flags &= ~BTF_XMIT_ACL;
! 1028:
! 1029: if (--sc->sc_refcnt < 0) {
! 1030: usb_detach_wakeup(&sc->sc_dev);
! 1031: return;
! 1032: }
! 1033:
! 1034: if (sc->sc_dying)
! 1035: return;
! 1036:
! 1037: if (status != USBD_NORMAL_COMPLETION) {
! 1038: DPRINTF("status=%s (%d)\n",
! 1039: usbd_errstr(status), status);
! 1040:
! 1041: unit->hci_stats.err_tx++;
! 1042:
! 1043: if (status == USBD_STALLED)
! 1044: usbd_clear_endpoint_stall_async(sc->sc_aclwr_pipe);
! 1045: else
! 1046: return;
! 1047: }
! 1048:
! 1049: ubt_xmit_acl_start(unit);
! 1050: }
! 1051:
! 1052: void
! 1053: ubt_xmit_sco_start(struct hci_unit *unit)
! 1054: {
! 1055: struct ubt_softc *sc = (struct ubt_softc *)unit->hci_softc;
! 1056: int i;
! 1057:
! 1058: if (sc->sc_dying || sc->sc_scowr_size == 0)
! 1059: return;
! 1060:
! 1061: for (i = 0 ; i < UBT_NXFERS ; i++) {
! 1062: if (sc->sc_scowr[i].busy)
! 1063: continue;
! 1064:
! 1065: ubt_xmit_sco_start1(sc, &sc->sc_scowr[i]);
! 1066: }
! 1067: }
! 1068:
! 1069: void
! 1070: ubt_xmit_sco_start1(struct ubt_softc *sc, struct ubt_isoc_xfer *isoc)
! 1071: {
! 1072: struct mbuf *m;
! 1073: uint8_t *buf;
! 1074: int num, len, size, space;
! 1075:
! 1076: space = sc->sc_scowr_size * UBT_NFRAMES;
! 1077: buf = isoc->buf;
! 1078: len = 0;
! 1079:
! 1080: /*
! 1081: * Fill the request buffer with data from the queue,
! 1082: * keeping any leftover packet on our private hook.
! 1083: *
! 1084: * Complete packets are passed back up to the stack
! 1085: * for disposal, since we can't rely on the controller
! 1086: * to tell us when it has finished with them.
! 1087: */
! 1088:
! 1089: m = sc->sc_scowr_mbuf;
! 1090: while (space > 0) {
! 1091: if (m == NULL) {
! 1092: IF_DEQUEUE(&sc->sc_unit.hci_scotxq, m);
! 1093: if (m == NULL)
! 1094: break;
! 1095:
! 1096: m_adj(m, 1); /* packet type */
! 1097: }
! 1098:
! 1099: if (m->m_pkthdr.len > 0) {
! 1100: size = MIN(m->m_pkthdr.len, space);
! 1101:
! 1102: m_copydata(m, 0, size, buf);
! 1103: m_adj(m, size);
! 1104:
! 1105: buf += size;
! 1106: len += size;
! 1107: space -= size;
! 1108: }
! 1109:
! 1110: if (m->m_pkthdr.len == 0) {
! 1111: sc->sc_unit.hci_stats.sco_tx++;
! 1112: hci_complete_sco(&sc->sc_unit, m);
! 1113: m = NULL;
! 1114: }
! 1115: }
! 1116: sc->sc_scowr_mbuf = m;
! 1117:
! 1118: DPRINTFN(15, "isoc=%p, len=%d, space=%d\n", isoc, len, space);
! 1119:
! 1120: if (len == 0) /* nothing to send */
! 1121: return;
! 1122:
! 1123: sc->sc_refcnt++;
! 1124: sc->sc_unit.hci_flags |= BTF_XMIT_SCO;
! 1125: sc->sc_unit.hci_stats.byte_tx += len;
! 1126: isoc->busy = 1;
! 1127:
! 1128: /*
! 1129: * calculate number of isoc frames and sizes
! 1130: */
! 1131:
! 1132: for (num = 0 ; len > 0 ; num++) {
! 1133: size = MIN(sc->sc_scowr_size, len);
! 1134:
! 1135: isoc->size[num] = size;
! 1136: len -= size;
! 1137: }
! 1138:
! 1139: usbd_setup_isoc_xfer(isoc->xfer,
! 1140: sc->sc_scowr_pipe,
! 1141: isoc,
! 1142: isoc->size,
! 1143: num,
! 1144: USBD_NO_COPY | USBD_FORCE_SHORT_XFER,
! 1145: ubt_xmit_sco_complete);
! 1146:
! 1147: usbd_transfer(isoc->xfer);
! 1148: }
! 1149:
! 1150: void
! 1151: ubt_xmit_sco_complete(usbd_xfer_handle xfer,
! 1152: usbd_private_handle h, usbd_status status)
! 1153: {
! 1154: struct ubt_isoc_xfer *isoc = h;
! 1155: struct ubt_softc *sc;
! 1156: int i;
! 1157:
! 1158: KASSERT(xfer == isoc->xfer);
! 1159: sc = isoc->softc;
! 1160:
! 1161: DPRINTFN(15, "isoc=%p, status=%s (%d)\n",
! 1162: isoc, usbd_errstr(status), status);
! 1163:
! 1164: isoc->busy = 0;
! 1165:
! 1166: for (i = 0 ; ; i++) {
! 1167: if (i == UBT_NXFERS) {
! 1168: sc->sc_unit.hci_flags &= ~BTF_XMIT_SCO;
! 1169: break;
! 1170: }
! 1171:
! 1172: if (sc->sc_scowr[i].busy)
! 1173: break;
! 1174: }
! 1175:
! 1176: if (--sc->sc_refcnt < 0) {
! 1177: usb_detach_wakeup(&sc->sc_dev);
! 1178: return;
! 1179: }
! 1180:
! 1181: if (sc->sc_dying)
! 1182: return;
! 1183:
! 1184: if (status != USBD_NORMAL_COMPLETION) {
! 1185: DPRINTF("status=%s (%d)\n",
! 1186: usbd_errstr(status), status);
! 1187:
! 1188: sc->sc_unit.hci_stats.err_tx++;
! 1189:
! 1190: if (status == USBD_STALLED)
! 1191: usbd_clear_endpoint_stall_async(sc->sc_scowr_pipe);
! 1192: else
! 1193: return;
! 1194: }
! 1195:
! 1196: ubt_xmit_sco_start(&sc->sc_unit);
! 1197: }
! 1198:
! 1199: /*
! 1200: * load incoming data into an mbuf with
! 1201: * leading type byte
! 1202: */
! 1203: static struct mbuf *
! 1204: ubt_mbufload(uint8_t *buf, int count, uint8_t type)
! 1205: {
! 1206: struct mbuf *m;
! 1207:
! 1208: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 1209: if (m == NULL)
! 1210: return NULL;
! 1211:
! 1212: *mtod(m, uint8_t *) = type;
! 1213: m->m_pkthdr.len = m->m_len = MHLEN;
! 1214: m_copyback(m, 1, count, buf); // (extends if necessary)
! 1215: if (m->m_pkthdr.len != MAX(MHLEN, count + 1)) {
! 1216: m_free(m);
! 1217: return NULL;
! 1218: }
! 1219:
! 1220: m->m_pkthdr.len = count + 1;
! 1221: m->m_len = MIN(MHLEN, m->m_pkthdr.len);
! 1222:
! 1223: return m;
! 1224: }
! 1225:
! 1226: void
! 1227: ubt_recv_event(usbd_xfer_handle xfer, usbd_private_handle h, usbd_status status)
! 1228: {
! 1229: struct ubt_softc *sc = h;
! 1230: struct mbuf *m;
! 1231: uint32_t count;
! 1232: void *buf;
! 1233:
! 1234: DPRINTFN(15, "sc=%p status=%s (%d)\n",
! 1235: sc, usbd_errstr(status), status);
! 1236:
! 1237: if (status != USBD_NORMAL_COMPLETION || sc->sc_dying)
! 1238: return;
! 1239:
! 1240: usbd_get_xfer_status(xfer, NULL, &buf, &count, NULL);
! 1241:
! 1242: if (count < sizeof(hci_event_hdr_t) - 1) {
! 1243: DPRINTF("dumped undersized event (count = %d)\n", count);
! 1244: sc->sc_unit.hci_stats.err_rx++;
! 1245: return;
! 1246: }
! 1247:
! 1248: sc->sc_unit.hci_stats.evt_rx++;
! 1249: sc->sc_unit.hci_stats.byte_rx += count;
! 1250:
! 1251: m = ubt_mbufload(buf, count, HCI_EVENT_PKT);
! 1252: if (m != NULL)
! 1253: hci_input_event(&sc->sc_unit, m);
! 1254: else
! 1255: sc->sc_unit.hci_stats.err_rx++;
! 1256: }
! 1257:
! 1258: void
! 1259: ubt_recv_acl_start(struct ubt_softc *sc)
! 1260: {
! 1261: usbd_status status;
! 1262:
! 1263: DPRINTFN(15, "sc=%p\n", sc);
! 1264:
! 1265: if (sc->sc_aclrd_busy || sc->sc_dying) {
! 1266: DPRINTF("sc_aclrd_busy=%d, sc_dying=%d\n",
! 1267: sc->sc_aclrd_busy,
! 1268: sc->sc_dying);
! 1269:
! 1270: return;
! 1271: }
! 1272:
! 1273: sc->sc_refcnt++;
! 1274: sc->sc_aclrd_busy = 1;
! 1275:
! 1276: usbd_setup_xfer(sc->sc_aclrd_xfer,
! 1277: sc->sc_aclrd_pipe,
! 1278: sc,
! 1279: sc->sc_aclrd_buf,
! 1280: UBT_BUFSIZ_ACL,
! 1281: USBD_NO_COPY | USBD_SHORT_XFER_OK,
! 1282: USBD_NO_TIMEOUT,
! 1283: ubt_recv_acl_complete);
! 1284:
! 1285: status = usbd_transfer(sc->sc_aclrd_xfer);
! 1286:
! 1287: KASSERT(status != USBD_NORMAL_COMPLETION);
! 1288:
! 1289: if (status != USBD_IN_PROGRESS) {
! 1290: DPRINTF("usbd_transfer status=%s (%d)\n",
! 1291: usbd_errstr(status), status);
! 1292:
! 1293: sc->sc_refcnt--;
! 1294: sc->sc_aclrd_busy = 0;
! 1295: }
! 1296: }
! 1297:
! 1298: void
! 1299: ubt_recv_acl_complete(usbd_xfer_handle xfer,
! 1300: usbd_private_handle h, usbd_status status)
! 1301: {
! 1302: struct ubt_softc *sc = h;
! 1303: struct mbuf *m;
! 1304: uint32_t count;
! 1305: void *buf;
! 1306:
! 1307: DPRINTFN(15, "sc=%p status=%s (%d)\n",
! 1308: sc, usbd_errstr(status), status);
! 1309:
! 1310: sc->sc_aclrd_busy = 0;
! 1311:
! 1312: if (--sc->sc_refcnt < 0) {
! 1313: DPRINTF("refcnt = %d\n", sc->sc_refcnt);
! 1314: usb_detach_wakeup(&sc->sc_dev);
! 1315: return;
! 1316: }
! 1317:
! 1318: if (sc->sc_dying) {
! 1319: DPRINTF("sc_dying\n");
! 1320: return;
! 1321: }
! 1322:
! 1323: if (status != USBD_NORMAL_COMPLETION) {
! 1324: DPRINTF("status=%s (%d)\n",
! 1325: usbd_errstr(status), status);
! 1326:
! 1327: sc->sc_unit.hci_stats.err_rx++;
! 1328:
! 1329: if (status == USBD_STALLED)
! 1330: usbd_clear_endpoint_stall_async(sc->sc_aclrd_pipe);
! 1331: else
! 1332: return;
! 1333: } else {
! 1334: usbd_get_xfer_status(xfer, NULL, &buf, &count, NULL);
! 1335:
! 1336: if (count < sizeof(hci_acldata_hdr_t) - 1) {
! 1337: DPRINTF("dumped undersized packet (%d)\n", count);
! 1338: sc->sc_unit.hci_stats.err_rx++;
! 1339: } else {
! 1340: sc->sc_unit.hci_stats.acl_rx++;
! 1341: sc->sc_unit.hci_stats.byte_rx += count;
! 1342:
! 1343: m = ubt_mbufload(buf, count, HCI_ACL_DATA_PKT);
! 1344: if (m != NULL)
! 1345: hci_input_acl(&sc->sc_unit, m);
! 1346: else
! 1347: sc->sc_unit.hci_stats.err_rx++;
! 1348: }
! 1349: }
! 1350:
! 1351: /* and restart */
! 1352: ubt_recv_acl_start(sc);
! 1353: }
! 1354:
! 1355: void
! 1356: ubt_recv_sco_start1(struct ubt_softc *sc, struct ubt_isoc_xfer *isoc)
! 1357: {
! 1358: int i;
! 1359:
! 1360: DPRINTFN(15, "sc=%p, isoc=%p\n", sc, isoc);
! 1361:
! 1362: if (isoc->busy || sc->sc_dying || sc->sc_scord_size == 0) {
! 1363: DPRINTF("%s%s%s\n",
! 1364: isoc->busy ? " busy" : "",
! 1365: sc->sc_dying ? " dying" : "",
! 1366: sc->sc_scord_size == 0 ? " size=0" : "");
! 1367:
! 1368: return;
! 1369: }
! 1370:
! 1371: sc->sc_refcnt++;
! 1372: isoc->busy = 1;
! 1373:
! 1374: for (i = 0 ; i < UBT_NFRAMES ; i++)
! 1375: isoc->size[i] = sc->sc_scord_size;
! 1376:
! 1377: usbd_setup_isoc_xfer(isoc->xfer,
! 1378: sc->sc_scord_pipe,
! 1379: isoc,
! 1380: isoc->size,
! 1381: UBT_NFRAMES,
! 1382: USBD_NO_COPY | USBD_SHORT_XFER_OK,
! 1383: ubt_recv_sco_complete);
! 1384:
! 1385: usbd_transfer(isoc->xfer);
! 1386: }
! 1387:
! 1388: void
! 1389: ubt_recv_sco_complete(usbd_xfer_handle xfer,
! 1390: usbd_private_handle h, usbd_status status)
! 1391: {
! 1392: struct ubt_isoc_xfer *isoc = h;
! 1393: struct ubt_softc *sc;
! 1394: struct mbuf *m;
! 1395: uint32_t count;
! 1396: uint8_t *ptr, *frame;
! 1397: int i, size, got, want;
! 1398:
! 1399: KASSERT(isoc != NULL);
! 1400: KASSERT(isoc->xfer == xfer);
! 1401:
! 1402: sc = isoc->softc;
! 1403: isoc->busy = 0;
! 1404:
! 1405: if (--sc->sc_refcnt < 0) {
! 1406: DPRINTF("refcnt=%d\n", sc->sc_refcnt);
! 1407: usb_detach_wakeup(&sc->sc_dev);
! 1408: return;
! 1409: }
! 1410:
! 1411: if (sc->sc_dying) {
! 1412: DPRINTF("sc_dying\n");
! 1413: return;
! 1414: }
! 1415:
! 1416: if (status != USBD_NORMAL_COMPLETION) {
! 1417: DPRINTF("status=%s (%d)\n",
! 1418: usbd_errstr(status), status);
! 1419:
! 1420: sc->sc_unit.hci_stats.err_rx++;
! 1421:
! 1422: if (status == USBD_STALLED) {
! 1423: usbd_clear_endpoint_stall_async(sc->sc_scord_pipe);
! 1424: goto restart;
! 1425: }
! 1426:
! 1427: return;
! 1428: }
! 1429:
! 1430: usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
! 1431: if (count == 0)
! 1432: goto restart;
! 1433:
! 1434: DPRINTFN(15, "sc=%p, isoc=%p, count=%u\n",
! 1435: sc, isoc, count);
! 1436:
! 1437: sc->sc_unit.hci_stats.byte_rx += count;
! 1438:
! 1439: /*
! 1440: * Extract SCO packets from ISOC frames. The way we have it,
! 1441: * no SCO packet can be bigger than MHLEN. This is unlikely
! 1442: * to actually happen, but if we ran out of mbufs and lost
! 1443: * sync then we may get spurious data that makes it seem that
! 1444: * way, so we discard data that wont fit. This doesnt really
! 1445: * help with the lost sync situation alas.
! 1446: */
! 1447:
! 1448: m = sc->sc_scord_mbuf;
! 1449: if (m != NULL) {
! 1450: sc->sc_scord_mbuf = NULL;
! 1451: ptr = mtod(m, uint8_t *) + m->m_pkthdr.len;
! 1452: got = m->m_pkthdr.len;
! 1453: want = sizeof(hci_scodata_hdr_t);
! 1454: if (got >= want)
! 1455: want += mtod(m, hci_scodata_hdr_t *)->length ;
! 1456: } else {
! 1457: ptr = NULL;
! 1458: got = 0;
! 1459: want = 0;
! 1460: }
! 1461:
! 1462: for (i = 0 ; i < UBT_NFRAMES ; i++) {
! 1463: frame = isoc->buf + (i * sc->sc_scord_size);
! 1464:
! 1465: while (isoc->size[i] > 0) {
! 1466: size = isoc->size[i];
! 1467:
! 1468: if (m == NULL) {
! 1469: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 1470: if (m == NULL) {
! 1471: printf("%s: out of memory (xfer halted)\n",
! 1472: sc->sc_dev.dv_xname);
! 1473:
! 1474: sc->sc_unit.hci_stats.err_rx++;
! 1475: return; /* lost sync */
! 1476: }
! 1477:
! 1478: ptr = mtod(m, uint8_t *);
! 1479: *ptr++ = HCI_SCO_DATA_PKT;
! 1480: got = 1;
! 1481: want = sizeof(hci_scodata_hdr_t);
! 1482: }
! 1483:
! 1484: if (got + size > want)
! 1485: size = want - got;
! 1486:
! 1487: if (got + size > MHLEN)
! 1488: memcpy(ptr, frame, MHLEN - got);
! 1489: else
! 1490: memcpy(ptr, frame, size);
! 1491:
! 1492: ptr += size;
! 1493: got += size;
! 1494: frame += size;
! 1495:
! 1496: if (got == want) {
! 1497: /*
! 1498: * If we only got a header, add the packet
! 1499: * length to our want count. Send complete
! 1500: * packets up to protocol stack.
! 1501: */
! 1502: if (want == sizeof(hci_scodata_hdr_t))
! 1503: want += mtod(m, hci_scodata_hdr_t *)->length;
! 1504:
! 1505: if (got == want) {
! 1506: m->m_pkthdr.len = m->m_len = got;
! 1507: sc->sc_unit.hci_stats.sco_rx++;
! 1508: hci_input_sco(&sc->sc_unit, m);
! 1509: m = NULL;
! 1510: }
! 1511: }
! 1512:
! 1513: isoc->size[i] -= size;
! 1514: }
! 1515: }
! 1516:
! 1517: if (m != NULL) {
! 1518: m->m_pkthdr.len = m->m_len = got;
! 1519: sc->sc_scord_mbuf = m;
! 1520: }
! 1521:
! 1522: restart: /* and restart */
! 1523: ubt_recv_sco_start1(sc, isoc);
! 1524: }
CVSweb