Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c44b2250 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman
Browse files

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: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 4005ad43
Loading
Loading
Loading
Loading
+36 −37
Original line number Original line Diff line number Diff line
@@ -1256,7 +1256,8 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
		struct uhci_qh *qh)
		struct uhci_qh *qh)
{
{
	struct uhci_td *td = NULL;	/* Since urb->number_of_packets > 0 */
	struct uhci_td *td = NULL;	/* Since urb->number_of_packets > 0 */
	int i, frame;
	int i;
	unsigned frame, next;
	unsigned long destination, status;
	unsigned long destination, status;
	struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
	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)
			urb->number_of_packets >= UHCI_NUMFRAMES)
		return -EFBIG;
		return -EFBIG;


	uhci_get_current_frame_number(uhci);

	/* Check the period and figure out the starting frame number */
	/* Check the period and figure out the starting frame number */
	if (!qh->bandwidth_reserved) {
	if (!qh->bandwidth_reserved) {
		qh->period = urb->interval;
		qh->period = urb->interval;
		if (urb->transfer_flags & URB_ISO_ASAP) {
		qh->phase = -1;		/* Find the best phase */
		qh->phase = -1;		/* Find the best phase */
		i = uhci_check_bandwidth(uhci, qh);
		i = uhci_check_bandwidth(uhci, qh);
		if (i)
		if (i)
			return i;
			return i;


		/* Allow a little time to allocate the TDs */
		/* Allow a little time to allocate the TDs */
			uhci_get_current_frame_number(uhci);
		next = uhci->frame_number + 10;
			frame = uhci->frame_number + 10;
		frame = qh->phase;


			/* Move forward to the first frame having the
		/* Round up to the first available slot */
			 * correct phase */
		frame += (next - frame + qh->period - 1) & -qh->period;
			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;
		}


	} else if (qh->period != urb->interval) {
	} else if (qh->period != urb->interval) {
		return -EINVAL;		/* Can't change the period */
		return -EINVAL;		/* Can't change the period */


	} else {
	} else {
		next = uhci->frame_number + 2;

		/* Find the next unused frame */
		/* Find the next unused frame */
		if (list_empty(&qh->queue)) {
		if (list_empty(&qh->queue)) {
			frame = qh->iso_frame;
			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->number_of_packets *
					lurb->interval;
					lurb->interval;
		}
		}
		if (urb->transfer_flags & URB_ISO_ASAP) {

			/* Skip some frames if necessary to insure
		/* Fell behind? */
			 * the start frame is in the future.
		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);
			else if (!uhci_frame_before_eq(next,
			if (uhci_frame_before_eq(frame, uhci->frame_number)) {
					frame + (urb->number_of_packets - 1) *
				frame = uhci->frame_number + 1;
						qh->period))
				frame += ((qh->phase - frame) &
				return -EXDEV;
					(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 */
	/* Make sure we won't have to go too far into the future */
	if (uhci_frame_before_eq(uhci->last_iso_frame + UHCI_NUMFRAMES,
	if (uhci_frame_before_eq(uhci->last_iso_frame + UHCI_NUMFRAMES,
			urb->start_frame + urb->number_of_packets *
			frame + urb->number_of_packets * urb->interval))
				urb->interval))
		return -EFBIG;
		return -EFBIG;
	urb->start_frame = frame;


	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);