diff options
author | thompsa <thompsa@FreeBSD.org> | 2009-03-17 01:46:40 +0000 |
---|---|---|
committer | thompsa <thompsa@FreeBSD.org> | 2009-03-17 01:46:40 +0000 |
commit | 152e3d301d04fa2aa6bf7600705f0170d2ba27c0 (patch) | |
tree | 85006ed8a85d5213a94fe0bf4564ece9a33ebbfe /sys/dev/usb | |
parent | aaec37fdbe35075f7a6fb6c59c1541265361965d (diff) | |
download | FreeBSD-src-152e3d301d04fa2aa6bf7600705f0170d2ba27c0.zip FreeBSD-src-152e3d301d04fa2aa6bf7600705f0170d2ba27c0.tar.gz |
MFp4 //depot/projects/usb 159225,159241,159292
Fix regression issue in the USB file system interface.
- Use cdev_privdata pointer as indicator of correct file handle.
- Remove redundant FIFO opened flags.
Don't send ZLP at close for ulpt and uscanner devices as this causes some
models to stop working. This reverts back to the USB1 behaviour.
Submitted by: Hans Petter Selasky
Diffstat (limited to 'sys/dev/usb')
-rw-r--r-- | sys/dev/usb/image/uscanner.c | 2 | ||||
-rw-r--r-- | sys/dev/usb/serial/ulpt.c | 6 | ||||
-rw-r--r-- | sys/dev/usb/usb_dev.c | 114 | ||||
-rw-r--r-- | sys/dev/usb/usb_dev.h | 6 | ||||
-rw-r--r-- | sys/dev/usb/usb_device.h | 2 |
5 files changed, 70 insertions, 60 deletions
diff --git a/sys/dev/usb/image/uscanner.c b/sys/dev/usb/image/uscanner.c index 916295e..946b35e 100644 --- a/sys/dev/usb/image/uscanner.c +++ b/sys/dev/usb/image/uscanner.c @@ -149,7 +149,7 @@ static const struct usb2_config uscanner_config[USCANNER_N_TRANSFER] = { .endpoint = UE_ADDR_ANY, .direction = UE_DIR_OUT, .mh.bufsize = USCANNER_BSIZE, - .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,.proxy_buffer = 1,.force_short_xfer = 1,}, + .mh.flags = {.pipe_bof = 1,.proxy_buffer = 1,}, .mh.callback = &uscanner_write_callback, }, diff --git a/sys/dev/usb/serial/ulpt.c b/sys/dev/usb/serial/ulpt.c index 2ecce99..56ff9fc 100644 --- a/sys/dev/usb/serial/ulpt.c +++ b/sys/dev/usb/serial/ulpt.c @@ -200,7 +200,8 @@ ulpt_write_callback(struct usb2_xfer *xfer) DPRINTF("no FIFO\n"); return; } - DPRINTF("state=0x%x\n", USB_GET_STATE(xfer)); + DPRINTF("state=0x%x actlen=%u\n", + USB_GET_STATE(xfer), xfer->actlen); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: @@ -208,7 +209,6 @@ ulpt_write_callback(struct usb2_xfer *xfer) tr_setup: if (usb2_fifo_get_data(f, xfer->frbuffers, 0, xfer->max_data_length, &actlen, 0)) { - xfer->frlengths[0] = actlen; usb2_start_hardware(xfer); } @@ -339,7 +339,7 @@ static const struct usb2_config ulpt_config[ULPT_N_TRANSFER] = { .endpoint = UE_ADDR_ANY, .direction = UE_DIR_OUT, .mh.bufsize = ULPT_BSIZE, - .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,.proxy_buffer = 1}, + .mh.flags = {.pipe_bof = 1,.proxy_buffer = 1}, .mh.callback = &ulpt_write_callback, }, 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; +} diff --git a/sys/dev/usb/usb_dev.h b/sys/dev/usb/usb_dev.h index 92be7af..e1c8b94 100644 --- a/sys/dev/usb/usb_dev.h +++ b/sys/dev/usb/usb_dev.h @@ -93,12 +93,12 @@ struct usb2_cdev_privdata { int bus_index; /* bus index */ int dev_index; /* device index */ int ep_addr; /* endpoint address */ + int fflags; uint8_t fifo_index; /* FIFO index */ uint8_t is_read; /* location has read access */ uint8_t is_write; /* location has write access */ uint8_t is_uref; /* USB refcount decr. needed */ uint8_t is_usbfs; /* USB-FS is active */ - int fflags; }; struct usb2_fs_privdata { @@ -130,7 +130,8 @@ struct usb2_fifo { struct usb2_xfer *xfer[2]; struct usb2_xfer **fs_xfer; struct mtx *priv_mtx; /* client data */ - int opened; /* set if FIFO is opened by a FILE */ + /* set if FIFO is opened by a FILE: */ + struct usb2_cdev_privdata *curr_cpd; void *priv_sc0; /* client data */ void *priv_sc1; /* client data */ void *queue_data; @@ -194,5 +195,6 @@ struct usb2_symlink *usb2_alloc_symlink(const char *target); void usb2_free_symlink(struct usb2_symlink *ps); int usb2_read_symlink(uint8_t *user_ptr, uint32_t startentry, uint32_t user_len); +void usb2_fifo_set_close_zlp(struct usb2_fifo *, uint8_t); #endif /* _USB2_DEV_H_ */ diff --git a/sys/dev/usb/usb_device.h b/sys/dev/usb/usb_device.h index 8ebf9e5..a6a5d79 100644 --- a/sys/dev/usb/usb_device.h +++ b/sys/dev/usb/usb_device.h @@ -127,8 +127,6 @@ struct usb2_device { uint32_t plugtime; /* copy of "ticks" */ - uint16_t ep_rd_opened; /* bitmask of endpoints opened */ - uint16_t ep_wr_opened; /* from the device nodes. */ uint16_t refcount; #define USB_DEV_REF_MAX 0xffff |