Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : /*
3 : : * USB-ACPI glue code
4 : : *
5 : : * Copyright 2012 Red Hat <mjg@redhat.com>
6 : : */
7 : : #include <linux/module.h>
8 : : #include <linux/usb.h>
9 : : #include <linux/device.h>
10 : : #include <linux/errno.h>
11 : : #include <linux/kernel.h>
12 : : #include <linux/acpi.h>
13 : : #include <linux/pci.h>
14 : : #include <linux/usb/hcd.h>
15 : :
16 : : #include "hub.h"
17 : :
18 : : /**
19 : : * usb_acpi_power_manageable - check whether usb port has
20 : : * acpi power resource.
21 : : * @hdev: USB device belonging to the usb hub
22 : : * @index: port index based zero
23 : : *
24 : : * Return true if the port has acpi power resource and false if no.
25 : : */
26 : 0 : bool usb_acpi_power_manageable(struct usb_device *hdev, int index)
27 : : {
28 : 0 : acpi_handle port_handle;
29 : 0 : int port1 = index + 1;
30 : :
31 : 0 : port_handle = usb_get_hub_port_acpi_handle(hdev,
32 : : port1);
33 [ # # ]: 0 : if (port_handle)
34 : 0 : return acpi_bus_power_manageable(port_handle);
35 : : else
36 : : return false;
37 : : }
38 : : EXPORT_SYMBOL_GPL(usb_acpi_power_manageable);
39 : :
40 : : /**
41 : : * usb_acpi_set_power_state - control usb port's power via acpi power
42 : : * resource
43 : : * @hdev: USB device belonging to the usb hub
44 : : * @index: port index based zero
45 : : * @enable: power state expected to be set
46 : : *
47 : : * Notice to use usb_acpi_power_manageable() to check whether the usb port
48 : : * has acpi power resource before invoking this function.
49 : : *
50 : : * Returns 0 on success, else negative errno.
51 : : */
52 : 0 : int usb_acpi_set_power_state(struct usb_device *hdev, int index, bool enable)
53 : : {
54 : 0 : struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
55 : 0 : struct usb_port *port_dev;
56 : 0 : acpi_handle port_handle;
57 : 0 : unsigned char state;
58 : 0 : int port1 = index + 1;
59 : 0 : int error = -EINVAL;
60 : :
61 [ # # ]: 0 : if (!hub)
62 : : return -ENODEV;
63 : 0 : port_dev = hub->ports[port1 - 1];
64 : :
65 : 0 : port_handle = (acpi_handle) usb_get_hub_port_acpi_handle(hdev, port1);
66 [ # # ]: 0 : if (!port_handle)
67 : : return error;
68 : :
69 [ # # ]: 0 : if (enable)
70 : : state = ACPI_STATE_D0;
71 : : else
72 : 0 : state = ACPI_STATE_D3_COLD;
73 : :
74 : 0 : error = acpi_bus_set_power(port_handle, state);
75 : 0 : if (!error)
76 : : dev_dbg(&port_dev->dev, "acpi: power was set to %d\n", enable);
77 : : else
78 : : dev_dbg(&port_dev->dev, "acpi: power failed to be set\n");
79 : :
80 : 0 : return error;
81 : : }
82 : : EXPORT_SYMBOL_GPL(usb_acpi_set_power_state);
83 : :
84 : : static enum usb_port_connect_type usb_acpi_get_connect_type(acpi_handle handle,
85 : : struct acpi_pld_info *pld)
86 : : {
87 : : enum usb_port_connect_type connect_type = USB_PORT_CONNECT_TYPE_UNKNOWN;
88 : : struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
89 : : union acpi_object *upc;
90 : : acpi_status status;
91 : :
92 : : /*
93 : : * According to 9.14 in ACPI Spec 6.2. _PLD indicates whether usb port
94 : : * is user visible and _UPC indicates whether it is connectable. If
95 : : * the port was visible and connectable, it could be freely connected
96 : : * and disconnected with USB devices. If no visible and connectable,
97 : : * a usb device is directly hard-wired to the port. If no visible and
98 : : * no connectable, the port would be not used.
99 : : */
100 : : status = acpi_evaluate_object(handle, "_UPC", NULL, &buffer);
101 : : upc = buffer.pointer;
102 : : if (!upc || (upc->type != ACPI_TYPE_PACKAGE)
103 : : || upc->package.count != 4) {
104 : : goto out;
105 : : }
106 : :
107 : : if (upc->package.elements[0].integer.value)
108 : : if (pld->user_visible)
109 : : connect_type = USB_PORT_CONNECT_TYPE_HOT_PLUG;
110 : : else
111 : : connect_type = USB_PORT_CONNECT_TYPE_HARD_WIRED;
112 : : else if (!pld->user_visible)
113 : : connect_type = USB_PORT_NOT_USED;
114 : : out:
115 : : kfree(upc);
116 : : return connect_type;
117 : : }
118 : :
119 : :
120 : : /*
121 : : * Private to usb-acpi, all the core needs to know is that
122 : : * port_dev->location is non-zero when it has been set by the firmware.
123 : : */
124 : : #define USB_ACPI_LOCATION_VALID (1 << 31)
125 : :
126 : 0 : static struct acpi_device *usb_acpi_find_port(struct acpi_device *parent,
127 : : int raw)
128 : : {
129 : 0 : struct acpi_device *adev;
130 : :
131 [ # # ]: 0 : if (!parent)
132 : : return NULL;
133 : :
134 [ # # ]: 0 : list_for_each_entry(adev, &parent->children, node) {
135 [ # # ]: 0 : if (acpi_device_adr(adev) == raw)
136 : 0 : return adev;
137 : : }
138 : :
139 : 0 : return acpi_find_child_device(parent, raw, false);
140 : : }
141 : :
142 : : static struct acpi_device *
143 : : usb_acpi_get_companion_for_port(struct usb_port *port_dev)
144 : : {
145 : : struct usb_device *udev;
146 : : struct acpi_device *adev;
147 : : acpi_handle *parent_handle;
148 : : int port1;
149 : :
150 : : /* Get the struct usb_device point of port's hub */
151 : : udev = to_usb_device(port_dev->dev.parent->parent);
152 : :
153 : : /*
154 : : * The root hub ports' parent is the root hub. The non-root-hub
155 : : * ports' parent is the parent hub port which the hub is
156 : : * connected to.
157 : : */
158 : : if (!udev->parent) {
159 : : adev = ACPI_COMPANION(&udev->dev);
160 : : port1 = usb_hcd_find_raw_port_number(bus_to_hcd(udev->bus),
161 : : port_dev->portnum);
162 : : } else {
163 : : parent_handle = usb_get_hub_port_acpi_handle(udev->parent,
164 : : udev->portnum);
165 : : if (!parent_handle)
166 : : return NULL;
167 : :
168 : : acpi_bus_get_device(parent_handle, &adev);
169 : : port1 = port_dev->portnum;
170 : : }
171 : :
172 : : return usb_acpi_find_port(adev, port1);
173 : : }
174 : :
175 : : static struct acpi_device *
176 : 0 : usb_acpi_find_companion_for_port(struct usb_port *port_dev)
177 : : {
178 : 0 : struct acpi_device *adev;
179 : 0 : struct acpi_pld_info *pld;
180 : 0 : acpi_handle *handle;
181 : 0 : acpi_status status;
182 : :
183 : 0 : adev = usb_acpi_get_companion_for_port(port_dev);
184 [ # # ]: 0 : if (!adev)
185 : : return NULL;
186 : :
187 : 0 : handle = adev->handle;
188 : 0 : status = acpi_get_physical_device_location(handle, &pld);
189 [ # # # # ]: 0 : if (!ACPI_FAILURE(status) && pld) {
190 : 0 : port_dev->location = USB_ACPI_LOCATION_VALID
191 : 0 : | pld->group_token << 8 | pld->group_position;
192 : 0 : port_dev->connect_type = usb_acpi_get_connect_type(handle, pld);
193 : 0 : ACPI_FREE(pld);
194 : : }
195 : :
196 : : return adev;
197 : : }
198 : :
199 : : static struct acpi_device *
200 : 0 : usb_acpi_find_companion_for_device(struct usb_device *udev)
201 : : {
202 : 0 : struct acpi_device *adev;
203 : 0 : struct usb_port *port_dev;
204 : 0 : struct usb_hub *hub;
205 : :
206 [ # # ]: 0 : if (!udev->parent) {
207 : : /* root hub is only child (_ADR=0) under its parent, the HC */
208 [ # # ]: 0 : adev = ACPI_COMPANION(udev->dev.parent);
209 : 0 : return acpi_find_child_device(adev, 0, false);
210 : : }
211 : :
212 : 0 : hub = usb_hub_to_struct_hub(udev->parent);
213 [ # # ]: 0 : if (!hub)
214 : : return NULL;
215 : :
216 : : /*
217 : : * This is an embedded USB device connected to a port and such
218 : : * devices share port's ACPI companion.
219 : : */
220 : 0 : port_dev = hub->ports[udev->portnum - 1];
221 : 0 : return usb_acpi_get_companion_for_port(port_dev);
222 : : }
223 : :
224 : 0 : static struct acpi_device *usb_acpi_find_companion(struct device *dev)
225 : : {
226 : : /*
227 : : * The USB hierarchy like following:
228 : : *
229 : : * Device (EHC1)
230 : : * Device (HUBN)
231 : : * Device (PR01)
232 : : * Device (PR11)
233 : : * Device (PR12)
234 : : * Device (FN12)
235 : : * Device (FN13)
236 : : * Device (PR13)
237 : : * ...
238 : : * where HUBN is root hub, and PRNN are USB ports and devices
239 : : * connected to them, and FNNN are individualk functions for
240 : : * connected composite USB devices. PRNN and FNNN may contain
241 : : * _CRS and other methods describing sideband resources for
242 : : * the connected device.
243 : : *
244 : : * On the kernel side both root hub and embedded USB devices are
245 : : * represented as instances of usb_device structure, and ports
246 : : * are represented as usb_port structures, so the whole process
247 : : * is split into 2 parts: finding companions for devices and
248 : : * finding companions for ports.
249 : : *
250 : : * Note that we do not handle individual functions of composite
251 : : * devices yet, for that we would need to assign companions to
252 : : * devices corresponding to USB interfaces.
253 : : */
254 [ # # ]: 0 : if (is_usb_device(dev))
255 : 0 : return usb_acpi_find_companion_for_device(to_usb_device(dev));
256 [ # # ]: 0 : else if (is_usb_port(dev))
257 : 0 : return usb_acpi_find_companion_for_port(to_usb_port(dev));
258 : :
259 : : return NULL;
260 : : }
261 : :
262 : 5217 : static bool usb_acpi_bus_match(struct device *dev)
263 : : {
264 [ + - - + ]: 5217 : return is_usb_device(dev) || is_usb_port(dev);
265 : : }
266 : :
267 : : static struct acpi_bus_type usb_acpi_bus = {
268 : : .name = "USB",
269 : : .match = usb_acpi_bus_match,
270 : : .find_companion = usb_acpi_find_companion,
271 : : };
272 : :
273 : 21 : int usb_acpi_register(void)
274 : : {
275 : 21 : return register_acpi_bus_type(&usb_acpi_bus);
276 : : }
277 : :
278 : 0 : void usb_acpi_unregister(void)
279 : : {
280 : 0 : unregister_acpi_bus_type(&usb_acpi_bus);
281 : 0 : }
|