diff options
Diffstat (limited to 'drivers/acpi/glue.c')
-rw-r--r-- | drivers/acpi/glue.c | 66 |
1 files changed, 49 insertions, 17 deletions
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 7a33a6d985f8..7cd0009e7ff3 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -17,6 +17,8 @@ #include <linux/rwsem.h> #include <linux/acpi.h> #include <linux/dma-mapping.h> +#include <linux/pci.h> +#include <linux/pci-acpi.h> #include <linux/platform_device.h> #include "internal.h" @@ -111,13 +113,10 @@ struct acpi_device *acpi_find_child_device(struct acpi_device *parent, return NULL; list_for_each_entry(adev, &parent->children, node) { - unsigned long long addr; - acpi_status status; + acpi_bus_address addr = acpi_device_adr(adev); int score; - status = acpi_evaluate_integer(adev->handle, METHOD_NAME__ADR, - NULL, &addr); - if (ACPI_FAILURE(status) || addr != address) + if (!adev->pnp.type.bus_address || addr != address) continue; if (!ret) { @@ -287,12 +286,13 @@ EXPORT_SYMBOL_GPL(acpi_unbind_one); void acpi_device_notify(struct device *dev) { - struct acpi_bus_type *type = acpi_get_bus_type(dev); struct acpi_device *adev; int ret; ret = acpi_bind_one(dev, NULL); if (ret) { + struct acpi_bus_type *type = acpi_get_bus_type(dev); + if (!type) goto err; @@ -304,17 +304,26 @@ void acpi_device_notify(struct device *dev) ret = acpi_bind_one(dev, adev); if (ret) goto err; - } - adev = ACPI_COMPANION(dev); - if (dev_is_platform(dev)) - acpi_configure_pmsi_domain(dev); + if (type->setup) { + type->setup(dev); + goto done; + } + } else { + adev = ACPI_COMPANION(dev); + + if (dev_is_pci(dev)) { + pci_acpi_setup(dev, adev); + goto done; + } else if (dev_is_platform(dev)) { + acpi_configure_pmsi_domain(dev); + } + } - if (type && type->setup) - type->setup(dev); - else if (adev->handler && adev->handler->bind) + if (adev->handler && adev->handler->bind) adev->handler->bind(dev); +done: acpi_handle_debug(ACPI_HANDLE(dev), "Bound to device %s\n", dev_name(dev)); @@ -327,16 +336,39 @@ err: void acpi_device_notify_remove(struct device *dev) { struct acpi_device *adev = ACPI_COMPANION(dev); - struct acpi_bus_type *type; if (!adev) return; - type = acpi_get_bus_type(dev); - if (type && type->cleanup) - type->cleanup(dev); + if (dev_is_pci(dev)) + pci_acpi_cleanup(dev, adev); else if (adev->handler && adev->handler->unbind) adev->handler->unbind(dev); acpi_unbind_one(dev); } + +int acpi_dev_turn_off_if_unused(struct device *dev, void *not_used) +{ + struct acpi_device *adev = to_acpi_device(dev); + + /* + * Skip device objects with device IDs, because they may be in use even + * if they are not companions of any physical device objects. + */ + if (adev->pnp.type.hardware_id) + return 0; + + mutex_lock(&adev->physical_node_lock); + + /* + * Device objects without device IDs are not in use if they have no + * corresponding physical device objects. + */ + if (list_empty(&adev->physical_node_list)) + acpi_device_set_power(adev, ACPI_STATE_D3_COLD); + + mutex_unlock(&adev->physical_node_lock); + + return 0; +} |