diff options
author | Jan Andersson <jan@gaisler.com> | 2011-05-18 04:44:51 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-05-19 19:43:20 -0400 |
commit | 51e2f62fe79651e7ed8e16ba126a163b116fe3d7 (patch) | |
tree | a46c220bf5a9ff3b4fd8195e127e69e0b8619222 /drivers/usb/host/uhci-debug.c | |
parent | bab1ff1bda27e654dfd382a1fbdfcda1f7ed0a37 (diff) |
USB: UHCI: Add support for big endian descriptors
This patch adds support for universal host controllers that use
big endian descriptors. Support for BE descriptors requires a non-PCI
host controller. For kernels with PCI-only UHCI there should be no
change in behaviour.
This patch tries to replicate the technique used to support BE descriptors
in the EHCI HCD. Parts added to uhci-hcd.h are basically copy'n'paste from
ehci.h.
Signed-off-by: Jan Andersson <jan@gaisler.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/uhci-debug.c')
-rw-r--r-- | drivers/usb/host/uhci-debug.c | 71 |
1 files changed, 39 insertions, 32 deletions
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index f882a84b1bbb..fc0b0daac93d 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c | |||
@@ -37,7 +37,8 @@ static void lprintk(char *buf) | |||
37 | } | 37 | } |
38 | } | 38 | } |
39 | 39 | ||
40 | static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space) | 40 | static int uhci_show_td(struct uhci_hcd *uhci, struct uhci_td *td, char *buf, |
41 | int len, int space) | ||
41 | { | 42 | { |
42 | char *out = buf; | 43 | char *out = buf; |
43 | char *spid; | 44 | char *spid; |
@@ -47,8 +48,9 @@ static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space) | |||
47 | if (len < 160) | 48 | if (len < 160) |
48 | return 0; | 49 | return 0; |
49 | 50 | ||
50 | status = td_status(td); | 51 | status = td_status(uhci, td); |
51 | out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td, le32_to_cpu(td->link)); | 52 | out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td, |
53 | hc32_to_cpu(uhci, td->link)); | ||
52 | out += sprintf(out, "e%d %s%s%s%s%s%s%s%s%s%sLength=%x ", | 54 | out += sprintf(out, "e%d %s%s%s%s%s%s%s%s%s%sLength=%x ", |
53 | ((status >> 27) & 3), | 55 | ((status >> 27) & 3), |
54 | (status & TD_CTRL_SPD) ? "SPD " : "", | 56 | (status & TD_CTRL_SPD) ? "SPD " : "", |
@@ -63,7 +65,7 @@ static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space) | |||
63 | (status & TD_CTRL_BITSTUFF) ? "BitStuff " : "", | 65 | (status & TD_CTRL_BITSTUFF) ? "BitStuff " : "", |
64 | status & 0x7ff); | 66 | status & 0x7ff); |
65 | 67 | ||
66 | token = td_token(td); | 68 | token = td_token(uhci, td); |
67 | switch (uhci_packetid(token)) { | 69 | switch (uhci_packetid(token)) { |
68 | case USB_PID_SETUP: | 70 | case USB_PID_SETUP: |
69 | spid = "SETUP"; | 71 | spid = "SETUP"; |
@@ -86,12 +88,13 @@ static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space) | |||
86 | (token >> 8) & 127, | 88 | (token >> 8) & 127, |
87 | (token & 0xff), | 89 | (token & 0xff), |
88 | spid); | 90 | spid); |
89 | out += sprintf(out, "(buf=%08x)\n", le32_to_cpu(td->buffer)); | 91 | out += sprintf(out, "(buf=%08x)\n", hc32_to_cpu(uhci, td->buffer)); |
90 | 92 | ||
91 | return out - buf; | 93 | return out - buf; |
92 | } | 94 | } |
93 | 95 | ||
94 | static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space) | 96 | static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp, |
97 | char *buf, int len, int space) | ||
95 | { | 98 | { |
96 | char *out = buf; | 99 | char *out = buf; |
97 | struct uhci_td *td; | 100 | struct uhci_td *td; |
@@ -130,9 +133,10 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space) | |||
130 | if (urbp->qh->type != USB_ENDPOINT_XFER_ISOC && | 133 | if (urbp->qh->type != USB_ENDPOINT_XFER_ISOC && |
131 | (++i <= 10 || debug > 2)) { | 134 | (++i <= 10 || debug > 2)) { |
132 | out += sprintf(out, "%*s%d: ", space + 2, "", i); | 135 | out += sprintf(out, "%*s%d: ", space + 2, "", i); |
133 | out += uhci_show_td(td, out, len - (out - buf), 0); | 136 | out += uhci_show_td(uhci, td, out, |
137 | len - (out - buf), 0); | ||
134 | } else { | 138 | } else { |
135 | if (td_status(td) & TD_CTRL_ACTIVE) | 139 | if (td_status(uhci, td) & TD_CTRL_ACTIVE) |
136 | ++nactive; | 140 | ++nactive; |
137 | else | 141 | else |
138 | ++ninactive; | 142 | ++ninactive; |
@@ -151,7 +155,7 @@ static int uhci_show_qh(struct uhci_hcd *uhci, | |||
151 | { | 155 | { |
152 | char *out = buf; | 156 | char *out = buf; |
153 | int i, nurbs; | 157 | int i, nurbs; |
154 | __le32 element = qh_element(qh); | 158 | __hc32 element = qh_element(qh); |
155 | char *qtype; | 159 | char *qtype; |
156 | 160 | ||
157 | /* Try to make sure there's enough memory */ | 161 | /* Try to make sure there's enough memory */ |
@@ -168,7 +172,8 @@ static int uhci_show_qh(struct uhci_hcd *uhci, | |||
168 | 172 | ||
169 | out += sprintf(out, "%*s[%p] %s QH link (%08x) element (%08x)\n", | 173 | out += sprintf(out, "%*s[%p] %s QH link (%08x) element (%08x)\n", |
170 | space, "", qh, qtype, | 174 | space, "", qh, qtype, |
171 | le32_to_cpu(qh->link), le32_to_cpu(element)); | 175 | hc32_to_cpu(uhci, qh->link), |
176 | hc32_to_cpu(uhci, element)); | ||
172 | if (qh->type == USB_ENDPOINT_XFER_ISOC) | 177 | if (qh->type == USB_ENDPOINT_XFER_ISOC) |
173 | out += sprintf(out, "%*s period %d phase %d load %d us, " | 178 | out += sprintf(out, "%*s period %d phase %d load %d us, " |
174 | "frame %x desc [%p]\n", | 179 | "frame %x desc [%p]\n", |
@@ -178,22 +183,22 @@ static int uhci_show_qh(struct uhci_hcd *uhci, | |||
178 | out += sprintf(out, "%*s period %d phase %d load %d us\n", | 183 | out += sprintf(out, "%*s period %d phase %d load %d us\n", |
179 | space, "", qh->period, qh->phase, qh->load); | 184 | space, "", qh->period, qh->phase, qh->load); |
180 | 185 | ||
181 | if (element & UHCI_PTR_QH) | 186 | if (element & UHCI_PTR_QH(uhci)) |
182 | out += sprintf(out, "%*s Element points to QH (bug?)\n", space, ""); | 187 | out += sprintf(out, "%*s Element points to QH (bug?)\n", space, ""); |
183 | 188 | ||
184 | if (element & UHCI_PTR_DEPTH) | 189 | if (element & UHCI_PTR_DEPTH(uhci)) |
185 | out += sprintf(out, "%*s Depth traverse\n", space, ""); | 190 | out += sprintf(out, "%*s Depth traverse\n", space, ""); |
186 | 191 | ||
187 | if (element & cpu_to_le32(8)) | 192 | if (element & cpu_to_hc32(uhci, 8)) |
188 | out += sprintf(out, "%*s Bit 3 set (bug?)\n", space, ""); | 193 | out += sprintf(out, "%*s Bit 3 set (bug?)\n", space, ""); |
189 | 194 | ||
190 | if (!(element & ~(UHCI_PTR_QH | UHCI_PTR_DEPTH))) | 195 | if (!(element & ~(UHCI_PTR_QH(uhci) | UHCI_PTR_DEPTH(uhci)))) |
191 | out += sprintf(out, "%*s Element is NULL (bug?)\n", space, ""); | 196 | out += sprintf(out, "%*s Element is NULL (bug?)\n", space, ""); |
192 | 197 | ||
193 | if (list_empty(&qh->queue)) { | 198 | if (list_empty(&qh->queue)) { |
194 | out += sprintf(out, "%*s queue is empty\n", space, ""); | 199 | out += sprintf(out, "%*s queue is empty\n", space, ""); |
195 | if (qh == uhci->skel_async_qh) | 200 | if (qh == uhci->skel_async_qh) |
196 | out += uhci_show_td(uhci->term_td, out, | 201 | out += uhci_show_td(uhci, uhci->term_td, out, |
197 | len - (out - buf), 0); | 202 | len - (out - buf), 0); |
198 | } else { | 203 | } else { |
199 | struct urb_priv *urbp = list_entry(qh->queue.next, | 204 | struct urb_priv *urbp = list_entry(qh->queue.next, |
@@ -201,13 +206,13 @@ static int uhci_show_qh(struct uhci_hcd *uhci, | |||
201 | struct uhci_td *td = list_entry(urbp->td_list.next, | 206 | struct uhci_td *td = list_entry(urbp->td_list.next, |
202 | struct uhci_td, list); | 207 | struct uhci_td, list); |
203 | 208 | ||
204 | if (element != LINK_TO_TD(td)) | 209 | if (element != LINK_TO_TD(uhci, td)) |
205 | out += sprintf(out, "%*s Element != First TD\n", | 210 | out += sprintf(out, "%*s Element != First TD\n", |
206 | space, ""); | 211 | space, ""); |
207 | i = nurbs = 0; | 212 | i = nurbs = 0; |
208 | list_for_each_entry(urbp, &qh->queue, node) { | 213 | list_for_each_entry(urbp, &qh->queue, node) { |
209 | if (++i <= 10) | 214 | if (++i <= 10) |
210 | out += uhci_show_urbp(urbp, out, | 215 | out += uhci_show_urbp(uhci, urbp, out, |
211 | len - (out - buf), space + 2); | 216 | len - (out - buf), space + 2); |
212 | else | 217 | else |
213 | ++nurbs; | 218 | ++nurbs; |
@@ -219,7 +224,8 @@ static int uhci_show_qh(struct uhci_hcd *uhci, | |||
219 | 224 | ||
220 | if (qh->dummy_td) { | 225 | if (qh->dummy_td) { |
221 | out += sprintf(out, "%*s Dummy TD\n", space, ""); | 226 | out += sprintf(out, "%*s Dummy TD\n", space, ""); |
222 | out += uhci_show_td(qh->dummy_td, out, len - (out - buf), 0); | 227 | out += uhci_show_td(uhci, qh->dummy_td, out, |
228 | len - (out - buf), 0); | ||
223 | } | 229 | } |
224 | 230 | ||
225 | return out - buf; | 231 | return out - buf; |
@@ -346,8 +352,8 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) | |||
346 | struct uhci_td *td; | 352 | struct uhci_td *td; |
347 | struct list_head *tmp, *head; | 353 | struct list_head *tmp, *head; |
348 | int nframes, nerrs; | 354 | int nframes, nerrs; |
349 | __le32 link; | 355 | __hc32 link; |
350 | __le32 fsbr_link; | 356 | __hc32 fsbr_link; |
351 | 357 | ||
352 | static const char * const qh_names[] = { | 358 | static const char * const qh_names[] = { |
353 | "unlink", "iso", "int128", "int64", "int32", "int16", | 359 | "unlink", "iso", "int128", "int64", "int32", "int16", |
@@ -375,7 +381,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) | |||
375 | nframes = 10; | 381 | nframes = 10; |
376 | nerrs = 0; | 382 | nerrs = 0; |
377 | for (i = 0; i < UHCI_NUMFRAMES; ++i) { | 383 | for (i = 0; i < UHCI_NUMFRAMES; ++i) { |
378 | __le32 qh_dma; | 384 | __hc32 qh_dma; |
379 | 385 | ||
380 | j = 0; | 386 | j = 0; |
381 | td = uhci->frame_cpu[i]; | 387 | td = uhci->frame_cpu[i]; |
@@ -385,7 +391,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) | |||
385 | 391 | ||
386 | if (nframes > 0) { | 392 | if (nframes > 0) { |
387 | out += sprintf(out, "- Frame %d -> (%08x)\n", | 393 | out += sprintf(out, "- Frame %d -> (%08x)\n", |
388 | i, le32_to_cpu(link)); | 394 | i, hc32_to_cpu(uhci, link)); |
389 | j = 1; | 395 | j = 1; |
390 | } | 396 | } |
391 | 397 | ||
@@ -394,7 +400,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) | |||
394 | do { | 400 | do { |
395 | td = list_entry(tmp, struct uhci_td, fl_list); | 401 | td = list_entry(tmp, struct uhci_td, fl_list); |
396 | tmp = tmp->next; | 402 | tmp = tmp->next; |
397 | if (link != LINK_TO_TD(td)) { | 403 | if (link != LINK_TO_TD(uhci, td)) { |
398 | if (nframes > 0) | 404 | if (nframes > 0) |
399 | out += sprintf(out, " link does " | 405 | out += sprintf(out, " link does " |
400 | "not match list entry!\n"); | 406 | "not match list entry!\n"); |
@@ -402,7 +408,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) | |||
402 | ++nerrs; | 408 | ++nerrs; |
403 | } | 409 | } |
404 | if (nframes > 0) | 410 | if (nframes > 0) |
405 | out += uhci_show_td(td, out, | 411 | out += uhci_show_td(uhci, td, out, |
406 | len - (out - buf), 4); | 412 | len - (out - buf), 4); |
407 | link = td->link; | 413 | link = td->link; |
408 | } while (tmp != head); | 414 | } while (tmp != head); |
@@ -414,11 +420,12 @@ check_link: | |||
414 | if (!j) { | 420 | if (!j) { |
415 | out += sprintf(out, | 421 | out += sprintf(out, |
416 | "- Frame %d -> (%08x)\n", | 422 | "- Frame %d -> (%08x)\n", |
417 | i, le32_to_cpu(link)); | 423 | i, hc32_to_cpu(uhci, link)); |
418 | j = 1; | 424 | j = 1; |
419 | } | 425 | } |
420 | out += sprintf(out, " link does not match " | 426 | out += sprintf(out, " link does not match " |
421 | "QH (%08x)!\n", le32_to_cpu(qh_dma)); | 427 | "QH (%08x)!\n", |
428 | hc32_to_cpu(uhci, qh_dma)); | ||
422 | } else | 429 | } else |
423 | ++nerrs; | 430 | ++nerrs; |
424 | } | 431 | } |
@@ -439,11 +446,11 @@ check_link: | |||
439 | 446 | ||
440 | /* Last QH is the Terminating QH, it's different */ | 447 | /* Last QH is the Terminating QH, it's different */ |
441 | if (i == SKEL_TERM) { | 448 | if (i == SKEL_TERM) { |
442 | if (qh_element(qh) != LINK_TO_TD(uhci->term_td)) | 449 | if (qh_element(qh) != LINK_TO_TD(uhci, uhci->term_td)) |
443 | out += sprintf(out, " skel_term_qh element is not set to term_td!\n"); | 450 | out += sprintf(out, " skel_term_qh element is not set to term_td!\n"); |
444 | link = fsbr_link; | 451 | link = fsbr_link; |
445 | if (!link) | 452 | if (!link) |
446 | link = LINK_TO_QH(uhci->skel_term_qh); | 453 | link = LINK_TO_QH(uhci, uhci->skel_term_qh); |
447 | goto check_qh_link; | 454 | goto check_qh_link; |
448 | } | 455 | } |
449 | 456 | ||
@@ -457,20 +464,20 @@ check_link: | |||
457 | out += uhci_show_qh(uhci, qh, out, | 464 | out += uhci_show_qh(uhci, qh, out, |
458 | len - (out - buf), 4); | 465 | len - (out - buf), 4); |
459 | if (!fsbr_link && qh->skel >= SKEL_FSBR) | 466 | if (!fsbr_link && qh->skel >= SKEL_FSBR) |
460 | fsbr_link = LINK_TO_QH(qh); | 467 | fsbr_link = LINK_TO_QH(uhci, qh); |
461 | } | 468 | } |
462 | if ((cnt -= 10) > 0) | 469 | if ((cnt -= 10) > 0) |
463 | out += sprintf(out, " Skipped %d QHs\n", cnt); | 470 | out += sprintf(out, " Skipped %d QHs\n", cnt); |
464 | 471 | ||
465 | link = UHCI_PTR_TERM; | 472 | link = UHCI_PTR_TERM(uhci); |
466 | if (i <= SKEL_ISO) | 473 | if (i <= SKEL_ISO) |
467 | ; | 474 | ; |
468 | else if (i < SKEL_ASYNC) | 475 | else if (i < SKEL_ASYNC) |
469 | link = LINK_TO_QH(uhci->skel_async_qh); | 476 | link = LINK_TO_QH(uhci, uhci->skel_async_qh); |
470 | else if (!uhci->fsbr_is_on) | 477 | else if (!uhci->fsbr_is_on) |
471 | ; | 478 | ; |
472 | else | 479 | else |
473 | link = LINK_TO_QH(uhci->skel_term_qh); | 480 | link = LINK_TO_QH(uhci, uhci->skel_term_qh); |
474 | check_qh_link: | 481 | check_qh_link: |
475 | if (qh->link != link) | 482 | if (qh->link != link) |
476 | out += sprintf(out, " last QH not linked to next skeleton!\n"); | 483 | out += sprintf(out, " last QH not linked to next skeleton!\n"); |