瀏覽代碼

[PATCH] USB: usbcore: always turn on hub port power

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 <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Alan Stern 19 年之前
父節點
當前提交
4489a5712b
共有 1 個文件被更改,包括 15 次插入8 次删除
  1. 15 8
      drivers/usb/core/hub.c

+ 15 - 8
drivers/usb/core/hub.c

@@ -432,15 +432,22 @@ static void hub_power_on(struct usb_hub *hub)
 {
 	int port1;
 	unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2;
-	u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
-
-	/* if hub supports power switching, enable power on each port */
-	if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2) {
+	u16 wHubCharacteristics =
+			le16_to_cpu(hub->descriptor->wHubCharacteristics);
+
+	/* 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));