Annotation of src/sys/dev/usb/ubt.c, Revision 1.63
1.63 ! dsainty 1: /* $NetBSD: ubt.c,v 1.62 2019/05/05 03:17:54 mrg Exp $ */
1.1 augustss 2:
1.14 gdamore 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: */
1.1 augustss 33: /*
1.5 dsainty 34: * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
1.1 augustss 35: * All rights reserved.
36: *
37: * This code is derived from software contributed to The NetBSD Foundation
1.5 dsainty 38: * by Lennart Augustsson (lennart@augustsson.net) and
1.63 ! dsainty 39: * David Sainty (dsainty@NetBSD.org).
1.1 augustss 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: *
50: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
51: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
52: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
53: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
54: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
55: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
56: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
57: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
58: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
59: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
60: * POSSIBILITY OF SUCH DAMAGE.
61: */
1.14 gdamore 62: /*
63: * This driver originally written by Lennart Augustsson and David Sainty,
64: * but was mostly rewritten for the NetBSD Bluetooth protocol stack by
65: * Iain Hibbert for Itronix, Inc using the FreeBSD ng_ubt.c driver as a
66: * reference.
67: */
1.1 augustss 68:
69: #include <sys/cdefs.h>
1.63 ! dsainty 70: __KERNEL_RCSID(0, "$NetBSD: ubt.c,v 1.62 2019/05/05 03:17:54 mrg Exp $");
1.57 skrll 71:
72: #ifdef _KERNEL_OPT
73: #include "opt_usb.h"
74: #endif
1.1 augustss 75:
76: #include <sys/param.h>
1.14 gdamore 77: #include <sys/device.h>
78: #include <sys/ioctl.h>
1.1 augustss 79: #include <sys/kernel.h>
1.54 skrll 80: #include <sys/kmem.h>
1.14 gdamore 81: #include <sys/mbuf.h>
1.1 augustss 82: #include <sys/proc.h>
1.14 gdamore 83: #include <sys/sysctl.h>
84: #include <sys/systm.h>
1.1 augustss 85:
86: #include <dev/usb/usb.h>
87: #include <dev/usb/usbdi.h>
88: #include <dev/usb/usbdi_util.h>
89: #include <dev/usb/usbdevs.h>
90:
1.14 gdamore 91: #include <netbt/bluetooth.h>
92: #include <netbt/hci.h>
93:
94: /*******************************************************************************
95: *
96: * debugging stuff
97: */
98: #undef DPRINTF
99: #undef DPRINTFN
1.3 augustss 100:
1.1 augustss 101: #ifdef UBT_DEBUG
1.27 plunky 102: int ubt_debug = 0;
1.14 gdamore 103:
1.40 plunky 104: #define DPRINTF(...) do { \
105: if (ubt_debug) { \
106: printf("%s: ", __func__); \
107: printf(__VA_ARGS__); \
108: } \
1.14 gdamore 109: } while (/* CONSTCOND */0)
110:
1.40 plunky 111: #define DPRINTFN(n, ...) do { \
112: if (ubt_debug > (n)) { \
113: printf("%s: ", __func__); \
114: printf(__VA_ARGS__); \
115: } \
1.14 gdamore 116: } while (/* CONSTCOND */0)
117:
118: SYSCTL_SETUP(sysctl_hw_ubt_debug_setup, "sysctl hw.ubt_debug setup")
119: {
120:
121: sysctl_createv(NULL, 0, NULL, NULL,
122: CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
123: CTLTYPE_INT, "ubt_debug",
124: SYSCTL_DESCR("ubt debug level"),
125: NULL, 0,
126: &ubt_debug, sizeof(ubt_debug),
127: CTL_HW, CTL_CREATE, CTL_EOL);
128: }
1.1 augustss 129: #else
1.14 gdamore 130: #define DPRINTF(...)
131: #define DPRINTFN(...)
1.1 augustss 132: #endif
133:
1.14 gdamore 134: /*******************************************************************************
135: *
136: * ubt softc structure
137: *
138: */
139:
140: /* buffer sizes */
1.1 augustss 141: /*
1.14 gdamore 142: * NB: although ACL packets can extend to 65535 bytes, most devices
143: * have max_acl_size at much less (largest I have seen is 384)
1.1 augustss 144: */
1.14 gdamore 145: #define UBT_BUFSIZ_CMD (HCI_CMD_PKT_SIZE - 1)
146: #define UBT_BUFSIZ_ACL (2048 - 1)
147: #define UBT_BUFSIZ_EVENT (HCI_EVENT_PKT_SIZE - 1)
148:
149: /* Transmit timeouts */
150: #define UBT_CMD_TIMEOUT USBD_DEFAULT_TIMEOUT
151: #define UBT_ACL_TIMEOUT USBD_DEFAULT_TIMEOUT
152:
153: /*
154: * ISOC transfers
155: *
156: * xfer buffer size depends on the frame size, and the number
157: * of frames per transfer is fixed, as each frame should be
158: * 1ms worth of data. This keeps the rate that xfers complete
159: * fairly constant. We use multiple xfers to keep the hardware
160: * busy
161: */
162: #define UBT_NXFERS 3 /* max xfers to queue */
163: #define UBT_NFRAMES 10 /* frames per xfer */
164:
165: struct ubt_isoc_xfer {
166: struct ubt_softc *softc;
1.54 skrll 167: struct usbd_xfer *xfer;
1.14 gdamore 168: uint8_t *buf;
169: uint16_t size[UBT_NFRAMES];
170: int busy;
171: };
1.1 augustss 172:
173: struct ubt_softc {
1.39 dyoung 174: device_t sc_dev;
1.54 skrll 175: struct usbd_device *sc_udev;
1.14 gdamore 176: int sc_refcnt;
177: int sc_dying;
1.29 plunky 178: int sc_enabled;
1.14 gdamore 179:
180: /* Control Interface */
1.54 skrll 181: struct usbd_interface * sc_iface0;
1.14 gdamore 182:
183: /* Commands (control) */
1.54 skrll 184: struct usbd_xfer *sc_cmd_xfer;
1.14 gdamore 185: uint8_t *sc_cmd_buf;
1.29 plunky 186: int sc_cmd_busy; /* write active */
187: MBUFQ_HEAD() sc_cmd_queue; /* output queue */
1.14 gdamore 188:
189: /* Events (interrupt) */
190: int sc_evt_addr; /* endpoint address */
1.54 skrll 191: struct usbd_pipe *sc_evt_pipe;
1.14 gdamore 192: uint8_t *sc_evt_buf;
1.5 dsainty 193:
194: /* ACL data (in) */
1.14 gdamore 195: int sc_aclrd_addr; /* endpoint address */
1.54 skrll 196: struct usbd_pipe *sc_aclrd_pipe; /* read pipe */
197: struct usbd_xfer *sc_aclrd_xfer; /* read xfer */
1.14 gdamore 198: uint8_t *sc_aclrd_buf; /* read buffer */
199: int sc_aclrd_busy; /* reading */
1.5 dsainty 200:
201: /* ACL data (out) */
1.14 gdamore 202: int sc_aclwr_addr; /* endpoint address */
1.54 skrll 203: struct usbd_pipe *sc_aclwr_pipe; /* write pipe */
204: struct usbd_xfer *sc_aclwr_xfer; /* write xfer */
1.14 gdamore 205: uint8_t *sc_aclwr_buf; /* write buffer */
1.29 plunky 206: int sc_aclwr_busy; /* write active */
207: MBUFQ_HEAD() sc_aclwr_queue;/* output queue */
1.14 gdamore 208:
209: /* ISOC interface */
1.54 skrll 210: struct usbd_interface *sc_iface1; /* ISOC interface */
1.14 gdamore 211: struct sysctllog *sc_log; /* sysctl log */
212: int sc_config; /* current config no */
213: int sc_alt_config; /* no of alternates */
214:
215: /* SCO data (in) */
216: int sc_scord_addr; /* endpoint address */
1.54 skrll 217: struct usbd_pipe *sc_scord_pipe; /* read pipe */
1.14 gdamore 218: int sc_scord_size; /* frame length */
219: struct ubt_isoc_xfer sc_scord[UBT_NXFERS];
220: struct mbuf *sc_scord_mbuf; /* current packet */
221:
222: /* SCO data (out) */
223: int sc_scowr_addr; /* endpoint address */
1.54 skrll 224: struct usbd_pipe *sc_scowr_pipe; /* write pipe */
1.14 gdamore 225: int sc_scowr_size; /* frame length */
226: struct ubt_isoc_xfer sc_scowr[UBT_NXFERS];
227: struct mbuf *sc_scowr_mbuf; /* current packet */
1.29 plunky 228: int sc_scowr_busy; /* write active */
229: MBUFQ_HEAD() sc_scowr_queue;/* output queue */
1.1 augustss 230:
1.14 gdamore 231: /* Protocol structure */
1.29 plunky 232: struct hci_unit *sc_unit;
233: struct bt_stats sc_stats;
1.23 plunky 234:
235: /* Successfully attached */
236: int sc_ok;
1.14 gdamore 237: };
238:
239: /*******************************************************************************
240: *
241: * Bluetooth unit/USB callback routines
242: *
243: */
1.39 dyoung 244: static int ubt_enable(device_t);
245: static void ubt_disable(device_t);
1.14 gdamore 246:
1.39 dyoung 247: static void ubt_xmit_cmd(device_t, struct mbuf *);
1.29 plunky 248: static void ubt_xmit_cmd_start(struct ubt_softc *);
1.54 skrll 249: static void ubt_xmit_cmd_complete(struct usbd_xfer *,
250: void *, usbd_status);
1.14 gdamore 251:
1.39 dyoung 252: static void ubt_xmit_acl(device_t, struct mbuf *);
1.29 plunky 253: static void ubt_xmit_acl_start(struct ubt_softc *);
1.54 skrll 254: static void ubt_xmit_acl_complete(struct usbd_xfer *,
255: void *, usbd_status);
1.14 gdamore 256:
1.39 dyoung 257: static void ubt_xmit_sco(device_t, struct mbuf *);
1.29 plunky 258: static void ubt_xmit_sco_start(struct ubt_softc *);
1.14 gdamore 259: static void ubt_xmit_sco_start1(struct ubt_softc *, struct ubt_isoc_xfer *);
1.54 skrll 260: static void ubt_xmit_sco_complete(struct usbd_xfer *,
261: void *, usbd_status);
1.5 dsainty 262:
1.54 skrll 263: static void ubt_recv_event(struct usbd_xfer *,
264: void *, usbd_status);
1.1 augustss 265:
1.14 gdamore 266: static void ubt_recv_acl_start(struct ubt_softc *);
1.54 skrll 267: static void ubt_recv_acl_complete(struct usbd_xfer *,
268: void *, usbd_status);
1.5 dsainty 269:
1.14 gdamore 270: static void ubt_recv_sco_start1(struct ubt_softc *, struct ubt_isoc_xfer *);
1.54 skrll 271: static void ubt_recv_sco_complete(struct usbd_xfer *,
272: void *, usbd_status);
1.6 dsainty 273:
1.39 dyoung 274: static void ubt_stats(device_t, struct bt_stats *, int);
1.29 plunky 275:
276: static const struct hci_if ubt_hci = {
277: .enable = ubt_enable,
278: .disable = ubt_disable,
279: .output_cmd = ubt_xmit_cmd,
280: .output_acl = ubt_xmit_acl,
281: .output_sco = ubt_xmit_sco,
282: .get_stats = ubt_stats,
1.54 skrll 283: .ipl = IPL_SOFTUSB,
1.29 plunky 284: };
1.6 dsainty 285:
1.14 gdamore 286: /*******************************************************************************
287: *
288: * USB Autoconfig stuff
289: *
290: */
1.5 dsainty 291:
1.55 msaitoh 292: int ubt_match(device_t, cfdata_t, void *);
293: void ubt_attach(device_t, device_t, void *);
294: int ubt_detach(device_t, int);
295: int ubt_activate(device_t, enum devact);
1.62 mrg 296:
1.55 msaitoh 297: CFATTACH_DECL_NEW(ubt, sizeof(struct ubt_softc), ubt_match, ubt_attach,
298: ubt_detach, ubt_activate);
1.1 augustss 299:
1.14 gdamore 300: static int ubt_set_isoc_config(struct ubt_softc *);
301: static int ubt_sysctl_config(SYSCTLFN_PROTO);
302: static void ubt_abortdealloc(struct ubt_softc *);
303:
1.15 plunky 304: /*
1.53 plunky 305: * To match or ignore, add details to the ubt_dev list.
306: * Use value of -1 to indicate a wildcard
307: * To override another entry, add details earlier
1.15 plunky 308: */
1.49 christos 309: const struct ubt_devno {
1.53 plunky 310: int vendor;
311: int product;
312: int class;
313: int subclass;
314: int proto;
1.49 christos 315: int match;
316: } ubt_dev[] = {
1.53 plunky 317: { /* ignore Broadcom 2033 without firmware */
318: USB_VENDOR_BROADCOM,
319: USB_PRODUCT_BROADCOM_BCM2033NF,
320: -1,
321: -1,
322: -1,
323: UMATCH_NONE
324: },
325: { /* Apple Bluetooth Host Controller MacbookPro 7,1 */
326: USB_VENDOR_APPLE,
327: USB_PRODUCT_APPLE_BLUETOOTH_HOST_1,
328: -1,
329: -1,
330: -1,
331: UMATCH_VENDOR_PRODUCT
332: },
333: { /* Apple Bluetooth Host Controller iMac 11,1 */
334: USB_VENDOR_APPLE,
335: USB_PRODUCT_APPLE_BLUETOOTH_HOST_2,
336: -1,
337: -1,
338: -1,
339: UMATCH_VENDOR_PRODUCT
340: },
341: { /* Apple Bluetooth Host Controller MacBookPro 8,2 */
342: USB_VENDOR_APPLE,
343: USB_PRODUCT_APPLE_BLUETOOTH_HOST_3,
344: -1,
345: -1,
346: -1,
347: UMATCH_VENDOR_PRODUCT
348: },
349: { /* Apple Bluetooth Host Controller MacBookAir 3,1 3,2*/
350: USB_VENDOR_APPLE,
351: USB_PRODUCT_APPLE_BLUETOOTH_HOST_4,
352: -1,
353: -1,
354: -1,
355: UMATCH_VENDOR_PRODUCT
356: },
357: { /* Apple Bluetooth Host Controller MacBookAir 4,1 */
358: USB_VENDOR_APPLE,
359: USB_PRODUCT_APPLE_BLUETOOTH_HOST_5,
360: -1,
361: -1,
362: -1,
363: UMATCH_VENDOR_PRODUCT
364: },
365: { /* Apple Bluetooth Host Controller MacMini 5,1 */
366: USB_VENDOR_APPLE,
367: USB_PRODUCT_APPLE_BLUETOOTH_HOST_6,
368: -1,
369: -1,
370: -1,
371: UMATCH_VENDOR_PRODUCT
372: },
373: { /* Apple Bluetooth Host Controller MacBookAir 6,1 */
374: USB_VENDOR_APPLE,
375: USB_PRODUCT_APPLE_BLUETOOTH_HOST_7,
376: -1,
377: -1,
378: -1,
379: UMATCH_VENDOR_PRODUCT
380: },
1.58 snj 381: { /* Apple Bluetooth Host Controller MacBookPro 9,2 */
382: USB_VENDOR_APPLE,
383: USB_PRODUCT_APPLE_BLUETOOTH_HOST_8,
384: -1,
385: -1,
386: -1,
387: UMATCH_VENDOR_PRODUCT
388: },
1.53 plunky 389: { /* Broadcom chips with PatchRAM support */
390: USB_VENDOR_BROADCOM,
391: -1,
392: UDCLASS_VENDOR,
393: UDSUBCLASS_RF,
394: UDPROTO_BLUETOOTH,
395: UMATCH_VENDOR_DEVCLASS_DEVPROTO
396: },
397: { /* Broadcom based device with PatchRAM support */
398: USB_VENDOR_FOXCONN,
399: -1,
400: UDCLASS_VENDOR,
401: UDSUBCLASS_RF,
402: UDPROTO_BLUETOOTH,
403: UMATCH_VENDOR_DEVCLASS_DEVPROTO
404: },
405: { /* Broadcom based device with PatchRAM support */
406: USB_VENDOR_LITEON,
407: -1,
408: UDCLASS_VENDOR,
409: UDSUBCLASS_RF,
410: UDPROTO_BLUETOOTH,
411: UMATCH_VENDOR_DEVCLASS_DEVPROTO
412: },
413: { /* Broadcom based device with PatchRAM support */
414: USB_VENDOR_BELKIN,
415: -1,
416: UDCLASS_VENDOR,
417: UDSUBCLASS_RF,
418: UDPROTO_BLUETOOTH,
419: UMATCH_VENDOR_DEVCLASS_DEVPROTO
420: },
421: { /* Broadcom based device with PatchRAM support */
422: USB_VENDOR_TOSHIBA,
423: -1,
424: UDCLASS_VENDOR,
425: UDSUBCLASS_RF,
426: UDPROTO_BLUETOOTH,
427: UMATCH_VENDOR_DEVCLASS_DEVPROTO
428: },
429: { /* Broadcom based device with PatchRAM support */
430: USB_VENDOR_ASUSTEK,
431: -1,
432: UDCLASS_VENDOR,
433: UDSUBCLASS_RF,
434: UDPROTO_BLUETOOTH,
435: UMATCH_VENDOR_DEVCLASS_DEVPROTO
436: },
437: { /* Generic Bluetooth SIG compliant devices */
438: -1,
439: -1,
440: UDCLASS_WIRELESS,
441: UDSUBCLASS_RF,
442: UDPROTO_BLUETOOTH,
443: UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO
444: },
1.15 plunky 445: };
446:
1.54 skrll 447: int
1.39 dyoung 448: ubt_match(device_t parent, cfdata_t match, void *aux)
1.1 augustss 449: {
1.39 dyoung 450: struct usb_attach_arg *uaa = aux;
1.53 plunky 451: size_t i;
1.1 augustss 452:
1.14 gdamore 453: DPRINTFN(50, "ubt_match\n");
1.1 augustss 454:
1.53 plunky 455: for (i = 0; i < __arraycount(ubt_dev); i++) {
1.56 msaitoh 456: if (ubt_dev[i].vendor != -1
1.54 skrll 457: && ubt_dev[i].vendor != (int)uaa->uaa_vendor)
1.53 plunky 458: continue;
1.56 msaitoh 459: if (ubt_dev[i].product != -1
1.54 skrll 460: && ubt_dev[i].product != (int)uaa->uaa_product)
1.53 plunky 461: continue;
1.56 msaitoh 462: if (ubt_dev[i].class != -1
1.54 skrll 463: && ubt_dev[i].class != uaa->uaa_class)
1.53 plunky 464: continue;
1.56 msaitoh 465: if (ubt_dev[i].subclass != -1
1.54 skrll 466: && ubt_dev[i].subclass != uaa->uaa_subclass)
1.53 plunky 467: continue;
1.56 msaitoh 468: if (ubt_dev[i].proto != -1
1.54 skrll 469: && ubt_dev[i].proto != uaa->uaa_proto)
1.53 plunky 470: continue;
1.15 plunky 471:
1.53 plunky 472: return ubt_dev[i].match;
473: }
1.14 gdamore 474:
475: return UMATCH_NONE;
1.1 augustss 476: }
477:
1.54 skrll 478: void
1.39 dyoung 479: ubt_attach(device_t parent, device_t self, void *aux)
1.1 augustss 480: {
1.39 dyoung 481: struct ubt_softc *sc = device_private(self);
482: struct usb_attach_arg *uaa = aux;
1.14 gdamore 483: usb_config_descriptor_t *cd;
484: usb_endpoint_descriptor_t *ed;
485: const struct sysctlnode *node;
486: char *devinfop;
487: int err;
488: uint8_t count, i;
1.1 augustss 489:
1.14 gdamore 490: DPRINTFN(50, "ubt_attach: sc=%p\n", sc);
1.1 augustss 491:
1.32 cube 492: sc->sc_dev = self;
1.54 skrll 493: sc->sc_udev = uaa->uaa_device;
1.14 gdamore 494:
1.29 plunky 495: MBUFQ_INIT(&sc->sc_cmd_queue);
496: MBUFQ_INIT(&sc->sc_aclwr_queue);
497: MBUFQ_INIT(&sc->sc_scowr_queue);
498:
1.37 plunky 499: aprint_naive("\n");
500: aprint_normal("\n");
501:
1.14 gdamore 502: devinfop = usbd_devinfo_alloc(sc->sc_udev, 0);
1.32 cube 503: aprint_normal_dev(self, "%s\n", devinfop);
1.12 augustss 504: usbd_devinfo_free(devinfop);
1.1 augustss 505:
1.14 gdamore 506: /*
1.23 plunky 507: * Move the device into the configured state
1.14 gdamore 508: */
1.23 plunky 509: err = usbd_set_config_index(sc->sc_udev, 0, 1);
510: if (err) {
1.56 msaitoh 511: aprint_error_dev(self,
512: "failed to set configuration idx 0: %s\n",
1.32 cube 513: usbd_errstr(err));
1.14 gdamore 514:
1.39 dyoung 515: return;
1.14 gdamore 516: }
1.1 augustss 517:
1.5 dsainty 518: /*
1.14 gdamore 519: * Interface 0 must have 3 endpoints
520: * 1) Interrupt endpoint to receive HCI events
521: * 2) Bulk IN endpoint to receive ACL data
522: * 3) Bulk OUT endpoint to send ACL data
1.3 augustss 523: */
1.23 plunky 524: err = usbd_device2interface_handle(sc->sc_udev, 0, &sc->sc_iface0);
1.14 gdamore 525: if (err) {
1.56 msaitoh 526: aprint_error_dev(self,
527: "Could not get interface 0 handle %s (%d)\n",
528: usbd_errstr(err), err);
1.14 gdamore 529:
1.39 dyoung 530: return;
1.14 gdamore 531: }
1.5 dsainty 532:
533: sc->sc_evt_addr = -1;
534: sc->sc_aclrd_addr = -1;
535: sc->sc_aclwr_addr = -1;
536:
1.14 gdamore 537: count = 0;
1.23 plunky 538: (void)usbd_endpoint_count(sc->sc_iface0, &count);
1.14 gdamore 539:
540: for (i = 0 ; i < count ; i++) {
541: int dir, type;
542:
1.23 plunky 543: ed = usbd_interface2endpoint_descriptor(sc->sc_iface0, i);
1.1 augustss 544: if (ed == NULL) {
1.32 cube 545: aprint_error_dev(self,
546: "could not read endpoint descriptor %d\n", i);
1.14 gdamore 547:
1.39 dyoung 548: return;
1.1 augustss 549: }
1.5 dsainty 550:
1.14 gdamore 551: dir = UE_GET_DIR(ed->bEndpointAddress);
552: type = UE_GET_XFERTYPE(ed->bmAttributes);
1.5 dsainty 553:
1.14 gdamore 554: if (dir == UE_DIR_IN && type == UE_INTERRUPT)
1.5 dsainty 555: sc->sc_evt_addr = ed->bEndpointAddress;
1.14 gdamore 556: else if (dir == UE_DIR_IN && type == UE_BULK)
1.5 dsainty 557: sc->sc_aclrd_addr = ed->bEndpointAddress;
1.14 gdamore 558: else if (dir == UE_DIR_OUT && type == UE_BULK)
1.5 dsainty 559: sc->sc_aclwr_addr = ed->bEndpointAddress;
1.1 augustss 560: }
1.5 dsainty 561:
1.14 gdamore 562: if (sc->sc_evt_addr == -1) {
1.32 cube 563: aprint_error_dev(self,
564: "missing INTERRUPT endpoint on interface 0\n");
1.14 gdamore 565:
1.39 dyoung 566: return;
1.14 gdamore 567: }
568: if (sc->sc_aclrd_addr == -1) {
1.32 cube 569: aprint_error_dev(self,
570: "missing BULK IN endpoint on interface 0\n");
1.14 gdamore 571:
1.39 dyoung 572: return;
1.14 gdamore 573: }
574: if (sc->sc_aclwr_addr == -1) {
1.32 cube 575: aprint_error_dev(self,
576: "missing BULK OUT endpoint on interface 0\n");
1.14 gdamore 577:
1.39 dyoung 578: return;
1.14 gdamore 579: }
580:
581: /*
582: * Interface 1 must have 2 endpoints
583: * 1) Isochronous IN endpoint to receive SCO data
584: * 2) Isochronous OUT endpoint to send SCO data
585: *
586: * and will have several configurations, which can be selected
587: * via a sysctl variable. We select config 0 to start, which
588: * means that no SCO data will be available.
589: */
1.23 plunky 590: err = usbd_device2interface_handle(sc->sc_udev, 1, &sc->sc_iface1);
1.14 gdamore 591: if (err) {
1.32 cube 592: aprint_error_dev(self,
593: "Could not get interface 1 handle %s (%d)\n",
594: usbd_errstr(err), err);
1.14 gdamore 595:
1.39 dyoung 596: return;
1.14 gdamore 597: }
598:
599: cd = usbd_get_config_descriptor(sc->sc_udev);
600: if (cd == NULL) {
1.32 cube 601: aprint_error_dev(self, "could not get config descriptor\n");
1.14 gdamore 602:
1.39 dyoung 603: return;
1.14 gdamore 604: }
605:
606: sc->sc_alt_config = usbd_get_no_alts(cd, 1);
607:
608: /* set initial config */
609: err = ubt_set_isoc_config(sc);
610: if (err) {
1.32 cube 611: aprint_error_dev(self, "ISOC config failed\n");
1.14 gdamore 612:
1.39 dyoung 613: return;
1.1 augustss 614: }
615:
1.14 gdamore 616: /* Attach HCI */
1.51 rmind 617: sc->sc_unit = hci_attach_pcb(&ubt_hci, sc->sc_dev, 0);
1.14 gdamore 618:
1.55 msaitoh 619: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev);
1.14 gdamore 620:
621: /* sysctl set-up for alternate configs */
622: sysctl_createv(&sc->sc_log, 0, NULL, &node,
623: 0,
1.39 dyoung 624: CTLTYPE_NODE, device_xname(sc->sc_dev),
1.14 gdamore 625: SYSCTL_DESCR("ubt driver information"),
626: NULL, 0,
627: NULL, 0,
628: CTL_HW,
629: CTL_CREATE, CTL_EOL);
630:
631: if (node != NULL) {
632: sysctl_createv(&sc->sc_log, 0, NULL, NULL,
633: CTLFLAG_READWRITE,
634: CTLTYPE_INT, "config",
635: SYSCTL_DESCR("configuration number"),
636: ubt_sysctl_config, 0,
1.48 dsl 637: (void *)sc, 0,
1.14 gdamore 638: CTL_HW, node->sysctl_num,
639: CTL_CREATE, CTL_EOL);
640:
641: sysctl_createv(&sc->sc_log, 0, NULL, NULL,
642: CTLFLAG_READONLY,
643: CTLTYPE_INT, "alt_config",
644: SYSCTL_DESCR("number of alternate configurations"),
645: NULL, 0,
646: &sc->sc_alt_config, sizeof(sc->sc_alt_config),
647: CTL_HW, node->sysctl_num,
648: CTL_CREATE, CTL_EOL);
649:
650: sysctl_createv(&sc->sc_log, 0, NULL, NULL,
651: CTLFLAG_READONLY,
652: CTLTYPE_INT, "sco_rxsize",
653: SYSCTL_DESCR("max SCO receive size"),
654: NULL, 0,
655: &sc->sc_scord_size, sizeof(sc->sc_scord_size),
656: CTL_HW, node->sysctl_num,
657: CTL_CREATE, CTL_EOL);
658:
659: sysctl_createv(&sc->sc_log, 0, NULL, NULL,
660: CTLFLAG_READONLY,
661: CTLTYPE_INT, "sco_txsize",
662: SYSCTL_DESCR("max SCO transmit size"),
663: NULL, 0,
664: &sc->sc_scowr_size, sizeof(sc->sc_scowr_size),
665: CTL_HW, node->sysctl_num,
666: CTL_CREATE, CTL_EOL);
667: }
668:
1.23 plunky 669: sc->sc_ok = 1;
1.46 plunky 670:
1.35 drochner 671: if (!pmf_device_register(self, NULL, NULL))
672: aprint_error_dev(self, "couldn't establish power handler\n");
1.46 plunky 673:
1.39 dyoung 674: return;
1.14 gdamore 675: }
676:
1.54 skrll 677: int
1.39 dyoung 678: ubt_detach(device_t self, int flags)
1.14 gdamore 679: {
1.39 dyoung 680: struct ubt_softc *sc = device_private(self);
1.14 gdamore 681: int s;
682:
683: DPRINTF("sc=%p flags=%d\n", sc, flags);
684:
1.46 plunky 685: pmf_device_deregister(self);
1.30 christos 686:
1.14 gdamore 687: sc->sc_dying = 1;
688:
1.23 plunky 689: if (!sc->sc_ok)
690: return 0;
691:
1.14 gdamore 692: /* delete sysctl nodes */
693: sysctl_teardown(&sc->sc_log);
694:
695: /* Detach HCI interface */
1.29 plunky 696: if (sc->sc_unit) {
1.51 rmind 697: hci_detach_pcb(sc->sc_unit);
1.29 plunky 698: sc->sc_unit = NULL;
699: }
1.14 gdamore 700:
701: /*
702: * Abort all pipes. Causes processes waiting for transfer to wake.
703: *
1.51 rmind 704: * Actually, hci_detach_pcb() above will call ubt_disable() which
705: * may call ubt_abortdealloc(), but lets be sure since doing it
706: * twice wont cause an error.
1.14 gdamore 707: */
708: ubt_abortdealloc(sc);
709:
710: /* wait for all processes to finish */
711: s = splusb();
712: if (sc->sc_refcnt-- > 0)
1.45 mrg 713: usb_detach_waitold(sc->sc_dev);
1.14 gdamore 714:
715: splx(s);
716:
1.55 msaitoh 717: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev);
1.14 gdamore 718:
719: DPRINTFN(1, "driver detached\n");
720:
721: return 0;
722: }
723:
724: int
1.39 dyoung 725: ubt_activate(device_t self, enum devact act)
1.14 gdamore 726: {
1.39 dyoung 727: struct ubt_softc *sc = device_private(self);
1.14 gdamore 728:
1.25 plunky 729: DPRINTFN(1, "sc=%p, act=%d\n", sc, act);
1.14 gdamore 730:
731: switch (act) {
732: case DVACT_DEACTIVATE:
733: sc->sc_dying = 1;
1.38 dyoung 734: return 0;
1.25 plunky 735: default:
1.38 dyoung 736: return EOPNOTSUPP;
1.14 gdamore 737: }
738: }
739:
740: /* set ISOC configuration */
741: static int
742: ubt_set_isoc_config(struct ubt_softc *sc)
743: {
744: usb_endpoint_descriptor_t *ed;
745: int rd_addr, wr_addr, rd_size, wr_size;
746: uint8_t count, i;
747: int err;
748:
749: err = usbd_set_interface(sc->sc_iface1, sc->sc_config);
1.17 plunky 750: if (err != USBD_NORMAL_COMPLETION) {
1.54 skrll 751: aprint_error_dev(sc->sc_dev,
1.32 cube 752: "Could not set config %d on ISOC interface. %s (%d)\n",
753: sc->sc_config, usbd_errstr(err), err);
1.14 gdamore 754:
1.17 plunky 755: return err == USBD_IN_USE ? EBUSY : EIO;
1.14 gdamore 756: }
757:
758: /*
759: * We wont get past the above if there are any pipes open, so no
760: * need to worry about buf/xfer/pipe deallocation. If we get an
761: * error after this, the frame quantities will be 0 and no SCO
762: * data will be possible.
763: */
764:
765: sc->sc_scord_size = rd_size = 0;
766: sc->sc_scord_addr = rd_addr = -1;
767:
768: sc->sc_scowr_size = wr_size = 0;
769: sc->sc_scowr_addr = wr_addr = -1;
770:
771: count = 0;
772: (void)usbd_endpoint_count(sc->sc_iface1, &count);
773:
774: for (i = 0 ; i < count ; i++) {
775: ed = usbd_interface2endpoint_descriptor(sc->sc_iface1, i);
776: if (ed == NULL) {
1.32 cube 777: aprint_error_dev(sc->sc_dev,
778: "could not read endpoint descriptor %d\n", i);
1.14 gdamore 779:
780: return EIO;
781: }
782:
783: DPRINTFN(5, "%s: endpoint type %02x (%02x) addr %02x (%s)\n",
1.39 dyoung 784: device_xname(sc->sc_dev),
1.14 gdamore 785: UE_GET_XFERTYPE(ed->bmAttributes),
786: UE_GET_ISO_TYPE(ed->bmAttributes),
787: ed->bEndpointAddress,
788: UE_GET_DIR(ed->bEndpointAddress) ? "in" : "out");
789:
790: if (UE_GET_XFERTYPE(ed->bmAttributes) != UE_ISOCHRONOUS)
1.3 augustss 791: continue;
1.14 gdamore 792:
793: if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) {
794: rd_addr = ed->bEndpointAddress;
795: rd_size = UGETW(ed->wMaxPacketSize);
796: } else {
797: wr_addr = ed->bEndpointAddress;
798: wr_size = UGETW(ed->wMaxPacketSize);
1.3 augustss 799: }
800: }
801:
1.14 gdamore 802: if (rd_addr == -1) {
1.32 cube 803: aprint_error_dev(sc->sc_dev,
804: "missing ISOC IN endpoint on interface config %d\n",
805: sc->sc_config);
1.14 gdamore 806:
807: return ENOENT;
808: }
809: if (wr_addr == -1) {
1.32 cube 810: aprint_error_dev(sc->sc_dev,
811: "missing ISOC OUT endpoint on interface config %d\n",
812: sc->sc_config);
1.14 gdamore 813:
814: return ENOENT;
815: }
816:
817: if (rd_size > MLEN) {
1.32 cube 818: aprint_error_dev(sc->sc_dev, "rd_size=%d exceeds MLEN\n",
819: rd_size);
1.14 gdamore 820:
821: return EOVERFLOW;
822: }
1.3 augustss 823:
1.14 gdamore 824: if (wr_size > MLEN) {
1.32 cube 825: aprint_error_dev(sc->sc_dev, "wr_size=%d exceeds MLEN\n",
826: wr_size);
1.14 gdamore 827:
828: return EOVERFLOW;
829: }
830:
831: sc->sc_scord_size = rd_size;
832: sc->sc_scord_addr = rd_addr;
833:
834: sc->sc_scowr_size = wr_size;
835: sc->sc_scowr_addr = wr_addr;
836:
837: return 0;
838: }
1.1 augustss 839:
1.14 gdamore 840: /* sysctl helper to set alternate configurations */
841: static int
842: ubt_sysctl_config(SYSCTLFN_ARGS)
843: {
844: struct sysctlnode node;
845: struct ubt_softc *sc;
846: int t, error;
847:
848: node = *rnode;
849: sc = node.sysctl_data;
850:
851: t = sc->sc_config;
852: node.sysctl_data = &t;
853: error = sysctl_lookup(SYSCTLFN_CALL(&node));
854: if (error || newp == NULL)
855: return error;
1.5 dsainty 856:
1.14 gdamore 857: if (t < 0 || t >= sc->sc_alt_config)
858: return EINVAL;
1.1 augustss 859:
1.18 plunky 860: /* This may not change when the unit is enabled */
1.29 plunky 861: if (sc->sc_enabled)
1.18 plunky 862: return EBUSY;
863:
1.44 plunky 864: KERNEL_LOCK(1, curlwp);
1.14 gdamore 865: sc->sc_config = t;
1.44 plunky 866: error = ubt_set_isoc_config(sc);
867: KERNEL_UNLOCK_ONE(curlwp);
868: return error;
1.1 augustss 869: }
870:
1.5 dsainty 871: static void
872: ubt_abortdealloc(struct ubt_softc *sc)
873: {
1.14 gdamore 874: int i;
875:
876: DPRINTFN(1, "sc=%p\n", sc);
1.5 dsainty 877:
1.14 gdamore 878: /* Abort all pipes */
1.36 plunky 879: usbd_abort_default_pipe(sc->sc_udev);
880:
1.5 dsainty 881: if (sc->sc_evt_pipe != NULL) {
882: usbd_abort_pipe(sc->sc_evt_pipe);
883: }
1.14 gdamore 884:
1.5 dsainty 885: if (sc->sc_aclrd_pipe != NULL) {
886: usbd_abort_pipe(sc->sc_aclrd_pipe);
887: }
1.14 gdamore 888:
1.5 dsainty 889: if (sc->sc_aclwr_pipe != NULL) {
890: usbd_abort_pipe(sc->sc_aclwr_pipe);
891: }
1.14 gdamore 892:
893: if (sc->sc_scord_pipe != NULL) {
894: usbd_abort_pipe(sc->sc_scord_pipe);
895: }
896:
897: if (sc->sc_scowr_pipe != NULL) {
898: usbd_abort_pipe(sc->sc_scowr_pipe);
899: }
900:
901: /* Free event buffer */
902: if (sc->sc_evt_buf != NULL) {
1.54 skrll 903: kmem_free(sc->sc_evt_buf, UBT_BUFSIZ_EVENT);
1.14 gdamore 904: sc->sc_evt_buf = NULL;
905: }
906:
907: /* Free all xfers and xfer buffers (implicit) */
908: if (sc->sc_cmd_xfer != NULL) {
1.54 skrll 909: usbd_destroy_xfer(sc->sc_cmd_xfer);
1.14 gdamore 910: sc->sc_cmd_xfer = NULL;
911: sc->sc_cmd_buf = NULL;
912: }
913:
1.5 dsainty 914: if (sc->sc_aclrd_xfer != NULL) {
1.54 skrll 915: usbd_destroy_xfer(sc->sc_aclrd_xfer);
1.5 dsainty 916: sc->sc_aclrd_xfer = NULL;
917: sc->sc_aclrd_buf = NULL;
918: }
1.14 gdamore 919:
1.5 dsainty 920: if (sc->sc_aclwr_xfer != NULL) {
1.54 skrll 921: usbd_destroy_xfer(sc->sc_aclwr_xfer);
1.5 dsainty 922: sc->sc_aclwr_xfer = NULL;
923: sc->sc_aclwr_buf = NULL;
924: }
925:
1.14 gdamore 926: for (i = 0 ; i < UBT_NXFERS ; i++) {
927: if (sc->sc_scord[i].xfer != NULL) {
1.54 skrll 928: usbd_destroy_xfer(sc->sc_scord[i].xfer);
1.14 gdamore 929: sc->sc_scord[i].xfer = NULL;
930: sc->sc_scord[i].buf = NULL;
931: }
1.1 augustss 932:
1.14 gdamore 933: if (sc->sc_scowr[i].xfer != NULL) {
1.54 skrll 934: usbd_destroy_xfer(sc->sc_scowr[i].xfer);
1.14 gdamore 935: sc->sc_scowr[i].xfer = NULL;
936: sc->sc_scowr[i].buf = NULL;
937: }
1.1 augustss 938: }
939:
1.54 skrll 940: if (sc->sc_evt_pipe != NULL) {
941: usbd_close_pipe(sc->sc_evt_pipe);
942: sc->sc_evt_pipe = NULL;
943: }
944:
945: if (sc->sc_aclrd_pipe != NULL) {
946: usbd_close_pipe(sc->sc_aclrd_pipe);
947: sc->sc_aclrd_pipe = NULL;
948: }
949:
950: if (sc->sc_aclwr_pipe != NULL) {
951: usbd_close_pipe(sc->sc_aclwr_pipe);
952: sc->sc_aclwr_pipe = NULL;
953: }
954:
955: if (sc->sc_scord_pipe != NULL) {
956: usbd_close_pipe(sc->sc_scord_pipe);
957: sc->sc_scord_pipe = NULL;
958: }
959:
960: if (sc->sc_scowr_pipe != NULL) {
961: usbd_close_pipe(sc->sc_scowr_pipe);
962: sc->sc_scowr_pipe = NULL;
963: }
964:
1.14 gdamore 965: /* Free partial SCO packets */
966: if (sc->sc_scord_mbuf != NULL) {
967: m_freem(sc->sc_scord_mbuf);
968: sc->sc_scord_mbuf = NULL;
1.1 augustss 969: }
970:
1.14 gdamore 971: if (sc->sc_scowr_mbuf != NULL) {
972: m_freem(sc->sc_scowr_mbuf);
973: sc->sc_scowr_mbuf = NULL;
1.1 augustss 974: }
1.29 plunky 975:
976: /* Empty mbuf queues */
977: MBUFQ_DRAIN(&sc->sc_cmd_queue);
978: MBUFQ_DRAIN(&sc->sc_aclwr_queue);
979: MBUFQ_DRAIN(&sc->sc_scowr_queue);
1.5 dsainty 980: }
981:
1.14 gdamore 982: /*******************************************************************************
983: *
984: * Bluetooth Unit/USB callbacks
985: *
986: */
1.5 dsainty 987: static int
1.39 dyoung 988: ubt_enable(device_t self)
1.5 dsainty 989: {
1.39 dyoung 990: struct ubt_softc *sc = device_private(self);
1.5 dsainty 991: usbd_status err;
1.29 plunky 992: int s, i, error;
1.5 dsainty 993:
1.14 gdamore 994: DPRINTFN(1, "sc=%p\n", sc);
1.5 dsainty 995:
1.29 plunky 996: if (sc->sc_enabled)
1.14 gdamore 997: return 0;
998:
1.29 plunky 999: s = splusb();
1000:
1.14 gdamore 1001: /* Events */
1.54 skrll 1002: sc->sc_evt_buf = kmem_alloc(UBT_BUFSIZ_EVENT, KM_SLEEP);
1.14 gdamore 1003: err = usbd_open_pipe_intr(sc->sc_iface0,
1004: sc->sc_evt_addr,
1005: USBD_SHORT_XFER_OK,
1006: &sc->sc_evt_pipe,
1007: sc,
1008: sc->sc_evt_buf,
1009: UBT_BUFSIZ_EVENT,
1010: ubt_recv_event,
1.21 drochner 1011: USBD_DEFAULT_INTERVAL);
1.5 dsainty 1012: if (err != USBD_NORMAL_COMPLETION) {
1013: error = EIO;
1.14 gdamore 1014: goto bad;
1.5 dsainty 1015: }
1016:
1.14 gdamore 1017: /* Commands */
1.54 skrll 1018: struct usbd_pipe *pipe0 = usbd_get_pipe0(sc->sc_udev);
1.60 skrll 1019: error = usbd_create_xfer(pipe0, UBT_BUFSIZ_CMD, USBD_FORCE_SHORT_XFER,
1020: 0, &sc->sc_cmd_xfer);
1.54 skrll 1021: if (error)
1.14 gdamore 1022: goto bad;
1.54 skrll 1023: sc->sc_cmd_buf = usbd_get_buffer(sc->sc_cmd_xfer);
1.29 plunky 1024: sc->sc_cmd_busy = 0;
1.5 dsainty 1025:
1.14 gdamore 1026: /* ACL read */
1027: err = usbd_open_pipe(sc->sc_iface0, sc->sc_aclrd_addr,
1028: USBD_EXCLUSIVE_USE, &sc->sc_aclrd_pipe);
1.5 dsainty 1029: if (err != USBD_NORMAL_COMPLETION) {
1030: error = EIO;
1.14 gdamore 1031: goto bad;
1.5 dsainty 1032: }
1.54 skrll 1033: error = usbd_create_xfer(sc->sc_aclrd_pipe, UBT_BUFSIZ_ACL,
1.60 skrll 1034: 0, 0, &sc->sc_aclrd_xfer);
1.54 skrll 1035: if (error)
1.14 gdamore 1036: goto bad;
1.54 skrll 1037: sc->sc_aclrd_buf = usbd_get_buffer(sc->sc_aclrd_xfer);
1.14 gdamore 1038: sc->sc_aclrd_busy = 0;
1039: ubt_recv_acl_start(sc);
1.5 dsainty 1040:
1.14 gdamore 1041: /* ACL write */
1042: err = usbd_open_pipe(sc->sc_iface0, sc->sc_aclwr_addr,
1043: USBD_EXCLUSIVE_USE, &sc->sc_aclwr_pipe);
1044: if (err != USBD_NORMAL_COMPLETION) {
1045: error = EIO;
1046: goto bad;
1.5 dsainty 1047: }
1.54 skrll 1048: error = usbd_create_xfer(sc->sc_aclwr_pipe, UBT_BUFSIZ_ACL,
1049: USBD_FORCE_SHORT_XFER, 0, &sc->sc_aclwr_xfer);
1050: if (error)
1.14 gdamore 1051: goto bad;
1.54 skrll 1052: sc->sc_aclwr_buf = usbd_get_buffer(sc->sc_aclwr_xfer);
1.29 plunky 1053: sc->sc_aclwr_busy = 0;
1.14 gdamore 1054:
1055: /* SCO read */
1056: if (sc->sc_scord_size > 0) {
1057: err = usbd_open_pipe(sc->sc_iface1, sc->sc_scord_addr,
1058: USBD_EXCLUSIVE_USE, &sc->sc_scord_pipe);
1059: if (err != USBD_NORMAL_COMPLETION) {
1060: error = EIO;
1061: goto bad;
1062: }
1063:
1064: for (i = 0 ; i < UBT_NXFERS ; i++) {
1.54 skrll 1065: error = usbd_create_xfer(sc->sc_scord_pipe,
1066: sc->sc_scord_size * UBT_NFRAMES,
1.60 skrll 1067: 0, UBT_NFRAMES,
1.54 skrll 1068: &sc->sc_scord[i].xfer);
1069: if (error)
1.14 gdamore 1070: goto bad;
1.54 skrll 1071:
1072: sc->sc_scord[i].buf =
1073: usbd_get_buffer(sc->sc_scord[i].xfer);
1.14 gdamore 1074: sc->sc_scord[i].softc = sc;
1075: sc->sc_scord[i].busy = 0;
1076: ubt_recv_sco_start1(sc, &sc->sc_scord[i]);
1077: }
1.5 dsainty 1078: }
1079:
1.14 gdamore 1080: /* SCO write */
1081: if (sc->sc_scowr_size > 0) {
1082: err = usbd_open_pipe(sc->sc_iface1, sc->sc_scowr_addr,
1083: USBD_EXCLUSIVE_USE, &sc->sc_scowr_pipe);
1084: if (err != USBD_NORMAL_COMPLETION) {
1085: error = EIO;
1086: goto bad;
1087: }
1088:
1089: for (i = 0 ; i < UBT_NXFERS ; i++) {
1.54 skrll 1090: error = usbd_create_xfer(sc->sc_scowr_pipe,
1091: sc->sc_scowr_size * UBT_NFRAMES,
1092: USBD_FORCE_SHORT_XFER, UBT_NFRAMES,
1093: &sc->sc_scowr[i].xfer);
1094: if (error)
1.14 gdamore 1095: goto bad;
1.54 skrll 1096: sc->sc_scowr[i].buf =
1097: usbd_get_buffer(sc->sc_scowr[i].xfer);
1.14 gdamore 1098: sc->sc_scowr[i].softc = sc;
1099: sc->sc_scowr[i].busy = 0;
1100: }
1.29 plunky 1101:
1102: sc->sc_scowr_busy = 0;
1.14 gdamore 1103: }
1.5 dsainty 1104:
1.29 plunky 1105: sc->sc_enabled = 1;
1106: splx(s);
1.5 dsainty 1107: return 0;
1108:
1.14 gdamore 1109: bad:
1110: ubt_abortdealloc(sc);
1.29 plunky 1111: splx(s);
1.5 dsainty 1112: return error;
1113: }
1114:
1.14 gdamore 1115: static void
1.39 dyoung 1116: ubt_disable(device_t self)
1.5 dsainty 1117: {
1.39 dyoung 1118: struct ubt_softc *sc = device_private(self);
1.29 plunky 1119: int s;
1.14 gdamore 1120:
1121: DPRINTFN(1, "sc=%p\n", sc);
1.5 dsainty 1122:
1.29 plunky 1123: if (sc->sc_enabled == 0)
1.14 gdamore 1124: return;
1.5 dsainty 1125:
1.29 plunky 1126: s = splusb();
1.5 dsainty 1127: ubt_abortdealloc(sc);
1128:
1.29 plunky 1129: sc->sc_enabled = 0;
1130: splx(s);
1.5 dsainty 1131: }
1132:
1.14 gdamore 1133: static void
1.39 dyoung 1134: ubt_xmit_cmd(device_t self, struct mbuf *m)
1.5 dsainty 1135: {
1.39 dyoung 1136: struct ubt_softc *sc = device_private(self);
1.29 plunky 1137: int s;
1138:
1139: KASSERT(sc->sc_enabled);
1140:
1141: s = splusb();
1142: MBUFQ_ENQUEUE(&sc->sc_cmd_queue, m);
1143:
1144: if (sc->sc_cmd_busy == 0)
1145: ubt_xmit_cmd_start(sc);
1146:
1147: splx(s);
1148: }
1149:
1150: static void
1151: ubt_xmit_cmd_start(struct ubt_softc *sc)
1152: {
1.5 dsainty 1153: usb_device_request_t req;
1154: usbd_status status;
1.14 gdamore 1155: struct mbuf *m;
1156: int len;
1.5 dsainty 1157:
1.14 gdamore 1158: if (sc->sc_dying)
1159: return;
1.5 dsainty 1160:
1.29 plunky 1161: if (MBUFQ_FIRST(&sc->sc_cmd_queue) == NULL)
1.14 gdamore 1162: return;
1.6 dsainty 1163:
1.29 plunky 1164: MBUFQ_DEQUEUE(&sc->sc_cmd_queue, m);
1.14 gdamore 1165: KASSERT(m != NULL);
1.5 dsainty 1166:
1.14 gdamore 1167: DPRINTFN(15, "%s: xmit CMD packet (%d bytes)\n",
1.39 dyoung 1168: device_xname(sc->sc_dev), m->m_pkthdr.len);
1.5 dsainty 1169:
1170: sc->sc_refcnt++;
1.29 plunky 1171: sc->sc_cmd_busy = 1;
1.14 gdamore 1172:
1173: len = m->m_pkthdr.len - 1;
1174: m_copydata(m, 1, len, sc->sc_cmd_buf);
1175: m_freem(m);
1.5 dsainty 1176:
1177: memset(&req, 0, sizeof(req));
1178: req.bmRequestType = UT_WRITE_CLASS_DEVICE;
1179: USETW(req.wLength, len);
1180:
1.14 gdamore 1181: usbd_setup_default_xfer(sc->sc_cmd_xfer,
1.5 dsainty 1182: sc->sc_udev,
1.27 plunky 1183: sc,
1.14 gdamore 1184: UBT_CMD_TIMEOUT,
1185: &req,
1186: sc->sc_cmd_buf,
1187: len,
1.54 skrll 1188: USBD_FORCE_SHORT_XFER,
1.14 gdamore 1189: ubt_xmit_cmd_complete);
1190:
1191: status = usbd_transfer(sc->sc_cmd_xfer);
1192:
1193: KASSERT(status != USBD_NORMAL_COMPLETION);
1194:
1195: if (status != USBD_IN_PROGRESS) {
1196: DPRINTF("usbd_transfer status=%s (%d)\n",
1197: usbd_errstr(status), status);
1198:
1199: sc->sc_refcnt--;
1.29 plunky 1200: sc->sc_cmd_busy = 0;
1.14 gdamore 1201: }
1202: }
1203:
1204: static void
1.54 skrll 1205: ubt_xmit_cmd_complete(struct usbd_xfer *xfer,
1206: void * h, usbd_status status)
1.14 gdamore 1207: {
1.27 plunky 1208: struct ubt_softc *sc = h;
1.14 gdamore 1209: uint32_t count;
1.5 dsainty 1210:
1.14 gdamore 1211: DPRINTFN(15, "%s: CMD complete status=%s (%d)\n",
1.39 dyoung 1212: device_xname(sc->sc_dev), usbd_errstr(status), status);
1.5 dsainty 1213:
1.29 plunky 1214: sc->sc_cmd_busy = 0;
1.14 gdamore 1215:
1216: if (--sc->sc_refcnt < 0) {
1217: DPRINTF("sc_refcnt=%d\n", sc->sc_refcnt);
1.45 mrg 1218: usb_detach_wakeupold(sc->sc_dev);
1.14 gdamore 1219: return;
1220: }
1.5 dsainty 1221:
1.14 gdamore 1222: if (sc->sc_dying) {
1223: DPRINTF("sc_dying\n");
1224: return;
1225: }
1.5 dsainty 1226:
1.14 gdamore 1227: if (status != USBD_NORMAL_COMPLETION) {
1228: DPRINTF("status=%s (%d)\n",
1229: usbd_errstr(status), status);
1.5 dsainty 1230:
1.29 plunky 1231: sc->sc_stats.err_tx++;
1.14 gdamore 1232: return;
1233: }
1.6 dsainty 1234:
1.14 gdamore 1235: usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
1.29 plunky 1236: sc->sc_stats.cmd_tx++;
1237: sc->sc_stats.byte_tx += count;
1.6 dsainty 1238:
1.29 plunky 1239: ubt_xmit_cmd_start(sc);
1.6 dsainty 1240: }
1241:
1.14 gdamore 1242: static void
1.39 dyoung 1243: ubt_xmit_acl(device_t self, struct mbuf *m)
1.5 dsainty 1244: {
1.39 dyoung 1245: struct ubt_softc *sc = device_private(self);
1.29 plunky 1246: int s;
1247:
1248: KASSERT(sc->sc_enabled);
1249:
1250: s = splusb();
1251: MBUFQ_ENQUEUE(&sc->sc_aclwr_queue, m);
1252:
1253: if (sc->sc_aclwr_busy == 0)
1254: ubt_xmit_acl_start(sc);
1255:
1256: splx(s);
1257: }
1258:
1259: static void
1260: ubt_xmit_acl_start(struct ubt_softc *sc)
1261: {
1.14 gdamore 1262: struct mbuf *m;
1.5 dsainty 1263: usbd_status status;
1.14 gdamore 1264: int len;
1265:
1266: if (sc->sc_dying)
1267: return;
1268:
1.29 plunky 1269: if (MBUFQ_FIRST(&sc->sc_aclwr_queue) == NULL)
1.14 gdamore 1270: return;
1.5 dsainty 1271:
1.14 gdamore 1272: sc->sc_refcnt++;
1.29 plunky 1273: sc->sc_aclwr_busy = 1;
1.14 gdamore 1274:
1.29 plunky 1275: MBUFQ_DEQUEUE(&sc->sc_aclwr_queue, m);
1.14 gdamore 1276: KASSERT(m != NULL);
1.5 dsainty 1277:
1.14 gdamore 1278: DPRINTFN(15, "%s: xmit ACL packet (%d bytes)\n",
1.39 dyoung 1279: device_xname(sc->sc_dev), m->m_pkthdr.len);
1.14 gdamore 1280:
1281: len = m->m_pkthdr.len - 1;
1282: if (len > UBT_BUFSIZ_ACL) {
1283: DPRINTF("%s: truncating ACL packet (%d => %d)!\n",
1.39 dyoung 1284: device_xname(sc->sc_dev), len, UBT_BUFSIZ_ACL);
1.6 dsainty 1285:
1.14 gdamore 1286: len = UBT_BUFSIZ_ACL;
1287: }
1.5 dsainty 1288:
1.14 gdamore 1289: m_copydata(m, 1, len, sc->sc_aclwr_buf);
1290: m_freem(m);
1.5 dsainty 1291:
1.29 plunky 1292: sc->sc_stats.acl_tx++;
1293: sc->sc_stats.byte_tx += len;
1.5 dsainty 1294:
1295: usbd_setup_xfer(sc->sc_aclwr_xfer,
1.27 plunky 1296: sc,
1.14 gdamore 1297: sc->sc_aclwr_buf,
1298: len,
1.54 skrll 1299: USBD_FORCE_SHORT_XFER,
1.14 gdamore 1300: UBT_ACL_TIMEOUT,
1301: ubt_xmit_acl_complete);
1.5 dsainty 1302:
1303: status = usbd_transfer(sc->sc_aclwr_xfer);
1304:
1.14 gdamore 1305: KASSERT(status != USBD_NORMAL_COMPLETION);
1306:
1307: if (status != USBD_IN_PROGRESS) {
1308: DPRINTF("usbd_transfer status=%s (%d)\n",
1309: usbd_errstr(status), status);
1310:
1311: sc->sc_refcnt--;
1.29 plunky 1312: sc->sc_aclwr_busy = 0;
1.14 gdamore 1313: }
1314: }
1315:
1316: static void
1.54 skrll 1317: ubt_xmit_acl_complete(struct usbd_xfer *xfer,
1318: void * h, usbd_status status)
1.14 gdamore 1319: {
1.27 plunky 1320: struct ubt_softc *sc = h;
1.14 gdamore 1321:
1322: DPRINTFN(15, "%s: ACL complete status=%s (%d)\n",
1.39 dyoung 1323: device_xname(sc->sc_dev), usbd_errstr(status), status);
1.14 gdamore 1324:
1.29 plunky 1325: sc->sc_aclwr_busy = 0;
1.14 gdamore 1326:
1327: if (--sc->sc_refcnt < 0) {
1.45 mrg 1328: usb_detach_wakeupold(sc->sc_dev);
1.14 gdamore 1329: return;
1330: }
1.5 dsainty 1331:
1.14 gdamore 1332: if (sc->sc_dying)
1333: return;
1.5 dsainty 1334:
1.14 gdamore 1335: if (status != USBD_NORMAL_COMPLETION) {
1336: DPRINTF("status=%s (%d)\n",
1337: usbd_errstr(status), status);
1338:
1.29 plunky 1339: sc->sc_stats.err_tx++;
1.14 gdamore 1340:
1341: if (status == USBD_STALLED)
1342: usbd_clear_endpoint_stall_async(sc->sc_aclwr_pipe);
1343: else
1344: return;
1345: }
1346:
1.29 plunky 1347: ubt_xmit_acl_start(sc);
1.14 gdamore 1348: }
1349:
1350: static void
1.39 dyoung 1351: ubt_xmit_sco(device_t self, struct mbuf *m)
1.14 gdamore 1352: {
1.39 dyoung 1353: struct ubt_softc *sc = device_private(self);
1.29 plunky 1354: int s;
1355:
1356: KASSERT(sc->sc_enabled);
1357:
1358: s = splusb();
1359: MBUFQ_ENQUEUE(&sc->sc_scowr_queue, m);
1360:
1361: if (sc->sc_scowr_busy == 0)
1362: ubt_xmit_sco_start(sc);
1363:
1364: splx(s);
1365: }
1366:
1367: static void
1368: ubt_xmit_sco_start(struct ubt_softc *sc)
1369: {
1.14 gdamore 1370: int i;
1371:
1372: if (sc->sc_dying || sc->sc_scowr_size == 0)
1373: return;
1374:
1375: for (i = 0 ; i < UBT_NXFERS ; i++) {
1376: if (sc->sc_scowr[i].busy)
1377: continue;
1378:
1379: ubt_xmit_sco_start1(sc, &sc->sc_scowr[i]);
1380: }
1.5 dsainty 1381: }
1382:
1.14 gdamore 1383: static void
1384: ubt_xmit_sco_start1(struct ubt_softc *sc, struct ubt_isoc_xfer *isoc)
1.6 dsainty 1385: {
1.14 gdamore 1386: struct mbuf *m;
1387: uint8_t *buf;
1388: int num, len, size, space;
1389:
1390: space = sc->sc_scowr_size * UBT_NFRAMES;
1391: buf = isoc->buf;
1392: len = 0;
1393:
1394: /*
1395: * Fill the request buffer with data from the queue,
1396: * keeping any leftover packet on our private hook.
1397: *
1398: * Complete packets are passed back up to the stack
1399: * for disposal, since we can't rely on the controller
1400: * to tell us when it has finished with them.
1401: */
1402:
1403: m = sc->sc_scowr_mbuf;
1404: while (space > 0) {
1405: if (m == NULL) {
1.29 plunky 1406: MBUFQ_DEQUEUE(&sc->sc_scowr_queue, m);
1.14 gdamore 1407: if (m == NULL)
1408: break;
1409:
1410: m_adj(m, 1); /* packet type */
1411: }
1412:
1413: if (m->m_pkthdr.len > 0) {
1414: size = MIN(m->m_pkthdr.len, space);
1415:
1416: m_copydata(m, 0, size, buf);
1417: m_adj(m, size);
1418:
1419: buf += size;
1420: len += size;
1421: space -= size;
1422: }
1423:
1424: if (m->m_pkthdr.len == 0) {
1.29 plunky 1425: sc->sc_stats.sco_tx++;
1426: if (!hci_complete_sco(sc->sc_unit, m))
1427: sc->sc_stats.err_tx++;
1428:
1.14 gdamore 1429: m = NULL;
1430: }
1431: }
1432: sc->sc_scowr_mbuf = m;
1433:
1434: DPRINTFN(15, "isoc=%p, len=%d, space=%d\n", isoc, len, space);
1435:
1436: if (len == 0) /* nothing to send */
1437: return;
1438:
1439: sc->sc_refcnt++;
1.29 plunky 1440: sc->sc_scowr_busy = 1;
1441: sc->sc_stats.byte_tx += len;
1.14 gdamore 1442: isoc->busy = 1;
1443:
1444: /*
1445: * calculate number of isoc frames and sizes
1446: */
1447:
1448: for (num = 0 ; len > 0 ; num++) {
1449: size = MIN(sc->sc_scowr_size, len);
1450:
1451: isoc->size[num] = size;
1452: len -= size;
1453: }
1454:
1455: usbd_setup_isoc_xfer(isoc->xfer,
1456: isoc,
1457: isoc->size,
1458: num,
1.54 skrll 1459: USBD_FORCE_SHORT_XFER,
1.14 gdamore 1460: ubt_xmit_sco_complete);
1461:
1462: usbd_transfer(isoc->xfer);
1.6 dsainty 1463: }
1464:
1.14 gdamore 1465: static void
1.54 skrll 1466: ubt_xmit_sco_complete(struct usbd_xfer *xfer,
1467: void * h, usbd_status status)
1.5 dsainty 1468: {
1.14 gdamore 1469: struct ubt_isoc_xfer *isoc = h;
1470: struct ubt_softc *sc;
1471: int i;
1472:
1473: KASSERT(xfer == isoc->xfer);
1474: sc = isoc->softc;
1475:
1476: DPRINTFN(15, "isoc=%p, status=%s (%d)\n",
1477: isoc, usbd_errstr(status), status);
1478:
1479: isoc->busy = 0;
1480:
1481: for (i = 0 ; ; i++) {
1482: if (i == UBT_NXFERS) {
1.29 plunky 1483: sc->sc_scowr_busy = 0;
1.14 gdamore 1484: break;
1485: }
1.5 dsainty 1486:
1.14 gdamore 1487: if (sc->sc_scowr[i].busy)
1488: break;
1489: }
1490:
1491: if (--sc->sc_refcnt < 0) {
1.45 mrg 1492: usb_detach_wakeupold(sc->sc_dev);
1.14 gdamore 1493: return;
1494: }
1.5 dsainty 1495:
1496: if (sc->sc_dying)
1.14 gdamore 1497: return;
1.5 dsainty 1498:
1.14 gdamore 1499: if (status != USBD_NORMAL_COMPLETION) {
1500: DPRINTF("status=%s (%d)\n",
1501: usbd_errstr(status), status);
1502:
1.29 plunky 1503: sc->sc_stats.err_tx++;
1.14 gdamore 1504:
1505: if (status == USBD_STALLED)
1506: usbd_clear_endpoint_stall_async(sc->sc_scowr_pipe);
1507: else
1508: return;
1509: }
1510:
1.29 plunky 1511: ubt_xmit_sco_start(sc);
1.14 gdamore 1512: }
1513:
1514: /*
1515: * load incoming data into an mbuf with
1516: * leading type byte
1517: */
1518: static struct mbuf *
1519: ubt_mbufload(uint8_t *buf, int count, uint8_t type)
1520: {
1521: struct mbuf *m;
1522:
1523: MGETHDR(m, M_DONTWAIT, MT_DATA);
1524: if (m == NULL)
1525: return NULL;
1526:
1527: *mtod(m, uint8_t *) = type;
1528: m->m_pkthdr.len = m->m_len = MHLEN;
1529: m_copyback(m, 1, count, buf); // (extends if necessary)
1530: if (m->m_pkthdr.len != MAX(MHLEN, count + 1)) {
1.61 maxv 1531: m_freem(m);
1.14 gdamore 1532: return NULL;
1533: }
1534:
1535: m->m_pkthdr.len = count + 1;
1536: m->m_len = MIN(MHLEN, m->m_pkthdr.len);
1537:
1538: return m;
1.5 dsainty 1539: }
1540:
1541: static void
1.54 skrll 1542: ubt_recv_event(struct usbd_xfer *xfer, void * h, usbd_status status)
1.5 dsainty 1543: {
1544: struct ubt_softc *sc = h;
1.14 gdamore 1545: struct mbuf *m;
1546: uint32_t count;
1.5 dsainty 1547: void *buf;
1548:
1.14 gdamore 1549: DPRINTFN(15, "sc=%p status=%s (%d)\n",
1550: sc, usbd_errstr(status), status);
1.5 dsainty 1551:
1.14 gdamore 1552: if (status != USBD_NORMAL_COMPLETION || sc->sc_dying)
1.5 dsainty 1553: return;
1554:
1.14 gdamore 1555: usbd_get_xfer_status(xfer, NULL, &buf, &count, NULL);
1556:
1.16 plunky 1557: if (count < sizeof(hci_event_hdr_t) - 1) {
1558: DPRINTF("dumped undersized event (count = %d)\n", count);
1.29 plunky 1559: sc->sc_stats.err_rx++;
1.16 plunky 1560: return;
1561: }
1562:
1.29 plunky 1563: sc->sc_stats.evt_rx++;
1564: sc->sc_stats.byte_rx += count;
1.5 dsainty 1565:
1.14 gdamore 1566: m = ubt_mbufload(buf, count, HCI_EVENT_PKT);
1.29 plunky 1567: if (m == NULL || !hci_input_event(sc->sc_unit, m))
1568: sc->sc_stats.err_rx++;
1.5 dsainty 1569: }
1570:
1571: static void
1.14 gdamore 1572: ubt_recv_acl_start(struct ubt_softc *sc)
1.5 dsainty 1573: {
1574: usbd_status status;
1575:
1.14 gdamore 1576: DPRINTFN(15, "sc=%p\n", sc);
1.5 dsainty 1577:
1.14 gdamore 1578: if (sc->sc_aclrd_busy || sc->sc_dying) {
1579: DPRINTF("sc_aclrd_busy=%d, sc_dying=%d\n",
1580: sc->sc_aclrd_busy,
1581: sc->sc_dying);
1.5 dsainty 1582:
1583: return;
1584: }
1.6 dsainty 1585:
1.14 gdamore 1586: sc->sc_refcnt++;
1587: sc->sc_aclrd_busy = 1;
1588:
1589: usbd_setup_xfer(sc->sc_aclrd_xfer,
1590: sc,
1591: sc->sc_aclrd_buf,
1592: UBT_BUFSIZ_ACL,
1.54 skrll 1593: USBD_SHORT_XFER_OK,
1.14 gdamore 1594: USBD_NO_TIMEOUT,
1595: ubt_recv_acl_complete);
1.5 dsainty 1596:
1597: status = usbd_transfer(sc->sc_aclrd_xfer);
1.9 dsainty 1598:
1.14 gdamore 1599: KASSERT(status != USBD_NORMAL_COMPLETION);
1.5 dsainty 1600:
1.14 gdamore 1601: if (status != USBD_IN_PROGRESS) {
1602: DPRINTF("usbd_transfer status=%s (%d)\n",
1603: usbd_errstr(status), status);
1.5 dsainty 1604:
1.14 gdamore 1605: sc->sc_refcnt--;
1606: sc->sc_aclrd_busy = 0;
1607: }
1.5 dsainty 1608: }
1609:
1610: static void
1.54 skrll 1611: ubt_recv_acl_complete(struct usbd_xfer *xfer,
1612: void * h, usbd_status status)
1.5 dsainty 1613: {
1614: struct ubt_softc *sc = h;
1.14 gdamore 1615: struct mbuf *m;
1616: uint32_t count;
1.5 dsainty 1617: void *buf;
1618:
1.14 gdamore 1619: DPRINTFN(15, "sc=%p status=%s (%d)\n",
1620: sc, usbd_errstr(status), status);
1621:
1622: sc->sc_aclrd_busy = 0;
1623:
1624: if (--sc->sc_refcnt < 0) {
1625: DPRINTF("refcnt = %d\n", sc->sc_refcnt);
1.45 mrg 1626: usb_detach_wakeupold(sc->sc_dev);
1.14 gdamore 1627: return;
1628: }
1629:
1630: if (sc->sc_dying) {
1631: DPRINTF("sc_dying\n");
1632: return;
1633: }
1634:
1635: if (status != USBD_NORMAL_COMPLETION) {
1636: DPRINTF("status=%s (%d)\n",
1637: usbd_errstr(status), status);
1638:
1.29 plunky 1639: sc->sc_stats.err_rx++;
1.14 gdamore 1640:
1641: if (status == USBD_STALLED)
1642: usbd_clear_endpoint_stall_async(sc->sc_aclrd_pipe);
1643: else
1644: return;
1645: } else {
1646: usbd_get_xfer_status(xfer, NULL, &buf, &count, NULL);
1647:
1.16 plunky 1648: if (count < sizeof(hci_acldata_hdr_t) - 1) {
1649: DPRINTF("dumped undersized packet (%d)\n", count);
1.29 plunky 1650: sc->sc_stats.err_rx++;
1.16 plunky 1651: } else {
1.29 plunky 1652: sc->sc_stats.acl_rx++;
1653: sc->sc_stats.byte_rx += count;
1.14 gdamore 1654:
1.16 plunky 1655: m = ubt_mbufload(buf, count, HCI_ACL_DATA_PKT);
1.29 plunky 1656: if (m == NULL || !hci_input_acl(sc->sc_unit, m))
1657: sc->sc_stats.err_rx++;
1.16 plunky 1658: }
1.14 gdamore 1659: }
1.5 dsainty 1660:
1.14 gdamore 1661: /* and restart */
1662: ubt_recv_acl_start(sc);
1663: }
1664:
1665: static void
1666: ubt_recv_sco_start1(struct ubt_softc *sc, struct ubt_isoc_xfer *isoc)
1667: {
1668: int i;
1669:
1670: DPRINTFN(15, "sc=%p, isoc=%p\n", sc, isoc);
1671:
1672: if (isoc->busy || sc->sc_dying || sc->sc_scord_size == 0) {
1673: DPRINTF("%s%s%s\n",
1674: isoc->busy ? " busy" : "",
1675: sc->sc_dying ? " dying" : "",
1676: sc->sc_scord_size == 0 ? " size=0" : "");
1.5 dsainty 1677:
1678: return;
1.14 gdamore 1679: }
1680:
1681: sc->sc_refcnt++;
1682: isoc->busy = 1;
1.5 dsainty 1683:
1.14 gdamore 1684: for (i = 0 ; i < UBT_NFRAMES ; i++)
1685: isoc->size[i] = sc->sc_scord_size;
1.5 dsainty 1686:
1.14 gdamore 1687: usbd_setup_isoc_xfer(isoc->xfer,
1688: isoc,
1689: isoc->size,
1690: UBT_NFRAMES,
1.54 skrll 1691: USBD_SHORT_XFER_OK,
1.14 gdamore 1692: ubt_recv_sco_complete);
1.5 dsainty 1693:
1.14 gdamore 1694: usbd_transfer(isoc->xfer);
1.5 dsainty 1695: }
1696:
1.14 gdamore 1697: static void
1.54 skrll 1698: ubt_recv_sco_complete(struct usbd_xfer *xfer,
1699: void * h, usbd_status status)
1.5 dsainty 1700: {
1.14 gdamore 1701: struct ubt_isoc_xfer *isoc = h;
1702: struct ubt_softc *sc;
1703: struct mbuf *m;
1704: uint32_t count;
1705: uint8_t *ptr, *frame;
1706: int i, size, got, want;
1707:
1708: KASSERT(isoc != NULL);
1709: KASSERT(isoc->xfer == xfer);
1710:
1711: sc = isoc->softc;
1712: isoc->busy = 0;
1713:
1714: if (--sc->sc_refcnt < 0) {
1715: DPRINTF("refcnt=%d\n", sc->sc_refcnt);
1.45 mrg 1716: usb_detach_wakeupold(sc->sc_dev);
1.14 gdamore 1717: return;
1718: }
1719:
1720: if (sc->sc_dying) {
1721: DPRINTF("sc_dying\n");
1722: return;
1723: }
1724:
1725: if (status != USBD_NORMAL_COMPLETION) {
1726: DPRINTF("status=%s (%d)\n",
1727: usbd_errstr(status), status);
1728:
1.29 plunky 1729: sc->sc_stats.err_rx++;
1.14 gdamore 1730:
1731: if (status == USBD_STALLED) {
1732: usbd_clear_endpoint_stall_async(sc->sc_scord_pipe);
1733: goto restart;
1734: }
1735:
1736: return;
1737: }
1738:
1739: usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
1740: if (count == 0)
1741: goto restart;
1742:
1743: DPRINTFN(15, "sc=%p, isoc=%p, count=%u\n",
1744: sc, isoc, count);
1745:
1.29 plunky 1746: sc->sc_stats.byte_rx += count;
1.14 gdamore 1747:
1748: /*
1749: * Extract SCO packets from ISOC frames. The way we have it,
1750: * no SCO packet can be bigger than MHLEN. This is unlikely
1751: * to actually happen, but if we ran out of mbufs and lost
1752: * sync then we may get spurious data that makes it seem that
1753: * way, so we discard data that wont fit. This doesnt really
1754: * help with the lost sync situation alas.
1755: */
1756:
1757: m = sc->sc_scord_mbuf;
1758: if (m != NULL) {
1759: sc->sc_scord_mbuf = NULL;
1760: ptr = mtod(m, uint8_t *) + m->m_pkthdr.len;
1761: got = m->m_pkthdr.len;
1762: want = sizeof(hci_scodata_hdr_t);
1763: if (got >= want)
1764: want += mtod(m, hci_scodata_hdr_t *)->length ;
1765: } else {
1766: ptr = NULL;
1767: got = 0;
1768: want = 0;
1769: }
1770:
1771: for (i = 0 ; i < UBT_NFRAMES ; i++) {
1772: frame = isoc->buf + (i * sc->sc_scord_size);
1773:
1774: while (isoc->size[i] > 0) {
1775: size = isoc->size[i];
1776:
1777: if (m == NULL) {
1778: MGETHDR(m, M_DONTWAIT, MT_DATA);
1779: if (m == NULL) {
1.32 cube 1780: aprint_error_dev(sc->sc_dev,
1781: "out of memory (xfer halted)\n");
1.14 gdamore 1782:
1.29 plunky 1783: sc->sc_stats.err_rx++;
1.14 gdamore 1784: return; /* lost sync */
1785: }
1786:
1787: ptr = mtod(m, uint8_t *);
1788: *ptr++ = HCI_SCO_DATA_PKT;
1789: got = 1;
1790: want = sizeof(hci_scodata_hdr_t);
1791: }
1792:
1793: if (got + size > want)
1794: size = want - got;
1795:
1.47 christos 1796: memcpy(ptr, frame, size);
1.14 gdamore 1797:
1798: ptr += size;
1799: got += size;
1800: frame += size;
1801:
1802: if (got == want) {
1803: /*
1804: * If we only got a header, add the packet
1805: * length to our want count. Send complete
1806: * packets up to protocol stack.
1807: */
1.47 christos 1808: if (want == sizeof(hci_scodata_hdr_t)) {
1809: uint32_t len =
1810: mtod(m, hci_scodata_hdr_t *)->length;
1811: want += len;
1812: if (len == 0 || want > MHLEN) {
1813: aprint_error_dev(sc->sc_dev,
1814: "packet too large %u "
1815: "(lost sync)\n", len);
1816: sc->sc_stats.err_rx++;
1817: return;
1818: }
1819: }
1.14 gdamore 1820:
1821: if (got == want) {
1822: m->m_pkthdr.len = m->m_len = got;
1.29 plunky 1823: sc->sc_stats.sco_rx++;
1824: if (!hci_input_sco(sc->sc_unit, m))
1825: sc->sc_stats.err_rx++;
1.54 skrll 1826:
1.14 gdamore 1827: m = NULL;
1828: }
1829: }
1830:
1831: isoc->size[i] -= size;
1832: }
1833: }
1834:
1835: if (m != NULL) {
1836: m->m_pkthdr.len = m->m_len = got;
1837: sc->sc_scord_mbuf = m;
1838: }
1839:
1840: restart: /* and restart */
1841: ubt_recv_sco_start1(sc, isoc);
1.1 augustss 1842: }
1.29 plunky 1843:
1844: void
1.39 dyoung 1845: ubt_stats(device_t self, struct bt_stats *dest, int flush)
1.29 plunky 1846: {
1.39 dyoung 1847: struct ubt_softc *sc = device_private(self);
1.29 plunky 1848: int s;
1849:
1850: s = splusb();
1851: memcpy(dest, &sc->sc_stats, sizeof(struct bt_stats));
1852:
1853: if (flush)
1854: memset(&sc->sc_stats, 0, sizeof(struct bt_stats));
1855:
1856: splx(s);
1857: }
CVSweb <webmaster@jp.NetBSD.org>