ng_ubt.c revision 190728
1184610Salfred/* 2184610Salfred * ng_ubt.c 3184610Salfred */ 4184610Salfred 5184610Salfred/*- 6187494Semax * Copyright (c) 2001-2009 Maksim Yevmenkin <m_evmenkin@yahoo.com> 7184610Salfred * All rights reserved. 8184610Salfred * 9184610Salfred * Redistribution and use in source and binary forms, with or without 10184610Salfred * modification, are permitted provided that the following conditions 11184610Salfred * are met: 12184610Salfred * 1. Redistributions of source code must retain the above copyright 13184610Salfred * notice, this list of conditions and the following disclaimer. 14184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 15184610Salfred * notice, this list of conditions and the following disclaimer in the 16184610Salfred * documentation and/or other materials provided with the distribution. 17184610Salfred * 18184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28184610Salfred * SUCH DAMAGE. 29184610Salfred * 30184610Salfred * $Id: ng_ubt.c,v 1.16 2003/10/10 19:15:06 max Exp $ 31184610Salfred * $FreeBSD: head/sys/dev/usb/bluetooth/ng_ubt.c 190728 2009-04-05 18:19:30Z thompsa $ 32184610Salfred */ 33184610Salfred 34187494Semax/* 35187494Semax * NOTE: ng_ubt2 driver has a split personality. On one side it is 36187741Semax * a USB device driver and on the other it is a Netgraph node. This 37187494Semax * driver will *NOT* create traditional /dev/ enties, only Netgraph 38187494Semax * node. 39187494Semax * 40187741Semax * NOTE ON LOCKS USED: ng_ubt2 drives uses 2 locks (mutexes) 41187494Semax * 42187741Semax * 1) sc_if_mtx - lock for device's interface #0 and #1. This lock is used 43187741Semax * by USB for any USB request going over device's interface #0 and #1, 44187741Semax * i.e. interrupt, control, bulk and isoc. transfers. 45187494Semax * 46187741Semax * 2) sc_ng_mtx - this lock is used to protect shared (between USB, Netgraph 47187741Semax * and Taskqueue) data, such as outgoing mbuf queues, task flags and hook 48187741Semax * pointer. This lock *SHOULD NOT* be grabbed for a long time. In fact, 49187741Semax * think of it as a spin lock. 50187494Semax * 51187494Semax * NOTE ON LOCKING STRATEGY: ng_ubt2 driver operates in 3 different contexts. 52187494Semax * 53187494Semax * 1) USB context. This is where all the USB related stuff happens. All 54187741Semax * callbacks run in this context. All callbacks are called (by USB) with 55187494Semax * appropriate interface lock held. It is (generally) allowed to grab 56187494Semax * any additional locks. 57187494Semax * 58187494Semax * 2) Netgraph context. This is where all the Netgraph related stuff happens. 59187494Semax * Since we mark node as WRITER, the Netgraph node will be "locked" (from 60187494Semax * Netgraph point of view). Any variable that is only modified from the 61187494Semax * Netgraph context does not require any additonal locking. It is generally 62187741Semax * *NOT* allowed to grab *ANY* additional locks. Whatever you do, *DO NOT* 63187741Semax * grab any lock in the Netgraph context that could cause de-scheduling of 64187741Semax * the Netgraph thread for significant amount of time. In fact, the only 65187741Semax * lock that is allowed in the Netgraph context is the sc_ng_mtx lock. 66187741Semax * Also make sure that any code that is called from the Netgraph context 67187741Semax * follows the rule above. 68187494Semax * 69187741Semax * 3) Taskqueue context. This is where ubt_task runs. Since we are generally 70187741Semax * NOT allowed to grab any lock that could cause de-scheduling in the 71187741Semax * Netgraph context, and, USB requires us to grab interface lock before 72187741Semax * doing things with transfers, it is safer to transition from the Netgraph 73187741Semax * context to the Taskqueue context before we can call into USB subsystem. 74187494Semax * 75187494Semax * So, to put everything together, the rules are as follows. 76187494Semax * It is OK to call from the USB context or the Taskqueue context into 77187494Semax * the Netgraph context (i.e. call NG_SEND_xxx functions). In other words 78187494Semax * it is allowed to call into the Netgraph context with locks held. 79187494Semax * Is it *NOT* OK to call from the Netgraph context into the USB context, 80187741Semax * because USB requires us to grab interface locks, and, it is safer to 81187741Semax * avoid it. So, to make things safer we set task flags to indicate which 82187741Semax * actions we want to perform and schedule ubt_task which would run in the 83187741Semax * Taskqueue context. 84187494Semax * Is is OK to call from the Taskqueue context into the USB context, 85187494Semax * and, ubt_task does just that (i.e. grabs appropriate interface locks 86187741Semax * before calling into USB). 87187741Semax * Access to the outgoing queues, task flags and hook pointer is 88187741Semax * controlled by the sc_ng_mtx lock. It is an unavoidable evil. Again, 89187741Semax * sc_ng_mtx should really be a spin lock (and it is very likely to an 90189002Sed * equivalent of spin lock due to adaptive nature of FreeBSD mutexes). 91187741Semax * All USB callbacks accept softc pointer as a private data. USB ensures 92187741Semax * that this pointer is valid. 93187494Semax */ 94187494Semax 95188746Sthompsa#include "usbdevs.h" 96188942Sthompsa#include <dev/usb/usb.h> 97188942Sthompsa#include <dev/usb/usb_mfunc.h> 98188942Sthompsa#include <dev/usb/usb_error.h> 99184610Salfred 100184610Salfred#define USB_DEBUG_VAR usb2_debug 101184610Salfred 102188942Sthompsa#include <dev/usb/usb_core.h> 103188942Sthompsa#include <dev/usb/usb_debug.h> 104188942Sthompsa#include <dev/usb/usb_parse.h> 105188942Sthompsa#include <dev/usb/usb_lookup.h> 106188942Sthompsa#include <dev/usb/usb_util.h> 107188942Sthompsa#include <dev/usb/usb_busdma.h> 108188942Sthompsa#include <dev/usb/usb_process.h> 109188942Sthompsa#include <dev/usb/usb_transfer.h> 110184610Salfred 111184610Salfred#include <sys/mbuf.h> 112187494Semax#include <sys/taskqueue.h> 113184610Salfred 114184610Salfred#include <netgraph/ng_message.h> 115184610Salfred#include <netgraph/netgraph.h> 116184610Salfred#include <netgraph/ng_parse.h> 117184610Salfred#include <netgraph/bluetooth/include/ng_bluetooth.h> 118184610Salfred#include <netgraph/bluetooth/include/ng_hci.h> 119184610Salfred#include <netgraph/bluetooth/include/ng_ubt.h> 120184610Salfred 121188942Sthompsa#include <dev/usb/bluetooth/ng_ubt_var.h> 122184610Salfred 123187494Semaxstatic int ubt_modevent(module_t, int, void *); 124187494Semaxstatic device_probe_t ubt_probe; 125187494Semaxstatic device_attach_t ubt_attach; 126187494Semaxstatic device_detach_t ubt_detach; 127184610Salfred 128187741Semaxstatic void ubt_task_schedule(ubt_softc_p, int); 129187494Semaxstatic task_fn_t ubt_task; 130184610Salfred 131187741Semax#define ubt_xfer_start(sc, i) usb2_transfer_start((sc)->sc_xfer[(i)]) 132187741Semax 133187494Semax/* Netgraph methods */ 134187494Semaxstatic ng_constructor_t ng_ubt_constructor; 135187494Semaxstatic ng_shutdown_t ng_ubt_shutdown; 136187494Semaxstatic ng_newhook_t ng_ubt_newhook; 137187494Semaxstatic ng_connect_t ng_ubt_connect; 138187494Semaxstatic ng_disconnect_t ng_ubt_disconnect; 139187494Semaxstatic ng_rcvmsg_t ng_ubt_rcvmsg; 140187494Semaxstatic ng_rcvdata_t ng_ubt_rcvdata; 141184610Salfred 142184610Salfred/* Queue length */ 143187494Semaxstatic const struct ng_parse_struct_field ng_ubt_node_qlen_type_fields[] = 144184610Salfred{ 145187494Semax { "queue", &ng_parse_int32_type, }, 146187494Semax { "qlen", &ng_parse_int32_type, }, 147187494Semax { NULL, } 148184610Salfred}; 149187494Semaxstatic const struct ng_parse_type ng_ubt_node_qlen_type = 150187494Semax{ 151184610Salfred &ng_parse_struct_type, 152184610Salfred &ng_ubt_node_qlen_type_fields 153184610Salfred}; 154184610Salfred 155184610Salfred/* Stat info */ 156187494Semaxstatic const struct ng_parse_struct_field ng_ubt_node_stat_type_fields[] = 157184610Salfred{ 158187494Semax { "pckts_recv", &ng_parse_uint32_type, }, 159187494Semax { "bytes_recv", &ng_parse_uint32_type, }, 160187494Semax { "pckts_sent", &ng_parse_uint32_type, }, 161187494Semax { "bytes_sent", &ng_parse_uint32_type, }, 162187494Semax { "oerrors", &ng_parse_uint32_type, }, 163187494Semax { "ierrors", &ng_parse_uint32_type, }, 164187494Semax { NULL, } 165184610Salfred}; 166187494Semaxstatic const struct ng_parse_type ng_ubt_node_stat_type = 167187494Semax{ 168184610Salfred &ng_parse_struct_type, 169184610Salfred &ng_ubt_node_stat_type_fields 170184610Salfred}; 171184610Salfred 172184610Salfred/* Netgraph node command list */ 173187494Semaxstatic const struct ng_cmdlist ng_ubt_cmdlist[] = 174187494Semax{ 175184610Salfred { 176184610Salfred NGM_UBT_COOKIE, 177184610Salfred NGM_UBT_NODE_SET_DEBUG, 178184610Salfred "set_debug", 179184610Salfred &ng_parse_uint16_type, 180184610Salfred NULL 181184610Salfred }, 182184610Salfred { 183184610Salfred NGM_UBT_COOKIE, 184184610Salfred NGM_UBT_NODE_GET_DEBUG, 185184610Salfred "get_debug", 186184610Salfred NULL, 187184610Salfred &ng_parse_uint16_type 188184610Salfred }, 189184610Salfred { 190184610Salfred NGM_UBT_COOKIE, 191184610Salfred NGM_UBT_NODE_SET_QLEN, 192184610Salfred "set_qlen", 193184610Salfred &ng_ubt_node_qlen_type, 194184610Salfred NULL 195184610Salfred }, 196184610Salfred { 197184610Salfred NGM_UBT_COOKIE, 198184610Salfred NGM_UBT_NODE_GET_QLEN, 199184610Salfred "get_qlen", 200184610Salfred &ng_ubt_node_qlen_type, 201184610Salfred &ng_ubt_node_qlen_type 202184610Salfred }, 203184610Salfred { 204184610Salfred NGM_UBT_COOKIE, 205184610Salfred NGM_UBT_NODE_GET_STAT, 206184610Salfred "get_stat", 207184610Salfred NULL, 208184610Salfred &ng_ubt_node_stat_type 209184610Salfred }, 210184610Salfred { 211184610Salfred NGM_UBT_COOKIE, 212184610Salfred NGM_UBT_NODE_RESET_STAT, 213184610Salfred "reset_stat", 214184610Salfred NULL, 215184610Salfred NULL 216184610Salfred }, 217187494Semax { 0, } 218184610Salfred}; 219184610Salfred 220184610Salfred/* Netgraph node type */ 221187494Semaxstatic struct ng_type typestruct = 222187494Semax{ 223187494Semax .version = NG_ABI_VERSION, 224187494Semax .name = NG_UBT_NODE_TYPE, 225187494Semax .constructor = ng_ubt_constructor, 226187494Semax .rcvmsg = ng_ubt_rcvmsg, 227187494Semax .shutdown = ng_ubt_shutdown, 228187494Semax .newhook = ng_ubt_newhook, 229187494Semax .connect = ng_ubt_connect, 230187494Semax .rcvdata = ng_ubt_rcvdata, 231187494Semax .disconnect = ng_ubt_disconnect, 232187494Semax .cmdlist = ng_ubt_cmdlist 233184610Salfred}; 234184610Salfred 235187494Semax/**************************************************************************** 236187494Semax **************************************************************************** 237187494Semax ** USB specific 238187494Semax **************************************************************************** 239187494Semax ****************************************************************************/ 240187494Semax 241184610Salfred/* USB methods */ 242187494Semaxstatic usb2_callback_t ubt_ctrl_write_callback; 243187494Semaxstatic usb2_callback_t ubt_intr_read_callback; 244187494Semaxstatic usb2_callback_t ubt_bulk_read_callback; 245187494Semaxstatic usb2_callback_t ubt_bulk_write_callback; 246187494Semaxstatic usb2_callback_t ubt_isoc_read_callback; 247187494Semaxstatic usb2_callback_t ubt_isoc_write_callback; 248184610Salfred 249187741Semaxstatic int ubt_fwd_mbuf_up(ubt_softc_p, struct mbuf **); 250187741Semaxstatic int ubt_isoc_read_one_frame(struct usb2_xfer *, int); 251184610Salfred 252187494Semax/* 253187494Semax * USB config 254187494Semax * 255187494Semax * The following desribes usb transfers that could be submitted on USB device. 256187494Semax * 257187494Semax * Interface 0 on the USB device must present the following endpoints 258187494Semax * 1) Interrupt endpoint to receive HCI events 259187494Semax * 2) Bulk IN endpoint to receive ACL data 260187494Semax * 3) Bulk OUT endpoint to send ACL data 261187494Semax * 262187494Semax * Interface 1 on the USB device must present the following endpoints 263187494Semax * 1) Isochronous IN endpoint to receive SCO data 264187494Semax * 2) Isochronous OUT endpoint to send SCO data 265187494Semax */ 266184610Salfred 267187494Semaxstatic const struct usb2_config ubt_config[UBT_N_TRANSFER] = 268187494Semax{ 269187494Semax /* 270187494Semax * Interface #0 271187494Semax */ 272184610Salfred 273187494Semax /* Outgoing bulk transfer - ACL packets */ 274187494Semax [UBT_IF_0_BULK_DT_WR] = { 275187494Semax .type = UE_BULK, 276187494Semax .endpoint = UE_ADDR_ANY, 277187494Semax .direction = UE_DIR_OUT, 278187741Semax .if_index = 0, 279187494Semax .mh.bufsize = UBT_BULK_WRITE_BUFFER_SIZE, 280187741Semax .mh.flags = { .pipe_bof = 1, .force_short_xfer = 1, }, 281187494Semax .mh.callback = &ubt_bulk_write_callback, 282184610Salfred }, 283187494Semax /* Incoming bulk transfer - ACL packets */ 284187494Semax [UBT_IF_0_BULK_DT_RD] = { 285187494Semax .type = UE_BULK, 286187494Semax .endpoint = UE_ADDR_ANY, 287187494Semax .direction = UE_DIR_IN, 288187741Semax .if_index = 0, 289187494Semax .mh.bufsize = UBT_BULK_READ_BUFFER_SIZE, 290187494Semax .mh.flags = { .pipe_bof = 1, .short_xfer_ok = 1, }, 291187494Semax .mh.callback = &ubt_bulk_read_callback, 292184610Salfred }, 293187494Semax /* Incoming interrupt transfer - HCI events */ 294187494Semax [UBT_IF_0_INTR_DT_RD] = { 295187494Semax .type = UE_INTERRUPT, 296187494Semax .endpoint = UE_ADDR_ANY, 297187494Semax .direction = UE_DIR_IN, 298187741Semax .if_index = 0, 299187494Semax .mh.flags = { .pipe_bof = 1, .short_xfer_ok = 1, }, 300187494Semax .mh.bufsize = UBT_INTR_BUFFER_SIZE, 301187494Semax .mh.callback = &ubt_intr_read_callback, 302184610Salfred }, 303187494Semax /* Outgoing control transfer - HCI commands */ 304187494Semax [UBT_IF_0_CTRL_DT_WR] = { 305187494Semax .type = UE_CONTROL, 306187494Semax .endpoint = 0x00, /* control pipe */ 307187494Semax .direction = UE_DIR_ANY, 308187741Semax .if_index = 0, 309187494Semax .mh.bufsize = UBT_CTRL_BUFFER_SIZE, 310187494Semax .mh.callback = &ubt_ctrl_write_callback, 311187494Semax .mh.timeout = 5000, /* 5 seconds */ 312184610Salfred }, 313184610Salfred 314187494Semax /* 315187494Semax * Interface #1 316187494Semax */ 317184610Salfred 318187494Semax /* Incoming isochronous transfer #1 - SCO packets */ 319187494Semax [UBT_IF_1_ISOC_DT_RD1] = { 320187494Semax .type = UE_ISOCHRONOUS, 321187494Semax .endpoint = UE_ADDR_ANY, 322187494Semax .direction = UE_DIR_IN, 323187741Semax .if_index = 1, 324187494Semax .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */ 325187494Semax .mh.frames = UBT_ISOC_NFRAMES, 326187494Semax .mh.flags = { .short_xfer_ok = 1, }, 327187494Semax .mh.callback = &ubt_isoc_read_callback, 328184610Salfred }, 329187494Semax /* Incoming isochronous transfer #2 - SCO packets */ 330187494Semax [UBT_IF_1_ISOC_DT_RD2] = { 331187494Semax .type = UE_ISOCHRONOUS, 332187494Semax .endpoint = UE_ADDR_ANY, 333187494Semax .direction = UE_DIR_IN, 334187741Semax .if_index = 1, 335187494Semax .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */ 336187494Semax .mh.frames = UBT_ISOC_NFRAMES, 337187494Semax .mh.flags = { .short_xfer_ok = 1, }, 338187494Semax .mh.callback = &ubt_isoc_read_callback, 339184610Salfred }, 340187494Semax /* Outgoing isochronous transfer #1 - SCO packets */ 341187494Semax [UBT_IF_1_ISOC_DT_WR1] = { 342187494Semax .type = UE_ISOCHRONOUS, 343187494Semax .endpoint = UE_ADDR_ANY, 344187494Semax .direction = UE_DIR_OUT, 345187741Semax .if_index = 1, 346187494Semax .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */ 347187494Semax .mh.frames = UBT_ISOC_NFRAMES, 348187494Semax .mh.flags = { .short_xfer_ok = 1, }, 349187494Semax .mh.callback = &ubt_isoc_write_callback, 350184610Salfred }, 351187494Semax /* Outgoing isochronous transfer #2 - SCO packets */ 352187494Semax [UBT_IF_1_ISOC_DT_WR2] = { 353187494Semax .type = UE_ISOCHRONOUS, 354187494Semax .endpoint = UE_ADDR_ANY, 355187494Semax .direction = UE_DIR_OUT, 356187741Semax .if_index = 1, 357187494Semax .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */ 358187494Semax .mh.frames = UBT_ISOC_NFRAMES, 359187494Semax .mh.flags = { .short_xfer_ok = 1, }, 360187494Semax .mh.callback = &ubt_isoc_write_callback, 361184610Salfred }, 362184610Salfred}; 363184610Salfred 364184610Salfred/* 365184610Salfred * If for some reason device should not be attached then put 366184610Salfred * VendorID/ProductID pair into the list below. The format is 367184610Salfred * as follows: 368184610Salfred * 369187494Semax * { USB_VPI(VENDOR_ID, PRODUCT_ID, 0) }, 370184610Salfred * 371184610Salfred * where VENDOR_ID and PRODUCT_ID are hex numbers. 372184610Salfred */ 373187741Semax 374187741Semaxstatic const struct usb2_device_id ubt_ignore_devs[] = 375187741Semax{ 376184610Salfred /* AVM USB Bluetooth-Adapter BlueFritz! v1.0 */ 377187494Semax { USB_VPI(USB_VENDOR_AVM, 0x2200, 0) }, 378184610Salfred}; 379184610Salfred 380184610Salfred/* List of supported bluetooth devices */ 381187741Semaxstatic const struct usb2_device_id ubt_devs[] = 382187741Semax{ 383187494Semax /* Generic Bluetooth class devices */ 384187494Semax { USB_IFACE_CLASS(UDCLASS_WIRELESS), 385187494Semax USB_IFACE_SUBCLASS(UDSUBCLASS_RF), 386187494Semax USB_IFACE_PROTOCOL(UDPROTO_BLUETOOTH) }, 387184610Salfred 388184610Salfred /* AVM USB Bluetooth-Adapter BlueFritz! v2.0 */ 389187494Semax { USB_VPI(USB_VENDOR_AVM, 0x3800, 0) }, 390184610Salfred}; 391184610Salfred 392184610Salfred/* 393187494Semax * Probe for a USB Bluetooth device. 394187494Semax * USB context. 395184610Salfred */ 396184610Salfred 397184610Salfredstatic int 398184610Salfredubt_probe(device_t dev) 399184610Salfred{ 400187494Semax struct usb2_attach_arg *uaa = device_get_ivars(dev); 401184610Salfred 402187494Semax if (uaa->usb2_mode != USB_MODE_HOST) 403184610Salfred return (ENXIO); 404187494Semax 405187494Semax if (uaa->info.bIfaceIndex != 0) 406184610Salfred return (ENXIO); 407187494Semax 408187865Semax if (uaa->use_generic == 0) 409187865Semax return (ENXIO); 410187865Semax 411184610Salfred if (usb2_lookup_id_by_uaa(ubt_ignore_devs, 412187494Semax sizeof(ubt_ignore_devs), uaa) == 0) 413184610Salfred return (ENXIO); 414187494Semax 415184610Salfred return (usb2_lookup_id_by_uaa(ubt_devs, sizeof(ubt_devs), uaa)); 416187494Semax} /* ubt_probe */ 417184610Salfred 418184610Salfred/* 419187494Semax * Attach the device. 420187494Semax * USB context. 421184610Salfred */ 422184610Salfred 423184610Salfredstatic int 424184610Salfredubt_attach(device_t dev) 425184610Salfred{ 426187494Semax struct usb2_attach_arg *uaa = device_get_ivars(dev); 427187494Semax struct ubt_softc *sc = device_get_softc(dev); 428187494Semax struct usb2_endpoint_descriptor *ed; 429190728Sthompsa struct usb2_interface_descriptor *id; 430187494Semax uint16_t wMaxPacketSize; 431187741Semax uint8_t alt_index, i, j; 432187741Semax uint8_t iface_index[2] = { 0, 1 }; 433184610Salfred 434184610Salfred device_set_usb2_desc(dev); 435184610Salfred 436187741Semax sc->sc_dev = dev; 437187741Semax sc->sc_debug = NG_UBT_WARN_LEVEL; 438184610Salfred 439187494Semax /* 440187494Semax * Create Netgraph node 441187494Semax */ 442187494Semax 443187494Semax if (ng_make_node_common(&typestruct, &sc->sc_node) != 0) { 444187741Semax UBT_ALERT(sc, "could not create Netgraph node\n"); 445187494Semax return (ENXIO); 446187494Semax } 447187494Semax 448187494Semax /* Name Netgraph node */ 449187741Semax if (ng_name_node(sc->sc_node, device_get_nameunit(dev)) != 0) { 450187741Semax UBT_ALERT(sc, "could not name Netgraph node\n"); 451187494Semax NG_NODE_UNREF(sc->sc_node); 452187494Semax return (ENXIO); 453187494Semax } 454187494Semax NG_NODE_SET_PRIVATE(sc->sc_node, sc); 455187494Semax NG_NODE_FORCE_WRITER(sc->sc_node); 456187494Semax 457184610Salfred /* 458184610Salfred * Initialize device softc structure 459184610Salfred */ 460184610Salfred 461187494Semax /* initialize locks */ 462187741Semax mtx_init(&sc->sc_ng_mtx, "ubt ng", NULL, MTX_DEF); 463187741Semax mtx_init(&sc->sc_if_mtx, "ubt if", NULL, MTX_DEF | MTX_RECURSE); 464187494Semax 465187494Semax /* initialize packet queues */ 466184610Salfred NG_BT_MBUFQ_INIT(&sc->sc_cmdq, UBT_DEFAULT_QLEN); 467184610Salfred NG_BT_MBUFQ_INIT(&sc->sc_aclq, UBT_DEFAULT_QLEN); 468187494Semax NG_BT_MBUFQ_INIT(&sc->sc_scoq, UBT_DEFAULT_QLEN); 469184610Salfred 470187494Semax /* initialize glue task */ 471187741Semax TASK_INIT(&sc->sc_task, 0, ubt_task, sc); 472184610Salfred 473184610Salfred /* 474184610Salfred * Configure Bluetooth USB device. Discover all required USB 475184610Salfred * interfaces and endpoints. 476184610Salfred * 477184610Salfred * USB device must present two interfaces: 478184610Salfred * 1) Interface 0 that has 3 endpoints 479184610Salfred * 1) Interrupt endpoint to receive HCI events 480184610Salfred * 2) Bulk IN endpoint to receive ACL data 481184610Salfred * 3) Bulk OUT endpoint to send ACL data 482184610Salfred * 483184610Salfred * 2) Interface 1 then has 2 endpoints 484184610Salfred * 1) Isochronous IN endpoint to receive SCO data 485184610Salfred * 2) Isochronous OUT endpoint to send SCO data 486184610Salfred * 487184610Salfred * Interface 1 (with isochronous endpoints) has several alternate 488184610Salfred * configurations with different packet size. 489184610Salfred */ 490184610Salfred 491184610Salfred /* 492187741Semax * For interface #1 search alternate settings, and find 493187741Semax * the descriptor with the largest wMaxPacketSize 494184610Salfred */ 495184610Salfred 496184610Salfred wMaxPacketSize = 0; 497187494Semax alt_index = 0; 498184610Salfred i = 0; 499184610Salfred j = 0; 500190728Sthompsa ed = NULL; 501187494Semax 502190728Sthompsa /* 503190728Sthompsa * Search through all the descriptors looking for the largest 504190728Sthompsa * packet size: 505190728Sthompsa */ 506190728Sthompsa while ((ed = (struct usb2_endpoint_descriptor *)usb2_desc_foreach( 507190728Sthompsa usb2_get_config_descriptor(uaa->device), 508190728Sthompsa (struct usb2_descriptor *)ed))) { 509184610Salfred 510190728Sthompsa if ((ed->bDescriptorType == UDESC_INTERFACE) && 511190728Sthompsa (ed->bLength >= sizeof(*id))) { 512190728Sthompsa id = (struct usb2_interface_descriptor *)ed; 513190728Sthompsa i = id->bInterfaceNumber; 514190728Sthompsa j = id->bAlternateSetting; 515184610Salfred } 516187494Semax 517190728Sthompsa if ((ed->bDescriptorType == UDESC_ENDPOINT) && 518190728Sthompsa (ed->bLength >= sizeof(*ed)) && 519190728Sthompsa (i == 1)) { 520190728Sthompsa uint16_t temp; 521190728Sthompsa 522190728Sthompsa temp = UGETW(ed->wMaxPacketSize); 523190728Sthompsa if (temp > wMaxPacketSize) { 524190728Sthompsa wMaxPacketSize = temp; 525190728Sthompsa alt_index = j; 526190728Sthompsa } 527184610Salfred } 528184610Salfred } 529184610Salfred 530187741Semax /* Set alt configuration on interface #1 only if we found it */ 531187494Semax if (wMaxPacketSize > 0 && 532187494Semax usb2_set_alt_interface_index(uaa->device, 1, alt_index)) { 533187741Semax UBT_ALERT(sc, "could not set alternate setting %d " \ 534187494Semax "for interface 1!\n", alt_index); 535184610Salfred goto detach; 536184610Salfred } 537184610Salfred 538187741Semax /* Setup transfers for both interfaces */ 539187741Semax if (usb2_transfer_setup(uaa->device, iface_index, sc->sc_xfer, 540187741Semax ubt_config, UBT_N_TRANSFER, sc, &sc->sc_if_mtx)) { 541187741Semax UBT_ALERT(sc, "could not allocate transfers\n"); 542184610Salfred goto detach; 543184610Salfred } 544184610Salfred 545187494Semax /* Claim all interfaces on the device */ 546187494Semax for (i = 1; usb2_get_iface(uaa->device, i) != NULL; i ++) 547184610Salfred usb2_set_parent_iface(uaa->device, i, uaa->info.bIfaceIndex); 548184610Salfred 549187494Semax return (0); /* success */ 550184610Salfred 551184610Salfreddetach: 552184610Salfred ubt_detach(dev); 553184610Salfred 554184610Salfred return (ENXIO); 555187494Semax} /* ubt_attach */ 556184610Salfred 557184610Salfred/* 558187494Semax * Detach the device. 559187494Semax * USB context. 560184610Salfred */ 561184610Salfred 562184610Salfredint 563184610Salfredubt_detach(device_t dev) 564184610Salfred{ 565187494Semax struct ubt_softc *sc = device_get_softc(dev); 566187494Semax node_p node = sc->sc_node; 567184610Salfred 568187494Semax /* Destroy Netgraph node */ 569187494Semax if (node != NULL) { 570187494Semax sc->sc_node = NULL; 571187494Semax NG_NODE_REALLY_DIE(node); 572187494Semax ng_rmnode_self(node); 573184610Salfred } 574184610Salfred 575187741Semax /* Make sure ubt_task in gone */ 576187741Semax taskqueue_drain(taskqueue_swi, &sc->sc_task); 577187741Semax 578187494Semax /* Free USB transfers, if any */ 579187494Semax usb2_transfer_unsetup(sc->sc_xfer, UBT_N_TRANSFER); 580184610Salfred 581187494Semax /* Destroy queues */ 582187741Semax UBT_NG_LOCK(sc); 583184610Salfred NG_BT_MBUFQ_DESTROY(&sc->sc_cmdq); 584184610Salfred NG_BT_MBUFQ_DESTROY(&sc->sc_aclq); 585184610Salfred NG_BT_MBUFQ_DESTROY(&sc->sc_scoq); 586187741Semax UBT_NG_UNLOCK(sc); 587184610Salfred 588187741Semax mtx_destroy(&sc->sc_if_mtx); 589187741Semax mtx_destroy(&sc->sc_ng_mtx); 590187494Semax 591184610Salfred return (0); 592187494Semax} /* ubt_detach */ 593184610Salfred 594187494Semax/* 595187494Semax * Called when outgoing control request (HCI command) has completed, i.e. 596187494Semax * HCI command was sent to the device. 597187494Semax * USB context. 598187494Semax */ 599187494Semax 600184610Salfredstatic void 601184610Salfredubt_ctrl_write_callback(struct usb2_xfer *xfer) 602184610Salfred{ 603187741Semax struct ubt_softc *sc = xfer->priv_sc; 604187494Semax struct usb2_device_request req; 605187494Semax struct mbuf *m; 606184610Salfred 607184610Salfred switch (USB_GET_STATE(xfer)) { 608184610Salfred case USB_ST_TRANSFERRED: 609187741Semax UBT_INFO(sc, "sent %d bytes to control pipe\n", xfer->actlen); 610187741Semax UBT_STAT_BYTES_SENT(sc, xfer->actlen); 611187741Semax UBT_STAT_PCKTS_SENT(sc); 612187494Semax /* FALLTHROUGH */ 613184610Salfred 614184610Salfred case USB_ST_SETUP: 615187494Semaxsend_next: 616187494Semax /* Get next command mbuf, if any */ 617187741Semax UBT_NG_LOCK(sc); 618184610Salfred NG_BT_MBUFQ_DEQUEUE(&sc->sc_cmdq, m); 619187741Semax UBT_NG_UNLOCK(sc); 620184610Salfred 621184610Salfred if (m == NULL) { 622187494Semax UBT_INFO(sc, "HCI command queue is empty\n"); 623187741Semax break; /* transfer complete */ 624184610Salfred } 625184610Salfred 626187494Semax /* Initialize a USB control request and then schedule it */ 627184610Salfred bzero(&req, sizeof(req)); 628184610Salfred req.bmRequestType = UBT_HCI_REQUEST; 629184610Salfred USETW(req.wLength, m->m_pkthdr.len); 630184610Salfred 631187494Semax UBT_INFO(sc, "Sending control request, " \ 632187494Semax "bmRequestType=0x%02x, wLength=%d\n", 633187494Semax req.bmRequestType, UGETW(req.wLength)); 634184610Salfred 635184610Salfred usb2_copy_in(xfer->frbuffers, 0, &req, sizeof(req)); 636184610Salfred usb2_m_copy_in(xfer->frbuffers + 1, 0, m, 0, m->m_pkthdr.len); 637184610Salfred 638184610Salfred xfer->frlengths[0] = sizeof(req); 639184610Salfred xfer->frlengths[1] = m->m_pkthdr.len; 640187494Semax xfer->nframes = 2; 641184610Salfred 642184610Salfred NG_FREE_M(m); 643184610Salfred 644184610Salfred usb2_start_hardware(xfer); 645187494Semax break; 646184610Salfred 647187494Semax default: /* Error */ 648187494Semax if (xfer->error != USB_ERR_CANCELLED) { 649187494Semax UBT_WARN(sc, "control transfer failed: %s\n", 650187494Semax usb2_errstr(xfer->error)); 651187494Semax 652187494Semax UBT_STAT_OERROR(sc); 653187494Semax goto send_next; 654184610Salfred } 655187494Semax 656187741Semax /* transfer cancelled */ 657187494Semax break; 658184610Salfred } 659187494Semax} /* ubt_ctrl_write_callback */ 660184610Salfred 661187494Semax/* 662187494Semax * Called when incoming interrupt transfer (HCI event) has completed, i.e. 663187494Semax * HCI event was received from the device. 664187494Semax * USB context. 665187494Semax */ 666187494Semax 667184610Salfredstatic void 668184610Salfredubt_intr_read_callback(struct usb2_xfer *xfer) 669184610Salfred{ 670187741Semax struct ubt_softc *sc = xfer->priv_sc; 671187494Semax struct mbuf *m; 672187494Semax ng_hci_event_pkt_t *hdr; 673184610Salfred 674187494Semax m = NULL; 675187494Semax 676184610Salfred switch (USB_GET_STATE(xfer)) { 677184610Salfred case USB_ST_TRANSFERRED: 678187494Semax /* Allocate a new mbuf */ 679184610Salfred MGETHDR(m, M_DONTWAIT, MT_DATA); 680184610Salfred if (m == NULL) { 681187494Semax UBT_STAT_IERROR(sc); 682187494Semax goto submit_next; 683184610Salfred } 684187494Semax 685184610Salfred MCLGET(m, M_DONTWAIT); 686184610Salfred if (!(m->m_flags & M_EXT)) { 687187494Semax UBT_STAT_IERROR(sc); 688187494Semax goto submit_next; 689184610Salfred } 690187494Semax 691187494Semax /* Add HCI packet type */ 692187494Semax *mtod(m, uint8_t *)= NG_HCI_EVENT_PKT; 693187494Semax m->m_pkthdr.len = m->m_len = 1; 694187494Semax 695187494Semax if (xfer->actlen > MCLBYTES - 1) 696187494Semax xfer->actlen = MCLBYTES - 1; 697187494Semax 698187494Semax usb2_copy_out(xfer->frbuffers, 0, mtod(m, uint8_t *) + 1, 699187494Semax xfer->actlen); 700187494Semax m->m_pkthdr.len += xfer->actlen; 701187494Semax m->m_len += xfer->actlen; 702187494Semax 703187494Semax UBT_INFO(sc, "got %d bytes from interrupt pipe\n", 704187494Semax xfer->actlen); 705187494Semax 706187494Semax /* Validate packet and send it up the stack */ 707187494Semax if (m->m_pkthdr.len < sizeof(*hdr)) { 708187494Semax UBT_INFO(sc, "HCI event packet is too short\n"); 709187494Semax 710187494Semax UBT_STAT_IERROR(sc); 711187494Semax goto submit_next; 712184610Salfred } 713184610Salfred 714187494Semax hdr = mtod(m, ng_hci_event_pkt_t *); 715187494Semax if (hdr->length != (m->m_pkthdr.len - sizeof(*hdr))) { 716187494Semax UBT_ERR(sc, "Invalid HCI event packet size, " \ 717187494Semax "length=%d, pktlen=%d\n", 718187494Semax hdr->length, m->m_pkthdr.len); 719184610Salfred 720187494Semax UBT_STAT_IERROR(sc); 721187494Semax goto submit_next; 722184610Salfred } 723184610Salfred 724187494Semax UBT_INFO(sc, "got complete HCI event frame, pktlen=%d, " \ 725187494Semax "length=%d\n", m->m_pkthdr.len, hdr->length); 726184610Salfred 727187494Semax UBT_STAT_PCKTS_RECV(sc); 728187494Semax UBT_STAT_BYTES_RECV(sc, m->m_pkthdr.len); 729184610Salfred 730187741Semax ubt_fwd_mbuf_up(sc, &m); 731187494Semax /* m == NULL at this point */ 732187494Semax /* FALLTHROUGH */ 733184610Salfred 734184610Salfred case USB_ST_SETUP: 735187494Semaxsubmit_next: 736187494Semax NG_FREE_M(m); /* checks for m != NULL */ 737184610Salfred 738187741Semax xfer->frlengths[0] = xfer->max_data_length; 739187741Semax usb2_start_hardware(xfer); 740187494Semax break; 741184610Salfred 742187494Semax default: /* Error */ 743187494Semax if (xfer->error != USB_ERR_CANCELLED) { 744187494Semax UBT_WARN(sc, "interrupt transfer failed: %s\n", 745187494Semax usb2_errstr(xfer->error)); 746184610Salfred 747187494Semax /* Try to clear stall first */ 748187741Semax xfer->flags.stall_pipe = 1; 749187741Semax goto submit_next; 750187741Semax } 751187741Semax /* transfer cancelled */ 752187494Semax break; 753184610Salfred } 754187494Semax} /* ubt_intr_read_callback */ 755184610Salfred 756187494Semax/* 757187494Semax * Called when incoming bulk transfer (ACL packet) has completed, i.e. 758187494Semax * ACL packet was received from the device. 759187494Semax * USB context. 760187494Semax */ 761187494Semax 762184610Salfredstatic void 763187494Semaxubt_bulk_read_callback(struct usb2_xfer *xfer) 764184610Salfred{ 765187741Semax struct ubt_softc *sc = xfer->priv_sc; 766187494Semax struct mbuf *m; 767187494Semax ng_hci_acldata_pkt_t *hdr; 768187494Semax uint16_t len; 769184610Salfred 770187494Semax m = NULL; 771184610Salfred 772184610Salfred switch (USB_GET_STATE(xfer)) { 773184610Salfred case USB_ST_TRANSFERRED: 774187494Semax /* Allocate new mbuf */ 775184610Salfred MGETHDR(m, M_DONTWAIT, MT_DATA); 776184610Salfred if (m == NULL) { 777187494Semax UBT_STAT_IERROR(sc); 778187494Semax goto submit_next; 779184610Salfred } 780187494Semax 781184610Salfred MCLGET(m, M_DONTWAIT); 782184610Salfred if (!(m->m_flags & M_EXT)) { 783187494Semax UBT_STAT_IERROR(sc); 784187494Semax goto submit_next; 785184610Salfred } 786184610Salfred 787187494Semax /* Add HCI packet type */ 788187494Semax *mtod(m, uint8_t *)= NG_HCI_ACL_DATA_PKT; 789187494Semax m->m_pkthdr.len = m->m_len = 1; 790184610Salfred 791187494Semax if (xfer->actlen > MCLBYTES - 1) 792187494Semax xfer->actlen = MCLBYTES - 1; 793184610Salfred 794187494Semax usb2_copy_out(xfer->frbuffers, 0, mtod(m, uint8_t *) + 1, 795187494Semax xfer->actlen); 796184610Salfred m->m_pkthdr.len += xfer->actlen; 797184610Salfred m->m_len += xfer->actlen; 798184610Salfred 799187494Semax UBT_INFO(sc, "got %d bytes from bulk-in pipe\n", 800187494Semax xfer->actlen); 801184610Salfred 802187494Semax /* Validate packet and send it up the stack */ 803187494Semax if (m->m_pkthdr.len < sizeof(*hdr)) { 804187494Semax UBT_INFO(sc, "HCI ACL packet is too short\n"); 805184610Salfred 806187494Semax UBT_STAT_IERROR(sc); 807187494Semax goto submit_next; 808184610Salfred } 809184610Salfred 810187494Semax hdr = mtod(m, ng_hci_acldata_pkt_t *); 811187494Semax len = le16toh(hdr->length); 812187494Semax if (len != (m->m_pkthdr.len - sizeof(*hdr))) { 813187494Semax UBT_ERR(sc, "Invalid ACL packet size, length=%d, " \ 814187494Semax "pktlen=%d\n", len, m->m_pkthdr.len); 815184610Salfred 816187494Semax UBT_STAT_IERROR(sc); 817187494Semax goto submit_next; 818184610Salfred } 819184610Salfred 820187494Semax UBT_INFO(sc, "got complete ACL data packet, pktlen=%d, " \ 821187494Semax "length=%d\n", m->m_pkthdr.len, len); 822184610Salfred 823187494Semax UBT_STAT_PCKTS_RECV(sc); 824187494Semax UBT_STAT_BYTES_RECV(sc, m->m_pkthdr.len); 825184610Salfred 826187741Semax ubt_fwd_mbuf_up(sc, &m); 827187494Semax /* m == NULL at this point */ 828187494Semax /* FALLTHOUGH */ 829184610Salfred 830187494Semax case USB_ST_SETUP: 831187494Semaxsubmit_next: 832187494Semax NG_FREE_M(m); /* checks for m != NULL */ 833184610Salfred 834187741Semax xfer->frlengths[0] = xfer->max_data_length; 835187741Semax usb2_start_hardware(xfer); 836187494Semax break; 837184610Salfred 838187494Semax default: /* Error */ 839187494Semax if (xfer->error != USB_ERR_CANCELLED) { 840187494Semax UBT_WARN(sc, "bulk-in transfer failed: %s\n", 841187494Semax usb2_errstr(xfer->error)); 842184610Salfred 843187494Semax /* Try to clear stall first */ 844187741Semax xfer->flags.stall_pipe = 1; 845187741Semax goto submit_next; 846187741Semax } 847187741Semax /* transfer cancelled */ 848187494Semax break; 849187494Semax } 850187494Semax} /* ubt_bulk_read_callback */ 851184610Salfred 852187494Semax/* 853187494Semax * Called when outgoing bulk transfer (ACL packet) has completed, i.e. 854187494Semax * ACL packet was sent to the device. 855187494Semax * USB context. 856187494Semax */ 857184610Salfred 858184610Salfredstatic void 859184610Salfredubt_bulk_write_callback(struct usb2_xfer *xfer) 860184610Salfred{ 861187741Semax struct ubt_softc *sc = xfer->priv_sc; 862187494Semax struct mbuf *m; 863184610Salfred 864184610Salfred switch (USB_GET_STATE(xfer)) { 865184610Salfred case USB_ST_TRANSFERRED: 866187741Semax UBT_INFO(sc, "sent %d bytes to bulk-out pipe\n", xfer->actlen); 867187741Semax UBT_STAT_BYTES_SENT(sc, xfer->actlen); 868187741Semax UBT_STAT_PCKTS_SENT(sc); 869187494Semax /* FALLTHROUGH */ 870184610Salfred 871187494Semax case USB_ST_SETUP: 872187741Semaxsend_next: 873187494Semax /* Get next mbuf, if any */ 874187741Semax UBT_NG_LOCK(sc); 875184610Salfred NG_BT_MBUFQ_DEQUEUE(&sc->sc_aclq, m); 876187741Semax UBT_NG_UNLOCK(sc); 877184610Salfred 878184610Salfred if (m == NULL) { 879187494Semax UBT_INFO(sc, "ACL data queue is empty\n"); 880187741Semax break; /* transfer completed */ 881184610Salfred } 882187494Semax 883184610Salfred /* 884187494Semax * Copy ACL data frame back to a linear USB transfer buffer 885187494Semax * and schedule transfer 886184610Salfred */ 887184610Salfred 888184610Salfred usb2_m_copy_in(xfer->frbuffers, 0, m, 0, m->m_pkthdr.len); 889187494Semax xfer->frlengths[0] = m->m_pkthdr.len; 890184610Salfred 891187494Semax UBT_INFO(sc, "bulk-out transfer has been started, len=%d\n", 892187494Semax m->m_pkthdr.len); 893184610Salfred 894184610Salfred NG_FREE_M(m); 895184610Salfred 896184610Salfred usb2_start_hardware(xfer); 897187494Semax break; 898184610Salfred 899187494Semax default: /* Error */ 900184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 901187494Semax UBT_WARN(sc, "bulk-out transfer failed: %s\n", 902187494Semax usb2_errstr(xfer->error)); 903184610Salfred 904187494Semax UBT_STAT_OERROR(sc); 905184610Salfred 906184610Salfred /* try to clear stall first */ 907187741Semax xfer->flags.stall_pipe = 1; 908187741Semax goto send_next; 909187741Semax } 910187741Semax /* transfer cancelled */ 911187494Semax break; 912184610Salfred } 913187494Semax} /* ubt_bulk_write_callback */ 914184610Salfred 915187494Semax/* 916187494Semax * Called when incoming isoc transfer (SCO packet) has completed, i.e. 917187494Semax * SCO packet was received from the device. 918187494Semax * USB context. 919187494Semax */ 920187494Semax 921184610Salfredstatic void 922184610Salfredubt_isoc_read_callback(struct usb2_xfer *xfer) 923184610Salfred{ 924187741Semax struct ubt_softc *sc = xfer->priv_sc; 925187494Semax int n; 926184610Salfred 927187494Semax switch (USB_GET_STATE(xfer)) { 928187494Semax case USB_ST_TRANSFERRED: 929187494Semax for (n = 0; n < xfer->nframes; n ++) 930187494Semax if (ubt_isoc_read_one_frame(xfer, n) < 0) 931187494Semax break; 932187494Semax /* FALLTHROUGH */ 933184610Salfred 934187494Semax case USB_ST_SETUP: 935187494Semaxread_next: 936187494Semax for (n = 0; n < xfer->nframes; n ++) 937187494Semax xfer->frlengths[n] = xfer->max_frame_size; 938184610Salfred 939187494Semax usb2_start_hardware(xfer); 940187494Semax break; 941184610Salfred 942187494Semax default: /* Error */ 943187494Semax if (xfer->error != USB_ERR_CANCELLED) { 944187494Semax UBT_STAT_IERROR(sc); 945187494Semax goto read_next; 946187494Semax } 947184610Salfred 948187741Semax /* transfer cancelled */ 949187494Semax break; 950187494Semax } 951187494Semax} /* ubt_isoc_read_callback */ 952184610Salfred 953187494Semax/* 954187494Semax * Helper function. Called from ubt_isoc_read_callback() to read 955187494Semax * SCO data from one frame. 956187494Semax * USB context. 957187494Semax */ 958184610Salfred 959187494Semaxstatic int 960187494Semaxubt_isoc_read_one_frame(struct usb2_xfer *xfer, int frame_no) 961187494Semax{ 962187494Semax struct ubt_softc *sc = xfer->priv_sc; 963187494Semax struct mbuf *m; 964187741Semax int len, want, got; 965184610Salfred 966187494Semax /* Get existing SCO reassembly buffer */ 967187494Semax m = sc->sc_isoc_in_buffer; 968187494Semax sc->sc_isoc_in_buffer = NULL; 969184610Salfred 970187494Semax /* While we have data in the frame */ 971187494Semax while ((len = xfer->frlengths[frame_no]) > 0) { 972187494Semax if (m == NULL) { 973187494Semax /* Start new reassembly buffer */ 974187494Semax MGETHDR(m, M_DONTWAIT, MT_DATA); 975187494Semax if (m == NULL) { 976187494Semax UBT_STAT_IERROR(sc); 977187494Semax return (-1); /* XXX out of sync! */ 978187494Semax } 979184610Salfred 980187494Semax MCLGET(m, M_DONTWAIT); 981187494Semax if (!(m->m_flags & M_EXT)) { 982187494Semax UBT_STAT_IERROR(sc); 983187494Semax NG_FREE_M(m); 984187494Semax return (-1); /* XXX out of sync! */ 985184610Salfred } 986184610Salfred 987187494Semax /* Expect SCO header */ 988187494Semax *mtod(m, uint8_t *) = NG_HCI_SCO_DATA_PKT; 989187494Semax m->m_pkthdr.len = m->m_len = got = 1; 990187494Semax want = sizeof(ng_hci_scodata_pkt_t); 991187494Semax } else { 992187494Semax /* 993187494Semax * Check if we have SCO header and if so 994187494Semax * adjust amount of data we want 995187494Semax */ 996187494Semax got = m->m_pkthdr.len; 997187494Semax want = sizeof(ng_hci_scodata_pkt_t); 998184610Salfred 999187494Semax if (got >= want) 1000187494Semax want += mtod(m, ng_hci_scodata_pkt_t *)->length; 1001184610Salfred } 1002184610Salfred 1003187494Semax /* Append frame data to the SCO reassembly buffer */ 1004187494Semax if (got + len > want) 1005187494Semax len = want - got; 1006184610Salfred 1007187494Semax usb2_copy_out(xfer->frbuffers, frame_no * xfer->max_frame_size, 1008187494Semax mtod(m, uint8_t *) + m->m_pkthdr.len, len); 1009184610Salfred 1010187494Semax m->m_pkthdr.len += len; 1011187494Semax m->m_len += len; 1012187494Semax xfer->frlengths[frame_no] -= len; 1013184610Salfred 1014187494Semax /* Check if we got everything we wanted, if not - continue */ 1015187494Semax if (got != want) 1016187494Semax continue; 1017184610Salfred 1018187494Semax /* If we got here then we got complete SCO frame */ 1019187494Semax UBT_INFO(sc, "got complete SCO data frame, pktlen=%d, " \ 1020187494Semax "length=%d\n", m->m_pkthdr.len, 1021187494Semax mtod(m, ng_hci_scodata_pkt_t *)->length); 1022184610Salfred 1023187494Semax UBT_STAT_PCKTS_RECV(sc); 1024187494Semax UBT_STAT_BYTES_RECV(sc, m->m_pkthdr.len); 1025184610Salfred 1026187741Semax ubt_fwd_mbuf_up(sc, &m); 1027187494Semax /* m == NULL at this point */ 1028187494Semax } 1029184610Salfred 1030187494Semax /* Put SCO reassembly buffer back */ 1031187494Semax sc->sc_isoc_in_buffer = m; 1032184610Salfred 1033187494Semax return (0); 1034187494Semax} /* ubt_isoc_read_one_frame */ 1035184610Salfred 1036187494Semax/* 1037187494Semax * Called when outgoing isoc transfer (SCO packet) has completed, i.e. 1038187494Semax * SCO packet was sent to the device. 1039187494Semax * USB context. 1040187494Semax */ 1041184610Salfred 1042184610Salfredstatic void 1043184610Salfredubt_isoc_write_callback(struct usb2_xfer *xfer) 1044184610Salfred{ 1045187741Semax struct ubt_softc *sc = xfer->priv_sc; 1046187494Semax struct mbuf *m; 1047187494Semax int n, space, offset; 1048184610Salfred 1049184610Salfred switch (USB_GET_STATE(xfer)) { 1050184610Salfred case USB_ST_TRANSFERRED: 1051187741Semax UBT_INFO(sc, "sent %d bytes to isoc-out pipe\n", xfer->actlen); 1052187741Semax UBT_STAT_BYTES_SENT(sc, xfer->actlen); 1053187741Semax UBT_STAT_PCKTS_SENT(sc); 1054187494Semax /* FALLTHROUGH */ 1055184610Salfred 1056184610Salfred case USB_ST_SETUP: 1057187494Semaxsend_next: 1058184610Salfred offset = 0; 1059187494Semax space = xfer->max_frame_size * xfer->nframes; 1060187494Semax m = NULL; 1061184610Salfred 1062187494Semax while (space > 0) { 1063187494Semax if (m == NULL) { 1064187741Semax UBT_NG_LOCK(sc); 1065187494Semax NG_BT_MBUFQ_DEQUEUE(&sc->sc_scoq, m); 1066187741Semax UBT_NG_UNLOCK(sc); 1067184610Salfred 1068187494Semax if (m == NULL) 1069187494Semax break; 1070187494Semax } 1071184610Salfred 1072187494Semax n = min(space, m->m_pkthdr.len); 1073187494Semax if (n > 0) { 1074187494Semax usb2_m_copy_in(xfer->frbuffers, offset, m,0, n); 1075187494Semax m_adj(m, n); 1076184610Salfred 1077187494Semax offset += n; 1078187494Semax space -= n; 1079187494Semax } 1080184610Salfred 1081187494Semax if (m->m_pkthdr.len == 0) 1082187494Semax NG_FREE_M(m); /* sets m = NULL */ 1083187494Semax } 1084184610Salfred 1085187494Semax /* Put whatever is left from mbuf back on queue */ 1086187494Semax if (m != NULL) { 1087187741Semax UBT_NG_LOCK(sc); 1088187494Semax NG_BT_MBUFQ_PREPEND(&sc->sc_scoq, m); 1089187741Semax UBT_NG_UNLOCK(sc); 1090184610Salfred } 1091184610Salfred 1092187494Semax /* 1093187494Semax * Calculate sizes for isoc frames. 1094187494Semax * Note that offset could be 0 at this point (i.e. we have 1095187494Semax * nothing to send). That is fine, as we have isoc. transfers 1096187494Semax * going in both directions all the time. In this case it 1097187494Semax * would be just empty isoc. transfer. 1098187494Semax */ 1099187494Semax 1100187494Semax for (n = 0; n < xfer->nframes; n ++) { 1101187494Semax xfer->frlengths[n] = min(offset, xfer->max_frame_size); 1102187494Semax offset -= xfer->frlengths[n]; 1103187494Semax } 1104187494Semax 1105184610Salfred usb2_start_hardware(xfer); 1106187494Semax break; 1107184610Salfred 1108187494Semax default: /* Error */ 1109187494Semax if (xfer->error != USB_ERR_CANCELLED) { 1110187494Semax UBT_STAT_OERROR(sc); 1111187494Semax goto send_next; 1112184610Salfred } 1113187494Semax 1114187741Semax /* transfer cancelled */ 1115187494Semax break; 1116184610Salfred } 1117184610Salfred} 1118184610Salfred 1119187741Semax/* 1120187741Semax * Utility function to forward provided mbuf upstream (i.e. up the stack). 1121187741Semax * Modifies value of the mbuf pointer (sets it to NULL). 1122187741Semax * Save to call from any context. 1123187741Semax */ 1124187741Semax 1125187741Semaxstatic int 1126187741Semaxubt_fwd_mbuf_up(ubt_softc_p sc, struct mbuf **m) 1127187741Semax{ 1128187741Semax hook_p hook; 1129187741Semax int error; 1130187741Semax 1131187741Semax /* 1132187741Semax * Close the race with Netgraph hook newhook/disconnect methods. 1133187741Semax * Save the hook pointer atomically. Two cases are possible: 1134187741Semax * 1135187741Semax * 1) The hook pointer is NULL. It means disconnect method got 1136187741Semax * there first. In this case we are done. 1137187741Semax * 1138187741Semax * 2) The hook pointer is not NULL. It means that hook pointer 1139187741Semax * could be either in valid or invalid (i.e. in the process 1140187741Semax * of disconnect) state. In any case grab an extra reference 1141187741Semax * to protect the hook pointer. 1142187741Semax * 1143187741Semax * It is ok to pass hook in invalid state to NG_SEND_DATA_ONLY() as 1144187741Semax * it checks for it. Drop extra reference after NG_SEND_DATA_ONLY(). 1145187741Semax */ 1146187741Semax 1147187741Semax UBT_NG_LOCK(sc); 1148187741Semax if ((hook = sc->sc_hook) != NULL) 1149187741Semax NG_HOOK_REF(hook); 1150187741Semax UBT_NG_UNLOCK(sc); 1151187741Semax 1152187741Semax if (hook == NULL) { 1153187741Semax NG_FREE_M(*m); 1154187741Semax return (ENETDOWN); 1155187741Semax } 1156187741Semax 1157187741Semax NG_SEND_DATA_ONLY(error, hook, *m); 1158187741Semax NG_HOOK_UNREF(hook); 1159187741Semax 1160187741Semax if (error != 0) 1161187741Semax UBT_STAT_IERROR(sc); 1162187741Semax 1163187741Semax return (error); 1164187741Semax} /* ubt_fwd_mbuf_up */ 1165187741Semax 1166184610Salfred/**************************************************************************** 1167184610Salfred **************************************************************************** 1168187494Semax ** Glue 1169184610Salfred **************************************************************************** 1170184610Salfred ****************************************************************************/ 1171184610Salfred 1172184610Salfred/* 1173187741Semax * Schedule glue task. Should be called with sc_ng_mtx held. 1174187494Semax * Netgraph context. 1175184610Salfred */ 1176184610Salfred 1177187741Semaxstatic void 1178187494Semaxubt_task_schedule(ubt_softc_p sc, int action) 1179184610Salfred{ 1180187741Semax mtx_assert(&sc->sc_ng_mtx, MA_OWNED); 1181184610Salfred 1182187741Semax /* 1183187741Semax * Try to handle corner case when "start all" and "stop all" 1184187741Semax * actions can both be set before task is executed. 1185187741Semax * 1186187741Semax * The rules are 1187187741Semax * 1188187741Semax * sc_task_flags action new sc_task_flags 1189187741Semax * ------------------------------------------------------ 1190187741Semax * 0 start start 1191187741Semax * 0 stop stop 1192187741Semax * start start start 1193187741Semax * start stop stop 1194187741Semax * stop start stop|start 1195187741Semax * stop stop stop 1196187741Semax * stop|start start stop|start 1197187741Semax * stop|start stop stop 1198187741Semax */ 1199187494Semax 1200187741Semax if (action != 0) { 1201187741Semax if ((action & UBT_FLAG_T_STOP_ALL) != 0) 1202187494Semax sc->sc_task_flags &= ~UBT_FLAG_T_START_ALL; 1203187494Semax 1204187494Semax sc->sc_task_flags |= action; 1205187494Semax } 1206187494Semax 1207187494Semax if (sc->sc_task_flags & UBT_FLAG_T_PENDING) 1208187741Semax return; 1209187494Semax 1210187494Semax if (taskqueue_enqueue(taskqueue_swi, &sc->sc_task) == 0) { 1211187494Semax sc->sc_task_flags |= UBT_FLAG_T_PENDING; 1212187741Semax return; 1213187494Semax } 1214187494Semax 1215187494Semax /* XXX: i think this should never happen */ 1216187494Semax} /* ubt_task_schedule */ 1217187494Semax 1218184610Salfred/* 1219187494Semax * Glue task. Examines sc_task_flags and does things depending on it. 1220187494Semax * Taskqueue context. 1221184610Salfred */ 1222184610Salfred 1223187494Semaxstatic void 1224187494Semaxubt_task(void *context, int pending) 1225184610Salfred{ 1226187741Semax ubt_softc_p sc = context; 1227187741Semax int task_flags, i; 1228184610Salfred 1229187741Semax UBT_NG_LOCK(sc); 1230187494Semax task_flags = sc->sc_task_flags; 1231187494Semax sc->sc_task_flags = 0; 1232187741Semax UBT_NG_UNLOCK(sc); 1233187494Semax 1234187741Semax /* 1235187741Semax * Stop all USB transfers synchronously. 1236187741Semax * Stop interface #0 and #1 transfers at the same time and in the 1237187741Semax * same loop. usb2_transfer_drain() will do appropriate locking. 1238187741Semax */ 1239187494Semax 1240187741Semax if (task_flags & UBT_FLAG_T_STOP_ALL) 1241187741Semax for (i = 0; i < UBT_N_TRANSFER; i ++) 1242187741Semax usb2_transfer_drain(sc->sc_xfer[i]); 1243187494Semax 1244187741Semax /* Start incoming interrupt and bulk, and all isoc. USB transfers */ 1245187494Semax if (task_flags & UBT_FLAG_T_START_ALL) { 1246187494Semax /* 1247187494Semax * Interface #0 1248187494Semax */ 1249187494Semax 1250187741Semax mtx_lock(&sc->sc_if_mtx); 1251187741Semax 1252187494Semax ubt_xfer_start(sc, UBT_IF_0_INTR_DT_RD); 1253187494Semax ubt_xfer_start(sc, UBT_IF_0_BULK_DT_RD); 1254187494Semax 1255187494Semax /* 1256187494Semax * Interface #1 1257187494Semax * Start both read and write isoc. transfers by default. 1258187494Semax * Get them going all the time even if we have nothing 1259187494Semax * to send to avoid any delays. 1260187494Semax */ 1261187494Semax 1262187494Semax ubt_xfer_start(sc, UBT_IF_1_ISOC_DT_RD1); 1263187494Semax ubt_xfer_start(sc, UBT_IF_1_ISOC_DT_RD2); 1264187494Semax ubt_xfer_start(sc, UBT_IF_1_ISOC_DT_WR1); 1265187494Semax ubt_xfer_start(sc, UBT_IF_1_ISOC_DT_WR2); 1266187741Semax 1267187741Semax mtx_unlock(&sc->sc_if_mtx); 1268184610Salfred } 1269187494Semax 1270187494Semax /* Start outgoing control transfer */ 1271187494Semax if (task_flags & UBT_FLAG_T_START_CTRL) { 1272187741Semax mtx_lock(&sc->sc_if_mtx); 1273187494Semax ubt_xfer_start(sc, UBT_IF_0_CTRL_DT_WR); 1274187741Semax mtx_unlock(&sc->sc_if_mtx); 1275184610Salfred } 1276184610Salfred 1277187494Semax /* Start outgoing bulk transfer */ 1278187494Semax if (task_flags & UBT_FLAG_T_START_BULK) { 1279187741Semax mtx_lock(&sc->sc_if_mtx); 1280187494Semax ubt_xfer_start(sc, UBT_IF_0_BULK_DT_WR); 1281187741Semax mtx_unlock(&sc->sc_if_mtx); 1282184610Salfred } 1283187494Semax} /* ubt_task */ 1284187494Semax 1285187494Semax/**************************************************************************** 1286187494Semax **************************************************************************** 1287187494Semax ** Netgraph specific 1288187494Semax **************************************************************************** 1289187494Semax ****************************************************************************/ 1290184610Salfred 1291187494Semax/* 1292187494Semax * Netgraph node constructor. Do not allow to create node of this type. 1293187494Semax * Netgraph context. 1294187494Semax */ 1295184610Salfred 1296187494Semaxstatic int 1297187494Semaxng_ubt_constructor(node_p node) 1298187494Semax{ 1299187494Semax return (EINVAL); 1300187494Semax} /* ng_ubt_constructor */ 1301184610Salfred 1302184610Salfred/* 1303187494Semax * Netgraph node destructor. Destroy node only when device has been detached. 1304187494Semax * Netgraph context. 1305184610Salfred */ 1306184610Salfred 1307184610Salfredstatic int 1308187494Semaxng_ubt_shutdown(node_p node) 1309184610Salfred{ 1310187494Semax if (node->nd_flags & NGF_REALLY_DIE) { 1311187494Semax /* 1312187494Semax * We came here because the USB device is being 1313187494Semax * detached, so stop being persistant. 1314187494Semax */ 1315187494Semax NG_NODE_SET_PRIVATE(node, NULL); 1316187494Semax NG_NODE_UNREF(node); 1317187494Semax } else 1318187494Semax NG_NODE_REVIVE(node); /* tell ng_rmnode we are persisant */ 1319184610Salfred 1320187494Semax return (0); 1321187494Semax} /* ng_ubt_shutdown */ 1322184610Salfred 1323187494Semax/* 1324187494Semax * Create new hook. There can only be one. 1325187494Semax * Netgraph context. 1326187494Semax */ 1327184610Salfred 1328187494Semaxstatic int 1329187494Semaxng_ubt_newhook(node_p node, hook_p hook, char const *name) 1330187494Semax{ 1331187494Semax struct ubt_softc *sc = NG_NODE_PRIVATE(node); 1332184610Salfred 1333187494Semax if (strcmp(name, NG_UBT_HOOK) != 0) 1334187494Semax return (EINVAL); 1335184610Salfred 1336187741Semax UBT_NG_LOCK(sc); 1337187741Semax if (sc->sc_hook != NULL) { 1338187741Semax UBT_NG_UNLOCK(sc); 1339187741Semax 1340187494Semax return (EISCONN); 1341187741Semax } 1342184610Salfred 1343187494Semax sc->sc_hook = hook; 1344187741Semax UBT_NG_UNLOCK(sc); 1345184610Salfred 1346187494Semax return (0); 1347187494Semax} /* ng_ubt_newhook */ 1348184610Salfred 1349187494Semax/* 1350187494Semax * Connect hook. Start incoming USB transfers. 1351187494Semax * Netgraph context. 1352187494Semax */ 1353184610Salfred 1354187494Semaxstatic int 1355187494Semaxng_ubt_connect(hook_p hook) 1356187494Semax{ 1357187494Semax struct ubt_softc *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 1358184610Salfred 1359187494Semax NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook)); 1360184610Salfred 1361187741Semax UBT_NG_LOCK(sc); 1362187494Semax ubt_task_schedule(sc, UBT_FLAG_T_START_ALL); 1363187741Semax UBT_NG_UNLOCK(sc); 1364184610Salfred 1365184610Salfred return (0); 1366187494Semax} /* ng_ubt_connect */ 1367184610Salfred 1368184610Salfred/* 1369187494Semax * Disconnect hook. 1370187494Semax * Netgraph context. 1371184610Salfred */ 1372184610Salfred 1373184610Salfredstatic int 1374184610Salfredng_ubt_disconnect(hook_p hook) 1375184610Salfred{ 1376187741Semax struct ubt_softc *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 1377184610Salfred 1378187741Semax UBT_NG_LOCK(sc); 1379184610Salfred 1380187741Semax if (hook != sc->sc_hook) { 1381187741Semax UBT_NG_UNLOCK(sc); 1382184610Salfred 1383187494Semax return (EINVAL); 1384187741Semax } 1385184610Salfred 1386187494Semax sc->sc_hook = NULL; 1387184610Salfred 1388187741Semax /* Kick off task to stop all USB xfers */ 1389187741Semax ubt_task_schedule(sc, UBT_FLAG_T_STOP_ALL); 1390184610Salfred 1391187494Semax /* Drain queues */ 1392187494Semax NG_BT_MBUFQ_DRAIN(&sc->sc_cmdq); 1393187494Semax NG_BT_MBUFQ_DRAIN(&sc->sc_aclq); 1394187494Semax NG_BT_MBUFQ_DRAIN(&sc->sc_scoq); 1395184610Salfred 1396187741Semax UBT_NG_UNLOCK(sc); 1397184610Salfred 1398187494Semax return (0); 1399187494Semax} /* ng_ubt_disconnect */ 1400187494Semax 1401184610Salfred/* 1402187494Semax * Process control message. 1403187494Semax * Netgraph context. 1404184610Salfred */ 1405184610Salfred 1406184610Salfredstatic int 1407184610Salfredng_ubt_rcvmsg(node_p node, item_p item, hook_p lasthook) 1408184610Salfred{ 1409187494Semax struct ubt_softc *sc = NG_NODE_PRIVATE(node); 1410187494Semax struct ng_mesg *msg, *rsp = NULL; 1411187494Semax struct ng_bt_mbufq *q; 1412187494Semax int error = 0, queue, qlen; 1413184610Salfred 1414184610Salfred NGI_GET_MSG(item, msg); 1415184610Salfred 1416184610Salfred switch (msg->header.typecookie) { 1417184610Salfred case NGM_GENERIC_COOKIE: 1418184610Salfred switch (msg->header.cmd) { 1419184610Salfred case NGM_TEXT_STATUS: 1420184610Salfred NG_MKRESPONSE(rsp, msg, NG_TEXTRESPONSE, M_NOWAIT); 1421187494Semax if (rsp == NULL) { 1422184610Salfred error = ENOMEM; 1423187494Semax break; 1424187494Semax } 1425187494Semax 1426187494Semax snprintf(rsp->data, NG_TEXTRESPONSE, 1427187494Semax "Hook: %s\n" \ 1428187494Semax "Task flags: %#x\n" \ 1429187494Semax "Debug: %d\n" \ 1430187494Semax "CMD queue: [have:%d,max:%d]\n" \ 1431187494Semax "ACL queue: [have:%d,max:%d]\n" \ 1432187494Semax "SCO queue: [have:%d,max:%d]", 1433187741Semax (sc->sc_hook != NULL) ? NG_UBT_HOOK : "", 1434187494Semax sc->sc_task_flags, 1435187494Semax sc->sc_debug, 1436187494Semax sc->sc_cmdq.len, 1437187494Semax sc->sc_cmdq.maxlen, 1438187494Semax sc->sc_aclq.len, 1439187494Semax sc->sc_aclq.maxlen, 1440187494Semax sc->sc_scoq.len, 1441187494Semax sc->sc_scoq.maxlen); 1442184610Salfred break; 1443184610Salfred 1444184610Salfred default: 1445184610Salfred error = EINVAL; 1446184610Salfred break; 1447184610Salfred } 1448184610Salfred break; 1449184610Salfred 1450184610Salfred case NGM_UBT_COOKIE: 1451184610Salfred switch (msg->header.cmd) { 1452184610Salfred case NGM_UBT_NODE_SET_DEBUG: 1453187494Semax if (msg->header.arglen != sizeof(ng_ubt_node_debug_ep)){ 1454184610Salfred error = EMSGSIZE; 1455187494Semax break; 1456187494Semax } 1457187494Semax 1458187494Semax sc->sc_debug = *((ng_ubt_node_debug_ep *) (msg->data)); 1459184610Salfred break; 1460184610Salfred 1461184610Salfred case NGM_UBT_NODE_GET_DEBUG: 1462184610Salfred NG_MKRESPONSE(rsp, msg, sizeof(ng_ubt_node_debug_ep), 1463184610Salfred M_NOWAIT); 1464187494Semax if (rsp == NULL) { 1465184610Salfred error = ENOMEM; 1466187494Semax break; 1467187494Semax } 1468187494Semax 1469187494Semax *((ng_ubt_node_debug_ep *) (rsp->data)) = sc->sc_debug; 1470184610Salfred break; 1471184610Salfred 1472184610Salfred case NGM_UBT_NODE_SET_QLEN: 1473187494Semax if (msg->header.arglen != sizeof(ng_ubt_node_qlen_ep)) { 1474184610Salfred error = EMSGSIZE; 1475187494Semax break; 1476187494Semax } 1477184610Salfred 1478187494Semax queue = ((ng_ubt_node_qlen_ep *) (msg->data))->queue; 1479187494Semax qlen = ((ng_ubt_node_qlen_ep *) (msg->data))->qlen; 1480184610Salfred 1481187494Semax switch (queue) { 1482187494Semax case NGM_UBT_NODE_QUEUE_CMD: 1483187494Semax q = &sc->sc_cmdq; 1484187494Semax break; 1485184610Salfred 1486187494Semax case NGM_UBT_NODE_QUEUE_ACL: 1487187494Semax q = &sc->sc_aclq; 1488187494Semax break; 1489184610Salfred 1490187494Semax case NGM_UBT_NODE_QUEUE_SCO: 1491187494Semax q = &sc->sc_scoq; 1492187494Semax break; 1493184610Salfred 1494187494Semax default: 1495187494Semax error = EINVAL; 1496187494Semax goto done; 1497187494Semax /* NOT REACHED */ 1498184610Salfred } 1499187494Semax 1500187494Semax q->maxlen = qlen; 1501184610Salfred break; 1502184610Salfred 1503184610Salfred case NGM_UBT_NODE_GET_QLEN: 1504184610Salfred if (msg->header.arglen != sizeof(ng_ubt_node_qlen_ep)) { 1505184610Salfred error = EMSGSIZE; 1506184610Salfred break; 1507184610Salfred } 1508187494Semax 1509184610Salfred queue = ((ng_ubt_node_qlen_ep *) (msg->data))->queue; 1510187494Semax 1511184610Salfred switch (queue) { 1512184610Salfred case NGM_UBT_NODE_QUEUE_CMD: 1513184610Salfred q = &sc->sc_cmdq; 1514184610Salfred break; 1515184610Salfred 1516184610Salfred case NGM_UBT_NODE_QUEUE_ACL: 1517184610Salfred q = &sc->sc_aclq; 1518184610Salfred break; 1519184610Salfred 1520184610Salfred case NGM_UBT_NODE_QUEUE_SCO: 1521184610Salfred q = &sc->sc_scoq; 1522184610Salfred break; 1523184610Salfred 1524184610Salfred default: 1525184610Salfred error = EINVAL; 1526187494Semax goto done; 1527187494Semax /* NOT REACHED */ 1528187494Semax } 1529187494Semax 1530187494Semax NG_MKRESPONSE(rsp, msg, sizeof(ng_ubt_node_qlen_ep), 1531187494Semax M_NOWAIT); 1532187494Semax if (rsp == NULL) { 1533187494Semax error = ENOMEM; 1534184610Salfred break; 1535184610Salfred } 1536184610Salfred 1537187494Semax ((ng_ubt_node_qlen_ep *) (rsp->data))->queue = queue; 1538187494Semax ((ng_ubt_node_qlen_ep *) (rsp->data))->qlen = q->maxlen; 1539184610Salfred break; 1540184610Salfred 1541184610Salfred case NGM_UBT_NODE_GET_STAT: 1542184610Salfred NG_MKRESPONSE(rsp, msg, sizeof(ng_ubt_node_stat_ep), 1543184610Salfred M_NOWAIT); 1544187494Semax if (rsp == NULL) { 1545184610Salfred error = ENOMEM; 1546187494Semax break; 1547184610Salfred } 1548187494Semax 1549187494Semax bcopy(&sc->sc_stat, rsp->data, 1550187494Semax sizeof(ng_ubt_node_stat_ep)); 1551184610Salfred break; 1552184610Salfred 1553184610Salfred case NGM_UBT_NODE_RESET_STAT: 1554187494Semax UBT_STAT_RESET(sc); 1555184610Salfred break; 1556184610Salfred 1557184610Salfred default: 1558184610Salfred error = EINVAL; 1559184610Salfred break; 1560184610Salfred } 1561184610Salfred break; 1562184610Salfred 1563184610Salfred default: 1564184610Salfred error = EINVAL; 1565184610Salfred break; 1566184610Salfred } 1567187494Semaxdone: 1568184610Salfred NG_RESPOND_MSG(error, node, item, rsp); 1569184610Salfred NG_FREE_MSG(msg); 1570184610Salfred 1571184610Salfred return (error); 1572187494Semax} /* ng_ubt_rcvmsg */ 1573184610Salfred 1574184610Salfred/* 1575187494Semax * Process data. 1576187494Semax * Netgraph context. 1577184610Salfred */ 1578184610Salfred 1579184610Salfredstatic int 1580184610Salfredng_ubt_rcvdata(hook_p hook, item_p item) 1581184610Salfred{ 1582187494Semax struct ubt_softc *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 1583187494Semax struct mbuf *m; 1584187494Semax struct ng_bt_mbufq *q; 1585187494Semax int action, error = 0; 1586184610Salfred 1587184610Salfred if (hook != sc->sc_hook) { 1588184610Salfred error = EINVAL; 1589184610Salfred goto done; 1590184610Salfred } 1591187494Semax 1592187494Semax /* Deatch mbuf and get HCI frame type */ 1593184610Salfred NGI_GET_M(item, m); 1594184610Salfred 1595187494Semax /* 1596187494Semax * Minimal size of the HCI frame is 4 bytes: 1 byte frame type, 1597187494Semax * 2 bytes connection handle and at least 1 byte of length. 1598187494Semax * Panic on data frame that has size smaller than 4 bytes (it 1599187494Semax * should not happen) 1600187494Semax */ 1601187494Semax 1602187494Semax if (m->m_pkthdr.len < 4) 1603187494Semax panic("HCI frame size is too small! pktlen=%d\n", 1604187494Semax m->m_pkthdr.len); 1605187494Semax 1606187494Semax /* Process HCI frame */ 1607184610Salfred switch (*mtod(m, uint8_t *)) { /* XXX call m_pullup ? */ 1608184610Salfred case NG_HCI_CMD_PKT: 1609187494Semax if (m->m_pkthdr.len - 1 > UBT_CTRL_BUFFER_SIZE) 1610187494Semax panic("HCI command frame size is too big! " \ 1611187494Semax "buffer size=%zd, packet len=%d\n", 1612187494Semax UBT_CTRL_BUFFER_SIZE, m->m_pkthdr.len); 1613187494Semax 1614184610Salfred q = &sc->sc_cmdq; 1615187494Semax action = UBT_FLAG_T_START_CTRL; 1616184610Salfred break; 1617184610Salfred 1618184610Salfred case NG_HCI_ACL_DATA_PKT: 1619187494Semax if (m->m_pkthdr.len - 1 > UBT_BULK_WRITE_BUFFER_SIZE) 1620187494Semax panic("ACL data frame size is too big! " \ 1621187494Semax "buffer size=%d, packet len=%d\n", 1622187494Semax UBT_BULK_WRITE_BUFFER_SIZE, m->m_pkthdr.len); 1623187494Semax 1624184610Salfred q = &sc->sc_aclq; 1625187494Semax action = UBT_FLAG_T_START_BULK; 1626184610Salfred break; 1627184610Salfred 1628184610Salfred case NG_HCI_SCO_DATA_PKT: 1629184610Salfred q = &sc->sc_scoq; 1630187494Semax action = 0; 1631184610Salfred break; 1632184610Salfred 1633184610Salfred default: 1634187494Semax UBT_ERR(sc, "Dropping unsupported HCI frame, type=0x%02x, " \ 1635187494Semax "pktlen=%d\n", *mtod(m, uint8_t *), m->m_pkthdr.len); 1636184610Salfred 1637184610Salfred NG_FREE_M(m); 1638184610Salfred error = EINVAL; 1639184610Salfred goto done; 1640187494Semax /* NOT REACHED */ 1641184610Salfred } 1642184610Salfred 1643187741Semax UBT_NG_LOCK(sc); 1644184610Salfred if (NG_BT_MBUFQ_FULL(q)) { 1645187494Semax NG_BT_MBUFQ_DROP(q); 1646187741Semax UBT_NG_UNLOCK(sc); 1647187494Semax 1648187494Semax UBT_ERR(sc, "Dropping HCI frame 0x%02x, len=%d. Queue full\n", 1649187494Semax *mtod(m, uint8_t *), m->m_pkthdr.len); 1650187494Semax 1651184610Salfred NG_FREE_M(m); 1652184610Salfred } else { 1653187494Semax /* Loose HCI packet type, enqueue mbuf and kick off task */ 1654187494Semax m_adj(m, sizeof(uint8_t)); 1655184610Salfred NG_BT_MBUFQ_ENQUEUE(q, m); 1656187494Semax ubt_task_schedule(sc, action); 1657187741Semax UBT_NG_UNLOCK(sc); 1658184610Salfred } 1659184610Salfreddone: 1660184610Salfred NG_FREE_ITEM(item); 1661184610Salfred 1662187494Semax return (error); 1663187494Semax} /* ng_ubt_rcvdata */ 1664187494Semax 1665187494Semax/**************************************************************************** 1666187494Semax **************************************************************************** 1667187494Semax ** Module 1668187494Semax **************************************************************************** 1669187494Semax ****************************************************************************/ 1670187494Semax 1671187494Semax/* 1672187494Semax * Load/Unload the driver module 1673187494Semax */ 1674187494Semax 1675187494Semaxstatic int 1676187494Semaxubt_modevent(module_t mod, int event, void *data) 1677187494Semax{ 1678187494Semax int error; 1679187494Semax 1680187494Semax switch (event) { 1681187494Semax case MOD_LOAD: 1682187494Semax error = ng_newtype(&typestruct); 1683187494Semax if (error != 0) 1684187494Semax printf("%s: Could not register Netgraph node type, " \ 1685187494Semax "error=%d\n", NG_UBT_NODE_TYPE, error); 1686187494Semax break; 1687187494Semax 1688187494Semax case MOD_UNLOAD: 1689187494Semax error = ng_rmtype(&typestruct); 1690187494Semax break; 1691187494Semax 1692187494Semax default: 1693187494Semax error = EOPNOTSUPP; 1694187494Semax break; 1695184610Salfred } 1696187494Semax 1697184610Salfred return (error); 1698187494Semax} /* ubt_modevent */ 1699187494Semax 1700187494Semaxstatic devclass_t ubt_devclass; 1701187494Semax 1702187494Semaxstatic device_method_t ubt_methods[] = 1703187494Semax{ 1704187494Semax DEVMETHOD(device_probe, ubt_probe), 1705187494Semax DEVMETHOD(device_attach, ubt_attach), 1706187494Semax DEVMETHOD(device_detach, ubt_detach), 1707187494Semax { 0, 0 } 1708187494Semax}; 1709187494Semax 1710187494Semaxstatic driver_t ubt_driver = 1711187494Semax{ 1712187494Semax .name = "ubt", 1713187494Semax .methods = ubt_methods, 1714187494Semax .size = sizeof(struct ubt_softc), 1715187494Semax}; 1716187494Semax 1717189275SthompsaDRIVER_MODULE(ng_ubt, uhub, ubt_driver, ubt_devclass, ubt_modevent, 0); 1718187494SemaxMODULE_VERSION(ng_ubt, NG_BLUETOOTH_VERSION); 1719187494SemaxMODULE_DEPEND(ng_ubt, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION); 1720187494SemaxMODULE_DEPEND(ng_ubt, ng_hci, NG_BLUETOOTH_VERSION, NG_BLUETOOTH_VERSION, NG_BLUETOOTH_VERSION); 1721188942SthompsaMODULE_DEPEND(ng_ubt, usb, 1, 1, 1); 1722187494Semax 1723