aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/uhci-q.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/uhci-q.c')
-rw-r--r--drivers/usb/host/uhci-q.c103
1 files changed, 73 insertions, 30 deletions
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 7acc23473c63..cbbaa4c1740f 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -184,6 +184,24 @@ static inline void uhci_remove_td_from_frame_list(struct uhci_hcd *uhci,
184 td->frame = -1; 184 td->frame = -1;
185} 185}
186 186
187static inline void uhci_remove_tds_from_frame(struct uhci_hcd *uhci,
188 unsigned int framenum)
189{
190 struct uhci_td *ftd, *ltd;
191
192 framenum &= (UHCI_NUMFRAMES - 1);
193
194 ftd = uhci->frame_cpu[framenum];
195 if (ftd) {
196 ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list);
197 uhci->frame[framenum] = ltd->link;
198 uhci->frame_cpu[framenum] = NULL;
199
200 while (!list_empty(&ftd->fl_list))
201 list_del_init(ftd->fl_list.prev);
202 }
203}
204
187/* 205/*
188 * Remove all the TDs for an Isochronous URB from the frame list 206 * Remove all the TDs for an Isochronous URB from the frame list
189 */ 207 */
@@ -523,7 +541,6 @@ static int uhci_map_status(int status, int dir_out)
523 return -ENOSR; 541 return -ENOSR;
524 if (status & TD_CTRL_STALLED) /* Stalled */ 542 if (status & TD_CTRL_STALLED) /* Stalled */
525 return -EPIPE; 543 return -EPIPE;
526 WARN_ON(status & TD_CTRL_ACTIVE); /* Active */
527 return 0; 544 return 0;
528} 545}
529 546
@@ -960,12 +977,12 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
960 return -EFBIG; 977 return -EFBIG;
961 978
962 /* Check the period and figure out the starting frame number */ 979 /* Check the period and figure out the starting frame number */
963 uhci_get_current_frame_number(uhci);
964 if (qh->period == 0) { 980 if (qh->period == 0) {
965 if (urb->transfer_flags & URB_ISO_ASAP) { 981 if (urb->transfer_flags & URB_ISO_ASAP) {
982 uhci_get_current_frame_number(uhci);
966 urb->start_frame = uhci->frame_number + 10; 983 urb->start_frame = uhci->frame_number + 10;
967 } else { 984 } else {
968 i = urb->start_frame - uhci->frame_number; 985 i = urb->start_frame - uhci->last_iso_frame;
969 if (i <= 0 || i >= UHCI_NUMFRAMES) 986 if (i <= 0 || i >= UHCI_NUMFRAMES)
970 return -EINVAL; 987 return -EINVAL;
971 } 988 }
@@ -974,7 +991,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
974 991
975 } else { /* Pick up where the last URB leaves off */ 992 } else { /* Pick up where the last URB leaves off */
976 if (list_empty(&qh->queue)) { 993 if (list_empty(&qh->queue)) {
977 frame = uhci->frame_number + 10; 994 frame = qh->iso_frame;
978 } else { 995 } else {
979 struct urb *lurb; 996 struct urb *lurb;
980 997
@@ -986,11 +1003,12 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
986 } 1003 }
987 if (urb->transfer_flags & URB_ISO_ASAP) 1004 if (urb->transfer_flags & URB_ISO_ASAP)
988 urb->start_frame = frame; 1005 urb->start_frame = frame;
989 /* FIXME: Sanity check */ 1006 else if (urb->start_frame != frame)
1007 return -EINVAL;
990 } 1008 }
991 1009
992 /* Make sure we won't have to go too far into the future */ 1010 /* Make sure we won't have to go too far into the future */
993 if (uhci_frame_before_eq(uhci->frame_number + UHCI_NUMFRAMES, 1011 if (uhci_frame_before_eq(uhci->last_iso_frame + UHCI_NUMFRAMES,
994 urb->start_frame + urb->number_of_packets * 1012 urb->start_frame + urb->number_of_packets *
995 urb->interval)) 1013 urb->interval))
996 return -EFBIG; 1014 return -EFBIG;
@@ -1020,7 +1038,13 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
1020 frame = urb->start_frame; 1038 frame = urb->start_frame;
1021 list_for_each_entry(td, &urbp->td_list, list) { 1039 list_for_each_entry(td, &urbp->td_list, list) {
1022 uhci_insert_td_in_frame_list(uhci, td, frame); 1040 uhci_insert_td_in_frame_list(uhci, td, frame);
1023 frame += urb->interval; 1041 frame += qh->period;
1042 }
1043
1044 if (list_empty(&qh->queue)) {
1045 qh->iso_packet_desc = &urb->iso_frame_desc[0];
1046 qh->iso_frame = urb->start_frame;
1047 qh->iso_status = 0;
1024 } 1048 }
1025 1049
1026 return 0; 1050 return 0;
@@ -1028,37 +1052,44 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
1028 1052
1029static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) 1053static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
1030{ 1054{
1031 struct uhci_td *td; 1055 struct uhci_td *td, *tmp;
1032 struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; 1056 struct urb_priv *urbp = urb->hcpriv;
1033 int status; 1057 struct uhci_qh *qh = urbp->qh;
1034 int i, ret = 0;
1035
1036 urb->actual_length = urb->error_count = 0;
1037 1058
1038 i = 0; 1059 list_for_each_entry_safe(td, tmp, &urbp->td_list, list) {
1039 list_for_each_entry(td, &urbp->td_list, list) { 1060 unsigned int ctrlstat;
1061 int status;
1040 int actlength; 1062 int actlength;
1041 unsigned int ctrlstat = td_status(td);
1042 1063
1043 if (ctrlstat & TD_CTRL_ACTIVE) 1064 if (uhci_frame_before_eq(uhci->cur_iso_frame, qh->iso_frame))
1044 return -EINPROGRESS; 1065 return -EINPROGRESS;
1045 1066
1046 actlength = uhci_actual_length(ctrlstat); 1067 uhci_remove_tds_from_frame(uhci, qh->iso_frame);
1047 urb->iso_frame_desc[i].actual_length = actlength; 1068
1048 urb->actual_length += actlength; 1069 ctrlstat = td_status(td);
1070 if (ctrlstat & TD_CTRL_ACTIVE) {
1071 status = -EXDEV; /* TD was added too late? */
1072 } else {
1073 status = uhci_map_status(uhci_status_bits(ctrlstat),
1074 usb_pipeout(urb->pipe));
1075 actlength = uhci_actual_length(ctrlstat);
1076
1077 urb->actual_length += actlength;
1078 qh->iso_packet_desc->actual_length = actlength;
1079 qh->iso_packet_desc->status = status;
1080 }
1049 1081
1050 status = uhci_map_status(uhci_status_bits(ctrlstat),
1051 usb_pipeout(urb->pipe));
1052 urb->iso_frame_desc[i].status = status;
1053 if (status) { 1082 if (status) {
1054 urb->error_count++; 1083 urb->error_count++;
1055 ret = status; 1084 qh->iso_status = status;
1056 } 1085 }
1057 1086
1058 i++; 1087 uhci_remove_td_from_urbp(td);
1088 uhci_free_td(uhci, td);
1089 qh->iso_frame += qh->period;
1090 ++qh->iso_packet_desc;
1059 } 1091 }
1060 1092 return qh->iso_status;
1061 return ret;
1062} 1093}
1063 1094
1064static int uhci_urb_enqueue(struct usb_hcd *hcd, 1095static int uhci_urb_enqueue(struct usb_hcd *hcd,
@@ -1119,6 +1150,7 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
1119 } 1150 }
1120 break; 1151 break;
1121 case USB_ENDPOINT_XFER_ISOC: 1152 case USB_ENDPOINT_XFER_ISOC:
1153 urb->error_count = 0;
1122 bustime = usb_check_bandwidth(urb->dev, urb); 1154 bustime = usb_check_bandwidth(urb->dev, urb);
1123 if (bustime < 0) { 1155 if (bustime < 0) {
1124 ret = bustime; 1156 ret = bustime;
@@ -1200,9 +1232,18 @@ __acquires(uhci->lock)
1200{ 1232{
1201 struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; 1233 struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
1202 1234
1203 /* Isochronous TDs get unlinked directly from the frame list */ 1235 /* When giving back the first URB in an Isochronous queue,
1204 if (qh->type == USB_ENDPOINT_XFER_ISOC) 1236 * reinitialize the QH's iso-related members for the next URB. */
1205 uhci_unlink_isochronous_tds(uhci, urb); 1237 if (qh->type == USB_ENDPOINT_XFER_ISOC &&
1238 urbp->node.prev == &qh->queue &&
1239 urbp->node.next != &qh->queue) {
1240 struct urb *nurb = list_entry(urbp->node.next,
1241 struct urb_priv, node)->urb;
1242
1243 qh->iso_packet_desc = &nurb->iso_frame_desc[0];
1244 qh->iso_frame = nurb->start_frame;
1245 qh->iso_status = 0;
1246 }
1206 1247
1207 /* Take the URB off the QH's queue. If the queue is now empty, 1248 /* Take the URB off the QH's queue. If the queue is now empty,
1208 * this is a perfect time for a toggle fixup. */ 1249 * this is a perfect time for a toggle fixup. */
@@ -1434,6 +1475,7 @@ rescan:
1434 1475
1435 uhci_clear_next_interrupt(uhci); 1476 uhci_clear_next_interrupt(uhci);
1436 uhci_get_current_frame_number(uhci); 1477 uhci_get_current_frame_number(uhci);
1478 uhci->cur_iso_frame = uhci->frame_number;
1437 1479
1438 /* Go through all the QH queues and process the URBs in each one */ 1480 /* Go through all the QH queues and process the URBs in each one */
1439 for (i = 0; i < UHCI_NUM_SKELQH - 1; ++i) { 1481 for (i = 0; i < UHCI_NUM_SKELQH - 1; ++i) {
@@ -1451,6 +1493,7 @@ rescan:
1451 } 1493 }
1452 } 1494 }
1453 1495
1496 uhci->last_iso_frame = uhci->cur_iso_frame;
1454 if (uhci->need_rescan) 1497 if (uhci->need_rescan)
1455 goto rescan; 1498 goto rescan;
1456 uhci->scan_in_progress = 0; 1499 uhci->scan_in_progress = 0;