summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorGordon Willem Klok <gwk@cvs.openbsd.org>2007-05-30 12:15:03 +0000
committerGordon Willem Klok <gwk@cvs.openbsd.org>2007-05-30 12:15:03 +0000
commit8364605cc796380ea2c5bb67ed7f97f7bd27c56d (patch)
tree5244f0ec59f1b53aaacf176f9027bddc9f9a896f /sys/dev
parent6ba0d1db64d5ba6d787cfdc1000d781b4a9ffa1d (diff)
Drop if_ubt.c originally from freebsd and replace with ubt.c from
netbsd that will work with the new netbt code. ok uwe
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/usb/if_ubt.c1756
-rw-r--r--sys/dev/usb/if_ubtreg.h207
-rw-r--r--sys/dev/usb/ubt.c1508
3 files changed, 1508 insertions, 1963 deletions
diff --git a/sys/dev/usb/if_ubt.c b/sys/dev/usb/if_ubt.c
deleted file mode 100644
index 8ce0ed58a08..00000000000
--- a/sys/dev/usb/if_ubt.c
+++ /dev/null
@@ -1,1756 +0,0 @@
-/* $OpenBSD: if_ubt.c,v 1.12 2007/05/28 15:48:02 fkr Exp $ */
-
-/*
- * 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: if_ubt.c,v 1.12 2007/05/28 15:48:02 fkr Exp $
- * $FreeBSD: src/sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c,v 1.20 2004/10/12 23:33:46 emax Exp $
- */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/conf.h>
-#include <sys/device.h>
-#include <sys/endian.h>
-#include <sys/fcntl.h>
-#include <sys/filio.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
-#include <sys/poll.h>
-#include <sys/uio.h>
-#include <sys/socket.h>
-
-#include <machine/bus.h>
-
-#include <net/if.h>
-#include <net/if_types.h>
-
-#include <netbt/bluetooth.h>
-#include <netbt/hci.h>
-#include <netbt/l2cap.h>
-#include <netbt/bt.h>
-#include <netbt/hci_var.h>
-
-#include <dev/usb/usb.h>
-#include <dev/usb/usbdi.h>
-#include <dev/usb/usbdi_util.h>
-#include <dev/usb/usbdivar.h>
-#include <dev/usb/usbdevs.h>
-
-#include <dev/usb/if_ubtreg.h>
-
-USB_DECLARE_DRIVER_CLASS(ubt, DV_IFNET);
-
-Static usbd_status ubt_request_start(struct ubt_softc *);
-Static void ubt_request_complete(usbd_xfer_handle,
- usbd_private_handle, usbd_status);
-
-Static usbd_status ubt_intr_start(struct ubt_softc *);
-Static void ubt_intr_complete(usbd_xfer_handle,
- usbd_private_handle, usbd_status);
-
-Static usbd_status ubt_bulk_in_start(struct ubt_softc *);
-Static void ubt_bulk_in_complete(usbd_xfer_handle,
- usbd_private_handle, usbd_status);
-
-Static usbd_status ubt_bulk_out_start(struct ubt_softc *);
-Static void ubt_bulk_out_complete(usbd_xfer_handle,
- usbd_private_handle, usbd_status);
-
-Static usbd_status ubt_isoc_in_start(struct ubt_softc *);
-Static void ubt_isoc_in_complete(usbd_xfer_handle,
- usbd_private_handle, usbd_status);
-
-Static usbd_status ubt_isoc_out_start(struct ubt_softc *);
-Static void ubt_isoc_out_complete(usbd_xfer_handle,
- usbd_private_handle, usbd_status);
-
-Static void ubt_reset(struct ubt_softc *);
-Static void ubt_stop(struct ubt_softc *);
-
-Static int ubt_rcvdata(struct ubt_softc *, struct mbuf *);
-
-Static void ubt_if_start(struct ifnet *);
-Static int ubt_if_ioctl(struct ifnet *, u_long, caddr_t);
-Static int ubt_if_init(struct ifnet *);
-Static void ubt_if_watchdog(struct ifnet *);
-
-int
-ubt_match(struct device *parent, void *match, void *aux)
-{
-#ifdef notyet
- /*
- * If for some reason device should not be attached then put
- * VendorID/ProductID pair into the list below. Currently I
- * do not know of any such devices. 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[] = {
- };
-#endif
-
- /*
- * 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.
- */
-
- Static struct usb_devno const ubt_broken_devices[] = {
- { USB_VENDOR_CSR, USB_PRODUCT_CSR_BLUECORE },
- { USB_VENDOR_MSI, USB_PRODUCT_MSI_BLUETOOTH },
- { USB_VENDOR_MSI, USB_PRODUCT_MSI_BLUETOOTH_2 }
- };
-
- struct usb_attach_arg *uaa = aux;
- usb_device_descriptor_t *dd = usbd_get_device_descriptor(uaa->device);
-
- if (uaa->iface == NULL)
- return (UMATCH_NONE);
-#ifdef notyet
- if (usb_lookup(ubt_ignored_devices, uaa->vendor, uaa->product))
- return (UMATCH_NONE);
-#endif
-
- 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);
-}
-
-void
-ubt_attach(struct device *parent, struct device *self, void *aux)
-{
- struct ubt_softc *sc = (struct ubt_softc *)self;
- struct usb_attach_arg *uaa = aux;
- usb_config_descriptor_t *cd = NULL;
- usb_interface_descriptor_t *id = NULL;
- usb_endpoint_descriptor_t *ed = NULL;
- char *devinfop;
- usbd_status error;
- int i, ai, alt_no, isoc_in, isoc_out,
- isoc_isize, isoc_osize;
- struct ifnet *ifp = &sc->sc_if;
-
- /* Get USB device info */
- sc->sc_udev = uaa->device;
-
- devinfop = usbd_devinfo_alloc(sc->sc_udev, 0);
- printf("\n%s: %s\n", USBDEVNAME(sc->sc_dev), devinfop);
- usbd_devinfo_free(devinfop);
-
- /*
- * 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_ep = -1;
- sc->sc_isoc_in_pipe = NULL;
- sc->sc_isoc_in_xfer = NULL;
-
- /* Isoc-out pipe */
- sc->sc_isoc_out_ep = -1;
- sc->sc_isoc_out_pipe = NULL;
- sc->sc_isoc_out_xfer = NULL;
- sc->sc_isoc_size = -1;
- NG_BT_MBUFQ_INIT(&sc->sc_scoq, UBT_DEFAULT_QLEN);
-
- /*
- * 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", USBDEVNAME(sc->sc_dev),
- usbd_errstr(error), error, sc->sc_iface0);
- return;
- }
-
- id = usbd_get_interface_descriptor(sc->sc_iface0);
- if (id == NULL) {
- printf("%s: Could not get interface 0 descriptor\n",
- USBDEVNAME(sc->sc_dev));
- return;
- }
-
- 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", USBDEVNAME(sc->sc_dev),
- i);
- return;
- }
-
- 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",
- USBDEVNAME(sc->sc_dev));
- return;
- }
- if (sc->sc_bulk_in_ep == -1) {
- printf("%s: Could not detect bulk-in endpoint\n",
- USBDEVNAME(sc->sc_dev));
- return;
- }
- if (sc->sc_bulk_out_ep == -1) {
- printf("%s: Could not detect bulk-out endpoint\n",
- USBDEVNAME(sc->sc_dev));
- return;
- }
-
- printf("%s: Interface 0 endpoints: interrupt=%#x, bulk-in=%#x, " \
- "bulk-out=%#x\n", USBDEVNAME(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",
- USBDEVNAME(sc->sc_dev));
- return;
- }
-
- 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", USBDEVNAME(sc->sc_dev),
- usbd_errstr(error), error, sc->sc_iface1);
- return;
- }
-
- id = usbd_get_interface_descriptor(sc->sc_iface1);
- if (id == NULL) {
- printf("%s: Could not get interface 1 descriptor\n",
- USBDEVNAME(sc->sc_dev));
- return;
- }
-
- /*
- * 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",
- USBDEVNAME(sc->sc_dev), ai, usbd_errstr(error),
- error);
- return;
- }
- id = usbd_get_interface_descriptor(sc->sc_iface1);
- if (id == NULL) {
- printf("%s: Could not get interface 1 descriptor for " \
- "alternate configuration %d\n",
- USBDEVNAME(sc->sc_dev), ai);
- return;
- }
-
- 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",
- USBDEVNAME(sc->sc_dev), ai, i);
- return;
- }
-
- 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",
- USBDEVNAME(sc->sc_dev));
- return;
- }
- if (sc->sc_isoc_out_ep == -1) {
- printf("%s: Could not detect isoc-out endpoint\n",
- USBDEVNAME(sc->sc_dev));
- return;
- }
- if (sc->sc_isoc_size <= 0) {
- printf("%s: Invalid isoc. packet size=%d\n",
- USBDEVNAME(sc->sc_dev), sc->sc_isoc_size);
- return;
- }
-
- 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", USBDEVNAME(sc->sc_dev),
- alt_no, usbd_errstr(error), error);
- return;
- }
-
- /* 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",
- USBDEVNAME(sc->sc_dev));
- return;
- }
- 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",
- USBDEVNAME(sc->sc_dev));
- return;
- }
-
- 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",
- USBDEVNAME(sc->sc_dev));
- return;
- }
- sc->sc_intr_buffer = usbd_alloc_buffer(sc->sc_intr_xfer,
- UBT_INTR_BUFFER_SIZE);
- if (sc->sc_intr_buffer == NULL) {
- printf("%s: Could not allocate interrupt buffer\n",
- USBDEVNAME(sc->sc_dev));
- return;
- }
-
- 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",
- USBDEVNAME(sc->sc_dev));
- return;
- }
- sc->sc_bulk_in_buffer = usbd_alloc_buffer(sc->sc_bulk_in_xfer,
- UBT_BULK_BUFFER_SIZE);
- if (sc->sc_bulk_in_buffer == NULL) {
- printf("%s: Could not allocate bulk-in buffer\n",
- USBDEVNAME(sc->sc_dev));
- return;
- }
-
- 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",
- USBDEVNAME(sc->sc_dev));
- return;
- }
- 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",
- USBDEVNAME(sc->sc_dev));
- return;
- }
-
- /*
- * Allocate buffers for isoc. transfers
- */
-
- sc->sc_isoc_nframes = (UBT_ISOC_BUFFER_SIZE / sc->sc_isoc_size) + 1;
-
- sc->sc_isoc_in_xfer = usbd_alloc_xfer(sc->sc_udev);
- if (sc->sc_isoc_in_xfer == NULL) {
- printf("%s: Could not allocate isoc-in xfer handle\n",
- USBDEVNAME(sc->sc_dev));
- return;
- }
- sc->sc_isoc_in_buffer = usbd_alloc_buffer(sc->sc_isoc_in_xfer,
- sc->sc_isoc_nframes * sc->sc_isoc_size);
- if (sc->sc_isoc_in_buffer == NULL) {
- printf("%s: Could not allocate isoc-in buffer\n",
- USBDEVNAME(sc->sc_dev));
- return;
- }
- sc->sc_isoc_in_frlen = malloc(sizeof(u_int16_t) * sc->sc_isoc_nframes,
- M_USBDEV, M_NOWAIT);
- if (sc->sc_isoc_in_frlen == NULL) {
- printf("%s: Could not allocate isoc-in frame sizes buffer\n",
- USBDEVNAME(sc->sc_dev));
- return;
- }
-
- sc->sc_isoc_out_xfer = usbd_alloc_xfer(sc->sc_udev);
- if (sc->sc_isoc_out_xfer == NULL) {
- printf("%s: Could not allocate isoc-out xfer handle\n",
- USBDEVNAME(sc->sc_dev));
- return;
- }
- sc->sc_isoc_out_buffer = usbd_alloc_buffer(sc->sc_isoc_out_xfer,
- sc->sc_isoc_nframes * sc->sc_isoc_size);
- if (sc->sc_isoc_out_buffer == NULL) {
- printf("%s: Could not allocate isoc-out buffer\n",
- USBDEVNAME(sc->sc_dev));
- return;
- }
- sc->sc_isoc_out_frlen = malloc(sizeof(u_int16_t) * sc->sc_isoc_nframes,
- M_USBDEV, M_NOWAIT);
- if (sc->sc_isoc_out_frlen == NULL) {
- printf("%s: Could not allocate isoc-out frame sizes buffer\n",
- USBDEVNAME(sc->sc_dev));
- return;
- }
-
- printf("%s: Interface 1 (alt.config %d) endpoints: isoc-in=%#x, " \
- "isoc-out=%#x; wMaxPacketSize=%d; nframes=%d, buffer size=%d\n",
- USBDEVNAME(sc->sc_dev), alt_no, sc->sc_isoc_in_ep,
- sc->sc_isoc_out_ep, sc->sc_isoc_size, sc->sc_isoc_nframes,
- (sc->sc_isoc_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__, USBDEVNAME(sc->sc_dev), usbd_errstr(error),
- error);
- return;
- }
-
- /* 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__, USBDEVNAME(sc->sc_dev), usbd_errstr(error),
- error);
- return;
- }
-
- /* 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__, USBDEVNAME(sc->sc_dev), usbd_errstr(error),
- error);
- return;
- }
-
-#if __broken__ /* XXX FIXME */
- /* 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__, USBDEVNAME(sc->sc_dev), usbd_errstr(error),
- error);
- return;
- }
-
- /* 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__, USBDEVNAME(sc->sc_dev), usbd_errstr(error),
- error);
- return;
- }
-#endif /* __broken__ */
-
- /* Start intr transfer */
- error = ubt_intr_start(sc);
- if (error != USBD_NORMAL_COMPLETION) {
- NG_UBT_ALERT(
-"%s: %s - Could not start interrupt transfer. %s (%d)\n",
- __func__, USBDEVNAME(sc->sc_dev), usbd_errstr(error),
- error);
- return;
- }
-
- /* Start bulk-in transfer */
- error = ubt_bulk_in_start(sc);
- if (error != USBD_NORMAL_COMPLETION) {
- NG_UBT_ALERT(
-"%s: %s - Could not start bulk-in transfer. %s (%d)\n",
- __func__, USBDEVNAME(sc->sc_dev), usbd_errstr(error),
- error);
- return;
- }
-
-#if __broken__ /* XXX FIXME */
- /* Start isoc-in transfer */
- error = ubt_isoc_in_start(sc);
- if (error != USBD_NORMAL_COMPLETION) {
- NG_UBT_ALERT(
-"%s: %s - Could not start isoc-in transfer. %s (%d)\n",
- __func__, USBDEVNAME(sc->sc_dev), usbd_errstr(error),
- error);
- return;
- }
-#endif /* __broken__ */
-
- /* Claim all interfaces on the device */
- for (i = 0; i < uaa->nifaces; i++)
- uaa->ifaces[i] = NULL;
-
- /* Attach network interface */
- bzero(ifp, sizeof(*ifp));
- strlcpy(ifp->if_xname, USBDEVNAME(sc->sc_dev), sizeof(ifp->if_xname));
- ifp->if_softc = sc;
- ifp->if_mtu = 65536;
- ifp->if_start = ubt_if_start;
- ifp->if_ioctl = ubt_if_ioctl;
- ifp->if_init = ubt_if_init;
- ifp->if_watchdog = ubt_if_watchdog;
- ifp->if_type = IFT_BLUETOOTH;
- IFQ_SET_READY(&ifp->if_snd);
- if_attach(ifp);
- if_alloc_sadl(ifp);
-
- usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
- USBDEV(sc->sc_dev));
-}
-
-int
-ubt_detach(struct device *self, int flags)
-{
- struct ubt_softc *sc = (struct ubt_softc *)self;
- struct ifnet *ifp = &sc->sc_if;
-
- /* Close pipes */
- if (sc->sc_intr_pipe != NULL) {
- usbd_close_pipe(sc->sc_intr_pipe);
- sc->sc_intr_pipe = NULL;
- }
-
- if (sc->sc_bulk_in_pipe != NULL) {
- usbd_close_pipe(sc->sc_bulk_in_pipe);
- sc->sc_bulk_in_pipe = NULL;
- }
- if (sc->sc_bulk_out_pipe != NULL) {
- usbd_close_pipe(sc->sc_bulk_out_pipe);
- sc->sc_bulk_out_pipe = NULL;
- }
-
- if (sc->sc_isoc_in_pipe != NULL) {
- usbd_close_pipe(sc->sc_isoc_in_pipe);
- sc->sc_isoc_in_pipe = NULL;
- }
- if (sc->sc_isoc_out_pipe != NULL) {
- 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;
- }
-
- if (sc->sc_isoc_in_xfer != NULL) {
- usbd_free_xfer(sc->sc_isoc_in_xfer);
- sc->sc_isoc_in_xfer = NULL;
- }
- if (sc->sc_isoc_out_xfer != NULL) {
- usbd_free_xfer(sc->sc_isoc_out_xfer);
- sc->sc_isoc_out_xfer = NULL;
- }
-
- /* Destroy isoc. frame size buffers */
- if (sc->sc_isoc_in_frlen != NULL) {
- free(sc->sc_isoc_in_frlen, M_USBDEV);
- sc->sc_isoc_in_frlen = NULL;
- }
- if (sc->sc_isoc_out_frlen != NULL) {
- free(sc->sc_isoc_out_frlen, M_USBDEV);
- sc->sc_isoc_out_frlen = NULL;
- }
-
-#if 0
- /* Destroy queues */
- NG_BT_MBUFQ_DRAIN(&sc->sc_cmdq);
- NG_BT_MBUFQ_DRAIN(&sc->sc_aclq);
- NG_BT_MBUFQ_DRAIN(&sc->sc_scoq);
-#endif
-
- if_detach(ifp);
-
- usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
- USBDEV(sc->sc_dev));
-
- return (0);
-}
-
-int
-ubt_activate(device_ptr_t self, enum devact act)
-{
- switch (act) {
- case DVACT_ACTIVATE:
- return (EOPNOTSUPP);
- case DVACT_DEACTIVATE:
- break;
- }
-
- return (0);
-}
-
-/*
- * Start USB control request (HCI command).
- */
-Static usbd_status
-ubt_request_start(struct ubt_softc * 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__, USBDEVNAME(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__, USBDEVNAME(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=%lu, len=%d\n",
- __func__, USBDEVNAME(sc->sc_dev),
- (ulong)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__, USBDEVNAME(sc->sc_dev), req.bmRequestType,
- UGETW(req.wLength));
-
- usbd_setup_default_xfer(
- sc->sc_ctrl_xfer,
- sc->sc_udev,
- (usbd_private_handle) sc,
- USBD_DEFAULT_TIMEOUT, /* XXX */
- &req,
- sc->sc_ctrl_buffer,
- m->m_pkthdr.len,
- USBD_NO_COPY,
- ubt_request_complete);
-
- 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__, USBDEVNAME(sc->sc_dev),
- usbd_errstr(status), status);
-
- 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__, USBDEVNAME(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)
-{
- struct ubt_softc * sc = p;
-
- if (sc == NULL)
- return;
-
- KASSERT((sc->sc_flags & UBT_CMD_XMIT), (
-"%s: %s - No control request is pending\n", __func__, USBDEVNAME(sc->sc_dev)));
-
- sc->sc_flags &= ~UBT_CMD_XMIT;
-
- if (s == USBD_CANCELLED) {
- NG_UBT_INFO(
-"%s: %s - Control request cancelled\n", __func__, USBDEVNAME(sc->sc_dev));
-
- return;
- }
-
- if (s != USBD_NORMAL_COMPLETION) {
- NG_UBT_ERR(
-"%s: %s - Control request failed. %s (%d)\n",
- __func__, USBDEVNAME(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__, USBDEVNAME(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(struct ubt_softc * sc)
-{
- struct mbuf *m = NULL;
- usbd_status status;
-
- KASSERT(!(sc->sc_flags & UBT_EVT_RECV), (
-"%s: %s - Another interrupt request is pending\n",
- __func__, USBDEVNAME(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, u_int8_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->sc_intr_buffer,
- UBT_INTR_BUFFER_SIZE,
- USBD_SHORT_XFER_OK,
- USBD_NO_TIMEOUT,
- ubt_intr_complete);
-
- 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__, USBDEVNAME(sc->sc_dev), usbd_errstr(status),
- status);
-
- NG_FREE_M(m);
-
- return (status);
- }
-
- sc->sc_flags |= UBT_EVT_RECV;
- sc->sc_intr_mbuf = 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)
-{
- struct ubt_softc * sc = p;
- struct mbuf *m = NULL;
- ng_hci_event_pkt_t *hdr = NULL;
- int error = 0;
-
- if (sc == NULL)
- return;
-
- KASSERT((sc->sc_flags & UBT_EVT_RECV), (
-"%s: %s - No interrupt request is pending\n",
- __func__, USBDEVNAME(sc->sc_dev)));
-
- sc->sc_flags &= ~UBT_EVT_RECV;
-
- m = sc->sc_intr_mbuf;
- bcopy(sc->sc_intr_buffer, mtod(m, void *) + m->m_len, h->actlen);
-
- hdr = mtod(m, ng_hci_event_pkt_t *);
-
- if (s == USBD_CANCELLED) {
- NG_UBT_INFO(
-"%s: %s - Interrupt xfer cancelled\n", __func__, USBDEVNAME(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__, USBDEVNAME(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__, USBDEVNAME(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__, USBDEVNAME(sc->sc_dev), m->m_pkthdr.len,
- hdr->length);
-
- NG_UBT_STAT_PCKTS_RECV(sc->sc_stat);
-
-#if 0
- NG_SEND_DATA_ONLY(error, sc->sc_hook, m);
-#endif
- ng_btsocket_hci_raw_node_rcvdata(&sc->sc_if, 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__, USBDEVNAME(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_complete */
-
-/*
- * Start bulk-in USB transfer (ACL data). Must be called when node is locked
- */
-Static usbd_status
-ubt_bulk_in_start(struct ubt_softc * 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__, USBDEVNAME(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, u_int8_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->sc_bulk_in_buffer,
- UBT_BULK_BUFFER_SIZE,
- USBD_SHORT_XFER_OK,
- USBD_NO_TIMEOUT,
- ubt_bulk_in_complete);
-
- 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__, USBDEVNAME(sc->sc_dev), usbd_errstr(status),
- status);
-
- NG_FREE_M(m);
-
- return (status);
- }
-
- sc->sc_flags |= UBT_ACL_RECV;
- sc->sc_bulk_in_mbuf = 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)
-{
- struct ubt_softc * sc = p;
- 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__, USBDEVNAME(sc->sc_dev)));
-
- sc->sc_flags &= ~UBT_ACL_RECV;
-
- m = sc->sc_bulk_in_mbuf;
- bcopy(sc->sc_intr_buffer, mtod(m, void *) + m->m_len, h->actlen);
-
- hdr = mtod(m, ng_hci_acldata_pkt_t *);
-
- if (s == USBD_CANCELLED) {
- NG_UBT_INFO(
-"%s: %s - Bulk-in xfer cancelled, pipe=%p\n",
- __func__, USBDEVNAME(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__, USBDEVNAME(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__, USBDEVNAME(sc->sc_dev), h->actlen);
-
- if (m->m_pkthdr.len < sizeof(*hdr)) {
- NG_FREE_M(m);
- goto done;
- }
-
- len = letoh16(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__, USBDEVNAME(sc->sc_dev), m->m_pkthdr.len, len);
-
- NG_UBT_STAT_PCKTS_RECV(sc->sc_stat);
-
-#if 0
- NG_SEND_DATA_ONLY(len, sc->sc_hook, m);
-#endif
- 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__, USBDEVNAME(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(struct ubt_softc * 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__, USBDEVNAME(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__, USBDEVNAME(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__, USBDEVNAME(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->sc_bulk_out_buffer,
- m->m_pkthdr.len,
- USBD_NO_COPY,
- USBD_DEFAULT_TIMEOUT, /* XXX */
- ubt_bulk_out_complete);
-
- 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__, USBDEVNAME(sc->sc_dev), usbd_errstr(status),
- status);
-
- 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__, USBDEVNAME(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)
-{
- struct ubt_softc * sc = p;
-
- if (sc == NULL)
- return;
-
- KASSERT((sc->sc_flags & UBT_ACL_XMIT), (
-"%s: %s - No bulk-out request is pending\n", __func__, USBDEVNAME(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__, USBDEVNAME(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__, USBDEVNAME(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__, USBDEVNAME(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 Isochronous-in USB transfer. Must be called with node locked
- */
-
-Static usbd_status
-ubt_isoc_in_start(struct ubt_softc * sc)
-{
- usbd_status status;
- int i;
-
- KASSERT(!(sc->sc_flags & UBT_SCO_RECV), (
-"%s: %s - Another isoc-in request is pending\n",
- __func__, USBDEVNAME(sc->sc_dev)));
-
- /* Initialize a isoc-in USB transfer and then schedule it */
- for (i = 0; i < sc->sc_isoc_nframes; i++)
- sc->sc_isoc_in_frlen[i] = sc->sc_isoc_size;
-
- usbd_setup_isoc_xfer(
- sc->sc_isoc_in_xfer,
- sc->sc_isoc_in_pipe,
- (usbd_private_handle) sc,
- sc->sc_isoc_in_frlen,
- sc->sc_isoc_nframes,
- USBD_NO_COPY, /* XXX flags */
- ubt_isoc_in_complete);
-
- status = usbd_transfer(sc->sc_isoc_in_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__, USBDEVNAME(sc->sc_dev),
- usbd_errstr(status), status);
-
- return (status);
- }
-
- sc->sc_flags |= UBT_SCO_RECV;
-
- 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)
-{
- struct ubt_softc * sc = p;
- struct mbuf *m = NULL;
- ng_hci_scodata_pkt_t *hdr = NULL;
- u_int8_t *b = NULL;
- int i;
-
- if (sc == NULL)
- return;
-
- KASSERT((sc->sc_flags & UBT_SCO_RECV), (
-"%s: %s - No isoc-in request is pending\n", __func__, USBDEVNAME(sc->sc_dev)));
-
- sc->sc_flags &= ~UBT_SCO_RECV;
-
-#if 0
- if (sc->sc_hook == NULL || NG_HOOK_NOT_VALID(sc->sc_hook)) {
- NG_UBT_INFO(
-"%s: %s - No upstream hook\n", __func__, USBDEVNAME(sc->sc_dev));
-
- return;
- }
-#endif
-
- if (s == USBD_CANCELLED) {
- NG_UBT_INFO(
-"%s: %s - Isoc-in xfer cancelled, pipe=%p\n",
- __func__, USBDEVNAME(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__, USBDEVNAME(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 */
- }
-
- NG_UBT_STAT_BYTES_RECV(sc->sc_stat, h->actlen);
-
- NG_UBT_INFO(
-"%s: %s - Got %d bytes from isoc-in pipe\n",
- __func__, USBDEVNAME(sc->sc_dev), h->actlen);
-
- /* Copy SCO data frame to mbuf */
- MGETHDR(m, M_DONTWAIT, MT_DATA);
- if (m == NULL) {
- NG_UBT_ALERT(
-"%s: %s - Could not allocate mbuf\n",
- __func__, USBDEVNAME(sc->sc_dev));
-
- NG_UBT_STAT_IERROR(sc->sc_stat);
- goto done;
- }
-
- /* Fix SCO data frame header if required */
- if (!(sc->sc_flags & UBT_HAVE_FRAME_TYPE)) {
- *mtod(m, u_int8_t *) = NG_HCI_SCO_DATA_PKT;
- m->m_pkthdr.len = 1;
- m->m_len = min(MHLEN, h->actlen + 1); /* XXX m_copyback */
- } else {
- m->m_pkthdr.len = 0;
- m->m_len = min(MHLEN, h->actlen); /* XXX m_copyback */
- }
-
- /*
- * XXX FIXME how do we know how many frames we have received?
- * XXX use frlen for now. is that correct?
- */
-
- b = (u_int8_t *) sc->sc_isoc_in_buffer;
-
- for (i = 0; i < sc->sc_isoc_nframes; i++) {
- b += (i * sc->sc_isoc_size);
-
- if (sc->sc_isoc_in_frlen[i] > 0)
- m_copyback(m, m->m_pkthdr.len,
- sc->sc_isoc_in_frlen[i], b);
- }
-
- if (m->m_pkthdr.len < sizeof(*hdr))
- goto done;
-
- hdr = mtod(m, ng_hci_scodata_pkt_t *);
-
- if (hdr->length == m->m_pkthdr.len - sizeof(*hdr)) {
- NG_UBT_INFO(
-"%s: %s - Got complete SCO data frame, pktlen=%d, length=%d\n",
- __func__, USBDEVNAME(sc->sc_dev), m->m_pkthdr.len,
- hdr->length);
-
- NG_UBT_STAT_PCKTS_RECV(sc->sc_stat);
-
-#if 0
- NG_SEND_DATA_ONLY(i, sc->sc_hook, m);
-#endif
- if (i != 0)
- NG_UBT_STAT_IERROR(sc->sc_stat);
- } else {
- NG_UBT_ERR(
-"%s: %s - Invalid SCO frame size, length=%d, pktlen=%d\n",
- __func__, USBDEVNAME(sc->sc_dev), hdr->length,
- m->m_pkthdr.len);
-
- NG_UBT_STAT_IERROR(sc->sc_stat);
- NG_FREE_M(m);
- }
-done:
- ubt_isoc_in_start(sc);
-} /* ubt_isoc_in_complete2 */
-
-/*
- * Start isochronous-out USB transfer. Must be called with node locked
- */
-
-Static usbd_status
-ubt_isoc_out_start(struct ubt_softc * sc)
-{
- struct mbuf *m = NULL;
- u_int8_t *b = NULL;
- int i, len, nframes;
- usbd_status status;
-
- KASSERT(!(sc->sc_flags & UBT_SCO_XMIT), (
-"%s: %s - Another isoc-out request is pending\n",
- __func__, USBDEVNAME(sc->sc_dev)));
-
- NG_BT_MBUFQ_DEQUEUE(&sc->sc_scoq, m);
- if (m == NULL) {
- NG_UBT_INFO(
-"%s: %s - SCO data queue is empty\n", __func__, USBDEVNAME(sc->sc_dev));
-
- return (USBD_NORMAL_COMPLETION);
- }
-
- /* Copy entire SCO frame into USB transfer buffer and start transfer */
- b = (u_int8_t *) sc->sc_isoc_out_buffer;
- nframes = 0;
-
- for (i = 0; i < sc->sc_isoc_nframes; i++) {
- b += (i * sc->sc_isoc_size);
-
- len = min(m->m_pkthdr.len, sc->sc_isoc_size);
- if (len > 0) {
- m_copydata(m, 0, len, b);
- m_adj(m, len);
- nframes ++;
- }
-
- sc->sc_isoc_out_frlen[i] = len;
- }
-
- if (m->m_pkthdr.len > 0)
- panic(
-"%s: %s - SCO data frame is too big, nframes=%d, size=%d, len=%d\n",
- __func__, USBDEVNAME(sc->sc_dev), sc->sc_isoc_nframes,
- sc->sc_isoc_size, m->m_pkthdr.len);
-
- NG_FREE_M(m);
-
- /* Initialize a isoc-out USB transfer and then schedule it */
- usbd_setup_isoc_xfer(
- sc->sc_isoc_out_xfer,
- sc->sc_isoc_out_pipe,
- (usbd_private_handle) sc,
- sc->sc_isoc_out_frlen,
- nframes,
- USBD_NO_COPY,
- ubt_isoc_out_complete);
-
- status = usbd_transfer(sc->sc_isoc_out_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__, USBDEVNAME(sc->sc_dev), usbd_errstr(status),
- status);
-
- NG_BT_MBUFQ_DROP(&sc->sc_scoq);
- 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__, USBDEVNAME(sc->sc_dev), nframes,
- sc->sc_isoc_size);
-
- sc->sc_flags |= UBT_SCO_XMIT;
- status = USBD_NORMAL_COMPLETION;
- }
-
- return (status);
-} /* 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)
-{
- struct ubt_softc * sc = p;
-
- if (sc == NULL)
- return;
-
- KASSERT((sc->sc_flags & UBT_SCO_XMIT), (
-"%s: %s - No isoc-out request is pending\n", __func__, USBDEVNAME(sc->sc_dev)));
-
- sc->sc_flags &= ~UBT_SCO_XMIT;
-
- if (s == USBD_CANCELLED) {
- NG_UBT_INFO(
-"%s: %s - Isoc-out xfer cancelled, pipe=%p\n",
- __func__, USBDEVNAME(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__, USBDEVNAME(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__, USBDEVNAME(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_scoq) > 0)
- ubt_isoc_out_start(sc);
-} /* ubt_isoc_out_complete2 */
-
-/*
- * Abort transfers on all USB pipes
- */
-
-Static void
-ubt_reset(struct ubt_softc * 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);
-
-#if 0
- /* Cleanup queues */
- NG_BT_MBUFQ_DRAIN(&sc->sc_cmdq);
- NG_BT_MBUFQ_DRAIN(&sc->sc_aclq);
- NG_BT_MBUFQ_DRAIN(&sc->sc_scoq);
-#endif
-} /* ubt_reset */
-
-/*
- * Process data
- */
-Static int
-ubt_rcvdata(struct ubt_softc *sc, struct mbuf *m)
-{
- usbd_status (*f)(struct ubt_softc *) = NULL;
- struct ng_bt_mbufq *q = NULL;
- int b, error = 0;
-
- if (sc == NULL) {
- error = EHOSTDOWN;
- goto done;
- }
-
-#if 0
- if (hook != sc->sc_hook) {
- error = EINVAL;
- goto done;
- }
-#endif
-
-#if 0
- /* Deatch mbuf and get HCI frame type */
- NGI_GET_M(item, m);
-#endif
-
- /* Process HCI frame */
- switch (*mtod(m, u_int8_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;
-
-#if __broken__ /* XXX FIXME */
- case NG_HCI_SCO_DATA_PKT:
- f = ubt_isoc_out_start;
- q = &sc->sc_scoq;
- b = UBT_SCO_XMIT;
- break;
-#endif /* __broken__ */
-
- default:
- NG_UBT_ERR(
-"%s: %s - Dropping unknown/unsupported HCI frame, type=%d, pktlen=%d\n",
- __func__, USBDEVNAME(sc->sc_dev), *mtod(m, u_int8_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(u_int8_t));
-
- if (NG_BT_MBUFQ_FULL(q)) {
- NG_UBT_ERR(
-"%s: %s - Dropping HCI frame %#x, len=%d. Queue full\n",
- __func__, USBDEVNAME(sc->sc_dev),
- *mtod(m, u_int8_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:
-#if 0
- NG_FREE_ITEM(item);
-#endif
-
- return (error);
-} /* ubt_rcvdata */
-
-void
-ubt_stop(struct ubt_softc *sc)
-{
- /* nothing yet */
- return;
-}
-
-void
-ubt_if_start(struct ifnet *ifp)
-{
- struct ubt_softc *sc = ifp->if_softc;
- struct mbuf *m0;
-
- for (;;) {
- IFQ_POLL(&ifp->if_snd, m0);
- if (m0 == NULL)
- break;
-
- IFQ_DEQUEUE(&ifp->if_snd, m0);
- ubt_rcvdata(sc, m0);
- }
-}
-
-int
-ubt_if_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
-{
- struct ubt_softc *sc = ifp->if_softc;
- struct ifreq *ifr = (struct ifreq *)data;
- int s;
- int error = 0;
-
- s = splnet();
- switch(command) {
- case SIOCSIFADDR:
- ifp->if_flags |= IFF_UP;
- ubt_if_init(ifp);
- break;
- case SIOCSIFMTU:
- if (ifr->ifr_mtu > 65536)
- error = EINVAL;
- ifp->if_mtu = ifr->ifr_mtu;
- break;
- case SIOCSIFFLAGS:
- if (ifp->if_flags & IFF_UP) {
- ubt_if_init(ifp);
- } else {
- if (ifp->if_flags & IFF_RUNNING)
- ubt_stop(sc);
- }
- error = 0;
- break;
- default:
- error = EINVAL;
- break;
- }
- splx(s);
-
- return(error);
-}
-
-int
-ubt_if_init(struct ifnet *ifp)
-{
- /* nothing yet */
- return (0);
-}
-
-void
-ubt_if_watchdog(struct ifnet *ifp)
-{
- /* nothing yet */
- return;
-}
diff --git a/sys/dev/usb/if_ubtreg.h b/sys/dev/usb/if_ubtreg.h
deleted file mode 100644
index f4d3bf0105a..00000000000
--- a/sys/dev/usb/if_ubtreg.h
+++ /dev/null
@@ -1,207 +0,0 @@
-/* $OpenBSD: if_ubtreg.h,v 1.1 2005/01/14 12:21:02 grange Exp $ */
-
-/*
- * 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: if_ubtreg.h,v 1.1 2005/01/14 12:21:02 grange Exp $
- * $FreeBSD: src/sys/netgraph/bluetooth/drivers/ubt/ng_ubt_var.h,v 1.4 2004/10/12 23:33:46 emax Exp $
- */
-
-#ifndef _NG_UBT_VAR_H_
-#define _NG_UBT_VAR_H_
-
-/**************************************************************************
- **************************************************************************
- ** Netgraph node hook name, type name and type cookie and commands
- **************************************************************************
- **************************************************************************/
-
-#define NG_UBT_NODE_TYPE "ubt"
-#define NG_UBT_HOOK "hook"
-
-#define NGM_UBT_COOKIE 1021837971
-
-/* Debug levels */
-#define NG_UBT_ALERT_LEVEL 1
-#define NG_UBT_ERR_LEVEL 2
-#define NG_UBT_WARN_LEVEL 3
-#define NG_UBT_INFO_LEVEL 4
-
-/**************************************************************************
- **************************************************************************
- ** UBT node command/event parameters
- **************************************************************************
- **************************************************************************/
-
-#define NGM_UBT_NODE_SET_DEBUG 1 /* set debug level */
-#define NGM_UBT_NODE_GET_DEBUG 2 /* get debug level */
-typedef u_int16_t ng_ubt_node_debug_ep;
-
-#define NGM_UBT_NODE_SET_QLEN 3 /* set queue length */
-#define NGM_UBT_NODE_GET_QLEN 4 /* get queue length */
-typedef struct {
- int32_t queue; /* queue index */
-#define NGM_UBT_NODE_QUEUE_CMD 1 /* commands */
-#define NGM_UBT_NODE_QUEUE_ACL 2 /* ACL data */
-#define NGM_UBT_NODE_QUEUE_SCO 3 /* SCO data */
-
- int32_t qlen; /* queue length */
-} ng_ubt_node_qlen_ep;
-
-#define NGM_UBT_NODE_GET_STAT 5 /* get statistic */
-typedef struct {
- u_int32_t pckts_recv; /* # of packets received */
- u_int32_t bytes_recv; /* # of bytes received */
- u_int32_t pckts_sent; /* # of packets sent */
- u_int32_t bytes_sent; /* # of bytes sent */
- u_int32_t oerrors; /* # of output errors */
- u_int32_t ierrors; /* # of input errors */
-} ng_ubt_node_stat_ep;
-
-#define NGM_UBT_NODE_RESET_STAT 6 /* reset statistic */
-
-#define NGM_UBT_NODE_DEV_NODES 7 /* on/off device interface */
-typedef u_int16_t ng_ubt_node_dev_nodes_ep;
-
-/* 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__, USBDEVNAME(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
-
-/* USB device softc structure */
-struct ubt_softc {
- USBBASEDEVICE sc_dev; /* pointer back to USB device */
-
- /* State */
- ng_ubt_node_debug_ep sc_debug; /* debug level */
- u_int32_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 */
-#define UBT_CTRL_DEV (1 << 7) /* ctrl device is open */
-#define UBT_INTR_DEV (1 << 8) /* intr device is open */
-#define UBT_BULK_DEV (1 << 9) /* bulk device is open */
-#define UBT_ANY_DEV (UBT_CTRL_DEV|UBT_INTR_DEV|UBT_BULK_DEV)
-
- 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 */
- 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_mbuf; /* interrupt mbuf */
- void *sc_intr_buffer; /* interrupt buffer */
-#define UBT_INTR_BUFFER_SIZE MCLBYTES
-
- /* 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_mbuf; /* bulk-in mbuf */
- void *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) */
- int sc_isoc_in_ep; /* isoc-in endpoint */
- usbd_pipe_handle sc_isoc_in_pipe; /* isoc-in pipe */
- usbd_xfer_handle sc_isoc_in_xfer; /* isoc-in xfer */
- void *sc_isoc_in_buffer; /* isoc-in buffer */
- u_int16_t *sc_isoc_in_frlen; /* isoc-in. frame length */
-
- /* Isoc. out pipe (ACL data) */
- int sc_isoc_out_ep; /* isoc-out endpoint */
- usbd_pipe_handle sc_isoc_out_pipe; /* isoc-out pipe */
- usbd_xfer_handle sc_isoc_out_xfer; /* isoc-out xfer */
- void *sc_isoc_out_buffer; /* isoc-in buffer */
- u_int16_t *sc_isoc_out_frlen; /* isoc-out. frame length */
- struct ng_bt_mbufq sc_scoq; /* SCO data queue */
-
- int sc_isoc_size; /* max. size of isoc. packet */
- u_int32_t sc_isoc_nframes; /* num. isoc. frames */
-#define UBT_ISOC_BUFFER_SIZE \
- (sizeof(ng_hci_scodata_pkt_t) + NG_HCI_SCO_PKT_SIZE)
-
-#if 0
- /* Netgraph specific */
- node_p sc_node; /* pointer back to node */
- hook_p sc_hook; /* upstream hook */
-#endif
-
- struct ifnet sc_if;
-};
-typedef struct ubt_softc ubt_softc_t;
-typedef struct ubt_softc * ubt_softc_p;
-
-#endif /* ndef _NG_UBT_VAR_H_ */
diff --git a/sys/dev/usb/ubt.c b/sys/dev/usb/ubt.c
new file mode 100644
index 00000000000..474b706c1d1
--- /dev/null
+++ b/sys/dev/usb/ubt.c
@@ -0,0 +1,1508 @@
+/* $OpenBSD: ubt.c,v 1.1 2007/05/30 12:15:02 gwk Exp $ */
+
+/*-
+ * Copyright (c) 2006 Itronix Inc.
+ * All rights reserved.
+ *
+ * Written by Iain Hibbert for Itronix Inc.
+ *
+ * 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.
+ * 3. The name of Itronix Inc. may not be used to endorse
+ * or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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.
+ */
+/*
+ * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (lennart@augustsson.net) and
+ * David Sainty (David.Sainty@dtsp.co.nz).
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+/*
+ * This driver originally written by Lennart Augustsson and David Sainty,
+ * but was mostly rewritten for the NetBSD Bluetooth protocol stack by
+ * Iain Hibbert for Itronix, Inc using the FreeBSD ng_ubt.c driver as a
+ * reference.
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/ioctl.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/proc.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+#include <dev/usb/usbdevs.h>
+
+#include <netbt/bluetooth.h>
+#include <netbt/hci.h>
+
+/*******************************************************************************
+ *
+ * debugging stuff
+ */
+#undef DPRINTF
+#undef DPRINTFN
+
+#ifdef UBT_DEBUG
+int ubt_debug = UBT_DEBUG;
+
+#define DPRINTF(fmt, args...) do { \
+ if (ubt_debug) \
+ printf("%s: "fmt, __func__ , ##args); \
+} while (/* CONSTCOND */0)
+
+#define DPRINTFN(n, fmt, args...) do { \
+ if (ubt_debug > (n)) \
+ printf("%s: "fmt, __func__ , ##args); \
+} while (/* CONSTCOND */0)
+
+#else
+#define DPRINTF(...)
+#define DPRINTFN(...)
+#endif
+
+/*******************************************************************************
+ *
+ * ubt softc structure
+ *
+ */
+
+/* buffer sizes */
+/*
+ * NB: although ACL packets can extend to 65535 bytes, most devices
+ * have max_acl_size at much less (largest I have seen is 384)
+ */
+#define UBT_BUFSIZ_CMD (HCI_CMD_PKT_SIZE - 1)
+#define UBT_BUFSIZ_ACL (2048 - 1)
+#define UBT_BUFSIZ_EVENT (HCI_EVENT_PKT_SIZE - 1)
+
+/* Transmit timeouts */
+#define UBT_CMD_TIMEOUT USBD_DEFAULT_TIMEOUT
+#define UBT_ACL_TIMEOUT USBD_DEFAULT_TIMEOUT
+
+/*
+ * ISOC transfers
+ *
+ * xfer buffer size depends on the frame size, and the number
+ * of frames per transfer is fixed, as each frame should be
+ * 1ms worth of data. This keeps the rate that xfers complete
+ * fairly constant. We use multiple xfers to keep the hardware
+ * busy
+ */
+#define UBT_NXFERS 3 /* max xfers to queue */
+#define UBT_NFRAMES 10 /* frames per xfer */
+
+struct ubt_isoc_xfer {
+ struct ubt_softc *softc;
+ usbd_xfer_handle xfer;
+ uint8_t *buf;
+ uint16_t size[UBT_NFRAMES];
+ int busy;
+};
+
+struct ubt_softc {
+ USBBASEDEVICE sc_dev;
+ usbd_device_handle sc_udev;
+ int sc_refcnt;
+ int sc_dying;
+
+ /* Control Interface */
+ usbd_interface_handle sc_iface0;
+
+ /* Commands (control) */
+ usbd_xfer_handle sc_cmd_xfer;
+ uint8_t *sc_cmd_buf;
+
+ /* Events (interrupt) */
+ int sc_evt_addr; /* endpoint address */
+ usbd_pipe_handle sc_evt_pipe;
+ uint8_t *sc_evt_buf;
+
+ /* ACL data (in) */
+ int sc_aclrd_addr; /* endpoint address */
+ usbd_pipe_handle sc_aclrd_pipe; /* read pipe */
+ usbd_xfer_handle sc_aclrd_xfer; /* read xfer */
+ uint8_t *sc_aclrd_buf; /* read buffer */
+ int sc_aclrd_busy; /* reading */
+
+ /* ACL data (out) */
+ int sc_aclwr_addr; /* endpoint address */
+ usbd_pipe_handle sc_aclwr_pipe; /* write pipe */
+ usbd_xfer_handle sc_aclwr_xfer; /* write xfer */
+ uint8_t *sc_aclwr_buf; /* write buffer */
+
+ /* ISOC interface */
+ usbd_interface_handle sc_iface1; /* ISOC interface */
+ struct sysctllog *sc_log; /* sysctl log */
+ int sc_config; /* current config no */
+ int sc_alt_config; /* no of alternates */
+
+ /* SCO data (in) */
+ int sc_scord_addr; /* endpoint address */
+ usbd_pipe_handle sc_scord_pipe; /* read pipe */
+ int sc_scord_size; /* frame length */
+ struct ubt_isoc_xfer sc_scord[UBT_NXFERS];
+ struct mbuf *sc_scord_mbuf; /* current packet */
+
+ /* SCO data (out) */
+ int sc_scowr_addr; /* endpoint address */
+ usbd_pipe_handle sc_scowr_pipe; /* write pipe */
+ int sc_scowr_size; /* frame length */
+ struct ubt_isoc_xfer sc_scowr[UBT_NXFERS];
+ struct mbuf *sc_scowr_mbuf; /* current packet */
+
+ /* Protocol structure */
+ struct hci_unit sc_unit;
+
+ /* Successfully attached */
+ int sc_ok;
+};
+
+/*
+ * Bluetooth unit/USB callback routines
+ */
+int ubt_enable(struct hci_unit *);
+void ubt_disable(struct hci_unit *);
+
+void ubt_xmit_cmd_start(struct hci_unit *);
+void ubt_xmit_cmd_complete(usbd_xfer_handle,
+ usbd_private_handle, usbd_status);
+
+void ubt_xmit_acl_start(struct hci_unit *);
+void ubt_xmit_acl_complete(usbd_xfer_handle,
+ usbd_private_handle, usbd_status);
+
+void ubt_xmit_sco_start(struct hci_unit *);
+void ubt_xmit_sco_start1(struct ubt_softc *, struct ubt_isoc_xfer *);
+void ubt_xmit_sco_complete(usbd_xfer_handle,
+ usbd_private_handle, usbd_status);
+
+void ubt_recv_event(usbd_xfer_handle,
+ usbd_private_handle, usbd_status);
+
+void ubt_recv_acl_start(struct ubt_softc *);
+void ubt_recv_acl_complete(usbd_xfer_handle,
+ usbd_private_handle, usbd_status);
+
+void ubt_recv_sco_start1(struct ubt_softc *, struct ubt_isoc_xfer *);
+void ubt_recv_sco_complete(usbd_xfer_handle,
+ usbd_private_handle, usbd_status);
+
+USB_DECLARE_DRIVER(ubt);
+
+static int ubt_set_isoc_config(struct ubt_softc *);
+static void ubt_abortdealloc(struct ubt_softc *);
+
+/*
+ * Match against the whole device, since we want to take
+ * both interfaces. If a device should be ignored then add
+ *
+ * { VendorID, ProductID }
+ *
+ * to the ubt_ignore list.
+ */
+static const struct usb_devno ubt_ignore[] = {
+ { USB_VENDOR_BROADCOM, USB_PRODUCT_BROADCOM_BCM2033NF },
+ { 0, 0 } /* end of list */
+};
+
+int
+ubt_match(struct device *parent, void *match, void *aux)
+{
+
+ struct usb_attach_arg *uaa = aux;
+ usb_device_descriptor_t *dd = usbd_get_device_descriptor(uaa->device);
+
+ DPRINTFN(50, "ubt_match\n");
+
+ if (usb_lookup(ubt_ignore, uaa->vendor, uaa->product))
+ return UMATCH_NONE;
+
+ if (dd->bDeviceClass == UDCLASS_WIRELESS
+ && dd->bDeviceSubClass == UDSUBCLASS_RF
+ && dd->bDeviceProtocol == UDPROTO_BLUETOOTH)
+ return UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO;
+
+ return UMATCH_NONE;
+}
+
+
+void
+ubt_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct ubt_softc *sc = (struct ubt_softc *)self;
+ struct usb_attach_arg *uaa = aux;
+ usb_config_descriptor_t *cd;
+ usb_endpoint_descriptor_t *ed;
+ char *devinfop;
+ int err;
+ uint8_t count, i;
+
+ DPRINTFN(50, "ubt_attach: sc=%p\n", sc);
+
+ sc->sc_udev = uaa->device;
+
+ devinfop = usbd_devinfo_alloc(sc->sc_udev, 0);
+ printf("\n%s: %s\n", USBDEVNAME(sc->sc_dev), devinfop);
+ usbd_devinfo_free(devinfop);
+
+ /*
+ * Move the device into the configured state
+ */
+ err = usbd_set_config_index(sc->sc_udev, 0, 1);
+ if (err) {
+ printf("%s: failed to set configuration idx 0: %s\n",
+ USBDEVNAME(sc->sc_dev), usbd_errstr(err));
+
+ return;
+ }
+
+ /*
+ * Interface 0 must have 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
+ */
+ err = usbd_device2interface_handle(sc->sc_udev, 0, &sc->sc_iface0);
+ if (err) {
+ printf("%s: Could not get interface 0 handle %s (%d)\n",
+ USBDEVNAME(sc->sc_dev), usbd_errstr(err), err);
+
+ return;
+ }
+
+ sc->sc_evt_addr = -1;
+ sc->sc_aclrd_addr = -1;
+ sc->sc_aclwr_addr = -1;
+
+ count = 0;
+ (void)usbd_endpoint_count(sc->sc_iface0, &count);
+
+ for (i = 0 ; i < count ; i++) {
+ int dir, type;
+
+ ed = usbd_interface2endpoint_descriptor(sc->sc_iface0, i);
+ if (ed == NULL) {
+ printf("%s: could not read endpoint descriptor %d\n",
+ USBDEVNAME(sc->sc_dev), i);
+
+ return;
+ }
+
+ dir = UE_GET_DIR(ed->bEndpointAddress);
+ type = UE_GET_XFERTYPE(ed->bmAttributes);
+
+ if (dir == UE_DIR_IN && type == UE_INTERRUPT)
+ sc->sc_evt_addr = ed->bEndpointAddress;
+ else if (dir == UE_DIR_IN && type == UE_BULK)
+ sc->sc_aclrd_addr = ed->bEndpointAddress;
+ else if (dir == UE_DIR_OUT && type == UE_BULK)
+ sc->sc_aclwr_addr = ed->bEndpointAddress;
+ }
+
+ if (sc->sc_evt_addr == -1) {
+ printf("%s: missing INTERRUPT endpoint on interface 0\n",
+ USBDEVNAME(sc->sc_dev));
+
+ return;
+ }
+ if (sc->sc_aclrd_addr == -1) {
+ printf("%s: missing BULK IN endpoint on interface 0\n",
+ USBDEVNAME(sc->sc_dev));
+
+ return;
+ }
+ if (sc->sc_aclwr_addr == -1) {
+ printf("%s: missing BULK OUT endpoint on interface 0\n",
+ USBDEVNAME(sc->sc_dev));
+
+ return;
+ }
+
+ /*
+ * Interface 1 must have 2 endpoints
+ * 1) Isochronous IN endpoint to receive SCO data
+ * 2) Isochronous OUT endpoint to send SCO data
+ *
+ * and will have several configurations, which can be selected
+ * via a sysctl variable. We select config 0 to start, which
+ * means that no SCO data will be available.
+ */
+ err = usbd_device2interface_handle(sc->sc_udev, 1, &sc->sc_iface1);
+ if (err) {
+ printf("%s: Could not get interface 1 handle %s (%d)\n",
+ USBDEVNAME(sc->sc_dev), usbd_errstr(err), err);
+
+ return;
+ }
+
+ cd = usbd_get_config_descriptor(sc->sc_udev);
+ if (cd == NULL) {
+ printf("%s: could not get config descriptor\n",
+ USBDEVNAME(sc->sc_dev));
+
+ return;
+ }
+
+ sc->sc_alt_config = usbd_get_no_alts(cd, 1);
+
+ /* set initial config */
+ err = ubt_set_isoc_config(sc);
+ if (err) {
+ printf("%s: ISOC config failed\n",
+ USBDEVNAME(sc->sc_dev));
+
+ return;
+ }
+
+ /* Attach HCI */
+ sc->sc_unit.hci_softc = self;
+ sc->sc_unit.hci_devname = USBDEVNAME(sc->sc_dev);
+ sc->sc_unit.hci_enable = ubt_enable;
+ sc->sc_unit.hci_disable = ubt_disable;
+ sc->sc_unit.hci_start_cmd = ubt_xmit_cmd_start;
+ sc->sc_unit.hci_start_acl = ubt_xmit_acl_start;
+ sc->sc_unit.hci_start_sco = ubt_xmit_sco_start;
+ sc->sc_unit.hci_ipl = IPL_USB; /* XXX: IPL_SOFTUSB ?? */
+ hci_attach(&sc->sc_unit);
+
+ usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
+ USBDEV(sc->sc_dev));
+
+ sc->sc_ok = 1;
+
+ return;
+}
+
+int
+ubt_detach(struct device *self, int flags)
+{
+ struct ubt_softc *sc = (struct ubt_softc *)self;
+ int s;
+
+ DPRINTF("sc=%p flags=%d\n", sc, flags);
+
+ sc->sc_dying = 1;
+
+ if (!sc->sc_ok)
+ return 0;
+
+ /* Detach HCI interface */
+ hci_detach(&sc->sc_unit);
+
+ /*
+ * Abort all pipes. Causes processes waiting for transfer to wake.
+ *
+ * Actually, hci_detach() above will call ubt_disable() which may
+ * call ubt_abortdealloc(), but lets be sure since doing it twice
+ * wont cause an error.
+ */
+ ubt_abortdealloc(sc);
+
+ /* wait for all processes to finish */
+ s = splusb();
+ if (sc->sc_refcnt-- > 0)
+ usb_detach_wait(USBDEV(sc->sc_dev));
+
+ splx(s);
+
+ usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
+ USBDEV(sc->sc_dev));
+
+ DPRINTFN(1, "driver detached\n");
+
+ return 0;
+}
+
+int
+ubt_activate(device_ptr_t self, enum devact act)
+{
+ struct ubt_softc *sc = (struct ubt_softc *)self;
+ int error = 0;
+
+ DPRINTFN(1, "ubt_activate: sc=%p, act=%d\n", sc, act);
+
+ switch (act) {
+ case DVACT_ACTIVATE:
+ return EOPNOTSUPP;
+ break;
+
+ case DVACT_DEACTIVATE:
+ sc->sc_dying = 1;
+ break;
+ }
+ return error;
+}
+
+/* set ISOC configuration */
+int
+ubt_set_isoc_config(struct ubt_softc *sc)
+{
+ usb_endpoint_descriptor_t *ed;
+ int rd_addr, wr_addr, rd_size, wr_size;
+ uint8_t count, i;
+ int err;
+
+ err = usbd_set_interface(sc->sc_iface1, sc->sc_config);
+ if (err != USBD_NORMAL_COMPLETION) {
+ printf(
+ "%s: Could not set config %d on ISOC interface. %s (%d)\n",
+ USBDEVNAME(sc->sc_dev), sc->sc_config, usbd_errstr(err), err);
+
+ return err == USBD_IN_USE ? EBUSY : EIO;
+ }
+
+ /*
+ * We wont get past the above if there are any pipes open, so no
+ * need to worry about buf/xfer/pipe deallocation. If we get an
+ * error after this, the frame quantities will be 0 and no SCO
+ * data will be possible.
+ */
+
+ sc->sc_scord_size = rd_size = 0;
+ sc->sc_scord_addr = rd_addr = -1;
+
+ sc->sc_scowr_size = wr_size = 0;
+ sc->sc_scowr_addr = wr_addr = -1;
+
+ count = 0;
+ (void)usbd_endpoint_count(sc->sc_iface1, &count);
+
+ for (i = 0 ; i < count ; i++) {
+ ed = usbd_interface2endpoint_descriptor(sc->sc_iface1, i);
+ if (ed == NULL) {
+ printf("%s: could not read endpoint descriptor %d\n",
+ USBDEVNAME(sc->sc_dev), i);
+
+ return EIO;
+ }
+
+ DPRINTFN(5, "%s: endpoint type %02x (%02x) addr %02x (%s)\n",
+ USBDEVNAME(sc->sc_dev),
+ UE_GET_XFERTYPE(ed->bmAttributes),
+ UE_GET_ISO_TYPE(ed->bmAttributes),
+ ed->bEndpointAddress,
+ UE_GET_DIR(ed->bEndpointAddress) ? "in" : "out");
+
+ if (UE_GET_XFERTYPE(ed->bmAttributes) != UE_ISOCHRONOUS)
+ continue;
+
+ if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) {
+ rd_addr = ed->bEndpointAddress;
+ rd_size = UGETW(ed->wMaxPacketSize);
+ } else {
+ wr_addr = ed->bEndpointAddress;
+ wr_size = UGETW(ed->wMaxPacketSize);
+ }
+ }
+
+ if (rd_addr == -1) {
+ printf(
+ "%s: missing ISOC IN endpoint on interface config %d\n",
+ USBDEVNAME(sc->sc_dev), sc->sc_config);
+
+ return ENOENT;
+ }
+ if (wr_addr == -1) {
+ printf(
+ "%s: missing ISOC OUT endpoint on interface config %d\n",
+ USBDEVNAME(sc->sc_dev), sc->sc_config);
+
+ return ENOENT;
+ }
+
+#ifdef DIAGNOSTIC
+ if (rd_size > MLEN) {
+ printf("%s: rd_size=%d exceeds MLEN\n",
+ USBDEVNAME(sc->sc_dev), rd_size);
+
+ return EOVERFLOW;
+ }
+
+ if (wr_size > MLEN) {
+ printf("%s: wr_size=%d exceeds MLEN\n",
+ USBDEVNAME(sc->sc_dev), wr_size);
+
+ return EOVERFLOW;
+ }
+#endif
+
+ sc->sc_scord_size = rd_size;
+ sc->sc_scord_addr = rd_addr;
+
+ sc->sc_scowr_size = wr_size;
+ sc->sc_scowr_addr = wr_addr;
+
+ return 0;
+}
+
+void
+ubt_abortdealloc(struct ubt_softc *sc)
+{
+ int i;
+
+ DPRINTFN(1, "sc=%p\n", sc);
+
+ /* Abort all pipes */
+ if (sc->sc_evt_pipe != NULL) {
+ usbd_abort_pipe(sc->sc_evt_pipe);
+ usbd_close_pipe(sc->sc_evt_pipe);
+ sc->sc_evt_pipe = NULL;
+ }
+
+ if (sc->sc_aclrd_pipe != NULL) {
+ usbd_abort_pipe(sc->sc_aclrd_pipe);
+ usbd_close_pipe(sc->sc_aclrd_pipe);
+ sc->sc_aclrd_pipe = NULL;
+ }
+
+ if (sc->sc_aclwr_pipe != NULL) {
+ usbd_abort_pipe(sc->sc_aclwr_pipe);
+ usbd_close_pipe(sc->sc_aclwr_pipe);
+ sc->sc_aclwr_pipe = NULL;
+ }
+
+ if (sc->sc_scord_pipe != NULL) {
+ usbd_abort_pipe(sc->sc_scord_pipe);
+ usbd_close_pipe(sc->sc_scord_pipe);
+ sc->sc_scord_pipe = NULL;
+ }
+
+ if (sc->sc_scowr_pipe != NULL) {
+ usbd_abort_pipe(sc->sc_scowr_pipe);
+ usbd_close_pipe(sc->sc_scowr_pipe);
+ sc->sc_scowr_pipe = NULL;
+ }
+
+ /* Free event buffer */
+ if (sc->sc_evt_buf != NULL) {
+ free(sc->sc_evt_buf, M_USBDEV);
+ sc->sc_evt_buf = NULL;
+ }
+
+ /* Free all xfers and xfer buffers (implicit) */
+ if (sc->sc_cmd_xfer != NULL) {
+ usbd_free_xfer(sc->sc_cmd_xfer);
+ sc->sc_cmd_xfer = NULL;
+ sc->sc_cmd_buf = NULL;
+ }
+
+ if (sc->sc_aclrd_xfer != NULL) {
+ usbd_free_xfer(sc->sc_aclrd_xfer);
+ sc->sc_aclrd_xfer = NULL;
+ sc->sc_aclrd_buf = NULL;
+ }
+
+ if (sc->sc_aclwr_xfer != NULL) {
+ usbd_free_xfer(sc->sc_aclwr_xfer);
+ sc->sc_aclwr_xfer = NULL;
+ sc->sc_aclwr_buf = NULL;
+ }
+
+ for (i = 0 ; i < UBT_NXFERS ; i++) {
+ if (sc->sc_scord[i].xfer != NULL) {
+ usbd_free_xfer(sc->sc_scord[i].xfer);
+ sc->sc_scord[i].xfer = NULL;
+ sc->sc_scord[i].buf = NULL;
+ }
+
+ if (sc->sc_scowr[i].xfer != NULL) {
+ usbd_free_xfer(sc->sc_scowr[i].xfer);
+ sc->sc_scowr[i].xfer = NULL;
+ sc->sc_scowr[i].buf = NULL;
+ }
+ }
+
+ /* Free partial SCO packets */
+ if (sc->sc_scord_mbuf != NULL) {
+ m_freem(sc->sc_scord_mbuf);
+ sc->sc_scord_mbuf = NULL;
+ }
+
+ if (sc->sc_scowr_mbuf != NULL) {
+ m_freem(sc->sc_scowr_mbuf);
+ sc->sc_scowr_mbuf = NULL;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Bluetooth Unit/USB callbacks
+ *
+ * All of this will be called at the IPL_ we specified above
+ */
+int
+ubt_enable(struct hci_unit *unit)
+{
+ struct ubt_softc *sc = (struct ubt_softc *)unit->hci_softc;
+ usbd_status err;
+ int i, error;
+
+ DPRINTFN(1, "sc=%p\n", sc);
+
+ if (unit->hci_flags & BTF_RUNNING)
+ return 0;
+
+ /* Events */
+ sc->sc_evt_buf = malloc(UBT_BUFSIZ_EVENT, M_USBDEV, M_NOWAIT);
+ if (sc->sc_evt_buf == NULL) {
+ error = ENOMEM;
+ goto bad;
+ }
+ err = usbd_open_pipe_intr(sc->sc_iface0,
+ sc->sc_evt_addr,
+ USBD_SHORT_XFER_OK,
+ &sc->sc_evt_pipe,
+ sc,
+ sc->sc_evt_buf,
+ UBT_BUFSIZ_EVENT,
+ ubt_recv_event,
+ USBD_DEFAULT_INTERVAL);
+ if (err != USBD_NORMAL_COMPLETION) {
+ error = EIO;
+ goto bad;
+ }
+
+ /* Commands */
+ sc->sc_cmd_xfer = usbd_alloc_xfer(sc->sc_udev);
+ if (sc->sc_cmd_xfer == NULL) {
+ error = ENOMEM;
+ goto bad;
+ }
+ sc->sc_cmd_buf = usbd_alloc_buffer(sc->sc_cmd_xfer, UBT_BUFSIZ_CMD);
+ if (sc->sc_cmd_buf == NULL) {
+ error = ENOMEM;
+ goto bad;
+ }
+
+ /* ACL read */
+ err = usbd_open_pipe(sc->sc_iface0, sc->sc_aclrd_addr,
+ USBD_EXCLUSIVE_USE, &sc->sc_aclrd_pipe);
+ if (err != USBD_NORMAL_COMPLETION) {
+ error = EIO;
+ goto bad;
+ }
+ sc->sc_aclrd_xfer = usbd_alloc_xfer(sc->sc_udev);
+ if (sc->sc_aclrd_xfer == NULL) {
+ error = ENOMEM;
+ goto bad;
+ }
+ sc->sc_aclrd_buf = usbd_alloc_buffer(sc->sc_aclrd_xfer, UBT_BUFSIZ_ACL);
+ if (sc->sc_aclrd_buf == NULL) {
+ error = ENOMEM;
+ goto bad;
+ }
+ sc->sc_aclrd_busy = 0;
+ ubt_recv_acl_start(sc);
+
+ /* ACL write */
+ err = usbd_open_pipe(sc->sc_iface0, sc->sc_aclwr_addr,
+ USBD_EXCLUSIVE_USE, &sc->sc_aclwr_pipe);
+ if (err != USBD_NORMAL_COMPLETION) {
+ error = EIO;
+ goto bad;
+ }
+ sc->sc_aclwr_xfer = usbd_alloc_xfer(sc->sc_udev);
+ if (sc->sc_aclwr_xfer == NULL) {
+ error = ENOMEM;
+ goto bad;
+ }
+ sc->sc_aclwr_buf = usbd_alloc_buffer(sc->sc_aclwr_xfer, UBT_BUFSIZ_ACL);
+ if (sc->sc_aclwr_buf == NULL) {
+ error = ENOMEM;
+ goto bad;
+ }
+
+ /* SCO read */
+ if (sc->sc_scord_size > 0) {
+ err = usbd_open_pipe(sc->sc_iface1, sc->sc_scord_addr,
+ USBD_EXCLUSIVE_USE, &sc->sc_scord_pipe);
+ if (err != USBD_NORMAL_COMPLETION) {
+ error = EIO;
+ goto bad;
+ }
+
+ for (i = 0 ; i < UBT_NXFERS ; i++) {
+ sc->sc_scord[i].xfer = usbd_alloc_xfer(sc->sc_udev);
+ if (sc->sc_scord[i].xfer == NULL) {
+ error = ENOMEM;
+ goto bad;
+ }
+ sc->sc_scord[i].buf = usbd_alloc_buffer(sc->sc_scord[i].xfer,
+ sc->sc_scord_size * UBT_NFRAMES);
+ if (sc->sc_scord[i].buf == NULL) {
+ error = ENOMEM;
+ goto bad;
+ }
+ sc->sc_scord[i].softc = sc;
+ sc->sc_scord[i].busy = 0;
+ ubt_recv_sco_start1(sc, &sc->sc_scord[i]);
+ }
+ }
+
+ /* SCO write */
+ if (sc->sc_scowr_size > 0) {
+ err = usbd_open_pipe(sc->sc_iface1, sc->sc_scowr_addr,
+ USBD_EXCLUSIVE_USE, &sc->sc_scowr_pipe);
+ if (err != USBD_NORMAL_COMPLETION) {
+ error = EIO;
+ goto bad;
+ }
+
+ for (i = 0 ; i < UBT_NXFERS ; i++) {
+ sc->sc_scowr[i].xfer = usbd_alloc_xfer(sc->sc_udev);
+ if (sc->sc_scowr[i].xfer == NULL) {
+ error = ENOMEM;
+ goto bad;
+ }
+ sc->sc_scowr[i].buf = usbd_alloc_buffer(sc->sc_scowr[i].xfer,
+ sc->sc_scowr_size * UBT_NFRAMES);
+ if (sc->sc_scowr[i].buf == NULL) {
+ error = ENOMEM;
+ goto bad;
+ }
+ sc->sc_scowr[i].softc = sc;
+ sc->sc_scowr[i].busy = 0;
+ }
+ }
+
+ unit->hci_flags &= ~BTF_XMIT;
+ unit->hci_flags |= BTF_RUNNING;
+ return 0;
+
+bad:
+ ubt_abortdealloc(sc);
+ return error;
+}
+
+void
+ubt_disable(struct hci_unit *unit)
+{
+ struct ubt_softc *sc = (struct ubt_softc *)unit->hci_softc;
+
+ DPRINTFN(1, "sc=%p\n", sc);
+
+ if ((unit->hci_flags & BTF_RUNNING) == 0)
+ return;
+
+ ubt_abortdealloc(sc);
+
+ unit->hci_flags &= ~BTF_RUNNING;
+}
+
+void
+ubt_xmit_cmd_start(struct hci_unit *unit)
+{
+ struct ubt_softc *sc = (struct ubt_softc *)unit->hci_softc;
+ usb_device_request_t req;
+ usbd_status status;
+ struct mbuf *m;
+ int len;
+
+ if (sc->sc_dying)
+ return;
+
+ if (IF_IS_EMPTY(&unit->hci_cmdq))
+ return;
+
+ IF_DEQUEUE(&unit->hci_cmdq, m);
+
+ DPRINTFN(15, "%s: xmit CMD packet (%d bytes)\n",
+ unit->hci_devname, m->m_pkthdr.len);
+
+ sc->sc_refcnt++;
+ unit->hci_flags |= BTF_XMIT_CMD;
+
+ len = m->m_pkthdr.len - 1;
+ m_copydata(m, 1, len, sc->sc_cmd_buf);
+ m_freem(m);
+
+ memset(&req, 0, sizeof(req));
+ req.bmRequestType = UT_WRITE_CLASS_DEVICE;
+ USETW(req.wLength, len);
+
+ usbd_setup_default_xfer(sc->sc_cmd_xfer,
+ sc->sc_udev,
+ unit,
+ UBT_CMD_TIMEOUT,
+ &req,
+ sc->sc_cmd_buf,
+ len,
+ USBD_NO_COPY | USBD_FORCE_SHORT_XFER,
+ ubt_xmit_cmd_complete);
+
+ status = usbd_transfer(sc->sc_cmd_xfer);
+
+ KASSERT(status != USBD_NORMAL_COMPLETION);
+
+ if (status != USBD_IN_PROGRESS) {
+ DPRINTF("usbd_transfer status=%s (%d)\n",
+ usbd_errstr(status), status);
+
+ sc->sc_refcnt--;
+ unit->hci_flags &= ~BTF_XMIT_CMD;
+ }
+}
+
+void
+ubt_xmit_cmd_complete(usbd_xfer_handle xfer,
+ usbd_private_handle h, usbd_status status)
+{
+ struct hci_unit *unit = h;
+ struct ubt_softc *sc = (struct ubt_softc *)unit->hci_softc;
+ uint32_t count;
+
+ DPRINTFN(15, "%s: CMD complete status=%s (%d)\n",
+ unit->hci_devname, usbd_errstr(status), status);
+
+ unit->hci_flags &= ~BTF_XMIT_CMD;
+
+ if (--sc->sc_refcnt < 0) {
+ DPRINTF("sc_refcnt=%d\n", sc->sc_refcnt);
+ usb_detach_wakeup(USBDEV(sc->sc_dev));
+ return;
+ }
+
+ if (sc->sc_dying) {
+ DPRINTF("sc_dying\n");
+ return;
+ }
+
+ if (status != USBD_NORMAL_COMPLETION) {
+ DPRINTF("status=%s (%d)\n",
+ usbd_errstr(status), status);
+
+ unit->hci_stats.err_tx++;
+ return;
+ }
+
+ usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
+ unit->hci_stats.cmd_tx++;
+ unit->hci_stats.byte_tx += count;
+
+ ubt_xmit_cmd_start(unit);
+}
+
+void
+ubt_xmit_acl_start(struct hci_unit *unit)
+{
+ struct ubt_softc *sc = (struct ubt_softc *)unit->hci_softc;
+ struct mbuf *m;
+ usbd_status status;
+ int len;
+
+ if (sc->sc_dying)
+ return;
+
+ if (IF_IS_EMPTY(&unit->hci_acltxq) == NULL)
+ return;
+
+ sc->sc_refcnt++;
+ unit->hci_flags |= BTF_XMIT_ACL;
+
+ IF_DEQUEUE(&unit->hci_acltxq, m);
+
+ DPRINTFN(15, "%s: xmit ACL packet (%d bytes)\n",
+ unit->hci_devname, m->m_pkthdr.len);
+
+ len = m->m_pkthdr.len - 1;
+ if (len > UBT_BUFSIZ_ACL) {
+ DPRINTF("%s: truncating ACL packet (%d => %d)!\n",
+ unit->hci_devname, len, UBT_BUFSIZ_ACL);
+
+ len = UBT_BUFSIZ_ACL;
+ }
+
+ m_copydata(m, 1, len, sc->sc_aclwr_buf);
+ m_freem(m);
+
+ unit->hci_stats.acl_tx++;
+ unit->hci_stats.byte_tx += len;
+
+ usbd_setup_xfer(sc->sc_aclwr_xfer,
+ sc->sc_aclwr_pipe,
+ unit,
+ sc->sc_aclwr_buf,
+ len,
+ USBD_NO_COPY | USBD_FORCE_SHORT_XFER,
+ UBT_ACL_TIMEOUT,
+ ubt_xmit_acl_complete);
+
+ status = usbd_transfer(sc->sc_aclwr_xfer);
+
+ KASSERT(status != USBD_NORMAL_COMPLETION);
+
+ if (status != USBD_IN_PROGRESS) {
+ DPRINTF("usbd_transfer status=%s (%d)\n",
+ usbd_errstr(status), status);
+
+ sc->sc_refcnt--;
+ unit->hci_flags &= ~BTF_XMIT_ACL;
+ }
+}
+
+void
+ubt_xmit_acl_complete(usbd_xfer_handle xfer,
+ usbd_private_handle h, usbd_status status)
+{
+ struct hci_unit *unit = h;
+ struct ubt_softc *sc = (struct ubt_softc *)unit->hci_softc;
+
+ DPRINTFN(15, "%s: ACL complete status=%s (%d)\n",
+ unit->hci_devname, usbd_errstr(status), status);
+
+ unit->hci_flags &= ~BTF_XMIT_ACL;
+
+ if (--sc->sc_refcnt < 0) {
+ usb_detach_wakeup(USBDEV(sc->sc_dev));
+ return;
+ }
+
+ if (sc->sc_dying)
+ return;
+
+ if (status != USBD_NORMAL_COMPLETION) {
+ DPRINTF("status=%s (%d)\n",
+ usbd_errstr(status), status);
+
+ unit->hci_stats.err_tx++;
+
+ if (status == USBD_STALLED)
+ usbd_clear_endpoint_stall_async(sc->sc_aclwr_pipe);
+ else
+ return;
+ }
+
+ ubt_xmit_acl_start(unit);
+}
+
+void
+ubt_xmit_sco_start(struct hci_unit *unit)
+{
+ struct ubt_softc *sc = (struct ubt_softc *)unit->hci_softc;
+ int i;
+
+ if (sc->sc_dying || sc->sc_scowr_size == 0)
+ return;
+
+ for (i = 0 ; i < UBT_NXFERS ; i++) {
+ if (sc->sc_scowr[i].busy)
+ continue;
+
+ ubt_xmit_sco_start1(sc, &sc->sc_scowr[i]);
+ }
+}
+
+void
+ubt_xmit_sco_start1(struct ubt_softc *sc, struct ubt_isoc_xfer *isoc)
+{
+ struct mbuf *m;
+ uint8_t *buf;
+ int num, len, size, space;
+
+ space = sc->sc_scowr_size * UBT_NFRAMES;
+ buf = isoc->buf;
+ len = 0;
+
+ /*
+ * Fill the request buffer with data from the queue,
+ * keeping any leftover packet on our private hook.
+ *
+ * Complete packets are passed back up to the stack
+ * for disposal, since we can't rely on the controller
+ * to tell us when it has finished with them.
+ */
+
+ m = sc->sc_scowr_mbuf;
+ while (space > 0) {
+ if (m == NULL) {
+ IF_DEQUEUE(&sc->sc_unit.hci_scotxq, m);
+ if (m == NULL)
+ break;
+
+ m_adj(m, 1); /* packet type */
+ }
+
+ if (m->m_pkthdr.len > 0) {
+ size = MIN(m->m_pkthdr.len, space);
+
+ m_copydata(m, 0, size, buf);
+ m_adj(m, size);
+
+ buf += size;
+ len += size;
+ space -= size;
+ }
+
+ if (m->m_pkthdr.len == 0) {
+ sc->sc_unit.hci_stats.sco_tx++;
+ hci_complete_sco(&sc->sc_unit, m);
+ m = NULL;
+ }
+ }
+ sc->sc_scowr_mbuf = m;
+
+ DPRINTFN(15, "isoc=%p, len=%d, space=%d\n", isoc, len, space);
+
+ if (len == 0) /* nothing to send */
+ return;
+
+ sc->sc_refcnt++;
+ sc->sc_unit.hci_flags |= BTF_XMIT_SCO;
+ sc->sc_unit.hci_stats.byte_tx += len;
+ isoc->busy = 1;
+
+ /*
+ * calculate number of isoc frames and sizes
+ */
+
+ for (num = 0 ; len > 0 ; num++) {
+ size = MIN(sc->sc_scowr_size, len);
+
+ isoc->size[num] = size;
+ len -= size;
+ }
+
+ usbd_setup_isoc_xfer(isoc->xfer,
+ sc->sc_scowr_pipe,
+ isoc,
+ isoc->size,
+ num,
+ USBD_NO_COPY | USBD_FORCE_SHORT_XFER,
+ ubt_xmit_sco_complete);
+
+ usbd_transfer(isoc->xfer);
+}
+
+void
+ubt_xmit_sco_complete(usbd_xfer_handle xfer,
+ usbd_private_handle h, usbd_status status)
+{
+ struct ubt_isoc_xfer *isoc = h;
+ struct ubt_softc *sc;
+ int i;
+
+ KASSERT(xfer == isoc->xfer);
+ sc = isoc->softc;
+
+ DPRINTFN(15, "isoc=%p, status=%s (%d)\n",
+ isoc, usbd_errstr(status), status);
+
+ isoc->busy = 0;
+
+ for (i = 0 ; ; i++) {
+ if (i == UBT_NXFERS) {
+ sc->sc_unit.hci_flags &= ~BTF_XMIT_SCO;
+ break;
+ }
+
+ if (sc->sc_scowr[i].busy)
+ break;
+ }
+
+ if (--sc->sc_refcnt < 0) {
+ usb_detach_wakeup(USBDEV(sc->sc_dev));
+ return;
+ }
+
+ if (sc->sc_dying)
+ return;
+
+ if (status != USBD_NORMAL_COMPLETION) {
+ DPRINTF("status=%s (%d)\n",
+ usbd_errstr(status), status);
+
+ sc->sc_unit.hci_stats.err_tx++;
+
+ if (status == USBD_STALLED)
+ usbd_clear_endpoint_stall_async(sc->sc_scowr_pipe);
+ else
+ return;
+ }
+
+ ubt_xmit_sco_start(&sc->sc_unit);
+}
+
+/*
+ * load incoming data into an mbuf with
+ * leading type byte
+ */
+static struct mbuf *
+ubt_mbufload(uint8_t *buf, int count, uint8_t type)
+{
+ struct mbuf *m;
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ return NULL;
+
+ *mtod(m, uint8_t *) = type;
+ m->m_pkthdr.len = m->m_len = MHLEN;
+ m_copyback(m, 1, count, buf); // (extends if necessary)
+ if (m->m_pkthdr.len != MAX(MHLEN, count + 1)) {
+ m_free(m);
+ return NULL;
+ }
+
+ m->m_pkthdr.len = count + 1;
+ m->m_len = MIN(MHLEN, m->m_pkthdr.len);
+
+ return m;
+}
+
+void
+ubt_recv_event(usbd_xfer_handle xfer, usbd_private_handle h, usbd_status status)
+{
+ struct ubt_softc *sc = h;
+ struct mbuf *m;
+ uint32_t count;
+ void *buf;
+
+ DPRINTFN(15, "sc=%p status=%s (%d)\n",
+ sc, usbd_errstr(status), status);
+
+ if (status != USBD_NORMAL_COMPLETION || sc->sc_dying)
+ return;
+
+ usbd_get_xfer_status(xfer, NULL, &buf, &count, NULL);
+
+ if (count < sizeof(hci_event_hdr_t) - 1) {
+ DPRINTF("dumped undersized event (count = %d)\n", count);
+ sc->sc_unit.hci_stats.err_rx++;
+ return;
+ }
+
+ sc->sc_unit.hci_stats.evt_rx++;
+ sc->sc_unit.hci_stats.byte_rx += count;
+
+ m = ubt_mbufload(buf, count, HCI_EVENT_PKT);
+ if (m != NULL)
+ hci_input_event(&sc->sc_unit, m);
+ else
+ sc->sc_unit.hci_stats.err_rx++;
+}
+
+void
+ubt_recv_acl_start(struct ubt_softc *sc)
+{
+ usbd_status status;
+
+ DPRINTFN(15, "sc=%p\n", sc);
+
+ if (sc->sc_aclrd_busy || sc->sc_dying) {
+ DPRINTF("sc_aclrd_busy=%d, sc_dying=%d\n",
+ sc->sc_aclrd_busy,
+ sc->sc_dying);
+
+ return;
+ }
+
+ sc->sc_refcnt++;
+ sc->sc_aclrd_busy = 1;
+
+ usbd_setup_xfer(sc->sc_aclrd_xfer,
+ sc->sc_aclrd_pipe,
+ sc,
+ sc->sc_aclrd_buf,
+ UBT_BUFSIZ_ACL,
+ USBD_NO_COPY | USBD_SHORT_XFER_OK,
+ USBD_NO_TIMEOUT,
+ ubt_recv_acl_complete);
+
+ status = usbd_transfer(sc->sc_aclrd_xfer);
+
+ KASSERT(status != USBD_NORMAL_COMPLETION);
+
+ if (status != USBD_IN_PROGRESS) {
+ DPRINTF("usbd_transfer status=%s (%d)\n",
+ usbd_errstr(status), status);
+
+ sc->sc_refcnt--;
+ sc->sc_aclrd_busy = 0;
+ }
+}
+
+void
+ubt_recv_acl_complete(usbd_xfer_handle xfer,
+ usbd_private_handle h, usbd_status status)
+{
+ struct ubt_softc *sc = h;
+ struct mbuf *m;
+ uint32_t count;
+ void *buf;
+
+ DPRINTFN(15, "sc=%p status=%s (%d)\n",
+ sc, usbd_errstr(status), status);
+
+ sc->sc_aclrd_busy = 0;
+
+ if (--sc->sc_refcnt < 0) {
+ DPRINTF("refcnt = %d\n", sc->sc_refcnt);
+ usb_detach_wakeup(USBDEV(sc->sc_dev));
+ return;
+ }
+
+ if (sc->sc_dying) {
+ DPRINTF("sc_dying\n");
+ return;
+ }
+
+ if (status != USBD_NORMAL_COMPLETION) {
+ DPRINTF("status=%s (%d)\n",
+ usbd_errstr(status), status);
+
+ sc->sc_unit.hci_stats.err_rx++;
+
+ if (status == USBD_STALLED)
+ usbd_clear_endpoint_stall_async(sc->sc_aclrd_pipe);
+ else
+ return;
+ } else {
+ usbd_get_xfer_status(xfer, NULL, &buf, &count, NULL);
+
+ if (count < sizeof(hci_acldata_hdr_t) - 1) {
+ DPRINTF("dumped undersized packet (%d)\n", count);
+ sc->sc_unit.hci_stats.err_rx++;
+ } else {
+ sc->sc_unit.hci_stats.acl_rx++;
+ sc->sc_unit.hci_stats.byte_rx += count;
+
+ m = ubt_mbufload(buf, count, HCI_ACL_DATA_PKT);
+ if (m != NULL)
+ hci_input_acl(&sc->sc_unit, m);
+ else
+ sc->sc_unit.hci_stats.err_rx++;
+ }
+ }
+
+ /* and restart */
+ ubt_recv_acl_start(sc);
+}
+
+void
+ubt_recv_sco_start1(struct ubt_softc *sc, struct ubt_isoc_xfer *isoc)
+{
+ int i;
+
+ DPRINTFN(15, "sc=%p, isoc=%p\n", sc, isoc);
+
+ if (isoc->busy || sc->sc_dying || sc->sc_scord_size == 0) {
+ DPRINTF("%s%s%s\n",
+ isoc->busy ? " busy" : "",
+ sc->sc_dying ? " dying" : "",
+ sc->sc_scord_size == 0 ? " size=0" : "");
+
+ return;
+ }
+
+ sc->sc_refcnt++;
+ isoc->busy = 1;
+
+ for (i = 0 ; i < UBT_NFRAMES ; i++)
+ isoc->size[i] = sc->sc_scord_size;
+
+ usbd_setup_isoc_xfer(isoc->xfer,
+ sc->sc_scord_pipe,
+ isoc,
+ isoc->size,
+ UBT_NFRAMES,
+ USBD_NO_COPY | USBD_SHORT_XFER_OK,
+ ubt_recv_sco_complete);
+
+ usbd_transfer(isoc->xfer);
+}
+
+void
+ubt_recv_sco_complete(usbd_xfer_handle xfer,
+ usbd_private_handle h, usbd_status status)
+{
+ struct ubt_isoc_xfer *isoc = h;
+ struct ubt_softc *sc;
+ struct mbuf *m;
+ uint32_t count;
+ uint8_t *ptr, *frame;
+ int i, size, got, want;
+
+ KASSERT(isoc != NULL);
+ KASSERT(isoc->xfer == xfer);
+
+ sc = isoc->softc;
+ isoc->busy = 0;
+
+ if (--sc->sc_refcnt < 0) {
+ DPRINTF("refcnt=%d\n", sc->sc_refcnt);
+ usb_detach_wakeup(USBDEV(sc->sc_dev));
+ return;
+ }
+
+ if (sc->sc_dying) {
+ DPRINTF("sc_dying\n");
+ return;
+ }
+
+ if (status != USBD_NORMAL_COMPLETION) {
+ DPRINTF("status=%s (%d)\n",
+ usbd_errstr(status), status);
+
+ sc->sc_unit.hci_stats.err_rx++;
+
+ if (status == USBD_STALLED) {
+ usbd_clear_endpoint_stall_async(sc->sc_scord_pipe);
+ goto restart;
+ }
+
+ return;
+ }
+
+ usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
+ if (count == 0)
+ goto restart;
+
+ DPRINTFN(15, "sc=%p, isoc=%p, count=%u\n",
+ sc, isoc, count);
+
+ sc->sc_unit.hci_stats.byte_rx += count;
+
+ /*
+ * Extract SCO packets from ISOC frames. The way we have it,
+ * no SCO packet can be bigger than MHLEN. This is unlikely
+ * to actually happen, but if we ran out of mbufs and lost
+ * sync then we may get spurious data that makes it seem that
+ * way, so we discard data that wont fit. This doesnt really
+ * help with the lost sync situation alas.
+ */
+
+ m = sc->sc_scord_mbuf;
+ if (m != NULL) {
+ sc->sc_scord_mbuf = NULL;
+ ptr = mtod(m, uint8_t *) + m->m_pkthdr.len;
+ got = m->m_pkthdr.len;
+ want = sizeof(hci_scodata_hdr_t);
+ if (got >= want)
+ want += mtod(m, hci_scodata_hdr_t *)->length ;
+ } else {
+ ptr = NULL;
+ got = 0;
+ want = 0;
+ }
+
+ for (i = 0 ; i < UBT_NFRAMES ; i++) {
+ frame = isoc->buf + (i * sc->sc_scord_size);
+
+ while (isoc->size[i] > 0) {
+ size = isoc->size[i];
+
+ if (m == NULL) {
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL) {
+ printf("%s: out of memory (xfer halted)\n",
+ USBDEVNAME(sc->sc_dev));
+
+ sc->sc_unit.hci_stats.err_rx++;
+ return; /* lost sync */
+ }
+
+ ptr = mtod(m, uint8_t *);
+ *ptr++ = HCI_SCO_DATA_PKT;
+ got = 1;
+ want = sizeof(hci_scodata_hdr_t);
+ }
+
+ if (got + size > want)
+ size = want - got;
+
+ if (got + size > MHLEN)
+ memcpy(ptr, frame, MHLEN - got);
+ else
+ memcpy(ptr, frame, size);
+
+ ptr += size;
+ got += size;
+ frame += size;
+
+ if (got == want) {
+ /*
+ * If we only got a header, add the packet
+ * length to our want count. Send complete
+ * packets up to protocol stack.
+ */
+ if (want == sizeof(hci_scodata_hdr_t))
+ want += mtod(m, hci_scodata_hdr_t *)->length;
+
+ if (got == want) {
+ m->m_pkthdr.len = m->m_len = got;
+ sc->sc_unit.hci_stats.sco_rx++;
+ hci_input_sco(&sc->sc_unit, m);
+ m = NULL;
+ }
+ }
+
+ isoc->size[i] -= size;
+ }
+ }
+
+ if (m != NULL) {
+ m->m_pkthdr.len = m->m_len = got;
+ sc->sc_scord_mbuf = m;
+ }
+
+restart: /* and restart */
+ ubt_recv_sco_start1(sc, isoc);
+}