From owner-p4-projects@FreeBSD.ORG Mon Jun 15 18:24:48 2009 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 77B421065670; Mon, 15 Jun 2009 18:24:48 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 34664106566B for ; Mon, 15 Jun 2009 18:24:48 +0000 (UTC) (envelope-from syl@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 2069E8FC0C for ; Mon, 15 Jun 2009 18:24:48 +0000 (UTC) (envelope-from syl@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id n5FIOmfE028978 for ; Mon, 15 Jun 2009 18:24:48 GMT (envelope-from syl@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id n5FIOlut028976 for perforce@freebsd.org; Mon, 15 Jun 2009 18:24:47 GMT (envelope-from syl@FreeBSD.org) Date: Mon, 15 Jun 2009 18:24:47 GMT Message-Id: <200906151824.n5FIOlut028976@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to syl@FreeBSD.org using -f From: Sylvestre Gallon To: Perforce Change Reviews Cc: Subject: PERFORCE change 164443 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 15 Jun 2009 18:24:50 -0000 http://perforce.freebsd.org/chv.cgi?CH=164443 Change 164443 by syl@syl_atuin on 2009/06/15 18:24:19 MFC needed to compile a kernel. Affected files ... .. //depot/projects/soc2009/syl_usb/src/sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c#2 integrate .. //depot/projects/soc2009/syl_usb/src/sys/netgraph/bluetooth/drivers/ubt/ng_ubt_var.h#2 integrate .. //depot/projects/soc2009/syl_usb/src/sys/netgraph/bluetooth/drivers/ubtbcmfw/ubtbcmfw.c#2 integrate Differences ... ==== //depot/projects/soc2009/syl_usb/src/sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c#2 (text+ko) ==== @@ -3,7 +3,7 @@ */ /*- - * Copyright (c) 2001-2002 Maksim Yevmenkin + * Copyright (c) 2001-2009 Maksim Yevmenkin * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,29 +27,89 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: ng_ubt.c,v 1.22 2005/10/31 17:57:44 max Exp $ - * $FreeBSD: src/sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c,v 1.36 2008/10/03 22:40:42 emax Exp $ + * $Id: ng_ubt.c,v 1.16 2003/10/10 19:15:06 max Exp $ + * $FreeBSD: src/sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c,v 1.42 2009/06/15 01:02:43 thompsa Exp $ */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +/* + * NOTE: ng_ubt2 driver has a split personality. On one side it is + * a USB device driver and on the other it is a Netgraph node. This + * driver will *NOT* create traditional /dev/ enties, only Netgraph + * node. + * + * NOTE ON LOCKS USED: ng_ubt2 drives uses 2 locks (mutexes) + * + * 1) sc_if_mtx - lock for device's interface #0 and #1. This lock is used + * by USB for any USB request going over device's interface #0 and #1, + * i.e. interrupt, control, bulk and isoc. transfers. + * + * 2) sc_ng_mtx - this lock is used to protect shared (between USB, Netgraph + * and Taskqueue) data, such as outgoing mbuf queues, task flags and hook + * pointer. This lock *SHOULD NOT* be grabbed for a long time. In fact, + * think of it as a spin lock. + * + * NOTE ON LOCKING STRATEGY: ng_ubt2 driver operates in 3 different contexts. + * + * 1) USB context. This is where all the USB related stuff happens. All + * callbacks run in this context. All callbacks are called (by USB) with + * appropriate interface lock held. It is (generally) allowed to grab + * any additional locks. + * + * 2) Netgraph context. This is where all the Netgraph related stuff happens. + * Since we mark node as WRITER, the Netgraph node will be "locked" (from + * Netgraph point of view). Any variable that is only modified from the + * Netgraph context does not require any additonal locking. It is generally + * *NOT* allowed to grab *ANY* additional locks. Whatever you do, *DO NOT* + * grab any lock in the Netgraph context that could cause de-scheduling of + * the Netgraph thread for significant amount of time. In fact, the only + * lock that is allowed in the Netgraph context is the sc_ng_mtx lock. + * Also make sure that any code that is called from the Netgraph context + * follows the rule above. + * + * 3) Taskqueue context. This is where ubt_task runs. Since we are generally + * NOT allowed to grab any lock that could cause de-scheduling in the + * Netgraph context, and, USB requires us to grab interface lock before + * doing things with transfers, it is safer to transition from the Netgraph + * context to the Taskqueue context before we can call into USB subsystem. + * + * So, to put everything together, the rules are as follows. + * It is OK to call from the USB context or the Taskqueue context into + * the Netgraph context (i.e. call NG_SEND_xxx functions). In other words + * it is allowed to call into the Netgraph context with locks held. + * Is it *NOT* OK to call from the Netgraph context into the USB context, + * because USB requires us to grab interface locks, and, it is safer to + * avoid it. So, to make things safer we set task flags to indicate which + * actions we want to perform and schedule ubt_task which would run in the + * Taskqueue context. + * Is is OK to call from the Taskqueue context into the USB context, + * and, ubt_task does just that (i.e. grabs appropriate interface locks + * before calling into USB). + * Access to the outgoing queues, task flags and hook pointer is + * controlled by the sc_ng_mtx lock. It is an unavoidable evil. Again, + * sc_ng_mtx should really be a spin lock (and it is very likely to an + * equivalent of spin lock due to adaptive nature of FreeBSD mutexes). + * All USB callbacks accept softc pointer as a private data. USB ensures + * that this pointer is valid. + */ +#include "usbdevs.h" #include -#include -#include -#include +#include +#include + +#define USB_DEBUG_VAR usb_debug + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include #include #include @@ -59,73 +119,17 @@ #include #include -#include "usbdevs.h" +static int ubt_modevent(module_t, int, void *); +static device_probe_t ubt_probe; +static device_attach_t ubt_attach; +static device_detach_t ubt_detach; -/* - * USB methods - */ +static void ubt_task_schedule(ubt_softc_p, int); +static task_fn_t ubt_task; -static device_probe_t ubt_match; -static device_attach_t ubt_attach; -static device_detach_t ubt_detach; +#define ubt_xfer_start(sc, i) usbd_transfer_start((sc)->sc_xfer[(i)]) -static device_method_t ubt_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, ubt_match), - DEVMETHOD(device_attach, ubt_attach), - DEVMETHOD(device_detach, ubt_detach), - - { 0, 0 } -}; - -static driver_t ubt_driver = { - "ubt", - ubt_methods, - sizeof(struct ubt_softc) -}; - -static devclass_t ubt_devclass; - -static int ubt_modevent (module_t, int, void *); - -static usbd_status ubt_request_start (ubt_softc_p); -static void ubt_request_complete (usbd_xfer_handle, - usbd_private_handle, usbd_status); -static void ubt_request_complete2 (node_p, hook_p, void *, int); - -static usbd_status ubt_intr_start (ubt_softc_p); -static void ubt_intr_complete (usbd_xfer_handle, - usbd_private_handle, usbd_status); -static void ubt_intr_complete2 (node_p, hook_p, void *, int); - -static usbd_status ubt_bulk_in_start (ubt_softc_p); -static void ubt_bulk_in_complete (usbd_xfer_handle, - usbd_private_handle, usbd_status); -static void ubt_bulk_in_complete2 (node_p, hook_p, void *, int); - -static usbd_status ubt_bulk_out_start (ubt_softc_p); -static void ubt_bulk_out_complete (usbd_xfer_handle, - usbd_private_handle, usbd_status); -static void ubt_bulk_out_complete2 (node_p, hook_p, void *, int); - -static usbd_status ubt_isoc_in_start_one (ubt_softc_p, int); -static usbd_status ubt_isoc_in_start (ubt_softc_p); -static void ubt_isoc_in_complete (usbd_xfer_handle, - usbd_private_handle, usbd_status); -static void ubt_isoc_in_complete2 (node_p, hook_p, void *, int); - -static usbd_status ubt_isoc_out_start_one (ubt_softc_p, int); -static usbd_status ubt_isoc_out_start (ubt_softc_p); -static void ubt_isoc_out_complete (usbd_xfer_handle, - usbd_private_handle, usbd_status); -static void ubt_isoc_out_complete2 (node_p, hook_p, void *, int); - -static void ubt_reset (ubt_softc_p); - -/* - * Netgraph methods - */ - +/* Netgraph methods */ static ng_constructor_t ng_ubt_constructor; static ng_shutdown_t ng_ubt_shutdown; static ng_newhook_t ng_ubt_newhook; @@ -141,7 +145,8 @@ { "qlen", &ng_parse_int32_type, }, { NULL, } }; -static const struct ng_parse_type ng_ubt_node_qlen_type = { +static const struct ng_parse_type ng_ubt_node_qlen_type = +{ &ng_parse_struct_type, &ng_ubt_node_qlen_type_fields }; @@ -157,61 +162,64 @@ { "ierrors", &ng_parse_uint32_type, }, { NULL, } }; -static const struct ng_parse_type ng_ubt_node_stat_type = { +static const struct ng_parse_type ng_ubt_node_stat_type = +{ &ng_parse_struct_type, &ng_ubt_node_stat_type_fields }; /* Netgraph node command list */ -static const struct ng_cmdlist ng_ubt_cmdlist[] = { +static const struct ng_cmdlist ng_ubt_cmdlist[] = { - NGM_UBT_COOKIE, - NGM_UBT_NODE_SET_DEBUG, - "set_debug", - &ng_parse_uint16_type, - NULL -}, -{ - NGM_UBT_COOKIE, - NGM_UBT_NODE_GET_DEBUG, - "get_debug", - NULL, - &ng_parse_uint16_type -}, -{ - NGM_UBT_COOKIE, - NGM_UBT_NODE_SET_QLEN, - "set_qlen", - &ng_ubt_node_qlen_type, - NULL -}, -{ - NGM_UBT_COOKIE, - NGM_UBT_NODE_GET_QLEN, - "get_qlen", - &ng_ubt_node_qlen_type, - &ng_ubt_node_qlen_type -}, -{ - NGM_UBT_COOKIE, - NGM_UBT_NODE_GET_STAT, - "get_stat", - NULL, - &ng_ubt_node_stat_type -}, -{ - NGM_UBT_COOKIE, - NGM_UBT_NODE_RESET_STAT, - "reset_stat", - NULL, - NULL -}, -{ 0, } + { + NGM_UBT_COOKIE, + NGM_UBT_NODE_SET_DEBUG, + "set_debug", + &ng_parse_uint16_type, + NULL + }, + { + NGM_UBT_COOKIE, + NGM_UBT_NODE_GET_DEBUG, + "get_debug", + NULL, + &ng_parse_uint16_type + }, + { + NGM_UBT_COOKIE, + NGM_UBT_NODE_SET_QLEN, + "set_qlen", + &ng_ubt_node_qlen_type, + NULL + }, + { + NGM_UBT_COOKIE, + NGM_UBT_NODE_GET_QLEN, + "get_qlen", + &ng_ubt_node_qlen_type, + &ng_ubt_node_qlen_type + }, + { + NGM_UBT_COOKIE, + NGM_UBT_NODE_GET_STAT, + "get_stat", + NULL, + &ng_ubt_node_stat_type + }, + { + NGM_UBT_COOKIE, + NGM_UBT_NODE_RESET_STAT, + "reset_stat", + NULL, + NULL + }, + { 0, } }; /* Netgraph node type */ -static struct ng_type typestruct = { - .version = NG_ABI_VERSION, +static struct ng_type typestruct = +{ + .version = NG_ABI_VERSION, .name = NG_UBT_NODE_TYPE, .constructor = ng_ubt_constructor, .rcvmsg = ng_ubt_rcvmsg, @@ -220,192 +228,251 @@ .connect = ng_ubt_connect, .rcvdata = ng_ubt_rcvdata, .disconnect = ng_ubt_disconnect, - .cmdlist = ng_ubt_cmdlist + .cmdlist = ng_ubt_cmdlist }; -/* - * Module - */ - -DRIVER_MODULE(ubt, uhub, ubt_driver, ubt_devclass, ubt_modevent, 0); -MODULE_VERSION(ng_ubt, NG_BLUETOOTH_VERSION); -MODULE_DEPEND(ng_ubt, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION); -MODULE_DEPEND(ubt, usb, 1, 1, 1); - - /**************************************************************************** **************************************************************************** ** USB specific **************************************************************************** ****************************************************************************/ +/* USB methods */ +static usb_callback_t ubt_ctrl_write_callback; +static usb_callback_t ubt_intr_read_callback; +static usb_callback_t ubt_bulk_read_callback; +static usb_callback_t ubt_bulk_write_callback; +static usb_callback_t ubt_isoc_read_callback; +static usb_callback_t ubt_isoc_write_callback; + +static int ubt_fwd_mbuf_up(ubt_softc_p, struct mbuf **); +static int ubt_isoc_read_one_frame(struct usb_xfer *, int); + /* - * Load/Unload the driver module + * USB config + * + * The following desribes usb transfers that could be submitted on USB device. + * + * Interface 0 on the USB device must present the following endpoints + * 1) Interrupt endpoint to receive HCI events + * 2) Bulk IN endpoint to receive ACL data + * 3) Bulk OUT endpoint to send ACL data + * + * Interface 1 on the USB device must present the following endpoints + * 1) Isochronous IN endpoint to receive SCO data + * 2) Isochronous OUT endpoint to send SCO data */ -static int -ubt_modevent(module_t mod, int event, void *data) +static const struct usb_config ubt_config[UBT_N_TRANSFER] = { - int error; + /* + * Interface #0 + */ + + /* Outgoing bulk transfer - ACL packets */ + [UBT_IF_0_BULK_DT_WR] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .if_index = 0, + .bufsize = UBT_BULK_WRITE_BUFFER_SIZE, + .flags = { .pipe_bof = 1, .force_short_xfer = 1, }, + .callback = &ubt_bulk_write_callback, + }, + /* Incoming bulk transfer - ACL packets */ + [UBT_IF_0_BULK_DT_RD] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_IN, + .if_index = 0, + .bufsize = UBT_BULK_READ_BUFFER_SIZE, + .flags = { .pipe_bof = 1, .short_xfer_ok = 1, }, + .callback = &ubt_bulk_read_callback, + }, + /* Incoming interrupt transfer - HCI events */ + [UBT_IF_0_INTR_DT_RD] = { + .type = UE_INTERRUPT, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_IN, + .if_index = 0, + .flags = { .pipe_bof = 1, .short_xfer_ok = 1, }, + .bufsize = UBT_INTR_BUFFER_SIZE, + .callback = &ubt_intr_read_callback, + }, + /* Outgoing control transfer - HCI commands */ + [UBT_IF_0_CTRL_DT_WR] = { + .type = UE_CONTROL, + .endpoint = 0x00, /* control pipe */ + .direction = UE_DIR_ANY, + .if_index = 0, + .bufsize = UBT_CTRL_BUFFER_SIZE, + .callback = &ubt_ctrl_write_callback, + .timeout = 5000, /* 5 seconds */ + }, + + /* + * Interface #1 + */ + + /* Incoming isochronous transfer #1 - SCO packets */ + [UBT_IF_1_ISOC_DT_RD1] = { + .type = UE_ISOCHRONOUS, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_IN, + .if_index = 1, + .bufsize = 0, /* use "wMaxPacketSize * frames" */ + .frames = UBT_ISOC_NFRAMES, + .flags = { .short_xfer_ok = 1, }, + .callback = &ubt_isoc_read_callback, + }, + /* Incoming isochronous transfer #2 - SCO packets */ + [UBT_IF_1_ISOC_DT_RD2] = { + .type = UE_ISOCHRONOUS, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_IN, + .if_index = 1, + .bufsize = 0, /* use "wMaxPacketSize * frames" */ + .frames = UBT_ISOC_NFRAMES, + .flags = { .short_xfer_ok = 1, }, + .callback = &ubt_isoc_read_callback, + }, + /* Outgoing isochronous transfer #1 - SCO packets */ + [UBT_IF_1_ISOC_DT_WR1] = { + .type = UE_ISOCHRONOUS, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .if_index = 1, + .bufsize = 0, /* use "wMaxPacketSize * frames" */ + .frames = UBT_ISOC_NFRAMES, + .flags = { .short_xfer_ok = 1, }, + .callback = &ubt_isoc_write_callback, + }, + /* Outgoing isochronous transfer #2 - SCO packets */ + [UBT_IF_1_ISOC_DT_WR2] = { + .type = UE_ISOCHRONOUS, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .if_index = 1, + .bufsize = 0, /* use "wMaxPacketSize * frames" */ + .frames = UBT_ISOC_NFRAMES, + .flags = { .short_xfer_ok = 1, }, + .callback = &ubt_isoc_write_callback, + }, +}; - switch (event) { - case MOD_LOAD: - error = ng_newtype(&typestruct); - if (error != 0) - printf( -"%s: Could not register Netgraph node type, error=%d\n", - NG_UBT_NODE_TYPE, error); - else - error = usbd_driver_load(mod, event, data); - break; +/* + * If for some reason device should not be attached then put + * VendorID/ProductID pair into the list below. The format is + * as follows: + * + * { USB_VPI(VENDOR_ID, PRODUCT_ID, 0) }, + * + * where VENDOR_ID and PRODUCT_ID are hex numbers. + */ - case MOD_UNLOAD: - error = ng_rmtype(&typestruct); - if (error == 0) - error = usbd_driver_load(mod, event, data); - break; +static const struct usb_device_id ubt_ignore_devs[] = +{ + /* AVM USB Bluetooth-Adapter BlueFritz! v1.0 */ + { USB_VPI(USB_VENDOR_AVM, 0x2200, 0) }, +}; - default: - error = EOPNOTSUPP; - break; - } +/* List of supported bluetooth devices */ +static const struct usb_device_id ubt_devs[] = +{ + /* Generic Bluetooth class devices */ + { USB_IFACE_CLASS(UDCLASS_WIRELESS), + USB_IFACE_SUBCLASS(UDSUBCLASS_RF), + USB_IFACE_PROTOCOL(UDPROTO_BLUETOOTH) }, - return (error); -} /* ubt_modevent */ + /* AVM USB Bluetooth-Adapter BlueFritz! v2.0 */ + { USB_VPI(USB_VENDOR_AVM, 0x3800, 0) }, +}; /* - * Probe for a USB Bluetooth device + * Probe for a USB Bluetooth device. + * USB context. */ static int -ubt_match(device_t self) +ubt_probe(device_t dev) { - /* - * If for some reason device should not be attached then put - * VendorID/ProductID pair into the list below. The format is - * as follows: - * - * { VENDOR_ID, PRODUCT_ID }, - * - * where VENDOR_ID and PRODUCT_ID are hex numbers. - */ + struct usb_attach_arg *uaa = device_get_ivars(dev); - static struct usb_devno const ubt_ignored_devices[] = { - { USB_VENDOR_AVM, 0x2200 }, /* AVM USB Bluetooth-Adapter BlueFritz! v1.0 */ - { 0, 0 } /* This should be the last item in the list */ - }; + if (uaa->usb_mode != USB_MODE_HOST) + return (ENXIO); - /* - * If device violates Bluetooth specification and has bDeviceClass, - * bDeviceSubClass and bDeviceProtocol set to wrong values then you - * could try to put VendorID/ProductID pair into the list below. - * Adding VendorID/ProductID pair into this list forces ng_ubt(4) - * to attach to the broken device. - */ + if (uaa->info.bIfaceIndex != 0) + return (ENXIO); - static struct usb_devno const ubt_broken_devices[] = { - { USB_VENDOR_AVM, 0x3800 }, /* AVM USB Bluetooth-Adapter BlueFritz! v2.0 */ - { 0, 0 } /* This should be the last item in the list */ - }; + if (uaa->use_generic == 0) + return (ENXIO); - struct usb_attach_arg *uaa = device_get_ivars(self); - usb_device_descriptor_t *dd = usbd_get_device_descriptor(uaa->device); + if (usbd_lookup_id_by_uaa(ubt_ignore_devs, + sizeof(ubt_ignore_devs), uaa) == 0) + return (ENXIO); - if (uaa->iface == NULL || - usb_lookup(ubt_ignored_devices, uaa->vendor, uaa->product)) - return (UMATCH_NONE); - - if (dd->bDeviceClass == UDCLASS_WIRELESS && - dd->bDeviceSubClass == UDSUBCLASS_RF && - dd->bDeviceProtocol == UDPROTO_BLUETOOTH) - return (UMATCH_DEVCLASS_DEVSUBCLASS); - - if (usb_lookup(ubt_broken_devices, uaa->vendor, uaa->product)) - return (UMATCH_VENDOR_PRODUCT); - - return (UMATCH_NONE); -} /* ubt_match */ + return (usbd_lookup_id_by_uaa(ubt_devs, sizeof(ubt_devs), uaa)); +} /* ubt_probe */ /* - * Attach the device + * Attach the device. + * USB context. */ static int -ubt_attach(device_t self) +ubt_attach(device_t dev) { - struct ubt_softc *sc = device_get_softc(self); - struct usb_attach_arg *uaa = device_get_ivars(self); - usb_config_descriptor_t *cd = NULL; - usb_interface_descriptor_t *id = NULL; - usb_endpoint_descriptor_t *ed = NULL; - usbd_status error; - int i, ai, alt_no, isoc_in, isoc_out, - isoc_isize, isoc_osize; + struct usb_attach_arg *uaa = device_get_ivars(dev); + struct ubt_softc *sc = device_get_softc(dev); + struct usb_endpoint_descriptor *ed; + struct usb_interface_descriptor *id; + uint16_t wMaxPacketSize; + uint8_t alt_index, i, j; + uint8_t iface_index[2] = { 0, 1 }; + + device_set_usb_desc(dev); - /* Get USB device info */ - sc->sc_dev = self; - sc->sc_udev = uaa->device; + sc->sc_dev = dev; + sc->sc_debug = NG_UBT_WARN_LEVEL; /* - * Initialize device softc structure + * Create Netgraph node */ - /* State */ - sc->sc_debug = NG_UBT_WARN_LEVEL; - sc->sc_flags = 0; - NG_UBT_STAT_RESET(sc->sc_stat); + if (ng_make_node_common(&typestruct, &sc->sc_node) != 0) { + UBT_ALERT(sc, "could not create Netgraph node\n"); + return (ENXIO); + } + + /* Name Netgraph node */ + if (ng_name_node(sc->sc_node, device_get_nameunit(dev)) != 0) { + UBT_ALERT(sc, "could not name Netgraph node\n"); + NG_NODE_UNREF(sc->sc_node); + return (ENXIO); + } + NG_NODE_SET_PRIVATE(sc->sc_node, sc); + NG_NODE_FORCE_WRITER(sc->sc_node); - /* Interfaces */ - sc->sc_iface0 = sc->sc_iface1 = NULL; + /* + * Initialize device softc structure + */ - /* Interrupt pipe */ - sc->sc_intr_ep = -1; - sc->sc_intr_pipe = NULL; - sc->sc_intr_xfer = NULL; - sc->sc_intr_buffer = NULL; + /* initialize locks */ + mtx_init(&sc->sc_ng_mtx, "ubt ng", NULL, MTX_DEF); + mtx_init(&sc->sc_if_mtx, "ubt if", NULL, MTX_DEF | MTX_RECURSE); - /* Control pipe */ - sc->sc_ctrl_xfer = NULL; - sc->sc_ctrl_buffer = NULL; + /* initialize packet queues */ NG_BT_MBUFQ_INIT(&sc->sc_cmdq, UBT_DEFAULT_QLEN); - - /* Bulk-in pipe */ - sc->sc_bulk_in_ep = -1; - sc->sc_bulk_in_pipe = NULL; - sc->sc_bulk_in_xfer = NULL; - sc->sc_bulk_in_buffer = NULL; - - /* Bulk-out pipe */ - sc->sc_bulk_out_ep = -1; - sc->sc_bulk_out_pipe = NULL; - sc->sc_bulk_out_xfer = NULL; - sc->sc_bulk_out_buffer = NULL; NG_BT_MBUFQ_INIT(&sc->sc_aclq, UBT_DEFAULT_QLEN); - - /* Isoc-in pipe */ - sc->sc_isoc_in_buffer = NULL; - sc->sc_isoc_in_ep = -1; - sc->sc_isoc_in_pipe = NULL; - bzero(&sc->sc_isoc_in, sizeof(sc->sc_isoc_in)); - - /* Isoc-out pipe */ - sc->sc_isoc_out_ep = -1; - sc->sc_isoc_out_pipe = NULL; - bzero(&sc->sc_isoc_out, sizeof(sc->sc_isoc_out)); - - sc->sc_isoc_size = -1; NG_BT_MBUFQ_INIT(&sc->sc_scoq, UBT_DEFAULT_QLEN); - /* Netgraph part */ - sc->sc_node = NULL; - sc->sc_hook = NULL; + /* initialize glue task */ + TASK_INIT(&sc->sc_task, 0, ubt_task, sc); /* - * XXX set configuration? + * Configure Bluetooth USB device. Discover all required USB + * interfaces and endpoints. * - * Configure Bluetooth USB device. Discover all required USB interfaces - * and endpoints. - * * USB device must present two interfaces: * 1) Interface 0 that has 3 endpoints * 1) Interrupt endpoint to receive HCI events @@ -416,1524 +483,804 @@ * 1) Isochronous IN endpoint to receive SCO data * 2) Isochronous OUT endpoint to send SCO data * - * Interface 1 (with isochronous endpoints) has several alternate + * Interface 1 (with isochronous endpoints) has several alternate * configurations with different packet size. */ /* - * Interface 0 + * For interface #1 search alternate settings, and find + * the descriptor with the largest wMaxPacketSize */ - error = usbd_device2interface_handle(sc->sc_udev, 0, &sc->sc_iface0); - if (error || sc->sc_iface0 == NULL) { - printf("%s: Could not get interface 0 handle. %s (%d), " \ - "handle=%p\n", device_get_nameunit(sc->sc_dev), - usbd_errstr(error), error, sc->sc_iface0); - goto bad; - } + wMaxPacketSize = 0; + alt_index = 0; + i = 0; + j = 0; + ed = NULL; - id = usbd_get_interface_descriptor(sc->sc_iface0); - if (id == NULL) { - printf("%s: Could not get interface 0 descriptor\n", - device_get_nameunit(sc->sc_dev)); - goto bad; - } - - for (i = 0; i < id->bNumEndpoints; i ++) { - ed = usbd_interface2endpoint_descriptor(sc->sc_iface0, i); - if (ed == NULL) { - printf("%s: Could not read endpoint descriptor for " \ - "interface 0, i=%d\n", device_get_nameunit(sc->sc_dev), - i); - goto bad; - } - - switch (UE_GET_XFERTYPE(ed->bmAttributes)) { - case UE_BULK: - if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) - sc->sc_bulk_in_ep = ed->bEndpointAddress; - else - sc->sc_bulk_out_ep = ed->bEndpointAddress; - break; - - case UE_INTERRUPT: - sc->sc_intr_ep = ed->bEndpointAddress; - break; - } - } - - /* Check if we got everything we wanted on Interface 0 */ - if (sc->sc_intr_ep == -1) { - printf("%s: Could not detect interrupt endpoint\n", - device_get_nameunit(sc->sc_dev)); - goto bad; - } - if (sc->sc_bulk_in_ep == -1) { - printf("%s: Could not detect bulk-in endpoint\n", - device_get_nameunit(sc->sc_dev)); - goto bad; - } - if (sc->sc_bulk_out_ep == -1) { - printf("%s: Could not detect bulk-out endpoint\n", - device_get_nameunit(sc->sc_dev)); - goto bad; - } - - printf("%s: Interface 0 endpoints: interrupt=%#x, bulk-in=%#x, " \ - "bulk-out=%#x\n", device_get_nameunit(sc->sc_dev), - sc->sc_intr_ep, sc->sc_bulk_in_ep, sc->sc_bulk_out_ep); - - /* - * Interface 1 + /* + * Search through all the descriptors looking for the largest + * packet size: */ + while ((ed = (struct usb_endpoint_descriptor *)usb_desc_foreach( + usbd_get_config_descriptor(uaa->device), + (struct usb_descriptor *)ed))) { - cd = usbd_get_config_descriptor(sc->sc_udev); - if (cd == NULL) { - printf("%s: Could not get device configuration descriptor\n", - device_get_nameunit(sc->sc_dev)); - goto bad; - } - - error = usbd_device2interface_handle(sc->sc_udev, 1, &sc->sc_iface1); - if (error || sc->sc_iface1 == NULL) { - printf("%s: Could not get interface 1 handle. %s (%d), " \ - "handle=%p\n", device_get_nameunit(sc->sc_dev), - usbd_errstr(error), error, sc->sc_iface1); - goto bad; - } - - id = usbd_get_interface_descriptor(sc->sc_iface1); - if (id == NULL) { - printf("%s: Could not get interface 1 descriptor\n", - device_get_nameunit(sc->sc_dev)); - goto bad; - } - - /* - * Scan all alternate configurations for interface 1 - */ - - alt_no = -1; - - for (ai = 0; ai < usbd_get_no_alts(cd, 1); ai++) { - error = usbd_set_interface(sc->sc_iface1, ai); - if (error) { - printf("%s: [SCAN] Could not set alternate " \ - "configuration %d for interface 1. %s (%d)\n", - device_get_nameunit(sc->sc_dev), ai, usbd_errstr(error), - error); - goto bad; - } - id = usbd_get_interface_descriptor(sc->sc_iface1); - if (id == NULL) { - printf("%s: Could not get interface 1 descriptor for " \ - "alternate configuration %d\n", - device_get_nameunit(sc->sc_dev), ai); - goto bad; + if ((ed->bDescriptorType == UDESC_INTERFACE) && + (ed->bLength >= sizeof(*id))) { + id = (struct usb_interface_descriptor *)ed; + i = id->bInterfaceNumber; + j = id->bAlternateSetting; } - isoc_in = isoc_out = -1; - isoc_isize = isoc_osize = 0; + if ((ed->bDescriptorType == UDESC_ENDPOINT) && + (ed->bLength >= sizeof(*ed)) && + (i == 1)) { + uint16_t temp; - for (i = 0; i < id->bNumEndpoints; i ++) { - ed = usbd_interface2endpoint_descriptor(sc->sc_iface1, i); - if (ed == NULL) { - printf("%s: Could not read endpoint " \ - "descriptor for interface 1, " \ - "alternate configuration %d, i=%d\n", - device_get_nameunit(sc->sc_dev), ai, i); - goto bad; - } - - if (UE_GET_XFERTYPE(ed->bmAttributes) != UE_ISOCHRONOUS) - continue; - - if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) { - isoc_in = ed->bEndpointAddress; - isoc_isize = UGETW(ed->wMaxPacketSize); - } else { - isoc_out = ed->bEndpointAddress; - isoc_osize = UGETW(ed->wMaxPacketSize); + temp = UGETW(ed->wMaxPacketSize); + if (temp > wMaxPacketSize) { + wMaxPacketSize = temp; + alt_index = j; } } - - /* - * Make sure that configuration looks sane and if so - * update current settings - */ - - if (isoc_in != -1 && isoc_out != -1 && - isoc_isize > 0 && isoc_osize > 0 && - isoc_isize == isoc_osize && isoc_isize > sc->sc_isoc_size) { - sc->sc_isoc_in_ep = isoc_in; - sc->sc_isoc_out_ep = isoc_out; - sc->sc_isoc_size = isoc_isize; - alt_no = ai; - } } - /* Check if we got everything we wanted on Interface 0 */ - if (sc->sc_isoc_in_ep == -1) { - printf("%s: Could not detect isoc-in endpoint\n", - device_get_nameunit(sc->sc_dev)); - goto bad; + /* Set alt configuration on interface #1 only if we found it */ + if (wMaxPacketSize > 0 && + usbd_set_alt_interface_index(uaa->device, 1, alt_index)) { + UBT_ALERT(sc, "could not set alternate setting %d " \ + "for interface 1!\n", alt_index); + goto detach; } - if (sc->sc_isoc_out_ep == -1) { - printf("%s: Could not detect isoc-out endpoint\n", - device_get_nameunit(sc->sc_dev)); - goto bad; - } - if (sc->sc_isoc_size <= 0) { - printf("%s: Invalid isoc. packet size=%d\n", - device_get_nameunit(sc->sc_dev), sc->sc_isoc_size); - goto bad; - } - error = usbd_set_interface(sc->sc_iface1, alt_no); - if (error) { - printf("%s: Could not set alternate configuration " \ - "%d for interface 1. %s (%d)\n", - device_get_nameunit(sc->sc_dev), - alt_no, usbd_errstr(error), error); - goto bad; - } - - /* Allocate USB transfer handles and buffers */ - sc->sc_ctrl_xfer = usbd_alloc_xfer(sc->sc_udev); - if (sc->sc_ctrl_xfer == NULL) { - printf("%s: Could not allocate control xfer handle\n", - device_get_nameunit(sc->sc_dev)); - goto bad; - } - sc->sc_ctrl_buffer = usbd_alloc_buffer(sc->sc_ctrl_xfer, - UBT_CTRL_BUFFER_SIZE); - if (sc->sc_ctrl_buffer == NULL) { - printf("%s: Could not allocate control buffer\n", - device_get_nameunit(sc->sc_dev)); - goto bad; - } - - sc->sc_intr_xfer = usbd_alloc_xfer(sc->sc_udev); - if (sc->sc_intr_xfer == NULL) { - printf("%s: Could not allocate interrupt xfer handle\n", - device_get_nameunit(sc->sc_dev)); - goto bad; - } - - sc->sc_bulk_in_xfer = usbd_alloc_xfer(sc->sc_udev); - if (sc->sc_bulk_in_xfer == NULL) { - printf("%s: Could not allocate bulk-in xfer handle\n", - device_get_nameunit(sc->sc_dev)); - goto bad; - } - - sc->sc_bulk_out_xfer = usbd_alloc_xfer(sc->sc_udev); - if (sc->sc_bulk_out_xfer == NULL) { - printf("%s: Could not allocate bulk-out xfer handle\n", - device_get_nameunit(sc->sc_dev)); - goto bad; - } - sc->sc_bulk_out_buffer = usbd_alloc_buffer(sc->sc_bulk_out_xfer, - UBT_BULK_BUFFER_SIZE); - if (sc->sc_bulk_out_buffer == NULL) { - printf("%s: Could not allocate bulk-out buffer\n", - device_get_nameunit(sc->sc_dev)); - goto bad; + /* Setup transfers for both interfaces */ + if (usbd_transfer_setup(uaa->device, iface_index, sc->sc_xfer, + ubt_config, UBT_N_TRANSFER, sc, &sc->sc_if_mtx)) { + UBT_ALERT(sc, "could not allocate transfers\n"); + goto detach; } - /* - * Allocate buffers for isoc. transfers - */ - - for (i = 0; i < NG_UBT_NXFERS; i++) { - sc->sc_isoc_in[i].xfer = usbd_alloc_xfer(sc->sc_udev); - if (sc->sc_isoc_in[i].xfer == NULL) { - printf("%s: Could not allocate isoc-in xfer handle\n", >>> TRUNCATED FOR MAIL (1000 lines) <<<