Implement outgoing interrupt pipes. It is part of the USB 1.1 spec.
The Lego Infrared Tower use it.
This commit is contained in:
parent
19921b23b5
commit
11229bf39e
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user