diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2004-07-21 00:01:09 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2004-07-21 00:01:09 +0000 |
commit | 1939583a95bbe7a8022a6bee1010821fde2ff1bb (patch) | |
tree | 7f8ebb392c8e96c623d578a3cd85077af6d5be37 /sys/dev | |
parent | eb833e87668c2e29e560a558673f37ed802ef6d9 (diff) |
from freebsd, ugen.c 1.68 usbdi_util.c 1.27 usbdi_util.h 1.15
log message:
Implement outgoing interrupt pipes. It is part of the USB 1.1 spec.
The Lego Infrared Tower use it.
ok deraadt@
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/usb/ugen.c | 33 | ||||
-rw-r--r-- | sys/dev/usb/usbdi_util.c | 44 | ||||
-rw-r--r-- | sys/dev/usb/usbdi_util.h | 6 |
3 files changed, 80 insertions, 3 deletions
diff --git a/sys/dev/usb/ugen.c b/sys/dev/usb/ugen.c index feee3004c41..b7f955fd601 100644 --- a/sys/dev/usb/ugen.c +++ b/sys/dev/usb/ugen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ugen.c,v 1.29 2004/07/08 22:18:44 deraadt Exp $ */ +/* $OpenBSD: ugen.c,v 1.30 2004/07/21 00:01:07 dlg Exp $ */ /* $NetBSD: ugen.c,v 1.63 2002/11/26 18:49:48 christos Exp $ */ /* $FreeBSD: src/sys/dev/usb/ugen.c,v 1.26 1999/11/17 22:33:41 n_hibma Exp $ */ @@ -359,6 +359,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); @@ -715,6 +722,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); } diff --git a/sys/dev/usb/usbdi_util.c b/sys/dev/usb/usbdi_util.c index 69fd35b6308..58fe86f4f9c 100644 --- a/sys/dev/usb/usbdi_util.c +++ b/sys/dev/usb/usbdi_util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: usbdi_util.c,v 1.16 2004/07/08 22:18:45 deraadt Exp $ */ +/* $OpenBSD: usbdi_util.c,v 1.17 2004/07/21 00:01:08 dlg Exp $ */ /* $NetBSD: usbdi_util.c,v 1.40 2002/07/11 21:14:36 augustss Exp $ */ /* $FreeBSD: src/sys/dev/usb/usbdi_util.c,v 1.14 1999/11/17 22:33:50 n_hibma Exp $ */ @@ -465,6 +465,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(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) { diff --git a/sys/dev/usb/usbdi_util.h b/sys/dev/usb/usbdi_util.h index 1d435df6ee5..71d40301b67 100644 --- a/sys/dev/usb/usbdi_util.h +++ b/sys/dev/usb/usbdi_util.h @@ -1,4 +1,4 @@ -/* $OpenBSD: usbdi_util.h,v 1.12 2003/07/08 13:19:09 nate Exp $ */ +/* $OpenBSD: usbdi_util.h,v 1.13 2004/07/21 00:01:08 dlg Exp $ */ /* $NetBSD: usbdi_util.h,v 1.28 2002/07/11 21:14:36 augustss Exp $ */ /* $FreeBSD: src/sys/dev/usb/usbdi_util.h,v 1.9 1999/11/17 22:33:50 n_hibma Exp $ */ @@ -82,6 +82,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); |