summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2007-10-16 17:55:30 +0200
committerGreg Kroah-Hartman <gregkh@suse.de>2007-10-25 21:18:43 +0200
commit7898ffc543566a9c4a1b4ff39f43857d2d84a51c (patch)
treef69b2c37ef58f3e850205c2036b01e420f2fbb53
parentUSB: io_edgeport: cleanups, and tty speed reporting (diff)
downloadlinux-7898ffc543566a9c4a1b4ff39f43857d2d84a51c.tar.xz
linux-7898ffc543566a9c4a1b4ff39f43857d2d84a51c.zip
USB: fix scheduling of Iso URBs in uhci-hcd
This patch (as1003) changes uhci-hcd to treat the URB_ISO_ASAP flag the same as other host controller drivers, namely, to schedule an Iso URB for the first available time slot that hasn't already expired. URBs in which the flag isn't set will be scheduled for the first slot following the last URB, even if it has expired. This fixes a problem reported by Martin Bachem. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/host/uhci-q.c19
1 files changed, 14 insertions, 5 deletions
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index e5d60d5b105a..60379b17bbc1 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -1271,7 +1271,8 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
} else if (qh->period != urb->interval) {
return -EINVAL; /* Can't change the period */
- } else { /* Pick up where the last URB leaves off */
+ } else {
+ /* Find the next unused frame */
if (list_empty(&qh->queue)) {
frame = qh->iso_frame;
} else {
@@ -1283,10 +1284,18 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
lurb->number_of_packets *
lurb->interval;
}
- if (urb->transfer_flags & URB_ISO_ASAP)
- urb->start_frame = frame;
- else if (urb->start_frame != frame)
- return -EINVAL;
+ if (urb->transfer_flags & URB_ISO_ASAP) {
+ /* Skip some frames if necessary to insure
+ * the start frame is in the future.
+ */
+ uhci_get_current_frame_number(uhci);
+ if (uhci_frame_before_eq(frame, uhci->frame_number)) {
+ frame = uhci->frame_number + 1;
+ frame += ((qh->phase - frame) &
+ (qh->period - 1));
+ }
+ } /* Otherwise pick up where the last URB leaves off */
+ urb->start_frame = frame;
}
/* Make sure we won't have to go too far into the future */