]> Pileus Git - ~andy/linux/blobdiff - drivers/usb/host/isp1760-hcd.c
Merge tag 'tty-3.4-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
[~andy/linux] / drivers / usb / host / isp1760-hcd.c
index 27dfab80ed8f3982c4454295481222e1698c6a6b..fc72d44bf787a7be1907e5736cd3c11cc955e462 100644 (file)
@@ -32,6 +32,13 @@ static struct kmem_cache *qtd_cachep;
 static struct kmem_cache *qh_cachep;
 static struct kmem_cache *urb_listitem_cachep;
 
+enum queue_head_types {
+       QH_CONTROL,
+       QH_BULK,
+       QH_INTERRUPT,
+       QH_END
+};
+
 struct isp1760_hcd {
        u32 hcs_params;
        spinlock_t              lock;
@@ -40,7 +47,7 @@ struct isp1760_hcd {
        struct slotinfo         int_slots[32];
        int                     int_done_map;
        struct memory_chunk memory_pool[BLOCKS];
-       struct list_head        controlqhs, bulkqhs, interruptqhs;
+       struct list_head        qh_list[QH_END];
 
        /* periodic schedule support */
 #define        DEFAULT_I_TDPS          1024
@@ -406,12 +413,12 @@ static int priv_init(struct usb_hcd *hcd)
 {
        struct isp1760_hcd              *priv = hcd_to_priv(hcd);
        u32                     hcc_params;
+       int i;
 
        spin_lock_init(&priv->lock);
 
-       INIT_LIST_HEAD(&priv->interruptqhs);
-       INIT_LIST_HEAD(&priv->controlqhs);
-       INIT_LIST_HEAD(&priv->bulkqhs);
+       for (i = 0; i < QH_END; i++)
+               INIT_LIST_HEAD(&priv->qh_list[i]);
 
        /*
         * hw default: 1K periodic list heads, one per frame.
@@ -930,9 +937,9 @@ void schedule_ptds(struct usb_hcd *hcd)
        struct isp1760_hcd *priv;
        struct isp1760_qh *qh, *qh_next;
        struct list_head *ep_queue;
-       struct usb_host_endpoint *ep;
        LIST_HEAD(urb_list);
        struct urb_listitem *urb_listitem, *urb_listitem_next;
+       int i;
 
        if (!hcd) {
                WARN_ON(1);
@@ -944,28 +951,13 @@ void schedule_ptds(struct usb_hcd *hcd)
        /*
         * check finished/retired xfers, transfer payloads, call urb_done()
         */
-       ep_queue = &priv->interruptqhs;
-       while (ep_queue) {
+       for (i = 0; i < QH_END; i++) {
+               ep_queue = &priv->qh_list[i];
                list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list) {
-                       ep = list_entry(qh->qtd_list.next, struct isp1760_qtd,
-                                                       qtd_list)->urb->ep;
                        collect_qtds(hcd, qh, &urb_list);
-                       if (list_empty(&qh->qtd_list)) {
+                       if (list_empty(&qh->qtd_list))
                                list_del(&qh->qh_list);
-                               if (ep->hcpriv == NULL) {
-                                       /* Endpoint has been disabled, so we
-                                       can free the associated queue head. */
-                                       qh_free(qh);
-                               }
-                       }
                }
-
-               if (ep_queue == &priv->interruptqhs)
-                       ep_queue = &priv->controlqhs;
-               else if (ep_queue == &priv->controlqhs)
-                       ep_queue = &priv->bulkqhs;
-               else
-                       ep_queue = NULL;
        }
 
        list_for_each_entry_safe(urb_listitem, urb_listitem_next, &urb_list,
@@ -998,17 +990,10 @@ void schedule_ptds(struct usb_hcd *hcd)
         *
         * I'm sure this scheme could be improved upon!
         */
-       ep_queue = &priv->controlqhs;
-       while (ep_queue) {
+       for (i = 0; i < QH_END; i++) {
+               ep_queue = &priv->qh_list[i];
                list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list)
                        enqueue_qtds(hcd, qh);
-
-               if (ep_queue == &priv->controlqhs)
-                       ep_queue = &priv->interruptqhs;
-               else if (ep_queue == &priv->interruptqhs)
-                       ep_queue = &priv->bulkqhs;
-               else
-                       ep_queue = NULL;
        }
 }
 
@@ -1543,16 +1528,16 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
 
        switch (usb_pipetype(urb->pipe)) {
        case PIPE_CONTROL:
-               ep_queue = &priv->controlqhs;
+               ep_queue = &priv->qh_list[QH_CONTROL];
                break;
        case PIPE_BULK:
-               ep_queue = &priv->bulkqhs;
+               ep_queue = &priv->qh_list[QH_BULK];
                break;
        case PIPE_INTERRUPT:
                if (urb->interval < 0)
                        return -EINVAL;
                /* FIXME: Check bandwidth  */
-               ep_queue = &priv->interruptqhs;
+               ep_queue = &priv->qh_list[QH_INTERRUPT];
                break;
        case PIPE_ISOCHRONOUS:
                dev_err(hcd->self.controller, "%s: isochronous USB packets "
@@ -1714,8 +1699,8 @@ static void isp1760_endpoint_disable(struct usb_hcd *hcd,
 {
        struct isp1760_hcd *priv = hcd_to_priv(hcd);
        unsigned long spinflags;
-       struct isp1760_qh *qh;
-       struct isp1760_qtd *qtd;
+       struct isp1760_qh *qh, *qh_iter;
+       int i;
 
        spin_lock_irqsave(&priv->lock, spinflags);
 
@@ -1723,14 +1708,17 @@ static void isp1760_endpoint_disable(struct usb_hcd *hcd,
        if (!qh)
                goto out;
 
-       list_for_each_entry(qtd, &qh->qtd_list, qtd_list)
-               if (qtd->status != QTD_RETIRE) {
-                       dequeue_urb_from_qtd(hcd, qh, qtd);
-                       qtd->urb->status = -ECONNRESET;
-               }
+       WARN_ON(!list_empty(&qh->qtd_list));
 
+       for (i = 0; i < QH_END; i++)
+               list_for_each_entry(qh_iter, &priv->qh_list[i], qh_list)
+                       if (qh_iter == qh) {
+                               list_del(&qh_iter->qh_list);
+                               i = QH_END;
+                               break;
+                       }
+       qh_free(qh);
        ep->hcpriv = NULL;
-       /* Cannot free qh here since it will be parsed by schedule_ptds() */
 
        schedule_ptds(hcd);