diff options
-rw-r--r-- | drivers/usb/host/ohci-hcd.c | 22 | ||||
-rw-r--r-- | drivers/usb/host/ohci-q.c | 26 |
2 files changed, 34 insertions, 14 deletions
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 8f6b695af6a4..604cad1bcf9c 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c | |||
@@ -216,31 +216,26 @@ static int ohci_urb_enqueue ( | |||
216 | frame &= ~(ed->interval - 1); | 216 | frame &= ~(ed->interval - 1); |
217 | frame |= ed->branch; | 217 | frame |= ed->branch; |
218 | urb->start_frame = frame; | 218 | urb->start_frame = frame; |
219 | ed->last_iso = frame + ed->interval * (size - 1); | ||
219 | } | 220 | } |
220 | } else if (ed->type == PIPE_ISOCHRONOUS) { | 221 | } else if (ed->type == PIPE_ISOCHRONOUS) { |
221 | u16 next = ohci_frame_no(ohci) + 1; | 222 | u16 next = ohci_frame_no(ohci) + 1; |
222 | u16 frame = ed->last_iso + ed->interval; | 223 | u16 frame = ed->last_iso + ed->interval; |
224 | u16 length = ed->interval * (size - 1); | ||
223 | 225 | ||
224 | /* Behind the scheduling threshold? */ | 226 | /* Behind the scheduling threshold? */ |
225 | if (unlikely(tick_before(frame, next))) { | 227 | if (unlikely(tick_before(frame, next))) { |
226 | 228 | ||
227 | /* USB_ISO_ASAP: Round up to the first available slot */ | 229 | /* URB_ISO_ASAP: Round up to the first available slot */ |
228 | if (urb->transfer_flags & URB_ISO_ASAP) { | 230 | if (urb->transfer_flags & URB_ISO_ASAP) { |
229 | frame += (next - frame + ed->interval - 1) & | 231 | frame += (next - frame + ed->interval - 1) & |
230 | -ed->interval; | 232 | -ed->interval; |
231 | 233 | ||
232 | /* | 234 | /* |
233 | * Not ASAP: Use the next slot in the stream. If | 235 | * Not ASAP: Use the next slot in the stream, |
234 | * the entire URB falls before the threshold, fail. | 236 | * no matter what. |
235 | */ | 237 | */ |
236 | } else { | 238 | } else { |
237 | if (tick_before(frame + ed->interval * | ||
238 | (urb->number_of_packets - 1), next)) { | ||
239 | retval = -EXDEV; | ||
240 | usb_hcd_unlink_urb_from_ep(hcd, urb); | ||
241 | goto fail; | ||
242 | } | ||
243 | |||
244 | /* | 239 | /* |
245 | * Some OHCI hardware doesn't handle late TDs | 240 | * Some OHCI hardware doesn't handle late TDs |
246 | * correctly. After retiring them it proceeds | 241 | * correctly. After retiring them it proceeds |
@@ -251,9 +246,16 @@ static int ohci_urb_enqueue ( | |||
251 | urb_priv->td_cnt = DIV_ROUND_UP( | 246 | urb_priv->td_cnt = DIV_ROUND_UP( |
252 | (u16) (next - frame), | 247 | (u16) (next - frame), |
253 | ed->interval); | 248 | ed->interval); |
249 | if (urb_priv->td_cnt >= urb_priv->length) { | ||
250 | ++urb_priv->td_cnt; /* Mark it */ | ||
251 | ohci_dbg(ohci, "iso underrun %p (%u+%u < %u)\n", | ||
252 | urb, frame, length, | ||
253 | next); | ||
254 | } | ||
254 | } | 255 | } |
255 | } | 256 | } |
256 | urb->start_frame = frame; | 257 | urb->start_frame = frame; |
258 | ed->last_iso = frame + length; | ||
257 | } | 259 | } |
258 | 260 | ||
259 | /* fill the TDs and link them to the ed; and | 261 | /* fill the TDs and link them to the ed; and |
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 */ |