aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/host/uhci-debug.c5
-rw-r--r--drivers/usb/host/uhci-hcd.h36
-rw-r--r--drivers/usb/host/uhci-q.c72
3 files changed, 63 insertions, 50 deletions
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index ecef5880cfd..ab8ba8220ad 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -153,7 +153,7 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
153 char *qtype; 153 char *qtype;
154 154
155 /* Try to make sure there's enough memory */ 155 /* Try to make sure there's enough memory */
156 if (len < 80 * 6) 156 if (len < 80 * 7)
157 return 0; 157 return 0;
158 158
159 switch (qh->type) { 159 switch (qh->type) {
@@ -167,6 +167,9 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
167 out += sprintf(out, "%*s[%p] %s QH link (%08x) element (%08x)\n", 167 out += sprintf(out, "%*s[%p] %s QH link (%08x) element (%08x)\n",
168 space, "", qh, qtype, 168 space, "", qh, qtype,
169 le32_to_cpu(qh->link), le32_to_cpu(element)); 169 le32_to_cpu(qh->link), le32_to_cpu(element));
170 if (qh->type == USB_ENDPOINT_XFER_ISOC)
171 out += sprintf(out, "%*s period %d\n",
172 space, "", qh->period);
170 173
171 if (element & UHCI_PTR_QH) 174 if (element & UHCI_PTR_QH)
172 out += sprintf(out, "%*s Element points to QH (bug?)\n", space, ""); 175 out += sprintf(out, "%*s Element points to QH (bug?)\n", space, "");
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index c87ceaa178b..eaac6ddf03a 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -140,6 +140,8 @@ struct uhci_qh {
140 140
141 unsigned long advance_jiffies; /* Time of last queue advance */ 141 unsigned long advance_jiffies; /* Time of last queue advance */
142 unsigned int unlink_frame; /* When the QH was unlinked */ 142 unsigned int unlink_frame; /* When the QH was unlinked */
143 unsigned int period; /* For Interrupt and Isochronous QHs */
144
143 int state; /* QH_STATE_xxx; see above */ 145 int state; /* QH_STATE_xxx; see above */
144 int type; /* Queue type (control, bulk, etc) */ 146 int type; /* Queue type (control, bulk, etc) */
145 147
@@ -315,38 +317,8 @@ static inline u32 td_status(struct uhci_td *td) {
315#define skel_bulk_qh skelqh[12] 317#define skel_bulk_qh skelqh[12]
316#define skel_term_qh skelqh[13] 318#define skel_term_qh skelqh[13]
317 319
318/* 320/* Find the skelqh entry corresponding to an interval exponent */
319 * Search tree for determining where <interval> fits in the skelqh[] 321#define UHCI_SKEL_INDEX(exponent) (9 - exponent)
320 * skeleton.
321 *
322 * An interrupt request should be placed into the slowest skelqh[]
323 * which meets the interval/period/frequency requirement.
324 * An interrupt request is allowed to be faster than <interval> but not slower.
325 *
326 * For a given <interval>, this function returns the appropriate/matching
327 * skelqh[] index value.
328 */
329static inline int __interval_to_skel(int interval)
330{
331 if (interval < 16) {
332 if (interval < 4) {
333 if (interval < 2)
334 return 9; /* int1 for 0-1 ms */
335 return 8; /* int2 for 2-3 ms */
336 }
337 if (interval < 8)
338 return 7; /* int4 for 4-7 ms */
339 return 6; /* int8 for 8-15 ms */
340 }
341 if (interval < 64) {
342 if (interval < 32)
343 return 5; /* int16 for 16-31 ms */
344 return 4; /* int32 for 32-63 ms */
345 }
346 if (interval < 128)
347 return 3; /* int64 for 64-127 ms */
348 return 2; /* int128 for 128-255 ms (Max.) */
349}
350 322
351 323
352/* 324/*
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 96ce4c87c87..7acc23473c6 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