From stern@rowland.harvard.edu Thu Apr 27 12:54:26 2006 Date: Thu, 27 Apr 2006 15:54:22 -0400 (EDT) From: Alan Stern To: Greg KH cc: David Brownell Subject: USB: usbcore: always turn on hub port power Message-ID: Some hubs claim not to support port-power switching, and right now the hub driver believes them and does not enable power to their ports. However it turns out that even though they don't actually switch power, they do ignore all events on a port until told to turn on the power! This problem has been reported by several users. This revised patch (as672b) makes the hub driver always try to turn on port power to all hubs, regardless of what the hub descriptor says. It also adds a comment explaining the need for this. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) --- gregkh-2.6.orig/drivers/usb/core/hub.c +++ gregkh-2.6/drivers/usb/core/hub.c @@ -432,15 +432,22 @@ static void hub_power_on(struct usb_hub { int port1; unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2; - u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); + u16 wHubCharacteristics = + le16_to_cpu(hub->descriptor->wHubCharacteristics); - /* if hub supports power switching, enable power on each port */ - if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2) { + /* Enable power on each port. Some hubs have reserved values + * of LPSM (> 2) in their descriptors, even though they are + * USB 2.0 hubs. Some hubs do not implement port-power switching + * but only emulate it. In all cases, the ports won't work + * unless we send these messages to the hub. + */ + if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2) dev_dbg(hub->intfdev, "enabling power on all ports\n"); - for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++) - set_port_feature(hub->hdev, port1, - USB_PORT_FEAT_POWER); - } + else + dev_dbg(hub->intfdev, "trying to enable port power on " + "non-switchable hub\n"); + for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++) + set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER); /* Wait at least 100 msec for power to become stable */ msleep(max(pgood_delay, (unsigned) 100));