Greg:
This patch is from David Brownell. It should be applied.
Alan Stern
UHCI root hub updates ... minor bugfixes and cleanups, improving
conformance with the USB hub specification.
- UHCI doesn't support any kind of power switching; so modify the
hub descriptor to stop claiming it does! Likewise fail attempts
to disable power on any port.
- Intel defined both overcurrent status overcurrent-change bits, but
the current code only knows about one. Modify hub descriptor to
report per-port overcurrent protection; and use both bits.
- Modify the port status set/clear macros to know about the bits
that must always be written as zero, and the write-to-clear bits.
Update callers which wrote "set" instead of "clear".
- Rewrote code returning port status; magic numbers are gone.
- Driver can't really support 8 root hub ports; don't try.
Also moves the #define DEBUG earlier so that it can kick in any of
the various debug macros ... like pr_debug() and dev_dbg().
diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
--- a/drivers/usb/host/uhci-hcd.c Wed Feb 18 13:56:23 2004
+++ b/drivers/usb/host/uhci-hcd.c Wed Feb 18 13:56:23 2004
@@ -27,6 +27,11 @@
*/
#include <linux/config.h>
+#ifdef CONFIG_USB_DEBUG
+#define DEBUG
+#else
+#undef DEBUG
+#endif
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
@@ -43,11 +48,6 @@
#include <linux/proc_fs.h>
#include <linux/dmapool.h>
#include <linux/dma-mapping.h>
-#ifdef CONFIG_USB_DEBUG
-#define DEBUG
-#else
-#undef DEBUG
-#endif
#include <linux/usb.h>
#include <asm/bitops.h>
@@ -2276,7 +2276,7 @@
/* This is experimental so anything less than 2 or greater than 8 is */
/* something weird and we'll ignore it */
- if (port < 2 || port > 8) {
+ if (port < 2 || port > UHCI_RH_MAXCHILD) {
info("port count misdetected? forcing to 2 ports");
port = 2;
}
diff -Nru a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
--- a/drivers/usb/host/uhci-hcd.h Wed Feb 18 13:56:23 2004
+++ b/drivers/usb/host/uhci-hcd.h Wed Feb 18 13:56:23 2004
@@ -49,12 +49,19 @@
#define USBPORTSC_CSC 0x0002 /* Connect Status Change */
#define USBPORTSC_PE 0x0004 /* Port Enable */
#define USBPORTSC_PEC 0x0008 /* Port Enable Change */
-#define USBPORTSC_LS 0x0030 /* Line Status */
+#define USBPORTSC_DPLUS 0x0010 /* D+ high (line status) */
+#define USBPORTSC_DMINUS 0x0020 /* D- high (line status) */
#define USBPORTSC_RD 0x0040 /* Resume Detect */
+#define USBPORTSC_RES1 0x0080 /* reserved, always 1 */
#define USBPORTSC_LSDA 0x0100 /* Low Speed Device Attached */
#define USBPORTSC_PR 0x0200 /* Port Reset */
+/* OC and OCC from Intel 430TX and later (not UHCI 1.1d spec) */
#define USBPORTSC_OC 0x0400 /* Over Current condition */
+#define USBPORTSC_OCC 0x0800 /* Over Current Change R/WC */
#define USBPORTSC_SUSP 0x1000 /* Suspend */
+#define USBPORTSC_RES2 0x2000 /* reserved, write zeroes */
+#define USBPORTSC_RES3 0x4000 /* reserved, write zeroes */
+#define USBPORTSC_RES4 0x8000 /* reserved, write zeroes */
/* Legacy support register */
#define USBLEGSUP 0xc0
diff -Nru a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c
--- a/drivers/usb/host/uhci-hub.c Wed Feb 18 13:56:23 2004
+++ b/drivers/usb/host/uhci-hub.c Wed Feb 18 13:56:23 2004
@@ -16,14 +16,22 @@
0x09, /* __u8 bLength; */
0x29, /* __u8 bDescriptorType; Hub-descriptor */
0x02, /* __u8 bNbrPorts; */
- 0x00, /* __u16 wHubCharacteristics; */
- 0x00,
+ 0x0a, /* __u16 wHubCharacteristics; */
+ 0x00, /* (per-port OC, no power switching) */
0x01, /* __u8 bPwrOn2pwrGood; 2ms */
0x00, /* __u8 bHubContrCurrent; 0 mA */
0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */
0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */
};
+#define UHCI_RH_MAXCHILD 7
+
+/* must write as zeroes */
+#define WZ_BITS (USBPORTSC_RES2 | USBPORTSC_RES3 | USBPORTSC_RES4)
+
+/* status change bits: nonzero writes will clear */
+#define RWC_BITS (USBPORTSC_OCC | USBPORTSC_PEC | USBPORTSC_CSC)
+
static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
@@ -32,7 +40,9 @@
*buf = 0;
for (i = 0; i < uhci->rh_numports; i++) {
- *buf |= ((inw(io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i +
1)) : 0);
+ *buf |= (inw(io_addr + USBPORTSC1 + i * 2) & RWC_BITS) != 0
+ ? (1 << (i + 1))
+ : 0;
len = (i + 1) / 8 + 1;
}
@@ -43,12 +53,15 @@
#define CLR_RH_PORTSTAT(x) \
status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \
- status = (status & 0xfff5) & ~(x); \
+ status &= ~(RWC_BITS|WZ_BITS); \
+ status &= ~(x); \
+ status |= RWC_BITS & (x); \
outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))
#define SET_RH_PORTSTAT(x) \
status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \
- status = (status & 0xfff5) | (x); \
+ status |= (x); \
+ status &= ~(RWC_BITS|WZ_BITS); \
outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))
@@ -57,13 +70,9 @@
u16 wIndex, char *buf, u16 wLength)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
- int i, status, retval = 0, len = 0;
+ int status, retval = 0, len = 0;
unsigned int io_addr = uhci->io_addr;
- __u16 cstatus;
- char c_p_r[8];
-
- for (i = 0; i < 8; i++)
- c_p_r[i] = 0;
+ u16 wPortChange, wPortStatus;
switch (typeReq) {
/* Request Destination:
@@ -79,18 +88,39 @@
OK(4); /* hub power */
case GetPortStatus:
status = inw(io_addr + USBPORTSC1 + 2 * (wIndex - 1));
- cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) |
- ((status & USBPORTSC_PEC) >> (3 - 1)) |
- (c_p_r[wIndex - 1] << (0 + 4));
- status = (status & USBPORTSC_CCS) |
- ((status & USBPORTSC_PE) >> (2 - 1)) |
- ((status & USBPORTSC_SUSP) >> (12 - 2)) |
- ((status & USBPORTSC_PR) >> (9 - 4)) |
- (1 << 8) | /* power on */
- ((status & USBPORTSC_LSDA) << (-8 + 9));
- *(__u16 *)buf = cpu_to_le16(status);
- *(__u16 *)(buf + 2) = cpu_to_le16(cstatus);
+ /* C_SUSPEND and C_RESET are always false */
+ wPortChange = 0;
+ if (status & USBPORTSC_CSC)
+ wPortChange |= 1 << (USB_PORT_FEAT_C_CONNECTION - 16);
+ if (status & USBPORTSC_PEC)
+ wPortChange |= 1 << (USB_PORT_FEAT_C_ENABLE - 16);
+ if (status & USBPORTSC_OCC)
+ wPortChange |= 1 << (USB_PORT_FEAT_C_OVER_CURRENT - 16);
+
+ /* UHCI has no power switching (always on) */
+ wPortStatus = 1 << USB_PORT_FEAT_POWER;
+ if (status & USBPORTSC_CCS)
+ wPortStatus |= 1 << USB_PORT_FEAT_CONNECTION;
+ if (status & USBPORTSC_PE) {
+ wPortStatus |= 1 << USB_PORT_FEAT_ENABLE;
+ if (status & (USBPORTSC_SUSP | USBPORTSC_RD))
+ wPortStatus |= 1 << USB_PORT_FEAT_SUSPEND;
+ }
+ if (status & USBPORTSC_OC)
+ wPortStatus |= 1 << USB_PORT_FEAT_OVER_CURRENT;
+ if (status & USBPORTSC_PR)
+ wPortStatus |= 1 << USB_PORT_FEAT_RESET;
+ if (status & USBPORTSC_LSDA)
+ wPortStatus |= 1 << USB_PORT_FEAT_LOWSPEED;
+
+ if (wPortChange)
+ dev_dbg (uhci->hcd.self.controller,
+ "port %d portsc %04x\n",
+ wIndex, status);
+
+ *(__u16 *)buf = cpu_to_le16(wPortStatus);
+ *(__u16 *)(buf + 2) = cpu_to_le16(wPortChange);
OK(4);
case SetHubFeature:
switch (wValue) {
@@ -104,6 +134,7 @@
case ClearHubFeature:
switch (wValue) {
case C_HUB_OVER_CURRENT:
+ case C_HUB_LOCAL_POWER:
OK(0); /* hub power over current */
default:
goto err;
@@ -120,18 +151,15 @@
case USB_PORT_FEAT_RESET:
SET_RH_PORTSTAT(USBPORTSC_PR);
mdelay(50); /* USB v1.1 7.1.7.3 */
- c_p_r[wIndex - 1] = 1;
CLR_RH_PORTSTAT(USBPORTSC_PR);
udelay(10);
SET_RH_PORTSTAT(USBPORTSC_PE);
mdelay(10);
- SET_RH_PORTSTAT(0xa);
+ CLR_RH_PORTSTAT(USBPORTSC_PEC|USBPORTSC_CSC);
OK(0);
case USB_PORT_FEAT_POWER:
+ /* UHCI has no power switching */
OK(0); /* port power ** */
- case USB_PORT_FEAT_ENABLE:
- SET_RH_PORTSTAT(USBPORTSC_PE);
- OK(0);
default:
goto err;
}
@@ -145,23 +173,25 @@
CLR_RH_PORTSTAT(USBPORTSC_PE);
OK(0);
case USB_PORT_FEAT_C_ENABLE:
- SET_RH_PORTSTAT(USBPORTSC_PEC);
+ CLR_RH_PORTSTAT(USBPORTSC_PEC);
OK(0);
case USB_PORT_FEAT_SUSPEND:
CLR_RH_PORTSTAT(USBPORTSC_SUSP);
OK(0);
case USB_PORT_FEAT_C_SUSPEND:
- /*** WR_RH_PORTSTAT(RH_PS_PSSC); */
+ /* this driver won't report these */
OK(0);
case USB_PORT_FEAT_POWER:
- OK(0); /* port power */
+ /* UHCI has no power switching */
+ goto err;
case USB_PORT_FEAT_C_CONNECTION:
- SET_RH_PORTSTAT(USBPORTSC_CSC);
+ CLR_RH_PORTSTAT(USBPORTSC_CSC);
OK(0);
case USB_PORT_FEAT_C_OVER_CURRENT:
+ CLR_RH_PORTSTAT(USBPORTSC_OCC);
OK(0); /* port power over current */
case USB_PORT_FEAT_C_RESET:
- c_p_r[wIndex - 1] = 0;
+ /* this driver won't report these */
OK(0);
default:
goto err;
-------------------------------------------------------
SF.Net is sponsored by: Speed Start Your Linux Apps Now.
Build and deploy apps & Web services for Linux with
a free DVD software kit from IBM. Click Now!
http://ads.osdn.com/?ad_id=1356&alloc_id=3438&op=click
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel