4 * Copyright 2012 Red Hat <mjg@redhat.com>
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation, version 2.
11 #include <linux/module.h>
12 #include <linux/usb.h>
13 #include <linux/device.h>
14 #include <linux/errno.h>
15 #include <linux/kernel.h>
16 #include <linux/acpi.h>
17 #include <linux/pci.h>
18 #include <linux/usb/hcd.h>
19 #include <acpi/acpi_bus.h>
24 * usb_acpi_power_manageable - check whether usb port has
25 * acpi power resource.
26 * @hdev: USB device belonging to the usb hub
27 * @index: port index based zero
29 * Return true if the port has acpi power resource and false if no.
31 bool usb_acpi_power_manageable(struct usb_device
*hdev
, int index
)
33 acpi_handle port_handle
;
34 int port1
= index
+ 1;
36 port_handle
= usb_get_hub_port_acpi_handle(hdev
,
39 return acpi_bus_power_manageable(port_handle
);
43 EXPORT_SYMBOL_GPL(usb_acpi_power_manageable
);
46 * usb_acpi_set_power_state - control usb port's power via acpi power
48 * @hdev: USB device belonging to the usb hub
49 * @index: port index based zero
50 * @enable: power state expected to be set
52 * Notice to use usb_acpi_power_manageable() to check whether the usb port
53 * has acpi power resource before invoking this function.
55 * Returns 0 on success, else negative errno.
57 int usb_acpi_set_power_state(struct usb_device
*hdev
, int index
, bool enable
)
59 acpi_handle port_handle
;
61 int port1
= index
+ 1;
64 port_handle
= (acpi_handle
)usb_get_hub_port_acpi_handle(hdev
,
70 state
= ACPI_STATE_D0
;
72 state
= ACPI_STATE_D3_COLD
;
74 error
= acpi_bus_set_power(port_handle
, state
);
76 dev_dbg(&hdev
->dev
, "The power of hub port %d was set to %d\n",
79 dev_dbg(&hdev
->dev
, "The power of hub port failed to be set\n");
83 EXPORT_SYMBOL_GPL(usb_acpi_set_power_state
);
85 static int usb_acpi_check_port_connect_type(struct usb_device
*hdev
,
86 acpi_handle handle
, int port1
)
89 struct acpi_buffer buffer
= { ACPI_ALLOCATE_BUFFER
, NULL
};
90 union acpi_object
*upc
;
91 struct acpi_pld_info
*pld
;
95 * Accoding to ACPI Spec 9.13. PLD indicates whether usb port is
96 * user visible and _UPC indicates whether it is connectable. If
97 * the port was visible and connectable, it could be freely connected
98 * and disconnected with USB devices. If no visible and connectable,
99 * a usb device is directly hard-wired to the port. If no visible and
100 * no connectable, the port would be not used.
102 status
= acpi_get_physical_device_location(handle
, &pld
);
103 if (ACPI_FAILURE(status
))
106 status
= acpi_evaluate_object(handle
, "_UPC", NULL
, &buffer
);
107 upc
= buffer
.pointer
;
108 if (!upc
|| (upc
->type
!= ACPI_TYPE_PACKAGE
)
109 || upc
->package
.count
!= 4) {
114 if (upc
->package
.elements
[0].integer
.value
)
115 if (pld
->user_visible
)
116 usb_set_hub_port_connect_type(hdev
, port1
,
117 USB_PORT_CONNECT_TYPE_HOT_PLUG
);
119 usb_set_hub_port_connect_type(hdev
, port1
,
120 USB_PORT_CONNECT_TYPE_HARD_WIRED
);
121 else if (!pld
->user_visible
)
122 usb_set_hub_port_connect_type(hdev
, port1
, USB_PORT_NOT_USED
);
130 static int usb_acpi_find_device(struct device
*dev
, acpi_handle
*handle
)
132 struct usb_device
*udev
;
133 acpi_handle
*parent_handle
;
137 * In the ACPI DSDT table, only usb root hub and usb ports are
138 * acpi device nodes. The hierarchy like following.
146 * So all binding process is divided into two parts. binding
147 * root hub and usb ports.
149 if (is_usb_device(dev
)) {
150 udev
= to_usb_device(dev
);
152 enum usb_port_connect_type type
;
155 * According usb port's connect type to set usb device's
158 type
= usb_get_hub_port_connect_type(udev
->parent
,
161 case USB_PORT_CONNECT_TYPE_HOT_PLUG
:
162 udev
->removable
= USB_DEVICE_REMOVABLE
;
164 case USB_PORT_CONNECT_TYPE_HARD_WIRED
:
165 udev
->removable
= USB_DEVICE_FIXED
;
168 udev
->removable
= USB_DEVICE_REMOVABLE_UNKNOWN
;
175 /* root hub's parent is the usb hcd. */
176 parent_handle
= DEVICE_ACPI_HANDLE(dev
->parent
);
177 *handle
= acpi_get_child(parent_handle
, udev
->portnum
);
181 } else if (is_usb_port(dev
)) {
182 sscanf(dev_name(dev
), "port%d", &port_num
);
183 /* Get the struct usb_device point of port's hub */
184 udev
= to_usb_device(dev
->parent
->parent
);
187 * The root hub ports' parent is the root hub. The non-root-hub
188 * ports' parent is the parent hub port which the hub is
192 struct usb_hcd
*hcd
= bus_to_hcd(udev
->bus
);
195 raw_port_num
= usb_hcd_find_raw_port_number(hcd
,
197 *handle
= acpi_get_child(DEVICE_ACPI_HANDLE(&udev
->dev
),
203 usb_get_hub_port_acpi_handle(udev
->parent
,
208 *handle
= acpi_get_child(parent_handle
, port_num
);
212 usb_acpi_check_port_connect_type(udev
, *handle
, port_num
);
219 static bool usb_acpi_bus_match(struct device
*dev
)
221 return is_usb_device(dev
) || is_usb_port(dev
);
224 static struct acpi_bus_type usb_acpi_bus
= {
226 .match
= usb_acpi_bus_match
,
227 .find_device
= usb_acpi_find_device
,
230 int usb_acpi_register(void)
232 return register_acpi_bus_type(&usb_acpi_bus
);
235 void usb_acpi_unregister(void)
237 unregister_acpi_bus_type(&usb_acpi_bus
);