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