diff options
author | Imre Kaloz <kaloz@openwrt.org> | 2014-03-12 13:37:40 +0000 |
---|---|---|
committer | Imre Kaloz <kaloz@openwrt.org> | 2014-03-12 13:37:40 +0000 |
commit | 68022cac6423111f5eaea8f1e8b297f1ed282a28 (patch) | |
tree | 506dd49aa00313f5598577da7a06a41eac0e7235 /target/linux/cns3xxx/files/drivers/usb/dwc/otg_hcd_queue.c | |
parent | 47dfbb5bc62c74b9685e6f243f31e768cae1a868 (diff) | |
download | master-31e0f0ae-68022cac6423111f5eaea8f1e8b297f1ed282a28.tar.gz master-31e0f0ae-68022cac6423111f5eaea8f1e8b297f1ed282a28.tar.bz2 master-31e0f0ae-68022cac6423111f5eaea8f1e8b297f1ed282a28.zip |
various dwc (OTG) driver fixups
Signed-off-by: Tim Harvey <tharvey@gateworks.com>
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
SVN-Revision: 39892
Diffstat (limited to 'target/linux/cns3xxx/files/drivers/usb/dwc/otg_hcd_queue.c')
-rw-r--r-- | target/linux/cns3xxx/files/drivers/usb/dwc/otg_hcd_queue.c | 43 |
1 files changed, 32 insertions, 11 deletions
diff --git a/target/linux/cns3xxx/files/drivers/usb/dwc/otg_hcd_queue.c b/target/linux/cns3xxx/files/drivers/usb/dwc/otg_hcd_queue.c index 7395d1dcfc..6e7b53c392 100644 --- a/target/linux/cns3xxx/files/drivers/usb/dwc/otg_hcd_queue.c +++ b/target/linux/cns3xxx/files/drivers/usb/dwc/otg_hcd_queue.c @@ -211,6 +211,8 @@ void dwc_otg_hcd_qh_init(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh, struct urb *urb) usb_pipeendpoint(urb->pipe), usb_pipein(urb->pipe) == USB_DIR_IN ? "IN" : "OUT"); + qh->nak_frame = 0xffff; + switch(urb->dev->speed) { case USB_SPEED_LOW: speed = "low"; @@ -453,7 +455,26 @@ static int schedule_periodic(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh) int status; struct usb_bus *bus = hcd_to_bus(dwc_otg_hcd_to_hcd(hcd)); int frame; - + int num_channels; + + num_channels = hcd->core_if->core_params->host_channels; + + if ((hcd->periodic_channels < num_channels - 1)) { + if (hcd->periodic_channels + hcd->nakking_channels >= num_channels) { + /* All non-periodic channels are nakking? Halt + * one to make room (as long as there is at + * least one channel for non-periodic transfers, + * all the blocking non-periodics can time-share + * that one channel. */ + dwc_hc_t *hc = dwc_otg_halt_nakking_channel(hcd); + if (hc) + DWC_DEBUGPL(DBG_HCD, "Out of Host Channels for periodic transfer - Halting channel %d (dev %d ep%d%s)\n", hc->hc_num, hc->dev_addr, hc->ep_num, (hc->ep_is_in ? "in" : "out")); + } + /* It could be that all channels are currently occupied, + * but in that case one will be freed up soon (either + * because it completed or because it was forced to halt + * above). */ + } status = find_uframe(hcd, qh); frame = -1; if (status == 0) { @@ -483,6 +504,8 @@ static int schedule_periodic(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh) /* Always start in the inactive schedule. */ list_add_tail(&qh->qh_list_entry, &hcd->periodic_sched_inactive); + hcd->periodic_channels++; + /* Update claimed usecs per (micro)frame. */ hcd->periodic_usecs += qh->usecs; @@ -553,6 +576,9 @@ static void deschedule_periodic(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh) int i; list_del_init(&qh->qh_list_entry); + + hcd->periodic_channels--; + /* Update claimed usecs per (micro)frame. */ hcd->periodic_usecs -= qh->usecs; for (i = 0; i < 8; i++) { @@ -628,9 +654,6 @@ void dwc_otg_hcd_qh_remove (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh) */ void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh, int sched_next_periodic_split) { - unsigned long flags; - SPIN_LOCK_IRQSAVE(&hcd->lock, flags); - if (dwc_qh_is_non_per(qh)) { dwc_otg_hcd_qh_remove(hcd, qh); if (!list_empty(&qh->qtd_list)) { @@ -690,8 +713,6 @@ void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh, int sched_n } } } - - SPIN_UNLOCK_IRQRESTORE(&hcd->lock, flags); } /** @@ -759,22 +780,22 @@ int dwc_otg_hcd_qtd_add (dwc_otg_qtd_t *qtd, { struct usb_host_endpoint *ep; dwc_otg_qh_t *qh; - unsigned long flags; int retval = 0; struct urb *urb = qtd->urb; - SPIN_LOCK_IRQSAVE(&dwc_otg_hcd->lock, flags); - /* * Get the QH which holds the QTD-list to insert to. Create QH if it * doesn't exist. */ + usb_hcd_link_urb_to_ep(dwc_otg_hcd_to_hcd(dwc_otg_hcd), urb); ep = dwc_urb_to_endpoint(urb); qh = (dwc_otg_qh_t *)ep->hcpriv; if (qh == NULL) { qh = dwc_otg_hcd_qh_create (dwc_otg_hcd, urb); if (qh == NULL) { + usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(dwc_otg_hcd), urb); + retval = -ENOMEM; goto done; } ep->hcpriv = qh; @@ -783,11 +804,11 @@ int dwc_otg_hcd_qtd_add (dwc_otg_qtd_t *qtd, retval = dwc_otg_hcd_qh_add(dwc_otg_hcd, qh); if (retval == 0) { list_add_tail(&qtd->qtd_list_entry, &qh->qtd_list); + } else { + usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(dwc_otg_hcd), urb); } done: - SPIN_UNLOCK_IRQRESTORE(&dwc_otg_hcd->lock, flags); - return retval; } |