ACPI provide "_PLD" and "_UPC" aml methods to describe usb port
visibility and connectability. This patch is to use those information
to change ehci root hub descriptors and set usb hub port's DeviceRemovable
in the hub_configure(). 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 device being created, set hub port's DeviceRemovable according ACPI
information and this also works for non-root hub.

Signed-off-by: Lan Tianyu <tianyu....@intel.com>
---
 drivers/usb/core/hub.c      |   23 +++++++++++++++++++++++
 drivers/usb/core/usb.h      |    4 ----
 drivers/usb/host/ehci-hub.c |    9 +++++++++
 include/linux/usb.h         |    4 ++++
 4 files changed, 36 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 90accde..706db5c 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1546,6 +1546,25 @@ static int hub_configure(struct usb_hub *hub,
                        dev_err(hub->intfdev,
                                "couldn't create port%d device.\n", i + 1);
 
+       if (!hub_is_superspeed(hdev)) {
+               for (i = 1; i <= hdev->maxchild; i++)
+                       if (hub->ports[i - 1]->connect_type
+                                       == USB_PORT_CONNECT_TYPE_HARD_WIRED)
+                               hub->descriptor->u.hs.DeviceRemovable[i/8]
+                                       |= 1 << (i%8);
+       } else  {
+               u16 port_removable =
+                       le16_to_cpu(hub->descriptor->u.ss.DeviceRemovable);
+
+               for (i = 1; i <= hdev->maxchild; i++)
+                       if (hub->ports[i - 1]->connect_type
+                                       == USB_PORT_CONNECT_TYPE_HARD_WIRED)
+                               port_removable |= 1 << i;
+
+               hub->descriptor->u.ss.DeviceRemovable =
+                               cpu_to_le16(port_removable);
+       }
+
        hub_activate(hub, HUB_INIT);
        return 0;
 
@@ -5191,8 +5210,12 @@ usb_get_hub_port_connect_type(struct usb_device *hdev, 
int port1)
 {
        struct usb_hub *hub = hdev_to_hub(hdev);
 
+       if (!hub)
+               return USB_PORT_CONNECT_TYPE_UNKNOWN;
+
        return hub->ports[port1 - 1]->connect_type;
 }
+EXPORT_SYMBOL_GPL(usb_get_hub_port_connect_type);
 
 #ifdef CONFIG_ACPI
 /**
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 1c528c1..1633f6e 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -169,10 +169,6 @@ extern void usb_notify_add_device(struct usb_device *udev);
 extern void usb_notify_remove_device(struct usb_device *udev);
 extern void usb_notify_add_bus(struct usb_bus *ubus);
 extern void usb_notify_remove_bus(struct usb_bus *ubus);
-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);
 
 #ifdef CONFIG_ACPI
 extern int usb_acpi_register(void);
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 4ccb97c..dd084b3 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -662,6 +662,7 @@ ehci_hub_descriptor (
        struct usb_hub_descriptor       *desc
 ) {
        int             ports = HCS_N_PORTS (ehci->hcs_params);
+       int             i;
        u16             temp;
 
        desc->bDescriptorType = 0x29;
@@ -676,6 +677,14 @@ ehci_hub_descriptor (
        memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
        memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
 
+       for (i = 1; i <= ports; i++) {
+               if (usb_get_hub_port_connect_type(
+                               ehci_to_hcd(ehci)->self.root_hub, i)
+                               == USB_PORT_CONNECT_TYPE_HARD_WIRED)
+                       desc->u.hs.DeviceRemovable[i/8] |= 1 << (i%8);
+       }
+
+
        temp = 0x0008;                  /* per-port overcurrent reporting */
        if (HCS_PPC (ehci->hcs_params))
                temp |= 0x0001;         /* per-port power control */
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 689b14b..e996bb6 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -577,6 +577,10 @@ static inline struct usb_device 
*interface_to_usbdev(struct usb_interface *intf)
        return to_usb_device(intf->dev.parent);
 }
 
+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 struct usb_device *usb_get_dev(struct usb_device *dev);
 extern void usb_put_dev(struct usb_device *dev);
 extern struct usb_device *usb_hub_find_child(struct usb_device *hdev,
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to