diff options
author | thompsa <thompsa@FreeBSD.org> | 2009-05-27 16:29:56 +0000 |
---|---|---|
committer | thompsa <thompsa@FreeBSD.org> | 2009-05-27 16:29:56 +0000 |
commit | 77ea8140da53162b03f0702d4d1203b1ade7095c (patch) | |
tree | 6d2db1181a316ff07083148521755dd05dc191e8 /sys/netgraph/bluetooth | |
parent | 896c73926fc3bf33749f691d39765d0e288e0df1 (diff) | |
download | FreeBSD-src-77ea8140da53162b03f0702d4d1203b1ade7095c.zip FreeBSD-src-77ea8140da53162b03f0702d4d1203b1ade7095c.tar.gz |
Delete the bluetooth drivers for the old usb stack.
Diffstat (limited to 'sys/netgraph/bluetooth')
-rw-r--r-- | sys/netgraph/bluetooth/drivers/ubt/TODO | 36 | ||||
-rw-r--r-- | sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c | 2344 | ||||
-rw-r--r-- | sys/netgraph/bluetooth/drivers/ubt/ng_ubt_var.h | 152 | ||||
-rw-r--r-- | sys/netgraph/bluetooth/drivers/ubtbcmfw/ubtbcmfw.c | 559 |
4 files changed, 0 insertions, 3091 deletions
diff --git a/sys/netgraph/bluetooth/drivers/ubt/TODO b/sys/netgraph/bluetooth/drivers/ubt/TODO deleted file mode 100644 index 7f840c9..0000000 --- a/sys/netgraph/bluetooth/drivers/ubt/TODO +++ /dev/null @@ -1,36 +0,0 @@ -$Id: TODO,v 1.1 2002/11/24 19:46:56 max Exp $ -$FreeBSD$ - -1) SMP/Locking - - The code makes use of ng_send_fn() whenever possible. Just - need to verify and make sure i did it right - - ** DONE. Seems to work ** - -2) Review USB ATTACH function - - It is a bit ugly now. Probably need a better way to discover - USB device configuration. - -2) Firmware upgrade - - According to Bluetooth spec device may present third interface - to perform firmware upgrade. 3Com USB Bluetooth dongle has - such interface. Need to implement set of Netgraph messages. - -3) Understand and fix isoc. USB transfers (SCO data) - - Currenty device reports that is got zero bytes and calls - isoc_in_complete callback over and over again. Why? - Also might need to setup at least two isoc. transfers in - both directions and switch them on the fly. Just to ensure - there at least one transfer at any time ready to run. - - ** DONE. Needs more testings ** - -4) Currently interrupt transfers are done as bulk-in transfers - - Need to check if that is allowed. - - ** DONE. Seems to work ** diff --git a/sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c b/sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c deleted file mode 100644 index 5d2b4a2..0000000 --- a/sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c +++ /dev/null @@ -1,2344 +0,0 @@ -/* - * ng_ubt.c - */ - -/*- - * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * 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$ - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/bus.h> -#include <sys/conf.h> -#include <sys/endian.h> -#include <sys/filio.h> -#include <sys/fcntl.h> -#include <sys/mbuf.h> -#include <sys/malloc.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/poll.h> -#include <sys/uio.h> -#include <machine/bus.h> - -#include <dev/usb/usb.h> -#include <dev/usb/usbdi.h> -#include <dev/usb/usbdi_util.h> -#include <dev/usb/usbdivar.h> - -#include <netgraph/ng_message.h> -#include <netgraph/netgraph.h> -#include <netgraph/ng_parse.h> -#include <netgraph/bluetooth/include/ng_bluetooth.h> -#include <netgraph/bluetooth/include/ng_hci.h> -#include <netgraph/bluetooth/include/ng_ubt.h> -#include <netgraph/bluetooth/drivers/ubt/ng_ubt_var.h> - -#include "usbdevs.h" - -/* - * USB methods - */ - -static device_probe_t ubt_match; -static device_attach_t ubt_attach; -static device_detach_t ubt_detach; - -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 - */ - -static ng_constructor_t ng_ubt_constructor; -static ng_shutdown_t ng_ubt_shutdown; -static ng_newhook_t ng_ubt_newhook; -static ng_connect_t ng_ubt_connect; -static ng_disconnect_t ng_ubt_disconnect; -static ng_rcvmsg_t ng_ubt_rcvmsg; -static ng_rcvdata_t ng_ubt_rcvdata; - -/* Queue length */ -static const struct ng_parse_struct_field ng_ubt_node_qlen_type_fields[] = -{ - { "queue", &ng_parse_int32_type, }, - { "qlen", &ng_parse_int32_type, }, - { NULL, } -}; -static const struct ng_parse_type ng_ubt_node_qlen_type = { - &ng_parse_struct_type, - &ng_ubt_node_qlen_type_fields -}; - -/* Stat info */ -static const struct ng_parse_struct_field ng_ubt_node_stat_type_fields[] = -{ - { "pckts_recv", &ng_parse_uint32_type, }, - { "bytes_recv", &ng_parse_uint32_type, }, - { "pckts_sent", &ng_parse_uint32_type, }, - { "bytes_sent", &ng_parse_uint32_type, }, - { "oerrors", &ng_parse_uint32_type, }, - { "ierrors", &ng_parse_uint32_type, }, - { NULL, } -}; -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[] = { -{ - 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, - .name = NG_UBT_NODE_TYPE, - .constructor = ng_ubt_constructor, - .rcvmsg = ng_ubt_rcvmsg, - .shutdown = ng_ubt_shutdown, - .newhook = ng_ubt_newhook, - .connect = ng_ubt_connect, - .rcvdata = ng_ubt_rcvdata, - .disconnect = ng_ubt_disconnect, - .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 - **************************************************************************** - ****************************************************************************/ - -/* - * Load/Unload the driver module - */ - -static int -ubt_modevent(module_t mod, int event, void *data) -{ - int error; - - 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; - - case MOD_UNLOAD: - error = ng_rmtype(&typestruct); - if (error == 0) - error = usbd_driver_load(mod, event, data); - break; - - default: - error = EOPNOTSUPP; - break; - } - - return (error); -} /* ubt_modevent */ - -/* - * Probe for a USB Bluetooth device - */ - -static int -ubt_match(device_t self) -{ - /* - * 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. - */ - - 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 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. - */ - - 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 */ - }; - - struct usb_attach_arg *uaa = device_get_ivars(self); - usb_device_descriptor_t *dd = usbd_get_device_descriptor(uaa->device); - - 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 */ - -/* - * Attach the device - */ - -static int -ubt_attach(device_t self) -{ - 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; - - /* Get USB device info */ - sc->sc_dev = self; - sc->sc_udev = uaa->device; - - /* - * Initialize device softc structure - */ - - /* State */ - sc->sc_debug = NG_UBT_WARN_LEVEL; - sc->sc_flags = 0; - NG_UBT_STAT_RESET(sc->sc_stat); - - /* Interfaces */ - sc->sc_iface0 = sc->sc_iface1 = NULL; - - /* Interrupt pipe */ - sc->sc_intr_ep = -1; - sc->sc_intr_pipe = NULL; - sc->sc_intr_xfer = NULL; - sc->sc_intr_buffer = NULL; - - /* Control pipe */ - sc->sc_ctrl_xfer = NULL; - sc->sc_ctrl_buffer = NULL; - 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; - - /* - * XXX set configuration? - * - * 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 - * 2) Bulk IN endpoint to receive ACL data - * 3) Bulk OUT endpoint to send ACL data - * - * 2) Interface 1 then has 2 endpoints - * 1) Isochronous IN endpoint to receive SCO data - * 2) Isochronous OUT endpoint to send SCO data - * - * Interface 1 (with isochronous endpoints) has several alternate - * configurations with different packet size. - */ - - /* - * Interface 0 - */ - - 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; - } - - 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 - */ - - 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; - } - - isoc_in = isoc_out = -1; - isoc_isize = isoc_osize = 0; - - 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); - } - } - - /* - * 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; - } - 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; - } - - /* - * 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", - device_get_nameunit(sc->sc_dev)); - goto bad; - } - - sc->sc_isoc_in[i].buffer = usbd_alloc_buffer( - sc->sc_isoc_in[i].xfer, - NG_UBT_NFRAMES * sc->sc_isoc_size); - if (sc->sc_isoc_in[i].buffer == NULL) { - printf("%s: Could not allocate isoc-in buffer\n", - device_get_nameunit(sc->sc_dev)); - goto bad; - } - - sc->sc_isoc_in[i].frlen = malloc( - sizeof(uint16_t) * NG_UBT_NFRAMES, - M_USBDEV, M_NOWAIT); - if (sc->sc_isoc_in[i].frlen == NULL) { - printf("%s: Could not allocate isoc-in frame sizes buffer\n", - device_get_nameunit(sc->sc_dev)); - goto bad; - } - } - - for (i = 0; i < NG_UBT_NXFERS; i++) { - sc->sc_isoc_out[i].xfer = usbd_alloc_xfer(sc->sc_udev); - if (sc->sc_isoc_out[i].xfer == NULL) { - printf("%s: Could not allocate isoc-out xfer handle\n", - device_get_nameunit(sc->sc_dev)); - goto bad; - } - - sc->sc_isoc_out[i].buffer = usbd_alloc_buffer( - sc->sc_isoc_out[i].xfer, - NG_UBT_NFRAMES * sc->sc_isoc_size); - if (sc->sc_isoc_out[i].buffer == NULL) { - printf("%s: Could not allocate isoc-out buffer\n", - device_get_nameunit(sc->sc_dev)); - goto bad; - } - - sc->sc_isoc_out[i].frlen = malloc( - sizeof(uint16_t) * NG_UBT_NFRAMES, - M_USBDEV, M_NOWAIT); - if (sc->sc_isoc_out[i].frlen == NULL) { - printf("%s: Could not allocate isoc-out frame sizes buffer\n", - device_get_nameunit(sc->sc_dev)); - goto bad; - } - } - - printf("%s: Interface 1 (alt.config %d) endpoints: isoc-in=%#x, " \ - "isoc-out=%#x; wMaxPacketSize=%d; nframes=%d, buffer size=%d\n", - device_get_nameunit(sc->sc_dev), alt_no, sc->sc_isoc_in_ep, - sc->sc_isoc_out_ep, sc->sc_isoc_size, NG_UBT_NFRAMES, - (NG_UBT_NFRAMES * sc->sc_isoc_size)); - - /* - * Open pipes - */ - - /* Interrupt */ - error = usbd_open_pipe(sc->sc_iface0, sc->sc_intr_ep, - USBD_EXCLUSIVE_USE, &sc->sc_intr_pipe); - if (error != USBD_NORMAL_COMPLETION) { - printf("%s: %s - Could not open interrupt pipe. %s (%d)\n", - __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(error), - error); - goto bad; - } - - /* Bulk-in */ - error = usbd_open_pipe(sc->sc_iface0, sc->sc_bulk_in_ep, - USBD_EXCLUSIVE_USE, &sc->sc_bulk_in_pipe); - if (error != USBD_NORMAL_COMPLETION) { - printf("%s: %s - Could not open bulk-in pipe. %s (%d)\n", - __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(error), - error); - goto bad; - } - - /* Bulk-out */ - error = usbd_open_pipe(sc->sc_iface0, sc->sc_bulk_out_ep, - USBD_EXCLUSIVE_USE, &sc->sc_bulk_out_pipe); - if (error != USBD_NORMAL_COMPLETION) { - printf("%s: %s - Could not open bulk-out pipe. %s (%d)\n", - __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(error), - error); - goto bad; - } - - /* Isoc-in */ - error = usbd_open_pipe(sc->sc_iface1, sc->sc_isoc_in_ep, - USBD_EXCLUSIVE_USE, &sc->sc_isoc_in_pipe); - if (error != USBD_NORMAL_COMPLETION) { - printf("%s: %s - Could not open isoc-in pipe. %s (%d)\n", - __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(error), - error); - goto bad; - } - - /* Isoc-out */ - error = usbd_open_pipe(sc->sc_iface1, sc->sc_isoc_out_ep, - USBD_EXCLUSIVE_USE, &sc->sc_isoc_out_pipe); - if (error != USBD_NORMAL_COMPLETION) { - printf("%s: %s - Could not open isoc-out pipe. %s (%d)\n", - __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(error), - error); - goto bad; - } - - /* Create Netgraph node */ - if (ng_make_node_common(&typestruct, &sc->sc_node) != 0) { - printf("%s: Could not create Netgraph node\n", - device_get_nameunit(sc->sc_dev)); - sc->sc_node = NULL; - goto bad; - } - - /* Name node */ - if (ng_name_node(sc->sc_node, device_get_nameunit(sc->sc_dev)) != 0) { - printf("%s: Could not name Netgraph node\n", - device_get_nameunit(sc->sc_dev)); - NG_NODE_UNREF(sc->sc_node); - sc->sc_node = NULL; - goto bad; - } - - NG_NODE_SET_PRIVATE(sc->sc_node, sc); - NG_NODE_FORCE_WRITER(sc->sc_node); - - /* Claim all interfaces on the device */ - for (i = 0; i < uaa->nifaces; i++) - uaa->ifaces[i] = NULL; - - usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, - sc->sc_dev); - - return 0; -bad: - ubt_detach(self); - - return ENXIO; -} /* ubt_attach */ - -/* - * Detach the device - */ - -static int -ubt_detach(device_t self) -{ - struct ubt_softc *sc = device_get_softc(self); - int i; - - /* Destroy Netgraph node */ - if (sc->sc_node != NULL) { - NG_NODE_SET_PRIVATE(sc->sc_node, NULL); - ng_rmnode_self(sc->sc_node); - sc->sc_node = NULL; - } - - /* Close pipes */ - if (sc->sc_intr_pipe != NULL) { - usbd_abort_pipe(sc->sc_intr_pipe); - usbd_close_pipe(sc->sc_intr_pipe); - sc->sc_intr_pipe = NULL; - } - - if (sc->sc_bulk_in_pipe != NULL) { - usbd_abort_pipe(sc->sc_bulk_in_pipe); - usbd_close_pipe(sc->sc_bulk_in_pipe); - sc->sc_bulk_in_pipe = NULL; - } - if (sc->sc_bulk_out_pipe != NULL) { - usbd_abort_pipe(sc->sc_bulk_out_pipe); - usbd_close_pipe(sc->sc_bulk_out_pipe); - sc->sc_bulk_out_pipe = NULL; - } - - if (sc->sc_isoc_in_pipe != NULL) { - usbd_abort_pipe(sc->sc_isoc_in_pipe); - usbd_close_pipe(sc->sc_isoc_in_pipe); - sc->sc_isoc_in_pipe = NULL; - } - if (sc->sc_isoc_out_pipe != NULL) { - usbd_abort_pipe(sc->sc_isoc_out_pipe); - usbd_close_pipe(sc->sc_isoc_out_pipe); - sc->sc_isoc_out_pipe = NULL; - } - - /* Destroy USB transfer handles */ - if (sc->sc_ctrl_xfer != NULL) { - usbd_free_xfer(sc->sc_ctrl_xfer); - sc->sc_ctrl_xfer = NULL; - } - - if (sc->sc_intr_xfer != NULL) { - usbd_free_xfer(sc->sc_intr_xfer); - sc->sc_intr_xfer = NULL; - } - - if (sc->sc_bulk_in_xfer != NULL) { - usbd_free_xfer(sc->sc_bulk_in_xfer); - sc->sc_bulk_in_xfer = NULL; - } - if (sc->sc_bulk_out_xfer != NULL) { - usbd_free_xfer(sc->sc_bulk_out_xfer); - sc->sc_bulk_out_xfer = NULL; - } - - for (i = 0; i < NG_UBT_NXFERS; i++) { - if (sc->sc_isoc_in[i].xfer != NULL) { - usbd_free_xfer(sc->sc_isoc_in[i].xfer); - sc->sc_isoc_in[i].xfer = NULL; - sc->sc_isoc_in[i].buffer = NULL; - } - - if (sc->sc_isoc_in[i].frlen != NULL) { - free(sc->sc_isoc_in[i].frlen, M_USBDEV); - sc->sc_isoc_in[i].frlen = NULL; - } - } - - for (i = 0; i < NG_UBT_NXFERS; i++) { - if (sc->sc_isoc_out[i].xfer != NULL) { - usbd_free_xfer(sc->sc_isoc_out[i].xfer); - sc->sc_isoc_out[i].xfer = NULL; - sc->sc_isoc_out[i].buffer = NULL; - } - - if (sc->sc_isoc_out[i].frlen != NULL) { - free(sc->sc_isoc_out[i].frlen, M_USBDEV); - sc->sc_isoc_out[i].frlen = NULL; - } - } - - NG_FREE_M(sc->sc_bulk_in_buffer); - NG_FREE_M(sc->sc_isoc_in_buffer); - - /* Destroy queues */ - NG_BT_MBUFQ_DRAIN(&sc->sc_cmdq); - NG_BT_MBUFQ_DRAIN(&sc->sc_aclq); - NG_BT_MBUFQ_DRAIN(&sc->sc_scoq); - - usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev); - - return (0); -} /* ubt_detach */ - -/* - * Start USB control request (HCI command). Must be called with node locked - */ - -static usbd_status -ubt_request_start(ubt_softc_p sc) -{ - usb_device_request_t req; - struct mbuf *m = NULL; - usbd_status status; - - KASSERT(!(sc->sc_flags & UBT_CMD_XMIT), ( -"%s: %s - Another control request is pending\n", - __func__, device_get_nameunit(sc->sc_dev))); - - NG_BT_MBUFQ_DEQUEUE(&sc->sc_cmdq, m); - if (m == NULL) { - NG_UBT_INFO( -"%s: %s - HCI command queue is empty\n", __func__, device_get_nameunit(sc->sc_dev)); - - return (USBD_NORMAL_COMPLETION); - } - - /* - * Check HCI command frame size and copy it back to - * linear USB transfer buffer. - */ - - if (m->m_pkthdr.len > UBT_CTRL_BUFFER_SIZE) - panic( -"%s: %s - HCI command frame too big, size=%zd, len=%d\n", - __func__, device_get_nameunit(sc->sc_dev), UBT_CTRL_BUFFER_SIZE, - m->m_pkthdr.len); - - m_copydata(m, 0, m->m_pkthdr.len, sc->sc_ctrl_buffer); - - /* Initialize a USB control request and then schedule it */ - bzero(&req, sizeof(req)); - req.bmRequestType = UBT_HCI_REQUEST; - USETW(req.wLength, m->m_pkthdr.len); - - NG_UBT_INFO( -"%s: %s - Sending control request, bmRequestType=%#x, wLength=%d\n", - __func__, device_get_nameunit(sc->sc_dev), req.bmRequestType, - UGETW(req.wLength)); - - usbd_setup_default_xfer( - sc->sc_ctrl_xfer, - sc->sc_udev, - (usbd_private_handle) sc->sc_node, - USBD_DEFAULT_TIMEOUT, /* XXX */ - &req, - sc->sc_ctrl_buffer, - m->m_pkthdr.len, - USBD_NO_COPY, - ubt_request_complete); - - NG_NODE_REF(sc->sc_node); - - status = usbd_transfer(sc->sc_ctrl_xfer); - if (status != USBD_NORMAL_COMPLETION && status != USBD_IN_PROGRESS) { - NG_UBT_ERR( -"%s: %s - Could not start control request. %s (%d)\n", - __func__, device_get_nameunit(sc->sc_dev), - usbd_errstr(status), status); - - NG_NODE_UNREF(sc->sc_node); - - NG_BT_MBUFQ_DROP(&sc->sc_cmdq); - NG_UBT_STAT_OERROR(sc->sc_stat); - - /* XXX FIXME should we try to resubmit another request? */ - } else { - NG_UBT_INFO( -"%s: %s - Control request has been started\n", - __func__, device_get_nameunit(sc->sc_dev)); - - sc->sc_flags |= UBT_CMD_XMIT; - status = USBD_NORMAL_COMPLETION; - } - - NG_FREE_M(m); - - return (status); -} /* ubt_request_start */ - -/* - * USB control request callback - */ - -static void -ubt_request_complete(usbd_xfer_handle h, usbd_private_handle p, usbd_status s) -{ - ng_send_fn((node_p) p, NULL, ubt_request_complete2, (void *) h, s); - NG_NODE_UNREF((node_p) p); -} /* ubt_request_complete */ - -static void -ubt_request_complete2(node_p node, hook_p hook, void *arg1, int arg2) -{ - ubt_softc_p sc = (ubt_softc_p) NG_NODE_PRIVATE(node); - usbd_xfer_handle h = (usbd_xfer_handle) arg1; - usbd_status s = (usbd_status) arg2; - - if (sc == NULL) - return; - - KASSERT((sc->sc_flags & UBT_CMD_XMIT), ( -"%s: %s - No control request is pending\n", __func__, device_get_nameunit(sc->sc_dev))); - - sc->sc_flags &= ~UBT_CMD_XMIT; - - if (s == USBD_CANCELLED) { - NG_UBT_INFO( -"%s: %s - Control request cancelled\n", __func__, device_get_nameunit(sc->sc_dev)); - - return; - } - - if (s != USBD_NORMAL_COMPLETION) { - NG_UBT_ERR( -"%s: %s - Control request failed. %s (%d)\n", - __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(s), s); - - if (s == USBD_STALLED) - usbd_clear_endpoint_stall_async(h->pipe); - - NG_UBT_STAT_OERROR(sc->sc_stat); - } else { - NG_UBT_INFO( -"%s: %s - Sent %d bytes to control pipe\n", - __func__, device_get_nameunit(sc->sc_dev), h->actlen); - - NG_UBT_STAT_BYTES_SENT(sc->sc_stat, h->actlen); - NG_UBT_STAT_PCKTS_SENT(sc->sc_stat); - } - - if (NG_BT_MBUFQ_LEN(&sc->sc_cmdq) > 0) - ubt_request_start(sc); -} /* ubt_request_complete2 */ - -/* - * Start interrupt transfer. Must be called when node is locked - */ - -static usbd_status -ubt_intr_start(ubt_softc_p sc) -{ - struct mbuf *m = NULL; - usbd_status status; - - KASSERT(!(sc->sc_flags & UBT_EVT_RECV), ( -"%s: %s - Another interrupt request is pending\n", - __func__, device_get_nameunit(sc->sc_dev))); - - /* Allocate new mbuf cluster */ - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) - return (USBD_NOMEM); - - MCLGET(m, M_DONTWAIT); - if (!(m->m_flags & M_EXT)) { - NG_FREE_M(m); - return (USBD_NOMEM); - } - - if (!(sc->sc_flags & UBT_HAVE_FRAME_TYPE)) { - *mtod(m, uint8_t *) = NG_HCI_EVENT_PKT; - m->m_pkthdr.len = m->m_len = 1; - } else - m->m_pkthdr.len = m->m_len = 0; - - /* Initialize a USB transfer and then schedule it */ - usbd_setup_xfer( - sc->sc_intr_xfer, - sc->sc_intr_pipe, - (usbd_private_handle) sc->sc_node, - (void *)(mtod(m, uint8_t *) + m->m_len), - MCLBYTES - m->m_len, - USBD_SHORT_XFER_OK, - USBD_NO_TIMEOUT, - ubt_intr_complete); - - NG_NODE_REF(sc->sc_node); - - status = usbd_transfer(sc->sc_intr_xfer); - if (status != USBD_NORMAL_COMPLETION && status != USBD_IN_PROGRESS) { - NG_UBT_ERR( -"%s: %s - Failed to start intrerrupt transfer. %s (%d)\n", - __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(status), - status); - - NG_NODE_UNREF(sc->sc_node); - - NG_FREE_M(m); - - return (status); - } - - sc->sc_flags |= UBT_EVT_RECV; - sc->sc_intr_buffer = m; - - return (USBD_NORMAL_COMPLETION); -} /* ubt_intr_start */ - -/* - * Process interrupt from USB device (We got data from interrupt pipe) - */ - -static void -ubt_intr_complete(usbd_xfer_handle h, usbd_private_handle p, usbd_status s) -{ - ng_send_fn((node_p) p, NULL, ubt_intr_complete2, (void *) h, s); - NG_NODE_UNREF((node_p) p); -} /* ubt_intr_complete */ - -static void -ubt_intr_complete2(node_p node, hook_p hook, void *arg1, int arg2) -{ - ubt_softc_p sc = (ubt_softc_p) NG_NODE_PRIVATE(node); - usbd_xfer_handle h = (usbd_xfer_handle) arg1; - usbd_status s = (usbd_status) arg2; - struct mbuf *m = NULL; - ng_hci_event_pkt_t *hdr = NULL; - int error; - - if (sc == NULL) - return; - - KASSERT((sc->sc_flags & UBT_EVT_RECV), ( -"%s: %s - No interrupt request is pending\n", - __func__, device_get_nameunit(sc->sc_dev))); - - sc->sc_flags &= ~UBT_EVT_RECV; - - m = sc->sc_intr_buffer; - sc->sc_intr_buffer = NULL; - - hdr = mtod(m, ng_hci_event_pkt_t *); - - if (sc->sc_hook == NULL || NG_HOOK_NOT_VALID(sc->sc_hook)) { - NG_UBT_INFO( -"%s: %s - No upstream hook\n", __func__, device_get_nameunit(sc->sc_dev)); - - NG_FREE_M(m); - return; - } - - if (s == USBD_CANCELLED) { - NG_UBT_INFO( -"%s: %s - Interrupt xfer cancelled\n", __func__, device_get_nameunit(sc->sc_dev)); - - NG_FREE_M(m); - return; - } - - if (s != USBD_NORMAL_COMPLETION) { - NG_UBT_WARN( -"%s: %s - Interrupt xfer failed, %s (%d). No new xfer will be submitted!\n", - __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(s), s); - - if (s == USBD_STALLED) - usbd_clear_endpoint_stall_async(sc->sc_intr_pipe); - - NG_UBT_STAT_IERROR(sc->sc_stat); - NG_FREE_M(m); - - return; /* XXX FIXME we should restart after some delay */ - } - - NG_UBT_STAT_BYTES_RECV(sc->sc_stat, h->actlen); - m->m_pkthdr.len += h->actlen; - m->m_len += h->actlen; - - NG_UBT_INFO( -"%s: %s - Got %d bytes from interrupt pipe\n", - __func__, device_get_nameunit(sc->sc_dev), h->actlen); - - if (m->m_pkthdr.len < sizeof(*hdr)) { - NG_FREE_M(m); - goto done; - } - - if (hdr->length == m->m_pkthdr.len - sizeof(*hdr)) { - NG_UBT_INFO( -"%s: %s - Got complete HCI event frame, pktlen=%d, length=%d\n", - __func__, device_get_nameunit(sc->sc_dev), m->m_pkthdr.len, - hdr->length); - - NG_UBT_STAT_PCKTS_RECV(sc->sc_stat); - - NG_SEND_DATA_ONLY(error, sc->sc_hook, m); - if (error != 0) - NG_UBT_STAT_IERROR(sc->sc_stat); - } else { - NG_UBT_ERR( -"%s: %s - Invalid HCI event frame size, length=%d, pktlen=%d\n", - __func__, device_get_nameunit(sc->sc_dev), hdr->length, - m->m_pkthdr.len); - - NG_UBT_STAT_IERROR(sc->sc_stat); - NG_FREE_M(m); - } -done: - ubt_intr_start(sc); -} /* ubt_intr_complete2 */ - -/* - * Start bulk-in USB transfer (ACL data). Must be called when node is locked - */ - -static usbd_status -ubt_bulk_in_start(ubt_softc_p sc) -{ - struct mbuf *m = NULL; - usbd_status status; - - KASSERT(!(sc->sc_flags & UBT_ACL_RECV), ( -"%s: %s - Another bulk-in request is pending\n", - __func__, device_get_nameunit(sc->sc_dev))); - - /* Allocate new mbuf cluster */ - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) - return (USBD_NOMEM); - - MCLGET(m, M_DONTWAIT); - if (!(m->m_flags & M_EXT)) { - NG_FREE_M(m); - return (USBD_NOMEM); - } - - if (!(sc->sc_flags & UBT_HAVE_FRAME_TYPE)) { - *mtod(m, uint8_t *) = NG_HCI_ACL_DATA_PKT; - m->m_pkthdr.len = m->m_len = 1; - } else - m->m_pkthdr.len = m->m_len = 0; - - /* Initialize a bulk-in USB transfer and then schedule it */ - usbd_setup_xfer( - sc->sc_bulk_in_xfer, - sc->sc_bulk_in_pipe, - (usbd_private_handle) sc->sc_node, - (void *)(mtod(m, uint8_t *) + m->m_len), - MCLBYTES - m->m_len, - USBD_SHORT_XFER_OK, - USBD_NO_TIMEOUT, - ubt_bulk_in_complete); - - NG_NODE_REF(sc->sc_node); - - status = usbd_transfer(sc->sc_bulk_in_xfer); - if (status != USBD_NORMAL_COMPLETION && status != USBD_IN_PROGRESS) { - NG_UBT_ERR( -"%s: %s - Failed to start bulk-in transfer. %s (%d)\n", - __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(status), - status); - - NG_NODE_UNREF(sc->sc_node); - - NG_FREE_M(m); - - return (status); - } - - sc->sc_flags |= UBT_ACL_RECV; - sc->sc_bulk_in_buffer = m; - - return (USBD_NORMAL_COMPLETION); -} /* ubt_bulk_in_start */ - -/* - * USB bulk-in transfer callback - */ - -static void -ubt_bulk_in_complete(usbd_xfer_handle h, usbd_private_handle p, usbd_status s) -{ - ng_send_fn((node_p) p, NULL, ubt_bulk_in_complete2, (void *) h, s); - NG_NODE_UNREF((node_p) p); -} /* ubt_bulk_in_complete */ - -static void -ubt_bulk_in_complete2(node_p node, hook_p hook, void *arg1, int arg2) -{ - ubt_softc_p sc = (ubt_softc_p) NG_NODE_PRIVATE(node); - usbd_xfer_handle h = (usbd_xfer_handle) arg1; - usbd_status s = (usbd_status) arg2; - struct mbuf *m = NULL; - ng_hci_acldata_pkt_t *hdr = NULL; - int len; - - if (sc == NULL) - return; - - KASSERT((sc->sc_flags & UBT_ACL_RECV), ( -"%s: %s - No bulk-in request is pending\n", __func__, device_get_nameunit(sc->sc_dev))); - - sc->sc_flags &= ~UBT_ACL_RECV; - - m = sc->sc_bulk_in_buffer; - sc->sc_bulk_in_buffer = NULL; - - hdr = mtod(m, ng_hci_acldata_pkt_t *); - - if (sc->sc_hook == NULL || NG_HOOK_NOT_VALID(sc->sc_hook)) { - NG_UBT_INFO( -"%s: %s - No upstream hook\n", __func__, device_get_nameunit(sc->sc_dev)); - - NG_FREE_M(m); - return; - } - - if (s == USBD_CANCELLED) { - NG_UBT_INFO( -"%s: %s - Bulk-in xfer cancelled, pipe=%p\n", - __func__, device_get_nameunit(sc->sc_dev), sc->sc_bulk_in_pipe); - - NG_FREE_M(m); - return; - } - - if (s != USBD_NORMAL_COMPLETION) { - NG_UBT_WARN( -"%s: %s - Bulk-in xfer failed, %s (%d). No new xfer will be submitted!\n", - __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(s), s); - - if (s == USBD_STALLED) - usbd_clear_endpoint_stall_async(sc->sc_bulk_in_pipe); - - NG_UBT_STAT_IERROR(sc->sc_stat); - NG_FREE_M(m); - - return; /* XXX FIXME we should restart after some delay */ - } - - NG_UBT_STAT_BYTES_RECV(sc->sc_stat, h->actlen); - m->m_pkthdr.len += h->actlen; - m->m_len += h->actlen; - - NG_UBT_INFO( -"%s: %s - Got %d bytes from bulk-in pipe\n", - __func__, device_get_nameunit(sc->sc_dev), h->actlen); - - if (m->m_pkthdr.len < sizeof(*hdr)) { - NG_FREE_M(m); - goto done; - } - - len = le16toh(hdr->length); - if (len == m->m_pkthdr.len - sizeof(*hdr)) { - NG_UBT_INFO( -"%s: %s - Got complete ACL data frame, pktlen=%d, length=%d\n", - __func__, device_get_nameunit(sc->sc_dev), m->m_pkthdr.len, len); - - NG_UBT_STAT_PCKTS_RECV(sc->sc_stat); - - NG_SEND_DATA_ONLY(len, sc->sc_hook, m); - if (len != 0) - NG_UBT_STAT_IERROR(sc->sc_stat); - } else { - NG_UBT_ERR( -"%s: %s - Invalid ACL frame size, length=%d, pktlen=%d\n", - __func__, device_get_nameunit(sc->sc_dev), len, - m->m_pkthdr.len); - - NG_UBT_STAT_IERROR(sc->sc_stat); - NG_FREE_M(m); - } -done: - ubt_bulk_in_start(sc); -} /* ubt_bulk_in_complete2 */ - -/* - * Start bulk-out USB transfer. Must be called with node locked - */ - -static usbd_status -ubt_bulk_out_start(ubt_softc_p sc) -{ - struct mbuf *m = NULL; - usbd_status status; - - KASSERT(!(sc->sc_flags & UBT_ACL_XMIT), ( -"%s: %s - Another bulk-out request is pending\n", - __func__, device_get_nameunit(sc->sc_dev))); - - NG_BT_MBUFQ_DEQUEUE(&sc->sc_aclq, m); - if (m == NULL) { - NG_UBT_INFO( -"%s: %s - ACL data queue is empty\n", __func__, device_get_nameunit(sc->sc_dev)); - - return (USBD_NORMAL_COMPLETION); - } - - /* - * Check ACL data frame size and copy it back to linear USB - * transfer buffer. - */ - - if (m->m_pkthdr.len > UBT_BULK_BUFFER_SIZE) - panic( -"%s: %s - ACL data frame too big, size=%d, len=%d\n", - __func__, device_get_nameunit(sc->sc_dev), UBT_BULK_BUFFER_SIZE, - m->m_pkthdr.len); - - m_copydata(m, 0, m->m_pkthdr.len, sc->sc_bulk_out_buffer); - - /* Initialize a bulk-out USB transfer and then schedule it */ - usbd_setup_xfer( - sc->sc_bulk_out_xfer, - sc->sc_bulk_out_pipe, - (usbd_private_handle) sc->sc_node, - sc->sc_bulk_out_buffer, - m->m_pkthdr.len, - USBD_NO_COPY, - USBD_DEFAULT_TIMEOUT, /* XXX */ - ubt_bulk_out_complete); - - NG_NODE_REF(sc->sc_node); - - status = usbd_transfer(sc->sc_bulk_out_xfer); - if (status != USBD_NORMAL_COMPLETION && status != USBD_IN_PROGRESS) { - NG_UBT_ERR( -"%s: %s - Could not start bulk-out transfer. %s (%d)\n", - __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(status), - status); - - NG_NODE_UNREF(sc->sc_node); - - NG_BT_MBUFQ_DROP(&sc->sc_aclq); - NG_UBT_STAT_OERROR(sc->sc_stat); - - /* XXX FIXME should we try to start another transfer? */ - } else { - NG_UBT_INFO( -"%s: %s - Bulk-out transfer has been started, len=%d\n", - __func__, device_get_nameunit(sc->sc_dev), m->m_pkthdr.len); - - sc->sc_flags |= UBT_ACL_XMIT; - status = USBD_NORMAL_COMPLETION; - } - - NG_FREE_M(m); - - return (status); -} /* ubt_bulk_out_start */ - -/* - * USB bulk-out transfer callback - */ - -static void -ubt_bulk_out_complete(usbd_xfer_handle h, usbd_private_handle p, usbd_status s) -{ - ng_send_fn((node_p) p, NULL, ubt_bulk_out_complete2, (void *) h, s); - NG_NODE_UNREF((node_p) p); -} /* ubt_bulk_out_complete */ - -static void -ubt_bulk_out_complete2(node_p node, hook_p hook, void *arg1, int arg2) -{ - ubt_softc_p sc = (ubt_softc_p) NG_NODE_PRIVATE(node); - usbd_xfer_handle h = (usbd_xfer_handle) arg1; - usbd_status s = (usbd_status) arg2; - - if (sc == NULL) - return; - - KASSERT((sc->sc_flags & UBT_ACL_XMIT), ( -"%s: %s - No bulk-out request is pending\n", __func__, device_get_nameunit(sc->sc_dev))); - - sc->sc_flags &= ~UBT_ACL_XMIT; - - if (s == USBD_CANCELLED) { - NG_UBT_INFO( -"%s: %s - Bulk-out xfer cancelled, pipe=%p\n", - __func__, device_get_nameunit(sc->sc_dev), sc->sc_bulk_out_pipe); - - return; - } - - if (s != USBD_NORMAL_COMPLETION) { - NG_UBT_WARN( -"%s: %s - Bulk-out xfer failed. %s (%d)\n", - __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(s), s); - - if (s == USBD_STALLED) - usbd_clear_endpoint_stall_async(sc->sc_bulk_out_pipe); - - NG_UBT_STAT_OERROR(sc->sc_stat); - } else { - NG_UBT_INFO( -"%s: %s - Sent %d bytes to bulk-out pipe\n", - __func__, device_get_nameunit(sc->sc_dev), h->actlen); - - NG_UBT_STAT_BYTES_SENT(sc->sc_stat, h->actlen); - NG_UBT_STAT_PCKTS_SENT(sc->sc_stat); - } - - if (NG_BT_MBUFQ_LEN(&sc->sc_aclq) > 0) - ubt_bulk_out_start(sc); -} /* ubt_bulk_out_complete2 */ - -/* - * Start non-active Isochronous-in USB transfer. - * Must be called with node locked - */ - -static usbd_status -ubt_isoc_in_start_one(ubt_softc_p sc, int idx) -{ - usbd_status status; - int i; - - for (i = 0; i < NG_UBT_NFRAMES; i++) - sc->sc_isoc_in[idx].frlen[i] = sc->sc_isoc_size; - - usbd_setup_isoc_xfer( - sc->sc_isoc_in[idx].xfer, - sc->sc_isoc_in_pipe, - (usbd_private_handle) sc->sc_node, - sc->sc_isoc_in[idx].frlen, - NG_UBT_NFRAMES, - USBD_NO_COPY | USBD_SHORT_XFER_OK, - ubt_isoc_in_complete); - - NG_NODE_REF(sc->sc_node); - - status = usbd_transfer(sc->sc_isoc_in[idx].xfer); - if (status != USBD_NORMAL_COMPLETION && status != USBD_IN_PROGRESS) { - NG_UBT_ERR( -"%s: %s - Failed to start isoc-in transfer. %s (%d)\n", - __func__, device_get_nameunit(sc->sc_dev), - usbd_errstr(status), status); - - NG_NODE_UNREF(sc->sc_node); - } else - sc->sc_isoc_in[idx].active = 1; - - return (status); -} - -/* - * (Re)Start all non-active Isochronous-in USB transfers. - * Must be called with node locked. - */ - -static usbd_status -ubt_isoc_in_start(ubt_softc_p sc) -{ - int i; - - for (i = 0; i < NG_UBT_NXFERS; i++) - if (!sc->sc_isoc_in[i].active) - ubt_isoc_in_start_one(sc, i); - - return (USBD_NORMAL_COMPLETION); -} /* ubt_isoc_in_start */ - -/* - * USB isochronous transfer callback - */ - -static void -ubt_isoc_in_complete(usbd_xfer_handle h, usbd_private_handle p, usbd_status s) -{ - ng_send_fn((node_p) p, NULL, ubt_isoc_in_complete2, (void *) h, s); - NG_NODE_UNREF((node_p) p); -} /* ubt_isoc_in_complete */ - -static void -ubt_isoc_in_complete2(node_p node, hook_p hook, void *arg1, int arg2) -{ - ubt_softc_p sc = (ubt_softc_p) NG_NODE_PRIVATE(node); - usbd_xfer_handle h = (usbd_xfer_handle) arg1; - usbd_status s = (usbd_status) arg2; - int i, idx, want, got; - struct mbuf *m; - - if (sc == NULL) - return; - - /* Find xfer */ - idx = -1; - for (i = 0; i < NG_UBT_NXFERS; i++) { - if (sc->sc_isoc_in[i].xfer == h) { - idx = i; - break; - } - } - KASSERT(idx != -1, ( -"%s:%s - Could not find isoc-in request\n", - __func__, device_get_nameunit(sc->sc_dev))); - KASSERT(sc->sc_isoc_in[idx].active, ( -"%s: %s - Isoc-in request is not active\n", - __func__, device_get_nameunit(sc->sc_dev))); - - sc->sc_isoc_in[idx].active = 0; - - if (sc->sc_hook == NULL || NG_HOOK_NOT_VALID(sc->sc_hook)) { - NG_UBT_INFO( -"%s: %s - No upstream hook\n", __func__, device_get_nameunit(sc->sc_dev)); - - return; - } - - /* Process xfer */ - if (s == USBD_CANCELLED) { - NG_UBT_INFO( -"%s: %s - Isoc-in xfer cancelled, pipe=%p\n", - __func__, device_get_nameunit(sc->sc_dev), sc->sc_isoc_in_pipe); - - return; - } - - if (s != USBD_NORMAL_COMPLETION) { - NG_UBT_WARN( -"%s: %s - Isoc-in xfer failed, %s (%d). No new xfer will be submitted!\n", - __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(s), s); - - if (s == USBD_STALLED) - usbd_clear_endpoint_stall_async(sc->sc_isoc_in_pipe); - - NG_UBT_STAT_IERROR(sc->sc_stat); - - return; /* XXX FIXME we should restart after some delay */ - } - - if (h->actlen <= 0) - goto done; - - NG_UBT_INFO( -"%s: %s - Got %d bytes from isoc-in pipe\n", - __func__, device_get_nameunit(sc->sc_dev), h->actlen); - - /* - * Re-assemble SCO HCI frame - */ - - m = sc->sc_isoc_in_buffer; - sc->sc_isoc_in_buffer = NULL; - - for (i = 0; i < NG_UBT_NFRAMES; i ++) { - uint8_t *frame = (uint8_t *) sc->sc_isoc_in[idx].buffer + - (i * sc->sc_isoc_size); - - while (sc->sc_isoc_in[idx].frlen[i] > 0) { - int error, frlen = sc->sc_isoc_in[idx].frlen[i]; - - if (m == NULL) { - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) { - goto done; /* XXX out of sync! */ - } - - MCLGET(m, M_DONTWAIT); - if (!(m->m_flags & M_EXT)) { - NG_FREE_M(m); - goto done; /* XXX out of sync! */ - } - - if (!(sc->sc_flags & UBT_HAVE_FRAME_TYPE)) { - *mtod(m, uint8_t *) = NG_HCI_SCO_DATA_PKT; - m->m_pkthdr.len = m->m_len = got = 1; - } else { - m->m_pkthdr.len = m->m_len = got = 0; - } - - want = sizeof(ng_hci_scodata_pkt_t); - } else { - got = m->m_pkthdr.len; - want = sizeof(ng_hci_scodata_pkt_t); - - if (got >= want) - want += mtod(m, ng_hci_scodata_pkt_t *)->length; - } - - if (got + frlen > want) - frlen = want - got; - - if (!m_append(m, frlen, frame)) { - NG_FREE_M(m); - goto done; /* XXX out of sync! */ - } - - got += frlen; - frame += frlen; - sc->sc_isoc_in[idx].frlen[i] -= frlen; - - if (got != want) - continue; - - if (want == sizeof(ng_hci_scodata_pkt_t)) - want += mtod(m, ng_hci_scodata_pkt_t *)->length; - - if (got != want) - continue; - - NG_UBT_INFO( -"%s: %s - Got complete SCO data frame, pktlen=%d, length=%d\n", - __func__, device_get_nameunit(sc->sc_dev), - m->m_pkthdr.len, - mtod(m, ng_hci_scodata_pkt_t *)->length); - - NG_UBT_STAT_PCKTS_RECV(sc->sc_stat); - NG_UBT_STAT_BYTES_RECV(sc->sc_stat, m->m_pkthdr.len); - - NG_SEND_DATA_ONLY(error, sc->sc_hook, m); - if (error != 0) - NG_UBT_STAT_IERROR(sc->sc_stat); - } - } - - sc->sc_isoc_in_buffer = m; -done: - ubt_isoc_in_start_one(sc, idx); -} /* ubt_isoc_in_complete2 */ - -/* - * Start non-active isochronous-out USB transfer. - * Must be called with node locked - */ - -static usbd_status -ubt_isoc_out_start_one(ubt_softc_p sc, int idx) -{ - int len, maxlen, size, nframes; - struct mbuf *m; - uint8_t *buffer; - usbd_status status; - - /* - * Fill the transfer buffer with data from the queue, - * putting any leftover back on the queue - */ - - len = 0; - maxlen = NG_UBT_NFRAMES * sc->sc_isoc_size; - m = NULL; - buffer = sc->sc_isoc_out[idx].buffer; - - while (maxlen > 0) { - if (m == NULL) { - NG_BT_MBUFQ_DEQUEUE(&sc->sc_scoq, m); - if (m == NULL) - break; - } - - if (m->m_pkthdr.len > 0) { - size = MIN(m->m_pkthdr.len, maxlen); - - m_copydata(m, 0, size, buffer); - m_adj(m, size); - - buffer += size; - len += size; - maxlen -= size; - } - - if (m->m_pkthdr.len == 0) { - NG_UBT_STAT_PCKTS_SENT(sc->sc_stat); - NG_FREE_M(m); - } - } - - if (m != NULL) - NG_BT_MBUFQ_PREPEND(&sc->sc_scoq, m); - - if (len == 0) - return (USBD_NORMAL_COMPLETION); /* nothing to send */ - - NG_UBT_STAT_BYTES_SENT(sc->sc_stat, len); - - /* Calculate number of isoc frames and sizes */ - for (nframes = 0; len > 0; nframes ++) { - size = MIN(sc->sc_isoc_size, len); - sc->sc_isoc_out[idx].frlen[nframes] = size; - len -= size; - } - - /* Initialize a isoc-out USB transfer and then schedule it */ - usbd_setup_isoc_xfer( - sc->sc_isoc_out[idx].xfer, - sc->sc_isoc_out_pipe, - (usbd_private_handle) sc->sc_node, - sc->sc_isoc_out[idx].frlen, - nframes, - USBD_NO_COPY | USBD_FORCE_SHORT_XFER, - ubt_isoc_out_complete); - - NG_NODE_REF(sc->sc_node); - sc->sc_isoc_out[idx].active = 1; - - status = usbd_transfer(sc->sc_isoc_out[idx].xfer); - if (status != USBD_NORMAL_COMPLETION && status != USBD_IN_PROGRESS) { - NG_UBT_ERR( -"%s: %s - Could not start isoc-out transfer. %s (%d)\n", - __func__, device_get_nameunit(sc->sc_dev), - usbd_errstr(status), status); - - sc->sc_isoc_out[idx].active = 0; - NG_NODE_UNREF(sc->sc_node); - - NG_UBT_STAT_OERROR(sc->sc_stat); - } else { - NG_UBT_INFO( -"%s: %s - Isoc-out transfer has been started, nframes=%d, size=%d\n", - __func__, device_get_nameunit(sc->sc_dev), nframes, - sc->sc_isoc_size); - status = USBD_NORMAL_COMPLETION; - } - - return (status); -} - -/* - * Start all non-active isochronous-out USB transfer. - * Must be called with node locked - */ - -static usbd_status -ubt_isoc_out_start(ubt_softc_p sc) -{ - int i; - - for (i = 0; i < NG_UBT_NXFERS; i++) { - if (sc->sc_isoc_out[i].active) - continue; - - ubt_isoc_out_start_one(sc, i); - } - - return (USBD_NORMAL_COMPLETION); -} /* ubt_isoc_out_start */ - -/* - * USB isoc-out. transfer callback - */ - -static void -ubt_isoc_out_complete(usbd_xfer_handle h, usbd_private_handle p, usbd_status s) -{ - ng_send_fn((node_p) p, NULL, ubt_isoc_out_complete2, (void *) h, s); - NG_NODE_UNREF((node_p) p); -} /* ubt_isoc_out_complete */ - -static void -ubt_isoc_out_complete2(node_p node, hook_p hook, void *arg1, int arg2) -{ - ubt_softc_p sc = (ubt_softc_p) NG_NODE_PRIVATE(node); - usbd_xfer_handle h = (usbd_xfer_handle) arg1; - usbd_status s = (usbd_status) arg2; - int i, idx; - - if (sc == NULL) - return; - - /* Find xfer */ - idx = -1; - for (i = 0; i < NG_UBT_NXFERS; i++) { - if (sc->sc_isoc_out[i].xfer == h) { - idx = i; - break; - } - } - KASSERT(idx != -1, ( -"%s:%s - Could not find isoc-out request\n", - __func__, device_get_nameunit(sc->sc_dev))); - KASSERT(sc->sc_isoc_out[idx].active, ( -"%s: %s - Isoc-out request is not active\n", - __func__, device_get_nameunit(sc->sc_dev))); - - sc->sc_isoc_out[idx].active = 0; - - /* Process xfer */ - if (s == USBD_CANCELLED) { - NG_UBT_INFO( -"%s: %s - Isoc-out xfer cancelled, pipe=%p\n", - __func__, device_get_nameunit(sc->sc_dev), - sc->sc_isoc_out_pipe); - - return; - } - - if (s != USBD_NORMAL_COMPLETION) { - NG_UBT_WARN( -"%s: %s - Isoc-out xfer failed. %s (%d)\n", - __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(s), s); - - if (s == USBD_STALLED) - usbd_clear_endpoint_stall_async(sc->sc_isoc_out_pipe); - - NG_UBT_STAT_OERROR(sc->sc_stat); - } else { - NG_UBT_INFO( -"%s: %s - Sent %d bytes to isoc-out pipe\n", - __func__, device_get_nameunit(sc->sc_dev), h->actlen); - -/* XXX FIXME NG_UBT_STAT_BYTES_SENT(sc->sc_stat, h->actlen); - NG_UBT_STAT_PCKTS_SENT(sc->sc_stat); */ - } - - if (NG_BT_MBUFQ_LEN(&sc->sc_scoq) > 0) - ubt_isoc_out_start(sc); -} /* ubt_isoc_out_complete2 */ - -/* - * Abort transfers on all USB pipes - */ - -static void -ubt_reset(ubt_softc_p sc) -{ - /* Interrupt */ - if (sc->sc_intr_pipe != NULL) - usbd_abort_pipe(sc->sc_intr_pipe); - - /* Bulk-in/out */ - if (sc->sc_bulk_in_pipe != NULL) - usbd_abort_pipe(sc->sc_bulk_in_pipe); - if (sc->sc_bulk_out_pipe != NULL) - usbd_abort_pipe(sc->sc_bulk_out_pipe); - - /* Isoc-in/out */ - if (sc->sc_isoc_in_pipe != NULL) - usbd_abort_pipe(sc->sc_isoc_in_pipe); - if (sc->sc_isoc_out_pipe != NULL) - usbd_abort_pipe(sc->sc_isoc_out_pipe); - - /* Cleanup queues */ - NG_BT_MBUFQ_DRAIN(&sc->sc_cmdq); - NG_BT_MBUFQ_DRAIN(&sc->sc_aclq); - NG_BT_MBUFQ_DRAIN(&sc->sc_scoq); -} /* ubt_reset */ - -/**************************************************************************** - **************************************************************************** - ** Netgraph specific - **************************************************************************** - ****************************************************************************/ - -/* - * Netgraph node constructor. Do not allow to create node of this type. - */ - -static int -ng_ubt_constructor(node_p node) -{ - return (EINVAL); -} /* ng_ubt_constructor */ - -/* - * Netgraph node destructor. Destroy node only when device has been detached - */ - -static int -ng_ubt_shutdown(node_p node) -{ - ubt_softc_p sc = (ubt_softc_p) NG_NODE_PRIVATE(node); - - /* Let old node go */ - NG_NODE_SET_PRIVATE(node, NULL); - NG_NODE_UNREF(node); - - if (sc == NULL) - goto done; - - /* Create Netgraph node */ - if (ng_make_node_common(&typestruct, &sc->sc_node) != 0) { - printf("%s: Could not create Netgraph node\n", - device_get_nameunit(sc->sc_dev)); - sc->sc_node = NULL; - goto done; - } - - /* Name node */ - if (ng_name_node(sc->sc_node, device_get_nameunit(sc->sc_dev)) != 0) { - printf("%s: Could not name Netgraph node\n", - device_get_nameunit(sc->sc_dev)); - NG_NODE_UNREF(sc->sc_node); - sc->sc_node = NULL; - goto done; - } - - NG_NODE_SET_PRIVATE(sc->sc_node, sc); - NG_NODE_FORCE_WRITER(sc->sc_node); -done: - return (0); -} /* ng_ubt_shutdown */ - -/* - * Create new hook. There can only be one. - */ - -static int -ng_ubt_newhook(node_p node, hook_p hook, char const *name) -{ - ubt_softc_p sc = (ubt_softc_p) NG_NODE_PRIVATE(node); - - if (strcmp(name, NG_UBT_HOOK) != 0) - return (EINVAL); - - if (sc->sc_hook != NULL) - return (EISCONN); - - sc->sc_hook = hook; - - return (0); -} /* ng_ubt_newhook */ - -/* - * Connect hook. Start incoming USB transfers - */ - -static int -ng_ubt_connect(hook_p hook) -{ - ubt_softc_p sc = (ubt_softc_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); - usbd_status status; - - NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook)); - - /* Start intr transfer */ - status = ubt_intr_start(sc); - if (status != USBD_NORMAL_COMPLETION) { - NG_UBT_ALERT( -"%s: %s - Could not start interrupt transfer. %s (%d)\n", - __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(status), - status); - goto fail; - } - - /* Start bulk-in transfer */ - status = ubt_bulk_in_start(sc); - if (status != USBD_NORMAL_COMPLETION) { - NG_UBT_ALERT( -"%s: %s - Could not start bulk-in transfer. %s (%d)\n", - __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(status), - status); - goto fail; - } - - /* Start isoc-in transfer */ - status = ubt_isoc_in_start(sc); - if (status != USBD_NORMAL_COMPLETION) { - NG_UBT_ALERT( -"%s: %s - Could not start isoc-in transfer. %s (%d)\n", - __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(status), - status); - goto fail; - } - - return (0); -fail: - ubt_reset(sc); - sc->sc_hook = NULL; - - return (ENXIO); -} /* ng_ubt_connect */ - -/* - * Disconnect hook - */ - -static int -ng_ubt_disconnect(hook_p hook) -{ - ubt_softc_p sc = (ubt_softc_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); - - if (sc != NULL) { - if (hook != sc->sc_hook) - return (EINVAL); - - ubt_reset(sc); - sc->sc_hook = NULL; - } - - return (0); -} /* ng_ubt_disconnect */ - -/* - * Process control message - */ - -static int -ng_ubt_rcvmsg(node_p node, item_p item, hook_p lasthook) -{ - ubt_softc_p sc = (ubt_softc_p) NG_NODE_PRIVATE(node); - struct ng_mesg *msg = NULL, *rsp = NULL; - struct ng_bt_mbufq *q = NULL; - int error = 0, queue, qlen; - - if (sc == NULL) { - NG_FREE_ITEM(item); - return (EHOSTDOWN); - } - - NGI_GET_MSG(item, msg); - - switch (msg->header.typecookie) { - case NGM_GENERIC_COOKIE: - switch (msg->header.cmd) { - case NGM_TEXT_STATUS: - NG_MKRESPONSE(rsp, msg, NG_TEXTRESPONSE, M_NOWAIT); - if (rsp == NULL) - error = ENOMEM; - else - snprintf(rsp->data, NG_TEXTRESPONSE, - "Hook: %s\n" \ - "Flags: %#x\n" \ - "Debug: %d\n" \ - "CMD queue: [have:%d,max:%d]\n" \ - "ACL queue: [have:%d,max:%d]\n" \ - "SCO queue: [have:%d,max:%d]", - (sc->sc_hook != NULL)? NG_UBT_HOOK : "", - sc->sc_flags, - sc->sc_debug, - NG_BT_MBUFQ_LEN(&sc->sc_cmdq), - sc->sc_cmdq.maxlen, - NG_BT_MBUFQ_LEN(&sc->sc_aclq), - sc->sc_aclq.maxlen, - NG_BT_MBUFQ_LEN(&sc->sc_scoq), - sc->sc_scoq.maxlen); - break; - - default: - error = EINVAL; - break; - } - break; - - case NGM_UBT_COOKIE: - switch (msg->header.cmd) { - case NGM_UBT_NODE_SET_DEBUG: - if (msg->header.arglen != sizeof(ng_ubt_node_debug_ep)) - error = EMSGSIZE; - else - sc->sc_debug = - *((ng_ubt_node_debug_ep *)(msg->data)); - break; - - case NGM_UBT_NODE_GET_DEBUG: - NG_MKRESPONSE(rsp, msg, sizeof(ng_ubt_node_debug_ep), - M_NOWAIT); - if (rsp == NULL) - error = ENOMEM; - else - *((ng_ubt_node_debug_ep *)(rsp->data)) = - sc->sc_debug; - break; - - case NGM_UBT_NODE_SET_QLEN: - if (msg->header.arglen != sizeof(ng_ubt_node_qlen_ep)) - error = EMSGSIZE; - else { - queue = ((ng_ubt_node_qlen_ep *) - (msg->data))->queue; - qlen = ((ng_ubt_node_qlen_ep *) - (msg->data))->qlen; - - if (qlen <= 0) { - error = EINVAL; - break; - } - - switch (queue) { - case NGM_UBT_NODE_QUEUE_CMD: - q = &sc->sc_cmdq; - break; - - case NGM_UBT_NODE_QUEUE_ACL: - q = &sc->sc_aclq; - break; - - case NGM_UBT_NODE_QUEUE_SCO: - q = &sc->sc_scoq; - break; - - default: - q = NULL; - error = EINVAL; - break; - } - - if (q != NULL) - q->maxlen = qlen; - } - break; - - case NGM_UBT_NODE_GET_QLEN: - if (msg->header.arglen != sizeof(ng_ubt_node_qlen_ep)) { - error = EMSGSIZE; - break; - } - - queue = ((ng_ubt_node_qlen_ep *)(msg->data))->queue; - switch (queue) { - case NGM_UBT_NODE_QUEUE_CMD: - q = &sc->sc_cmdq; - break; - - case NGM_UBT_NODE_QUEUE_ACL: - q = &sc->sc_aclq; - break; - - case NGM_UBT_NODE_QUEUE_SCO: - q = &sc->sc_scoq; - break; - - default: - q = NULL; - error = EINVAL; - break; - } - - if (q != NULL) { - NG_MKRESPONSE(rsp, msg, - sizeof(ng_ubt_node_qlen_ep), M_NOWAIT); - if (rsp == NULL) { - error = ENOMEM; - break; - } - - ((ng_ubt_node_qlen_ep *)(rsp->data))->queue = - queue; - ((ng_ubt_node_qlen_ep *)(rsp->data))->qlen = - q->maxlen; - } - break; - - case NGM_UBT_NODE_GET_STAT: - NG_MKRESPONSE(rsp, msg, sizeof(ng_ubt_node_stat_ep), - M_NOWAIT); - if (rsp == NULL) - error = ENOMEM; - else - bcopy(&sc->sc_stat, rsp->data, - sizeof(ng_ubt_node_stat_ep)); - break; - - case NGM_UBT_NODE_RESET_STAT: - NG_UBT_STAT_RESET(sc->sc_stat); - break; - - default: - error = EINVAL; - break; - } - break; - - default: - error = EINVAL; - break; - } - - NG_RESPOND_MSG(error, node, item, rsp); - NG_FREE_MSG(msg); - - return (error); -} /* ng_ubt_rcvmsg */ - -/* - * Process data - */ - -static int -ng_ubt_rcvdata(hook_p hook, item_p item) -{ - ubt_softc_p sc = (ubt_softc_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); - struct mbuf *m = NULL; - usbd_status (*f)(ubt_softc_p) = NULL; - struct ng_bt_mbufq *q = NULL; - int b, error = 0; - - if (sc == NULL) { - error = EHOSTDOWN; - goto done; - } - - if (hook != sc->sc_hook) { - error = EINVAL; - goto done; - } - - /* Deatch mbuf and get HCI frame type */ - NGI_GET_M(item, m); - - /* Process HCI frame */ - switch (*mtod(m, uint8_t *)) { /* XXX call m_pullup ? */ - case NG_HCI_CMD_PKT: - f = ubt_request_start; - q = &sc->sc_cmdq; - b = UBT_CMD_XMIT; - break; - - case NG_HCI_ACL_DATA_PKT: - f = ubt_bulk_out_start; - q = &sc->sc_aclq; - b = UBT_ACL_XMIT; - break; - - case NG_HCI_SCO_DATA_PKT: - f = ubt_isoc_out_start; - q = &sc->sc_scoq; - b = UBT_SCO_XMIT; - break; - - default: - NG_UBT_ERR( -"%s: %s - Dropping unknown/unsupported HCI frame, type=%d, pktlen=%d\n", - __func__, device_get_nameunit(sc->sc_dev), *mtod(m, uint8_t *), - m->m_pkthdr.len); - - NG_FREE_M(m); - error = EINVAL; - - goto done; - /* NOT REACHED */ - } - - /* Loose frame type, if required */ - if (!(sc->sc_flags & UBT_NEED_FRAME_TYPE)) - m_adj(m, sizeof(uint8_t)); - - if (NG_BT_MBUFQ_FULL(q)) { - NG_UBT_ERR( -"%s: %s - Dropping HCI frame %#x, len=%d. Queue full\n", - __func__, device_get_nameunit(sc->sc_dev), - *mtod(m, uint8_t *), m->m_pkthdr.len); - - NG_FREE_M(m); - } else - NG_BT_MBUFQ_ENQUEUE(q, m); - - if (!(sc->sc_flags & b)) - if ((*f)(sc) != USBD_NORMAL_COMPLETION) - error = EIO; -done: - NG_FREE_ITEM(item); - - return (error); -} /* ng_ubt_rcvdata */ - diff --git a/sys/netgraph/bluetooth/drivers/ubt/ng_ubt_var.h b/sys/netgraph/bluetooth/drivers/ubt/ng_ubt_var.h deleted file mode 100644 index 6fdce0e..0000000 --- a/sys/netgraph/bluetooth/drivers/ubt/ng_ubt_var.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * ng_ubt_var.h - */ - -/*- - * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: ng_ubt_var.h,v 1.5 2005/10/31 17:57:44 max Exp $ - * $FreeBSD$ - */ - -#ifndef _NG_UBT_VAR_H_ -#define _NG_UBT_VAR_H_ - -/* pullup wrapper */ -#define NG_UBT_M_PULLUP(m, s) \ - do { \ - if ((m)->m_len < (s)) \ - (m) = m_pullup((m), (s)); \ - if ((m) == NULL) \ - NG_UBT_ALERT("%s: %s - m_pullup(%d) failed\n", \ - __func__, device_get_nameunit(sc->sc_dev), (s)); \ - } while (0) - -/* Debug printf's */ -#define NG_UBT_ALERT if (sc->sc_debug >= NG_UBT_ALERT_LEVEL) printf -#define NG_UBT_ERR if (sc->sc_debug >= NG_UBT_ERR_LEVEL) printf -#define NG_UBT_WARN if (sc->sc_debug >= NG_UBT_WARN_LEVEL) printf -#define NG_UBT_INFO if (sc->sc_debug >= NG_UBT_INFO_LEVEL) printf - -/* Bluetooth USB control request type */ -#define UBT_HCI_REQUEST 0x20 -#define UBT_DEFAULT_QLEN 12 - -/* Isoc transfers */ -#define NG_UBT_NXFERS 3 /* max xfers to queue */ -#define NG_UBT_NFRAMES 10 /* frames per xfer */ - -struct ubt_isoc_xfer { - usbd_xfer_handle xfer; /* isoc xfer */ - void *buffer; /* isoc buffer */ - uint16_t *frlen; /* isoc frame length */ - int active; /* is xfer active */ -}; -typedef struct ubt_isoc_xfer ubt_isoc_xfer_t; -typedef struct ubt_isoc_xfer * ubt_isoc_xfer_p; - -/* USB device softc structure */ -struct ubt_softc { - /* State */ - ng_ubt_node_debug_ep sc_debug; /* debug level */ - uint32_t sc_flags; /* device flags */ -#define UBT_NEED_FRAME_TYPE (1 << 0) /* device required frame type */ -#define UBT_HAVE_FRAME_TYPE UBT_NEED_FRAME_TYPE -#define UBT_CMD_XMIT (1 << 1) /* CMD xmit in progress */ -#define UBT_ACL_XMIT (1 << 2) /* ACL xmit in progress */ -#define UBT_SCO_XMIT (1 << 3) /* SCO xmit in progress */ -#define UBT_EVT_RECV (1 << 4) /* EVN recv in progress */ -#define UBT_ACL_RECV (1 << 5) /* ACL recv in progress */ -#define UBT_SCO_RECV (1 << 6) /* SCO recv in progress */ - - ng_ubt_node_stat_ep sc_stat; /* statistic */ -#define NG_UBT_STAT_PCKTS_SENT(s) (s).pckts_sent ++ -#define NG_UBT_STAT_BYTES_SENT(s, n) (s).bytes_sent += (n) -#define NG_UBT_STAT_PCKTS_RECV(s) (s).pckts_recv ++ -#define NG_UBT_STAT_BYTES_RECV(s, n) (s).bytes_recv += (n) -#define NG_UBT_STAT_OERROR(s) (s).oerrors ++ -#define NG_UBT_STAT_IERROR(s) (s).ierrors ++ -#define NG_UBT_STAT_RESET(s) bzero(&(s), sizeof((s))) - - /* USB device specific */ - device_t sc_dev; /* pointer back to USB device */ - usbd_device_handle sc_udev; /* USB device handle */ - - usbd_interface_handle sc_iface0; /* USB interface 0 */ - usbd_interface_handle sc_iface1; /* USB interface 1 */ - - /* Interrupt pipe (HCI events) */ - int sc_intr_ep; /* interrupt endpoint */ - usbd_pipe_handle sc_intr_pipe; /* interrupt pipe handle */ - usbd_xfer_handle sc_intr_xfer; /* intr xfer */ - struct mbuf *sc_intr_buffer; /* interrupt buffer */ - - /* Control pipe (HCI commands) */ - usbd_xfer_handle sc_ctrl_xfer; /* control xfer handle */ - void *sc_ctrl_buffer; /* control buffer */ - struct ng_bt_mbufq sc_cmdq; /* HCI command queue */ -#define UBT_CTRL_BUFFER_SIZE \ - (sizeof(ng_hci_cmd_pkt_t) + NG_HCI_CMD_PKT_SIZE) - - /* Bulk in pipe (ACL data) */ - int sc_bulk_in_ep; /* bulk-in enpoint */ - usbd_pipe_handle sc_bulk_in_pipe; /* bulk-in pipe */ - usbd_xfer_handle sc_bulk_in_xfer; /* bulk-in xfer */ - struct mbuf *sc_bulk_in_buffer; /* bulk-in buffer */ - - /* Bulk out pipe (ACL data) */ - int sc_bulk_out_ep; /* bulk-out endpoint */ - usbd_pipe_handle sc_bulk_out_pipe; /* bulk-out pipe */ - usbd_xfer_handle sc_bulk_out_xfer; /* bulk-out xfer */ - void *sc_bulk_out_buffer; /* bulk-out buffer */ - struct ng_bt_mbufq sc_aclq; /* ACL data queue */ -#define UBT_BULK_BUFFER_SIZE \ - MCLBYTES /* XXX should be big enough to hold one frame */ - - /* Isoc. in pipe (SCO data) */ - struct mbuf *sc_isoc_in_buffer; - int sc_isoc_in_ep; /* isoc-in endpoint */ - usbd_pipe_handle sc_isoc_in_pipe; /* isoc-in pipe */ - ubt_isoc_xfer_t sc_isoc_in[NG_UBT_NXFERS]; /* isoc-in xfers */ - - /* Isoc. out pipe (SCO data) */ - int sc_isoc_out_ep; /* isoc-out endpoint */ - usbd_pipe_handle sc_isoc_out_pipe; /* isoc-out pipe */ - ubt_isoc_xfer_t sc_isoc_out[NG_UBT_NXFERS]; /* isoc-out xfers */ - struct ng_bt_mbufq sc_scoq; /* SCO data queue */ - - int sc_isoc_size; /* max. size of isoc. packet */ -#define UBT_ISOC_BUFFER_SIZE \ - (sizeof(ng_hci_scodata_pkt_t) + NG_HCI_SCO_PKT_SIZE) - - /* Netgraph specific */ - node_p sc_node; /* pointer back to node */ - hook_p sc_hook; /* upstream hook */ -}; -typedef struct ubt_softc ubt_softc_t; -typedef struct ubt_softc * ubt_softc_p; - -#endif /* ndef _NG_UBT_VAR_H_ */ - diff --git a/sys/netgraph/bluetooth/drivers/ubtbcmfw/ubtbcmfw.c b/sys/netgraph/bluetooth/drivers/ubtbcmfw/ubtbcmfw.c deleted file mode 100644 index e4b06ab..0000000 --- a/sys/netgraph/bluetooth/drivers/ubtbcmfw/ubtbcmfw.c +++ /dev/null @@ -1,559 +0,0 @@ -/* - * ubtbcmfw.c - */ - -/*- - * Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: ubtbcmfw.c,v 1.3 2003/10/10 19:15:08 max Exp $ - * $FreeBSD$ - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/bus.h> -#include <sys/conf.h> -#include <sys/filio.h> -#include <sys/fcntl.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/poll.h> -#include <sys/proc.h> -#include <sys/sysctl.h> -#include <sys/uio.h> - -#include <dev/usb/usb.h> -#include <dev/usb/usbdi.h> -#include <dev/usb/usbdi_util.h> - -#include "usbdevs.h" - -/* - * Download firmware to BCM2033. - */ - -#define UBTBCMFW_CONFIG_NO 1 /* Config number */ -#define UBTBCMFW_IFACE_IDX 0 /* Control interface */ -#define UBTBCMFW_INTR_IN_EP 0x81 /* Fixed endpoint */ -#define UBTBCMFW_BULK_OUT_EP 0x02 /* Fixed endpoint */ -#define UBTBCMFW_INTR_IN UE_GET_ADDR(UBTBCMFW_INTR_IN_EP) -#define UBTBCMFW_BULK_OUT UE_GET_ADDR(UBTBCMFW_BULK_OUT_EP) - -struct ubtbcmfw_softc { - device_t sc_dev; /* base device */ - usbd_device_handle sc_udev; /* USB device handle */ - struct cdev *sc_ctrl_dev; /* control device */ - struct cdev *sc_intr_in_dev; /* interrupt device */ - struct cdev *sc_bulk_out_dev; /* bulk device */ - usbd_pipe_handle sc_intr_in_pipe; /* interrupt pipe */ - usbd_pipe_handle sc_bulk_out_pipe; /* bulk out pipe */ - int sc_flags; -#define UBTBCMFW_CTRL_DEV (1 << 0) -#define UBTBCMFW_INTR_IN_DEV (1 << 1) -#define UBTBCMFW_BULK_OUT_DEV (1 << 2) - int sc_refcnt; - int sc_dying; -}; - -typedef struct ubtbcmfw_softc *ubtbcmfw_softc_p; - -/* - * Device methods - */ - -#define UBTBCMFW_BSIZE 1024 - -static d_open_t ubtbcmfw_open; -static d_close_t ubtbcmfw_close; -static d_read_t ubtbcmfw_read; -static d_write_t ubtbcmfw_write; -static d_ioctl_t ubtbcmfw_ioctl; -static d_poll_t ubtbcmfw_poll; - -static struct cdevsw ubtbcmfw_cdevsw = { - .d_version = D_VERSION, - .d_flags = D_NEEDGIANT, - .d_open = ubtbcmfw_open, - .d_close = ubtbcmfw_close, - .d_read = ubtbcmfw_read, - .d_write = ubtbcmfw_write, - .d_ioctl = ubtbcmfw_ioctl, - .d_poll = ubtbcmfw_poll, - .d_name = "ubtbcmfw", -}; - -/* - * Module - */ - -static device_probe_t ubtbcmfw_match; -static device_attach_t ubtbcmfw_attach; -static device_detach_t ubtbcmfw_detach; - -static device_method_t ubtbcmfw_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, ubtbcmfw_match), - DEVMETHOD(device_attach, ubtbcmfw_attach), - DEVMETHOD(device_detach, ubtbcmfw_detach), - - { 0, 0 } -}; - -static driver_t ubtbcmfw_driver = { - "ubtbcmfw", - ubtbcmfw_methods, - sizeof(struct ubtbcmfw_softc) -}; - -static devclass_t ubtbcmfw_devclass; - -MODULE_DEPEND(ubtbcmfw, usb, 1, 1, 1); -DRIVER_MODULE(ubtbcmfw, uhub, ubtbcmfw_driver, ubtbcmfw_devclass, - usbd_driver_load, 0); - -/* - * Probe for a USB Bluetooth device - */ - -static int -ubtbcmfw_match(device_t self) -{ -#define USB_PRODUCT_BROADCOM_BCM2033NF 0x2033 - struct usb_attach_arg *uaa = device_get_ivars(self); - - if (uaa->iface != NULL) - return (UMATCH_NONE); - - /* Match the boot device. */ - if (uaa->vendor == USB_VENDOR_BROADCOM && - uaa->product == USB_PRODUCT_BROADCOM_BCM2033NF) - return (UMATCH_VENDOR_PRODUCT); - - return (UMATCH_NONE); -} - -/* - * Attach the device - */ - -static int -ubtbcmfw_attach(device_t self) -{ - struct ubtbcmfw_softc *sc = device_get_softc(self); - struct usb_attach_arg *uaa = device_get_ivars(self); - usbd_interface_handle iface; - usbd_status err; - - sc->sc_dev = self; - sc->sc_udev = uaa->device; - - sc->sc_ctrl_dev = sc->sc_intr_in_dev = sc->sc_bulk_out_dev = NULL; - sc->sc_intr_in_pipe = sc->sc_bulk_out_pipe = NULL; - sc->sc_flags = sc->sc_refcnt = sc->sc_dying = 0; - - err = usbd_set_config_no(sc->sc_udev, UBTBCMFW_CONFIG_NO, 1); - if (err) { - printf("%s: setting config no failed. %s\n", - device_get_nameunit(sc->sc_dev), usbd_errstr(err)); - goto bad; - } - - err = usbd_device2interface_handle(sc->sc_udev, UBTBCMFW_IFACE_IDX, - &iface); - if (err) { - printf("%s: getting interface handle failed. %s\n", - device_get_nameunit(sc->sc_dev), usbd_errstr(err)); - goto bad; - } - - /* Will be used as a bulk pipe */ - err = usbd_open_pipe(iface, UBTBCMFW_INTR_IN_EP, 0, - &sc->sc_intr_in_pipe); - if (err) { - printf("%s: open intr in failed. %s\n", - device_get_nameunit(sc->sc_dev), usbd_errstr(err)); - goto bad; - } - - err = usbd_open_pipe(iface, UBTBCMFW_BULK_OUT_EP, 0, - &sc->sc_bulk_out_pipe); - if (err) { - printf("%s: open bulk out failed. %s\n", - device_get_nameunit(sc->sc_dev), usbd_errstr(err)); - goto bad; - } - - /* Create device nodes */ - sc->sc_ctrl_dev = make_dev(&ubtbcmfw_cdevsw, - 0, UID_ROOT, GID_OPERATOR, 0644, - "%s", device_get_nameunit(sc->sc_dev)); - sc->sc_ctrl_dev->si_drv1 = sc; - - sc->sc_intr_in_dev = make_dev(&ubtbcmfw_cdevsw, - UBTBCMFW_INTR_IN, UID_ROOT, GID_OPERATOR, 0644, - "%s.%d", device_get_nameunit(sc->sc_dev), UBTBCMFW_INTR_IN); - sc->sc_intr_in_dev->si_drv1 = sc; - - sc->sc_bulk_out_dev = make_dev(&ubtbcmfw_cdevsw, - UBTBCMFW_BULK_OUT, UID_ROOT, GID_OPERATOR, 0644, - "%s.%d", device_get_nameunit(sc->sc_dev), UBTBCMFW_BULK_OUT); - sc->sc_bulk_out_dev->si_drv1 = sc; - - return 0; -bad: - ubtbcmfw_detach(self); - return ENXIO; -} - -/* - * Detach the device - */ - -static int -ubtbcmfw_detach(device_t self) -{ - struct ubtbcmfw_softc *sc = device_get_softc(self); - - sc->sc_dying = 1; - if (-- sc->sc_refcnt >= 0) { - if (sc->sc_intr_in_pipe != NULL) - usbd_abort_pipe(sc->sc_intr_in_pipe); - - if (sc->sc_bulk_out_pipe != NULL) - usbd_abort_pipe(sc->sc_bulk_out_pipe); - - usb_detach_wait(sc->sc_dev); - } - - /* Destroy device nodes */ - if (sc->sc_bulk_out_dev != NULL) { - destroy_dev(sc->sc_bulk_out_dev); - sc->sc_bulk_out_dev = NULL; - } - - if (sc->sc_intr_in_dev != NULL) { - destroy_dev(sc->sc_intr_in_dev); - sc->sc_intr_in_dev = NULL; - } - - if (sc->sc_ctrl_dev != NULL) { - destroy_dev(sc->sc_ctrl_dev); - sc->sc_ctrl_dev = NULL; - } - - /* Close pipes */ - if (sc->sc_intr_in_pipe != NULL) { - usbd_close_pipe(sc->sc_intr_in_pipe); - sc->sc_intr_in_pipe = NULL; - } - - if (sc->sc_bulk_out_pipe != NULL) { - usbd_close_pipe(sc->sc_bulk_out_pipe); - sc->sc_intr_in_pipe = NULL; - } - - return (0); -} - -/* - * Open endpoint device - * XXX FIXME softc locking - */ - -static int -ubtbcmfw_open(struct cdev *dev, int flag, int mode, struct thread *p) -{ - ubtbcmfw_softc_p sc = dev->si_drv1; - int error = 0; - - if (sc->sc_dying) - return (ENXIO); - - switch (dev2unit(dev)) { - case USB_CONTROL_ENDPOINT: - if (!(sc->sc_flags & UBTBCMFW_CTRL_DEV)) - sc->sc_flags |= UBTBCMFW_CTRL_DEV; - else - error = EBUSY; - break; - - case UBTBCMFW_INTR_IN: - if (!(sc->sc_flags & UBTBCMFW_INTR_IN_DEV)) { - if (sc->sc_intr_in_pipe != NULL) - sc->sc_flags |= UBTBCMFW_INTR_IN_DEV; - else - error = ENXIO; - } else - error = EBUSY; - break; - - case UBTBCMFW_BULK_OUT: - if (!(sc->sc_flags & UBTBCMFW_BULK_OUT_DEV)) { - if (sc->sc_bulk_out_pipe != NULL) - sc->sc_flags |= UBTBCMFW_BULK_OUT_DEV; - else - error = ENXIO; - } else - error = EBUSY; - break; - - default: - error = ENXIO; - break; - } - - return (error); -} - -/* - * Close endpoint device - * XXX FIXME softc locking - */ - -static int -ubtbcmfw_close(struct cdev *dev, int flag, int mode, struct thread *p) -{ - ubtbcmfw_softc_p sc = dev->si_drv1; - - switch (dev2unit(dev)) { - case USB_CONTROL_ENDPOINT: - sc->sc_flags &= ~UBTBCMFW_CTRL_DEV; - break; - - case UBTBCMFW_INTR_IN: - if (sc->sc_intr_in_pipe != NULL) - usbd_abort_pipe(sc->sc_intr_in_pipe); - - sc->sc_flags &= ~UBTBCMFW_INTR_IN_DEV; - break; - - case UBTBCMFW_BULK_OUT: - if (sc->sc_bulk_out_pipe != NULL) - usbd_abort_pipe(sc->sc_bulk_out_pipe); - - sc->sc_flags &= ~UBTBCMFW_BULK_OUT_DEV; - break; - } - - return (0); -} - -/* - * Read from the endpoint device - * XXX FIXME softc locking - */ - -static int -ubtbcmfw_read(struct cdev *dev, struct uio *uio, int flag) -{ - ubtbcmfw_softc_p sc = dev->si_drv1; - u_int8_t buf[UBTBCMFW_BSIZE]; - usbd_xfer_handle xfer; - usbd_status err; - int n, tn, error = 0; - - if (sc->sc_dying) - return (ENXIO); - - if (dev2unit(dev) != UBTBCMFW_INTR_IN) - return (EOPNOTSUPP); - if (sc->sc_intr_in_pipe == NULL) - return (ENXIO); - - xfer = usbd_alloc_xfer(sc->sc_udev); - if (xfer == NULL) - return (ENOMEM); - - sc->sc_refcnt ++; - - while ((n = min(sizeof(buf), uio->uio_resid)) != 0) { - tn = n; - err = usbd_bulk_transfer(xfer, sc->sc_intr_in_pipe, - USBD_SHORT_XFER_OK, USBD_DEFAULT_TIMEOUT, - buf, &tn, "bcmrd"); - switch (err) { - case USBD_NORMAL_COMPLETION: - error = uiomove(buf, tn, uio); - break; - - case USBD_INTERRUPTED: - error = EINTR; - break; - - case USBD_TIMEOUT: - error = ETIMEDOUT; - break; - - default: - error = EIO; - break; - } - - if (error != 0 || tn < n) - break; - } - - usbd_free_xfer(xfer); - - if (-- sc->sc_refcnt < 0) - usb_detach_wakeup(sc->sc_dev); - - return (error); -} - -/* - * Write into the endpoint device - * XXX FIXME softc locking - */ - -static int -ubtbcmfw_write(struct cdev *dev, struct uio *uio, int flag) -{ - ubtbcmfw_softc_p sc = dev->si_drv1; - u_int8_t buf[UBTBCMFW_BSIZE]; - usbd_xfer_handle xfer; - usbd_status err; - int n, error = 0; - - if (sc->sc_dying) - return (ENXIO); - - if (dev2unit(dev) != UBTBCMFW_BULK_OUT) - return (EOPNOTSUPP); - if (sc->sc_bulk_out_pipe == NULL) - return (ENXIO); - - xfer = usbd_alloc_xfer(sc->sc_udev); - if (xfer == NULL) - return (ENOMEM); - - sc->sc_refcnt ++; - - while ((n = min(sizeof(buf), uio->uio_resid)) != 0) { - error = uiomove(buf, n, uio); - if (error != 0) - break; - - err = usbd_bulk_transfer(xfer, sc->sc_bulk_out_pipe, - 0, USBD_DEFAULT_TIMEOUT, buf, &n, "bcmwr"); - switch (err) { - case USBD_NORMAL_COMPLETION: - break; - - case USBD_INTERRUPTED: - error = EINTR; - break; - - case USBD_TIMEOUT: - error = ETIMEDOUT; - break; - - default: - error = EIO; - break; - } - - if (error != 0) - break; - } - - usbd_free_xfer(xfer); - - if (-- sc->sc_refcnt < 0) - usb_detach_wakeup(sc->sc_dev); - - return (error); -} - -/* - * Process ioctl on the endpoint device - * XXX FIXME softc locking - */ - -static int -ubtbcmfw_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, - struct thread *p) -{ - ubtbcmfw_softc_p sc = dev->si_drv1; - int error = 0; - - if (sc->sc_dying) - return (ENXIO); - - if (dev2unit(dev) != USB_CONTROL_ENDPOINT) - return (EOPNOTSUPP); - - sc->sc_refcnt ++; - - switch (cmd) { - case USB_GET_DEVICE_DESC: - *(usb_device_descriptor_t *) data = - *usbd_get_device_descriptor(sc->sc_udev); - break; - - default: - error = EINVAL; - break; - } - - if (-- sc->sc_refcnt < 0) - usb_detach_wakeup(sc->sc_dev); - - return (error); -} - -/* - * Poll the endpoint device - * XXX FIXME softc locking - */ - -static int -ubtbcmfw_poll(struct cdev *dev, int events, struct thread *p) -{ - ubtbcmfw_softc_p sc = dev->si_drv1; - int revents = 0; - - switch (dev2unit(dev)) { - case UBTBCMFW_INTR_IN: - if (sc->sc_intr_in_pipe != NULL) - revents |= events & (POLLIN | POLLRDNORM); - else - revents = ENXIO; - break; - - case UBTBCMFW_BULK_OUT: - if (sc->sc_bulk_out_pipe != NULL) - revents |= events & (POLLOUT | POLLWRNORM); - else - revents = ENXIO; - break; - - default: - revents = EOPNOTSUPP; - break; - } - - return (revents); -} |