1 /* 2 * ng_ubt.c 3 */ 4 5 /*- 6 * Copyright (c) 2001-2002 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.22 2005/10/31 17:57:44 max Exp $ 31 * $FreeBSD$ 32 */ 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/bus.h> 37 #include <sys/conf.h> 38 #include <sys/endian.h> 39 #include <sys/filio.h> 40 #include <sys/fcntl.h> 41 #include <sys/mbuf.h> 42 #include <sys/malloc.h> 43 #include <sys/kernel.h> 44 #include <sys/module.h> 45 #include <sys/poll.h> 46 #include <sys/uio.h> 47 #include <machine/bus.h> 48 49 #include <dev/usb/usb.h> 50 #include <dev/usb/usbdi.h> 51 #include <dev/usb/usbdi_util.h> 52 #include <dev/usb/usbdivar.h> 53 54 #include <netgraph/ng_message.h> 55 #include <netgraph/netgraph.h> 56 #include <netgraph/ng_parse.h> 57 #include <netgraph/bluetooth/include/ng_bluetooth.h> 58 #include <netgraph/bluetooth/include/ng_hci.h> 59 #include <netgraph/bluetooth/include/ng_ubt.h> 60 #include <netgraph/bluetooth/drivers/ubt/ng_ubt_var.h> 61 62 #include "usbdevs.h" 63 64 /* 65 * USB methods 66 */ 67 68 static device_probe_t ubt_match; 69 static device_attach_t ubt_attach; 70 static device_detach_t ubt_detach; 71 72 static device_method_t ubt_methods[] = { 73 /* Device interface */ 74 DEVMETHOD(device_probe, ubt_match), 75 DEVMETHOD(device_attach, ubt_attach), 76 DEVMETHOD(device_detach, ubt_detach), 77 78 { 0, 0 } 79 }; 80 81 static driver_t ubt_driver = { 82 "ubt", 83 ubt_methods, 84 sizeof(struct ubt_softc) 85 }; 86 87 static devclass_t ubt_devclass; 88 89 static int ubt_modevent (module_t, int, void *); 90 91 static usbd_status ubt_request_start (ubt_softc_p); 92 static void ubt_request_complete (usbd_xfer_handle, 93 usbd_private_handle, usbd_status); 94 static void ubt_request_complete2 (node_p, hook_p, void *, int); 95 96 static usbd_status ubt_intr_start (ubt_softc_p); 97 static void ubt_intr_complete (usbd_xfer_handle, 98 usbd_private_handle, usbd_status); 99 static void ubt_intr_complete2 (node_p, hook_p, void *, int); 100 101 static usbd_status ubt_bulk_in_start (ubt_softc_p); 102 static void ubt_bulk_in_complete (usbd_xfer_handle, 103 usbd_private_handle, usbd_status); 104 static void ubt_bulk_in_complete2 (node_p, hook_p, void *, int); 105 106 static usbd_status ubt_bulk_out_start (ubt_softc_p); 107 static void ubt_bulk_out_complete (usbd_xfer_handle, 108 usbd_private_handle, usbd_status); 109 static void ubt_bulk_out_complete2 (node_p, hook_p, void *, int); 110 111 static usbd_status ubt_isoc_in_start_one (ubt_softc_p, int); 112 static usbd_status ubt_isoc_in_start (ubt_softc_p); 113 static void ubt_isoc_in_complete (usbd_xfer_handle, 114 usbd_private_handle, usbd_status); 115 static void ubt_isoc_in_complete2 (node_p, hook_p, void *, int); 116 117 static usbd_status ubt_isoc_out_start_one (ubt_softc_p, int); 118 static usbd_status ubt_isoc_out_start (ubt_softc_p); 119 static void ubt_isoc_out_complete (usbd_xfer_handle, 120 usbd_private_handle, usbd_status); 121 static void ubt_isoc_out_complete2 (node_p, hook_p, void *, int); 122 123 static void ubt_reset (ubt_softc_p); 124 125 /* 126 * Netgraph methods 127 */ 128 129 static ng_constructor_t ng_ubt_constructor; 130 static ng_shutdown_t ng_ubt_shutdown; 131 static ng_newhook_t ng_ubt_newhook; 132 static ng_connect_t ng_ubt_connect; 133 static ng_disconnect_t ng_ubt_disconnect; 134 static ng_rcvmsg_t ng_ubt_rcvmsg; 135 static ng_rcvdata_t ng_ubt_rcvdata; 136 137 /* Queue length */ 138 static const struct ng_parse_struct_field ng_ubt_node_qlen_type_fields[] = 139 { 140 { "queue", &ng_parse_int32_type, }, 141 { "qlen", &ng_parse_int32_type, }, 142 { NULL, } 143 }; 144 static const struct ng_parse_type ng_ubt_node_qlen_type = { 145 &ng_parse_struct_type, 146 &ng_ubt_node_qlen_type_fields 147 }; 148 149 /* Stat info */ 150 static const struct ng_parse_struct_field ng_ubt_node_stat_type_fields[] = 151 { 152 { "pckts_recv", &ng_parse_uint32_type, }, 153 { "bytes_recv", &ng_parse_uint32_type, }, 154 { "pckts_sent", &ng_parse_uint32_type, }, 155 { "bytes_sent", &ng_parse_uint32_type, }, 156 { "oerrors", &ng_parse_uint32_type, }, 157 { "ierrors", &ng_parse_uint32_type, }, 158 { NULL, } 159 }; 160 static const struct ng_parse_type ng_ubt_node_stat_type = { 161 &ng_parse_struct_type, 162 &ng_ubt_node_stat_type_fields 163 }; 164 165 /* Netgraph node command list */ 166 static const struct ng_cmdlist ng_ubt_cmdlist[] = { 167 { 168 NGM_UBT_COOKIE, 169 NGM_UBT_NODE_SET_DEBUG, 170 "set_debug", 171 &ng_parse_uint16_type, 172 NULL 173 }, 174 { 175 NGM_UBT_COOKIE, 176 NGM_UBT_NODE_GET_DEBUG, 177 "get_debug", 178 NULL, 179 &ng_parse_uint16_type 180 }, 181 { 182 NGM_UBT_COOKIE, 183 NGM_UBT_NODE_SET_QLEN, 184 "set_qlen", 185 &ng_ubt_node_qlen_type, 186 NULL 187 }, 188 { 189 NGM_UBT_COOKIE, 190 NGM_UBT_NODE_GET_QLEN, 191 "get_qlen", 192 &ng_ubt_node_qlen_type, 193 &ng_ubt_node_qlen_type 194 }, 195 { 196 NGM_UBT_COOKIE, 197 NGM_UBT_NODE_GET_STAT, 198 "get_stat", 199 NULL, 200 &ng_ubt_node_stat_type 201 }, 202 { 203 NGM_UBT_COOKIE, 204 NGM_UBT_NODE_RESET_STAT, 205 "reset_stat", 206 NULL, 207 NULL 208 }, 209 { 0, } 210 }; 211 212 /* Netgraph node type */ 213 static struct ng_type typestruct = { 214 .version = NG_ABI_VERSION, 215 .name = NG_UBT_NODE_TYPE, 216 .constructor = ng_ubt_constructor, 217 .rcvmsg = ng_ubt_rcvmsg, 218 .shutdown = ng_ubt_shutdown, 219 .newhook = ng_ubt_newhook, 220 .connect = ng_ubt_connect, 221 .rcvdata = ng_ubt_rcvdata, 222 .disconnect = ng_ubt_disconnect, 223 .cmdlist = ng_ubt_cmdlist 224 }; 225 226 /* 227 * Module 228 */ 229 230 DRIVER_MODULE(ubt, uhub, ubt_driver, ubt_devclass, ubt_modevent, 0); 231 MODULE_VERSION(ng_ubt, NG_BLUETOOTH_VERSION); 232 MODULE_DEPEND(ng_ubt, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION); 233 MODULE_DEPEND(ubt, usb, 1, 1, 1); 234 235 236 /**************************************************************************** 237 **************************************************************************** 238 ** USB specific 239 **************************************************************************** 240 ****************************************************************************/ 241 242 /* 243 * Load/Unload the driver module 244 */ 245 246 static int 247 ubt_modevent(module_t mod, int event, void *data) 248 { 249 int error; 250 251 switch (event) { 252 case MOD_LOAD: 253 error = ng_newtype(&typestruct); 254 if (error != 0) 255 printf( 256 "%s: Could not register Netgraph node type, error=%d\n", 257 NG_UBT_NODE_TYPE, error); 258 else 259 error = usbd_driver_load(mod, event, data); 260 break; 261 262 case MOD_UNLOAD: 263 error = ng_rmtype(&typestruct); 264 if (error == 0) 265 error = usbd_driver_load(mod, event, data); 266 break; 267 268 default: 269 error = EOPNOTSUPP; 270 break; 271 } 272 273 return (error); 274 } /* ubt_modevent */ 275 276 /* 277 * Probe for a USB Bluetooth device 278 */ 279 280 static int 281 ubt_match(device_t self) 282 { 283 /* 284 * If for some reason device should not be attached then put 285 * VendorID/ProductID pair into the list below. The format is 286 * as follows: 287 * 288 * { VENDOR_ID, PRODUCT_ID }, 289 * 290 * where VENDOR_ID and PRODUCT_ID are hex numbers. 291 */ 292 293 static struct usb_devno const ubt_ignored_devices[] = { 294 { USB_VENDOR_AVM, 0x2200 }, /* AVM USB Bluetooth-Adapter BlueFritz! v1.0 */ 295 { 0, 0 } /* This should be the last item in the list */ 296 }; 297 298 /* 299 * If device violates Bluetooth specification and has bDeviceClass, 300 * bDeviceSubClass and bDeviceProtocol set to wrong values then you 301 * could try to put VendorID/ProductID pair into the list below. 302 * Adding VendorID/ProductID pair into this list forces ng_ubt(4) 303 * to attach to the broken device. 304 */ 305 306 static struct usb_devno const ubt_broken_devices[] = { 307 { USB_VENDOR_AVM, 0x3800 }, /* AVM USB Bluetooth-Adapter BlueFritz! v2.0 */ 308 { 0, 0 } /* This should be the last item in the list */ 309 }; 310 311 struct usb_attach_arg *uaa = device_get_ivars(self); 312 usb_device_descriptor_t *dd = usbd_get_device_descriptor(uaa->device); 313 314 if (uaa->iface == NULL || 315 usb_lookup(ubt_ignored_devices, uaa->vendor, uaa->product)) 316 return (UMATCH_NONE); 317 318 if (dd->bDeviceClass == UDCLASS_WIRELESS && 319 dd->bDeviceSubClass == UDSUBCLASS_RF && 320 dd->bDeviceProtocol == UDPROTO_BLUETOOTH) 321 return (UMATCH_DEVCLASS_DEVSUBCLASS); 322 323 if (usb_lookup(ubt_broken_devices, uaa->vendor, uaa->product)) 324 return (UMATCH_VENDOR_PRODUCT); 325 326 return (UMATCH_NONE); 327 } /* ubt_match */ 328 329 /* 330 * Attach the device 331 */ 332 333 static int 334 ubt_attach(device_t self) 335 { 336 struct ubt_softc *sc = device_get_softc(self); 337 struct usb_attach_arg *uaa = device_get_ivars(self); 338 usb_config_descriptor_t *cd = NULL; 339 usb_interface_descriptor_t *id = NULL; 340 usb_endpoint_descriptor_t *ed = NULL; 341 usbd_status error; 342 int i, ai, alt_no, isoc_in, isoc_out, 343 isoc_isize, isoc_osize; 344 345 /* Get USB device info */ 346 sc->sc_dev = self; 347 sc->sc_udev = uaa->device; 348 349 /* 350 * Initialize device softc structure 351 */ 352 353 /* State */ 354 sc->sc_debug = NG_UBT_WARN_LEVEL; 355 sc->sc_flags = 0; 356 NG_UBT_STAT_RESET(sc->sc_stat); 357 358 /* Interfaces */ 359 sc->sc_iface0 = sc->sc_iface1 = NULL; 360 361 /* Interrupt pipe */ 362 sc->sc_intr_ep = -1; 363 sc->sc_intr_pipe = NULL; 364 sc->sc_intr_xfer = NULL; 365 sc->sc_intr_buffer = NULL; 366 367 /* Control pipe */ 368 sc->sc_ctrl_xfer = NULL; 369 sc->sc_ctrl_buffer = NULL; 370 NG_BT_MBUFQ_INIT(&sc->sc_cmdq, UBT_DEFAULT_QLEN); 371 372 /* Bulk-in pipe */ 373 sc->sc_bulk_in_ep = -1; 374 sc->sc_bulk_in_pipe = NULL; 375 sc->sc_bulk_in_xfer = NULL; 376 sc->sc_bulk_in_buffer = NULL; 377 378 /* Bulk-out pipe */ 379 sc->sc_bulk_out_ep = -1; 380 sc->sc_bulk_out_pipe = NULL; 381 sc->sc_bulk_out_xfer = NULL; 382 sc->sc_bulk_out_buffer = NULL; 383 NG_BT_MBUFQ_INIT(&sc->sc_aclq, UBT_DEFAULT_QLEN); 384 385 /* Isoc-in pipe */ 386 sc->sc_isoc_in_buffer = NULL; 387 sc->sc_isoc_in_ep = -1; 388 sc->sc_isoc_in_pipe = NULL; 389 bzero(&sc->sc_isoc_in, sizeof(sc->sc_isoc_in)); 390 391 /* Isoc-out pipe */ 392 sc->sc_isoc_out_ep = -1; 393 sc->sc_isoc_out_pipe = NULL; 394 bzero(&sc->sc_isoc_out, sizeof(sc->sc_isoc_out)); 395 396 sc->sc_isoc_size = -1; 397 NG_BT_MBUFQ_INIT(&sc->sc_scoq, UBT_DEFAULT_QLEN); 398 399 /* Netgraph part */ 400 sc->sc_node = NULL; 401 sc->sc_hook = NULL; 402 403 /* 404 * XXX set configuration? 405 * 406 * Configure Bluetooth USB device. Discover all required USB interfaces 407 * and endpoints. 408 * 409 * USB device must present two interfaces: 410 * 1) Interface 0 that has 3 endpoints 411 * 1) Interrupt endpoint to receive HCI events 412 * 2) Bulk IN endpoint to receive ACL data 413 * 3) Bulk OUT endpoint to send ACL data 414 * 415 * 2) Interface 1 then has 2 endpoints 416 * 1) Isochronous IN endpoint to receive SCO data 417 * 2) Isochronous OUT endpoint to send SCO data 418 * 419 * Interface 1 (with isochronous endpoints) has several alternate 420 * configurations with different packet size. 421 */ 422 423 /* 424 * Interface 0 425 */ 426 427 error = usbd_device2interface_handle(sc->sc_udev, 0, &sc->sc_iface0); 428 if (error || sc->sc_iface0 == NULL) { 429 printf("%s: Could not get interface 0 handle. %s (%d), " \ 430 "handle=%p\n", device_get_nameunit(sc->sc_dev), 431 usbd_errstr(error), error, sc->sc_iface0); 432 goto bad; 433 } 434 435 id = usbd_get_interface_descriptor(sc->sc_iface0); 436 if (id == NULL) { 437 printf("%s: Could not get interface 0 descriptor\n", 438 device_get_nameunit(sc->sc_dev)); 439 goto bad; 440 } 441 442 for (i = 0; i < id->bNumEndpoints; i ++) { 443 ed = usbd_interface2endpoint_descriptor(sc->sc_iface0, i); 444 if (ed == NULL) { 445 printf("%s: Could not read endpoint descriptor for " \ 446 "interface 0, i=%d\n", device_get_nameunit(sc->sc_dev), 447 i); 448 goto bad; 449 } 450 451 switch (UE_GET_XFERTYPE(ed->bmAttributes)) { 452 case UE_BULK: 453 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) 454 sc->sc_bulk_in_ep = ed->bEndpointAddress; 455 else 456 sc->sc_bulk_out_ep = ed->bEndpointAddress; 457 break; 458 459 case UE_INTERRUPT: 460 sc->sc_intr_ep = ed->bEndpointAddress; 461 break; 462 } 463 } 464 465 /* Check if we got everything we wanted on Interface 0 */ 466 if (sc->sc_intr_ep == -1) { 467 printf("%s: Could not detect interrupt endpoint\n", 468 device_get_nameunit(sc->sc_dev)); 469 goto bad; 470 } 471 if (sc->sc_bulk_in_ep == -1) { 472 printf("%s: Could not detect bulk-in endpoint\n", 473 device_get_nameunit(sc->sc_dev)); 474 goto bad; 475 } 476 if (sc->sc_bulk_out_ep == -1) { 477 printf("%s: Could not detect bulk-out endpoint\n", 478 device_get_nameunit(sc->sc_dev)); 479 goto bad; 480 } 481 482 printf("%s: Interface 0 endpoints: interrupt=%#x, bulk-in=%#x, " \ 483 "bulk-out=%#x\n", device_get_nameunit(sc->sc_dev), 484 sc->sc_intr_ep, sc->sc_bulk_in_ep, sc->sc_bulk_out_ep); 485 486 /* 487 * Interface 1 488 */ 489 490 cd = usbd_get_config_descriptor(sc->sc_udev); 491 if (cd == NULL) { 492 printf("%s: Could not get device configuration descriptor\n", 493 device_get_nameunit(sc->sc_dev)); 494 goto bad; 495 } 496 497 error = usbd_device2interface_handle(sc->sc_udev, 1, &sc->sc_iface1); 498 if (error || sc->sc_iface1 == NULL) { 499 printf("%s: Could not get interface 1 handle. %s (%d), " \ 500 "handle=%p\n", device_get_nameunit(sc->sc_dev), 501 usbd_errstr(error), error, sc->sc_iface1); 502 goto bad; 503 } 504 505 id = usbd_get_interface_descriptor(sc->sc_iface1); 506 if (id == NULL) { 507 printf("%s: Could not get interface 1 descriptor\n", 508 device_get_nameunit(sc->sc_dev)); 509 goto bad; 510 } 511 512 /* 513 * Scan all alternate configurations for interface 1 514 */ 515 516 alt_no = -1; 517 518 for (ai = 0; ai < usbd_get_no_alts(cd, 1); ai++) { 519 error = usbd_set_interface(sc->sc_iface1, ai); 520 if (error) { 521 printf("%s: [SCAN] Could not set alternate " \ 522 "configuration %d for interface 1. %s (%d)\n", 523 device_get_nameunit(sc->sc_dev), ai, usbd_errstr(error), 524 error); 525 goto bad; 526 } 527 id = usbd_get_interface_descriptor(sc->sc_iface1); 528 if (id == NULL) { 529 printf("%s: Could not get interface 1 descriptor for " \ 530 "alternate configuration %d\n", 531 device_get_nameunit(sc->sc_dev), ai); 532 goto bad; 533 } 534 535 isoc_in = isoc_out = -1; 536 isoc_isize = isoc_osize = 0; 537 538 for (i = 0; i < id->bNumEndpoints; i ++) { 539 ed = usbd_interface2endpoint_descriptor(sc->sc_iface1, i); 540 if (ed == NULL) { 541 printf("%s: Could not read endpoint " \ 542 "descriptor for interface 1, " \ 543 "alternate configuration %d, i=%d\n", 544 device_get_nameunit(sc->sc_dev), ai, i); 545 goto bad; 546 } 547 548 if (UE_GET_XFERTYPE(ed->bmAttributes) != UE_ISOCHRONOUS) 549 continue; 550 551 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) { 552 isoc_in = ed->bEndpointAddress; 553 isoc_isize = UGETW(ed->wMaxPacketSize); 554 } else { 555 isoc_out = ed->bEndpointAddress; 556 isoc_osize = UGETW(ed->wMaxPacketSize); 557 } 558 } 559 560 /* 561 * Make sure that configuration looks sane and if so 562 * update current settings 563 */ 564 565 if (isoc_in != -1 && isoc_out != -1 && 566 isoc_isize > 0 && isoc_osize > 0 && 567 isoc_isize == isoc_osize && isoc_isize > sc->sc_isoc_size) { 568 sc->sc_isoc_in_ep = isoc_in; 569 sc->sc_isoc_out_ep = isoc_out; 570 sc->sc_isoc_size = isoc_isize; 571 alt_no = ai; 572 } 573 } 574 575 /* Check if we got everything we wanted on Interface 0 */ 576 if (sc->sc_isoc_in_ep == -1) { 577 printf("%s: Could not detect isoc-in endpoint\n", 578 device_get_nameunit(sc->sc_dev)); 579 goto bad; 580 } 581 if (sc->sc_isoc_out_ep == -1) { 582 printf("%s: Could not detect isoc-out endpoint\n", 583 device_get_nameunit(sc->sc_dev)); 584 goto bad; 585 } 586 if (sc->sc_isoc_size <= 0) { 587 printf("%s: Invalid isoc. packet size=%d\n", 588 device_get_nameunit(sc->sc_dev), sc->sc_isoc_size); 589 goto bad; 590 } 591 592 error = usbd_set_interface(sc->sc_iface1, alt_no); 593 if (error) { 594 printf("%s: Could not set alternate configuration " \ 595 "%d for interface 1. %s (%d)\n", 596 device_get_nameunit(sc->sc_dev), 597 alt_no, usbd_errstr(error), error); 598 goto bad; 599 } 600 601 /* Allocate USB transfer handles and buffers */ 602 sc->sc_ctrl_xfer = usbd_alloc_xfer(sc->sc_udev); 603 if (sc->sc_ctrl_xfer == NULL) { 604 printf("%s: Could not allocate control xfer handle\n", 605 device_get_nameunit(sc->sc_dev)); 606 goto bad; 607 } 608 sc->sc_ctrl_buffer = usbd_alloc_buffer(sc->sc_ctrl_xfer, 609 UBT_CTRL_BUFFER_SIZE); 610 if (sc->sc_ctrl_buffer == NULL) { 611 printf("%s: Could not allocate control buffer\n", 612 device_get_nameunit(sc->sc_dev)); 613 goto bad; 614 } 615 616 sc->sc_intr_xfer = usbd_alloc_xfer(sc->sc_udev); 617 if (sc->sc_intr_xfer == NULL) { 618 printf("%s: Could not allocate interrupt xfer handle\n", 619 device_get_nameunit(sc->sc_dev)); 620 goto bad; 621 } 622 623 sc->sc_bulk_in_xfer = usbd_alloc_xfer(sc->sc_udev); 624 if (sc->sc_bulk_in_xfer == NULL) { 625 printf("%s: Could not allocate bulk-in xfer handle\n", 626 device_get_nameunit(sc->sc_dev)); 627 goto bad; 628 } 629 630 sc->sc_bulk_out_xfer = usbd_alloc_xfer(sc->sc_udev); 631 if (sc->sc_bulk_out_xfer == NULL) { 632 printf("%s: Could not allocate bulk-out xfer handle\n", 633 device_get_nameunit(sc->sc_dev)); 634 goto bad; 635 } 636 sc->sc_bulk_out_buffer = usbd_alloc_buffer(sc->sc_bulk_out_xfer, 637 UBT_BULK_BUFFER_SIZE); 638 if (sc->sc_bulk_out_buffer == NULL) { 639 printf("%s: Could not allocate bulk-out buffer\n", 640 device_get_nameunit(sc->sc_dev)); 641 goto bad; 642 } 643 644 /* 645 * Allocate buffers for isoc. transfers 646 */ 647 648 for (i = 0; i < NG_UBT_NXFERS; i++) { 649 sc->sc_isoc_in[i].xfer = usbd_alloc_xfer(sc->sc_udev); 650 if (sc->sc_isoc_in[i].xfer == NULL) { 651 printf("%s: Could not allocate isoc-in xfer handle\n", 652 device_get_nameunit(sc->sc_dev)); 653 goto bad; 654 } 655 656 sc->sc_isoc_in[i].buffer = usbd_alloc_buffer( 657 sc->sc_isoc_in[i].xfer, 658 NG_UBT_NFRAMES * sc->sc_isoc_size); 659 if (sc->sc_isoc_in[i].buffer == NULL) { 660 printf("%s: Could not allocate isoc-in buffer\n", 661 device_get_nameunit(sc->sc_dev)); 662 goto bad; 663 } 664 665 sc->sc_isoc_in[i].frlen = malloc( 666 sizeof(uint16_t) * NG_UBT_NFRAMES, 667 M_USBDEV, M_NOWAIT); 668 if (sc->sc_isoc_in[i].frlen == NULL) { 669 printf("%s: Could not allocate isoc-in frame sizes buffer\n", 670 device_get_nameunit(sc->sc_dev)); 671 goto bad; 672 } 673 } 674 675 for (i = 0; i < NG_UBT_NXFERS; i++) { 676 sc->sc_isoc_out[i].xfer = usbd_alloc_xfer(sc->sc_udev); 677 if (sc->sc_isoc_out[i].xfer == NULL) { 678 printf("%s: Could not allocate isoc-out xfer handle\n", 679 device_get_nameunit(sc->sc_dev)); 680 goto bad; 681 } 682 683 sc->sc_isoc_out[i].buffer = usbd_alloc_buffer( 684 sc->sc_isoc_out[i].xfer, 685 NG_UBT_NFRAMES * sc->sc_isoc_size); 686 if (sc->sc_isoc_out[i].buffer == NULL) { 687 printf("%s: Could not allocate isoc-out buffer\n", 688 device_get_nameunit(sc->sc_dev)); 689 goto bad; 690 } 691 692 sc->sc_isoc_out[i].frlen = malloc( 693 sizeof(uint16_t) * NG_UBT_NFRAMES, 694 M_USBDEV, M_NOWAIT); 695 if (sc->sc_isoc_out[i].frlen == NULL) { 696 printf("%s: Could not allocate isoc-out frame sizes buffer\n", 697 device_get_nameunit(sc->sc_dev)); 698 goto bad; 699 } 700 } 701 702 printf("%s: Interface 1 (alt.config %d) endpoints: isoc-in=%#x, " \ 703 "isoc-out=%#x; wMaxPacketSize=%d; nframes=%d, buffer size=%d\n", 704 device_get_nameunit(sc->sc_dev), alt_no, sc->sc_isoc_in_ep, 705 sc->sc_isoc_out_ep, sc->sc_isoc_size, NG_UBT_NFRAMES, 706 (NG_UBT_NFRAMES * sc->sc_isoc_size)); 707 708 /* 709 * Open pipes 710 */ 711 712 /* Interrupt */ 713 error = usbd_open_pipe(sc->sc_iface0, sc->sc_intr_ep, 714 USBD_EXCLUSIVE_USE, &sc->sc_intr_pipe); 715 if (error != USBD_NORMAL_COMPLETION) { 716 printf("%s: %s - Could not open interrupt pipe. %s (%d)\n", 717 __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(error), 718 error); 719 goto bad; 720 } 721 722 /* Bulk-in */ 723 error = usbd_open_pipe(sc->sc_iface0, sc->sc_bulk_in_ep, 724 USBD_EXCLUSIVE_USE, &sc->sc_bulk_in_pipe); 725 if (error != USBD_NORMAL_COMPLETION) { 726 printf("%s: %s - Could not open bulk-in pipe. %s (%d)\n", 727 __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(error), 728 error); 729 goto bad; 730 } 731 732 /* Bulk-out */ 733 error = usbd_open_pipe(sc->sc_iface0, sc->sc_bulk_out_ep, 734 USBD_EXCLUSIVE_USE, &sc->sc_bulk_out_pipe); 735 if (error != USBD_NORMAL_COMPLETION) { 736 printf("%s: %s - Could not open bulk-out pipe. %s (%d)\n", 737 __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(error), 738 error); 739 goto bad; 740 } 741 742 /* Isoc-in */ 743 error = usbd_open_pipe(sc->sc_iface1, sc->sc_isoc_in_ep, 744 USBD_EXCLUSIVE_USE, &sc->sc_isoc_in_pipe); 745 if (error != USBD_NORMAL_COMPLETION) { 746 printf("%s: %s - Could not open isoc-in pipe. %s (%d)\n", 747 __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(error), 748 error); 749 goto bad; 750 } 751 752 /* Isoc-out */ 753 error = usbd_open_pipe(sc->sc_iface1, sc->sc_isoc_out_ep, 754 USBD_EXCLUSIVE_USE, &sc->sc_isoc_out_pipe); 755 if (error != USBD_NORMAL_COMPLETION) { 756 printf("%s: %s - Could not open isoc-out pipe. %s (%d)\n", 757 __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(error), 758 error); 759 goto bad; 760 } 761 762 /* Create Netgraph node */ 763 if (ng_make_node_common(&typestruct, &sc->sc_node) != 0) { 764 printf("%s: Could not create Netgraph node\n", 765 device_get_nameunit(sc->sc_dev)); 766 sc->sc_node = NULL; 767 goto bad; 768 } 769 770 /* Name node */ 771 if (ng_name_node(sc->sc_node, device_get_nameunit(sc->sc_dev)) != 0) { 772 printf("%s: Could not name Netgraph node\n", 773 device_get_nameunit(sc->sc_dev)); 774 NG_NODE_UNREF(sc->sc_node); 775 sc->sc_node = NULL; 776 goto bad; 777 } 778 779 NG_NODE_SET_PRIVATE(sc->sc_node, sc); 780 NG_NODE_FORCE_WRITER(sc->sc_node); 781 782 /* Claim all interfaces on the device */ 783 for (i = 0; i < uaa->nifaces; i++) 784 uaa->ifaces[i] = NULL; 785 786 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, 787 sc->sc_dev); 788 789 return 0; 790 bad: 791 ubt_detach(self); 792 793 return ENXIO; 794 } /* ubt_attach */ 795 796 /* 797 * Detach the device 798 */ 799 800 static int 801 ubt_detach(device_t self) 802 { 803 struct ubt_softc *sc = device_get_softc(self); 804 int i; 805 806 /* Destroy Netgraph node */ 807 if (sc->sc_node != NULL) { 808 NG_NODE_SET_PRIVATE(sc->sc_node, NULL); 809 ng_rmnode_self(sc->sc_node); 810 sc->sc_node = NULL; 811 } 812 813 /* Close pipes */ 814 if (sc->sc_intr_pipe != NULL) { 815 usbd_close_pipe(sc->sc_intr_pipe); 816 sc->sc_intr_pipe = NULL; 817 } 818 819 if (sc->sc_bulk_in_pipe != NULL) { 820 usbd_close_pipe(sc->sc_bulk_in_pipe); 821 sc->sc_bulk_in_pipe = NULL; 822 } 823 if (sc->sc_bulk_out_pipe != NULL) { 824 usbd_close_pipe(sc->sc_bulk_out_pipe); 825 sc->sc_bulk_out_pipe = NULL; 826 } 827 828 if (sc->sc_isoc_in_pipe != NULL) { 829 usbd_close_pipe(sc->sc_isoc_in_pipe); 830 sc->sc_isoc_in_pipe = NULL; 831 } 832 if (sc->sc_isoc_out_pipe != NULL) { 833 usbd_close_pipe(sc->sc_isoc_out_pipe); 834 sc->sc_isoc_out_pipe = NULL; 835 } 836 837 /* Destroy USB transfer handles */ 838 if (sc->sc_ctrl_xfer != NULL) { 839 usbd_free_xfer(sc->sc_ctrl_xfer); 840 sc->sc_ctrl_xfer = NULL; 841 } 842 843 if (sc->sc_intr_xfer != NULL) { 844 usbd_free_xfer(sc->sc_intr_xfer); 845 sc->sc_intr_xfer = NULL; 846 } 847 848 if (sc->sc_bulk_in_xfer != NULL) { 849 usbd_free_xfer(sc->sc_bulk_in_xfer); 850 sc->sc_bulk_in_xfer = NULL; 851 } 852 if (sc->sc_bulk_out_xfer != NULL) { 853 usbd_free_xfer(sc->sc_bulk_out_xfer); 854 sc->sc_bulk_out_xfer = NULL; 855 } 856 857 for (i = 0; i < NG_UBT_NXFERS; i++) { 858 if (sc->sc_isoc_in[i].xfer != NULL) { 859 usbd_free_xfer(sc->sc_isoc_in[i].xfer); 860 sc->sc_isoc_in[i].xfer = NULL; 861 sc->sc_isoc_in[i].buffer = NULL; 862 } 863 864 if (sc->sc_isoc_in[i].frlen != NULL) { 865 free(sc->sc_isoc_in[i].frlen, M_USBDEV); 866 sc->sc_isoc_in[i].frlen = NULL; 867 } 868 } 869 870 for (i = 0; i < NG_UBT_NXFERS; i++) { 871 if (sc->sc_isoc_out[i].xfer != NULL) { 872 usbd_free_xfer(sc->sc_isoc_out[i].xfer); 873 sc->sc_isoc_out[i].xfer = NULL; 874 sc->sc_isoc_out[i].buffer = NULL; 875 } 876 877 if (sc->sc_isoc_out[i].frlen != NULL) { 878 free(sc->sc_isoc_out[i].frlen, M_USBDEV); 879 sc->sc_isoc_out[i].frlen = NULL; 880 } 881 } 882 883 NG_FREE_M(sc->sc_bulk_in_buffer); 884 NG_FREE_M(sc->sc_isoc_in_buffer); 885 886 /* Destroy queues */ 887 NG_BT_MBUFQ_DRAIN(&sc->sc_cmdq); 888 NG_BT_MBUFQ_DRAIN(&sc->sc_aclq); 889 NG_BT_MBUFQ_DRAIN(&sc->sc_scoq); 890 891 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev); 892 893 return (0); 894 } /* ubt_detach */ 895 896 /* 897 * Start USB control request (HCI command). Must be called with node locked 898 */ 899 900 static usbd_status 901 ubt_request_start(ubt_softc_p sc) 902 { 903 usb_device_request_t req; 904 struct mbuf *m = NULL; 905 usbd_status status; 906 907 KASSERT(!(sc->sc_flags & UBT_CMD_XMIT), ( 908 "%s: %s - Another control request is pending\n", 909 __func__, device_get_nameunit(sc->sc_dev))); 910 911 NG_BT_MBUFQ_DEQUEUE(&sc->sc_cmdq, m); 912 if (m == NULL) { 913 NG_UBT_INFO( 914 "%s: %s - HCI command queue is empty\n", __func__, device_get_nameunit(sc->sc_dev)); 915 916 return (USBD_NORMAL_COMPLETION); 917 } 918 919 /* 920 * Check HCI command frame size and copy it back to 921 * linear USB transfer buffer. 922 */ 923 924 if (m->m_pkthdr.len > UBT_CTRL_BUFFER_SIZE) 925 panic( 926 "%s: %s - HCI command frame too big, size=%zd, len=%d\n", 927 __func__, device_get_nameunit(sc->sc_dev), UBT_CTRL_BUFFER_SIZE, 928 m->m_pkthdr.len); 929 930 m_copydata(m, 0, m->m_pkthdr.len, sc->sc_ctrl_buffer); 931 932 /* Initialize a USB control request and then schedule it */ 933 bzero(&req, sizeof(req)); 934 req.bmRequestType = UBT_HCI_REQUEST; 935 USETW(req.wLength, m->m_pkthdr.len); 936 937 NG_UBT_INFO( 938 "%s: %s - Sending control request, bmRequestType=%#x, wLength=%d\n", 939 __func__, device_get_nameunit(sc->sc_dev), req.bmRequestType, 940 UGETW(req.wLength)); 941 942 usbd_setup_default_xfer( 943 sc->sc_ctrl_xfer, 944 sc->sc_udev, 945 (usbd_private_handle) sc->sc_node, 946 USBD_DEFAULT_TIMEOUT, /* XXX */ 947 &req, 948 sc->sc_ctrl_buffer, 949 m->m_pkthdr.len, 950 USBD_NO_COPY, 951 ubt_request_complete); 952 953 NG_NODE_REF(sc->sc_node); 954 955 status = usbd_transfer(sc->sc_ctrl_xfer); 956 if (status != USBD_NORMAL_COMPLETION && status != USBD_IN_PROGRESS) { 957 NG_UBT_ERR( 958 "%s: %s - Could not start control request. %s (%d)\n", 959 __func__, device_get_nameunit(sc->sc_dev), 960 usbd_errstr(status), status); 961 962 NG_NODE_UNREF(sc->sc_node); 963 964 NG_BT_MBUFQ_DROP(&sc->sc_cmdq); 965 NG_UBT_STAT_OERROR(sc->sc_stat); 966 967 /* XXX FIXME should we try to resubmit another request? */ 968 } else { 969 NG_UBT_INFO( 970 "%s: %s - Control request has been started\n", 971 __func__, device_get_nameunit(sc->sc_dev)); 972 973 sc->sc_flags |= UBT_CMD_XMIT; 974 status = USBD_NORMAL_COMPLETION; 975 } 976 977 NG_FREE_M(m); 978 979 return (status); 980 } /* ubt_request_start */ 981 982 /* 983 * USB control request callback 984 */ 985 986 static void 987 ubt_request_complete(usbd_xfer_handle h, usbd_private_handle p, usbd_status s) 988 { 989 ng_send_fn((node_p) p, NULL, ubt_request_complete2, (void *) h, s); 990 NG_NODE_UNREF((node_p) p); 991 } /* ubt_request_complete */ 992 993 static void 994 ubt_request_complete2(node_p node, hook_p hook, void *arg1, int arg2) 995 { 996 ubt_softc_p sc = (ubt_softc_p) NG_NODE_PRIVATE(node); 997 usbd_xfer_handle h = (usbd_xfer_handle) arg1; 998 usbd_status s = (usbd_status) arg2; 999 1000 if (sc == NULL) 1001 return; 1002 1003 KASSERT((sc->sc_flags & UBT_CMD_XMIT), ( 1004 "%s: %s - No control request is pending\n", __func__, device_get_nameunit(sc->sc_dev))); 1005 1006 sc->sc_flags &= ~UBT_CMD_XMIT; 1007 1008 if (s == USBD_CANCELLED) { 1009 NG_UBT_INFO( 1010 "%s: %s - Control request cancelled\n", __func__, device_get_nameunit(sc->sc_dev)); 1011 1012 return; 1013 } 1014 1015 if (s != USBD_NORMAL_COMPLETION) { 1016 NG_UBT_ERR( 1017 "%s: %s - Control request failed. %s (%d)\n", 1018 __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(s), s); 1019 1020 if (s == USBD_STALLED) 1021 usbd_clear_endpoint_stall_async(h->pipe); 1022 1023 NG_UBT_STAT_OERROR(sc->sc_stat); 1024 } else { 1025 NG_UBT_INFO( 1026 "%s: %s - Sent %d bytes to control pipe\n", 1027 __func__, device_get_nameunit(sc->sc_dev), h->actlen); 1028 1029 NG_UBT_STAT_BYTES_SENT(sc->sc_stat, h->actlen); 1030 NG_UBT_STAT_PCKTS_SENT(sc->sc_stat); 1031 } 1032 1033 if (NG_BT_MBUFQ_LEN(&sc->sc_cmdq) > 0) 1034 ubt_request_start(sc); 1035 } /* ubt_request_complete2 */ 1036 1037 /* 1038 * Start interrupt transfer. Must be called when node is locked 1039 */ 1040 1041 static usbd_status 1042 ubt_intr_start(ubt_softc_p sc) 1043 { 1044 struct mbuf *m = NULL; 1045 usbd_status status; 1046 1047 KASSERT(!(sc->sc_flags & UBT_EVT_RECV), ( 1048 "%s: %s - Another interrupt request is pending\n", 1049 __func__, device_get_nameunit(sc->sc_dev))); 1050 1051 /* Allocate new mbuf cluster */ 1052 MGETHDR(m, M_DONTWAIT, MT_DATA); 1053 if (m == NULL) 1054 return (USBD_NOMEM); 1055 1056 MCLGET(m, M_DONTWAIT); 1057 if (!(m->m_flags & M_EXT)) { 1058 NG_FREE_M(m); 1059 return (USBD_NOMEM); 1060 } 1061 1062 if (!(sc->sc_flags & UBT_HAVE_FRAME_TYPE)) { 1063 *mtod(m, uint8_t *) = NG_HCI_EVENT_PKT; 1064 m->m_pkthdr.len = m->m_len = 1; 1065 } else 1066 m->m_pkthdr.len = m->m_len = 0; 1067 1068 /* Initialize a USB transfer and then schedule it */ 1069 usbd_setup_xfer( 1070 sc->sc_intr_xfer, 1071 sc->sc_intr_pipe, 1072 (usbd_private_handle) sc->sc_node, 1073 (void *)(mtod(m, uint8_t *) + m->m_len), 1074 MCLBYTES - m->m_len, 1075 USBD_SHORT_XFER_OK, 1076 USBD_NO_TIMEOUT, 1077 ubt_intr_complete); 1078 1079 NG_NODE_REF(sc->sc_node); 1080 1081 status = usbd_transfer(sc->sc_intr_xfer); 1082 if (status != USBD_NORMAL_COMPLETION && status != USBD_IN_PROGRESS) { 1083 NG_UBT_ERR( 1084 "%s: %s - Failed to start intrerrupt transfer. %s (%d)\n", 1085 __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(status), 1086 status); 1087 1088 NG_NODE_UNREF(sc->sc_node); 1089 1090 NG_FREE_M(m); 1091 1092 return (status); 1093 } 1094 1095 sc->sc_flags |= UBT_EVT_RECV; 1096 sc->sc_intr_buffer = m; 1097 1098 return (USBD_NORMAL_COMPLETION); 1099 } /* ubt_intr_start */ 1100 1101 /* 1102 * Process interrupt from USB device (We got data from interrupt pipe) 1103 */ 1104 1105 static void 1106 ubt_intr_complete(usbd_xfer_handle h, usbd_private_handle p, usbd_status s) 1107 { 1108 ng_send_fn((node_p) p, NULL, ubt_intr_complete2, (void *) h, s); 1109 NG_NODE_UNREF((node_p) p); 1110 } /* ubt_intr_complete */ 1111 1112 static void 1113 ubt_intr_complete2(node_p node, hook_p hook, void *arg1, int arg2) 1114 { 1115 ubt_softc_p sc = (ubt_softc_p) NG_NODE_PRIVATE(node); 1116 usbd_xfer_handle h = (usbd_xfer_handle) arg1; 1117 usbd_status s = (usbd_status) arg2; 1118 struct mbuf *m = NULL; 1119 ng_hci_event_pkt_t *hdr = NULL; 1120 int error; 1121 1122 if (sc == NULL) 1123 return; 1124 1125 KASSERT((sc->sc_flags & UBT_EVT_RECV), ( 1126 "%s: %s - No interrupt request is pending\n", 1127 __func__, device_get_nameunit(sc->sc_dev))); 1128 1129 sc->sc_flags &= ~UBT_EVT_RECV; 1130 1131 m = sc->sc_intr_buffer; 1132 sc->sc_intr_buffer = NULL; 1133 1134 hdr = mtod(m, ng_hci_event_pkt_t *); 1135 1136 if (sc->sc_hook == NULL || NG_HOOK_NOT_VALID(sc->sc_hook)) { 1137 NG_UBT_INFO( 1138 "%s: %s - No upstream hook\n", __func__, device_get_nameunit(sc->sc_dev)); 1139 1140 NG_FREE_M(m); 1141 return; 1142 } 1143 1144 if (s == USBD_CANCELLED) { 1145 NG_UBT_INFO( 1146 "%s: %s - Interrupt xfer cancelled\n", __func__, device_get_nameunit(sc->sc_dev)); 1147 1148 NG_FREE_M(m); 1149 return; 1150 } 1151 1152 if (s != USBD_NORMAL_COMPLETION) { 1153 NG_UBT_WARN( 1154 "%s: %s - Interrupt xfer failed, %s (%d). No new xfer will be submitted!\n", 1155 __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(s), s); 1156 1157 if (s == USBD_STALLED) 1158 usbd_clear_endpoint_stall_async(sc->sc_intr_pipe); 1159 1160 NG_UBT_STAT_IERROR(sc->sc_stat); 1161 NG_FREE_M(m); 1162 1163 return; /* XXX FIXME we should restart after some delay */ 1164 } 1165 1166 NG_UBT_STAT_BYTES_RECV(sc->sc_stat, h->actlen); 1167 m->m_pkthdr.len += h->actlen; 1168 m->m_len += h->actlen; 1169 1170 NG_UBT_INFO( 1171 "%s: %s - Got %d bytes from interrupt pipe\n", 1172 __func__, device_get_nameunit(sc->sc_dev), h->actlen); 1173 1174 if (m->m_pkthdr.len < sizeof(*hdr)) { 1175 NG_FREE_M(m); 1176 goto done; 1177 } 1178 1179 if (hdr->length == m->m_pkthdr.len - sizeof(*hdr)) { 1180 NG_UBT_INFO( 1181 "%s: %s - Got complete HCI event frame, pktlen=%d, length=%d\n", 1182 __func__, device_get_nameunit(sc->sc_dev), m->m_pkthdr.len, 1183 hdr->length); 1184 1185 NG_UBT_STAT_PCKTS_RECV(sc->sc_stat); 1186 1187 NG_SEND_DATA_ONLY(error, sc->sc_hook, m); 1188 if (error != 0) 1189 NG_UBT_STAT_IERROR(sc->sc_stat); 1190 } else { 1191 NG_UBT_ERR( 1192 "%s: %s - Invalid HCI event frame size, length=%d, pktlen=%d\n", 1193 __func__, device_get_nameunit(sc->sc_dev), hdr->length, 1194 m->m_pkthdr.len); 1195 1196 NG_UBT_STAT_IERROR(sc->sc_stat); 1197 NG_FREE_M(m); 1198 } 1199 done: 1200 ubt_intr_start(sc); 1201 } /* ubt_intr_complete2 */ 1202 1203 /* 1204 * Start bulk-in USB transfer (ACL data). Must be called when node is locked 1205 */ 1206 1207 static usbd_status 1208 ubt_bulk_in_start(ubt_softc_p sc) 1209 { 1210 struct mbuf *m = NULL; 1211 usbd_status status; 1212 1213 KASSERT(!(sc->sc_flags & UBT_ACL_RECV), ( 1214 "%s: %s - Another bulk-in request is pending\n", 1215 __func__, device_get_nameunit(sc->sc_dev))); 1216 1217 /* Allocate new mbuf cluster */ 1218 MGETHDR(m, M_DONTWAIT, MT_DATA); 1219 if (m == NULL) 1220 return (USBD_NOMEM); 1221 1222 MCLGET(m, M_DONTWAIT); 1223 if (!(m->m_flags & M_EXT)) { 1224 NG_FREE_M(m); 1225 return (USBD_NOMEM); 1226 } 1227 1228 if (!(sc->sc_flags & UBT_HAVE_FRAME_TYPE)) { 1229 *mtod(m, uint8_t *) = NG_HCI_ACL_DATA_PKT; 1230 m->m_pkthdr.len = m->m_len = 1; 1231 } else 1232 m->m_pkthdr.len = m->m_len = 0; 1233 1234 /* Initialize a bulk-in USB transfer and then schedule it */ 1235 usbd_setup_xfer( 1236 sc->sc_bulk_in_xfer, 1237 sc->sc_bulk_in_pipe, 1238 (usbd_private_handle) sc->sc_node, 1239 (void *)(mtod(m, uint8_t *) + m->m_len), 1240 MCLBYTES - m->m_len, 1241 USBD_SHORT_XFER_OK, 1242 USBD_NO_TIMEOUT, 1243 ubt_bulk_in_complete); 1244 1245 NG_NODE_REF(sc->sc_node); 1246 1247 status = usbd_transfer(sc->sc_bulk_in_xfer); 1248 if (status != USBD_NORMAL_COMPLETION && status != USBD_IN_PROGRESS) { 1249 NG_UBT_ERR( 1250 "%s: %s - Failed to start bulk-in transfer. %s (%d)\n", 1251 __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(status), 1252 status); 1253 1254 NG_NODE_UNREF(sc->sc_node); 1255 1256 NG_FREE_M(m); 1257 1258 return (status); 1259 } 1260 1261 sc->sc_flags |= UBT_ACL_RECV; 1262 sc->sc_bulk_in_buffer = m; 1263 1264 return (USBD_NORMAL_COMPLETION); 1265 } /* ubt_bulk_in_start */ 1266 1267 /* 1268 * USB bulk-in transfer callback 1269 */ 1270 1271 static void 1272 ubt_bulk_in_complete(usbd_xfer_handle h, usbd_private_handle p, usbd_status s) 1273 { 1274 ng_send_fn((node_p) p, NULL, ubt_bulk_in_complete2, (void *) h, s); 1275 NG_NODE_UNREF((node_p) p); 1276 } /* ubt_bulk_in_complete */ 1277 1278 static void 1279 ubt_bulk_in_complete2(node_p node, hook_p hook, void *arg1, int arg2) 1280 { 1281 ubt_softc_p sc = (ubt_softc_p) NG_NODE_PRIVATE(node); 1282 usbd_xfer_handle h = (usbd_xfer_handle) arg1; 1283 usbd_status s = (usbd_status) arg2; 1284 struct mbuf *m = NULL; 1285 ng_hci_acldata_pkt_t *hdr = NULL; 1286 int len; 1287 1288 if (sc == NULL) 1289 return; 1290 1291 KASSERT((sc->sc_flags & UBT_ACL_RECV), ( 1292 "%s: %s - No bulk-in request is pending\n", __func__, device_get_nameunit(sc->sc_dev))); 1293 1294 sc->sc_flags &= ~UBT_ACL_RECV; 1295 1296 m = sc->sc_bulk_in_buffer; 1297 sc->sc_bulk_in_buffer = NULL; 1298 1299 hdr = mtod(m, ng_hci_acldata_pkt_t *); 1300 1301 if (sc->sc_hook == NULL || NG_HOOK_NOT_VALID(sc->sc_hook)) { 1302 NG_UBT_INFO( 1303 "%s: %s - No upstream hook\n", __func__, device_get_nameunit(sc->sc_dev)); 1304 1305 NG_FREE_M(m); 1306 return; 1307 } 1308 1309 if (s == USBD_CANCELLED) { 1310 NG_UBT_INFO( 1311 "%s: %s - Bulk-in xfer cancelled, pipe=%p\n", 1312 __func__, device_get_nameunit(sc->sc_dev), sc->sc_bulk_in_pipe); 1313 1314 NG_FREE_M(m); 1315 return; 1316 } 1317 1318 if (s != USBD_NORMAL_COMPLETION) { 1319 NG_UBT_WARN( 1320 "%s: %s - Bulk-in xfer failed, %s (%d). No new xfer will be submitted!\n", 1321 __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(s), s); 1322 1323 if (s == USBD_STALLED) 1324 usbd_clear_endpoint_stall_async(sc->sc_bulk_in_pipe); 1325 1326 NG_UBT_STAT_IERROR(sc->sc_stat); 1327 NG_FREE_M(m); 1328 1329 return; /* XXX FIXME we should restart after some delay */ 1330 } 1331 1332 NG_UBT_STAT_BYTES_RECV(sc->sc_stat, h->actlen); 1333 m->m_pkthdr.len += h->actlen; 1334 m->m_len += h->actlen; 1335 1336 NG_UBT_INFO( 1337 "%s: %s - Got %d bytes from bulk-in pipe\n", 1338 __func__, device_get_nameunit(sc->sc_dev), h->actlen); 1339 1340 if (m->m_pkthdr.len < sizeof(*hdr)) { 1341 NG_FREE_M(m); 1342 goto done; 1343 } 1344 1345 len = le16toh(hdr->length); 1346 if (len == m->m_pkthdr.len - sizeof(*hdr)) { 1347 NG_UBT_INFO( 1348 "%s: %s - Got complete ACL data frame, pktlen=%d, length=%d\n", 1349 __func__, device_get_nameunit(sc->sc_dev), m->m_pkthdr.len, len); 1350 1351 NG_UBT_STAT_PCKTS_RECV(sc->sc_stat); 1352 1353 NG_SEND_DATA_ONLY(len, sc->sc_hook, m); 1354 if (len != 0) 1355 NG_UBT_STAT_IERROR(sc->sc_stat); 1356 } else { 1357 NG_UBT_ERR( 1358 "%s: %s - Invalid ACL frame size, length=%d, pktlen=%d\n", 1359 __func__, device_get_nameunit(sc->sc_dev), len, 1360 m->m_pkthdr.len); 1361 1362 NG_UBT_STAT_IERROR(sc->sc_stat); 1363 NG_FREE_M(m); 1364 } 1365 done: 1366 ubt_bulk_in_start(sc); 1367 } /* ubt_bulk_in_complete2 */ 1368 1369 /* 1370 * Start bulk-out USB transfer. Must be called with node locked 1371 */ 1372 1373 static usbd_status 1374 ubt_bulk_out_start(ubt_softc_p sc) 1375 { 1376 struct mbuf *m = NULL; 1377 usbd_status status; 1378 1379 KASSERT(!(sc->sc_flags & UBT_ACL_XMIT), ( 1380 "%s: %s - Another bulk-out request is pending\n", 1381 __func__, device_get_nameunit(sc->sc_dev))); 1382 1383 NG_BT_MBUFQ_DEQUEUE(&sc->sc_aclq, m); 1384 if (m == NULL) { 1385 NG_UBT_INFO( 1386 "%s: %s - ACL data queue is empty\n", __func__, device_get_nameunit(sc->sc_dev)); 1387 1388 return (USBD_NORMAL_COMPLETION); 1389 } 1390 1391 /* 1392 * Check ACL data frame size and copy it back to linear USB 1393 * transfer buffer. 1394 */ 1395 1396 if (m->m_pkthdr.len > UBT_BULK_BUFFER_SIZE) 1397 panic( 1398 "%s: %s - ACL data frame too big, size=%d, len=%d\n", 1399 __func__, device_get_nameunit(sc->sc_dev), UBT_BULK_BUFFER_SIZE, 1400 m->m_pkthdr.len); 1401 1402 m_copydata(m, 0, m->m_pkthdr.len, sc->sc_bulk_out_buffer); 1403 1404 /* Initialize a bulk-out USB transfer and then schedule it */ 1405 usbd_setup_xfer( 1406 sc->sc_bulk_out_xfer, 1407 sc->sc_bulk_out_pipe, 1408 (usbd_private_handle) sc->sc_node, 1409 sc->sc_bulk_out_buffer, 1410 m->m_pkthdr.len, 1411 USBD_NO_COPY, 1412 USBD_DEFAULT_TIMEOUT, /* XXX */ 1413 ubt_bulk_out_complete); 1414 1415 NG_NODE_REF(sc->sc_node); 1416 1417 status = usbd_transfer(sc->sc_bulk_out_xfer); 1418 if (status != USBD_NORMAL_COMPLETION && status != USBD_IN_PROGRESS) { 1419 NG_UBT_ERR( 1420 "%s: %s - Could not start bulk-out transfer. %s (%d)\n", 1421 __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(status), 1422 status); 1423 1424 NG_NODE_UNREF(sc->sc_node); 1425 1426 NG_BT_MBUFQ_DROP(&sc->sc_aclq); 1427 NG_UBT_STAT_OERROR(sc->sc_stat); 1428 1429 /* XXX FIXME should we try to start another transfer? */ 1430 } else { 1431 NG_UBT_INFO( 1432 "%s: %s - Bulk-out transfer has been started, len=%d\n", 1433 __func__, device_get_nameunit(sc->sc_dev), m->m_pkthdr.len); 1434 1435 sc->sc_flags |= UBT_ACL_XMIT; 1436 status = USBD_NORMAL_COMPLETION; 1437 } 1438 1439 NG_FREE_M(m); 1440 1441 return (status); 1442 } /* ubt_bulk_out_start */ 1443 1444 /* 1445 * USB bulk-out transfer callback 1446 */ 1447 1448 static void 1449 ubt_bulk_out_complete(usbd_xfer_handle h, usbd_private_handle p, usbd_status s) 1450 { 1451 ng_send_fn((node_p) p, NULL, ubt_bulk_out_complete2, (void *) h, s); 1452 NG_NODE_UNREF((node_p) p); 1453 } /* ubt_bulk_out_complete */ 1454 1455 static void 1456 ubt_bulk_out_complete2(node_p node, hook_p hook, void *arg1, int arg2) 1457 { 1458 ubt_softc_p sc = (ubt_softc_p) NG_NODE_PRIVATE(node); 1459 usbd_xfer_handle h = (usbd_xfer_handle) arg1; 1460 usbd_status s = (usbd_status) arg2; 1461 1462 if (sc == NULL) 1463 return; 1464 1465 KASSERT((sc->sc_flags & UBT_ACL_XMIT), ( 1466 "%s: %s - No bulk-out request is pending\n", __func__, device_get_nameunit(sc->sc_dev))); 1467 1468 sc->sc_flags &= ~UBT_ACL_XMIT; 1469 1470 if (s == USBD_CANCELLED) { 1471 NG_UBT_INFO( 1472 "%s: %s - Bulk-out xfer cancelled, pipe=%p\n", 1473 __func__, device_get_nameunit(sc->sc_dev), sc->sc_bulk_out_pipe); 1474 1475 return; 1476 } 1477 1478 if (s != USBD_NORMAL_COMPLETION) { 1479 NG_UBT_WARN( 1480 "%s: %s - Bulk-out xfer failed. %s (%d)\n", 1481 __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(s), s); 1482 1483 if (s == USBD_STALLED) 1484 usbd_clear_endpoint_stall_async(sc->sc_bulk_out_pipe); 1485 1486 NG_UBT_STAT_OERROR(sc->sc_stat); 1487 } else { 1488 NG_UBT_INFO( 1489 "%s: %s - Sent %d bytes to bulk-out pipe\n", 1490 __func__, device_get_nameunit(sc->sc_dev), h->actlen); 1491 1492 NG_UBT_STAT_BYTES_SENT(sc->sc_stat, h->actlen); 1493 NG_UBT_STAT_PCKTS_SENT(sc->sc_stat); 1494 } 1495 1496 if (NG_BT_MBUFQ_LEN(&sc->sc_aclq) > 0) 1497 ubt_bulk_out_start(sc); 1498 } /* ubt_bulk_out_complete2 */ 1499 1500 /* 1501 * Start non-active Isochronous-in USB transfer. 1502 * Must be called with node locked 1503 */ 1504 1505 static usbd_status 1506 ubt_isoc_in_start_one(ubt_softc_p sc, int idx) 1507 { 1508 usbd_status status; 1509 int i; 1510 1511 for (i = 0; i < NG_UBT_NFRAMES; i++) 1512 sc->sc_isoc_in[idx].frlen[i] = sc->sc_isoc_size; 1513 1514 usbd_setup_isoc_xfer( 1515 sc->sc_isoc_in[idx].xfer, 1516 sc->sc_isoc_in_pipe, 1517 (usbd_private_handle) sc->sc_node, 1518 sc->sc_isoc_in[idx].frlen, 1519 NG_UBT_NFRAMES, 1520 USBD_NO_COPY | USBD_SHORT_XFER_OK, 1521 ubt_isoc_in_complete); 1522 1523 NG_NODE_REF(sc->sc_node); 1524 1525 status = usbd_transfer(sc->sc_isoc_in[idx].xfer); 1526 if (status != USBD_NORMAL_COMPLETION && status != USBD_IN_PROGRESS) { 1527 NG_UBT_ERR( 1528 "%s: %s - Failed to start isoc-in transfer. %s (%d)\n", 1529 __func__, device_get_nameunit(sc->sc_dev), 1530 usbd_errstr(status), status); 1531 1532 NG_NODE_UNREF(sc->sc_node); 1533 } else 1534 sc->sc_isoc_in[idx].active = 1; 1535 1536 return (status); 1537 } 1538 1539 /* 1540 * (Re)Start all non-active Isochronous-in USB transfers. 1541 * Must be called with node locked. 1542 */ 1543 1544 static usbd_status 1545 ubt_isoc_in_start(ubt_softc_p sc) 1546 { 1547 int i; 1548 1549 for (i = 0; i < NG_UBT_NXFERS; i++) 1550 if (!sc->sc_isoc_in[i].active) 1551 ubt_isoc_in_start_one(sc, i); 1552 1553 return (USBD_NORMAL_COMPLETION); 1554 } /* ubt_isoc_in_start */ 1555 1556 /* 1557 * USB isochronous transfer callback 1558 */ 1559 1560 static void 1561 ubt_isoc_in_complete(usbd_xfer_handle h, usbd_private_handle p, usbd_status s) 1562 { 1563 ng_send_fn((node_p) p, NULL, ubt_isoc_in_complete2, (void *) h, s); 1564 NG_NODE_UNREF((node_p) p); 1565 } /* ubt_isoc_in_complete */ 1566 1567 static void 1568 ubt_isoc_in_complete2(node_p node, hook_p hook, void *arg1, int arg2) 1569 { 1570 ubt_softc_p sc = (ubt_softc_p) NG_NODE_PRIVATE(node); 1571 usbd_xfer_handle h = (usbd_xfer_handle) arg1; 1572 usbd_status s = (usbd_status) arg2; 1573 int i, idx, want, got; 1574 struct mbuf *m; 1575 1576 if (sc == NULL) 1577 return; 1578 1579 /* Find xfer */ 1580 idx = -1; 1581 for (i = 0; i < NG_UBT_NXFERS; i++) { 1582 if (sc->sc_isoc_in[i].xfer == h) { 1583 idx = i; 1584 break; 1585 } 1586 } 1587 KASSERT(idx != -1, ( 1588 "%s:%s - Could not find isoc-in request\n", 1589 __func__, device_get_nameunit(sc->sc_dev))); 1590 KASSERT(sc->sc_isoc_in[idx].active, ( 1591 "%s: %s - Isoc-in request is not active\n", 1592 __func__, device_get_nameunit(sc->sc_dev))); 1593 1594 sc->sc_isoc_in[idx].active = 0; 1595 1596 if (sc->sc_hook == NULL || NG_HOOK_NOT_VALID(sc->sc_hook)) { 1597 NG_UBT_INFO( 1598 "%s: %s - No upstream hook\n", __func__, device_get_nameunit(sc->sc_dev)); 1599 1600 return; 1601 } 1602 1603 /* Process xfer */ 1604 if (s == USBD_CANCELLED) { 1605 NG_UBT_INFO( 1606 "%s: %s - Isoc-in xfer cancelled, pipe=%p\n", 1607 __func__, device_get_nameunit(sc->sc_dev), sc->sc_isoc_in_pipe); 1608 1609 return; 1610 } 1611 1612 if (s != USBD_NORMAL_COMPLETION) { 1613 NG_UBT_WARN( 1614 "%s: %s - Isoc-in xfer failed, %s (%d). No new xfer will be submitted!\n", 1615 __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(s), s); 1616 1617 if (s == USBD_STALLED) 1618 usbd_clear_endpoint_stall_async(sc->sc_isoc_in_pipe); 1619 1620 NG_UBT_STAT_IERROR(sc->sc_stat); 1621 1622 return; /* XXX FIXME we should restart after some delay */ 1623 } 1624 1625 if (h->actlen <= 0) 1626 goto done; 1627 1628 NG_UBT_INFO( 1629 "%s: %s - Got %d bytes from isoc-in pipe\n", 1630 __func__, device_get_nameunit(sc->sc_dev), h->actlen); 1631 1632 /* 1633 * Re-assemble SCO HCI frame 1634 */ 1635 1636 m = sc->sc_isoc_in_buffer; 1637 sc->sc_isoc_in_buffer = NULL; 1638 1639 for (i = 0; i < NG_UBT_NFRAMES; i ++) { 1640 uint8_t *frame = (uint8_t *) sc->sc_isoc_in[idx].buffer + 1641 (i * sc->sc_isoc_size); 1642 1643 while (sc->sc_isoc_in[idx].frlen[i] > 0) { 1644 int error, frlen = sc->sc_isoc_in[idx].frlen[i]; 1645 1646 if (m == NULL) { 1647 MGETHDR(m, M_DONTWAIT, MT_DATA); 1648 if (m == NULL) { 1649 goto done; /* XXX out of sync! */ 1650 } 1651 1652 MCLGET(m, M_DONTWAIT); 1653 if (!(m->m_flags & M_EXT)) { 1654 NG_FREE_M(m); 1655 goto done; /* XXX out of sync! */ 1656 } 1657 1658 if (!(sc->sc_flags & UBT_HAVE_FRAME_TYPE)) { 1659 *mtod(m, uint8_t *) = NG_HCI_SCO_DATA_PKT; 1660 m->m_pkthdr.len = m->m_len = got = 1; 1661 } else { 1662 m->m_pkthdr.len = m->m_len = got = 0; 1663 } 1664 1665 want = sizeof(ng_hci_scodata_pkt_t); 1666 } else { 1667 got = m->m_pkthdr.len; 1668 want = sizeof(ng_hci_scodata_pkt_t); 1669 1670 if (got >= want) 1671 want += mtod(m, ng_hci_scodata_pkt_t *)->length; 1672 } 1673 1674 if (got + frlen > want) 1675 frlen = want - got; 1676 1677 if (!m_append(m, frlen, frame)) { 1678 NG_FREE_M(m); 1679 goto done; /* XXX out of sync! */ 1680 } 1681 1682 got += frlen; 1683 frame += frlen; 1684 sc->sc_isoc_in[idx].frlen[i] -= frlen; 1685 1686 if (got != want) 1687 continue; 1688 1689 if (want == sizeof(ng_hci_scodata_pkt_t)) 1690 want += mtod(m, ng_hci_scodata_pkt_t *)->length; 1691 1692 if (got != want) 1693 continue; 1694 1695 NG_UBT_INFO( 1696 "%s: %s - Got complete SCO data frame, pktlen=%d, length=%d\n", 1697 __func__, device_get_nameunit(sc->sc_dev), 1698 m->m_pkthdr.len, 1699 mtod(m, ng_hci_scodata_pkt_t *)->length); 1700 1701 NG_UBT_STAT_PCKTS_RECV(sc->sc_stat); 1702 NG_UBT_STAT_BYTES_RECV(sc->sc_stat, m->m_pkthdr.len); 1703 1704 NG_SEND_DATA_ONLY(error, sc->sc_hook, m); 1705 if (error != 0) 1706 NG_UBT_STAT_IERROR(sc->sc_stat); 1707 } 1708 } 1709 1710 sc->sc_isoc_in_buffer = m; 1711 done: 1712 ubt_isoc_in_start_one(sc, idx); 1713 } /* ubt_isoc_in_complete2 */ 1714 1715 /* 1716 * Start non-active isochronous-out USB transfer. 1717 * Must be called with node locked 1718 */ 1719 1720 static usbd_status 1721 ubt_isoc_out_start_one(ubt_softc_p sc, int idx) 1722 { 1723 int len, maxlen, size, nframes; 1724 struct mbuf *m; 1725 uint8_t *buffer; 1726 usbd_status status; 1727 1728 /* 1729 * Fill the transfer buffer with data from the queue, 1730 * putting any leftover back on the queue 1731 */ 1732 1733 len = 0; 1734 maxlen = NG_UBT_NFRAMES * sc->sc_isoc_size; 1735 m = NULL; 1736 buffer = sc->sc_isoc_out[idx].buffer; 1737 1738 while (maxlen > 0) { 1739 if (m == NULL) { 1740 NG_BT_MBUFQ_DEQUEUE(&sc->sc_scoq, m); 1741 if (m == NULL) 1742 break; 1743 } 1744 1745 if (m->m_pkthdr.len > 0) { 1746 size = MIN(m->m_pkthdr.len, maxlen); 1747 1748 m_copydata(m, 0, size, buffer); 1749 m_adj(m, size); 1750 1751 buffer += size; 1752 len += size; 1753 maxlen -= size; 1754 } 1755 1756 if (m->m_pkthdr.len == 0) { 1757 NG_UBT_STAT_PCKTS_SENT(sc->sc_stat); 1758 NG_FREE_M(m); 1759 } 1760 } 1761 1762 if (m != NULL) 1763 NG_BT_MBUFQ_PREPEND(&sc->sc_scoq, m); 1764 1765 if (len == 0) 1766 return (USBD_NORMAL_COMPLETION); /* nothing to send */ 1767 1768 NG_UBT_STAT_BYTES_SENT(sc->sc_stat, len); 1769 1770 /* Calculate number of isoc frames and sizes */ 1771 for (nframes = 0; len > 0; nframes ++) { 1772 size = MIN(sc->sc_isoc_size, len); 1773 sc->sc_isoc_out[idx].frlen[nframes] = size; 1774 len -= size; 1775 } 1776 1777 /* Initialize a isoc-out USB transfer and then schedule it */ 1778 usbd_setup_isoc_xfer( 1779 sc->sc_isoc_out[idx].xfer, 1780 sc->sc_isoc_out_pipe, 1781 (usbd_private_handle) sc->sc_node, 1782 sc->sc_isoc_out[idx].frlen, 1783 nframes, 1784 USBD_NO_COPY | USBD_FORCE_SHORT_XFER, 1785 ubt_isoc_out_complete); 1786 1787 NG_NODE_REF(sc->sc_node); 1788 sc->sc_isoc_out[idx].active = 1; 1789 1790 status = usbd_transfer(sc->sc_isoc_out[idx].xfer); 1791 if (status != USBD_NORMAL_COMPLETION && status != USBD_IN_PROGRESS) { 1792 NG_UBT_ERR( 1793 "%s: %s - Could not start isoc-out transfer. %s (%d)\n", 1794 __func__, device_get_nameunit(sc->sc_dev), 1795 usbd_errstr(status), status); 1796 1797 sc->sc_isoc_out[idx].active = 0; 1798 NG_NODE_UNREF(sc->sc_node); 1799 1800 NG_UBT_STAT_OERROR(sc->sc_stat); 1801 } else { 1802 NG_UBT_INFO( 1803 "%s: %s - Isoc-out transfer has been started, nframes=%d, size=%d\n", 1804 __func__, device_get_nameunit(sc->sc_dev), nframes, 1805 sc->sc_isoc_size); 1806 status = USBD_NORMAL_COMPLETION; 1807 } 1808 1809 return (status); 1810 } 1811 1812 /* 1813 * Start all non-active isochronous-out USB transfer. 1814 * Must be called with node locked 1815 */ 1816 1817 static usbd_status 1818 ubt_isoc_out_start(ubt_softc_p sc) 1819 { 1820 int i; 1821 1822 for (i = 0; i < NG_UBT_NXFERS; i++) { 1823 if (sc->sc_isoc_out[i].active) 1824 continue; 1825 1826 ubt_isoc_out_start_one(sc, i); 1827 } 1828 1829 return (USBD_NORMAL_COMPLETION); 1830 } /* ubt_isoc_out_start */ 1831 1832 /* 1833 * USB isoc-out. transfer callback 1834 */ 1835 1836 static void 1837 ubt_isoc_out_complete(usbd_xfer_handle h, usbd_private_handle p, usbd_status s) 1838 { 1839 ng_send_fn((node_p) p, NULL, ubt_isoc_out_complete2, (void *) h, s); 1840 NG_NODE_UNREF((node_p) p); 1841 } /* ubt_isoc_out_complete */ 1842 1843 static void 1844 ubt_isoc_out_complete2(node_p node, hook_p hook, void *arg1, int arg2) 1845 { 1846 ubt_softc_p sc = (ubt_softc_p) NG_NODE_PRIVATE(node); 1847 usbd_xfer_handle h = (usbd_xfer_handle) arg1; 1848 usbd_status s = (usbd_status) arg2; 1849 int i, idx; 1850 1851 if (sc == NULL) 1852 return; 1853 1854 /* Find xfer */ 1855 idx = -1; 1856 for (i = 0; i < NG_UBT_NXFERS; i++) { 1857 if (sc->sc_isoc_out[i].xfer == h) { 1858 idx = i; 1859 break; 1860 } 1861 } 1862 KASSERT(idx != -1, ( 1863 "%s:%s - Could not find isoc-out request\n", 1864 __func__, device_get_nameunit(sc->sc_dev))); 1865 KASSERT(sc->sc_isoc_out[idx].active, ( 1866 "%s: %s - Isoc-out request is not active\n", 1867 __func__, device_get_nameunit(sc->sc_dev))); 1868 1869 sc->sc_isoc_out[idx].active = 0; 1870 1871 /* Process xfer */ 1872 if (s == USBD_CANCELLED) { 1873 NG_UBT_INFO( 1874 "%s: %s - Isoc-out xfer cancelled, pipe=%p\n", 1875 __func__, device_get_nameunit(sc->sc_dev), 1876 sc->sc_isoc_out_pipe); 1877 1878 return; 1879 } 1880 1881 if (s != USBD_NORMAL_COMPLETION) { 1882 NG_UBT_WARN( 1883 "%s: %s - Isoc-out xfer failed. %s (%d)\n", 1884 __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(s), s); 1885 1886 if (s == USBD_STALLED) 1887 usbd_clear_endpoint_stall_async(sc->sc_isoc_out_pipe); 1888 1889 NG_UBT_STAT_OERROR(sc->sc_stat); 1890 } else { 1891 NG_UBT_INFO( 1892 "%s: %s - Sent %d bytes to isoc-out pipe\n", 1893 __func__, device_get_nameunit(sc->sc_dev), h->actlen); 1894 1895 /* XXX FIXME NG_UBT_STAT_BYTES_SENT(sc->sc_stat, h->actlen); 1896 NG_UBT_STAT_PCKTS_SENT(sc->sc_stat); */ 1897 } 1898 1899 if (NG_BT_MBUFQ_LEN(&sc->sc_scoq) > 0) 1900 ubt_isoc_out_start(sc); 1901 } /* ubt_isoc_out_complete2 */ 1902 1903 /* 1904 * Abort transfers on all USB pipes 1905 */ 1906 1907 static void 1908 ubt_reset(ubt_softc_p sc) 1909 { 1910 /* Interrupt */ 1911 if (sc->sc_intr_pipe != NULL) 1912 usbd_abort_pipe(sc->sc_intr_pipe); 1913 1914 /* Bulk-in/out */ 1915 if (sc->sc_bulk_in_pipe != NULL) 1916 usbd_abort_pipe(sc->sc_bulk_in_pipe); 1917 if (sc->sc_bulk_out_pipe != NULL) 1918 usbd_abort_pipe(sc->sc_bulk_out_pipe); 1919 1920 /* Isoc-in/out */ 1921 if (sc->sc_isoc_in_pipe != NULL) 1922 usbd_abort_pipe(sc->sc_isoc_in_pipe); 1923 if (sc->sc_isoc_out_pipe != NULL) 1924 usbd_abort_pipe(sc->sc_isoc_out_pipe); 1925 1926 /* Cleanup queues */ 1927 NG_BT_MBUFQ_DRAIN(&sc->sc_cmdq); 1928 NG_BT_MBUFQ_DRAIN(&sc->sc_aclq); 1929 NG_BT_MBUFQ_DRAIN(&sc->sc_scoq); 1930 } /* ubt_reset */ 1931 1932 /**************************************************************************** 1933 **************************************************************************** 1934 ** Netgraph specific 1935 **************************************************************************** 1936 ****************************************************************************/ 1937 1938 /* 1939 * Netgraph node constructor. Do not allow to create node of this type. 1940 */ 1941 1942 static int 1943 ng_ubt_constructor(node_p node) 1944 { 1945 return (EINVAL); 1946 } /* ng_ubt_constructor */ 1947 1948 /* 1949 * Netgraph node destructor. Destroy node only when device has been detached 1950 */ 1951 1952 static int 1953 ng_ubt_shutdown(node_p node) 1954 { 1955 ubt_softc_p sc = (ubt_softc_p) NG_NODE_PRIVATE(node); 1956 1957 /* Let old node go */ 1958 NG_NODE_SET_PRIVATE(node, NULL); 1959 NG_NODE_UNREF(node); 1960 1961 if (sc == NULL) 1962 goto done; 1963 1964 /* Create Netgraph node */ 1965 if (ng_make_node_common(&typestruct, &sc->sc_node) != 0) { 1966 printf("%s: Could not create Netgraph node\n", 1967 device_get_nameunit(sc->sc_dev)); 1968 sc->sc_node = NULL; 1969 goto done; 1970 } 1971 1972 /* Name node */ 1973 if (ng_name_node(sc->sc_node, device_get_nameunit(sc->sc_dev)) != 0) { 1974 printf("%s: Could not name Netgraph node\n", 1975 device_get_nameunit(sc->sc_dev)); 1976 NG_NODE_UNREF(sc->sc_node); 1977 sc->sc_node = NULL; 1978 goto done; 1979 } 1980 1981 NG_NODE_SET_PRIVATE(sc->sc_node, sc); 1982 NG_NODE_FORCE_WRITER(sc->sc_node); 1983 done: 1984 return (0); 1985 } /* ng_ubt_shutdown */ 1986 1987 /* 1988 * Create new hook. There can only be one. 1989 */ 1990 1991 static int 1992 ng_ubt_newhook(node_p node, hook_p hook, char const *name) 1993 { 1994 ubt_softc_p sc = (ubt_softc_p) NG_NODE_PRIVATE(node); 1995 1996 if (strcmp(name, NG_UBT_HOOK) != 0) 1997 return (EINVAL); 1998 1999 if (sc->sc_hook != NULL) 2000 return (EISCONN); 2001 2002 sc->sc_hook = hook; 2003 2004 return (0); 2005 } /* ng_ubt_newhook */ 2006 2007 /* 2008 * Connect hook. Start incoming USB transfers 2009 */ 2010 2011 static int 2012 ng_ubt_connect(hook_p hook) 2013 { 2014 ubt_softc_p sc = (ubt_softc_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 2015 usbd_status status; 2016 2017 NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook)); 2018 2019 /* Start intr transfer */ 2020 status = ubt_intr_start(sc); 2021 if (status != USBD_NORMAL_COMPLETION) { 2022 NG_UBT_ALERT( 2023 "%s: %s - Could not start interrupt transfer. %s (%d)\n", 2024 __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(status), 2025 status); 2026 goto fail; 2027 } 2028 2029 /* Start bulk-in transfer */ 2030 status = ubt_bulk_in_start(sc); 2031 if (status != USBD_NORMAL_COMPLETION) { 2032 NG_UBT_ALERT( 2033 "%s: %s - Could not start bulk-in transfer. %s (%d)\n", 2034 __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(status), 2035 status); 2036 goto fail; 2037 } 2038 2039 /* Start isoc-in transfer */ 2040 status = ubt_isoc_in_start(sc); 2041 if (status != USBD_NORMAL_COMPLETION) { 2042 NG_UBT_ALERT( 2043 "%s: %s - Could not start isoc-in transfer. %s (%d)\n", 2044 __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(status), 2045 status); 2046 goto fail; 2047 } 2048 2049 return (0); 2050 fail: 2051 ubt_reset(sc); 2052 sc->sc_hook = NULL; 2053 2054 return (ENXIO); 2055 } /* ng_ubt_connect */ 2056 2057 /* 2058 * Disconnect hook 2059 */ 2060 2061 static int 2062 ng_ubt_disconnect(hook_p hook) 2063 { 2064 ubt_softc_p sc = (ubt_softc_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 2065 2066 if (sc != NULL) { 2067 if (hook != sc->sc_hook) 2068 return (EINVAL); 2069 2070 ubt_reset(sc); 2071 sc->sc_hook = NULL; 2072 } 2073 2074 return (0); 2075 } /* ng_ubt_disconnect */ 2076 2077 /* 2078 * Process control message 2079 */ 2080 2081 static int 2082 ng_ubt_rcvmsg(node_p node, item_p item, hook_p lasthook) 2083 { 2084 ubt_softc_p sc = (ubt_softc_p) NG_NODE_PRIVATE(node); 2085 struct ng_mesg *msg = NULL, *rsp = NULL; 2086 struct ng_bt_mbufq *q = NULL; 2087 int error = 0, queue, qlen; 2088 2089 if (sc == NULL) { 2090 NG_FREE_ITEM(item); 2091 return (EHOSTDOWN); 2092 } 2093 2094 NGI_GET_MSG(item, msg); 2095 2096 switch (msg->header.typecookie) { 2097 case NGM_GENERIC_COOKIE: 2098 switch (msg->header.cmd) { 2099 case NGM_TEXT_STATUS: 2100 NG_MKRESPONSE(rsp, msg, NG_TEXTRESPONSE, M_NOWAIT); 2101 if (rsp == NULL) 2102 error = ENOMEM; 2103 else 2104 snprintf(rsp->data, NG_TEXTRESPONSE, 2105 "Hook: %s\n" \ 2106 "Flags: %#x\n" \ 2107 "Debug: %d\n" \ 2108 "CMD queue: [have:%d,max:%d]\n" \ 2109 "ACL queue: [have:%d,max:%d]\n" \ 2110 "SCO queue: [have:%d,max:%d]", 2111 (sc->sc_hook != NULL)? NG_UBT_HOOK : "", 2112 sc->sc_flags, 2113 sc->sc_debug, 2114 NG_BT_MBUFQ_LEN(&sc->sc_cmdq), 2115 sc->sc_cmdq.maxlen, 2116 NG_BT_MBUFQ_LEN(&sc->sc_aclq), 2117 sc->sc_aclq.maxlen, 2118 NG_BT_MBUFQ_LEN(&sc->sc_scoq), 2119 sc->sc_scoq.maxlen); 2120 break; 2121 2122 default: 2123 error = EINVAL; 2124 break; 2125 } 2126 break; 2127 2128 case NGM_UBT_COOKIE: 2129 switch (msg->header.cmd) { 2130 case NGM_UBT_NODE_SET_DEBUG: 2131 if (msg->header.arglen != sizeof(ng_ubt_node_debug_ep)) 2132 error = EMSGSIZE; 2133 else 2134 sc->sc_debug = 2135 *((ng_ubt_node_debug_ep *)(msg->data)); 2136 break; 2137 2138 case NGM_UBT_NODE_GET_DEBUG: 2139 NG_MKRESPONSE(rsp, msg, sizeof(ng_ubt_node_debug_ep), 2140 M_NOWAIT); 2141 if (rsp == NULL) 2142 error = ENOMEM; 2143 else 2144 *((ng_ubt_node_debug_ep *)(rsp->data)) = 2145 sc->sc_debug; 2146 break; 2147 2148 case NGM_UBT_NODE_SET_QLEN: 2149 if (msg->header.arglen != sizeof(ng_ubt_node_qlen_ep)) 2150 error = EMSGSIZE; 2151 else { 2152 queue = ((ng_ubt_node_qlen_ep *) 2153 (msg->data))->queue; 2154 qlen = ((ng_ubt_node_qlen_ep *) 2155 (msg->data))->qlen; 2156 2157 if (qlen <= 0) { 2158 error = EINVAL; 2159 break; 2160 } 2161 2162 switch (queue) { 2163 case NGM_UBT_NODE_QUEUE_CMD: 2164 q = &sc->sc_cmdq; 2165 break; 2166 2167 case NGM_UBT_NODE_QUEUE_ACL: 2168 q = &sc->sc_aclq; 2169 break; 2170 2171 case NGM_UBT_NODE_QUEUE_SCO: 2172 q = &sc->sc_scoq; 2173 break; 2174 2175 default: 2176 q = NULL; 2177 error = EINVAL; 2178 break; 2179 } 2180 2181 if (q != NULL) 2182 q->maxlen = qlen; 2183 } 2184 break; 2185 2186 case NGM_UBT_NODE_GET_QLEN: 2187 if (msg->header.arglen != sizeof(ng_ubt_node_qlen_ep)) { 2188 error = EMSGSIZE; 2189 break; 2190 } 2191 2192 queue = ((ng_ubt_node_qlen_ep *)(msg->data))->queue; 2193 switch (queue) { 2194 case NGM_UBT_NODE_QUEUE_CMD: 2195 q = &sc->sc_cmdq; 2196 break; 2197 2198 case NGM_UBT_NODE_QUEUE_ACL: 2199 q = &sc->sc_aclq; 2200 break; 2201 2202 case NGM_UBT_NODE_QUEUE_SCO: 2203 q = &sc->sc_scoq; 2204 break; 2205 2206 default: 2207 q = NULL; 2208 error = EINVAL; 2209 break; 2210 } 2211 2212 if (q != NULL) { 2213 NG_MKRESPONSE(rsp, msg, 2214 sizeof(ng_ubt_node_qlen_ep), M_NOWAIT); 2215 if (rsp == NULL) { 2216 error = ENOMEM; 2217 break; 2218 } 2219 2220 ((ng_ubt_node_qlen_ep *)(rsp->data))->queue = 2221 queue; 2222 ((ng_ubt_node_qlen_ep *)(rsp->data))->qlen = 2223 q->maxlen; 2224 } 2225 break; 2226 2227 case NGM_UBT_NODE_GET_STAT: 2228 NG_MKRESPONSE(rsp, msg, sizeof(ng_ubt_node_stat_ep), 2229 M_NOWAIT); 2230 if (rsp == NULL) 2231 error = ENOMEM; 2232 else 2233 bcopy(&sc->sc_stat, rsp->data, 2234 sizeof(ng_ubt_node_stat_ep)); 2235 break; 2236 2237 case NGM_UBT_NODE_RESET_STAT: 2238 NG_UBT_STAT_RESET(sc->sc_stat); 2239 break; 2240 2241 default: 2242 error = EINVAL; 2243 break; 2244 } 2245 break; 2246 2247 default: 2248 error = EINVAL; 2249 break; 2250 } 2251 2252 NG_RESPOND_MSG(error, node, item, rsp); 2253 NG_FREE_MSG(msg); 2254 2255 return (error); 2256 } /* ng_ubt_rcvmsg */ 2257 2258 /* 2259 * Process data 2260 */ 2261 2262 static int 2263 ng_ubt_rcvdata(hook_p hook, item_p item) 2264 { 2265 ubt_softc_p sc = (ubt_softc_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 2266 struct mbuf *m = NULL; 2267 usbd_status (*f)(ubt_softc_p) = NULL; 2268 struct ng_bt_mbufq *q = NULL; 2269 int b, error = 0; 2270 2271 if (sc == NULL) { 2272 error = EHOSTDOWN; 2273 goto done; 2274 } 2275 2276 if (hook != sc->sc_hook) { 2277 error = EINVAL; 2278 goto done; 2279 } 2280 2281 /* Deatch mbuf and get HCI frame type */ 2282 NGI_GET_M(item, m); 2283 2284 /* Process HCI frame */ 2285 switch (*mtod(m, uint8_t *)) { /* XXX call m_pullup ? */ 2286 case NG_HCI_CMD_PKT: 2287 f = ubt_request_start; 2288 q = &sc->sc_cmdq; 2289 b = UBT_CMD_XMIT; 2290 break; 2291 2292 case NG_HCI_ACL_DATA_PKT: 2293 f = ubt_bulk_out_start; 2294 q = &sc->sc_aclq; 2295 b = UBT_ACL_XMIT; 2296 break; 2297 2298 case NG_HCI_SCO_DATA_PKT: 2299 f = ubt_isoc_out_start; 2300 q = &sc->sc_scoq; 2301 b = UBT_SCO_XMIT; 2302 break; 2303 2304 default: 2305 NG_UBT_ERR( 2306 "%s: %s - Dropping unknown/unsupported HCI frame, type=%d, pktlen=%d\n", 2307 __func__, device_get_nameunit(sc->sc_dev), *mtod(m, uint8_t *), 2308 m->m_pkthdr.len); 2309 2310 NG_FREE_M(m); 2311 error = EINVAL; 2312 2313 goto done; 2314 /* NOT REACHED */ 2315 } 2316 2317 /* Loose frame type, if required */ 2318 if (!(sc->sc_flags & UBT_NEED_FRAME_TYPE)) 2319 m_adj(m, sizeof(uint8_t)); 2320 2321 if (NG_BT_MBUFQ_FULL(q)) { 2322 NG_UBT_ERR( 2323 "%s: %s - Dropping HCI frame %#x, len=%d. Queue full\n", 2324 __func__, device_get_nameunit(sc->sc_dev), 2325 *mtod(m, uint8_t *), m->m_pkthdr.len); 2326 2327 NG_FREE_M(m); 2328 } else 2329 NG_BT_MBUFQ_ENQUEUE(q, m); 2330 2331 if (!(sc->sc_flags & b)) 2332 if ((*f)(sc) != USBD_NORMAL_COMPLETION) 2333 error = EIO; 2334 done: 2335 NG_FREE_ITEM(item); 2336 2337 return (error); 2338 } /* ng_ubt_rcvdata */ 2339 2340