Commit c00a2df2 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

[PATCH] USB: More UHCI root hub code improvements

This adds some minor improvements to the UHCI root hub code.  The only
important change is that it handles the overcurrent indicator bits on VIA
controllers properly; they are reported using the opposite sense from
Intel controllers.



	Report the OverCurrent status bits in the /proc debugging file
	and spontaneously change the use of whitespace.

	Remove unused variable in uhci_hub_status_data().

	Report OverCurrent status for VIA controllers properly (the
	meaning of the status bit is inverted with respect to Intel
	controllers).

	Save the port status I/O address in a variable rather than
	recalculating it many times.

	Merge code for handling SetHubFeature and ClearHubFeature since
	we don't implement either one.

	Remove some unnecessary comments.

	Remove redundant min_t calculation.
parent 1345ad81
...@@ -225,20 +225,22 @@ static int uhci_show_sc(int port, unsigned short status, char *buf, int len) ...@@ -225,20 +225,22 @@ static int uhci_show_sc(int port, unsigned short status, char *buf, int len)
char *out = buf; char *out = buf;
/* Try to make sure there's enough memory */ /* Try to make sure there's enough memory */
if (len < 80) if (len < 160)
return 0; return 0;
out += sprintf(out, " stat%d = %04x %s%s%s%s%s%s%s%s\n", out += sprintf(out, " stat%d = %04x %s%s%s%s%s%s%s%s%s%s\n",
port, port,
status, status,
(status & USBPORTSC_SUSP) ? "PortSuspend " : "", (status & USBPORTSC_SUSP) ? " Suspend" : "",
(status & USBPORTSC_PR) ? "PortReset " : "", (status & USBPORTSC_OCC) ? " OverCurrentChange" : "",
(status & USBPORTSC_LSDA) ? "LowSpeed " : "", (status & USBPORTSC_OC) ? " OverCurrent" : "",
(status & USBPORTSC_RD) ? "ResumeDetect " : "", (status & USBPORTSC_PR) ? " Reset" : "",
(status & USBPORTSC_PEC) ? "EnableChange " : "", (status & USBPORTSC_LSDA) ? " LowSpeed" : "",
(status & USBPORTSC_PE) ? "PortEnabled " : "", (status & USBPORTSC_RD) ? " ResumeDetect" : "",
(status & USBPORTSC_CSC) ? "ConnectChange " : "", (status & USBPORTSC_PEC) ? " EnableChange" : "",
(status & USBPORTSC_CCS) ? "PortConnected " : ""); (status & USBPORTSC_PE) ? " Enabled" : "",
(status & USBPORTSC_CSC) ? " ConnectChange" : "",
(status & USBPORTSC_CCS) ? " Connected" : "");
return out - buf; return out - buf;
} }
......
...@@ -36,33 +36,30 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf) ...@@ -36,33 +36,30 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
{ {
struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct uhci_hcd *uhci = hcd_to_uhci(hcd);
unsigned int io_addr = uhci->io_addr; unsigned int io_addr = uhci->io_addr;
int i, len = 1; int i;
*buf = 0; *buf = 0;
for (i = 0; i < uhci->rh_numports; i++) { for (i = 0; i < uhci->rh_numports; i++) {
*buf |= (inw(io_addr + USBPORTSC1 + i * 2) & RWC_BITS) != 0 if (inw(io_addr + USBPORTSC1 + i * 2) & RWC_BITS)
? (1 << (i + 1)) *buf |= (1 << (i + 1));
: 0;
len = (i + 1) / 8 + 1;
} }
return !!*buf; return !!*buf;
} }
#define OK(x) len = (x); break #define OK(x) len = (x); break
#define CLR_RH_PORTSTAT(x) \ #define CLR_RH_PORTSTAT(x) \
status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \ status = inw(port_addr); \
status &= ~(RWC_BITS|WZ_BITS); \ status &= ~(RWC_BITS|WZ_BITS); \
status &= ~(x); \ status &= ~(x); \
status |= RWC_BITS & (x); \ status |= RWC_BITS & (x); \
outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1)) outw(status, port_addr)
#define SET_RH_PORTSTAT(x) \ #define SET_RH_PORTSTAT(x) \
status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \ status = inw(port_addr); \
status |= (x); \ status |= (x); \
status &= ~(RWC_BITS|WZ_BITS); \ status &= ~(RWC_BITS|WZ_BITS); \
outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1)) outw(status, port_addr)
/* size of returned buffer is part of USB spec */ /* size of returned buffer is part of USB spec */
...@@ -71,8 +68,8 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -71,8 +68,8 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
{ {
struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct uhci_hcd *uhci = hcd_to_uhci(hcd);
int status, retval = 0, len = 0; int status, retval = 0, len = 0;
unsigned int io_addr = uhci->io_addr; unsigned int port_addr = uhci->io_addr + USBPORTSC1 + 2 * (wIndex-1);
u16 wPortChange, wPortStatus; __u16 wPortChange, wPortStatus;
switch (typeReq) { switch (typeReq) {
/* Request Destination: /* Request Destination:
...@@ -87,9 +84,19 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -87,9 +84,19 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
*(__u32 *)buf = cpu_to_le32(0); *(__u32 *)buf = cpu_to_le32(0);
OK(4); /* hub power */ OK(4); /* hub power */
case GetPortStatus: case GetPortStatus:
status = inw(io_addr + USBPORTSC1 + 2 * (wIndex - 1)); if (!wIndex || wIndex > uhci->rh_numports)
goto err;
status = inw(port_addr);
/* C_SUSPEND and C_RESET are always false */ /* Intel controllers report the OverCurrent bit active on.
* VIA controllers report it active off, so we'll adjust the
* bit value. (It's not standardized in the UHCI spec.)
*/
if (to_pci_dev(hcd->self.controller)->vendor ==
PCI_VENDOR_ID_VIA)
status ^= USBPORTSC_OC;
/* UHCI doesn't support C_SUSPEND and C_RESET (always false) */
wPortChange = 0; wPortChange = 0;
if (status & USBPORTSC_CSC) if (status & USBPORTSC_CSC)
wPortChange |= 1 << (USB_PORT_FEAT_C_CONNECTION - 16); wPortChange |= 1 << (USB_PORT_FEAT_C_CONNECTION - 16);
...@@ -122,20 +129,12 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -122,20 +129,12 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
*(__u16 *)buf = cpu_to_le16(wPortStatus); *(__u16 *)buf = cpu_to_le16(wPortStatus);
*(__u16 *)(buf + 2) = cpu_to_le16(wPortChange); *(__u16 *)(buf + 2) = cpu_to_le16(wPortChange);
OK(4); OK(4);
case SetHubFeature: case SetHubFeature: /* We don't implement these */
switch (wValue) {
case C_HUB_OVER_CURRENT:
case C_HUB_LOCAL_POWER:
break;
default:
goto err;
}
break;
case ClearHubFeature: case ClearHubFeature:
switch (wValue) { switch (wValue) {
case C_HUB_OVER_CURRENT: case C_HUB_OVER_CURRENT:
case C_HUB_LOCAL_POWER: case C_HUB_LOCAL_POWER:
OK(0); /* hub power over current */ OK(0);
default: default:
goto err; goto err;
} }
...@@ -159,7 +158,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -159,7 +158,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
OK(0); OK(0);
case USB_PORT_FEAT_POWER: case USB_PORT_FEAT_POWER:
/* UHCI has no power switching */ /* UHCI has no power switching */
OK(0); /* port power ** */ OK(0);
default: default:
goto err; goto err;
} }
...@@ -189,7 +188,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -189,7 +188,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
OK(0); OK(0);
case USB_PORT_FEAT_C_OVER_CURRENT: case USB_PORT_FEAT_C_OVER_CURRENT:
CLR_RH_PORTSTAT(USBPORTSC_OCC); CLR_RH_PORTSTAT(USBPORTSC_OCC);
OK(0); /* port power over current */ OK(0);
case USB_PORT_FEAT_C_RESET: case USB_PORT_FEAT_C_RESET:
/* this driver won't report these */ /* this driver won't report these */
OK(0); OK(0);
...@@ -198,8 +197,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -198,8 +197,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
} }
break; break;
case GetHubDescriptor: case GetHubDescriptor:
len = min_t(unsigned int, wLength, len = min_t(unsigned int, sizeof(root_hub_hub_des), wLength);
min_t(unsigned int, sizeof(root_hub_hub_des), wLength));
memcpy(buf, root_hub_hub_des, len); memcpy(buf, root_hub_hub_des, len);
if (len > 2) if (len > 2)
buf[2] = uhci->rh_numports; buf[2] = uhci->rh_numports;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment