diff options
Diffstat (limited to 'sys/dev/usb/usb_dev.c')
-rw-r--r-- | sys/dev/usb/usb_dev.c | 114 |
1 files changed, 62 insertions, 52 deletions
diff --git a/sys/dev/usb/usb_dev.c b/sys/dev/usb/usb_dev.c index 512b1f8..d3d98ff 100644 --- a/sys/dev/usb/usb_dev.c +++ b/sys/dev/usb/usb_dev.c @@ -72,7 +72,8 @@ SYSCTL_INT(_hw_usb2_dev, OID_AUTO, debug, CTLFLAG_RW, /* prototypes */ -static int usb2_fifo_open(struct usb2_fifo *, int); +static int usb2_fifo_open(struct usb2_cdev_privdata *, + struct usb2_fifo *, int); static void usb2_fifo_close(struct usb2_fifo *, int); static void usb2_dev_init(void *); static void usb2_dev_init_post(void *); @@ -160,7 +161,6 @@ usb2_ref_device(struct usb2_cdev_privdata* cpd, int need_uref) { struct usb2_fifo **ppf; struct usb2_fifo *f; - int dev_ep_index; DPRINTFN(2, "usb2_ref_device, cpd=%p need uref=%d\n", cpd, need_uref); @@ -180,7 +180,6 @@ usb2_ref_device(struct usb2_cdev_privdata* cpd, int need_uref) goto error; } /* check if we are doing an open */ - dev_ep_index = cpd->ep_addr; if (cpd->fflags == 0) { /* set defaults */ cpd->txfifo = NULL; @@ -200,15 +199,12 @@ usb2_ref_device(struct usb2_cdev_privdata* cpd, int need_uref) cpd->is_write = 1; /* ref */ if (f == NULL || f->refcount == USB_FIFO_REF_MAX) goto error; + if (f->curr_cpd != cpd) + goto error; /* check if USB-FS is active */ if (f->fs_ep_max != 0) { cpd->is_usbfs = 1; } - /* - * Get real endpoint index associated with - * this FIFO: - */ - dev_ep_index = f->dev_ep_index; } else { cpd->txfifo = NULL; cpd->is_write = 0; /* no ref */ @@ -222,15 +218,12 @@ usb2_ref_device(struct usb2_cdev_privdata* cpd, int need_uref) cpd->is_read = 1; /* ref */ if (f == NULL || f->refcount == USB_FIFO_REF_MAX) goto error; + if (f->curr_cpd != cpd) + goto error; /* check if USB-FS is active */ if (f->fs_ep_max != 0) { cpd->is_usbfs = 1; } - /* - * Get real endpoint index associated with - * this FIFO: - */ - dev_ep_index = f->dev_ep_index; } else { cpd->rxfifo = NULL; cpd->is_read = 0; /* no ref */ @@ -434,7 +427,7 @@ usb2_fifo_create(struct usb2_cdev_privdata *cpd) /* wrong endpoint index */ continue; } - if (f->opened) { + if (f->curr_cpd != NULL) { /* FIFO is opened */ is_busy = 1; continue; @@ -451,7 +444,7 @@ usb2_fifo_create(struct usb2_cdev_privdata *cpd) /* wrong endpoint index */ continue; } - if (f->opened) { + if (f->curr_cpd != NULL) { /* FIFO is opened */ is_busy = 1; continue; @@ -466,10 +459,20 @@ usb2_fifo_create(struct usb2_cdev_privdata *cpd) if (no_null == 0) { if (ep >= (USB_EP_MAX / 2)) { /* we don't create any endpoints in this range */ - DPRINTFN(5, "dev_ep_index out of range\n"); + DPRINTFN(5, "ep out of range\n"); return (is_busy ? EBUSY : EINVAL); } } + + if ((ep != 0) && is_busy) { + /* + * Only the default control endpoint is allowed to be + * opened multiple times! + */ + DPRINTFN(5, "busy\n"); + return (EBUSY); + } + /* Check TX FIFO */ if (is_tx && (udev->fifo[n + USB_FIFO_TX] == NULL)) { @@ -639,7 +642,8 @@ usb2_dev_get_pipe(struct usb2_device *udev, uint8_t ep_index, uint8_t dir) * Else: Failure *------------------------------------------------------------------------*/ static int -usb2_fifo_open(struct usb2_fifo *f, int fflags) +usb2_fifo_open(struct usb2_cdev_privdata *cpd, + struct usb2_fifo *f, int fflags) { int err; @@ -660,11 +664,14 @@ usb2_fifo_open(struct usb2_fifo *f, int fflags) /* check if we are already opened */ /* we don't need any locks when checking this variable */ - if (f->opened) { + if (f->curr_cpd != NULL) { err = EBUSY; goto done; } + /* reset short flag before open */ + f->flag_short = 0; + /* call open method */ err = (f->methods->f_open) (f, fflags); if (err) { @@ -690,9 +697,9 @@ usb2_fifo_open(struct usb2_fifo *f, int fflags) /* reset ASYNC proc flag */ f->async_p = NULL; - /* flag the fifo as opened to prevent others */ mtx_lock(&usb2_ref_lock); - f->opened = 1; + /* flag the fifo as opened to prevent others */ + f->curr_cpd = cpd; mtx_unlock(&usb2_ref_lock); /* reset queue */ @@ -733,14 +740,14 @@ usb2_fifo_close(struct usb2_fifo *f, int fflags) int err; /* check if we are not opened */ - if (!f->opened) { + if (f->curr_cpd == NULL) { /* nothing to do - already closed */ return; } mtx_lock(f->priv_mtx); - /* clear current file flag */ - f->opened = 0; + /* clear current cdev private data pointer */ + f->curr_cpd = NULL; /* check if we are selected */ if (f->flag_isselect) { @@ -834,21 +841,6 @@ usb2_open(struct cdev *dev, int fflags, int devtype, struct thread *td) } cpd->fflags = fflags; /* access mode for open lifetime */ - /* Check if the endpoint is already open, we always allow EP0 */ - if (ep > 0) { - if ((fflags & FREAD && cpd->udev->ep_rd_opened & (1 << ep)) || - (fflags & FWRITE && cpd->udev->ep_wr_opened & (1 << ep))) { - DPRINTFN(2, "endpoint already open\n"); - usb2_unref_device(cpd); - free(cpd, M_USBDEV); - return (EBUSY); - } - if (fflags & FREAD) - cpd->udev->ep_rd_opened |= (1 << ep); - if (fflags & FWRITE) - cpd->udev->ep_wr_opened |= (1 << ep); - } - /* create FIFOs, if any */ err = usb2_fifo_create(cpd); /* check for error */ @@ -859,7 +851,7 @@ usb2_open(struct cdev *dev, int fflags, int devtype, struct thread *td) return (err); } if (fflags & FREAD) { - err = usb2_fifo_open(cpd->rxfifo, fflags); + err = usb2_fifo_open(cpd, cpd->rxfifo, fflags); if (err) { DPRINTFN(2, "read open failed\n"); usb2_unref_device(cpd); @@ -868,7 +860,7 @@ usb2_open(struct cdev *dev, int fflags, int devtype, struct thread *td) } } if (fflags & FWRITE) { - err = usb2_fifo_open(cpd->txfifo, fflags); + err = usb2_fifo_open(cpd, cpd->txfifo, fflags); if (err) { DPRINTFN(2, "write open failed\n"); if (fflags & FREAD) { @@ -892,27 +884,20 @@ static void usb2_close(void *arg) { struct usb2_cdev_privdata *cpd = arg; - struct usb2_device *udev; int err; - DPRINTFN(2, "usb2_close, cpd=%p\n", cpd); + DPRINTFN(2, "cpd=%p\n", cpd); err = usb2_ref_device(cpd, 1); if (err) { free(cpd, M_USBDEV); return; } - - udev = cpd->udev; if (cpd->fflags & FREAD) { usb2_fifo_close(cpd->rxfifo, cpd->fflags); - /* clear read bitmask */ - udev->ep_rd_opened &= ~(1 << cpd->ep_addr); } if (cpd->fflags & FWRITE) { usb2_fifo_close(cpd->txfifo, cpd->fflags); - /* clear write bitmask */ - udev->ep_wr_opened &= ~(1 << cpd->ep_addr); } usb2_unref_device(cpd); @@ -1621,7 +1606,6 @@ usb2_fifo_attach(struct usb2_device *udev, void *priv_sc, /* initialise FIFO structures */ f_tx->fifo_index = n + USB_FIFO_TX; - f_tx->dev_ep_index = (n / 2) + (USB_EP_MAX / 2); f_tx->priv_mtx = priv_mtx; f_tx->priv_sc0 = priv_sc; f_tx->methods = pm; @@ -1629,7 +1613,6 @@ usb2_fifo_attach(struct usb2_device *udev, void *priv_sc, f_tx->udev = udev; f_rx->fifo_index = n + USB_FIFO_RX; - f_rx->dev_ep_index = (n / 2) + (USB_EP_MAX / 2); f_rx->priv_mtx = priv_mtx; f_rx->priv_sc0 = priv_sc; f_rx->methods = pm; @@ -1684,12 +1667,13 @@ usb2_fifo_attach(struct usb2_device *udev, void *priv_sc, pd->bus_index = device_get_unit(udev->bus->bdev); pd->dev_index = udev->device_index; pd->ep_addr = -1; /* not an endpoint */ - pd->fifo_index = f_tx->fifo_index; + pd->fifo_index = f_tx->fifo_index & f_rx->fifo_index; pd->mode = FREAD|FWRITE; /* Now, create the device itself */ f_sc->dev = make_dev(&usb2_devsw, 0, uid, gid, mode, devname); + /* XXX setting si_drv1 and creating the device is not atomic! */ f_sc->dev->si_drv1 = pd; } @@ -1762,7 +1746,9 @@ usb2_fifo_detach(struct usb2_fifo_sc *f_sc) f_sc->fp[USB_FIFO_RX] = NULL; if (f_sc->dev != NULL) { - destroy_dev_sched_cb(f_sc->dev, usb2_fifo_cleanup, f_sc->dev->si_drv1); + destroy_dev_sched_cb(f_sc->dev, + usb2_fifo_cleanup, f_sc->dev->si_drv1); + f_sc->dev = NULL; } DPRINTFN(2, "detached %p\n", f_sc); @@ -1949,6 +1935,13 @@ usb2_fifo_get_data(struct usb2_fifo *f, struct usb2_page_cache *pc, break; } if (f->flag_flushing) { + /* check if we should send a short packet */ + if (f->flag_short != 0) { + f->flag_short = 0; + tr_data = 1; + break; + } + /* flushing complete */ f->flag_flushing = 0; usb2_fifo_wakeup(f); } @@ -2007,6 +2000,13 @@ usb2_fifo_get_data_linear(struct usb2_fifo *f, void *ptr, break; } if (f->flag_flushing) { + /* check if we should send a short packet */ + if (f->flag_short != 0) { + f->flag_short = 0; + tr_data = 1; + break; + } + /* flushing complete */ f->flag_flushing = 0; usb2_fifo_wakeup(f); } @@ -2186,3 +2186,13 @@ usb2_read_symlink(uint8_t *user_ptr, uint32_t startentry, uint32_t user_len) sx_unlock(&usb2_sym_lock); return (error); } + +void +usb2_fifo_set_close_zlp(struct usb2_fifo *f, uint8_t onoff) +{ + if (f == NULL) + return; + + /* send a Zero Length Packet, ZLP, before close */ + f->flag_short = onoff; +} |