Skip to content

Commit

Permalink
usb: Set device removable state based on ACPI USB data
Browse files Browse the repository at this point in the history
ACPI offers two methods that allow us to infer whether or not a USB port
is removable. The _PLD method gives us information on whether the port is
"user visible" or not. If that's not present then we can fall back to the
_UPC method which tells us whether or not a port is connectable.

Signed-off-by: Matthew Garrett <mjg@redhat.com>
Signed-off-by: Lan Tianyu <tianyu.lan@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Matthew Garrett authored and Greg Kroah-Hartman committed May 12, 2012
1 parent da0af6e commit 54d3f8c
Showing 1 changed file with 57 additions and 0 deletions.
57 changes: 57 additions & 0 deletions drivers/usb/core/usb-acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}

Expand Down

0 comments on commit 54d3f8c

Please sign in to comment.