diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2012-10-01 18:32:09 +0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-10-22 22:10:24 +0400 |
commit | c44b225077bb1fb25ed5cd5c4f226897b91bedd4 (patch) | |
tree | 65d4817c67f9feb3c9ebd1a6db2928fff1c8c61c /drivers/usb/host/uhci-q.c | |
parent | 4005ad4390bf698e3bdae9567e79242ec0584097 (diff) | |
download | linux-c44b225077bb1fb25ed5cd5c4f226897b91bedd4.tar.xz |
UHCI: implement new semantics for URB_ISO_ASAP
This patch (as1613) updates the isochronous scheduling in uhci-hcd to
match the new semantics for URB_ISO_ASAP. The amount of code
alteration is smaller than it looks because of a change in the
indentation level.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/host/uhci-q.c')
-rw-r--r-- | drivers/usb/host/uhci-q.c | 73 |
1 files changed, 36 insertions, 37 deletions
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index d2c6f5ac4626..15921fd55048 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1256,7 +1256,8 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, struct uhci_qh *qh) { struct uhci_td *td = NULL; /* Since urb->number_of_packets > 0 */ - int i, frame; + int i; + unsigned frame, next; unsigned long destination, status; struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; @@ -1265,37 +1266,29 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, urb->number_of_packets >= UHCI_NUMFRAMES) return -EFBIG; + uhci_get_current_frame_number(uhci); + /* Check the period and figure out the starting frame number */ if (!qh->bandwidth_reserved) { qh->period = urb->interval; - if (urb->transfer_flags & URB_ISO_ASAP) { - qh->phase = -1; /* Find the best phase */ - i = uhci_check_bandwidth(uhci, qh); - if (i) - return i; - - /* Allow a little time to allocate the TDs */ - uhci_get_current_frame_number(uhci); - frame = uhci->frame_number + 10; - - /* Move forward to the first frame having the - * correct phase */ - urb->start_frame = frame + ((qh->phase - frame) & - (qh->period - 1)); - } else { - i = urb->start_frame - uhci->last_iso_frame; - if (i <= 0 || i >= UHCI_NUMFRAMES) - return -EINVAL; - qh->phase = urb->start_frame & (qh->period - 1); - i = uhci_check_bandwidth(uhci, qh); - if (i) - return i; - } + qh->phase = -1; /* Find the best phase */ + i = uhci_check_bandwidth(uhci, qh); + if (i) + return i; + + /* Allow a little time to allocate the TDs */ + next = uhci->frame_number + 10; + frame = qh->phase; + + /* Round up to the first available slot */ + frame += (next - frame + qh->period - 1) & -qh->period; } else if (qh->period != urb->interval) { return -EINVAL; /* Can't change the period */ } else { + next = uhci->frame_number + 2; + /* Find the next unused frame */ if (list_empty(&qh->queue)) { frame = qh->iso_frame; @@ -1308,25 +1301,31 @@ 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) { - /* Skip some frames if necessary to insure - * the start frame is in the future. + + /* Fell behind? */ + if (uhci_frame_before_eq(frame, next)) { + + /* USB_ISO_ASAP: Round up to the first available slot */ + if (urb->transfer_flags & URB_ISO_ASAP) + frame += (next - frame + qh->period - 1) & + -qh->period; + + /* + * Not ASAP: Use the next slot in the stream. If + * the entire URB falls before the threshold, fail. */ - 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; + else if (!uhci_frame_before_eq(next, + frame + (urb->number_of_packets - 1) * + qh->period)) + return -EXDEV; + } } /* Make sure we won't have to go too far into the future */ if (uhci_frame_before_eq(uhci->last_iso_frame + UHCI_NUMFRAMES, - urb->start_frame + urb->number_of_packets * - urb->interval)) + frame + urb->number_of_packets * urb->interval)) return -EFBIG; + urb->start_frame = frame; status = TD_CTRL_ACTIVE | TD_CTRL_IOS; destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); |