summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgreen <green@FreeBSD.org>2004-10-02 22:33:26 +0000
committergreen <green@FreeBSD.org>2004-10-02 22:33:26 +0000
commitc0dc03c5fc1ace84fd4d1de81f0d357cb9068311 (patch)
treef317089f2097755739485b8e465f8267f605181d
parent58075b5ab9e2b1eefa0656765cd623691f680679 (diff)
downloadFreeBSD-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).
-rw-r--r--sys/dev/usb/ugen.c42
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");
OpenPOWER on IntegriCloud