diff options
Diffstat (limited to 'drivers/usb/host/isp1760-hcd.c')
-rw-r--r-- | drivers/usb/host/isp1760-hcd.c | 74 |
1 files changed, 31 insertions, 43 deletions
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c index 27dfab80ed8..fc72d44bf78 100644 --- a/drivers/usb/host/isp1760-hcd.c +++ b/drivers/usb/host/isp1760-hcd.c @@ -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); |