1 /* 2 * ng_ubt.c 3 */ 4 5 /*- 6 * Copyright (c) 2001-2009 Maksim Yevmenkin <m_evmenkin@yahoo.com> 7 * All rights reserved. 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 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * $Id: ng_ubt.c,v 1.16 2003/10/10 19:15:06 max Exp $ 31 * $FreeBSD$ 32 */ 33 34 /* 35 * NOTE: ng_ubt2 driver has a split personality. On one side it is 36 * a USB device driver and on the other it is a Netgraph node. This 37 * driver will *NOT* create traditional /dev/ enties, only Netgraph 38 * node. 39 * 40 * NOTE ON LOCKS USED: ng_ubt2 drives uses 2 locks (mutexes) 41 * 42 * 1) sc_if_mtx - lock for device's interface #0 and #1. This lock is used 43 * by USB for any USB request going over device's interface #0 and #1, 44 * i.e. interrupt, control, bulk and isoc. transfers. 45 * 46 * 2) sc_ng_mtx - this lock is used to protect shared (between USB, Netgraph 47 * and Taskqueue) data, such as outgoing mbuf queues, task flags and hook 48 * pointer. This lock *SHOULD NOT* be grabbed for a long time. In fact, 49 * think of it as a spin lock. 50 * 51 * NOTE ON LOCKING STRATEGY: ng_ubt2 driver operates in 3 different contexts. 52 * 53 * 1) USB context. This is where all the USB related stuff happens. All 54 * callbacks run in this context. All callbacks are called (by USB) with 55 * appropriate interface lock held. It is (generally) allowed to grab 56 * any additional locks. 57 * 58 * 2) Netgraph context. This is where all the Netgraph related stuff happens. 59 * Since we mark node as WRITER, the Netgraph node will be "locked" (from 60 * Netgraph point of view). Any variable that is only modified from the 61 * Netgraph context does not require any additonal locking. It is generally 62 * *NOT* allowed to grab *ANY* additional locks. Whatever you do, *DO NOT* 63 * grab any lock in the Netgraph context that could cause de-scheduling of 64 * the Netgraph thread for significant amount of time. In fact, the only 65 * lock that is allowed in the Netgraph context is the sc_ng_mtx lock. 66 * Also make sure that any code that is called from the Netgraph context 67 * follows the rule above. 68 * 69 * 3) Taskqueue context. This is where ubt_task runs. Since we are generally 70 * NOT allowed to grab any lock that could cause de-scheduling in the 71 * Netgraph context, and, USB requires us to grab interface lock before 72 * doing things with transfers, it is safer to transition from the Netgraph 73 * context to the Taskqueue context before we can call into USB subsystem. 74 * 75 * So, to put everything together, the rules are as follows. 76 * It is OK to call from the USB context or the Taskqueue context into 77 * the Netgraph context (i.e. call NG_SEND_xxx functions). In other words 78 * it is allowed to call into the Netgraph context with locks held. 79 * Is it *NOT* OK to call from the Netgraph context into the USB context, 80 * because USB requires us to grab interface locks, and, it is safer to 81 * avoid it. So, to make things safer we set task flags to indicate which 82 * actions we want to perform and schedule ubt_task which would run in the 83 * Taskqueue context. 84 * Is is OK to call from the Taskqueue context into the USB context, 85 * and, ubt_task does just that (i.e. grabs appropriate interface locks 86 * before calling into USB). 87 * Access to the outgoing queues, task flags and hook pointer is 88 * controlled by the sc_ng_mtx lock. It is an unavoidable evil. Again, 89 * sc_ng_mtx should really be a spin lock (and it is very likely to an 90 * equivalent of spin lock due to adaptive nature of FreeBSD mutexes). 91 * All USB callbacks accept softc pointer as a private data. USB ensures 92 * that this pointer is valid. 93 */ 94 95 #include <sys/stdint.h> 96 #include <sys/stddef.h> 97 #include <sys/param.h> 98 #include <sys/queue.h> 99 #include <sys/types.h> 100 #include <sys/systm.h> 101 #include <sys/kernel.h> 102 #include <sys/bus.h> 103 #include <sys/module.h> 104 #include <sys/lock.h> 105 #include <sys/mutex.h> 106 #include <sys/condvar.h> 107 #include <sys/sysctl.h> 108 #include <sys/sx.h> 109 #include <sys/unistd.h> 110 #include <sys/callout.h> 111 #include <sys/malloc.h> 112 #include <sys/priv.h> 113 114 #include "usbdevs.h" 115 #include <dev/usb/usb.h> 116 #include <dev/usb/usbdi.h> 117 #include <dev/usb/usbdi_util.h> 118 119 #define USB_DEBUG_VAR usb_debug 120 #include <dev/usb/usb_debug.h> 121 #include <dev/usb/usb_busdma.h> 122 123 #include <sys/mbuf.h> 124 #include <sys/taskqueue.h> 125 126 #include <netgraph/ng_message.h> 127 #include <netgraph/netgraph.h> 128 #include <netgraph/ng_parse.h> 129 #include <netgraph/bluetooth/include/ng_bluetooth.h> 130 #include <netgraph/bluetooth/include/ng_hci.h> 131 #include <netgraph/bluetooth/include/ng_ubt.h> 132 #include <netgraph/bluetooth/drivers/ubt/ng_ubt_var.h> 133 134 static int ubt_modevent(module_t, int, void *); 135 static device_probe_t ubt_probe; 136 static device_attach_t ubt_attach; 137 static device_detach_t ubt_detach; 138 139 static void ubt_task_schedule(ubt_softc_p, int); 140 static task_fn_t ubt_task; 141 142 #define ubt_xfer_start(sc, i) usbd_transfer_start((sc)->sc_xfer[(i)]) 143 144 /* Netgraph methods */ 145 static ng_constructor_t ng_ubt_constructor; 146 static ng_shutdown_t ng_ubt_shutdown; 147 static ng_newhook_t ng_ubt_newhook; 148 static ng_connect_t ng_ubt_connect; 149 static ng_disconnect_t ng_ubt_disconnect; 150 static ng_rcvmsg_t ng_ubt_rcvmsg; 151 static ng_rcvdata_t ng_ubt_rcvdata; 152 153 /* Queue length */ 154 static const struct ng_parse_struct_field ng_ubt_node_qlen_type_fields[] = 155 { 156 { "queue", &ng_parse_int32_type, }, 157 { "qlen", &ng_parse_int32_type, }, 158 { NULL, } 159 }; 160 static const struct ng_parse_type ng_ubt_node_qlen_type = 161 { 162 &ng_parse_struct_type, 163 &ng_ubt_node_qlen_type_fields 164 }; 165 166 /* Stat info */ 167 static const struct ng_parse_struct_field ng_ubt_node_stat_type_fields[] = 168 { 169 { "pckts_recv", &ng_parse_uint32_type, }, 170 { "bytes_recv", &ng_parse_uint32_type, }, 171 { "pckts_sent", &ng_parse_uint32_type, }, 172 { "bytes_sent", &ng_parse_uint32_type, }, 173 { "oerrors", &ng_parse_uint32_type, }, 174 { "ierrors", &ng_parse_uint32_type, }, 175 { NULL, } 176 }; 177 static const struct ng_parse_type ng_ubt_node_stat_type = 178 { 179 &ng_parse_struct_type, 180 &ng_ubt_node_stat_type_fields 181 }; 182 183 /* Netgraph node command list */ 184 static const struct ng_cmdlist ng_ubt_cmdlist[] = 185 { 186 { 187 NGM_UBT_COOKIE, 188 NGM_UBT_NODE_SET_DEBUG, 189 "set_debug", 190 &ng_parse_uint16_type, 191 NULL 192 }, 193 { 194 NGM_UBT_COOKIE, 195 NGM_UBT_NODE_GET_DEBUG, 196 "get_debug", 197 NULL, 198 &ng_parse_uint16_type 199 }, 200 { 201 NGM_UBT_COOKIE, 202 NGM_UBT_NODE_SET_QLEN, 203 "set_qlen", 204 &ng_ubt_node_qlen_type, 205 NULL 206 }, 207 { 208 NGM_UBT_COOKIE, 209 NGM_UBT_NODE_GET_QLEN, 210 "get_qlen", 211 &ng_ubt_node_qlen_type, 212 &ng_ubt_node_qlen_type 213 }, 214 { 215 NGM_UBT_COOKIE, 216 NGM_UBT_NODE_GET_STAT, 217 "get_stat", 218 NULL, 219 &ng_ubt_node_stat_type 220 }, 221 { 222 NGM_UBT_COOKIE, 223 NGM_UBT_NODE_RESET_STAT, 224 "reset_stat", 225 NULL, 226 NULL 227 }, 228 { 0, } 229 }; 230 231 /* Netgraph node type */ 232 static struct ng_type typestruct = 233 { 234 .version = NG_ABI_VERSION, 235 .name = NG_UBT_NODE_TYPE, 236 .constructor = ng_ubt_constructor, 237 .rcvmsg = ng_ubt_rcvmsg, 238 .shutdown = ng_ubt_shutdown, 239 .newhook = ng_ubt_newhook, 240 .connect = ng_ubt_connect, 241 .rcvdata = ng_ubt_rcvdata, 242 .disconnect = ng_ubt_disconnect, 243 .cmdlist = ng_ubt_cmdlist 244 }; 245 246 /**************************************************************************** 247 **************************************************************************** 248 ** USB specific 249 **************************************************************************** 250 ****************************************************************************/ 251 252 /* USB methods */ 253 static usb_callback_t ubt_ctrl_write_callback; 254 static usb_callback_t ubt_intr_read_callback; 255 static usb_callback_t ubt_bulk_read_callback; 256 static usb_callback_t ubt_bulk_write_callback; 257 static usb_callback_t ubt_isoc_read_callback; 258 static usb_callback_t ubt_isoc_write_callback; 259 260 static int ubt_fwd_mbuf_up(ubt_softc_p, struct mbuf **); 261 static int ubt_isoc_read_one_frame(struct usb_xfer *, int); 262 263 /* 264 * USB config 265 * 266 * The following desribes usb transfers that could be submitted on USB device. 267 * 268 * Interface 0 on the USB device must present the following endpoints 269 * 1) Interrupt endpoint to receive HCI events 270 * 2) Bulk IN endpoint to receive ACL data 271 * 3) Bulk OUT endpoint to send ACL data 272 * 273 * Interface 1 on the USB device must present the following endpoints 274 * 1) Isochronous IN endpoint to receive SCO data 275 * 2) Isochronous OUT endpoint to send SCO data 276 */ 277 278 static const struct usb_config ubt_config[UBT_N_TRANSFER] = 279 { 280 /* 281 * Interface #0 282 */ 283 284 /* Outgoing bulk transfer - ACL packets */ 285 [UBT_IF_0_BULK_DT_WR] = { 286 .type = UE_BULK, 287 .endpoint = UE_ADDR_ANY, 288 .direction = UE_DIR_OUT, 289 .if_index = 0, 290 .bufsize = UBT_BULK_WRITE_BUFFER_SIZE, 291 .flags = { .pipe_bof = 1, .force_short_xfer = 1, }, 292 .callback = &ubt_bulk_write_callback, 293 }, 294 /* Incoming bulk transfer - ACL packets */ 295 [UBT_IF_0_BULK_DT_RD] = { 296 .type = UE_BULK, 297 .endpoint = UE_ADDR_ANY, 298 .direction = UE_DIR_IN, 299 .if_index = 0, 300 .bufsize = UBT_BULK_READ_BUFFER_SIZE, 301 .flags = { .pipe_bof = 1, .short_xfer_ok = 1, }, 302 .callback = &ubt_bulk_read_callback, 303 }, 304 /* Incoming interrupt transfer - HCI events */ 305 [UBT_IF_0_INTR_DT_RD] = { 306 .type = UE_INTERRUPT, 307 .endpoint = UE_ADDR_ANY, 308 .direction = UE_DIR_IN, 309 .if_index = 0, 310 .flags = { .pipe_bof = 1, .short_xfer_ok = 1, }, 311 .bufsize = UBT_INTR_BUFFER_SIZE, 312 .callback = &ubt_intr_read_callback, 313 }, 314 /* Outgoing control transfer - HCI commands */ 315 [UBT_IF_0_CTRL_DT_WR] = { 316 .type = UE_CONTROL, 317 .endpoint = 0x00, /* control pipe */ 318 .direction = UE_DIR_ANY, 319 .if_index = 0, 320 .bufsize = UBT_CTRL_BUFFER_SIZE, 321 .callback = &ubt_ctrl_write_callback, 322 .timeout = 5000, /* 5 seconds */ 323 }, 324 325 /* 326 * Interface #1 327 */ 328 329 /* Incoming isochronous transfer #1 - SCO packets */ 330 [UBT_IF_1_ISOC_DT_RD1] = { 331 .type = UE_ISOCHRONOUS, 332 .endpoint = UE_ADDR_ANY, 333 .direction = UE_DIR_IN, 334 .if_index = 1, 335 .bufsize = 0, /* use "wMaxPacketSize * frames" */ 336 .frames = UBT_ISOC_NFRAMES, 337 .flags = { .short_xfer_ok = 1, }, 338 .callback = &ubt_isoc_read_callback, 339 }, 340 /* Incoming isochronous transfer #2 - SCO packets */ 341 [UBT_IF_1_ISOC_DT_RD2] = { 342 .type = UE_ISOCHRONOUS, 343 .endpoint = UE_ADDR_ANY, 344 .direction = UE_DIR_IN, 345 .if_index = 1, 346 .bufsize = 0, /* use "wMaxPacketSize * frames" */ 347 .frames = UBT_ISOC_NFRAMES, 348 .flags = { .short_xfer_ok = 1, }, 349 .callback = &ubt_isoc_read_callback, 350 }, 351 /* Outgoing isochronous transfer #1 - SCO packets */ 352 [UBT_IF_1_ISOC_DT_WR1] = { 353 .type = UE_ISOCHRONOUS, 354 .endpoint = UE_ADDR_ANY, 355 .direction = UE_DIR_OUT, 356 .if_index = 1, 357 .bufsize = 0, /* use "wMaxPacketSize * frames" */ 358 .frames = UBT_ISOC_NFRAMES, 359 .flags = { .short_xfer_ok = 1, }, 360 .callback = &ubt_isoc_write_callback, 361 }, 362 /* Outgoing isochronous transfer #2 - SCO packets */ 363 [UBT_IF_1_ISOC_DT_WR2] = { 364 .type = UE_ISOCHRONOUS, 365 .endpoint = UE_ADDR_ANY, 366 .direction = UE_DIR_OUT, 367 .if_index = 1, 368 .bufsize = 0, /* use "wMaxPacketSize * frames" */ 369 .frames = UBT_ISOC_NFRAMES, 370 .flags = { .short_xfer_ok = 1, }, 371 .callback = &ubt_isoc_write_callback, 372 }, 373 }; 374 375 /* 376 * If for some reason device should not be attached then put 377 * VendorID/ProductID pair into the list below. The format is 378 * as follows: 379 * 380 * { USB_VPI(VENDOR_ID, PRODUCT_ID, 0) }, 381 * 382 * where VENDOR_ID and PRODUCT_ID are hex numbers. 383 */ 384 385 static const STRUCT_USB_HOST_ID ubt_ignore_devs[] = 386 { 387 /* AVM USB Bluetooth-Adapter BlueFritz! v1.0 */ 388 { USB_VPI(USB_VENDOR_AVM, 0x2200, 0) }, 389 }; 390 391 /* List of supported bluetooth devices */ 392 static const STRUCT_USB_HOST_ID ubt_devs[] = 393 { 394 /* Generic Bluetooth class devices */ 395 { USB_IFACE_CLASS(UDCLASS_WIRELESS), 396 USB_IFACE_SUBCLASS(UDSUBCLASS_RF), 397 USB_IFACE_PROTOCOL(UDPROTO_BLUETOOTH) }, 398 399 /* AVM USB Bluetooth-Adapter BlueFritz! v2.0 */ 400 { USB_VPI(USB_VENDOR_AVM, 0x3800, 0) }, 401 402 /* Broadcom USB dongles, mostly BCM20702 and BCM20702A0 */ 403 { USB_VENDOR(USB_VENDOR_BROADCOM), 404 USB_IFACE_CLASS(UICLASS_VENDOR), 405 USB_IFACE_SUBCLASS(UDSUBCLASS_RF), 406 USB_IFACE_PROTOCOL(UDPROTO_BLUETOOTH) }, 407 }; 408 409 /* 410 * Probe for a USB Bluetooth device. 411 * USB context. 412 */ 413 414 static int 415 ubt_probe(device_t dev) 416 { 417 struct usb_attach_arg *uaa = device_get_ivars(dev); 418 int error; 419 420 if (uaa->usb_mode != USB_MODE_HOST) 421 return (ENXIO); 422 423 if (uaa->info.bIfaceIndex != 0) 424 return (ENXIO); 425 426 if (usbd_lookup_id_by_uaa(ubt_ignore_devs, 427 sizeof(ubt_ignore_devs), uaa) == 0) 428 return (ENXIO); 429 430 error = usbd_lookup_id_by_uaa(ubt_devs, sizeof(ubt_devs), uaa); 431 if (error == 0) 432 return (BUS_PROBE_GENERIC); 433 return (error); 434 } /* ubt_probe */ 435 436 /* 437 * Attach the device. 438 * USB context. 439 */ 440 441 static int 442 ubt_attach(device_t dev) 443 { 444 struct usb_attach_arg *uaa = device_get_ivars(dev); 445 struct ubt_softc *sc = device_get_softc(dev); 446 struct usb_endpoint_descriptor *ed; 447 struct usb_interface_descriptor *id; 448 struct usb_interface *iface; 449 uint16_t wMaxPacketSize; 450 uint8_t alt_index, i, j; 451 uint8_t iface_index[2] = { 0, 1 }; 452 453 device_set_usb_desc(dev); 454 455 sc->sc_dev = dev; 456 sc->sc_debug = NG_UBT_WARN_LEVEL; 457 458 /* 459 * Create Netgraph node 460 */ 461 462 if (ng_make_node_common(&typestruct, &sc->sc_node) != 0) { 463 UBT_ALERT(sc, "could not create Netgraph node\n"); 464 return (ENXIO); 465 } 466 467 /* Name Netgraph node */ 468 if (ng_name_node(sc->sc_node, device_get_nameunit(dev)) != 0) { 469 UBT_ALERT(sc, "could not name Netgraph node\n"); 470 NG_NODE_UNREF(sc->sc_node); 471 return (ENXIO); 472 } 473 NG_NODE_SET_PRIVATE(sc->sc_node, sc); 474 NG_NODE_FORCE_WRITER(sc->sc_node); 475 476 /* 477 * Initialize device softc structure 478 */ 479 480 /* initialize locks */ 481 mtx_init(&sc->sc_ng_mtx, "ubt ng", NULL, MTX_DEF); 482 mtx_init(&sc->sc_if_mtx, "ubt if", NULL, MTX_DEF | MTX_RECURSE); 483 484 /* initialize packet queues */ 485 NG_BT_MBUFQ_INIT(&sc->sc_cmdq, UBT_DEFAULT_QLEN); 486 NG_BT_MBUFQ_INIT(&sc->sc_aclq, UBT_DEFAULT_QLEN); 487 NG_BT_MBUFQ_INIT(&sc->sc_scoq, UBT_DEFAULT_QLEN); 488 489 /* initialize glue task */ 490 TASK_INIT(&sc->sc_task, 0, ubt_task, sc); 491 492 /* 493 * Configure Bluetooth USB device. Discover all required USB 494 * interfaces and endpoints. 495 * 496 * USB device must present two interfaces: 497 * 1) Interface 0 that has 3 endpoints 498 * 1) Interrupt endpoint to receive HCI events 499 * 2) Bulk IN endpoint to receive ACL data 500 * 3) Bulk OUT endpoint to send ACL data 501 * 502 * 2) Interface 1 then has 2 endpoints 503 * 1) Isochronous IN endpoint to receive SCO data 504 * 2) Isochronous OUT endpoint to send SCO data 505 * 506 * Interface 1 (with isochronous endpoints) has several alternate 507 * configurations with different packet size. 508 */ 509 510 /* 511 * For interface #1 search alternate settings, and find 512 * the descriptor with the largest wMaxPacketSize 513 */ 514 515 wMaxPacketSize = 0; 516 alt_index = 0; 517 i = 0; 518 j = 0; 519 ed = NULL; 520 521 /* 522 * Search through all the descriptors looking for the largest 523 * packet size: 524 */ 525 while ((ed = (struct usb_endpoint_descriptor *)usb_desc_foreach( 526 usbd_get_config_descriptor(uaa->device), 527 (struct usb_descriptor *)ed))) { 528 529 if ((ed->bDescriptorType == UDESC_INTERFACE) && 530 (ed->bLength >= sizeof(*id))) { 531 id = (struct usb_interface_descriptor *)ed; 532 i = id->bInterfaceNumber; 533 j = id->bAlternateSetting; 534 } 535 536 if ((ed->bDescriptorType == UDESC_ENDPOINT) && 537 (ed->bLength >= sizeof(*ed)) && 538 (i == 1)) { 539 uint16_t temp; 540 541 temp = UGETW(ed->wMaxPacketSize); 542 if (temp > wMaxPacketSize) { 543 wMaxPacketSize = temp; 544 alt_index = j; 545 } 546 } 547 } 548 549 /* Set alt configuration on interface #1 only if we found it */ 550 if (wMaxPacketSize > 0 && 551 usbd_set_alt_interface_index(uaa->device, 1, alt_index)) { 552 UBT_ALERT(sc, "could not set alternate setting %d " \ 553 "for interface 1!\n", alt_index); 554 goto detach; 555 } 556 557 /* Setup transfers for both interfaces */ 558 if (usbd_transfer_setup(uaa->device, iface_index, sc->sc_xfer, 559 ubt_config, UBT_N_TRANSFER, sc, &sc->sc_if_mtx)) { 560 UBT_ALERT(sc, "could not allocate transfers\n"); 561 goto detach; 562 } 563 564 /* Claim all interfaces belonging to the Bluetooth part */ 565 for (i = 1;; i++) { 566 iface = usbd_get_iface(uaa->device, i); 567 if (iface == NULL) 568 break; 569 id = usbd_get_interface_descriptor(iface); 570 571 if ((id != NULL) && 572 (id->bInterfaceClass == UICLASS_WIRELESS) && 573 (id->bInterfaceSubClass == UISUBCLASS_RF) && 574 (id->bInterfaceProtocol == UIPROTO_BLUETOOTH)) { 575 usbd_set_parent_iface(uaa->device, i, 576 uaa->info.bIfaceIndex); 577 } 578 } 579 return (0); /* success */ 580 581 detach: 582 ubt_detach(dev); 583 584 return (ENXIO); 585 } /* ubt_attach */ 586 587 /* 588 * Detach the device. 589 * USB context. 590 */ 591 592 int 593 ubt_detach(device_t dev) 594 { 595 struct ubt_softc *sc = device_get_softc(dev); 596 node_p node = sc->sc_node; 597 598 /* Destroy Netgraph node */ 599 if (node != NULL) { 600 sc->sc_node = NULL; 601 NG_NODE_REALLY_DIE(node); 602 ng_rmnode_self(node); 603 } 604 605 /* Make sure ubt_task in gone */ 606 taskqueue_drain(taskqueue_swi, &sc->sc_task); 607 608 /* Free USB transfers, if any */ 609 usbd_transfer_unsetup(sc->sc_xfer, UBT_N_TRANSFER); 610 611 /* Destroy queues */ 612 UBT_NG_LOCK(sc); 613 NG_BT_MBUFQ_DESTROY(&sc->sc_cmdq); 614 NG_BT_MBUFQ_DESTROY(&sc->sc_aclq); 615 NG_BT_MBUFQ_DESTROY(&sc->sc_scoq); 616 UBT_NG_UNLOCK(sc); 617 618 mtx_destroy(&sc->sc_if_mtx); 619 mtx_destroy(&sc->sc_ng_mtx); 620 621 return (0); 622 } /* ubt_detach */ 623 624 /* 625 * Called when outgoing control request (HCI command) has completed, i.e. 626 * HCI command was sent to the device. 627 * USB context. 628 */ 629 630 static void 631 ubt_ctrl_write_callback(struct usb_xfer *xfer, usb_error_t error) 632 { 633 struct ubt_softc *sc = usbd_xfer_softc(xfer); 634 struct usb_device_request req; 635 struct mbuf *m; 636 struct usb_page_cache *pc; 637 int actlen; 638 639 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 640 641 switch (USB_GET_STATE(xfer)) { 642 case USB_ST_TRANSFERRED: 643 UBT_INFO(sc, "sent %d bytes to control pipe\n", actlen); 644 UBT_STAT_BYTES_SENT(sc, actlen); 645 UBT_STAT_PCKTS_SENT(sc); 646 /* FALLTHROUGH */ 647 648 case USB_ST_SETUP: 649 send_next: 650 /* Get next command mbuf, if any */ 651 UBT_NG_LOCK(sc); 652 NG_BT_MBUFQ_DEQUEUE(&sc->sc_cmdq, m); 653 UBT_NG_UNLOCK(sc); 654 655 if (m == NULL) { 656 UBT_INFO(sc, "HCI command queue is empty\n"); 657 break; /* transfer complete */ 658 } 659 660 /* Initialize a USB control request and then schedule it */ 661 bzero(&req, sizeof(req)); 662 req.bmRequestType = UBT_HCI_REQUEST; 663 USETW(req.wLength, m->m_pkthdr.len); 664 665 UBT_INFO(sc, "Sending control request, " \ 666 "bmRequestType=0x%02x, wLength=%d\n", 667 req.bmRequestType, UGETW(req.wLength)); 668 669 pc = usbd_xfer_get_frame(xfer, 0); 670 usbd_copy_in(pc, 0, &req, sizeof(req)); 671 pc = usbd_xfer_get_frame(xfer, 1); 672 usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len); 673 674 usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 675 usbd_xfer_set_frame_len(xfer, 1, m->m_pkthdr.len); 676 usbd_xfer_set_frames(xfer, 2); 677 678 NG_FREE_M(m); 679 680 usbd_transfer_submit(xfer); 681 break; 682 683 default: /* Error */ 684 if (error != USB_ERR_CANCELLED) { 685 UBT_WARN(sc, "control transfer failed: %s\n", 686 usbd_errstr(error)); 687 688 UBT_STAT_OERROR(sc); 689 goto send_next; 690 } 691 692 /* transfer cancelled */ 693 break; 694 } 695 } /* ubt_ctrl_write_callback */ 696 697 /* 698 * Called when incoming interrupt transfer (HCI event) has completed, i.e. 699 * HCI event was received from the device. 700 * USB context. 701 */ 702 703 static void 704 ubt_intr_read_callback(struct usb_xfer *xfer, usb_error_t error) 705 { 706 struct ubt_softc *sc = usbd_xfer_softc(xfer); 707 struct mbuf *m; 708 ng_hci_event_pkt_t *hdr; 709 struct usb_page_cache *pc; 710 int actlen; 711 712 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 713 714 m = NULL; 715 716 switch (USB_GET_STATE(xfer)) { 717 case USB_ST_TRANSFERRED: 718 /* Allocate a new mbuf */ 719 MGETHDR(m, M_NOWAIT, MT_DATA); 720 if (m == NULL) { 721 UBT_STAT_IERROR(sc); 722 goto submit_next; 723 } 724 725 MCLGET(m, M_NOWAIT); 726 if (!(m->m_flags & M_EXT)) { 727 UBT_STAT_IERROR(sc); 728 goto submit_next; 729 } 730 731 /* Add HCI packet type */ 732 *mtod(m, uint8_t *)= NG_HCI_EVENT_PKT; 733 m->m_pkthdr.len = m->m_len = 1; 734 735 if (actlen > MCLBYTES - 1) 736 actlen = MCLBYTES - 1; 737 738 pc = usbd_xfer_get_frame(xfer, 0); 739 usbd_copy_out(pc, 0, mtod(m, uint8_t *) + 1, actlen); 740 m->m_pkthdr.len += actlen; 741 m->m_len += actlen; 742 743 UBT_INFO(sc, "got %d bytes from interrupt pipe\n", 744 actlen); 745 746 /* Validate packet and send it up the stack */ 747 if (m->m_pkthdr.len < (int)sizeof(*hdr)) { 748 UBT_INFO(sc, "HCI event packet is too short\n"); 749 750 UBT_STAT_IERROR(sc); 751 goto submit_next; 752 } 753 754 hdr = mtod(m, ng_hci_event_pkt_t *); 755 if (hdr->length != (m->m_pkthdr.len - sizeof(*hdr))) { 756 UBT_ERR(sc, "Invalid HCI event packet size, " \ 757 "length=%d, pktlen=%d\n", 758 hdr->length, m->m_pkthdr.len); 759 760 UBT_STAT_IERROR(sc); 761 goto submit_next; 762 } 763 764 UBT_INFO(sc, "got complete HCI event frame, pktlen=%d, " \ 765 "length=%d\n", m->m_pkthdr.len, hdr->length); 766 767 UBT_STAT_PCKTS_RECV(sc); 768 UBT_STAT_BYTES_RECV(sc, m->m_pkthdr.len); 769 770 ubt_fwd_mbuf_up(sc, &m); 771 /* m == NULL at this point */ 772 /* FALLTHROUGH */ 773 774 case USB_ST_SETUP: 775 submit_next: 776 NG_FREE_M(m); /* checks for m != NULL */ 777 778 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 779 usbd_transfer_submit(xfer); 780 break; 781 782 default: /* Error */ 783 if (error != USB_ERR_CANCELLED) { 784 UBT_WARN(sc, "interrupt transfer failed: %s\n", 785 usbd_errstr(error)); 786 787 /* Try to clear stall first */ 788 usbd_xfer_set_stall(xfer); 789 goto submit_next; 790 } 791 /* transfer cancelled */ 792 break; 793 } 794 } /* ubt_intr_read_callback */ 795 796 /* 797 * Called when incoming bulk transfer (ACL packet) has completed, i.e. 798 * ACL packet was received from the device. 799 * USB context. 800 */ 801 802 static void 803 ubt_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 804 { 805 struct ubt_softc *sc = usbd_xfer_softc(xfer); 806 struct mbuf *m; 807 ng_hci_acldata_pkt_t *hdr; 808 struct usb_page_cache *pc; 809 int len; 810 int actlen; 811 812 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 813 814 m = NULL; 815 816 switch (USB_GET_STATE(xfer)) { 817 case USB_ST_TRANSFERRED: 818 /* Allocate new mbuf */ 819 MGETHDR(m, M_NOWAIT, MT_DATA); 820 if (m == NULL) { 821 UBT_STAT_IERROR(sc); 822 goto submit_next; 823 } 824 825 MCLGET(m, M_NOWAIT); 826 if (!(m->m_flags & M_EXT)) { 827 UBT_STAT_IERROR(sc); 828 goto submit_next; 829 } 830 831 /* Add HCI packet type */ 832 *mtod(m, uint8_t *)= NG_HCI_ACL_DATA_PKT; 833 m->m_pkthdr.len = m->m_len = 1; 834 835 if (actlen > MCLBYTES - 1) 836 actlen = MCLBYTES - 1; 837 838 pc = usbd_xfer_get_frame(xfer, 0); 839 usbd_copy_out(pc, 0, mtod(m, uint8_t *) + 1, actlen); 840 m->m_pkthdr.len += actlen; 841 m->m_len += actlen; 842 843 UBT_INFO(sc, "got %d bytes from bulk-in pipe\n", 844 actlen); 845 846 /* Validate packet and send it up the stack */ 847 if (m->m_pkthdr.len < (int)sizeof(*hdr)) { 848 UBT_INFO(sc, "HCI ACL packet is too short\n"); 849 850 UBT_STAT_IERROR(sc); 851 goto submit_next; 852 } 853 854 hdr = mtod(m, ng_hci_acldata_pkt_t *); 855 len = le16toh(hdr->length); 856 if (len != (int)(m->m_pkthdr.len - sizeof(*hdr))) { 857 UBT_ERR(sc, "Invalid ACL packet size, length=%d, " \ 858 "pktlen=%d\n", len, m->m_pkthdr.len); 859 860 UBT_STAT_IERROR(sc); 861 goto submit_next; 862 } 863 864 UBT_INFO(sc, "got complete ACL data packet, pktlen=%d, " \ 865 "length=%d\n", m->m_pkthdr.len, len); 866 867 UBT_STAT_PCKTS_RECV(sc); 868 UBT_STAT_BYTES_RECV(sc, m->m_pkthdr.len); 869 870 ubt_fwd_mbuf_up(sc, &m); 871 /* m == NULL at this point */ 872 /* FALLTHOUGH */ 873 874 case USB_ST_SETUP: 875 submit_next: 876 NG_FREE_M(m); /* checks for m != NULL */ 877 878 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 879 usbd_transfer_submit(xfer); 880 break; 881 882 default: /* Error */ 883 if (error != USB_ERR_CANCELLED) { 884 UBT_WARN(sc, "bulk-in transfer failed: %s\n", 885 usbd_errstr(error)); 886 887 /* Try to clear stall first */ 888 usbd_xfer_set_stall(xfer); 889 goto submit_next; 890 } 891 /* transfer cancelled */ 892 break; 893 } 894 } /* ubt_bulk_read_callback */ 895 896 /* 897 * Called when outgoing bulk transfer (ACL packet) has completed, i.e. 898 * ACL packet was sent to the device. 899 * USB context. 900 */ 901 902 static void 903 ubt_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 904 { 905 struct ubt_softc *sc = usbd_xfer_softc(xfer); 906 struct mbuf *m; 907 struct usb_page_cache *pc; 908 int actlen; 909 910 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 911 912 switch (USB_GET_STATE(xfer)) { 913 case USB_ST_TRANSFERRED: 914 UBT_INFO(sc, "sent %d bytes to bulk-out pipe\n", actlen); 915 UBT_STAT_BYTES_SENT(sc, actlen); 916 UBT_STAT_PCKTS_SENT(sc); 917 /* FALLTHROUGH */ 918 919 case USB_ST_SETUP: 920 send_next: 921 /* Get next mbuf, if any */ 922 UBT_NG_LOCK(sc); 923 NG_BT_MBUFQ_DEQUEUE(&sc->sc_aclq, m); 924 UBT_NG_UNLOCK(sc); 925 926 if (m == NULL) { 927 UBT_INFO(sc, "ACL data queue is empty\n"); 928 break; /* transfer completed */ 929 } 930 931 /* 932 * Copy ACL data frame back to a linear USB transfer buffer 933 * and schedule transfer 934 */ 935 936 pc = usbd_xfer_get_frame(xfer, 0); 937 usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len); 938 usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len); 939 940 UBT_INFO(sc, "bulk-out transfer has been started, len=%d\n", 941 m->m_pkthdr.len); 942 943 NG_FREE_M(m); 944 945 usbd_transfer_submit(xfer); 946 break; 947 948 default: /* Error */ 949 if (error != USB_ERR_CANCELLED) { 950 UBT_WARN(sc, "bulk-out transfer failed: %s\n", 951 usbd_errstr(error)); 952 953 UBT_STAT_OERROR(sc); 954 955 /* try to clear stall first */ 956 usbd_xfer_set_stall(xfer); 957 goto send_next; 958 } 959 /* transfer cancelled */ 960 break; 961 } 962 } /* ubt_bulk_write_callback */ 963 964 /* 965 * Called when incoming isoc transfer (SCO packet) has completed, i.e. 966 * SCO packet was received from the device. 967 * USB context. 968 */ 969 970 static void 971 ubt_isoc_read_callback(struct usb_xfer *xfer, usb_error_t error) 972 { 973 struct ubt_softc *sc = usbd_xfer_softc(xfer); 974 int n; 975 int actlen, nframes; 976 977 usbd_xfer_status(xfer, &actlen, NULL, NULL, &nframes); 978 979 switch (USB_GET_STATE(xfer)) { 980 case USB_ST_TRANSFERRED: 981 for (n = 0; n < nframes; n ++) 982 if (ubt_isoc_read_one_frame(xfer, n) < 0) 983 break; 984 /* FALLTHROUGH */ 985 986 case USB_ST_SETUP: 987 read_next: 988 for (n = 0; n < nframes; n ++) 989 usbd_xfer_set_frame_len(xfer, n, 990 usbd_xfer_max_framelen(xfer)); 991 992 usbd_transfer_submit(xfer); 993 break; 994 995 default: /* Error */ 996 if (error != USB_ERR_CANCELLED) { 997 UBT_STAT_IERROR(sc); 998 goto read_next; 999 } 1000 1001 /* transfer cancelled */ 1002 break; 1003 } 1004 } /* ubt_isoc_read_callback */ 1005 1006 /* 1007 * Helper function. Called from ubt_isoc_read_callback() to read 1008 * SCO data from one frame. 1009 * USB context. 1010 */ 1011 1012 static int 1013 ubt_isoc_read_one_frame(struct usb_xfer *xfer, int frame_no) 1014 { 1015 struct ubt_softc *sc = usbd_xfer_softc(xfer); 1016 struct usb_page_cache *pc; 1017 struct mbuf *m; 1018 int len, want, got, total; 1019 1020 /* Get existing SCO reassembly buffer */ 1021 pc = usbd_xfer_get_frame(xfer, 0); 1022 m = sc->sc_isoc_in_buffer; 1023 total = usbd_xfer_frame_len(xfer, frame_no); 1024 1025 /* While we have data in the frame */ 1026 while (total > 0) { 1027 if (m == NULL) { 1028 /* Start new reassembly buffer */ 1029 MGETHDR(m, M_NOWAIT, MT_DATA); 1030 if (m == NULL) { 1031 UBT_STAT_IERROR(sc); 1032 return (-1); /* XXX out of sync! */ 1033 } 1034 1035 MCLGET(m, M_NOWAIT); 1036 if (!(m->m_flags & M_EXT)) { 1037 UBT_STAT_IERROR(sc); 1038 NG_FREE_M(m); 1039 return (-1); /* XXX out of sync! */ 1040 } 1041 1042 /* Expect SCO header */ 1043 *mtod(m, uint8_t *) = NG_HCI_SCO_DATA_PKT; 1044 m->m_pkthdr.len = m->m_len = got = 1; 1045 want = sizeof(ng_hci_scodata_pkt_t); 1046 } else { 1047 /* 1048 * Check if we have SCO header and if so 1049 * adjust amount of data we want 1050 */ 1051 got = m->m_pkthdr.len; 1052 want = sizeof(ng_hci_scodata_pkt_t); 1053 1054 if (got >= want) 1055 want += mtod(m, ng_hci_scodata_pkt_t *)->length; 1056 } 1057 1058 /* Append frame data to the SCO reassembly buffer */ 1059 len = total; 1060 if (got + len > want) 1061 len = want - got; 1062 1063 usbd_copy_out(pc, frame_no * usbd_xfer_max_framelen(xfer), 1064 mtod(m, uint8_t *) + m->m_pkthdr.len, len); 1065 1066 m->m_pkthdr.len += len; 1067 m->m_len += len; 1068 total -= len; 1069 1070 /* Check if we got everything we wanted, if not - continue */ 1071 if (got != want) 1072 continue; 1073 1074 /* If we got here then we got complete SCO frame */ 1075 UBT_INFO(sc, "got complete SCO data frame, pktlen=%d, " \ 1076 "length=%d\n", m->m_pkthdr.len, 1077 mtod(m, ng_hci_scodata_pkt_t *)->length); 1078 1079 UBT_STAT_PCKTS_RECV(sc); 1080 UBT_STAT_BYTES_RECV(sc, m->m_pkthdr.len); 1081 1082 ubt_fwd_mbuf_up(sc, &m); 1083 /* m == NULL at this point */ 1084 } 1085 1086 /* Put SCO reassembly buffer back */ 1087 sc->sc_isoc_in_buffer = m; 1088 1089 return (0); 1090 } /* ubt_isoc_read_one_frame */ 1091 1092 /* 1093 * Called when outgoing isoc transfer (SCO packet) has completed, i.e. 1094 * SCO packet was sent to the device. 1095 * USB context. 1096 */ 1097 1098 static void 1099 ubt_isoc_write_callback(struct usb_xfer *xfer, usb_error_t error) 1100 { 1101 struct ubt_softc *sc = usbd_xfer_softc(xfer); 1102 struct usb_page_cache *pc; 1103 struct mbuf *m; 1104 int n, space, offset; 1105 int actlen, nframes; 1106 1107 usbd_xfer_status(xfer, &actlen, NULL, NULL, &nframes); 1108 pc = usbd_xfer_get_frame(xfer, 0); 1109 1110 switch (USB_GET_STATE(xfer)) { 1111 case USB_ST_TRANSFERRED: 1112 UBT_INFO(sc, "sent %d bytes to isoc-out pipe\n", actlen); 1113 UBT_STAT_BYTES_SENT(sc, actlen); 1114 UBT_STAT_PCKTS_SENT(sc); 1115 /* FALLTHROUGH */ 1116 1117 case USB_ST_SETUP: 1118 send_next: 1119 offset = 0; 1120 space = usbd_xfer_max_framelen(xfer) * nframes; 1121 m = NULL; 1122 1123 while (space > 0) { 1124 if (m == NULL) { 1125 UBT_NG_LOCK(sc); 1126 NG_BT_MBUFQ_DEQUEUE(&sc->sc_scoq, m); 1127 UBT_NG_UNLOCK(sc); 1128 1129 if (m == NULL) 1130 break; 1131 } 1132 1133 n = min(space, m->m_pkthdr.len); 1134 if (n > 0) { 1135 usbd_m_copy_in(pc, offset, m,0, n); 1136 m_adj(m, n); 1137 1138 offset += n; 1139 space -= n; 1140 } 1141 1142 if (m->m_pkthdr.len == 0) 1143 NG_FREE_M(m); /* sets m = NULL */ 1144 } 1145 1146 /* Put whatever is left from mbuf back on queue */ 1147 if (m != NULL) { 1148 UBT_NG_LOCK(sc); 1149 NG_BT_MBUFQ_PREPEND(&sc->sc_scoq, m); 1150 UBT_NG_UNLOCK(sc); 1151 } 1152 1153 /* 1154 * Calculate sizes for isoc frames. 1155 * Note that offset could be 0 at this point (i.e. we have 1156 * nothing to send). That is fine, as we have isoc. transfers 1157 * going in both directions all the time. In this case it 1158 * would be just empty isoc. transfer. 1159 */ 1160 1161 for (n = 0; n < nframes; n ++) { 1162 usbd_xfer_set_frame_len(xfer, n, 1163 min(offset, usbd_xfer_max_framelen(xfer))); 1164 offset -= usbd_xfer_frame_len(xfer, n); 1165 } 1166 1167 usbd_transfer_submit(xfer); 1168 break; 1169 1170 default: /* Error */ 1171 if (error != USB_ERR_CANCELLED) { 1172 UBT_STAT_OERROR(sc); 1173 goto send_next; 1174 } 1175 1176 /* transfer cancelled */ 1177 break; 1178 } 1179 } 1180 1181 /* 1182 * Utility function to forward provided mbuf upstream (i.e. up the stack). 1183 * Modifies value of the mbuf pointer (sets it to NULL). 1184 * Save to call from any context. 1185 */ 1186 1187 static int 1188 ubt_fwd_mbuf_up(ubt_softc_p sc, struct mbuf **m) 1189 { 1190 hook_p hook; 1191 int error; 1192 1193 /* 1194 * Close the race with Netgraph hook newhook/disconnect methods. 1195 * Save the hook pointer atomically. Two cases are possible: 1196 * 1197 * 1) The hook pointer is NULL. It means disconnect method got 1198 * there first. In this case we are done. 1199 * 1200 * 2) The hook pointer is not NULL. It means that hook pointer 1201 * could be either in valid or invalid (i.e. in the process 1202 * of disconnect) state. In any case grab an extra reference 1203 * to protect the hook pointer. 1204 * 1205 * It is ok to pass hook in invalid state to NG_SEND_DATA_ONLY() as 1206 * it checks for it. Drop extra reference after NG_SEND_DATA_ONLY(). 1207 */ 1208 1209 UBT_NG_LOCK(sc); 1210 if ((hook = sc->sc_hook) != NULL) 1211 NG_HOOK_REF(hook); 1212 UBT_NG_UNLOCK(sc); 1213 1214 if (hook == NULL) { 1215 NG_FREE_M(*m); 1216 return (ENETDOWN); 1217 } 1218 1219 NG_SEND_DATA_ONLY(error, hook, *m); 1220 NG_HOOK_UNREF(hook); 1221 1222 if (error != 0) 1223 UBT_STAT_IERROR(sc); 1224 1225 return (error); 1226 } /* ubt_fwd_mbuf_up */ 1227 1228 /**************************************************************************** 1229 **************************************************************************** 1230 ** Glue 1231 **************************************************************************** 1232 ****************************************************************************/ 1233 1234 /* 1235 * Schedule glue task. Should be called with sc_ng_mtx held. 1236 * Netgraph context. 1237 */ 1238 1239 static void 1240 ubt_task_schedule(ubt_softc_p sc, int action) 1241 { 1242 mtx_assert(&sc->sc_ng_mtx, MA_OWNED); 1243 1244 /* 1245 * Try to handle corner case when "start all" and "stop all" 1246 * actions can both be set before task is executed. 1247 * 1248 * The rules are 1249 * 1250 * sc_task_flags action new sc_task_flags 1251 * ------------------------------------------------------ 1252 * 0 start start 1253 * 0 stop stop 1254 * start start start 1255 * start stop stop 1256 * stop start stop|start 1257 * stop stop stop 1258 * stop|start start stop|start 1259 * stop|start stop stop 1260 */ 1261 1262 if (action != 0) { 1263 if ((action & UBT_FLAG_T_STOP_ALL) != 0) 1264 sc->sc_task_flags &= ~UBT_FLAG_T_START_ALL; 1265 1266 sc->sc_task_flags |= action; 1267 } 1268 1269 if (sc->sc_task_flags & UBT_FLAG_T_PENDING) 1270 return; 1271 1272 if (taskqueue_enqueue(taskqueue_swi, &sc->sc_task) == 0) { 1273 sc->sc_task_flags |= UBT_FLAG_T_PENDING; 1274 return; 1275 } 1276 1277 /* XXX: i think this should never happen */ 1278 } /* ubt_task_schedule */ 1279 1280 /* 1281 * Glue task. Examines sc_task_flags and does things depending on it. 1282 * Taskqueue context. 1283 */ 1284 1285 static void 1286 ubt_task(void *context, int pending) 1287 { 1288 ubt_softc_p sc = context; 1289 int task_flags, i; 1290 1291 UBT_NG_LOCK(sc); 1292 task_flags = sc->sc_task_flags; 1293 sc->sc_task_flags = 0; 1294 UBT_NG_UNLOCK(sc); 1295 1296 /* 1297 * Stop all USB transfers synchronously. 1298 * Stop interface #0 and #1 transfers at the same time and in the 1299 * same loop. usbd_transfer_drain() will do appropriate locking. 1300 */ 1301 1302 if (task_flags & UBT_FLAG_T_STOP_ALL) 1303 for (i = 0; i < UBT_N_TRANSFER; i ++) 1304 usbd_transfer_drain(sc->sc_xfer[i]); 1305 1306 /* Start incoming interrupt and bulk, and all isoc. USB transfers */ 1307 if (task_flags & UBT_FLAG_T_START_ALL) { 1308 /* 1309 * Interface #0 1310 */ 1311 1312 mtx_lock(&sc->sc_if_mtx); 1313 1314 ubt_xfer_start(sc, UBT_IF_0_INTR_DT_RD); 1315 ubt_xfer_start(sc, UBT_IF_0_BULK_DT_RD); 1316 1317 /* 1318 * Interface #1 1319 * Start both read and write isoc. transfers by default. 1320 * Get them going all the time even if we have nothing 1321 * to send to avoid any delays. 1322 */ 1323 1324 ubt_xfer_start(sc, UBT_IF_1_ISOC_DT_RD1); 1325 ubt_xfer_start(sc, UBT_IF_1_ISOC_DT_RD2); 1326 ubt_xfer_start(sc, UBT_IF_1_ISOC_DT_WR1); 1327 ubt_xfer_start(sc, UBT_IF_1_ISOC_DT_WR2); 1328 1329 mtx_unlock(&sc->sc_if_mtx); 1330 } 1331 1332 /* Start outgoing control transfer */ 1333 if (task_flags & UBT_FLAG_T_START_CTRL) { 1334 mtx_lock(&sc->sc_if_mtx); 1335 ubt_xfer_start(sc, UBT_IF_0_CTRL_DT_WR); 1336 mtx_unlock(&sc->sc_if_mtx); 1337 } 1338 1339 /* Start outgoing bulk transfer */ 1340 if (task_flags & UBT_FLAG_T_START_BULK) { 1341 mtx_lock(&sc->sc_if_mtx); 1342 ubt_xfer_start(sc, UBT_IF_0_BULK_DT_WR); 1343 mtx_unlock(&sc->sc_if_mtx); 1344 } 1345 } /* ubt_task */ 1346 1347 /**************************************************************************** 1348 **************************************************************************** 1349 ** Netgraph specific 1350 **************************************************************************** 1351 ****************************************************************************/ 1352 1353 /* 1354 * Netgraph node constructor. Do not allow to create node of this type. 1355 * Netgraph context. 1356 */ 1357 1358 static int 1359 ng_ubt_constructor(node_p node) 1360 { 1361 return (EINVAL); 1362 } /* ng_ubt_constructor */ 1363 1364 /* 1365 * Netgraph node destructor. Destroy node only when device has been detached. 1366 * Netgraph context. 1367 */ 1368 1369 static int 1370 ng_ubt_shutdown(node_p node) 1371 { 1372 if (node->nd_flags & NGF_REALLY_DIE) { 1373 /* 1374 * We came here because the USB device is being 1375 * detached, so stop being persistant. 1376 */ 1377 NG_NODE_SET_PRIVATE(node, NULL); 1378 NG_NODE_UNREF(node); 1379 } else 1380 NG_NODE_REVIVE(node); /* tell ng_rmnode we are persisant */ 1381 1382 return (0); 1383 } /* ng_ubt_shutdown */ 1384 1385 /* 1386 * Create new hook. There can only be one. 1387 * Netgraph context. 1388 */ 1389 1390 static int 1391 ng_ubt_newhook(node_p node, hook_p hook, char const *name) 1392 { 1393 struct ubt_softc *sc = NG_NODE_PRIVATE(node); 1394 1395 if (strcmp(name, NG_UBT_HOOK) != 0) 1396 return (EINVAL); 1397 1398 UBT_NG_LOCK(sc); 1399 if (sc->sc_hook != NULL) { 1400 UBT_NG_UNLOCK(sc); 1401 1402 return (EISCONN); 1403 } 1404 1405 sc->sc_hook = hook; 1406 UBT_NG_UNLOCK(sc); 1407 1408 return (0); 1409 } /* ng_ubt_newhook */ 1410 1411 /* 1412 * Connect hook. Start incoming USB transfers. 1413 * Netgraph context. 1414 */ 1415 1416 static int 1417 ng_ubt_connect(hook_p hook) 1418 { 1419 struct ubt_softc *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 1420 1421 NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook)); 1422 1423 UBT_NG_LOCK(sc); 1424 ubt_task_schedule(sc, UBT_FLAG_T_START_ALL); 1425 UBT_NG_UNLOCK(sc); 1426 1427 return (0); 1428 } /* ng_ubt_connect */ 1429 1430 /* 1431 * Disconnect hook. 1432 * Netgraph context. 1433 */ 1434 1435 static int 1436 ng_ubt_disconnect(hook_p hook) 1437 { 1438 struct ubt_softc *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 1439 1440 UBT_NG_LOCK(sc); 1441 1442 if (hook != sc->sc_hook) { 1443 UBT_NG_UNLOCK(sc); 1444 1445 return (EINVAL); 1446 } 1447 1448 sc->sc_hook = NULL; 1449 1450 /* Kick off task to stop all USB xfers */ 1451 ubt_task_schedule(sc, UBT_FLAG_T_STOP_ALL); 1452 1453 /* Drain queues */ 1454 NG_BT_MBUFQ_DRAIN(&sc->sc_cmdq); 1455 NG_BT_MBUFQ_DRAIN(&sc->sc_aclq); 1456 NG_BT_MBUFQ_DRAIN(&sc->sc_scoq); 1457 1458 UBT_NG_UNLOCK(sc); 1459 1460 return (0); 1461 } /* ng_ubt_disconnect */ 1462 1463 /* 1464 * Process control message. 1465 * Netgraph context. 1466 */ 1467 1468 static int 1469 ng_ubt_rcvmsg(node_p node, item_p item, hook_p lasthook) 1470 { 1471 struct ubt_softc *sc = NG_NODE_PRIVATE(node); 1472 struct ng_mesg *msg, *rsp = NULL; 1473 struct ng_bt_mbufq *q; 1474 int error = 0, queue, qlen; 1475 1476 NGI_GET_MSG(item, msg); 1477 1478 switch (msg->header.typecookie) { 1479 case NGM_GENERIC_COOKIE: 1480 switch (msg->header.cmd) { 1481 case NGM_TEXT_STATUS: 1482 NG_MKRESPONSE(rsp, msg, NG_TEXTRESPONSE, M_NOWAIT); 1483 if (rsp == NULL) { 1484 error = ENOMEM; 1485 break; 1486 } 1487 1488 snprintf(rsp->data, NG_TEXTRESPONSE, 1489 "Hook: %s\n" \ 1490 "Task flags: %#x\n" \ 1491 "Debug: %d\n" \ 1492 "CMD queue: [have:%d,max:%d]\n" \ 1493 "ACL queue: [have:%d,max:%d]\n" \ 1494 "SCO queue: [have:%d,max:%d]", 1495 (sc->sc_hook != NULL) ? NG_UBT_HOOK : "", 1496 sc->sc_task_flags, 1497 sc->sc_debug, 1498 sc->sc_cmdq.len, 1499 sc->sc_cmdq.maxlen, 1500 sc->sc_aclq.len, 1501 sc->sc_aclq.maxlen, 1502 sc->sc_scoq.len, 1503 sc->sc_scoq.maxlen); 1504 break; 1505 1506 default: 1507 error = EINVAL; 1508 break; 1509 } 1510 break; 1511 1512 case NGM_UBT_COOKIE: 1513 switch (msg->header.cmd) { 1514 case NGM_UBT_NODE_SET_DEBUG: 1515 if (msg->header.arglen != sizeof(ng_ubt_node_debug_ep)){ 1516 error = EMSGSIZE; 1517 break; 1518 } 1519 1520 sc->sc_debug = *((ng_ubt_node_debug_ep *) (msg->data)); 1521 break; 1522 1523 case NGM_UBT_NODE_GET_DEBUG: 1524 NG_MKRESPONSE(rsp, msg, sizeof(ng_ubt_node_debug_ep), 1525 M_NOWAIT); 1526 if (rsp == NULL) { 1527 error = ENOMEM; 1528 break; 1529 } 1530 1531 *((ng_ubt_node_debug_ep *) (rsp->data)) = sc->sc_debug; 1532 break; 1533 1534 case NGM_UBT_NODE_SET_QLEN: 1535 if (msg->header.arglen != sizeof(ng_ubt_node_qlen_ep)) { 1536 error = EMSGSIZE; 1537 break; 1538 } 1539 1540 queue = ((ng_ubt_node_qlen_ep *) (msg->data))->queue; 1541 qlen = ((ng_ubt_node_qlen_ep *) (msg->data))->qlen; 1542 1543 switch (queue) { 1544 case NGM_UBT_NODE_QUEUE_CMD: 1545 q = &sc->sc_cmdq; 1546 break; 1547 1548 case NGM_UBT_NODE_QUEUE_ACL: 1549 q = &sc->sc_aclq; 1550 break; 1551 1552 case NGM_UBT_NODE_QUEUE_SCO: 1553 q = &sc->sc_scoq; 1554 break; 1555 1556 default: 1557 error = EINVAL; 1558 goto done; 1559 /* NOT REACHED */ 1560 } 1561 1562 q->maxlen = qlen; 1563 break; 1564 1565 case NGM_UBT_NODE_GET_QLEN: 1566 if (msg->header.arglen != sizeof(ng_ubt_node_qlen_ep)) { 1567 error = EMSGSIZE; 1568 break; 1569 } 1570 1571 queue = ((ng_ubt_node_qlen_ep *) (msg->data))->queue; 1572 1573 switch (queue) { 1574 case NGM_UBT_NODE_QUEUE_CMD: 1575 q = &sc->sc_cmdq; 1576 break; 1577 1578 case NGM_UBT_NODE_QUEUE_ACL: 1579 q = &sc->sc_aclq; 1580 break; 1581 1582 case NGM_UBT_NODE_QUEUE_SCO: 1583 q = &sc->sc_scoq; 1584 break; 1585 1586 default: 1587 error = EINVAL; 1588 goto done; 1589 /* NOT REACHED */ 1590 } 1591 1592 NG_MKRESPONSE(rsp, msg, sizeof(ng_ubt_node_qlen_ep), 1593 M_NOWAIT); 1594 if (rsp == NULL) { 1595 error = ENOMEM; 1596 break; 1597 } 1598 1599 ((ng_ubt_node_qlen_ep *) (rsp->data))->queue = queue; 1600 ((ng_ubt_node_qlen_ep *) (rsp->data))->qlen = q->maxlen; 1601 break; 1602 1603 case NGM_UBT_NODE_GET_STAT: 1604 NG_MKRESPONSE(rsp, msg, sizeof(ng_ubt_node_stat_ep), 1605 M_NOWAIT); 1606 if (rsp == NULL) { 1607 error = ENOMEM; 1608 break; 1609 } 1610 1611 bcopy(&sc->sc_stat, rsp->data, 1612 sizeof(ng_ubt_node_stat_ep)); 1613 break; 1614 1615 case NGM_UBT_NODE_RESET_STAT: 1616 UBT_STAT_RESET(sc); 1617 break; 1618 1619 default: 1620 error = EINVAL; 1621 break; 1622 } 1623 break; 1624 1625 default: 1626 error = EINVAL; 1627 break; 1628 } 1629 done: 1630 NG_RESPOND_MSG(error, node, item, rsp); 1631 NG_FREE_MSG(msg); 1632 1633 return (error); 1634 } /* ng_ubt_rcvmsg */ 1635 1636 /* 1637 * Process data. 1638 * Netgraph context. 1639 */ 1640 1641 static int 1642 ng_ubt_rcvdata(hook_p hook, item_p item) 1643 { 1644 struct ubt_softc *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 1645 struct mbuf *m; 1646 struct ng_bt_mbufq *q; 1647 int action, error = 0; 1648 1649 if (hook != sc->sc_hook) { 1650 error = EINVAL; 1651 goto done; 1652 } 1653 1654 /* Deatch mbuf and get HCI frame type */ 1655 NGI_GET_M(item, m); 1656 1657 /* 1658 * Minimal size of the HCI frame is 4 bytes: 1 byte frame type, 1659 * 2 bytes connection handle and at least 1 byte of length. 1660 * Panic on data frame that has size smaller than 4 bytes (it 1661 * should not happen) 1662 */ 1663 1664 if (m->m_pkthdr.len < 4) 1665 panic("HCI frame size is too small! pktlen=%d\n", 1666 m->m_pkthdr.len); 1667 1668 /* Process HCI frame */ 1669 switch (*mtod(m, uint8_t *)) { /* XXX call m_pullup ? */ 1670 case NG_HCI_CMD_PKT: 1671 if (m->m_pkthdr.len - 1 > (int)UBT_CTRL_BUFFER_SIZE) 1672 panic("HCI command frame size is too big! " \ 1673 "buffer size=%zd, packet len=%d\n", 1674 UBT_CTRL_BUFFER_SIZE, m->m_pkthdr.len); 1675 1676 q = &sc->sc_cmdq; 1677 action = UBT_FLAG_T_START_CTRL; 1678 break; 1679 1680 case NG_HCI_ACL_DATA_PKT: 1681 if (m->m_pkthdr.len - 1 > UBT_BULK_WRITE_BUFFER_SIZE) 1682 panic("ACL data frame size is too big! " \ 1683 "buffer size=%d, packet len=%d\n", 1684 UBT_BULK_WRITE_BUFFER_SIZE, m->m_pkthdr.len); 1685 1686 q = &sc->sc_aclq; 1687 action = UBT_FLAG_T_START_BULK; 1688 break; 1689 1690 case NG_HCI_SCO_DATA_PKT: 1691 q = &sc->sc_scoq; 1692 action = 0; 1693 break; 1694 1695 default: 1696 UBT_ERR(sc, "Dropping unsupported HCI frame, type=0x%02x, " \ 1697 "pktlen=%d\n", *mtod(m, uint8_t *), m->m_pkthdr.len); 1698 1699 NG_FREE_M(m); 1700 error = EINVAL; 1701 goto done; 1702 /* NOT REACHED */ 1703 } 1704 1705 UBT_NG_LOCK(sc); 1706 if (NG_BT_MBUFQ_FULL(q)) { 1707 NG_BT_MBUFQ_DROP(q); 1708 UBT_NG_UNLOCK(sc); 1709 1710 UBT_ERR(sc, "Dropping HCI frame 0x%02x, len=%d. Queue full\n", 1711 *mtod(m, uint8_t *), m->m_pkthdr.len); 1712 1713 NG_FREE_M(m); 1714 } else { 1715 /* Loose HCI packet type, enqueue mbuf and kick off task */ 1716 m_adj(m, sizeof(uint8_t)); 1717 NG_BT_MBUFQ_ENQUEUE(q, m); 1718 ubt_task_schedule(sc, action); 1719 UBT_NG_UNLOCK(sc); 1720 } 1721 done: 1722 NG_FREE_ITEM(item); 1723 1724 return (error); 1725 } /* ng_ubt_rcvdata */ 1726 1727 /**************************************************************************** 1728 **************************************************************************** 1729 ** Module 1730 **************************************************************************** 1731 ****************************************************************************/ 1732 1733 /* 1734 * Load/Unload the driver module 1735 */ 1736 1737 static int 1738 ubt_modevent(module_t mod, int event, void *data) 1739 { 1740 int error; 1741 1742 switch (event) { 1743 case MOD_LOAD: 1744 error = ng_newtype(&typestruct); 1745 if (error != 0) 1746 printf("%s: Could not register Netgraph node type, " \ 1747 "error=%d\n", NG_UBT_NODE_TYPE, error); 1748 break; 1749 1750 case MOD_UNLOAD: 1751 error = ng_rmtype(&typestruct); 1752 break; 1753 1754 default: 1755 error = EOPNOTSUPP; 1756 break; 1757 } 1758 1759 return (error); 1760 } /* ubt_modevent */ 1761 1762 static devclass_t ubt_devclass; 1763 1764 static device_method_t ubt_methods[] = 1765 { 1766 DEVMETHOD(device_probe, ubt_probe), 1767 DEVMETHOD(device_attach, ubt_attach), 1768 DEVMETHOD(device_detach, ubt_detach), 1769 DEVMETHOD_END 1770 }; 1771 1772 static driver_t ubt_driver = 1773 { 1774 .name = "ubt", 1775 .methods = ubt_methods, 1776 .size = sizeof(struct ubt_softc), 1777 }; 1778 1779 DRIVER_MODULE(ng_ubt, uhub, ubt_driver, ubt_devclass, ubt_modevent, 0); 1780 MODULE_VERSION(ng_ubt, NG_BLUETOOTH_VERSION); 1781 MODULE_DEPEND(ng_ubt, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION); 1782 MODULE_DEPEND(ng_ubt, ng_hci, NG_BLUETOOTH_VERSION, NG_BLUETOOTH_VERSION, NG_BLUETOOTH_VERSION); 1783 MODULE_DEPEND(ng_ubt, usb, 1, 1, 1); 1784 1785