aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/uhci-q.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2006-05-19 16:44:55 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-06-21 18:04:12 -0400
commitcaf3827a65af476c71eaeb79636869a4ab128d48 (patch)
tree78ef5d5ec466e59d9ac626faf34fb1031ba4fd8e /drivers/usb/host/uhci-q.c
parent10b8e47d6b32bfba22874354c62770cb4e42aa6c (diff)
[PATCH] UHCI: store the period in the queue header
This patch (as689) stores the period for periodic transfers (interrupt and ISO) in the queue header. This is necessary for proper bandwidth tracking (not yet implemented). It also makes the scheduling of ISO transfers a bit more rigorous, with checks for out-of-bounds frame numbers. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/uhci-q.c')
-rw-r--r--drivers/usb/host/uhci-q.c72
1 files changed, 55 insertions, 17 deletions
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 96ce4c87c871..7acc23473c63 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -763,6 +763,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
763 wmb(); 763 wmb();
764 qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE); 764 qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE);
765 qh->dummy_td = td; 765 qh->dummy_td = td;
766 qh->period = urb->interval;
766 767
767 usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), 768 usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
768 usb_pipeout(urb->pipe), toggle); 769 usb_pipeout(urb->pipe), toggle);
@@ -790,14 +791,30 @@ static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb,
790 return ret; 791 return ret;
791} 792}
792 793
793static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, 794static int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb,
794 struct uhci_qh *qh) 795 struct uhci_qh *qh)
795{ 796{
797 int exponent;
798
796 /* USB 1.1 interrupt transfers only involve one packet per interval. 799 /* USB 1.1 interrupt transfers only involve one packet per interval.
797 * Drivers can submit URBs of any length, but longer ones will need 800 * Drivers can submit URBs of any length, but longer ones will need
798 * multiple intervals to complete. 801 * multiple intervals to complete.
799 */ 802 */
800 qh->skel = uhci->skelqh[__interval_to_skel(urb->interval)]; 803
804 /* Figure out which power-of-two queue to use */
805 for (exponent = 7; exponent >= 0; --exponent) {
806 if ((1 << exponent) <= urb->interval)
807 break;
808 }
809 if (exponent < 0)
810 return -EINVAL;
811 urb->interval = 1 << exponent;
812
813 if (qh->period == 0)
814 qh->skel = uhci->skelqh[UHCI_SKEL_INDEX(exponent)];
815 else if (qh->period != urb->interval)
816 return -EINVAL; /* Can't change the period */
817
801 return uhci_submit_common(uhci, urb, qh); 818 return uhci_submit_common(uhci, urb, qh);
802} 819}
803 820
@@ -937,31 +954,50 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
937 unsigned long destination, status; 954 unsigned long destination, status;
938 struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; 955 struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
939 956
940 if (urb->number_of_packets > 900) /* 900? Why? */ 957 /* Values must not be too big (could overflow below) */
958 if (urb->interval >= UHCI_NUMFRAMES ||
959 urb->number_of_packets >= UHCI_NUMFRAMES)
941 return -EFBIG; 960 return -EFBIG;
942 961
943 status = TD_CTRL_ACTIVE | TD_CTRL_IOS; 962 /* Check the period and figure out the starting frame number */
944 destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); 963 uhci_get_current_frame_number(uhci);
964 if (qh->period == 0) {
965 if (urb->transfer_flags & URB_ISO_ASAP) {
966 urb->start_frame = uhci->frame_number + 10;
967 } else {
968 i = urb->start_frame - uhci->frame_number;
969 if (i <= 0 || i >= UHCI_NUMFRAMES)
970 return -EINVAL;
971 }
972 } else if (qh->period != urb->interval) {
973 return -EINVAL; /* Can't change the period */
945 974
946 /* Figure out the starting frame number */ 975 } else { /* Pick up where the last URB leaves off */
947 if (urb->transfer_flags & URB_ISO_ASAP) {
948 if (list_empty(&qh->queue)) { 976 if (list_empty(&qh->queue)) {
949 uhci_get_current_frame_number(uhci); 977 frame = uhci->frame_number + 10;
950 urb->start_frame = (uhci->frame_number + 10); 978 } else {
951 979 struct urb *lurb;
952 } else { /* Go right after the last one */
953 struct urb *last_urb;
954 980
955 last_urb = list_entry(qh->queue.prev, 981 lurb = list_entry(qh->queue.prev,
956 struct urb_priv, node)->urb; 982 struct urb_priv, node)->urb;
957 urb->start_frame = (last_urb->start_frame + 983 frame = lurb->start_frame +
958 last_urb->number_of_packets * 984 lurb->number_of_packets *
959 last_urb->interval); 985 lurb->interval;
960 } 986 }
961 } else { 987 if (urb->transfer_flags & URB_ISO_ASAP)
988 urb->start_frame = frame;
962 /* FIXME: Sanity check */ 989 /* FIXME: Sanity check */
963 } 990 }
964 991
992 /* Make sure we won't have to go too far into the future */
993 if (uhci_frame_before_eq(uhci->frame_number + UHCI_NUMFRAMES,
994 urb->start_frame + urb->number_of_packets *
995 urb->interval))
996 return -EFBIG;
997
998 status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
999 destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
1000
965 for (i = 0; i < urb->number_of_packets; i++) { 1001 for (i = 0; i < urb->number_of_packets; i++) {
966 td = uhci_alloc_td(uhci); 1002 td = uhci_alloc_td(uhci);
967 if (!td) 1003 if (!td)
@@ -978,6 +1014,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
978 td->status |= __constant_cpu_to_le32(TD_CTRL_IOC); 1014 td->status |= __constant_cpu_to_le32(TD_CTRL_IOC);
979 1015
980 qh->skel = uhci->skel_iso_qh; 1016 qh->skel = uhci->skel_iso_qh;
1017 qh->period = urb->interval;
981 1018
982 /* Add the TDs to the frame list */ 1019 /* Add the TDs to the frame list */
983 frame = urb->start_frame; 1020 frame = urb->start_frame;
@@ -1206,6 +1243,7 @@ __acquires(uhci->lock)
1206 uhci_unlink_qh(uhci, qh); 1243 uhci_unlink_qh(uhci, qh);
1207 1244
1208 /* Bandwidth stuff not yet implemented */ 1245 /* Bandwidth stuff not yet implemented */
1246 qh->period = 0;
1209 } 1247 }
1210} 1248}
1211 1249