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>
