]> rtime.felk.cvut.cz Git - zynq/linux.git/commitdiff
usb: assign ACPI companions for embedded USB devices
authorDmitry Torokhov <dtor@chromium.org>
Thu, 24 Jan 2019 23:28:12 +0000 (15:28 -0800)
committerMarcel Holtmann <marcel@holtmann.org>
Fri, 25 Jan 2019 07:46:26 +0000 (08:46 +0100)
USB devices permanently connected to USB ports may be described in ACPI
tables and share ACPI devices with ports they are connected to. See [1]
for details.

This will allow us to describe sideband resources for devices, such as,
for example, hard reset line for BT USB controllers.

[1] https://docs.microsoft.com/en-us/windows-hardware/drivers/bringup/other-acpi-namespace-objects#acpi-namespace-hierarchy-and-adr-for-embedded-usb-devices

Signed-off-by: Dmitry Torokhov <dtor@chromium.org>
Signed-off-by: Rajat Jain <rajatja@google.com> (changed how we get the usb_port)
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Tested-by: Sukumar Ghorai <sukumar.ghorai@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
drivers/usb/core/usb-acpi.c

index 8ff73c83e8e82814664445e338b9a006ff7a5772..9043d7242d67ee40001a3b978e09097928373787 100644 (file)
@@ -200,30 +200,56 @@ static struct acpi_device *
 usb_acpi_find_companion_for_device(struct usb_device *udev)
 {
        struct acpi_device *adev;
+       struct usb_port *port_dev;
+       struct usb_hub *hub;
+
+       if (!udev->parent) {
+               /* root hub is only child (_ADR=0) under its parent, the HC */
+               adev = ACPI_COMPANION(udev->dev.parent);
+               return acpi_find_child_device(adev, 0, false);
+       }
 
-       if (!udev->parent)
+       hub = usb_hub_to_struct_hub(udev->parent);
+       if (!hub)
                return NULL;
 
-       /* root hub is only child (_ADR=0) under its parent, the HC */
-       adev = ACPI_COMPANION(udev->dev.parent);
-       return acpi_find_child_device(adev, 0, false);
+       /*
+        * This is an embedded USB device connected to a port and such
+        * devices share port's ACPI companion.
+        */
+       port_dev = hub->ports[udev->portnum - 1];
+       return usb_acpi_get_companion_for_port(port_dev);
 }
 
-
 static struct acpi_device *usb_acpi_find_companion(struct device *dev)
 {
        /*
-        * In the ACPI DSDT table, only usb root hub and usb ports are
-        * acpi device nodes. The hierarchy like following.
+        * The USB hierarchy like following:
+        *
         * Device (EHC1)
         *      Device (HUBN)
         *              Device (PR01)
         *                      Device (PR11)
         *                      Device (PR12)
+        *                              Device (FN12)
+        *                              Device (FN13)
         *                      Device (PR13)
         *                      ...
-        * So all binding process is divided into two parts. binding
-        * root hub and usb ports.
+        * where HUBN is root hub, and PRNN are USB ports and devices
+        * connected to them, and FNNN are individualk functions for
+        * connected composite USB devices. PRNN and FNNN may contain
+        * _CRS and other methods describing sideband resources for
+        * the connected device.
+        *
+        * On the kernel side both root hub and embedded USB devices are
+        * represented as instances of usb_device structure, and ports
+        * are represented as usb_port structures, so the whole process
+        * is split into 2 parts: finding companions for devices and
+        * finding companions for ports.
+        *
+        * Note that we do not handle individual functions of composite
+        * devices yet, for that we would need to assign companions to
+        * devices corresponding to USB interfaces.
         */
        if (is_usb_device(dev))
                return usb_acpi_find_companion_for_device(to_usb_device(dev));