diff options
| -rw-r--r-- | drivers/usb/host/uhci-debug.c | 5 | ||||
| -rw-r--r-- | drivers/usb/host/uhci-hcd.h | 36 | ||||
| -rw-r--r-- | drivers/usb/host/uhci-q.c | 72 |
3 files changed, 63 insertions, 50 deletions
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index ecef5880cfd9..ab8ba8220ad1 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 c87ceaa178b6..eaac6ddf03a0 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 | */ | ||
| 329 | static 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 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 | ||
| 793 | static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, | 794 | static 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 | ||
