[U-Boot] [PATCH 16/17] musb-new: Add interrupt queue support

Hans de Goede hdegoede at redhat.com
Sun Jan 11 20:34:54 CET 2015


Add interrupt queue support, so that a usb keyboard can be used without
causing huge latencies.

Signed-off-by: Hans de Goede <hdegoede at redhat.com>
---
 drivers/usb/musb-new/musb_uboot.c | 65 +++++++++++++++++++++++++++++++++++++++
 include/usb.h                     |  3 +-
 2 files changed, 67 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/musb-new/musb_uboot.c b/drivers/usb/musb-new/musb_uboot.c
index 3f9a98c..6e58ddf 100644
--- a/drivers/usb/musb-new/musb_uboot.c
+++ b/drivers/usb/musb-new/musb_uboot.c
@@ -12,6 +12,11 @@
 #include "musb_gadget.h"
 
 #ifdef CONFIG_MUSB_HOST
+struct int_queue {
+	struct usb_host_endpoint hep;
+	struct urb urb;
+};
+
 static struct musb *host;
 static struct usb_hcd hcd;
 static enum usb_device_speed host_speed;
@@ -112,6 +117,66 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe,
 	return submit_urb(&hcd, &urb);
 }
 
+struct int_queue *create_int_queue(struct usb_device *dev, unsigned long pipe,
+	int queuesize, int elementsize, void *buffer, int interval)
+{
+	struct int_queue *queue;
+	int ret, index = usb_pipein(pipe) * 16 + usb_pipeendpoint(pipe);
+
+	if (queuesize != 1) {
+		printf("ERROR musb int-queues only support queuesize 1\n");
+		return NULL;
+	}
+
+	if (dev->int_pending & (1 << index)) {
+		printf("ERROR int-urb is already pending on pipe %lx\n", pipe);
+		return NULL;
+	}
+
+	queue = malloc(sizeof(*queue));
+	if (!queue)
+		return NULL;
+
+	construct_urb(&queue->urb, &queue->hep, dev, USB_ENDPOINT_XFER_INT,
+		      pipe, buffer, elementsize, NULL, interval);
+
+	ret = musb_urb_enqueue(&hcd, &queue->urb, 0);
+	if (ret < 0) {
+		printf("Failed to enqueue URB to controller\n");
+		free(queue);
+		return NULL;
+	}
+
+	dev->int_pending |= 1 << index;
+	return queue;
+}
+
+int destroy_int_queue(struct usb_device *dev, struct int_queue *queue)
+{
+	int index = usb_pipein(queue->urb.pipe) * 16 + 
+		    usb_pipeendpoint(queue->urb.pipe);
+
+	if (queue->urb.status == -EINPROGRESS)
+		musb_urb_dequeue(&hcd, &queue->urb, -ETIME);
+
+	dev->int_pending &= ~(1 << index);
+	free(queue);
+	return 0;
+}
+
+void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
+{
+	if (queue->urb.status != -EINPROGRESS)
+		return NULL; /* URB has already completed in a prev. poll */
+
+	host->isr(0, host);
+
+	if (queue->urb.status != -EINPROGRESS)
+		return queue->urb.transfer_buffer; /* Done */
+
+	return NULL; /* URB still pending */
+}
+
 void usb_reset_root_port(void)
 {
 	void *mbase = host->mregs;
diff --git a/include/usb.h b/include/usb.h
index a083591..a8fee0b 100644
--- a/include/usb.h
+++ b/include/usb.h
@@ -120,6 +120,7 @@ struct usb_device {
 	 * Each instance needs its own set of data structures.
 	 */
 	unsigned long status;
+	unsigned long int_pending;	/* 1 bit per ep, used by int_queue */
 	int act_len;			/* transfered bytes */
 	int maxchild;			/* Number of ports if hub */
 	int portnr;
@@ -172,7 +173,7 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
 int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
 			int transfer_len, int interval);
 
-#ifdef CONFIG_USB_EHCI /* Only the ehci code has pollable int support */
+#if defined CONFIG_USB_EHCI || defined CONFIG_MUSB_HOST
 struct int_queue *create_int_queue(struct usb_device *dev, unsigned long pipe,
 	int queuesize, int elementsize, void *buffer, int interval);
 int destroy_int_queue(struct usb_device *dev, struct int_queue *queue);
-- 
2.1.0



More information about the U-Boot mailing list