// SPDX-License-Identifier: GPL-2.0-only/* * scan.c - support for transforming the ACPI namespace into individual objects */ #define pr_fmt(fmt) "ACPI: " fmt #include <linux/async.h>#include <linux/auxiliary_bus.h>#include <linux/module.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/kernel.h>#include <linux/acpi.h>#include <linux/acpi_iort.h>#include <linux/acpi_rimt.h>#include <linux/acpi_viot.h>#include <linux/iommu.h>#include <linux/signal.h>#include <linux/kthread.h>#include <linux/dmi.h>#include <linux/dma-map-ops.h>#include <linux/platform_data/x86/apple.h>#include <linux/pgtable.h>#include <linux/crc32.h>#include <linux/dma-direct.h> #include "internal.h"#include "sleep.h" #define ACPI_BUS_HID "LNXSYBUS" #define INVALID_ACPI_HANDLE ((acpi_handle)ZERO_PAGE(0)) static const char *dummy_hid = "device"; static LIST_HEAD(acpi_dep_list);static DEFINE_MUTEX(acpi_dep_list_lock);LIST_HEAD(acpi_bus_id_list);static DEFINE_MUTEX(acpi_scan_lock);static LIST_HEAD(acpi_scan_handlers_list);DEFINE_MUTEX(acpi_device_lock);LIST_HEAD(acpi_wakeup_device_list);static DEFINE_MUTEX(acpi_hp_context_lock);static LIST_HEAD(acpi_scan_system_dev_list); /* * The UART device described by the SPCR table is the only object which needs * special-casing. Everything else is covered by ACPI namespace paths in STAO * table. */static u64 spcr_uart_addr; void acpi_scan_lock_acquire(void){ mutex_lock(&acpi_scan_lock);}EXPORT_SYMBOL_GPL(acpi_scan_lock_acquire); void acpi_scan_lock_release(void){ mutex_unlock(&acpi_scan_lock);}EXPORT_SYMBOL_GPL(acpi_scan_lock_release); void acpi_lock_hp_context(void){ mutex_lock(&acpi_hp_context_lock);} void acpi_unlock_hp_context(void){ mutex_unlock(&acpi_hp_context_lock);} void acpi_initialize_hp_context(struct acpi_device *adev, struct acpi_hotplug_context *hp, acpi_hp_notify notify, acpi_hp_uevent uevent){ acpi_lock_hp_context(); hp->notify = notify; hp->uevent = uevent; acpi_set_hp_context(adev, hp); acpi_unlock_hp_context();}EXPORT_SYMBOL_GPL(acpi_initialize_hp_context); int acpi_scan_add_handler(struct acpi_scan_handler *handler){ if (!handler) return -EINVAL; list_add_tail(&handler->list_node, &acpi_scan_handlers_list); return 0;} int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler, const char *hotplug_profile_name){ int error; error = acpi_scan_add_handler(handler); if (error) return error; acpi_sysfs_add_hotplug_profile(&handler->hotplug, hotplug_profile_name); return 0;} bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent){ struct acpi_device_physical_node *pn; bool offline = true; char *envp[] = { "EVENT=offline", NULL }; /* * acpi_container_offline() calls this for all of the container's * children under the container's physical_node_lock lock. */ mutex_lock_nested(&adev->physical_node_lock, SINGLE_DEPTH_NESTING); list_for_each_entry(pn, &adev->physical_node_list, node) if (device_supports_offline(pn->dev) && !dev_offline(pn->dev)) { if (uevent) kobject_uevent_env(&pn->dev->kobj, KOBJ_CHANGE, envp); offline = false; break; } mutex_unlock(&adev->physical_node_lock); return offline;} static acpi_status acpi_bus_offline(acpi_handle handle, u32 lvl, void *data, void **ret_p){ struct acpi_device *device = acpi_fetch_acpi_dev(handle); struct acpi_device_physical_node *pn; bool second_pass = (bool)data; acpi_status status = AE_OK; if (!device) return AE_OK; if (device->handler && !device->handler->hotplug.enabled) { *ret_p = &device->dev; return AE_SUPPORT; } mutex_lock(&device->physical_node_lock); list_for_each_entry(pn, &device->physical_node_list, node) { int ret; if (second_pass) { /* Skip devices offlined by the first pass. */ if (pn->put_online) continue; } else { pn->put_online = false; } ret = device_offline(pn->dev); if (ret >= 0) { pn->put_online = !ret; } else { *ret_p = pn->dev; if (second_pass) { status = AE_ERROR; break; } } } mutex_unlock(&device->physical_node_lock); return status;} static acpi_status acpi_bus_online(acpi_handle handle, u32 lvl, void *data, void **ret_p){ struct acpi_device *device = acpi_fetch_acpi_dev(handle); struct acpi_device_physical_node *pn; if (!device) return AE_OK; mutex_lock(&device->physical_node_lock); list_for_each_entry(pn, &device->physical_node_list, node) if (pn->put_online) { device_online(pn->dev); pn->put_online = false; } mutex_unlock(&device->physical_node_lock); return AE_OK;} static int acpi_scan_try_to_offline(struct acpi_device *device){ acpi_handle handle = device->handle; struct device *errdev = NULL; acpi_status status; /* * Carry out two passes here and ignore errors in the first pass, * because if the devices in question are memory blocks and * CONFIG_MEMCG is set, one of the blocks may hold data structures * that the other blocks depend on, but it is not known in advance which * block holds them. * * If the first pass is successful, the second one isn't needed, though. */ status = acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, NULL, acpi_bus_offline, (void *)false, (void **)&errdev); if (status == AE_SUPPORT) { dev_warn(errdev, "Offline disabled.\n"); acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, acpi_bus_online, NULL, NULL, NULL); return -EPERM; } acpi_bus_offline(handle, 0, (void *)false, (void **)&errdev); if (errdev) { errdev = NULL; acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, NULL, acpi_bus_offline, (void *)true, (void **)&errdev); if (!errdev) acpi_bus_offline(handle, 0, (void *)true, (void **)&errdev); if (errdev) { dev_warn(errdev, "Offline failed.\n"); acpi_bus_online(handle, 0, NULL, NULL); acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, acpi_bus_online, NULL, NULL, NULL); return -EBUSY; } } return 0;} #define ACPI_SCAN_CHECK_FLAG_STATUS BIT(0)#define ACPI_SCAN_CHECK_FLAG_EJECT BIT(1) static int acpi_scan_check_and_detach(struct acpi_device *adev, void *p){ struct acpi_scan_handler *handler = adev->handler; uintptr_t flags = (uintptr_t)p; acpi_dev_for_each_child_reverse(adev, acpi_scan_check_and_detach, p); if (flags & ACPI_SCAN_CHECK_FLAG_STATUS) { acpi_bus_get_status(adev); /* * Skip devices that are still there and take the enabled * flag into account. */ if (acpi_device_is_enabled(adev)) return 0; /* Skip device that have not been enumerated. */ if (!acpi_device_enumerated(adev)) { dev_dbg(&adev->dev, "Still not enumerated\n"); return 0; } } if (handler && handler->detach) handler->detach(adev); /* * Most likely, the device is going away, so put it into D3cold before * that. */ acpi_device_set_power(adev, ACPI_STATE_D3_COLD); adev->flags.initialized = false; /* For eject this is deferred to acpi_bus_post_eject() */ if (!(flags & ACPI_SCAN_CHECK_FLAG_EJECT)) { adev->handler = NULL; acpi_device_clear_enumerated(adev); } return 0;} static int acpi_bus_post_eject(struct acpi_device *adev, void *not_used){ struct acpi_scan_handler *handler = adev->handler; acpi_dev_for_each_child_reverse(adev, acpi_bus_post_eject, NULL); if (handler) { if (handler->post_eject) handler->post_eject(adev); adev->handler = NULL; } acpi_device_clear_enumerated(adev); return 0;} static void acpi_scan_check_subtree(struct acpi_device *adev){ uintptr_t flags = ACPI_SCAN_CHECK_FLAG_STATUS; acpi_scan_check_and_detach(adev, (void *)flags);} static int acpi_scan_hot_remove(struct acpi_device *device){ acpi_handle handle = device->handle; unsigned long long sta; acpi_status status; uintptr_t flags = ACPI_SCAN_CHECK_FLAG_EJECT; if (device->handler && device->handler->hotplug.demand_offline) { if (!acpi_scan_is_offline(device, true)) return -EBUSY; } else { int error = acpi_scan_try_to_offline(device); if (error) return error; } acpi_handle_debug(handle, "Ejecting\n"); acpi_scan_check_and_detach(device, (void *)flags); acpi_evaluate_lck(handle, 0); /* * TBD: _EJD support. */ status = acpi_evaluate_ej0(handle); if (status == AE_NOT_FOUND) return -ENODEV; else if (ACPI_FAILURE(status)) return -EIO; /* * Verify if eject was indeed successful. If not, log an error * message. No need to call _OST since _EJ0 call was made OK. */ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); if (ACPI_FAILURE(status)) { acpi_handle_warn(handle, "Status check after eject failed (0x%x)\n", status); } else if (sta & ACPI_STA_DEVICE_ENABLED) { acpi_handle_warn(handle, "Eject incomplete - status 0x%llx\n", sta); } else { acpi_bus_post_eject(device, NULL); } return 0;} static int acpi_scan_rescan_bus(struct acpi_device *adev){ struct acpi_scan_handler *handler = adev->handler; int ret; if (handler && handler->hotplug.scan_dependent) ret = handler->hotplug.scan_dependent(adev); else ret = acpi_bus_scan(adev->handle); if (ret) dev_info(&adev->dev, "Namespace scan failure\n"); return ret;} static int acpi_scan_device_check(struct acpi_device *adev){ struct acpi_device *parent; acpi_scan_check_subtree(adev); if (!acpi_device_is_present(adev)) return 0; /* * This function is only called for device objects for which matching * scan handlers exist. The only situation in which the scan handler * is not attached to this device object yet is when the device has * just appeared (either it wasn't present at all before or it was * removed and then added again). */ if (adev->handler) { dev_dbg(&adev->dev, "Already enumerated\n"); return 0; } parent = acpi_dev_parent(adev); if (!parent) parent = adev; return acpi_scan_rescan_bus(parent);} static int acpi_scan_bus_check(struct acpi_device *adev){ acpi_scan_check_subtree(adev); return acpi_scan_rescan_bus(adev);} static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type){ switch (type) { case ACPI_NOTIFY_BUS_CHECK: return acpi_scan_bus_check(adev); case ACPI_NOTIFY_DEVICE_CHECK: return acpi_scan_device_check(adev); case ACPI_NOTIFY_EJECT_REQUEST: case ACPI_OST_EC_OSPM_EJECT: if (adev->handler && !adev->handler->hotplug.enabled) { dev_info(&adev->dev, "Eject disabled\n"); return -EPERM; } acpi_evaluate_ost(adev->handle, ACPI_NOTIFY_EJECT_REQUEST, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); return acpi_scan_hot_remove(adev); } return -EINVAL;} void acpi_device_hotplug(struct acpi_device *adev, u32 src){ u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; int error = -ENODEV; lock_device_hotplug(); mutex_lock(&acpi_scan_lock); /* * The device object's ACPI handle cannot become invalid as long as we * are holding acpi_scan_lock, but it might have become invalid before * that lock was acquired. */ if (adev->handle == INVALID_ACPI_HANDLE) goto err_out; if (adev->flags.is_dock_station) { error = dock_notify(adev, src); } else if (adev->flags.hotplug_notify) { error = acpi_generic_hotplug_event(adev, src); } else { acpi_hp_notify notify; acpi_lock_hp_context(); notify = adev->hp ? adev->hp->notify : NULL; acpi_unlock_hp_context(); /* * There may be additional notify handlers for device objects * without the .event() callback, so ignore them here. */ if (notify) error = notify(adev, src); else goto out; } switch (error) { case 0: ost_code = ACPI_OST_SC_SUCCESS; break; case -EPERM: ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; break; case -EBUSY: ost_code = ACPI_OST_SC_DEVICE_BUSY; break; default: ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; break; } err_out: acpi_evaluate_ost(adev->handle, src, ost_code, NULL); out: acpi_put_acpi_dev(adev); mutex_unlock(&acpi_scan_lock); unlock_device_hotplug();} static void acpi_free_power_resources_lists(struct acpi_device *device){ int i; if (device->wakeup.flags.valid) acpi_power_resources_list_free(&device->wakeup.resources);Lines 1–500 of 2961. Load more
// SPDX-License-Identifier: GPL-2.0-only /* * scan.c - support for transforming the ACPI namespace into individual objects */ #define pr_fmt(fmt) "ACPI: " fmt #include <linux/async.h> #include <linux/auxiliary_bus.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/kernel.h> #include <linux/acpi.h> #include <linux/acpi_iort.h> #include <linux/acpi_rimt.h> #include <linux/acpi_viot.h> #include <linux/iommu.h> #include <linux/signal.h> #include <linux/kthread.h> #include <linux/dmi.h> #include <linux/dma-map-ops.h> #include <linux/platform_data/x86/apple.h> #include <linux/pgtable.h> #include <linux/crc32.h> #include <linux/dma-direct.h> #include "internal.h" #include "sleep.h" #define ACPI_BUS_HID "LNXSYBUS" #define INVALID_ACPI_HANDLE ((acpi_handle)ZERO_PAGE(0)) static const char *dummy_hid = "device"; static LIST_HEAD(acpi_dep_list); static DEFINE_MUTEX(acpi_dep_list_lock); LIST_HEAD(acpi_bus_id_list); static DEFINE_MUTEX(acpi_scan_lock); static LIST_HEAD(acpi_scan_handlers_list); DEFINE_MUTEX(acpi_device_lock); LIST_HEAD(acpi_wakeup_device_list); static DEFINE_MUTEX(acpi_hp_context_lock); static LIST_HEAD(acpi_scan_system_dev_list); /* * The UART device described by the SPCR table is the only object which needs * special-casing. Everything else is covered by ACPI namespace paths in STAO * table. */ static u64 spcr_uart_addr; void acpi_scan_lock_acquire(void) { mutex_lock(&acpi_scan_lock); } EXPORT_SYMBOL_GPL(acpi_scan_lock_acquire); void acpi_scan_lock_release(void) { mutex_unlock(&acpi_scan_lock); } EXPORT_SYMBOL_GPL(acpi_scan_lock_release); void acpi_lock_hp_context(void) { mutex_lock(&acpi_hp_context_lock); } void acpi_unlock_hp_context(void) { mutex_unlock(&acpi_hp_context_lock); } void acpi_initialize_hp_context(struct acpi_device *adev, struct acpi_hotplug_context *hp, acpi_hp_notify notify, acpi_hp_uevent uevent) { acpi_lock_hp_context(); hp->notify = notify; hp->uevent = uevent; acpi_set_hp_context(adev, hp); acpi_unlock_hp_context(); } EXPORT_SYMBOL_GPL(acpi_initialize_hp_context); int acpi_scan_add_handler(struct acpi_scan_handler *handler) { if (!handler) return -EINVAL; list_add_tail(&handler->list_node, &acpi_scan_handlers_list); return 0; } int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler, const char *hotplug_profile_name) { int error; error = acpi_scan_add_handler(handler); if (error) return error; acpi_sysfs_add_hotplug_profile(&handler->hotplug, hotplug_profile_name); return 0; } bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent) { struct acpi_device_physical_node *pn; bool offline = true; char *envp[] = { "EVENT=offline", NULL }; /* * acpi_container_offline() calls this for all of the container's * children under the container's physical_node_lock lock. */ mutex_lock_nested(&adev->physical_node_lock, SINGLE_DEPTH_NESTING); list_for_each_entry(pn, &adev->physical_node_list, node) if (device_supports_offline(pn->dev) && !dev_offline(pn->dev)) { if (uevent) kobject_uevent_env(&pn->dev->kobj, KOBJ_CHANGE, envp); offline = false; break; } mutex_unlock(&adev->physical_node_lock); return offline; } static acpi_status acpi_bus_offline(acpi_handle handle, u32 lvl, void *data, void **ret_p) { struct acpi_device *device = acpi_fetch_acpi_dev(handle); struct acpi_device_physical_node *pn; bool second_pass = (bool)data; acpi_status status = AE_OK; if (!device) return AE_OK; if (device->handler && !device->handler->hotplug.enabled) { *ret_p = &device->dev; return AE_SUPPORT; } mutex_lock(&device->physical_node_lock); list_for_each_entry(pn, &device->physical_node_list, node) { int ret; if (second_pass) { /* Skip devices offlined by the first pass. */ if (pn->put_online) continue; } else { pn->put_online = false; } ret = device_offline(pn->dev); if (ret >= 0) { pn->put_online = !ret; } else { *ret_p = pn->dev; if (second_pass) { status = AE_ERROR; break; } } } mutex_unlock(&device->physical_node_lock); return status; } static acpi_status acpi_bus_online(acpi_handle handle, u32 lvl, void *data, void **ret_p) { struct acpi_device *device = acpi_fetch_acpi_dev(handle); struct acpi_device_physical_node *pn; if (!device) return AE_OK; mutex_lock(&device->physical_node_lock); list_for_each_entry(pn, &device->physical_node_list, node) if (pn->put_online) { device_online(pn->dev); pn->put_online = false; } mutex_unlock(&device->physical_node_lock); return AE_OK; } static int acpi_scan_try_to_offline(struct acpi_device *device) { acpi_handle handle = device->handle; struct device *errdev = NULL; acpi_status status; /* * Carry out two passes here and ignore errors in the first pass, * because if the devices in question are memory blocks and * CONFIG_MEMCG is set, one of the blocks may hold data structures * that the other blocks depend on, but it is not known in advance which * block holds them. * * If the first pass is successful, the second one isn't needed, though. */ status = acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, NULL, acpi_bus_offline, (void *)false, (void **)&errdev); if (status == AE_SUPPORT) { dev_warn(errdev, "Offline disabled.\n"); acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, acpi_bus_online, NULL, NULL, NULL); return -EPERM; } acpi_bus_offline(handle, 0, (void *)false, (void **)&errdev); if (errdev) { errdev = NULL; acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, NULL, acpi_bus_offline, (void *)true, (void **)&errdev); if (!errdev) acpi_bus_offline(handle, 0, (void *)true, (void **)&errdev); if (errdev) { dev_warn(errdev, "Offline failed.\n"); acpi_bus_online(handle, 0, NULL, NULL); acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, acpi_bus_online, NULL, NULL, NULL); return -EBUSY; } } return 0; } #define ACPI_SCAN_CHECK_FLAG_STATUS BIT(0) #define ACPI_SCAN_CHECK_FLAG_EJECT BIT(1) static int acpi_scan_check_and_detach(struct acpi_device *adev, void *p) { struct acpi_scan_handler *handler = adev->handler; uintptr_t flags = (uintptr_t)p; acpi_dev_for_each_child_reverse(adev, acpi_scan_check_and_detach, p); if (flags & ACPI_SCAN_CHECK_FLAG_STATUS) { acpi_bus_get_status(adev); /* * Skip devices that are still there and take the enabled * flag into account. */ if (acpi_device_is_enabled(adev)) return 0; /* Skip device that have not been enumerated. */ if (!acpi_device_enumerated(adev)) { dev_dbg(&adev->dev, "Still not enumerated\n"); return 0; } } if (handler && handler->detach) handler->detach(adev); /* * Most likely, the device is going away, so put it into D3cold before * that. */ acpi_device_set_power(adev, ACPI_STATE_D3_COLD); adev->flags.initialized = false; /* For eject this is deferred to acpi_bus_post_eject() */ if (!(flags & ACPI_SCAN_CHECK_FLAG_EJECT)) { adev->handler = NULL; acpi_device_clear_enumerated(adev); } return 0; } static int acpi_bus_post_eject(struct acpi_device *adev, void *not_used) { struct acpi_scan_handler *handler = adev->handler; acpi_dev_for_each_child_reverse(adev, acpi_bus_post_eject, NULL); if (handler) { if (handler->post_eject) handler->post_eject(adev); adev->handler = NULL; } acpi_device_clear_enumerated(adev); return 0; } static void acpi_scan_check_subtree(struct acpi_device *adev) { uintptr_t flags = ACPI_SCAN_CHECK_FLAG_STATUS; acpi_scan_check_and_detach(adev, (void *)flags); } static int acpi_scan_hot_remove(struct acpi_device *device) { acpi_handle handle = device->handle; unsigned long long sta; acpi_status status; uintptr_t flags = ACPI_SCAN_CHECK_FLAG_EJECT; if (device->handler && device->handler->hotplug.demand_offline) { if (!acpi_scan_is_offline(device, true)) return -EBUSY; } else { int error = acpi_scan_try_to_offline(device); if (error) return error; } acpi_handle_debug(handle, "Ejecting\n"); acpi_scan_check_and_detach(device, (void *)flags); acpi_evaluate_lck(handle, 0); /* * TBD: _EJD support. */ status = acpi_evaluate_ej0(handle); if (status == AE_NOT_FOUND) return -ENODEV; else if (ACPI_FAILURE(status)) return -EIO; /* * Verify if eject was indeed successful. If not, log an error * message. No need to call _OST since _EJ0 call was made OK. */ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); if (ACPI_FAILURE(status)) { acpi_handle_warn(handle, "Status check after eject failed (0x%x)\n", status); } else if (sta & ACPI_STA_DEVICE_ENABLED) { acpi_handle_warn(handle, "Eject incomplete - status 0x%llx\n", sta); } else { acpi_bus_post_eject(device, NULL); } return 0; } static int acpi_scan_rescan_bus(struct acpi_device *adev) { struct acpi_scan_handler *handler = adev->handler; int ret; if (handler && handler->hotplug.scan_dependent) ret = handler->hotplug.scan_dependent(adev); else ret = acpi_bus_scan(adev->handle); if (ret) dev_info(&adev->dev, "Namespace scan failure\n"); return ret; } static int acpi_scan_device_check(struct acpi_device *adev) { struct acpi_device *parent; acpi_scan_check_subtree(adev); if (!acpi_device_is_present(adev)) return 0; /* * This function is only called for device objects for which matching * scan handlers exist. The only situation in which the scan handler * is not attached to this device object yet is when the device has * just appeared (either it wasn't present at all before or it was * removed and then added again). */ if (adev->handler) { dev_dbg(&adev->dev, "Already enumerated\n"); return 0; } parent = acpi_dev_parent(adev); if (!parent) parent = adev; return acpi_scan_rescan_bus(parent); } static int acpi_scan_bus_check(struct acpi_device *adev) { acpi_scan_check_subtree(adev); return acpi_scan_rescan_bus(adev); } static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type) { switch (type) { case ACPI_NOTIFY_BUS_CHECK: return acpi_scan_bus_check(adev); case ACPI_NOTIFY_DEVICE_CHECK: return acpi_scan_device_check(adev); case ACPI_NOTIFY_EJECT_REQUEST: case ACPI_OST_EC_OSPM_EJECT: if (adev->handler && !adev->handler->hotplug.enabled) { dev_info(&adev->dev, "Eject disabled\n"); return -EPERM; } acpi_evaluate_ost(adev->handle, ACPI_NOTIFY_EJECT_REQUEST, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); return acpi_scan_hot_remove(adev); } return -EINVAL; } void acpi_device_hotplug(struct acpi_device *adev, u32 src) { u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; int error = -ENODEV; lock_device_hotplug(); mutex_lock(&acpi_scan_lock); /* * The device object's ACPI handle cannot become invalid as long as we * are holding acpi_scan_lock, but it might have become invalid before * that lock was acquired. */ if (adev->handle == INVALID_ACPI_HANDLE) goto err_out; if (adev->flags.is_dock_station) { error = dock_notify(adev, src); } else if (adev->flags.hotplug_notify) { error = acpi_generic_hotplug_event(adev, src); } else { acpi_hp_notify notify; acpi_lock_hp_context(); notify = adev->hp ? adev->hp->notify : NULL; acpi_unlock_hp_context(); /* * There may be additional notify handlers for device objects * without the .event() callback, so ignore them here. */ if (notify) error = notify(adev, src); else goto out; } switch (error) { case 0: ost_code = ACPI_OST_SC_SUCCESS; break; case -EPERM: ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; break; case -EBUSY: ost_code = ACPI_OST_SC_DEVICE_BUSY; break; default: ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; break; } err_out: acpi_evaluate_ost(adev->handle, src, ost_code, NULL); out: acpi_put_acpi_dev(adev); mutex_unlock(&acpi_scan_lock); unlock_device_hotplug(); } static void acpi_free_power_resources_lists(struct acpi_device *device) { int i; if (device->wakeup.flags.valid) acpi_power_resources_list_free(&device->wakeup.resources);