USB: Set usb port's DeviceRemovable according acpi information
authorLan Tianyu <tianyu.lan@intel.com>
Mon, 21 Jan 2013 14:18:00 +0000 (22:18 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 21 Jan 2013 21:22:03 +0000 (13:22 -0800)
ACPI provide "_PLD" and "_UPC" aml methods to describe usb port
visibility and connectability. This patch is to add usb_hub_adjust_DeviceRemovable()
to adjust usb hub port's DeviceRemovable according ACPI information and invoke it in
the rh_call_control(). When hub descriptor request is issued at first time,
usb port device isn't created and usb port is not bound with acpi. So first
hub descriptor request is not changed based on ACPI information. After usb
port devices being created, call usb_hub_adjust_DeviceRemovable in the hub_configure()
and then set hub port's DeviceRemovable according ACPI information and this also works
for non-root hub.

Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Lan Tianyu <tianyu.lan@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/core/hcd.c
drivers/usb/core/hub.c
drivers/usb/core/usb.h

index 5f6da8b2d6a1aba53eaa22bc3ca27666c5cae4bd..2459896d040a2b55dc7e261e08afc34051e70d67 100644 (file)
@@ -619,6 +619,10 @@ nongeneric:
                status = hcd->driver->hub_control (hcd,
                        typeReq, wValue, wIndex,
                        tbuf, wLength);
+
+               if (typeReq == GetHubDescriptor)
+                       usb_hub_adjust_deviceremovable(hcd->self.root_hub,
+                               (struct usb_hub_descriptor *)tbuf);
                break;
 error:
                /* "protocol stall" on error */
index cfdd4eecc5a91827eef449c9ff62d3e4006e5d41..29ca6ed3bea89969a267f49b7979bbdcea37a73b 100644 (file)
@@ -1513,6 +1513,8 @@ static int hub_configure(struct usb_hub *hub,
                        dev_err(hub->intfdev,
                                "couldn't create port%d device.\n", i + 1);
 
+       usb_hub_adjust_deviceremovable(hdev, hub->descriptor);
+
        hub_activate(hub, HUB_INIT);
        return 0;
 
@@ -5219,6 +5221,47 @@ usb_get_hub_port_connect_type(struct usb_device *hdev, int port1)
        return hub->ports[port1 - 1]->connect_type;
 }
 
+void usb_hub_adjust_deviceremovable(struct usb_device *hdev,
+               struct usb_hub_descriptor *desc)
+{
+       enum usb_port_connect_type connect_type;
+       int i;
+
+       if (!hub_is_superspeed(hdev)) {
+               for (i = 1; i <= hdev->maxchild; i++) {
+                       connect_type = usb_get_hub_port_connect_type(hdev, i);
+
+                       if (connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) {
+                               u8 mask = 1 << (i%8);
+
+                               if (!(desc->u.hs.DeviceRemovable[i/8] & mask)) {
+                                       dev_dbg(&hdev->dev, "usb port%d's DeviceRemovable is changed to 1 according to platform information.\n",
+                                               i);
+                                       desc->u.hs.DeviceRemovable[i/8] |= mask;
+                               }
+                       }
+               }
+       } else {
+               u16 port_removable = le16_to_cpu(desc->u.ss.DeviceRemovable);
+
+               for (i = 1; i <= hdev->maxchild; i++) {
+                       connect_type = usb_get_hub_port_connect_type(hdev, i);
+
+                       if (connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) {
+                               u16 mask = 1 << i;
+
+                               if (!(port_removable & mask)) {
+                                       dev_dbg(&hdev->dev, "usb port%d's DeviceRemovable is changed to 1 according to platform information.\n",
+                                               i);
+                                       port_removable |= mask;
+                               }
+                       }
+               }
+
+               desc->u.ss.DeviceRemovable = cpu_to_le16(port_removable);
+       }
+}
+
 #ifdef CONFIG_ACPI
 /**
  * usb_get_hub_port_acpi_handle - Get the usb port's acpi handle
index fb7d8fcb4551e09c12f1a8242eb456beb48ab5fa..a7f20bde0e5e2a18d202a346b1e4024af28fd796 100644 (file)
@@ -1,6 +1,7 @@
 #include <linux/pm.h>
 #include <linux/acpi.h>
 
+struct usb_hub_descriptor;
 struct dev_state;
 
 /* Functions local to drivers/usb/core/ */
@@ -182,6 +183,8 @@ extern enum usb_port_connect_type
        usb_get_hub_port_connect_type(struct usb_device *hdev, int port1);
 extern void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1,
        enum usb_port_connect_type type);
+extern void usb_hub_adjust_deviceremovable(struct usb_device *hdev,
+               struct usb_hub_descriptor *desc);
 
 #ifdef CONFIG_ACPI
 extern int usb_acpi_register(void);