From dafcc0eab4091d9509c063fcc3719e7c09d49dee Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Fri, 11 May 2012 16:08:28 +0800 Subject: [PATCH] --- yaml --- r: 303926 b: refs/heads/master c: 54d3f8c63d6940966217b807972778fb17c3fa82 h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/drivers/usb/core/usb-acpi.c | 57 +++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/[refs] b/[refs] index 873bb97dc84d..c8dacbec3bca 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: da0af6e78ef311d97754aa03e10eade82cc99e16 +refs/heads/master: 54d3f8c63d6940966217b807972778fb17c3fa82 diff --git a/trunk/drivers/usb/core/usb-acpi.c b/trunk/drivers/usb/core/usb-acpi.c index cab5cb7c256c..8947b203d5a4 100644 --- a/trunk/drivers/usb/core/usb-acpi.c +++ b/trunk/drivers/usb/core/usb-acpi.c @@ -19,6 +19,54 @@ #include "usb.h" +static int usb_acpi_check_upc(struct usb_device *udev, acpi_handle handle) +{ + acpi_status status; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *upc; + int ret = 0; + + status = acpi_evaluate_object(handle, "_UPC", NULL, &buffer); + + if (ACPI_FAILURE(status)) + return -ENODEV; + + upc = buffer.pointer; + + if (!upc || (upc->type != ACPI_TYPE_PACKAGE) + || upc->package.count != 4) { + ret = -EINVAL; + goto out; + } + + if (upc->package.elements[0].integer.value) + udev->removable = USB_DEVICE_REMOVABLE; + else + udev->removable = USB_DEVICE_FIXED; + +out: + kfree(upc); + return ret; +} + +static int usb_acpi_check_pld(struct usb_device *udev, acpi_handle handle) +{ + acpi_status status; + struct acpi_pld pld; + + status = acpi_get_physical_device_location(handle, &pld); + + if (ACPI_FAILURE(status)) + return -ENODEV; + + if (pld.user_visible) + udev->removable = USB_DEVICE_REMOVABLE; + else + udev->removable = USB_DEVICE_FIXED; + + return 0; +} + static int usb_acpi_find_device(struct device *dev, acpi_handle *handle) { struct usb_device *udev; @@ -40,6 +88,15 @@ static int usb_acpi_find_device(struct device *dev, acpi_handle *handle) if (!*handle) return -ENODEV; + /* + * PLD will tell us whether a port is removable to the user or + * not. If we don't get an answer from PLD (it's not present + * or it's malformed) then try to infer it from UPC. If a + * device isn't connectable then it's probably not removable. + */ + if (usb_acpi_check_pld(udev, *handle) != 0) + usb_acpi_check_upc(udev, *handle); + return 0; }