From owner-p4-projects@FreeBSD.ORG Sun Sep 17 09:39:25 2006 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id B5CA916A4F6; Sun, 17 Sep 2006 09:39:25 +0000 (UTC) X-Original-To: perforce@FreeBSD.org Delivered-To: perforce@FreeBSD.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 784B716A40F for ; Sun, 17 Sep 2006 09:39:25 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id 23F0A43D49 for ; Sun, 17 Sep 2006 09:39:25 +0000 (GMT) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.6/8.13.6) with ESMTP id k8H9dPvS097853 for ; Sun, 17 Sep 2006 09:39:25 GMT (envelope-from hselasky@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.6/8.13.4/Submit) id k8H9dORn097850 for perforce@freebsd.org; Sun, 17 Sep 2006 09:39:24 GMT (envelope-from hselasky@FreeBSD.org) Date: Sun, 17 Sep 2006 09:39:24 GMT Message-Id: <200609170939.k8H9dORn097850@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky To: Perforce Change Reviews Cc: Subject: PERFORCE change 106227 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 17 Sep 2006 09:39:26 -0000 http://perforce.freebsd.org/chv.cgi?CH=106227 Change 106227 by hselasky@hselasky_mini_itx on 2006/09/17 09:38:36 Finished reworking "ubtbcmfw". Please test! Affected files ... .. //depot/projects/usb/src/sys/netgraph/bluetooth/drivers/ubtbcmfw/ubtbcmfw.c#2 edit Differences ... ==== //depot/projects/usb/src/sys/netgraph/bluetooth/drivers/ubtbcmfw/ubtbcmfw.c#2 (text+ko) ==== @@ -33,20 +33,14 @@ #include #include -#include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include #include -#include -#include +#include #include "usbdevs.h" @@ -56,81 +50,141 @@ #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) +#define UBTBCMFW_T_MAX 4 /* units */ struct ubtbcmfw_softc { - USBBASEDEVICE 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; + struct usb_cdev sc_cdev; + struct mtx sc_mtx; + struct usbd_memory_wait sc_mem_wait; + + device_t sc_dev; + struct usbd_device *sc_udev; + struct usbd_xfer *sc_xfer[UBTBCMFW_T_MAX]; + + u_int8_t sc_flags; +#define UBTBCMFW_FLAG_WRITE_STALL 0x01 +#define UBTBCMFW_FLAG_READ_STALL 0x02 }; -typedef struct ubtbcmfw_softc *ubtbcmfw_softc_p; +#define UBTBCMFW_BSIZE 1024 +#define UBTBCMFW_IFQ_MAXLEN 2 + +/* prototypes */ + +static device_probe_t ubtbcmfw_probe; +static device_attach_t ubtbcmfw_attach; +static device_detach_t ubtbcmfw_detach; + +static void +ubtbcmfw_write_callback(struct usbd_xfer *xfer); + +static void +ubtbcmfw_write_clear_stall_callback(struct usbd_xfer *xfer); + +static void +ubtbcmfw_read_callback(struct usbd_xfer *xfer); + +static void +ubtbcmfw_read_clear_stall_callback(struct usbd_xfer *xfer); + +static void +ubtbcmfw_start_read(struct usb_cdev *cdev); + +static void +ubtbcmfw_stop_read(struct usb_cdev *cdev); + +static void +ubtbcmfw_start_write(struct usb_cdev *cdev); + +static void +ubtbcmfw_stop_write(struct usb_cdev *cdev); + +static int32_t +ubtbcmfw_open(struct usb_cdev *cdev, int32_t fflags, + int32_t devtype, struct thread *td); +static int32_t +ubtbcmfw_ioctl(struct usb_cdev *cdev, u_long cmd, caddr_t data, + int32_t fflags, struct thread *td); + +static const struct usbd_config ubtbcmfw_config[UBTBCMFW_T_MAX] = { -/* - * Device methods - */ + [0] = { + .type = UE_BULK, + .endpoint = 0x02, /* fixed */ + .direction = UE_DIR_OUT, + .bufsize = UBTBCMFW_BSIZE, + .flags = 0, + .callback = &ubtbcmfw_write_callback, + }, -#define UBTBCMFW_UNIT(n) ((minor(n) >> 4) & 0xf) -#define UBTBCMFW_ENDPOINT(n) (minor(n) & 0xf) -#define UBTBCMFW_MINOR(u, e) (((u) << 4) | (e)) -#define UBTBCMFW_BSIZE 1024 + [1] = { + .type = UE_INTERRUPT, + .endpoint = 0x01, /* fixed */ + .direction = UE_DIR_IN, + .bufsize = UBTBCMFW_BSIZE, + .flags = USBD_SHORT_XFER_OK, + .callback = &ubtbcmfw_read_callback, + }, -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; + [2] = { + .type = UE_CONTROL, + .endpoint = 0x00, /* Control pipe */ + .direction = -1, + .bufsize = sizeof(usb_device_request_t), + .flags = USBD_USE_DMA, + .callback = &ubtbcmfw_write_clear_stall_callback, + .timeout = 1000, /* 1 second */ + }, -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", + [3] = { + .type = UE_CONTROL, + .endpoint = 0x00, /* Control pipe */ + .direction = -1, + .bufsize = sizeof(usb_device_request_t), + .flags = USBD_USE_DMA, + .callback = &ubtbcmfw_read_clear_stall_callback, + .timeout = 1000, /* 1 second */ + }, }; /* * Module */ -USB_DECLARE_DRIVER(ubtbcmfw); -DRIVER_MODULE(ubtbcmfw, uhub, ubtbcmfw_driver, ubtbcmfw_devclass, +static devclass_t ubtbcmfw_devclass; + +static device_method_t ubtbcmfw_methods[] = { + DEVMETHOD(device_probe, ubtbcmfw_probe), + DEVMETHOD(device_attach, ubtbcmfw_attach), + DEVMETHOD(device_detach, ubtbcmfw_detach), + { 0, 0 } +}; + +static driver_t ubtbcmfw_driver = { + .name = "ubtbcmfw", + .methods = ubtbcmfw_methods, + .size = sizeof(struct ubtbcmfw_softc), +}; + +DRIVER_MODULE(ubtbcmfw, uhub, ubtbcmfw_driver, ubtbcmfw_devclass, usbd_driver_load, 0); +MODULE_DEPEND(ubtbcmfw, usb, 1, 1, 1); /* * Probe for a USB Bluetooth device */ -USB_MATCH(ubtbcmfw) +static int +ubtbcmfw_probe(device_t dev) { -#define USB_PRODUCT_BROADCOM_BCM2033NF 0x2033 + struct usb_attach_arg *uaa = device_get_ivars(dev); - USB_MATCH_START(ubtbcmfw, uaa); - if (uaa->iface != NULL) return (UMATCH_NONE); /* Match the boot device. */ if (uaa->vendor == USB_VENDOR_BROADCOM && - uaa->product == USB_PRODUCT_BROADCOM_BCM2033NF) + uaa->product == USB_PRODUCT_BROADCOM_BCM2033) return (UMATCH_VENDOR_PRODUCT); return (UMATCH_NONE); @@ -140,364 +194,273 @@ * Attach the device */ -USB_ATTACH(ubtbcmfw) +static int +ubtbcmfw_attach(device_t dev) { - USB_ATTACH_START(ubtbcmfw, sc, uaa); - usbd_interface_handle iface; - usbd_status err; - char devinfo[1024]; + struct usb_attach_arg *uaa = device_get_ivars(dev); + struct ubtbcmfw_softc *sc = device_get_softc(dev); + int32_t err; + const char *p_buf[4]; + char buf_1[32]; + char buf_2[32]; + char buf_3[32]; + + if (sc == NULL) { + return ENOMEM; + } + sc->sc_dev = dev; sc->sc_udev = uaa->device; - usbd_devinfo(sc->sc_udev, 0, devinfo); - USB_ATTACH_SETUP; - printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo); + + usbd_set_desc(dev, 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; + mtx_init(&(sc->sc_mtx), "ubtbcmfw lock", NULL, MTX_DEF|MTX_RECURSE); err = usbd_set_config_no(sc->sc_udev, UBTBCMFW_CONFIG_NO, 1); if (err) { - printf("%s: setting config no failed. %s\n", - USBDEVNAME(sc->sc_dev), usbd_errstr(err)); - goto bad; + device_printf(dev, "setting config no failed, err=%s\n", + usbd_errstr(err)); + goto detach;; } - err = usbd_device2interface_handle(sc->sc_udev, UBTBCMFW_IFACE_IDX, - &iface); + err = usbd_transfer_setup(uaa->device, UBTBCMFW_IFACE_IDX, + sc->sc_xfer, ubtbcmfw_config, UBTBCMFW_T_MAX, + sc, &(sc->sc_mtx), &(sc->sc_mem_wait)); if (err) { - printf("%s: getting interface handle failed. %s\n", - USBDEVNAME(sc->sc_dev), usbd_errstr(err)); - goto bad; + device_printf(dev, "allocating USB transfers " + "failed, err=%s\n", usbd_errstr(err)); + goto detach; } - /* 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", - USBDEVNAME(sc->sc_dev), usbd_errstr(err)); - goto bad; - } + snprintf(buf_1, sizeof(buf_1), "%s", + device_get_nameunit(dev)); + + snprintf(buf_2, sizeof(buf_2), "%s.1", + device_get_nameunit(dev)); + + snprintf(buf_3, sizeof(buf_3), "%s.2", + device_get_nameunit(dev)); + + p_buf[0] = buf_1; + p_buf[1] = buf_2; + p_buf[2] = buf_3; + p_buf[3] = NULL; + + sc->sc_cdev.sc_start_read = &ubtbcmfw_start_read; + sc->sc_cdev.sc_start_write = &ubtbcmfw_start_write; + sc->sc_cdev.sc_stop_read = &ubtbcmfw_stop_read; + sc->sc_cdev.sc_stop_write = &ubtbcmfw_stop_write; + sc->sc_cdev.sc_open = &ubtbcmfw_open; + sc->sc_cdev.sc_ioctl = &ubtbcmfw_ioctl; + sc->sc_cdev.sc_flags |= (USB_CDEV_FLAG_FWD_SHORT| + USB_CDEV_FLAG_WAKEUP_RD_IMMED| + USB_CDEV_FLAG_WAKEUP_WR_IMMED); - err = usbd_open_pipe(iface, UBTBCMFW_BULK_OUT_EP, 0, - &sc->sc_bulk_out_pipe); + err = usb_cdev_attach(&(sc->sc_cdev), sc, &(sc->sc_mtx), p_buf, + UID_ROOT, GID_OPERATOR, 0644, + UBTBCMFW_BSIZE, UBTBCMFW_IFQ_MAXLEN, + UBTBCMFW_BSIZE, UBTBCMFW_IFQ_MAXLEN); if (err) { - printf("%s: open bulk out failed. %s\n", - USBDEVNAME(sc->sc_dev), usbd_errstr(err)); - goto bad; + goto detach; } - /* Create device nodes */ - sc->sc_ctrl_dev = make_dev(&ubtbcmfw_cdevsw, - UBTBCMFW_MINOR(USBDEVUNIT(sc->sc_dev), 0), - UID_ROOT, GID_OPERATOR, 0644, - "%s", USBDEVNAME(sc->sc_dev)); + return 0; /* success */ - sc->sc_intr_in_dev = make_dev(&ubtbcmfw_cdevsw, - UBTBCMFW_MINOR(USBDEVUNIT(sc->sc_dev), UBTBCMFW_INTR_IN), - UID_ROOT, GID_OPERATOR, 0644, - "%s.%d", USBDEVNAME(sc->sc_dev), UBTBCMFW_INTR_IN); - - sc->sc_bulk_out_dev = make_dev(&ubtbcmfw_cdevsw, - UBTBCMFW_MINOR(USBDEVUNIT(sc->sc_dev), UBTBCMFW_BULK_OUT), - UID_ROOT, GID_OPERATOR, 0644, - "%s.%d", USBDEVNAME(sc->sc_dev), UBTBCMFW_BULK_OUT); - - USB_ATTACH_SUCCESS_RETURN; -bad: - ubtbcmfw_detach(self); - - USB_ATTACH_ERROR_RETURN; + detach: + ubtbcmfw_detach(dev); + return ENOMEM; /* failure */ } /* * Detach the device */ -USB_DETACH(ubtbcmfw) +static int +ubtbcmfw_detach(device_t dev) { - USB_DETACH_START(ubtbcmfw, sc); + struct ubtbcmfw_softc *sc = device_get_softc(dev); + + usb_cdev_detach(&(sc->sc_cdev)); - sc->sc_dying = 1; + usbd_transfer_unsetup(sc->sc_xfer, UBTBCMFW_T_MAX); - if (-- sc->sc_refcnt >= 0) { - if (sc->sc_intr_in_pipe != NULL) - usbd_abort_pipe(sc->sc_intr_in_pipe); + usbd_transfer_drain(&(sc->sc_mem_wait), &(sc->sc_mtx)); - if (sc->sc_bulk_out_pipe != NULL) - usbd_abort_pipe(sc->sc_bulk_out_pipe); + mtx_destroy(&(sc->sc_mtx)); - usb_detach_wait(USBDEV(sc->sc_dev)); - } + return (0); +} - /* Destroy device nodes */ - if (sc->sc_bulk_out_dev != NULL) { - destroy_dev(sc->sc_bulk_out_dev); - sc->sc_bulk_out_dev = NULL; - } +static void +ubtbcmfw_write_callback(struct usbd_xfer *xfer) +{ + struct ubtbcmfw_softc *sc = xfer->priv_sc; + u_int32_t actlen; - if (sc->sc_intr_in_dev != NULL) { - destroy_dev(sc->sc_intr_in_dev); - sc->sc_intr_in_dev = NULL; - } + USBD_CHECK_STATUS(xfer); - if (sc->sc_ctrl_dev != NULL) { - destroy_dev(sc->sc_ctrl_dev); - sc->sc_ctrl_dev = NULL; + tr_transferred: + tr_setup: + if (sc->sc_flags & UBTBCMFW_FLAG_WRITE_STALL) { + usbd_transfer_start(sc->sc_xfer[2]); + return; } + if (usb_cdev_get_data(&(sc->sc_cdev), xfer->buffer, + UBTBCMFW_BSIZE, &actlen, 0)) { - /* Close pipes */ - if (sc->sc_intr_in_pipe != NULL) { - usbd_close_pipe(sc->sc_intr_in_pipe); - sc->sc_intr_in_pipe = NULL; + xfer->length = actlen; + usbd_start_hardware(xfer); } + return; - if (sc->sc_bulk_out_pipe != NULL) { - usbd_close_pipe(sc->sc_bulk_out_pipe); - sc->sc_intr_in_pipe = NULL; + tr_error: + if (xfer->error != USBD_CANCELLED) { + /* try to clear stall first */ + sc->sc_flags |= UBTBCMFW_FLAG_WRITE_STALL; + usbd_transfer_start(sc->sc_xfer[2]); } - - return (0); + return; } -/* - * Open endpoint device - * XXX FIXME softc locking - */ - -Static int -ubtbcmfw_open(struct cdev *dev, int flag, int mode, usb_proc_ptr p) +static void +ubtbcmfw_write_clear_stall_callback(struct usbd_xfer *xfer) { - ubtbcmfw_softc_p sc = NULL; - int error = 0; + struct ubtbcmfw_softc *sc = xfer->priv_sc; + struct usbd_xfer *xfer_other = sc->sc_xfer[0]; - /* checks for sc != NULL */ - USB_GET_SC_OPEN(ubtbcmfw, UBTBCMFW_UNIT(dev), sc); - if (sc->sc_dying) - return (ENXIO); + USBD_CHECK_STATUS(xfer); - switch (UBTBCMFW_ENDPOINT(dev)) { - case USB_CONTROL_ENDPOINT: - if (!(sc->sc_flags & UBTBCMFW_CTRL_DEV)) - sc->sc_flags |= UBTBCMFW_CTRL_DEV; - else - error = EBUSY; - break; + tr_setup: + /* start clear stall */ + usbd_clear_stall_tr_setup(xfer, xfer_other); + return; - 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; + tr_transferred: + usbd_clear_stall_tr_transferred(xfer, xfer_other); - 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; + sc->sc_flags &= ~UBTBCMFW_FLAG_WRITE_STALL; + usbd_transfer_start(xfer_other); + return; - default: - error = ENXIO; - break; - } - - return (error); + tr_error: + /* bomb out */ + sc->sc_flags &= ~UBTBCMFW_FLAG_WRITE_STALL; + usb_cdev_get_data_error(&(sc->sc_cdev)); + return; } -/* - * Close endpoint device - * XXX FIXME softc locking - */ - -Static int -ubtbcmfw_close(struct cdev *dev, int flag, int mode, usb_proc_ptr p) +static void +ubtbcmfw_read_callback(struct usbd_xfer *xfer) { - ubtbcmfw_softc_p sc = NULL; + struct ubtbcmfw_softc *sc = xfer->priv_sc; + struct usbd_mbuf *m; - USB_GET_SC(ubtbcmfw, UBTBCMFW_UNIT(dev), sc); - if (sc == NULL) - return (ENXIO); + USBD_CHECK_STATUS(xfer); - switch (UBTBCMFW_ENDPOINT(dev)) { - case USB_CONTROL_ENDPOINT: - sc->sc_flags &= ~UBTBCMFW_CTRL_DEV; - break; + tr_transferred: + usb_cdev_put_data(&(sc->sc_cdev), xfer->buffer, xfer->actlen, 1); - case UBTBCMFW_INTR_IN: - if (sc->sc_intr_in_pipe != NULL) - usbd_abort_pipe(sc->sc_intr_in_pipe); + tr_setup: + if (sc->sc_flags & UBTBCMFW_FLAG_READ_STALL) { + usbd_transfer_start(sc->sc_xfer[3]); + return; + } - sc->sc_flags &= ~UBTBCMFW_INTR_IN_DEV; - break; + USBD_IF_POLL(&sc->sc_cdev.sc_rdq_free, m); - case UBTBCMFW_BULK_OUT: - if (sc->sc_bulk_out_pipe != NULL) - usbd_abort_pipe(sc->sc_bulk_out_pipe); + if (m) { + usbd_start_hardware(xfer); + } + return; - sc->sc_flags &= ~UBTBCMFW_BULK_OUT_DEV; - break; + tr_error: + if (xfer->error != USBD_CANCELLED) { + /* try to clear stall first */ + sc->sc_flags |= UBTBCMFW_FLAG_READ_STALL; + usbd_transfer_start(sc->sc_xfer[3]); } - - return (0); + return; } -/* - * Read from the endpoint device - * XXX FIXME softc locking - */ - -Static int -ubtbcmfw_read(struct cdev *dev, struct uio *uio, int flag) +static void +ubtbcmfw_read_clear_stall_callback(struct usbd_xfer *xfer) { - ubtbcmfw_softc_p sc = NULL; - u_int8_t buf[UBTBCMFW_BSIZE]; - usbd_xfer_handle xfer; - usbd_status err; - int n, tn, error = 0; + struct ubtbcmfw_softc *sc = xfer->priv_sc; + struct usbd_xfer *xfer_other = sc->sc_xfer[1]; - USB_GET_SC(ubtbcmfw, UBTBCMFW_UNIT(dev), sc); - if (sc == NULL || sc->sc_dying) - return (ENXIO); + USBD_CHECK_STATUS(xfer); - if (UBTBCMFW_ENDPOINT(dev) != UBTBCMFW_INTR_IN) - return (EOPNOTSUPP); - if (sc->sc_intr_in_pipe == NULL) - return (ENXIO); + tr_setup: + /* start clear stall */ + usbd_clear_stall_tr_setup(xfer, xfer_other); + return; - xfer = usbd_alloc_xfer(sc->sc_udev); - if (xfer == NULL) - return (ENOMEM); + tr_transferred: + usbd_clear_stall_tr_transferred(xfer, xfer_other); - sc->sc_refcnt ++; + sc->sc_flags &= ~UBTBCMFW_FLAG_READ_STALL; + usbd_transfer_start(xfer_other); + return; - 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; + tr_error: + /* bomb out */ + sc->sc_flags &= ~UBTBCMFW_FLAG_READ_STALL; + usb_cdev_put_data_error(&(sc->sc_cdev)); + return; +} - case USBD_INTERRUPTED: - error = EINTR; - break; +static void +ubtbcmfw_start_read(struct usb_cdev *cdev) +{ + struct ubtbcmfw_softc *sc = cdev->sc_priv_ptr; + usbd_transfer_start(sc->sc_xfer[1]); + return; +} - case USBD_TIMEOUT: - error = ETIMEDOUT; - break; +static void +ubtbcmfw_stop_read(struct usb_cdev *cdev) +{ + struct ubtbcmfw_softc *sc = cdev->sc_priv_ptr; + usbd_transfer_stop(sc->sc_xfer[3]); + usbd_transfer_stop(sc->sc_xfer[1]); + return; +} - default: - error = EIO; - break; - } +static void +ubtbcmfw_start_write(struct usb_cdev *cdev) +{ + struct ubtbcmfw_softc *sc = cdev->sc_priv_ptr; + usbd_transfer_start(sc->sc_xfer[0]); + return; +} - if (error != 0 || tn < n) - break; - } - - usbd_free_xfer(xfer); - - if (-- sc->sc_refcnt < 0) - usb_detach_wakeup(USBDEV(sc->sc_dev)); - - return (error); +static void +ubtbcmfw_stop_write(struct usb_cdev *cdev) +{ + struct ubtbcmfw_softc *sc = cdev->sc_priv_ptr; + usbd_transfer_stop(sc->sc_xfer[2]); + usbd_transfer_stop(sc->sc_xfer[0]); + return; } -/* - * Write into the endpoint device - * XXX FIXME softc locking - */ - -Static int -ubtbcmfw_write(struct cdev *dev, struct uio *uio, int flag) +static int32_t +ubtbcmfw_open(struct usb_cdev *cdev, int32_t fflags, + int32_t devtype, struct thread *td) { - ubtbcmfw_softc_p sc = NULL; - u_int8_t buf[UBTBCMFW_BSIZE]; - usbd_xfer_handle xfer; - usbd_status err; - int n, error = 0; + struct ubtbcmfw_softc *sc = cdev->sc_priv_ptr; - USB_GET_SC(ubtbcmfw, UBTBCMFW_UNIT(dev), sc); - if (sc == NULL || sc->sc_dying) - return (ENXIO); - - if (UBTBCMFW_ENDPOINT(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; + if (fflags & FWRITE) { + sc->sc_flags |= UBTBCMFW_FLAG_WRITE_STALL; } - - usbd_free_xfer(xfer); - - if (-- sc->sc_refcnt < 0) - usb_detach_wakeup(USBDEV(sc->sc_dev)); - - return (error); + return 0; } -/* - * 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, usb_proc_ptr p) +static int32_t +ubtbcmfw_ioctl(struct usb_cdev *cdev, u_long cmd, caddr_t data, + int32_t fflags, struct thread *td) { - ubtbcmfw_softc_p sc = NULL; - int error = 0; - - USB_GET_SC(ubtbcmfw, UBTBCMFW_UNIT(dev), sc); - if (sc == NULL || sc->sc_dying) - return (ENXIO); - - if (UBTBCMFW_ENDPOINT(dev) != USB_CONTROL_ENDPOINT) - return (EOPNOTSUPP); - - sc->sc_refcnt ++; + struct ubtbcmfw_softc *sc = cdev->sc_priv_ptr; + int32_t error = 0; switch (cmd) { case USB_GET_DEVICE_DESC: @@ -510,47 +473,5 @@ break; } - if (-- sc->sc_refcnt < 0) - usb_detach_wakeup(USBDEV(sc->sc_dev)); - return (error); } - -/* - * Poll the endpoint device - * XXX FIXME softc locking - */ - -Static int -ubtbcmfw_poll(struct cdev *dev, int events, usb_proc_ptr p) -{ - ubtbcmfw_softc_p sc = NULL; - int revents = 0; - - USB_GET_SC(ubtbcmfw, UBTBCMFW_UNIT(dev), sc); - if (sc == NULL) - return (ENXIO); - - switch (UBTBCMFW_ENDPOINT(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); -} -