Implement outgoing interrupt pipes. It is part of the USB 1.1 spec.

The Lego Infrared Tower use it.
This commit is contained in:
John Hay 2003-02-28 19:28:29 +00:00
parent 19921b23b5
commit 11229bf39e
5 changed files with 95 additions and 5 deletions

View File

@ -104,9 +104,12 @@ and
should be used.
All I/O operations on a bulk endpoint are unbuffered.
.Pp
The interrupt transfer mode can only be in.
To perform input from an interrupt endpoint
The interrupt transfer mode can be in or out depending on the
endpoint.
To perform I/O on an interrupt endpoint
.Xr read 2
and
.Xr write 2
should be used.
A moderate amount of buffering is done
by the driver.

View File

@ -419,6 +419,13 @@ ugenopen(dev_t dev, int flag, int mode, usb_proc_ptr p)
edesc = sce->edesc;
switch (edesc->bmAttributes & UE_XFERTYPE) {
case UE_INTERRUPT:
if (dir == OUT) {
err = usbd_open_pipe(sce->iface,
edesc->bEndpointAddress, 0, &sce->pipeh);
if (err)
return (EIO);
break;
}
isize = UGETW(edesc->wMaxPacketSize);
if (isize == 0) /* shouldn't happen */
return (EINVAL);
@ -776,6 +783,30 @@ ugen_do_write(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
}
usbd_free_xfer(xfer);
break;
case UE_INTERRUPT:
xfer = usbd_alloc_xfer(sc->sc_udev);
if (xfer == 0)
return (EIO);
while ((n = min(UGETW(sce->edesc->wMaxPacketSize),
uio->uio_resid)) != 0) {
error = uiomove(buf, n, uio);
if (error)
break;
DPRINTFN(1, ("ugenwrite: transfer %d bytes\n", n));
err = usbd_intr_transfer(xfer, sce->pipeh, 0,
sce->timeout, buf, &n,"ugenwi");
if (err) {
if (err == USBD_INTERRUPTED)
error = EINTR;
else if (err == USBD_TIMEOUT)
error = ETIMEDOUT;
else
error = EIO;
break;
}
}
usbd_free_xfer(xfer);
break;
default:
return (ENXIO);
}

View File

@ -149,6 +149,7 @@ struct uhci_pipe {
/* Interrupt pipe */
struct {
int npoll;
int isread;
uhci_soft_qh_t **qhs;
} intr;
/* Bulk pipe */
@ -2032,6 +2033,7 @@ uhci_device_intr_start(usbd_xfer_handle xfer)
uhci_soft_td_t *data, *dataend;
uhci_soft_qh_t *sqh;
usbd_status err;
int isread, endpt;
int i, s;
if (sc->sc_dying)
@ -2045,8 +2047,15 @@ uhci_device_intr_start(usbd_xfer_handle xfer)
panic("uhci_device_intr_transfer: a request\n");
#endif
err = uhci_alloc_std_chain(upipe, sc, xfer->length, 1, xfer->flags,
&xfer->dmabuf, &data, &dataend);
endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;
isread = UE_GET_DIR(endpt) == UE_DIR_IN;
sqh = upipe->u.bulk.sqh;
upipe->u.intr.isread = isread;
err = uhci_alloc_std_chain(upipe, sc, xfer->length, isread,
xfer->flags, &xfer->dmabuf, &data,
&dataend);
if (err)
return (err);
dataend->td.td_status |= htole32(UHCI_TD_IOC);
@ -2637,7 +2646,8 @@ uhci_device_intr_done(usbd_xfer_handle xfer)
DPRINTFN(5,("uhci_device_intr_done: requeing\n"));
/* This alloc cannot fail since we freed the chain above. */
uhci_alloc_std_chain(upipe, sc, xfer->length, 1, xfer->flags,
uhci_alloc_std_chain(upipe, sc, xfer->length,
upipe->u.intr.isread, xfer->flags,
&xfer->dmabuf, &data, &dataend);
dataend->td.td_status |= htole32(UHCI_TD_IOC);

View File

@ -445,6 +445,48 @@ usbd_bulk_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
return (err);
}
Static void usbd_intr_transfer_cb(usbd_xfer_handle xfer,
usbd_private_handle priv, usbd_status status);
Static void
usbd_intr_transfer_cb(usbd_xfer_handle xfer, usbd_private_handle priv,
usbd_status status)
{
wakeup(xfer);
}
usbd_status
usbd_intr_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
u_int16_t flags, u_int32_t timeout, void *buf,
u_int32_t *size, char *lbl)
{
usbd_status err;
int s, error;
usbd_setup_xfer(xfer, pipe, 0, buf, *size,
flags, timeout, usbd_intr_transfer_cb);
DPRINTFN(1, ("usbd_intr_transfer: start transfer %d bytes\n", *size));
s = splusb(); /* don't want callback until tsleep() */
err = usbd_transfer(xfer);
if (err != USBD_IN_PROGRESS) {
splx(s);
return (err);
}
error = tsleep((caddr_t)xfer, PZERO | PCATCH, lbl, 0);
splx(s);
if (error) {
DPRINTF(("usbd_intr_transfer: tsleep=%d\n", error));
usbd_abort_pipe(pipe);
return (USBD_INTERRUPTED);
}
usbd_get_xfer_status(xfer, NULL, NULL, size, &err);
DPRINTFN(1,("usbd_intr_transfer: transferred %d\n", *size));
if (err) {
DPRINTF(("usbd_intr_transfer: error=%d\n", err));
usbd_clear_endpoint_stall(pipe);
}
return (err);
}
void
usb_detach_wait(device_ptr_t dv)
{

View File

@ -80,6 +80,10 @@ usbd_status usbd_bulk_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
u_int16_t flags, u_int32_t timeout, void *buf,
u_int32_t *size, char *lbl);
usbd_status usbd_intr_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
u_int16_t flags, u_int32_t timeout, void *buf,
u_int32_t *size, char *lbl);
void usb_detach_wait(device_ptr_t);
void usb_detach_wakeup(device_ptr_t);