Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 325862
b: refs/heads/master
c: 05f9168
h: refs/heads/master
v: v3
  • Loading branch information
Lan Tianyu authored and Greg Kroah-Hartman committed Sep 10, 2012
1 parent 1d1343e commit d923265
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 36 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: d557542421da643358201664903e67fd01dfca1a
refs/heads/master: 05f916894a692f0cc0973aef21521133623b21c0
31 changes: 31 additions & 0 deletions trunk/drivers/usb/core/hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ struct usb_port {
struct usb_device *child;
struct device dev;
struct dev_state *port_owner;
enum usb_port_connect_type connect_type;
};

struct usb_hub {
Expand Down Expand Up @@ -5078,6 +5079,36 @@ struct usb_device *usb_hub_find_child(struct usb_device *hdev,
}
EXPORT_SYMBOL_GPL(usb_hub_find_child);

/**
* usb_set_hub_port_connect_type - set hub port connect type.
* @hdev: USB device belonging to the usb hub
* @port1: port num of the port
* @type: connect type of the port
*/
void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1,
enum usb_port_connect_type type)
{
struct usb_hub *hub = hdev_to_hub(hdev);

hub->ports[port1 - 1]->connect_type = type;
}

/**
* usb_get_hub_port_connect_type - Get the port's connect type
* @hdev: USB device belonging to the usb hub
* @port1: port num of the port
*
* Return connect type of the port and if input params are
* invalid, return USB_PORT_CONNECT_TYPE_UNKNOWN.
*/
enum usb_port_connect_type
usb_get_hub_port_connect_type(struct usb_device *hdev, int port1)
{
struct usb_hub *hub = hdev_to_hub(hdev);

return hub->ports[port1 - 1]->connect_type;
}

#ifdef CONFIG_ACPI
/**
* usb_get_hub_port_acpi_handle - Get the usb port's acpi handle
Expand Down
80 changes: 45 additions & 35 deletions trunk/drivers/usb/core/usb-acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,54 +19,50 @@

#include "usb.h"

static int usb_acpi_check_upc(struct usb_device *udev, acpi_handle handle)
static int usb_acpi_check_port_connect_type(struct usb_device *hdev,
acpi_handle handle, int port1)
{
acpi_status status;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *upc;
struct acpi_pld pld;
int ret = 0;

status = acpi_evaluate_object(handle, "_UPC", NULL, &buffer);

/*
* Accoding to ACPI Spec 9.13. PLD indicates whether usb port is
* user visible and _UPC indicates whether it is connectable. If
* the port was visible and connectable, it could be freely connected
* and disconnected with USB devices. If no visible and connectable,
* a usb device is directly hard-wired to the port. If no visible and
* no connectable, the port would be not used.
*/
status = acpi_get_physical_device_location(handle, &pld);
if (ACPI_FAILURE(status))
return -ENODEV;

status = acpi_evaluate_object(handle, "_UPC", NULL, &buffer);
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;
if (pld.user_visible)
usb_set_hub_port_connect_type(hdev, port1,
USB_PORT_CONNECT_TYPE_HOT_PLUG);
else
usb_set_hub_port_connect_type(hdev, port1,
USB_PORT_CONNECT_TYPE_HARD_WIRED);
else if (!pld.user_visible)
usb_set_hub_port_connect_type(hdev, port1, USB_PORT_NOT_USED);

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 @@ -88,8 +84,30 @@ static int usb_acpi_find_device(struct device *dev, acpi_handle *handle)
*/
if (is_usb_device(dev)) {
udev = to_usb_device(dev);
if (udev->parent)
if (udev->parent) {
enum usb_port_connect_type type;

/*
* According usb port's connect type to set usb device's
* removability.
*/
type = usb_get_hub_port_connect_type(udev->parent,
udev->portnum);
switch (type) {
case USB_PORT_CONNECT_TYPE_HOT_PLUG:
udev->removable = USB_DEVICE_REMOVABLE;
break;
case USB_PORT_CONNECT_TYPE_HARD_WIRED:
udev->removable = USB_DEVICE_FIXED;
break;
default:
udev->removable = USB_DEVICE_REMOVABLE_UNKNOWN;
break;
}

return -ENODEV;
}

/* root hub's parent is the usb hcd. */
parent_handle = DEVICE_ACPI_HANDLE(dev->parent);
*handle = acpi_get_child(parent_handle, udev->portnum);
Expand Down Expand Up @@ -122,18 +140,10 @@ static int usb_acpi_find_device(struct device *dev, acpi_handle *handle)
if (!*handle)
return -ENODEV;
}
usb_acpi_check_port_connect_type(udev, *handle, port_num);
} else
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
4 changes: 4 additions & 0 deletions trunk/drivers/usb/core/usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,10 @@ 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);
Expand Down
7 changes: 7 additions & 0 deletions trunk/include/linux/usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,13 @@ enum usb_device_removable {
USB_DEVICE_FIXED,
};

enum usb_port_connect_type {
USB_PORT_CONNECT_TYPE_UNKNOWN = 0,
USB_PORT_CONNECT_TYPE_HOT_PLUG,
USB_PORT_CONNECT_TYPE_HARD_WIRED,
USB_PORT_NOT_USED,
};

/*
* USB 3.0 Link Power Management (LPM) parameters.
*
Expand Down

0 comments on commit d923265

Please sign in to comment.