Delete the bluetooth drivers for the old usb stack.

This commit is contained in:
Andrew Thompson 2009-05-27 16:29:56 +00:00
parent 2f98b86b92
commit 31097ae267
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=192903
4 changed files with 0 additions and 3091 deletions

View File

@ -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 **

File diff suppressed because it is too large Load Diff

View File

@ -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_ */

View File

@ -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);
}