root/drivers/usb/core/usb-acpi.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. usb_acpi_power_manageable
  2. usb_acpi_set_power_state
  3. usb_acpi_get_connect_type
  4. usb_acpi_find_port
  5. usb_acpi_get_companion_for_port
  6. usb_acpi_find_companion_for_port
  7. usb_acpi_find_companion_for_device
  8. usb_acpi_find_companion
  9. usb_acpi_bus_match
  10. usb_acpi_register
  11. usb_acpi_unregister

   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 bool usb_acpi_power_manageable(struct usb_device *hdev, int index)
  27 {
  28         acpi_handle port_handle;
  29         int port1 = index + 1;
  30 
  31         port_handle = usb_get_hub_port_acpi_handle(hdev,
  32                 port1);
  33         if (port_handle)
  34                 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 int usb_acpi_set_power_state(struct usb_device *hdev, int index, bool enable)
  53 {
  54         struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
  55         struct usb_port *port_dev;
  56         acpi_handle port_handle;
  57         unsigned char state;
  58         int port1 = index + 1;
  59         int error = -EINVAL;
  60 
  61         if (!hub)
  62                 return -ENODEV;
  63         port_dev = hub->ports[port1 - 1];
  64 
  65         port_handle = (acpi_handle) usb_get_hub_port_acpi_handle(hdev, port1);
  66         if (!port_handle)
  67                 return error;
  68 
  69         if (enable)
  70                 state = ACPI_STATE_D0;
  71         else
  72                 state = ACPI_STATE_D3_COLD;
  73 
  74         error = acpi_bus_set_power(port_handle, state);
  75         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         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 static struct acpi_device *usb_acpi_find_port(struct acpi_device *parent,
 127                                               int raw)
 128 {
 129         struct acpi_device *adev;
 130 
 131         if (!parent)
 132                 return NULL;
 133 
 134         list_for_each_entry(adev, &parent->children, node) {
 135                 if (acpi_device_adr(adev) == raw)
 136                         return adev;
 137         }
 138 
 139         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 usb_acpi_find_companion_for_port(struct usb_port *port_dev)
 177 {
 178         struct acpi_device *adev;
 179         struct acpi_pld_info *pld;
 180         acpi_handle *handle;
 181         acpi_status status;
 182 
 183         adev = usb_acpi_get_companion_for_port(port_dev);
 184         if (!adev)
 185                 return NULL;
 186 
 187         handle = adev->handle;
 188         status = acpi_get_physical_device_location(handle, &pld);
 189         if (!ACPI_FAILURE(status) && pld) {
 190                 port_dev->location = USB_ACPI_LOCATION_VALID
 191                         | pld->group_token << 8 | pld->group_position;
 192                 port_dev->connect_type = usb_acpi_get_connect_type(handle, pld);
 193                 ACPI_FREE(pld);
 194         }
 195 
 196         return adev;
 197 }
 198 
 199 static struct acpi_device *
 200 usb_acpi_find_companion_for_device(struct usb_device *udev)
 201 {
 202         struct acpi_device *adev;
 203         struct usb_port *port_dev;
 204         struct usb_hub *hub;
 205 
 206         if (!udev->parent) {
 207                 /* root hub is only child (_ADR=0) under its parent, the HC */
 208                 adev = ACPI_COMPANION(udev->dev.parent);
 209                 return acpi_find_child_device(adev, 0, false);
 210         }
 211 
 212         hub = usb_hub_to_struct_hub(udev->parent);
 213         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         port_dev = hub->ports[udev->portnum - 1];
 221         return usb_acpi_get_companion_for_port(port_dev);
 222 }
 223 
 224 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         if (is_usb_device(dev))
 255                 return usb_acpi_find_companion_for_device(to_usb_device(dev));
 256         else if (is_usb_port(dev))
 257                 return usb_acpi_find_companion_for_port(to_usb_port(dev));
 258 
 259         return NULL;
 260 }
 261 
 262 static bool usb_acpi_bus_match(struct device *dev)
 263 {
 264         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 int usb_acpi_register(void)
 274 {
 275         return register_acpi_bus_type(&usb_acpi_bus);
 276 }
 277 
 278 void usb_acpi_unregister(void)
 279 {
 280         unregister_acpi_bus_type(&usb_acpi_bus);
 281 }

/* [<][>][^][v][top][bottom][index][help] */