diff options
author | Hans de Goede | 2015-01-11 20:34:54 +0100 |
---|---|---|
committer | Marek Vasut | 2015-01-18 12:31:36 +0100 |
commit | 904f2a83a8c620ceb3974cc6b1529b966d7899b1 (patch) | |
tree | 7dbcc475c638bf71883f6e385476d89244cc5b76 /drivers/usb/musb-new | |
parent | accf04c2aa106a8ea5387d309e1ac037eba5ad63 (diff) |
musb-new: Add interrupt queue support
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>
Diffstat (limited to 'drivers/usb/musb-new')
-rw-r--r-- | drivers/usb/musb-new/musb_uboot.c | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/drivers/usb/musb-new/musb_uboot.c b/drivers/usb/musb-new/musb_uboot.c index 3f9a98c9070..6e58ddf02cc 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; |