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>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
bab1ff1bda
commit
51e2f62fe7
@@ -37,7 +37,8 @@ static void lprintk(char *buf)
|
||||
}
|
||||
}
|
||||
|
||||
static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
|
||||
static int uhci_show_td(struct uhci_hcd *uhci, struct uhci_td *td, char *buf,
|
||||
int len, int space)
|
||||
{
|
||||
char *out = buf;
|
||||
char *spid;
|
||||
@@ -47,8 +48,9 @@ static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
|
||||
if (len < 160)
|
||||
return 0;
|
||||
|
||||
status = td_status(td);
|
||||
out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td, le32_to_cpu(td->link));
|
||||
status = td_status(uhci, td);
|
||||
out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td,
|
||||
hc32_to_cpu(uhci, td->link));
|
||||
out += sprintf(out, "e%d %s%s%s%s%s%s%s%s%s%sLength=%x ",
|
||||
((status >> 27) & 3),
|
||||
(status & TD_CTRL_SPD) ? "SPD " : "",
|
||||
@@ -63,7 +65,7 @@ static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
|
||||
(status & TD_CTRL_BITSTUFF) ? "BitStuff " : "",
|
||||
status & 0x7ff);
|
||||
|
||||
token = td_token(td);
|
||||
token = td_token(uhci, td);
|
||||
switch (uhci_packetid(token)) {
|
||||
case USB_PID_SETUP:
|
||||
spid = "SETUP";
|
||||
@@ -86,12 +88,13 @@ static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
|
||||
(token >> 8) & 127,
|
||||
(token & 0xff),
|
||||
spid);
|
||||
out += sprintf(out, "(buf=%08x)\n", le32_to_cpu(td->buffer));
|
||||
out += sprintf(out, "(buf=%08x)\n", hc32_to_cpu(uhci, td->buffer));
|
||||
|
||||
return out - buf;
|
||||
}
|
||||
|
||||
static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
|
||||
static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp,
|
||||
char *buf, int len, int space)
|
||||
{
|
||||
char *out = buf;
|
||||
struct uhci_td *td;
|
||||
@@ -130,9 +133,10 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
|
||||
if (urbp->qh->type != USB_ENDPOINT_XFER_ISOC &&
|
||||
(++i <= 10 || debug > 2)) {
|
||||
out += sprintf(out, "%*s%d: ", space + 2, "", i);
|
||||
out += uhci_show_td(td, out, len - (out - buf), 0);
|
||||
out += uhci_show_td(uhci, td, out,
|
||||
len - (out - buf), 0);
|
||||
} else {
|
||||
if (td_status(td) & TD_CTRL_ACTIVE)
|
||||
if (td_status(uhci, td) & TD_CTRL_ACTIVE)
|
||||
++nactive;
|
||||
else
|
||||
++ninactive;
|
||||
@@ -151,7 +155,7 @@ static int uhci_show_qh(struct uhci_hcd *uhci,
|
||||
{
|
||||
char *out = buf;
|
||||
int i, nurbs;
|
||||
__le32 element = qh_element(qh);
|
||||
__hc32 element = qh_element(qh);
|
||||
char *qtype;
|
||||
|
||||
/* Try to make sure there's enough memory */
|
||||
@@ -168,7 +172,8 @@ static int uhci_show_qh(struct uhci_hcd *uhci,
|
||||
|
||||
out += sprintf(out, "%*s[%p] %s QH link (%08x) element (%08x)\n",
|
||||
space, "", qh, qtype,
|
||||
le32_to_cpu(qh->link), le32_to_cpu(element));
|
||||
hc32_to_cpu(uhci, qh->link),
|
||||
hc32_to_cpu(uhci, element));
|
||||
if (qh->type == USB_ENDPOINT_XFER_ISOC)
|
||||
out += sprintf(out, "%*s period %d phase %d load %d us, "
|
||||
"frame %x desc [%p]\n",
|
||||
@@ -178,22 +183,22 @@ static int uhci_show_qh(struct uhci_hcd *uhci,
|
||||
out += sprintf(out, "%*s period %d phase %d load %d us\n",
|
||||
space, "", qh->period, qh->phase, qh->load);
|
||||
|
||||
if (element & UHCI_PTR_QH)
|
||||
if (element & UHCI_PTR_QH(uhci))
|
||||
out += sprintf(out, "%*s Element points to QH (bug?)\n", space, "");
|
||||
|
||||
if (element & UHCI_PTR_DEPTH)
|
||||
if (element & UHCI_PTR_DEPTH(uhci))
|
||||
out += sprintf(out, "%*s Depth traverse\n", space, "");
|
||||
|
||||
if (element & cpu_to_le32(8))
|
||||
if (element & cpu_to_hc32(uhci, 8))
|
||||
out += sprintf(out, "%*s Bit 3 set (bug?)\n", space, "");
|
||||
|
||||
if (!(element & ~(UHCI_PTR_QH | UHCI_PTR_DEPTH)))
|
||||
if (!(element & ~(UHCI_PTR_QH(uhci) | UHCI_PTR_DEPTH(uhci))))
|
||||
out += sprintf(out, "%*s Element is NULL (bug?)\n", space, "");
|
||||
|
||||
if (list_empty(&qh->queue)) {
|
||||
out += sprintf(out, "%*s queue is empty\n", space, "");
|
||||
if (qh == uhci->skel_async_qh)
|
||||
out += uhci_show_td(uhci->term_td, out,
|
||||
out += uhci_show_td(uhci, uhci->term_td, out,
|
||||
len - (out - buf), 0);
|
||||
} else {
|
||||
struct urb_priv *urbp = list_entry(qh->queue.next,
|
||||
@@ -201,13 +206,13 @@ static int uhci_show_qh(struct uhci_hcd *uhci,
|
||||
struct uhci_td *td = list_entry(urbp->td_list.next,
|
||||
struct uhci_td, list);
|
||||
|
||||
if (element != LINK_TO_TD(td))
|
||||
if (element != LINK_TO_TD(uhci, td))
|
||||
out += sprintf(out, "%*s Element != First TD\n",
|
||||
space, "");
|
||||
i = nurbs = 0;
|
||||
list_for_each_entry(urbp, &qh->queue, node) {
|
||||
if (++i <= 10)
|
||||
out += uhci_show_urbp(urbp, out,
|
||||
out += uhci_show_urbp(uhci, urbp, out,
|
||||
len - (out - buf), space + 2);
|
||||
else
|
||||
++nurbs;
|
||||
@@ -219,7 +224,8 @@ static int uhci_show_qh(struct uhci_hcd *uhci,
|
||||
|
||||
if (qh->dummy_td) {
|
||||
out += sprintf(out, "%*s Dummy TD\n", space, "");
|
||||
out += uhci_show_td(qh->dummy_td, out, len - (out - buf), 0);
|
||||
out += uhci_show_td(uhci, qh->dummy_td, out,
|
||||
len - (out - buf), 0);
|
||||
}
|
||||
|
||||
return out - buf;
|
||||
@@ -346,8 +352,8 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
|
||||
struct uhci_td *td;
|
||||
struct list_head *tmp, *head;
|
||||
int nframes, nerrs;
|
||||
__le32 link;
|
||||
__le32 fsbr_link;
|
||||
__hc32 link;
|
||||
__hc32 fsbr_link;
|
||||
|
||||
static const char * const qh_names[] = {
|
||||
"unlink", "iso", "int128", "int64", "int32", "int16",
|
||||
@@ -375,7 +381,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
|
||||
nframes = 10;
|
||||
nerrs = 0;
|
||||
for (i = 0; i < UHCI_NUMFRAMES; ++i) {
|
||||
__le32 qh_dma;
|
||||
__hc32 qh_dma;
|
||||
|
||||
j = 0;
|
||||
td = uhci->frame_cpu[i];
|
||||
@@ -385,7 +391,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
|
||||
|
||||
if (nframes > 0) {
|
||||
out += sprintf(out, "- Frame %d -> (%08x)\n",
|
||||
i, le32_to_cpu(link));
|
||||
i, hc32_to_cpu(uhci, link));
|
||||
j = 1;
|
||||
}
|
||||
|
||||
@@ -394,7 +400,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
|
||||
do {
|
||||
td = list_entry(tmp, struct uhci_td, fl_list);
|
||||
tmp = tmp->next;
|
||||
if (link != LINK_TO_TD(td)) {
|
||||
if (link != LINK_TO_TD(uhci, td)) {
|
||||
if (nframes > 0)
|
||||
out += sprintf(out, " link does "
|
||||
"not match list entry!\n");
|
||||
@@ -402,7 +408,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
|
||||
++nerrs;
|
||||
}
|
||||
if (nframes > 0)
|
||||
out += uhci_show_td(td, out,
|
||||
out += uhci_show_td(uhci, td, out,
|
||||
len - (out - buf), 4);
|
||||
link = td->link;
|
||||
} while (tmp != head);
|
||||
@@ -414,11 +420,12 @@ check_link:
|
||||
if (!j) {
|
||||
out += sprintf(out,
|
||||
"- Frame %d -> (%08x)\n",
|
||||
i, le32_to_cpu(link));
|
||||
i, hc32_to_cpu(uhci, link));
|
||||
j = 1;
|
||||
}
|
||||
out += sprintf(out, " link does not match "
|
||||
"QH (%08x)!\n", le32_to_cpu(qh_dma));
|
||||
"QH (%08x)!\n",
|
||||
hc32_to_cpu(uhci, qh_dma));
|
||||
} else
|
||||
++nerrs;
|
||||
}
|
||||
@@ -439,11 +446,11 @@ check_link:
|
||||
|
||||
/* Last QH is the Terminating QH, it's different */
|
||||
if (i == SKEL_TERM) {
|
||||
if (qh_element(qh) != LINK_TO_TD(uhci->term_td))
|
||||
if (qh_element(qh) != LINK_TO_TD(uhci, uhci->term_td))
|
||||
out += sprintf(out, " skel_term_qh element is not set to term_td!\n");
|
||||
link = fsbr_link;
|
||||
if (!link)
|
||||
link = LINK_TO_QH(uhci->skel_term_qh);
|
||||
link = LINK_TO_QH(uhci, uhci->skel_term_qh);
|
||||
goto check_qh_link;
|
||||
}
|
||||
|
||||
@@ -457,20 +464,20 @@ check_link:
|
||||
out += uhci_show_qh(uhci, qh, out,
|
||||
len - (out - buf), 4);
|
||||
if (!fsbr_link && qh->skel >= SKEL_FSBR)
|
||||
fsbr_link = LINK_TO_QH(qh);
|
||||
fsbr_link = LINK_TO_QH(uhci, qh);
|
||||
}
|
||||
if ((cnt -= 10) > 0)
|
||||
out += sprintf(out, " Skipped %d QHs\n", cnt);
|
||||
|
||||
link = UHCI_PTR_TERM;
|
||||
link = UHCI_PTR_TERM(uhci);
|
||||
if (i <= SKEL_ISO)
|
||||
;
|
||||
else if (i < SKEL_ASYNC)
|
||||
link = LINK_TO_QH(uhci->skel_async_qh);
|
||||
link = LINK_TO_QH(uhci, uhci->skel_async_qh);
|
||||
else if (!uhci->fsbr_is_on)
|
||||
;
|
||||
else
|
||||
link = LINK_TO_QH(uhci->skel_term_qh);
|
||||
link = LINK_TO_QH(uhci, uhci->skel_term_qh);
|
||||
check_qh_link:
|
||||
if (qh->link != link)
|
||||
out += sprintf(out, " last QH not linked to next skeleton!\n");
|
||||
|
||||
Reference in New Issue
Block a user