LCOV - code coverage report
Current view: top level - drivers/usb/core - usb-acpi.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 4 66 6.1 %
Date: 2022-04-01 13:59:58 Functions: 2 9 22.2 %
Branches: 2 34 5.9 %

           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                 :      16758 : static bool usb_acpi_bus_match(struct device *dev)
     263                 :            : {
     264   [ +  -  -  + ]:      16758 :         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                 :         78 : int usb_acpi_register(void)
     274                 :            : {
     275                 :         78 :         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 : }

Generated by: LCOV version 1.14