diff options
author | green <green@FreeBSD.org> | 2004-10-02 22:33:26 +0000 |
---|---|---|
committer | green <green@FreeBSD.org> | 2004-10-02 22:33:26 +0000 |
commit | c0dc03c5fc1ace84fd4d1de81f0d357cb9068311 (patch) | |
tree | f317089f2097755739485b8e465f8267f605181d /sys/dev/usb | |
parent | 58075b5ab9e2b1eefa0656765cd623691f680679 (diff) | |
download | FreeBSD-src-c0dc03c5fc1ace84fd4d1de81f0d357cb9068311.zip FreeBSD-src-c0dc03c5fc1ace84fd4d1de81f0d357cb9068311.tar.gz |
* 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).
Diffstat (limited to 'sys/dev/usb')
-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 3cf3072..b0564d1 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"); |