aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/host/uhci-q.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/uhci-q.c')
-rw-r--r--drivers/usb/host/uhci-q.c87
1 files changed, 45 insertions, 42 deletions
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 84ed28b34f9..da6f56d996c 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -280,7 +280,7 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
qh->load = usb_calc_bus_time(udev->speed,
usb_endpoint_dir_in(&hep->desc),
qh->type == USB_ENDPOINT_XFER_ISOC,
- le16_to_cpu(hep->desc.wMaxPacketSize))
+ usb_endpoint_maxp(&hep->desc))
/ 1000 + 1;
} else { /* Skeleton QH */
@@ -792,7 +792,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
{
struct uhci_td *td;
unsigned long destination, status;
- int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize);
+ int maxsze = usb_endpoint_maxp(&qh->hep->desc);
int len = urb->transfer_buffer_length;
dma_addr_t data = urb->transfer_dma;
__hc32 *plink;
@@ -918,7 +918,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
{
struct uhci_td *td;
unsigned long destination, status;
- int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize);
+ int maxsze = usb_endpoint_maxp(&qh->hep->desc);
int len = urb->transfer_buffer_length;
int this_sg_len;
dma_addr_t data;
@@ -943,7 +943,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
if (usb_pipein(urb->pipe))
status |= TD_CTRL_SPD;
- i = urb->num_sgs;
+ i = urb->num_mapped_sgs;
if (len > 0 && i > 0) {
sg = urb->sg;
data = sg_dma_address(sg);
@@ -1200,7 +1200,7 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
if (debug > 1 && errbuf) {
/* Print the chain for debugging */
uhci_show_qh(uhci, urbp->qh, errbuf,
- ERRBUF_LEN, 0);
+ ERRBUF_LEN - EXTRA_SPACE, 0);
lprintk(errbuf);
}
}
@@ -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 + 1;
+
/* Find the next unused frame */
if (list_empty(&qh->queue)) {
frame = qh->iso_frame;
@@ -1308,25 +1301,35 @@ 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(next, frame)) {
+
+ /* 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,
+ * no matter what.
*/
- 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))
+ dev_dbg(uhci_dev(uhci), "iso underrun %p (%u+%u < %u)\n",
+ urb, frame,
+ (urb->number_of_packets - 1) *
+ qh->period,
+ next);
+ }
}
/* 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);