Date: Sat, 22 Feb 2003 20:24:01 +0200 From: John Hay <jhay@icomtek.csir.co.za> To: current@FreeBSD.org Subject: usb patch: outgoing interrupt pipes Message-ID: <20030222182401.GA30119@zibbi.icomtek.csir.co.za>
next in thread | raw e-mail | index | archive | help
Hi, I have a patch that adds outgoing interrupt pipes to the usb stack. I needed it to make a Lego infrared tower work with FreeBSD. Outgoing interrupt pipes are part of the USB 1.1 spec, but I think our usb code comes from before that, so it only have incoming interrupt pipes. Is there anybody that would like to review this or shall I just go ahead and commit it? One thing to note is that the patch only fix it for uhci controllers. I haven't been able to get my hands on an ohci controller. John -- John Hay -- John.Hay@icomtek.csir.co.za / jhay@FreeBSD.org Index: share/man/man4/ugen.4 =================================================================== RCS file: /home/ncvs/src/share/man/man4/ugen.4,v retrieving revision 1.2 diff -u -r1.2 ugen.4 --- share/man/man4/ugen.4 22 Nov 2001 11:56:54 -0000 1.2 +++ share/man/man4/ugen.4 14 Feb 2003 10:20:01 -0000 @@ -104,9 +104,12 @@ 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. Index: sys/dev/usb/ugen.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/ugen.c,v retrieving revision 1.66 diff -u -r1.66 ugen.c --- sys/dev/usb/ugen.c 21 Jan 2003 08:55:44 -0000 1.66 +++ sys/dev/usb/ugen.c 12 Feb 2003 16:05:24 -0000 @@ -419,6 +419,13 @@ 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); @@ -764,6 +771,30 @@ DPRINTFN(1, ("ugenwrite: transfer %d bytes\n", n)); err = usbd_bulk_transfer(xfer, sce->pipeh, 0, sce->timeout, buf, &n,"ugenwb"); + if (err) { + if (err == USBD_INTERRUPTED) + error = EINTR; + else if (err == USBD_TIMEOUT) + error = ETIMEDOUT; + else + error = EIO; + break; + } + } + 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; Index: sys/dev/usb/uhci.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/uhci.c,v retrieving revision 1.130 diff -u -r1.130 uhci.c --- sys/dev/usb/uhci.c 21 Jan 2003 08:55:44 -0000 1.130 +++ sys/dev/usb/uhci.c 12 Feb 2003 16:27:48 -0000 @@ -149,6 +149,7 @@ /* Interrupt pipe */ struct { int npoll; + int isread; uhci_soft_qh_t **qhs; } intr; /* Bulk pipe */ @@ -2032,6 +2033,7 @@ 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 @@ 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 @@ 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); Index: sys/dev/usb/usbdi_util.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/usbdi_util.c,v retrieving revision 1.26 diff -u -r1.26 usbdi_util.c --- sys/dev/usb/usbdi_util.c 22 Aug 2002 21:24:00 -0000 1.26 +++ sys/dev/usb/usbdi_util.c 12 Feb 2003 16:05:24 -0000 @@ -445,6 +445,48 @@ 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) { Index: sys/dev/usb/usbdi_util.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/usbdi_util.h,v retrieving revision 1.14 diff -u -r1.14 usbdi_util.h --- sys/dev/usb/usbdi_util.h 7 Apr 2002 17:13:00 -0000 1.14 +++ sys/dev/usb/usbdi_util.h 12 Feb 2003 16:05:24 -0000 @@ -80,6 +80,10 @@ 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); To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-current" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20030222182401.GA30119>