diff options
author | Brian Feldman <green@FreeBSD.org> | 2004-10-02 22:33:26 +0000 |
---|---|---|
committer | Brian Feldman <green@FreeBSD.org> | 2004-10-02 22:33:26 +0000 |
commit | df3d6ec928cae98368e1c5e64b139b4e9788839f (patch) | |
tree | f317089f2097755739485b8e465f8267f605181d /sys | |
parent | 4cb1b18827456c5fcc25802a90320ddd7f903c43 (diff) | |
download | src-df3d6ec928cae98368e1c5e64b139b4e9788839f.tar.gz src-df3d6ec928cae98368e1c5e64b139b4e9788839f.zip |
* When toggling short transfers on a bulk transfer endpoint, cancel and
restart the current waiting transfer. If this isn't done, the device's
next transfer (that we would like to do a short read on) is going to
return an error -- for short transfer.
* For bulk transfer endpoints, restore the maximum transfer length each
time a transfer is done, or the first short transfer will make all the
rest that size or smaller.
* Remove impossibilities (malloc(M_WAITOK) == NULL, &var == NULL).
Notes
Notes:
svn path=/head/; revision=136066
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/usb/ugen.c | 42 |
1 files changed, 22 insertions, 20 deletions
diff --git a/sys/dev/usb/ugen.c b/sys/dev/usb/ugen.c index 3cf3072a51e2..b0564d1dae8c 100644 --- a/sys/dev/usb/ugen.c +++ b/sys/dev/usb/ugen.c @@ -126,6 +126,7 @@ struct ugen_endpoint { usbd_xfer_handle xfer; int err; int len; + int maxlen; void *buf; int datardy; } bulkreq; @@ -421,7 +422,7 @@ ugenopen(struct cdev *dev, int flag, int mode, usb_proc_ptr p) for (dir = OUT; dir <= IN; dir++) { if (flag & (dir == OUT ? FWRITE : FREAD)) { sce = &sc->sc_endpoints[endpt][dir]; - if (sce == 0 || sce->edesc == 0) + if (sce->edesc == 0) return (ENXIO); } } @@ -480,18 +481,18 @@ ugenopen(struct cdev *dev, int flag, int mode, usb_proc_ptr p) if (isize == 0) /* shouldn't happen */ return (EINVAL); sce->bulkreq.buf = malloc(isize, M_USBDEV, M_WAITOK); - if (sce->bulkreq.buf == 0) - return (ENOMEM); + DPRINTFN(5, ("ugenopen: bulk endpt=%d,isize=%d\n", + endpt, isize)); sce->bulkreq.xfer = usbd_alloc_xfer(sc->sc_udev); if (sce->bulkreq.xfer == 0) { free(sce->bulkreq.buf, M_USBDEV); return (ENOMEM); } - sce->bulkreq.len = isize; + sce->bulkreq.maxlen = isize; sce->bulkreq.err = 0; sce->bulkreq.datardy = 0; usbd_setup_xfer(sce->bulkreq.xfer, sce->pipeh, sce, - sce->bulkreq.buf, sce->bulkreq.len, + sce->bulkreq.buf, sce->bulkreq.maxlen, sce->state & UGEN_SHORT_OK ? USBD_SHORT_XFER_OK : 0, sce->timeout, ugen_rdcb); @@ -587,7 +588,7 @@ ugenclose(struct cdev *dev, int flag, int mode, usb_proc_ptr p) if (!(flag & (dir == OUT ? FWRITE : FREAD))) continue; sce = &sc->sc_endpoints[endpt][dir]; - if (sce == NULL || sce->pipeh == NULL) + if (sce->pipeh == NULL) continue; DPRINTFN(5, ("ugenclose: endpt=%d dir=%d sce=%p\n", endpt, dir, sce)); @@ -680,9 +681,6 @@ ugen_do_read(struct ugen_softc *sc, int endpt, struct uio *uio, int flag) if (endpt == USB_CONTROL_ENDPOINT) return (ENODEV); - if (sce == NULL) - return (EINVAL); - if (sce->edesc == NULL) { printf("ugenread: no edesc\n"); return (EIO); @@ -756,7 +754,7 @@ ugen_do_read(struct ugen_softc *sc, int endpt, struct uio *uio, int flag) sce->bulkreq.datardy = 0; usbd_setup_xfer(sce->bulkreq.xfer, sce->pipeh, sce, - sce->bulkreq.buf, sce->bulkreq.len, + sce->bulkreq.buf, sce->bulkreq.maxlen, sce->state & UGEN_SHORT_OK ? USBD_SHORT_XFER_OK : 0, sce->timeout, ugen_rdcb); usbd_transfer(sce->bulkreq.xfer); @@ -845,9 +843,6 @@ ugen_do_write(struct ugen_softc *sc, int endpt, struct uio *uio, int flag) if (endpt == USB_CONTROL_ENDPOINT) return (ENODEV); - if (sce == NULL) - return (EINVAL); - if (sce->edesc == NULL) { printf("ugenwrite: no edesc\n"); return (EIO); @@ -963,7 +958,7 @@ USB_DETACH(ugen) for (i = 0; i < USB_MAX_ENDPOINTS; i++) { for (dir = OUT; dir <= IN; dir++) { sce = &sc->sc_endpoints[i][dir]; - if (sce && sce->pipeh) + if (sce->pipeh) usbd_abort_pipe(sce->pipeh); /* cancel async bulk transfer */ if (sce->bulkreq.xfer != NULL) @@ -1240,8 +1235,6 @@ ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd, if (endpt == USB_CONTROL_ENDPOINT) return (EINVAL); sce = &sc->sc_endpoints[endpt][IN]; - if (sce == NULL) - return (EINVAL); if (sce->pipeh == NULL) { printf("ugenioctl: USB_SET_SHORT_XFER, no pipe\n"); @@ -1252,11 +1245,22 @@ ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd, sce->state |= UGEN_SHORT_OK; else sce->state &= ~UGEN_SHORT_OK; + /* + * If this is a bulk data pipe awaiting data, then we + * need to restart the current operation with the new + * short transfer status set. + */ + if (sce->bulkreq.xfer != NULL && sce->bulkreq.datardy == 0) { + usbd_abort_pipe(sce->pipeh); + usbd_setup_xfer(sce->bulkreq.xfer, sce->pipeh, sce, + sce->bulkreq.buf, sce->bulkreq.maxlen, + sce->state & UGEN_SHORT_OK ? + USBD_SHORT_XFER_OK : 0, sce->timeout, ugen_rdcb); + usbd_transfer(sce->bulkreq.xfer); + } return (0); case USB_SET_TIMEOUT: sce = &sc->sc_endpoints[endpt][IN]; - if (sce == NULL) - return (EINVAL); sce->timeout = *(int *)addr; return (0); default: @@ -1508,8 +1512,6 @@ ugenpoll(struct cdev *dev, int events, usb_proc_ptr p) /* XXX always IN */ sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN]; - if (sce == NULL) - return (EINVAL); if (!sce->edesc) { printf("ugenpoll: no edesc\n"); |