musb-new: Add interrupt queue support
authorHans de Goede <hdegoede@redhat.com>
Sun, 11 Jan 2015 19:34:54 +0000 (20:34 +0100)
committerMarek Vasut <marex@denx.de>
Sun, 18 Jan 2015 11:31:36 +0000 (12:31 +0100)
Add interrupt queue support, so that a usb keyboard can be used without
causing huge latencies.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
drivers/usb/musb-new/musb_uboot.c
include/usb.h

index 3f9a98c9070a9faf8a6d55256179fe39c7bd333c..6e58ddf02cc34b67b4550b9f752d5a00c2d0615c 100644 (file)
 #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;
index a083591ba02865cda03b47eef2e8e5abcb4c5f24..a8fee0bdb76f59a30e478286d06abb1d8201ce8a 100644 (file)
@@ -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);