diff options
-rw-r--r-- | drivers/usb/host/uhci-q.c | 39 |
1 files changed, 26 insertions, 13 deletions
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 51de06bc438d..7e46887d9e12 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c | |||
@@ -108,13 +108,16 @@ static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, | |||
108 | } | 108 | } |
109 | } | 109 | } |
110 | 110 | ||
111 | static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td) | 111 | static inline void uhci_remove_td_frame_list(struct uhci_hcd *uhci, |
112 | struct uhci_td *td) | ||
112 | { | 113 | { |
113 | /* If it's not inserted, don't remove it */ | 114 | /* If it's not inserted, don't remove it */ |
114 | if (td->frame == -1 && list_empty(&td->fl_list)) | 115 | if (td->frame == -1) { |
116 | WARN_ON(!list_empty(&td->fl_list)); | ||
115 | return; | 117 | return; |
118 | } | ||
116 | 119 | ||
117 | if (td->frame != -1 && uhci->frame_cpu[td->frame] == td) { | 120 | if (uhci->frame_cpu[td->frame] == td) { |
118 | if (list_empty(&td->fl_list)) { | 121 | if (list_empty(&td->fl_list)) { |
119 | uhci->frame[td->frame] = td->link; | 122 | uhci->frame[td->frame] = td->link; |
120 | uhci->frame_cpu[td->frame] = NULL; | 123 | uhci->frame_cpu[td->frame] = NULL; |
@@ -132,13 +135,20 @@ static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td) | |||
132 | ptd->link = td->link; | 135 | ptd->link = td->link; |
133 | } | 136 | } |
134 | 137 | ||
135 | wmb(); | ||
136 | td->link = UHCI_PTR_TERM; | ||
137 | |||
138 | list_del_init(&td->fl_list); | 138 | list_del_init(&td->fl_list); |
139 | td->frame = -1; | 139 | td->frame = -1; |
140 | } | 140 | } |
141 | 141 | ||
142 | static void unlink_isochronous_tds(struct uhci_hcd *uhci, struct urb *urb) | ||
143 | { | ||
144 | struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; | ||
145 | struct uhci_td *td; | ||
146 | |||
147 | list_for_each_entry(td, &urbp->td_list, list) | ||
148 | uhci_remove_td_frame_list(uhci, td); | ||
149 | wmb(); | ||
150 | } | ||
151 | |||
142 | /* | 152 | /* |
143 | * Inserts a td list into qh. | 153 | * Inserts a td list into qh. |
144 | */ | 154 | */ |
@@ -498,7 +508,6 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) | |||
498 | 508 | ||
499 | list_for_each_entry_safe(td, tmp, &urbp->td_list, list) { | 509 | list_for_each_entry_safe(td, tmp, &urbp->td_list, list) { |
500 | uhci_remove_td_from_urb(td); | 510 | uhci_remove_td_from_urb(td); |
501 | uhci_remove_td(uhci, td); | ||
502 | list_add(&td->remove_list, &uhci->td_remove_list); | 511 | list_add(&td->remove_list, &uhci->td_remove_list); |
503 | } | 512 | } |
504 | 513 | ||
@@ -1068,6 +1077,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb) | |||
1068 | struct uhci_td *td; | 1077 | struct uhci_td *td; |
1069 | int i, ret, frame; | 1078 | int i, ret, frame; |
1070 | int status, destination; | 1079 | int status, destination; |
1080 | struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; | ||
1071 | 1081 | ||
1072 | status = TD_CTRL_ACTIVE | TD_CTRL_IOS; | 1082 | status = TD_CTRL_ACTIVE | TD_CTRL_IOS; |
1073 | destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); | 1083 | destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); |
@@ -1076,11 +1086,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb) | |||
1076 | if (ret) | 1086 | if (ret) |
1077 | return ret; | 1087 | return ret; |
1078 | 1088 | ||
1079 | frame = urb->start_frame; | 1089 | for (i = 0; i < urb->number_of_packets; i++) { |
1080 | for (i = 0; i < urb->number_of_packets; i++, frame += urb->interval) { | ||
1081 | if (!urb->iso_frame_desc[i].length) | ||
1082 | continue; | ||
1083 | |||
1084 | td = uhci_alloc_td(uhci); | 1090 | td = uhci_alloc_td(uhci); |
1085 | if (!td) | 1091 | if (!td) |
1086 | return -ENOMEM; | 1092 | return -ENOMEM; |
@@ -1091,8 +1097,12 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb) | |||
1091 | 1097 | ||
1092 | if (i + 1 >= urb->number_of_packets) | 1098 | if (i + 1 >= urb->number_of_packets) |
1093 | td->status |= cpu_to_le32(TD_CTRL_IOC); | 1099 | td->status |= cpu_to_le32(TD_CTRL_IOC); |
1100 | } | ||
1094 | 1101 | ||
1102 | frame = urb->start_frame; | ||
1103 | list_for_each_entry(td, &urbp->td_list, list) { | ||
1095 | uhci_insert_td_frame_list(uhci, td, frame); | 1104 | uhci_insert_td_frame_list(uhci, td, frame); |
1105 | frame += urb->interval; | ||
1096 | } | 1106 | } |
1097 | 1107 | ||
1098 | return -EINPROGRESS; | 1108 | return -EINPROGRESS; |
@@ -1105,7 +1115,7 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) | |||
1105 | int status; | 1115 | int status; |
1106 | int i, ret = 0; | 1116 | int i, ret = 0; |
1107 | 1117 | ||
1108 | urb->actual_length = 0; | 1118 | urb->actual_length = urb->error_count = 0; |
1109 | 1119 | ||
1110 | i = 0; | 1120 | i = 0; |
1111 | list_for_each_entry(td, &urbp->td_list, list) { | 1121 | list_for_each_entry(td, &urbp->td_list, list) { |
@@ -1129,6 +1139,7 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) | |||
1129 | 1139 | ||
1130 | i++; | 1140 | i++; |
1131 | } | 1141 | } |
1142 | unlink_isochronous_tds(uhci, urb); | ||
1132 | 1143 | ||
1133 | return ret; | 1144 | return ret; |
1134 | } | 1145 | } |
@@ -1361,6 +1372,8 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) | |||
1361 | goto done; | 1372 | goto done; |
1362 | list_del_init(&urbp->urb_list); | 1373 | list_del_init(&urbp->urb_list); |
1363 | 1374 | ||
1375 | if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) | ||
1376 | unlink_isochronous_tds(uhci, urb); | ||
1364 | uhci_unlink_generic(uhci, urb); | 1377 | uhci_unlink_generic(uhci, urb); |
1365 | 1378 | ||
1366 | uhci_get_current_frame_number(uhci); | 1379 | uhci_get_current_frame_number(uhci); |