diff options
Diffstat (limited to 'drivers/usb/host/uhci-q.c')
| -rw-r--r-- | drivers/usb/host/uhci-q.c | 62 |
1 files changed, 35 insertions, 27 deletions
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 4e0fbe2c1a9a..7e46887d9e12 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c | |||
| @@ -89,10 +89,10 @@ static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, | |||
| 89 | td->frame = framenum; | 89 | td->frame = framenum; |
| 90 | 90 | ||
| 91 | /* Is there a TD already mapped there? */ | 91 | /* Is there a TD already mapped there? */ |
| 92 | if (uhci->fl->frame_cpu[framenum]) { | 92 | if (uhci->frame_cpu[framenum]) { |
| 93 | struct uhci_td *ftd, *ltd; | 93 | struct uhci_td *ftd, *ltd; |
| 94 | 94 | ||
| 95 | ftd = uhci->fl->frame_cpu[framenum]; | 95 | ftd = uhci->frame_cpu[framenum]; |
| 96 | ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list); | 96 | ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list); |
| 97 | 97 | ||
| 98 | list_add_tail(&td->fl_list, &ftd->fl_list); | 98 | list_add_tail(&td->fl_list, &ftd->fl_list); |
| @@ -101,29 +101,32 @@ static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, | |||
| 101 | wmb(); | 101 | wmb(); |
| 102 | ltd->link = cpu_to_le32(td->dma_handle); | 102 | ltd->link = cpu_to_le32(td->dma_handle); |
| 103 | } else { | 103 | } else { |
| 104 | td->link = uhci->fl->frame[framenum]; | 104 | td->link = uhci->frame[framenum]; |
| 105 | wmb(); | 105 | wmb(); |
| 106 | uhci->fl->frame[framenum] = cpu_to_le32(td->dma_handle); | 106 | uhci->frame[framenum] = cpu_to_le32(td->dma_handle); |
| 107 | uhci->fl->frame_cpu[framenum] = td; | 107 | uhci->frame_cpu[framenum] = 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->fl->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->fl->frame[td->frame] = td->link; | 122 | uhci->frame[td->frame] = td->link; |
| 120 | uhci->fl->frame_cpu[td->frame] = NULL; | 123 | uhci->frame_cpu[td->frame] = NULL; |
| 121 | } else { | 124 | } else { |
| 122 | struct uhci_td *ntd; | 125 | struct uhci_td *ntd; |
| 123 | 126 | ||
| 124 | ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list); | 127 | ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list); |
| 125 | uhci->fl->frame[td->frame] = cpu_to_le32(ntd->dma_handle); | 128 | uhci->frame[td->frame] = cpu_to_le32(ntd->dma_handle); |
| 126 | uhci->fl->frame_cpu[td->frame] = ntd; | 129 | uhci->frame_cpu[td->frame] = ntd; |
| 127 | } | 130 | } |
| 128 | } else { | 131 | } else { |
| 129 | struct uhci_td *ptd; | 132 | struct uhci_td *ptd; |
| @@ -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 | */ |
| @@ -443,7 +453,6 @@ static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *u | |||
| 443 | 453 | ||
| 444 | memset((void *)urbp, 0, sizeof(*urbp)); | 454 | memset((void *)urbp, 0, sizeof(*urbp)); |
| 445 | 455 | ||
| 446 | urbp->inserttime = jiffies; | ||
| 447 | urbp->fsbrtime = jiffies; | 456 | urbp->fsbrtime = jiffies; |
| 448 | urbp->urb = urb; | 457 | urbp->urb = urb; |
| 449 | 458 | ||
| @@ -462,8 +471,6 @@ static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td) | |||
| 462 | { | 471 | { |
| 463 | struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; | 472 | struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; |
| 464 | 473 | ||
| 465 | td->urb = urb; | ||
| 466 | |||
| 467 | list_add_tail(&td->list, &urbp->td_list); | 474 | list_add_tail(&td->list, &urbp->td_list); |
| 468 | } | 475 | } |
| 469 | 476 | ||
| @@ -473,8 +480,6 @@ static void uhci_remove_td_from_urb(struct uhci_td *td) | |||
| 473 | return; | 480 | return; |
| 474 | 481 | ||
| 475 | list_del_init(&td->list); | 482 | list_del_init(&td->list); |
| 476 | |||
| 477 | td->urb = NULL; | ||
| 478 | } | 483 | } |
| 479 | 484 | ||
| 480 | static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) | 485 | static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) |
| @@ -503,7 +508,6 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) | |||
| 503 | 508 | ||
| 504 | list_for_each_entry_safe(td, tmp, &urbp->td_list, list) { | 509 | list_for_each_entry_safe(td, tmp, &urbp->td_list, list) { |
| 505 | uhci_remove_td_from_urb(td); | 510 | uhci_remove_td_from_urb(td); |
| 506 | uhci_remove_td(uhci, td); | ||
| 507 | list_add(&td->remove_list, &uhci->td_remove_list); | 511 | list_add(&td->remove_list, &uhci->td_remove_list); |
| 508 | } | 512 | } |
| 509 | 513 | ||
| @@ -1073,6 +1077,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb) | |||
| 1073 | struct uhci_td *td; | 1077 | struct uhci_td *td; |
| 1074 | int i, ret, frame; | 1078 | int i, ret, frame; |
| 1075 | int status, destination; | 1079 | int status, destination; |
| 1080 | struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; | ||
| 1076 | 1081 | ||
| 1077 | status = TD_CTRL_ACTIVE | TD_CTRL_IOS; | 1082 | status = TD_CTRL_ACTIVE | TD_CTRL_IOS; |
| 1078 | destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); | 1083 | destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); |
| @@ -1081,11 +1086,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb) | |||
| 1081 | if (ret) | 1086 | if (ret) |
| 1082 | return ret; | 1087 | return ret; |
| 1083 | 1088 | ||
| 1084 | frame = urb->start_frame; | 1089 | for (i = 0; i < urb->number_of_packets; i++) { |
| 1085 | for (i = 0; i < urb->number_of_packets; i++, frame += urb->interval) { | ||
| 1086 | if (!urb->iso_frame_desc[i].length) | ||
| 1087 | continue; | ||
| 1088 | |||
| 1089 | td = uhci_alloc_td(uhci); | 1090 | td = uhci_alloc_td(uhci); |
| 1090 | if (!td) | 1091 | if (!td) |
| 1091 | return -ENOMEM; | 1092 | return -ENOMEM; |
| @@ -1096,8 +1097,12 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb) | |||
| 1096 | 1097 | ||
| 1097 | if (i + 1 >= urb->number_of_packets) | 1098 | if (i + 1 >= urb->number_of_packets) |
| 1098 | td->status |= cpu_to_le32(TD_CTRL_IOC); | 1099 | td->status |= cpu_to_le32(TD_CTRL_IOC); |
| 1100 | } | ||
| 1099 | 1101 | ||
| 1102 | frame = urb->start_frame; | ||
| 1103 | list_for_each_entry(td, &urbp->td_list, list) { | ||
| 1100 | uhci_insert_td_frame_list(uhci, td, frame); | 1104 | uhci_insert_td_frame_list(uhci, td, frame); |
| 1105 | frame += urb->interval; | ||
| 1101 | } | 1106 | } |
| 1102 | 1107 | ||
| 1103 | return -EINPROGRESS; | 1108 | return -EINPROGRESS; |
| @@ -1110,7 +1115,7 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) | |||
| 1110 | int status; | 1115 | int status; |
| 1111 | int i, ret = 0; | 1116 | int i, ret = 0; |
| 1112 | 1117 | ||
| 1113 | urb->actual_length = 0; | 1118 | urb->actual_length = urb->error_count = 0; |
| 1114 | 1119 | ||
| 1115 | i = 0; | 1120 | i = 0; |
| 1116 | list_for_each_entry(td, &urbp->td_list, list) { | 1121 | list_for_each_entry(td, &urbp->td_list, list) { |
| @@ -1134,6 +1139,7 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) | |||
| 1134 | 1139 | ||
| 1135 | i++; | 1140 | i++; |
| 1136 | } | 1141 | } |
| 1142 | unlink_isochronous_tds(uhci, urb); | ||
| 1137 | 1143 | ||
| 1138 | return ret; | 1144 | return ret; |
| 1139 | } | 1145 | } |
| @@ -1366,6 +1372,8 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) | |||
| 1366 | goto done; | 1372 | goto done; |
| 1367 | list_del_init(&urbp->urb_list); | 1373 | list_del_init(&urbp->urb_list); |
| 1368 | 1374 | ||
| 1375 | if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) | ||
| 1376 | unlink_isochronous_tds(uhci, urb); | ||
| 1369 | uhci_unlink_generic(uhci, urb); | 1377 | uhci_unlink_generic(uhci, urb); |
| 1370 | 1378 | ||
| 1371 | uhci_get_current_frame_number(uhci); | 1379 | uhci_get_current_frame_number(uhci); |
