* 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).
This commit is contained in:
green 2004-10-02 22:33:26 +00:00
parent 5dede2828a
commit 528d4ff186

View File

@ -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");