From bcfcd409d4dbb886d78c61423ce3034c94324c32 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 24 Jan 2019 15:28:11 -0800 Subject: usb: split code locating ACPI companion into port and device In preparation for handling embedded USB devices let's split usb_acpi_find_companion() into usb_acpi_find_companion_for_device() and usb_acpi_find_companion_for_port(). Signed-off-by: Dmitry Torokhov Signed-off-by: Rajat Jain Acked-by: Greg Kroah-Hartman Tested-by: Sukumar Ghorai Signed-off-by: Marcel Holtmann --- drivers/usb/core/usb-acpi.c | 133 ++++++++++++++++++++++++-------------------- 1 file changed, 72 insertions(+), 61 deletions(-) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index e221861b3187..8ff73c83e8e8 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -139,12 +139,79 @@ static struct acpi_device *usb_acpi_find_port(struct acpi_device *parent, return acpi_find_child_device(parent, raw, false); } -static struct acpi_device *usb_acpi_find_companion(struct device *dev) +static struct acpi_device * +usb_acpi_get_companion_for_port(struct usb_port *port_dev) { struct usb_device *udev; struct acpi_device *adev; acpi_handle *parent_handle; + int port1; + + /* Get the struct usb_device point of port's hub */ + udev = to_usb_device(port_dev->dev.parent->parent); + + /* + * The root hub ports' parent is the root hub. The non-root-hub + * ports' parent is the parent hub port which the hub is + * connected to. + */ + if (!udev->parent) { + adev = ACPI_COMPANION(&udev->dev); + port1 = usb_hcd_find_raw_port_number(bus_to_hcd(udev->bus), + port_dev->portnum); + } else { + parent_handle = usb_get_hub_port_acpi_handle(udev->parent, + udev->portnum); + if (!parent_handle) + return NULL; + + acpi_bus_get_device(parent_handle, &adev); + port1 = port_dev->portnum; + } + + return usb_acpi_find_port(adev, port1); +} + +static struct acpi_device * +usb_acpi_find_companion_for_port(struct usb_port *port_dev) +{ + struct acpi_device *adev; + struct acpi_pld_info *pld; + acpi_handle *handle; + acpi_status status; + + adev = usb_acpi_get_companion_for_port(port_dev); + if (!adev) + return NULL; + + handle = adev->handle; + status = acpi_get_physical_device_location(handle, &pld); + if (!ACPI_FAILURE(status) && pld) { + port_dev->location = USB_ACPI_LOCATION_VALID + | pld->group_token << 8 | pld->group_position; + port_dev->connect_type = usb_acpi_get_connect_type(handle, pld); + ACPI_FREE(pld); + } + return adev; +} + +static struct acpi_device * +usb_acpi_find_companion_for_device(struct usb_device *udev) +{ + struct acpi_device *adev; + + if (!udev->parent) + 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); +} + + +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. @@ -158,66 +225,10 @@ static struct acpi_device *usb_acpi_find_companion(struct device *dev) * So all binding process is divided into two parts. binding * root hub and usb ports. */ - if (is_usb_device(dev)) { - udev = to_usb_device(dev); - if (udev->parent) - return NULL; - - /* root hub is only child (_ADR=0) under its parent, the HC */ - adev = ACPI_COMPANION(dev->parent); - return acpi_find_child_device(adev, 0, false); - } else if (is_usb_port(dev)) { - struct usb_port *port_dev = to_usb_port(dev); - int port1 = port_dev->portnum; - struct acpi_pld_info *pld; - acpi_handle *handle; - acpi_status status; - - /* Get the struct usb_device point of port's hub */ - udev = to_usb_device(dev->parent->parent); - - /* - * The root hub ports' parent is the root hub. The non-root-hub - * ports' parent is the parent hub port which the hub is - * connected to. - */ - if (!udev->parent) { - struct usb_hcd *hcd = bus_to_hcd(udev->bus); - int raw; - - raw = usb_hcd_find_raw_port_number(hcd, port1); - - adev = usb_acpi_find_port(ACPI_COMPANION(&udev->dev), - raw); - - if (!adev) - return NULL; - } else { - parent_handle = - usb_get_hub_port_acpi_handle(udev->parent, - udev->portnum); - if (!parent_handle) - return NULL; - - acpi_bus_get_device(parent_handle, &adev); - - adev = usb_acpi_find_port(adev, port1); - - if (!adev) - return NULL; - } - handle = adev->handle; - status = acpi_get_physical_device_location(handle, &pld); - if (ACPI_FAILURE(status) || !pld) - return adev; - - port_dev->location = USB_ACPI_LOCATION_VALID - | pld->group_token << 8 | pld->group_position; - port_dev->connect_type = usb_acpi_get_connect_type(handle, pld); - ACPI_FREE(pld); - - return adev; - } + if (is_usb_device(dev)) + return usb_acpi_find_companion_for_device(to_usb_device(dev)); + else if (is_usb_port(dev)) + return usb_acpi_find_companion_for_port(to_usb_port(dev)); return NULL; } -- cgit v1.2.3 From b4dfbbd1803d81b51bf2c47b182a7029b476d8e2 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 24 Jan 2019 15:28:12 -0800 Subject: usb: assign ACPI companions for embedded USB devices 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 Signed-off-by: Rajat Jain (changed how we get the usb_port) Acked-by: Greg Kroah-Hartman Tested-by: Sukumar Ghorai Signed-off-by: Marcel Holtmann --- drivers/usb/core/usb-acpi.c | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index 8ff73c83e8e8..9043d7242d67 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -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)); -- cgit v1.2.3