Skip site navigation (1)Skip section navigation (2)
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>