diff options
Diffstat (limited to 'drivers/usb/host/ohci-q.c')
-rw-r--r-- | drivers/usb/host/ohci-q.c | 26 |
1 files changed, 22 insertions, 4 deletions
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index df4a6707322d..e7f577e63624 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c | |||
@@ -41,9 +41,13 @@ finish_urb(struct ohci_hcd *ohci, struct urb *urb, int status) | |||
41 | __releases(ohci->lock) | 41 | __releases(ohci->lock) |
42 | __acquires(ohci->lock) | 42 | __acquires(ohci->lock) |
43 | { | 43 | { |
44 | struct device *dev = ohci_to_hcd(ohci)->self.controller; | 44 | struct device *dev = ohci_to_hcd(ohci)->self.controller; |
45 | struct usb_host_endpoint *ep = urb->ep; | ||
46 | struct urb_priv *urb_priv; | ||
47 | |||
45 | // ASSERT (urb->hcpriv != 0); | 48 | // ASSERT (urb->hcpriv != 0); |
46 | 49 | ||
50 | restart: | ||
47 | urb_free_priv (ohci, urb->hcpriv); | 51 | urb_free_priv (ohci, urb->hcpriv); |
48 | urb->hcpriv = NULL; | 52 | urb->hcpriv = NULL; |
49 | if (likely(status == -EINPROGRESS)) | 53 | if (likely(status == -EINPROGRESS)) |
@@ -80,6 +84,21 @@ __acquires(ohci->lock) | |||
80 | ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_IE); | 84 | ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_IE); |
81 | ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); | 85 | ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); |
82 | } | 86 | } |
87 | |||
88 | /* | ||
89 | * An isochronous URB that is sumitted too late won't have any TDs | ||
90 | * (marked by the fact that the td_cnt value is larger than the | ||
91 | * actual number of TDs). If the next URB on this endpoint is like | ||
92 | * that, give it back now. | ||
93 | */ | ||
94 | if (!list_empty(&ep->urb_list)) { | ||
95 | urb = list_first_entry(&ep->urb_list, struct urb, urb_list); | ||
96 | urb_priv = urb->hcpriv; | ||
97 | if (urb_priv->td_cnt > urb_priv->length) { | ||
98 | status = 0; | ||
99 | goto restart; | ||
100 | } | ||
101 | } | ||
83 | } | 102 | } |
84 | 103 | ||
85 | 104 | ||
@@ -546,7 +565,6 @@ td_fill (struct ohci_hcd *ohci, u32 info, | |||
546 | td->hwCBP = cpu_to_hc32 (ohci, data & 0xFFFFF000); | 565 | td->hwCBP = cpu_to_hc32 (ohci, data & 0xFFFFF000); |
547 | *ohci_hwPSWp(ohci, td, 0) = cpu_to_hc16 (ohci, | 566 | *ohci_hwPSWp(ohci, td, 0) = cpu_to_hc16 (ohci, |
548 | (data & 0x0FFF) | 0xE000); | 567 | (data & 0x0FFF) | 0xE000); |
549 | td->ed->last_iso = info & 0xffff; | ||
550 | } else { | 568 | } else { |
551 | td->hwCBP = cpu_to_hc32 (ohci, data); | 569 | td->hwCBP = cpu_to_hc32 (ohci, data); |
552 | } | 570 | } |
@@ -996,7 +1014,7 @@ rescan_this: | |||
996 | urb_priv->td_cnt++; | 1014 | urb_priv->td_cnt++; |
997 | 1015 | ||
998 | /* if URB is done, clean up */ | 1016 | /* if URB is done, clean up */ |
999 | if (urb_priv->td_cnt == urb_priv->length) { | 1017 | if (urb_priv->td_cnt >= urb_priv->length) { |
1000 | modified = completed = 1; | 1018 | modified = completed = 1; |
1001 | finish_urb(ohci, urb, 0); | 1019 | finish_urb(ohci, urb, 0); |
1002 | } | 1020 | } |
@@ -1086,7 +1104,7 @@ static void takeback_td(struct ohci_hcd *ohci, struct td *td) | |||
1086 | urb_priv->td_cnt++; | 1104 | urb_priv->td_cnt++; |
1087 | 1105 | ||
1088 | /* If all this urb's TDs are done, call complete() */ | 1106 | /* If all this urb's TDs are done, call complete() */ |
1089 | if (urb_priv->td_cnt == urb_priv->length) | 1107 | if (urb_priv->td_cnt >= urb_priv->length) |
1090 | finish_urb(ohci, urb, status); | 1108 | finish_urb(ohci, urb, status); |
1091 | 1109 | ||
1092 | /* clean schedule: unlink EDs that are no longer busy */ | 1110 | /* clean schedule: unlink EDs that are no longer busy */ |