Browse Source

USB: IMX21: upgrade the isochronous API

This patch attempts to update the imx21-hcd driver to the current
standard for the isochronous API.  Firstly, urb->start_frame should
always be set by the driver; it is not an input parameter.  Secondly,
the URB_ISO_ASAP flag matters only when an URB is submitted to a
stream that has gotten an underrun.  It causes the URB to be scheduled
for the next available slot in the future, rather than the earliest
unused (and expired) slot.

Unfortunately, I don't have any way to test these changes.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
CC: Sascha Hauer <kernel@pengutronix.de>
CC: Martin Fuzzey <mfuzzey@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Alan Stern 12 years ago
parent
commit
9db33f3174
1 changed files with 26 additions and 17 deletions
  1. 26 17
      drivers/usb/host/imx21-hcd.c

+ 26 - 17
drivers/usb/host/imx21-hcd.c

@@ -809,26 +809,36 @@ static int imx21_hc_urb_enqueue_isoc(struct usb_hcd *hcd,
 
 	/* calculate frame */
 	cur_frame = imx21_hc_get_frame(hcd);
-	if (urb->transfer_flags & URB_ISO_ASAP) {
-		if (list_empty(&ep_priv->td_list))
-			urb->start_frame = cur_frame + 5;
-		else
-			urb->start_frame = list_entry(
-				ep_priv->td_list.prev,
-				struct td, list)->frame + urb->interval;
-	}
-	urb->start_frame = wrap_frame(urb->start_frame);
-	if (frame_after(cur_frame, urb->start_frame)) {
-		dev_dbg(imx21->dev,
-			"enqueue: adjusting iso start %d (cur=%d) asap=%d\n",
-			urb->start_frame, cur_frame,
-			(urb->transfer_flags & URB_ISO_ASAP) != 0);
-		urb->start_frame = wrap_frame(cur_frame + 1);
+	i = 0;
+	if (list_empty(&ep_priv->td_list)) {
+		urb->start_frame = wrap_frame(cur_frame + 5);
+	} else {
+		urb->start_frame = wrap_frame(list_entry(ep_priv->td_list.prev,
+				struct td, list)->frame + urb->interval);
+
+		if (frame_after(cur_frame, urb->start_frame)) {
+			dev_dbg(imx21->dev,
+				"enqueue: adjusting iso start %d (cur=%d) asap=%d\n",
+				urb->start_frame, cur_frame,
+				(urb->transfer_flags & URB_ISO_ASAP) != 0);
+			i = DIV_ROUND_UP(wrap_frame(
+					cur_frame - urb->start_frame),
+					urb->interval);
+			if (urb->transfer_flags & URB_ISO_ASAP) {
+				urb->start_frame = wrap_frame(urb->start_frame
+						+ i * urb->interval);
+				i = 0;
+			} else if (i >= urb->number_of_packets) {
+				ret = -EXDEV;
+				goto alloc_dmem_failed;
+			}
+		}
 	}
 
 	/* set up transfers */
+	urb_priv->isoc_remaining = urb->number_of_packets - i;
 	td = urb_priv->isoc_td;
-	for (i = 0; i < urb->number_of_packets; i++, td++) {
+	for (; i < urb->number_of_packets; i++, td++) {
 		unsigned int offset = urb->iso_frame_desc[i].offset;
 		td->ep = ep;
 		td->urb = urb;
@@ -840,7 +850,6 @@ static int imx21_hc_urb_enqueue_isoc(struct usb_hcd *hcd,
 		list_add_tail(&td->list, &ep_priv->td_list);
 	}
 
-	urb_priv->isoc_remaining = urb->number_of_packets;
 	dev_vdbg(imx21->dev, "setup %d packets for iso frame %d->%d\n",
 		urb->number_of_packets, urb->start_frame, td->frame);