18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * scan.c - support for transforming the ACPI namespace into individual objects 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/module.h> 78c2ecf20Sopenharmony_ci#include <linux/init.h> 88c2ecf20Sopenharmony_ci#include <linux/slab.h> 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/acpi.h> 118c2ecf20Sopenharmony_ci#include <linux/acpi_iort.h> 128c2ecf20Sopenharmony_ci#include <linux/signal.h> 138c2ecf20Sopenharmony_ci#include <linux/kthread.h> 148c2ecf20Sopenharmony_ci#include <linux/dmi.h> 158c2ecf20Sopenharmony_ci#include <linux/nls.h> 168c2ecf20Sopenharmony_ci#include <linux/dma-map-ops.h> 178c2ecf20Sopenharmony_ci#include <linux/platform_data/x86/apple.h> 188c2ecf20Sopenharmony_ci#include <linux/pgtable.h> 198c2ecf20Sopenharmony_ci#include <linux/dma-direct.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "internal.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define _COMPONENT ACPI_BUS_COMPONENT 248c2ecf20Sopenharmony_ciACPI_MODULE_NAME("scan"); 258c2ecf20Sopenharmony_ciextern struct acpi_device *acpi_root; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define ACPI_BUS_CLASS "system_bus" 288c2ecf20Sopenharmony_ci#define ACPI_BUS_HID "LNXSYBUS" 298c2ecf20Sopenharmony_ci#define ACPI_BUS_DEVICE_NAME "System Bus" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define ACPI_IS_ROOT_DEVICE(device) (!(device)->parent) 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define INVALID_ACPI_HANDLE ((acpi_handle)empty_zero_page) 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic const char *dummy_hid = "device"; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic LIST_HEAD(acpi_dep_list); 388c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(acpi_dep_list_lock); 398c2ecf20Sopenharmony_ciLIST_HEAD(acpi_bus_id_list); 408c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(acpi_scan_lock); 418c2ecf20Sopenharmony_cistatic LIST_HEAD(acpi_scan_handlers_list); 428c2ecf20Sopenharmony_ciDEFINE_MUTEX(acpi_device_lock); 438c2ecf20Sopenharmony_ciLIST_HEAD(acpi_wakeup_device_list); 448c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(acpi_hp_context_lock); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* 478c2ecf20Sopenharmony_ci * The UART device described by the SPCR table is the only object which needs 488c2ecf20Sopenharmony_ci * special-casing. Everything else is covered by ACPI namespace paths in STAO 498c2ecf20Sopenharmony_ci * table. 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_cistatic u64 spcr_uart_addr; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistruct acpi_dep_data { 548c2ecf20Sopenharmony_ci struct list_head node; 558c2ecf20Sopenharmony_ci acpi_handle master; 568c2ecf20Sopenharmony_ci acpi_handle slave; 578c2ecf20Sopenharmony_ci}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_civoid acpi_scan_lock_acquire(void) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci mutex_lock(&acpi_scan_lock); 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_scan_lock_acquire); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_civoid acpi_scan_lock_release(void) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci mutex_unlock(&acpi_scan_lock); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_scan_lock_release); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_civoid acpi_lock_hp_context(void) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci mutex_lock(&acpi_hp_context_lock); 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_civoid acpi_unlock_hp_context(void) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci mutex_unlock(&acpi_hp_context_lock); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_civoid acpi_initialize_hp_context(struct acpi_device *adev, 828c2ecf20Sopenharmony_ci struct acpi_hotplug_context *hp, 838c2ecf20Sopenharmony_ci int (*notify)(struct acpi_device *, u32), 848c2ecf20Sopenharmony_ci void (*uevent)(struct acpi_device *, u32)) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci acpi_lock_hp_context(); 878c2ecf20Sopenharmony_ci hp->notify = notify; 888c2ecf20Sopenharmony_ci hp->uevent = uevent; 898c2ecf20Sopenharmony_ci acpi_set_hp_context(adev, hp); 908c2ecf20Sopenharmony_ci acpi_unlock_hp_context(); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_initialize_hp_context); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ciint acpi_scan_add_handler(struct acpi_scan_handler *handler) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci if (!handler) 978c2ecf20Sopenharmony_ci return -EINVAL; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci list_add_tail(&handler->list_node, &acpi_scan_handlers_list); 1008c2ecf20Sopenharmony_ci return 0; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ciint acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler, 1048c2ecf20Sopenharmony_ci const char *hotplug_profile_name) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci int error; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci error = acpi_scan_add_handler(handler); 1098c2ecf20Sopenharmony_ci if (error) 1108c2ecf20Sopenharmony_ci return error; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci acpi_sysfs_add_hotplug_profile(&handler->hotplug, hotplug_profile_name); 1138c2ecf20Sopenharmony_ci return 0; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cibool acpi_scan_is_offline(struct acpi_device *adev, bool uevent) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct acpi_device_physical_node *pn; 1198c2ecf20Sopenharmony_ci bool offline = true; 1208c2ecf20Sopenharmony_ci char *envp[] = { "EVENT=offline", NULL }; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /* 1238c2ecf20Sopenharmony_ci * acpi_container_offline() calls this for all of the container's 1248c2ecf20Sopenharmony_ci * children under the container's physical_node_lock lock. 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_ci mutex_lock_nested(&adev->physical_node_lock, SINGLE_DEPTH_NESTING); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci list_for_each_entry(pn, &adev->physical_node_list, node) 1298c2ecf20Sopenharmony_ci if (device_supports_offline(pn->dev) && !pn->dev->offline) { 1308c2ecf20Sopenharmony_ci if (uevent) 1318c2ecf20Sopenharmony_ci kobject_uevent_env(&pn->dev->kobj, KOBJ_CHANGE, envp); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci offline = false; 1348c2ecf20Sopenharmony_ci break; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci mutex_unlock(&adev->physical_node_lock); 1388c2ecf20Sopenharmony_ci return offline; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic acpi_status acpi_bus_offline(acpi_handle handle, u32 lvl, void *data, 1428c2ecf20Sopenharmony_ci void **ret_p) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci struct acpi_device *device = NULL; 1458c2ecf20Sopenharmony_ci struct acpi_device_physical_node *pn; 1468c2ecf20Sopenharmony_ci bool second_pass = (bool)data; 1478c2ecf20Sopenharmony_ci acpi_status status = AE_OK; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (acpi_bus_get_device(handle, &device)) 1508c2ecf20Sopenharmony_ci return AE_OK; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (device->handler && !device->handler->hotplug.enabled) { 1538c2ecf20Sopenharmony_ci *ret_p = &device->dev; 1548c2ecf20Sopenharmony_ci return AE_SUPPORT; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci mutex_lock(&device->physical_node_lock); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci list_for_each_entry(pn, &device->physical_node_list, node) { 1608c2ecf20Sopenharmony_ci int ret; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (second_pass) { 1638c2ecf20Sopenharmony_ci /* Skip devices offlined by the first pass. */ 1648c2ecf20Sopenharmony_ci if (pn->put_online) 1658c2ecf20Sopenharmony_ci continue; 1668c2ecf20Sopenharmony_ci } else { 1678c2ecf20Sopenharmony_ci pn->put_online = false; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci ret = device_offline(pn->dev); 1708c2ecf20Sopenharmony_ci if (ret >= 0) { 1718c2ecf20Sopenharmony_ci pn->put_online = !ret; 1728c2ecf20Sopenharmony_ci } else { 1738c2ecf20Sopenharmony_ci *ret_p = pn->dev; 1748c2ecf20Sopenharmony_ci if (second_pass) { 1758c2ecf20Sopenharmony_ci status = AE_ERROR; 1768c2ecf20Sopenharmony_ci break; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci mutex_unlock(&device->physical_node_lock); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci return status; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic acpi_status acpi_bus_online(acpi_handle handle, u32 lvl, void *data, 1878c2ecf20Sopenharmony_ci void **ret_p) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci struct acpi_device *device = NULL; 1908c2ecf20Sopenharmony_ci struct acpi_device_physical_node *pn; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (acpi_bus_get_device(handle, &device)) 1938c2ecf20Sopenharmony_ci return AE_OK; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci mutex_lock(&device->physical_node_lock); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci list_for_each_entry(pn, &device->physical_node_list, node) 1988c2ecf20Sopenharmony_ci if (pn->put_online) { 1998c2ecf20Sopenharmony_ci device_online(pn->dev); 2008c2ecf20Sopenharmony_ci pn->put_online = false; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci mutex_unlock(&device->physical_node_lock); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci return AE_OK; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic int acpi_scan_try_to_offline(struct acpi_device *device) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci acpi_handle handle = device->handle; 2118c2ecf20Sopenharmony_ci struct device *errdev = NULL; 2128c2ecf20Sopenharmony_ci acpi_status status; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci /* 2158c2ecf20Sopenharmony_ci * Carry out two passes here and ignore errors in the first pass, 2168c2ecf20Sopenharmony_ci * because if the devices in question are memory blocks and 2178c2ecf20Sopenharmony_ci * CONFIG_MEMCG is set, one of the blocks may hold data structures 2188c2ecf20Sopenharmony_ci * that the other blocks depend on, but it is not known in advance which 2198c2ecf20Sopenharmony_ci * block holds them. 2208c2ecf20Sopenharmony_ci * 2218c2ecf20Sopenharmony_ci * If the first pass is successful, the second one isn't needed, though. 2228c2ecf20Sopenharmony_ci */ 2238c2ecf20Sopenharmony_ci status = acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, 2248c2ecf20Sopenharmony_ci NULL, acpi_bus_offline, (void *)false, 2258c2ecf20Sopenharmony_ci (void **)&errdev); 2268c2ecf20Sopenharmony_ci if (status == AE_SUPPORT) { 2278c2ecf20Sopenharmony_ci dev_warn(errdev, "Offline disabled.\n"); 2288c2ecf20Sopenharmony_ci acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, 2298c2ecf20Sopenharmony_ci acpi_bus_online, NULL, NULL, NULL); 2308c2ecf20Sopenharmony_ci return -EPERM; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci acpi_bus_offline(handle, 0, (void *)false, (void **)&errdev); 2338c2ecf20Sopenharmony_ci if (errdev) { 2348c2ecf20Sopenharmony_ci errdev = NULL; 2358c2ecf20Sopenharmony_ci acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, 2368c2ecf20Sopenharmony_ci NULL, acpi_bus_offline, (void *)true, 2378c2ecf20Sopenharmony_ci (void **)&errdev); 2388c2ecf20Sopenharmony_ci if (!errdev) 2398c2ecf20Sopenharmony_ci acpi_bus_offline(handle, 0, (void *)true, 2408c2ecf20Sopenharmony_ci (void **)&errdev); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (errdev) { 2438c2ecf20Sopenharmony_ci dev_warn(errdev, "Offline failed.\n"); 2448c2ecf20Sopenharmony_ci acpi_bus_online(handle, 0, NULL, NULL); 2458c2ecf20Sopenharmony_ci acpi_walk_namespace(ACPI_TYPE_ANY, handle, 2468c2ecf20Sopenharmony_ci ACPI_UINT32_MAX, acpi_bus_online, 2478c2ecf20Sopenharmony_ci NULL, NULL, NULL); 2488c2ecf20Sopenharmony_ci return -EBUSY; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci return 0; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic int acpi_scan_hot_remove(struct acpi_device *device) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci acpi_handle handle = device->handle; 2578c2ecf20Sopenharmony_ci unsigned long long sta; 2588c2ecf20Sopenharmony_ci acpi_status status; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if (device->handler && device->handler->hotplug.demand_offline) { 2618c2ecf20Sopenharmony_ci if (!acpi_scan_is_offline(device, true)) 2628c2ecf20Sopenharmony_ci return -EBUSY; 2638c2ecf20Sopenharmony_ci } else { 2648c2ecf20Sopenharmony_ci int error = acpi_scan_try_to_offline(device); 2658c2ecf20Sopenharmony_ci if (error) 2668c2ecf20Sopenharmony_ci return error; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_INFO, 2708c2ecf20Sopenharmony_ci "Hot-removing device %s...\n", dev_name(&device->dev))); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci acpi_bus_trim(device); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci acpi_evaluate_lck(handle, 0); 2758c2ecf20Sopenharmony_ci /* 2768c2ecf20Sopenharmony_ci * TBD: _EJD support. 2778c2ecf20Sopenharmony_ci */ 2788c2ecf20Sopenharmony_ci status = acpi_evaluate_ej0(handle); 2798c2ecf20Sopenharmony_ci if (status == AE_NOT_FOUND) 2808c2ecf20Sopenharmony_ci return -ENODEV; 2818c2ecf20Sopenharmony_ci else if (ACPI_FAILURE(status)) 2828c2ecf20Sopenharmony_ci return -EIO; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* 2858c2ecf20Sopenharmony_ci * Verify if eject was indeed successful. If not, log an error 2868c2ecf20Sopenharmony_ci * message. No need to call _OST since _EJ0 call was made OK. 2878c2ecf20Sopenharmony_ci */ 2888c2ecf20Sopenharmony_ci status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); 2898c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 2908c2ecf20Sopenharmony_ci acpi_handle_warn(handle, 2918c2ecf20Sopenharmony_ci "Status check after eject failed (0x%x)\n", status); 2928c2ecf20Sopenharmony_ci } else if (sta & ACPI_STA_DEVICE_ENABLED) { 2938c2ecf20Sopenharmony_ci acpi_handle_warn(handle, 2948c2ecf20Sopenharmony_ci "Eject incomplete - status 0x%llx\n", sta); 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci return 0; 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic int acpi_scan_device_not_present(struct acpi_device *adev) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci if (!acpi_device_enumerated(adev)) { 3038c2ecf20Sopenharmony_ci dev_warn(&adev->dev, "Still not present\n"); 3048c2ecf20Sopenharmony_ci return -EALREADY; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci acpi_bus_trim(adev); 3078c2ecf20Sopenharmony_ci return 0; 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_cistatic int acpi_scan_device_check(struct acpi_device *adev) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci int error; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci acpi_bus_get_status(adev); 3158c2ecf20Sopenharmony_ci if (adev->status.present || adev->status.functional) { 3168c2ecf20Sopenharmony_ci /* 3178c2ecf20Sopenharmony_ci * This function is only called for device objects for which 3188c2ecf20Sopenharmony_ci * matching scan handlers exist. The only situation in which 3198c2ecf20Sopenharmony_ci * the scan handler is not attached to this device object yet 3208c2ecf20Sopenharmony_ci * is when the device has just appeared (either it wasn't 3218c2ecf20Sopenharmony_ci * present at all before or it was removed and then added 3228c2ecf20Sopenharmony_ci * again). 3238c2ecf20Sopenharmony_ci */ 3248c2ecf20Sopenharmony_ci if (adev->handler) { 3258c2ecf20Sopenharmony_ci dev_warn(&adev->dev, "Already enumerated\n"); 3268c2ecf20Sopenharmony_ci return -EALREADY; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci error = acpi_bus_scan(adev->handle); 3298c2ecf20Sopenharmony_ci if (error) { 3308c2ecf20Sopenharmony_ci dev_warn(&adev->dev, "Namespace scan failure\n"); 3318c2ecf20Sopenharmony_ci return error; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci if (!adev->handler) { 3348c2ecf20Sopenharmony_ci dev_warn(&adev->dev, "Enumeration failure\n"); 3358c2ecf20Sopenharmony_ci error = -ENODEV; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci } else { 3388c2ecf20Sopenharmony_ci error = acpi_scan_device_not_present(adev); 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci return error; 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cistatic int acpi_scan_bus_check(struct acpi_device *adev) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci struct acpi_scan_handler *handler = adev->handler; 3468c2ecf20Sopenharmony_ci struct acpi_device *child; 3478c2ecf20Sopenharmony_ci int error; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci acpi_bus_get_status(adev); 3508c2ecf20Sopenharmony_ci if (!(adev->status.present || adev->status.functional)) { 3518c2ecf20Sopenharmony_ci acpi_scan_device_not_present(adev); 3528c2ecf20Sopenharmony_ci return 0; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci if (handler && handler->hotplug.scan_dependent) 3558c2ecf20Sopenharmony_ci return handler->hotplug.scan_dependent(adev); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci error = acpi_bus_scan(adev->handle); 3588c2ecf20Sopenharmony_ci if (error) { 3598c2ecf20Sopenharmony_ci dev_warn(&adev->dev, "Namespace scan failure\n"); 3608c2ecf20Sopenharmony_ci return error; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci list_for_each_entry(child, &adev->children, node) { 3638c2ecf20Sopenharmony_ci error = acpi_scan_bus_check(child); 3648c2ecf20Sopenharmony_ci if (error) 3658c2ecf20Sopenharmony_ci return error; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci return 0; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci switch (type) { 3738c2ecf20Sopenharmony_ci case ACPI_NOTIFY_BUS_CHECK: 3748c2ecf20Sopenharmony_ci return acpi_scan_bus_check(adev); 3758c2ecf20Sopenharmony_ci case ACPI_NOTIFY_DEVICE_CHECK: 3768c2ecf20Sopenharmony_ci return acpi_scan_device_check(adev); 3778c2ecf20Sopenharmony_ci case ACPI_NOTIFY_EJECT_REQUEST: 3788c2ecf20Sopenharmony_ci case ACPI_OST_EC_OSPM_EJECT: 3798c2ecf20Sopenharmony_ci if (adev->handler && !adev->handler->hotplug.enabled) { 3808c2ecf20Sopenharmony_ci dev_info(&adev->dev, "Eject disabled\n"); 3818c2ecf20Sopenharmony_ci return -EPERM; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci acpi_evaluate_ost(adev->handle, ACPI_NOTIFY_EJECT_REQUEST, 3848c2ecf20Sopenharmony_ci ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); 3858c2ecf20Sopenharmony_ci return acpi_scan_hot_remove(adev); 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci return -EINVAL; 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_civoid acpi_device_hotplug(struct acpi_device *adev, u32 src) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; 3938c2ecf20Sopenharmony_ci int error = -ENODEV; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci lock_device_hotplug(); 3968c2ecf20Sopenharmony_ci mutex_lock(&acpi_scan_lock); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci /* 3998c2ecf20Sopenharmony_ci * The device object's ACPI handle cannot become invalid as long as we 4008c2ecf20Sopenharmony_ci * are holding acpi_scan_lock, but it might have become invalid before 4018c2ecf20Sopenharmony_ci * that lock was acquired. 4028c2ecf20Sopenharmony_ci */ 4038c2ecf20Sopenharmony_ci if (adev->handle == INVALID_ACPI_HANDLE) 4048c2ecf20Sopenharmony_ci goto err_out; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci if (adev->flags.is_dock_station) { 4078c2ecf20Sopenharmony_ci error = dock_notify(adev, src); 4088c2ecf20Sopenharmony_ci } else if (adev->flags.hotplug_notify) { 4098c2ecf20Sopenharmony_ci error = acpi_generic_hotplug_event(adev, src); 4108c2ecf20Sopenharmony_ci } else { 4118c2ecf20Sopenharmony_ci int (*notify)(struct acpi_device *, u32); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci acpi_lock_hp_context(); 4148c2ecf20Sopenharmony_ci notify = adev->hp ? adev->hp->notify : NULL; 4158c2ecf20Sopenharmony_ci acpi_unlock_hp_context(); 4168c2ecf20Sopenharmony_ci /* 4178c2ecf20Sopenharmony_ci * There may be additional notify handlers for device objects 4188c2ecf20Sopenharmony_ci * without the .event() callback, so ignore them here. 4198c2ecf20Sopenharmony_ci */ 4208c2ecf20Sopenharmony_ci if (notify) 4218c2ecf20Sopenharmony_ci error = notify(adev, src); 4228c2ecf20Sopenharmony_ci else 4238c2ecf20Sopenharmony_ci goto out; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci switch (error) { 4268c2ecf20Sopenharmony_ci case 0: 4278c2ecf20Sopenharmony_ci ost_code = ACPI_OST_SC_SUCCESS; 4288c2ecf20Sopenharmony_ci break; 4298c2ecf20Sopenharmony_ci case -EPERM: 4308c2ecf20Sopenharmony_ci ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; 4318c2ecf20Sopenharmony_ci break; 4328c2ecf20Sopenharmony_ci case -EBUSY: 4338c2ecf20Sopenharmony_ci ost_code = ACPI_OST_SC_DEVICE_BUSY; 4348c2ecf20Sopenharmony_ci break; 4358c2ecf20Sopenharmony_ci default: 4368c2ecf20Sopenharmony_ci ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; 4378c2ecf20Sopenharmony_ci break; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci err_out: 4418c2ecf20Sopenharmony_ci acpi_evaluate_ost(adev->handle, src, ost_code, NULL); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci out: 4448c2ecf20Sopenharmony_ci acpi_bus_put_acpi_device(adev); 4458c2ecf20Sopenharmony_ci mutex_unlock(&acpi_scan_lock); 4468c2ecf20Sopenharmony_ci unlock_device_hotplug(); 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic void acpi_free_power_resources_lists(struct acpi_device *device) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci int i; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (device->wakeup.flags.valid) 4548c2ecf20Sopenharmony_ci acpi_power_resources_list_free(&device->wakeup.resources); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (!device->power.flags.power_resources) 4578c2ecf20Sopenharmony_ci return; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) { 4608c2ecf20Sopenharmony_ci struct acpi_device_power_state *ps = &device->power.states[i]; 4618c2ecf20Sopenharmony_ci acpi_power_resources_list_free(&ps->resources); 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic void acpi_device_release(struct device *dev) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci struct acpi_device *acpi_dev = to_acpi_device(dev); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci acpi_free_properties(acpi_dev); 4708c2ecf20Sopenharmony_ci acpi_free_pnp_ids(&acpi_dev->pnp); 4718c2ecf20Sopenharmony_ci acpi_free_power_resources_lists(acpi_dev); 4728c2ecf20Sopenharmony_ci kfree(acpi_dev); 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cistatic void acpi_device_del(struct acpi_device *device) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci struct acpi_device_bus_id *acpi_device_bus_id; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci mutex_lock(&acpi_device_lock); 4808c2ecf20Sopenharmony_ci if (device->parent) 4818c2ecf20Sopenharmony_ci list_del(&device->node); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) 4848c2ecf20Sopenharmony_ci if (!strcmp(acpi_device_bus_id->bus_id, 4858c2ecf20Sopenharmony_ci acpi_device_hid(device))) { 4868c2ecf20Sopenharmony_ci ida_simple_remove(&acpi_device_bus_id->instance_ida, device->pnp.instance_no); 4878c2ecf20Sopenharmony_ci if (ida_is_empty(&acpi_device_bus_id->instance_ida)) { 4888c2ecf20Sopenharmony_ci list_del(&acpi_device_bus_id->node); 4898c2ecf20Sopenharmony_ci kfree_const(acpi_device_bus_id->bus_id); 4908c2ecf20Sopenharmony_ci kfree(acpi_device_bus_id); 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci break; 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci list_del(&device->wakeup_list); 4968c2ecf20Sopenharmony_ci mutex_unlock(&acpi_device_lock); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci acpi_power_add_remove_device(device, false); 4998c2ecf20Sopenharmony_ci acpi_device_remove_files(device); 5008c2ecf20Sopenharmony_ci if (device->remove) 5018c2ecf20Sopenharmony_ci device->remove(device); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci device_del(&device->dev); 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cistatic BLOCKING_NOTIFIER_HEAD(acpi_reconfig_chain); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_cistatic LIST_HEAD(acpi_device_del_list); 5098c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(acpi_device_del_lock); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_cistatic void acpi_device_del_work_fn(struct work_struct *work_not_used) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci for (;;) { 5148c2ecf20Sopenharmony_ci struct acpi_device *adev; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci mutex_lock(&acpi_device_del_lock); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci if (list_empty(&acpi_device_del_list)) { 5198c2ecf20Sopenharmony_ci mutex_unlock(&acpi_device_del_lock); 5208c2ecf20Sopenharmony_ci break; 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci adev = list_first_entry(&acpi_device_del_list, 5238c2ecf20Sopenharmony_ci struct acpi_device, del_list); 5248c2ecf20Sopenharmony_ci list_del(&adev->del_list); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci mutex_unlock(&acpi_device_del_lock); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci blocking_notifier_call_chain(&acpi_reconfig_chain, 5298c2ecf20Sopenharmony_ci ACPI_RECONFIG_DEVICE_REMOVE, adev); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci acpi_device_del(adev); 5328c2ecf20Sopenharmony_ci /* 5338c2ecf20Sopenharmony_ci * Drop references to all power resources that might have been 5348c2ecf20Sopenharmony_ci * used by the device. 5358c2ecf20Sopenharmony_ci */ 5368c2ecf20Sopenharmony_ci acpi_power_transition(adev, ACPI_STATE_D3_COLD); 5378c2ecf20Sopenharmony_ci put_device(&adev->dev); 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci/** 5428c2ecf20Sopenharmony_ci * acpi_scan_drop_device - Drop an ACPI device object. 5438c2ecf20Sopenharmony_ci * @handle: Handle of an ACPI namespace node, not used. 5448c2ecf20Sopenharmony_ci * @context: Address of the ACPI device object to drop. 5458c2ecf20Sopenharmony_ci * 5468c2ecf20Sopenharmony_ci * This is invoked by acpi_ns_delete_node() during the removal of the ACPI 5478c2ecf20Sopenharmony_ci * namespace node the device object pointed to by @context is attached to. 5488c2ecf20Sopenharmony_ci * 5498c2ecf20Sopenharmony_ci * The unregistration is carried out asynchronously to avoid running 5508c2ecf20Sopenharmony_ci * acpi_device_del() under the ACPICA's namespace mutex and the list is used to 5518c2ecf20Sopenharmony_ci * ensure the correct ordering (the device objects must be unregistered in the 5528c2ecf20Sopenharmony_ci * same order in which the corresponding namespace nodes are deleted). 5538c2ecf20Sopenharmony_ci */ 5548c2ecf20Sopenharmony_cistatic void acpi_scan_drop_device(acpi_handle handle, void *context) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci static DECLARE_WORK(work, acpi_device_del_work_fn); 5578c2ecf20Sopenharmony_ci struct acpi_device *adev = context; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci mutex_lock(&acpi_device_del_lock); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci /* 5628c2ecf20Sopenharmony_ci * Use the ACPI hotplug workqueue which is ordered, so this work item 5638c2ecf20Sopenharmony_ci * won't run after any hotplug work items submitted subsequently. That 5648c2ecf20Sopenharmony_ci * prevents attempts to register device objects identical to those being 5658c2ecf20Sopenharmony_ci * deleted from happening concurrently (such attempts result from 5668c2ecf20Sopenharmony_ci * hotplug events handled via the ACPI hotplug workqueue). It also will 5678c2ecf20Sopenharmony_ci * run after all of the work items submitted previosuly, which helps 5688c2ecf20Sopenharmony_ci * those work items to ensure that they are not accessing stale device 5698c2ecf20Sopenharmony_ci * objects. 5708c2ecf20Sopenharmony_ci */ 5718c2ecf20Sopenharmony_ci if (list_empty(&acpi_device_del_list)) 5728c2ecf20Sopenharmony_ci acpi_queue_hotplug_work(&work); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci list_add_tail(&adev->del_list, &acpi_device_del_list); 5758c2ecf20Sopenharmony_ci /* Make acpi_ns_validate_handle() return NULL for this handle. */ 5768c2ecf20Sopenharmony_ci adev->handle = INVALID_ACPI_HANDLE; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci mutex_unlock(&acpi_device_del_lock); 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_cistatic int acpi_get_device_data(acpi_handle handle, struct acpi_device **device, 5828c2ecf20Sopenharmony_ci void (*callback)(void *)) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci acpi_status status; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (!device) 5878c2ecf20Sopenharmony_ci return -EINVAL; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci *device = NULL; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci status = acpi_get_data_full(handle, acpi_scan_drop_device, 5928c2ecf20Sopenharmony_ci (void **)device, callback); 5938c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status) || !*device) { 5948c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n", 5958c2ecf20Sopenharmony_ci handle)); 5968c2ecf20Sopenharmony_ci return -ENODEV; 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci return 0; 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ciint acpi_bus_get_device(acpi_handle handle, struct acpi_device **device) 6028c2ecf20Sopenharmony_ci{ 6038c2ecf20Sopenharmony_ci return acpi_get_device_data(handle, device, NULL); 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_bus_get_device); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic void get_acpi_device(void *dev) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci if (dev) 6108c2ecf20Sopenharmony_ci get_device(&((struct acpi_device *)dev)->dev); 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_cistruct acpi_device *acpi_bus_get_acpi_device(acpi_handle handle) 6148c2ecf20Sopenharmony_ci{ 6158c2ecf20Sopenharmony_ci struct acpi_device *adev = NULL; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci acpi_get_device_data(handle, &adev, get_acpi_device); 6188c2ecf20Sopenharmony_ci return adev; 6198c2ecf20Sopenharmony_ci} 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_civoid acpi_bus_put_acpi_device(struct acpi_device *adev) 6228c2ecf20Sopenharmony_ci{ 6238c2ecf20Sopenharmony_ci put_device(&adev->dev); 6248c2ecf20Sopenharmony_ci} 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_cistatic struct acpi_device_bus_id *acpi_device_bus_id_match(const char *dev_id) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci struct acpi_device_bus_id *acpi_device_bus_id; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci /* Find suitable bus_id and instance number in acpi_bus_id_list. */ 6318c2ecf20Sopenharmony_ci list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) { 6328c2ecf20Sopenharmony_ci if (!strcmp(acpi_device_bus_id->bus_id, dev_id)) 6338c2ecf20Sopenharmony_ci return acpi_device_bus_id; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci return NULL; 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_cistatic int acpi_device_set_name(struct acpi_device *device, 6398c2ecf20Sopenharmony_ci struct acpi_device_bus_id *acpi_device_bus_id) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci struct ida *instance_ida = &acpi_device_bus_id->instance_ida; 6428c2ecf20Sopenharmony_ci int result; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci result = ida_simple_get(instance_ida, 0, ACPI_MAX_DEVICE_INSTANCES, GFP_KERNEL); 6458c2ecf20Sopenharmony_ci if (result < 0) 6468c2ecf20Sopenharmony_ci return result; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci device->pnp.instance_no = result; 6498c2ecf20Sopenharmony_ci dev_set_name(&device->dev, "%s:%02x", acpi_device_bus_id->bus_id, result); 6508c2ecf20Sopenharmony_ci return 0; 6518c2ecf20Sopenharmony_ci} 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ciint acpi_device_add(struct acpi_device *device, 6548c2ecf20Sopenharmony_ci void (*release)(struct device *)) 6558c2ecf20Sopenharmony_ci{ 6568c2ecf20Sopenharmony_ci struct acpi_device_bus_id *acpi_device_bus_id; 6578c2ecf20Sopenharmony_ci int result; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci if (device->handle) { 6608c2ecf20Sopenharmony_ci acpi_status status; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci status = acpi_attach_data(device->handle, acpi_scan_drop_device, 6638c2ecf20Sopenharmony_ci device); 6648c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 6658c2ecf20Sopenharmony_ci acpi_handle_err(device->handle, 6668c2ecf20Sopenharmony_ci "Unable to attach device data\n"); 6678c2ecf20Sopenharmony_ci return -ENODEV; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci /* 6728c2ecf20Sopenharmony_ci * Linkage 6738c2ecf20Sopenharmony_ci * ------- 6748c2ecf20Sopenharmony_ci * Link this device to its parent and siblings. 6758c2ecf20Sopenharmony_ci */ 6768c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&device->children); 6778c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&device->node); 6788c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&device->wakeup_list); 6798c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&device->physical_node_list); 6808c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&device->del_list); 6818c2ecf20Sopenharmony_ci mutex_init(&device->physical_node_lock); 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci mutex_lock(&acpi_device_lock); 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci acpi_device_bus_id = acpi_device_bus_id_match(acpi_device_hid(device)); 6868c2ecf20Sopenharmony_ci if (acpi_device_bus_id) { 6878c2ecf20Sopenharmony_ci result = acpi_device_set_name(device, acpi_device_bus_id); 6888c2ecf20Sopenharmony_ci if (result) 6898c2ecf20Sopenharmony_ci goto err_unlock; 6908c2ecf20Sopenharmony_ci } else { 6918c2ecf20Sopenharmony_ci acpi_device_bus_id = kzalloc(sizeof(*acpi_device_bus_id), 6928c2ecf20Sopenharmony_ci GFP_KERNEL); 6938c2ecf20Sopenharmony_ci if (!acpi_device_bus_id) { 6948c2ecf20Sopenharmony_ci result = -ENOMEM; 6958c2ecf20Sopenharmony_ci goto err_unlock; 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci acpi_device_bus_id->bus_id = 6988c2ecf20Sopenharmony_ci kstrdup_const(acpi_device_hid(device), GFP_KERNEL); 6998c2ecf20Sopenharmony_ci if (!acpi_device_bus_id->bus_id) { 7008c2ecf20Sopenharmony_ci kfree(acpi_device_bus_id); 7018c2ecf20Sopenharmony_ci result = -ENOMEM; 7028c2ecf20Sopenharmony_ci goto err_unlock; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci ida_init(&acpi_device_bus_id->instance_ida); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci result = acpi_device_set_name(device, acpi_device_bus_id); 7088c2ecf20Sopenharmony_ci if (result) { 7098c2ecf20Sopenharmony_ci kfree_const(acpi_device_bus_id->bus_id); 7108c2ecf20Sopenharmony_ci kfree(acpi_device_bus_id); 7118c2ecf20Sopenharmony_ci goto err_unlock; 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list); 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci if (device->parent) 7188c2ecf20Sopenharmony_ci list_add_tail(&device->node, &device->parent->children); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci if (device->wakeup.flags.valid) 7218c2ecf20Sopenharmony_ci list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list); 7228c2ecf20Sopenharmony_ci mutex_unlock(&acpi_device_lock); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci if (device->parent) 7258c2ecf20Sopenharmony_ci device->dev.parent = &device->parent->dev; 7268c2ecf20Sopenharmony_ci device->dev.bus = &acpi_bus_type; 7278c2ecf20Sopenharmony_ci device->dev.release = release; 7288c2ecf20Sopenharmony_ci result = device_add(&device->dev); 7298c2ecf20Sopenharmony_ci if (result) { 7308c2ecf20Sopenharmony_ci dev_err(&device->dev, "Error registering device\n"); 7318c2ecf20Sopenharmony_ci goto err; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci result = acpi_device_setup_files(device); 7358c2ecf20Sopenharmony_ci if (result) 7368c2ecf20Sopenharmony_ci printk(KERN_ERR PREFIX "Error creating sysfs interface for device %s\n", 7378c2ecf20Sopenharmony_ci dev_name(&device->dev)); 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci return 0; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci err: 7428c2ecf20Sopenharmony_ci mutex_lock(&acpi_device_lock); 7438c2ecf20Sopenharmony_ci if (device->parent) 7448c2ecf20Sopenharmony_ci list_del(&device->node); 7458c2ecf20Sopenharmony_ci list_del(&device->wakeup_list); 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci err_unlock: 7488c2ecf20Sopenharmony_ci mutex_unlock(&acpi_device_lock); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci acpi_detach_data(device->handle, acpi_scan_drop_device); 7518c2ecf20Sopenharmony_ci return result; 7528c2ecf20Sopenharmony_ci} 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci/* -------------------------------------------------------------------------- 7558c2ecf20Sopenharmony_ci Device Enumeration 7568c2ecf20Sopenharmony_ci -------------------------------------------------------------------------- */ 7578c2ecf20Sopenharmony_cistatic struct acpi_device *acpi_bus_get_parent(acpi_handle handle) 7588c2ecf20Sopenharmony_ci{ 7598c2ecf20Sopenharmony_ci struct acpi_device *device = NULL; 7608c2ecf20Sopenharmony_ci acpi_status status; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci /* 7638c2ecf20Sopenharmony_ci * Fixed hardware devices do not appear in the namespace and do not 7648c2ecf20Sopenharmony_ci * have handles, but we fabricate acpi_devices for them, so we have 7658c2ecf20Sopenharmony_ci * to deal with them specially. 7668c2ecf20Sopenharmony_ci */ 7678c2ecf20Sopenharmony_ci if (!handle) 7688c2ecf20Sopenharmony_ci return acpi_root; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci do { 7718c2ecf20Sopenharmony_ci status = acpi_get_parent(handle, &handle); 7728c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 7738c2ecf20Sopenharmony_ci return status == AE_NULL_ENTRY ? NULL : acpi_root; 7748c2ecf20Sopenharmony_ci } while (acpi_bus_get_device(handle, &device)); 7758c2ecf20Sopenharmony_ci return device; 7768c2ecf20Sopenharmony_ci} 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ciacpi_status 7798c2ecf20Sopenharmony_ciacpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd) 7808c2ecf20Sopenharmony_ci{ 7818c2ecf20Sopenharmony_ci acpi_status status; 7828c2ecf20Sopenharmony_ci acpi_handle tmp; 7838c2ecf20Sopenharmony_ci struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; 7848c2ecf20Sopenharmony_ci union acpi_object *obj; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci status = acpi_get_handle(handle, "_EJD", &tmp); 7878c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 7888c2ecf20Sopenharmony_ci return status; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer); 7918c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(status)) { 7928c2ecf20Sopenharmony_ci obj = buffer.pointer; 7938c2ecf20Sopenharmony_ci status = acpi_get_handle(ACPI_ROOT_OBJECT, obj->string.pointer, 7948c2ecf20Sopenharmony_ci ejd); 7958c2ecf20Sopenharmony_ci kfree(buffer.pointer); 7968c2ecf20Sopenharmony_ci } 7978c2ecf20Sopenharmony_ci return status; 7988c2ecf20Sopenharmony_ci} 7998c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_bus_get_ejd); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_cistatic int acpi_bus_extract_wakeup_device_power_package(struct acpi_device *dev) 8028c2ecf20Sopenharmony_ci{ 8038c2ecf20Sopenharmony_ci acpi_handle handle = dev->handle; 8048c2ecf20Sopenharmony_ci struct acpi_device_wakeup *wakeup = &dev->wakeup; 8058c2ecf20Sopenharmony_ci struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 8068c2ecf20Sopenharmony_ci union acpi_object *package = NULL; 8078c2ecf20Sopenharmony_ci union acpi_object *element = NULL; 8088c2ecf20Sopenharmony_ci acpi_status status; 8098c2ecf20Sopenharmony_ci int err = -ENODATA; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&wakeup->resources); 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci /* _PRW */ 8148c2ecf20Sopenharmony_ci status = acpi_evaluate_object(handle, "_PRW", NULL, &buffer); 8158c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 8168c2ecf20Sopenharmony_ci ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW")); 8178c2ecf20Sopenharmony_ci return err; 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci package = (union acpi_object *)buffer.pointer; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci if (!package || package->package.count < 2) 8238c2ecf20Sopenharmony_ci goto out; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci element = &(package->package.elements[0]); 8268c2ecf20Sopenharmony_ci if (!element) 8278c2ecf20Sopenharmony_ci goto out; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci if (element->type == ACPI_TYPE_PACKAGE) { 8308c2ecf20Sopenharmony_ci if ((element->package.count < 2) || 8318c2ecf20Sopenharmony_ci (element->package.elements[0].type != 8328c2ecf20Sopenharmony_ci ACPI_TYPE_LOCAL_REFERENCE) 8338c2ecf20Sopenharmony_ci || (element->package.elements[1].type != ACPI_TYPE_INTEGER)) 8348c2ecf20Sopenharmony_ci goto out; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci wakeup->gpe_device = 8378c2ecf20Sopenharmony_ci element->package.elements[0].reference.handle; 8388c2ecf20Sopenharmony_ci wakeup->gpe_number = 8398c2ecf20Sopenharmony_ci (u32) element->package.elements[1].integer.value; 8408c2ecf20Sopenharmony_ci } else if (element->type == ACPI_TYPE_INTEGER) { 8418c2ecf20Sopenharmony_ci wakeup->gpe_device = NULL; 8428c2ecf20Sopenharmony_ci wakeup->gpe_number = element->integer.value; 8438c2ecf20Sopenharmony_ci } else { 8448c2ecf20Sopenharmony_ci goto out; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci element = &(package->package.elements[1]); 8488c2ecf20Sopenharmony_ci if (element->type != ACPI_TYPE_INTEGER) 8498c2ecf20Sopenharmony_ci goto out; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci wakeup->sleep_state = element->integer.value; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci err = acpi_extract_power_resources(package, 2, &wakeup->resources); 8548c2ecf20Sopenharmony_ci if (err) 8558c2ecf20Sopenharmony_ci goto out; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci if (!list_empty(&wakeup->resources)) { 8588c2ecf20Sopenharmony_ci int sleep_state; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci err = acpi_power_wakeup_list_init(&wakeup->resources, 8618c2ecf20Sopenharmony_ci &sleep_state); 8628c2ecf20Sopenharmony_ci if (err) { 8638c2ecf20Sopenharmony_ci acpi_handle_warn(handle, "Retrieving current states " 8648c2ecf20Sopenharmony_ci "of wakeup power resources failed\n"); 8658c2ecf20Sopenharmony_ci acpi_power_resources_list_free(&wakeup->resources); 8668c2ecf20Sopenharmony_ci goto out; 8678c2ecf20Sopenharmony_ci } 8688c2ecf20Sopenharmony_ci if (sleep_state < wakeup->sleep_state) { 8698c2ecf20Sopenharmony_ci acpi_handle_warn(handle, "Overriding _PRW sleep state " 8708c2ecf20Sopenharmony_ci "(S%d) by S%d from power resources\n", 8718c2ecf20Sopenharmony_ci (int)wakeup->sleep_state, sleep_state); 8728c2ecf20Sopenharmony_ci wakeup->sleep_state = sleep_state; 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci out: 8778c2ecf20Sopenharmony_ci kfree(buffer.pointer); 8788c2ecf20Sopenharmony_ci return err; 8798c2ecf20Sopenharmony_ci} 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_cistatic bool acpi_wakeup_gpe_init(struct acpi_device *device) 8828c2ecf20Sopenharmony_ci{ 8838c2ecf20Sopenharmony_ci static const struct acpi_device_id button_device_ids[] = { 8848c2ecf20Sopenharmony_ci {"PNP0C0C", 0}, /* Power button */ 8858c2ecf20Sopenharmony_ci {"PNP0C0D", 0}, /* Lid */ 8868c2ecf20Sopenharmony_ci {"PNP0C0E", 0}, /* Sleep button */ 8878c2ecf20Sopenharmony_ci {"", 0}, 8888c2ecf20Sopenharmony_ci }; 8898c2ecf20Sopenharmony_ci struct acpi_device_wakeup *wakeup = &device->wakeup; 8908c2ecf20Sopenharmony_ci acpi_status status; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci wakeup->flags.notifier_present = 0; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci /* Power button, Lid switch always enable wakeup */ 8958c2ecf20Sopenharmony_ci if (!acpi_match_device_ids(device, button_device_ids)) { 8968c2ecf20Sopenharmony_ci if (!acpi_match_device_ids(device, &button_device_ids[1])) { 8978c2ecf20Sopenharmony_ci /* Do not use Lid/sleep button for S5 wakeup */ 8988c2ecf20Sopenharmony_ci if (wakeup->sleep_state == ACPI_STATE_S5) 8998c2ecf20Sopenharmony_ci wakeup->sleep_state = ACPI_STATE_S4; 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci acpi_mark_gpe_for_wake(wakeup->gpe_device, wakeup->gpe_number); 9028c2ecf20Sopenharmony_ci device_set_wakeup_capable(&device->dev, true); 9038c2ecf20Sopenharmony_ci return true; 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci status = acpi_setup_gpe_for_wake(device->handle, wakeup->gpe_device, 9078c2ecf20Sopenharmony_ci wakeup->gpe_number); 9088c2ecf20Sopenharmony_ci return ACPI_SUCCESS(status); 9098c2ecf20Sopenharmony_ci} 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_cistatic void acpi_bus_get_wakeup_device_flags(struct acpi_device *device) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci int err; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci /* Presence of _PRW indicates wake capable */ 9168c2ecf20Sopenharmony_ci if (!acpi_has_method(device->handle, "_PRW")) 9178c2ecf20Sopenharmony_ci return; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci err = acpi_bus_extract_wakeup_device_power_package(device); 9208c2ecf20Sopenharmony_ci if (err) { 9218c2ecf20Sopenharmony_ci dev_err(&device->dev, "_PRW evaluation error: %d\n", err); 9228c2ecf20Sopenharmony_ci return; 9238c2ecf20Sopenharmony_ci } 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci device->wakeup.flags.valid = acpi_wakeup_gpe_init(device); 9268c2ecf20Sopenharmony_ci device->wakeup.prepare_count = 0; 9278c2ecf20Sopenharmony_ci /* 9288c2ecf20Sopenharmony_ci * Call _PSW/_DSW object to disable its ability to wake the sleeping 9298c2ecf20Sopenharmony_ci * system for the ACPI device with the _PRW object. 9308c2ecf20Sopenharmony_ci * The _PSW object is deprecated in ACPI 3.0 and is replaced by _DSW. 9318c2ecf20Sopenharmony_ci * So it is necessary to call _DSW object first. Only when it is not 9328c2ecf20Sopenharmony_ci * present will the _PSW object used. 9338c2ecf20Sopenharmony_ci */ 9348c2ecf20Sopenharmony_ci err = acpi_device_sleep_wake(device, 0, 0, 0); 9358c2ecf20Sopenharmony_ci if (err) 9368c2ecf20Sopenharmony_ci pr_debug("error in _DSW or _PSW evaluation\n"); 9378c2ecf20Sopenharmony_ci} 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_cistatic void acpi_bus_init_power_state(struct acpi_device *device, int state) 9408c2ecf20Sopenharmony_ci{ 9418c2ecf20Sopenharmony_ci struct acpi_device_power_state *ps = &device->power.states[state]; 9428c2ecf20Sopenharmony_ci char pathname[5] = { '_', 'P', 'R', '0' + state, '\0' }; 9438c2ecf20Sopenharmony_ci struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 9448c2ecf20Sopenharmony_ci acpi_status status; 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ps->resources); 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci /* Evaluate "_PRx" to get referenced power resources */ 9498c2ecf20Sopenharmony_ci status = acpi_evaluate_object(device->handle, pathname, NULL, &buffer); 9508c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(status)) { 9518c2ecf20Sopenharmony_ci union acpi_object *package = buffer.pointer; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci if (buffer.length && package 9548c2ecf20Sopenharmony_ci && package->type == ACPI_TYPE_PACKAGE 9558c2ecf20Sopenharmony_ci && package->package.count) 9568c2ecf20Sopenharmony_ci acpi_extract_power_resources(package, 0, &ps->resources); 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci ACPI_FREE(buffer.pointer); 9598c2ecf20Sopenharmony_ci } 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci /* Evaluate "_PSx" to see if we can do explicit sets */ 9628c2ecf20Sopenharmony_ci pathname[2] = 'S'; 9638c2ecf20Sopenharmony_ci if (acpi_has_method(device->handle, pathname)) 9648c2ecf20Sopenharmony_ci ps->flags.explicit_set = 1; 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci /* State is valid if there are means to put the device into it. */ 9678c2ecf20Sopenharmony_ci if (!list_empty(&ps->resources) || ps->flags.explicit_set) 9688c2ecf20Sopenharmony_ci ps->flags.valid = 1; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci ps->power = -1; /* Unknown - driver assigned */ 9718c2ecf20Sopenharmony_ci ps->latency = -1; /* Unknown - driver assigned */ 9728c2ecf20Sopenharmony_ci} 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_cistatic void acpi_bus_get_power_flags(struct acpi_device *device) 9758c2ecf20Sopenharmony_ci{ 9768c2ecf20Sopenharmony_ci u32 i; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci /* Presence of _PS0|_PR0 indicates 'power manageable' */ 9798c2ecf20Sopenharmony_ci if (!acpi_has_method(device->handle, "_PS0") && 9808c2ecf20Sopenharmony_ci !acpi_has_method(device->handle, "_PR0")) 9818c2ecf20Sopenharmony_ci return; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci device->flags.power_manageable = 1; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci /* 9868c2ecf20Sopenharmony_ci * Power Management Flags 9878c2ecf20Sopenharmony_ci */ 9888c2ecf20Sopenharmony_ci if (acpi_has_method(device->handle, "_PSC")) 9898c2ecf20Sopenharmony_ci device->power.flags.explicit_get = 1; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci if (acpi_has_method(device->handle, "_IRC")) 9928c2ecf20Sopenharmony_ci device->power.flags.inrush_current = 1; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci if (acpi_has_method(device->handle, "_DSW")) 9958c2ecf20Sopenharmony_ci device->power.flags.dsw_present = 1; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci /* 9988c2ecf20Sopenharmony_ci * Enumerate supported power management states 9998c2ecf20Sopenharmony_ci */ 10008c2ecf20Sopenharmony_ci for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) 10018c2ecf20Sopenharmony_ci acpi_bus_init_power_state(device, i); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&device->power.states[ACPI_STATE_D3_COLD].resources); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci /* Set the defaults for D0 and D3hot (always supported). */ 10068c2ecf20Sopenharmony_ci device->power.states[ACPI_STATE_D0].flags.valid = 1; 10078c2ecf20Sopenharmony_ci device->power.states[ACPI_STATE_D0].power = 100; 10088c2ecf20Sopenharmony_ci device->power.states[ACPI_STATE_D3_HOT].flags.valid = 1; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci /* 10118c2ecf20Sopenharmony_ci * Use power resources only if the D0 list of them is populated, because 10128c2ecf20Sopenharmony_ci * some platforms may provide _PR3 only to indicate D3cold support and 10138c2ecf20Sopenharmony_ci * in those cases the power resources list returned by it may be bogus. 10148c2ecf20Sopenharmony_ci */ 10158c2ecf20Sopenharmony_ci if (!list_empty(&device->power.states[ACPI_STATE_D0].resources)) { 10168c2ecf20Sopenharmony_ci device->power.flags.power_resources = 1; 10178c2ecf20Sopenharmony_ci /* 10188c2ecf20Sopenharmony_ci * D3cold is supported if the D3hot list of power resources is 10198c2ecf20Sopenharmony_ci * not empty. 10208c2ecf20Sopenharmony_ci */ 10218c2ecf20Sopenharmony_ci if (!list_empty(&device->power.states[ACPI_STATE_D3_HOT].resources)) 10228c2ecf20Sopenharmony_ci device->power.states[ACPI_STATE_D3_COLD].flags.valid = 1; 10238c2ecf20Sopenharmony_ci } 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci if (acpi_bus_init_power(device)) 10268c2ecf20Sopenharmony_ci device->flags.power_manageable = 0; 10278c2ecf20Sopenharmony_ci} 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_cistatic void acpi_bus_get_flags(struct acpi_device *device) 10308c2ecf20Sopenharmony_ci{ 10318c2ecf20Sopenharmony_ci /* Presence of _STA indicates 'dynamic_status' */ 10328c2ecf20Sopenharmony_ci if (acpi_has_method(device->handle, "_STA")) 10338c2ecf20Sopenharmony_ci device->flags.dynamic_status = 1; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci /* Presence of _RMV indicates 'removable' */ 10368c2ecf20Sopenharmony_ci if (acpi_has_method(device->handle, "_RMV")) 10378c2ecf20Sopenharmony_ci device->flags.removable = 1; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci /* Presence of _EJD|_EJ0 indicates 'ejectable' */ 10408c2ecf20Sopenharmony_ci if (acpi_has_method(device->handle, "_EJD") || 10418c2ecf20Sopenharmony_ci acpi_has_method(device->handle, "_EJ0")) 10428c2ecf20Sopenharmony_ci device->flags.ejectable = 1; 10438c2ecf20Sopenharmony_ci} 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_cistatic void acpi_device_get_busid(struct acpi_device *device) 10468c2ecf20Sopenharmony_ci{ 10478c2ecf20Sopenharmony_ci char bus_id[5] = { '?', 0 }; 10488c2ecf20Sopenharmony_ci struct acpi_buffer buffer = { sizeof(bus_id), bus_id }; 10498c2ecf20Sopenharmony_ci int i = 0; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci /* 10528c2ecf20Sopenharmony_ci * Bus ID 10538c2ecf20Sopenharmony_ci * ------ 10548c2ecf20Sopenharmony_ci * The device's Bus ID is simply the object name. 10558c2ecf20Sopenharmony_ci * TBD: Shouldn't this value be unique (within the ACPI namespace)? 10568c2ecf20Sopenharmony_ci */ 10578c2ecf20Sopenharmony_ci if (ACPI_IS_ROOT_DEVICE(device)) { 10588c2ecf20Sopenharmony_ci strcpy(device->pnp.bus_id, "ACPI"); 10598c2ecf20Sopenharmony_ci return; 10608c2ecf20Sopenharmony_ci } 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci switch (device->device_type) { 10638c2ecf20Sopenharmony_ci case ACPI_BUS_TYPE_POWER_BUTTON: 10648c2ecf20Sopenharmony_ci strcpy(device->pnp.bus_id, "PWRF"); 10658c2ecf20Sopenharmony_ci break; 10668c2ecf20Sopenharmony_ci case ACPI_BUS_TYPE_SLEEP_BUTTON: 10678c2ecf20Sopenharmony_ci strcpy(device->pnp.bus_id, "SLPF"); 10688c2ecf20Sopenharmony_ci break; 10698c2ecf20Sopenharmony_ci case ACPI_BUS_TYPE_ECDT_EC: 10708c2ecf20Sopenharmony_ci strcpy(device->pnp.bus_id, "ECDT"); 10718c2ecf20Sopenharmony_ci break; 10728c2ecf20Sopenharmony_ci default: 10738c2ecf20Sopenharmony_ci acpi_get_name(device->handle, ACPI_SINGLE_NAME, &buffer); 10748c2ecf20Sopenharmony_ci /* Clean up trailing underscores (if any) */ 10758c2ecf20Sopenharmony_ci for (i = 3; i > 1; i--) { 10768c2ecf20Sopenharmony_ci if (bus_id[i] == '_') 10778c2ecf20Sopenharmony_ci bus_id[i] = '\0'; 10788c2ecf20Sopenharmony_ci else 10798c2ecf20Sopenharmony_ci break; 10808c2ecf20Sopenharmony_ci } 10818c2ecf20Sopenharmony_ci strcpy(device->pnp.bus_id, bus_id); 10828c2ecf20Sopenharmony_ci break; 10838c2ecf20Sopenharmony_ci } 10848c2ecf20Sopenharmony_ci} 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci/* 10878c2ecf20Sopenharmony_ci * acpi_ata_match - see if an acpi object is an ATA device 10888c2ecf20Sopenharmony_ci * 10898c2ecf20Sopenharmony_ci * If an acpi object has one of the ACPI ATA methods defined, 10908c2ecf20Sopenharmony_ci * then we can safely call it an ATA device. 10918c2ecf20Sopenharmony_ci */ 10928c2ecf20Sopenharmony_cibool acpi_ata_match(acpi_handle handle) 10938c2ecf20Sopenharmony_ci{ 10948c2ecf20Sopenharmony_ci return acpi_has_method(handle, "_GTF") || 10958c2ecf20Sopenharmony_ci acpi_has_method(handle, "_GTM") || 10968c2ecf20Sopenharmony_ci acpi_has_method(handle, "_STM") || 10978c2ecf20Sopenharmony_ci acpi_has_method(handle, "_SDD"); 10988c2ecf20Sopenharmony_ci} 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci/* 11018c2ecf20Sopenharmony_ci * acpi_bay_match - see if an acpi object is an ejectable driver bay 11028c2ecf20Sopenharmony_ci * 11038c2ecf20Sopenharmony_ci * If an acpi object is ejectable and has one of the ACPI ATA methods defined, 11048c2ecf20Sopenharmony_ci * then we can safely call it an ejectable drive bay 11058c2ecf20Sopenharmony_ci */ 11068c2ecf20Sopenharmony_cibool acpi_bay_match(acpi_handle handle) 11078c2ecf20Sopenharmony_ci{ 11088c2ecf20Sopenharmony_ci acpi_handle phandle; 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci if (!acpi_has_method(handle, "_EJ0")) 11118c2ecf20Sopenharmony_ci return false; 11128c2ecf20Sopenharmony_ci if (acpi_ata_match(handle)) 11138c2ecf20Sopenharmony_ci return true; 11148c2ecf20Sopenharmony_ci if (ACPI_FAILURE(acpi_get_parent(handle, &phandle))) 11158c2ecf20Sopenharmony_ci return false; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci return acpi_ata_match(phandle); 11188c2ecf20Sopenharmony_ci} 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_cibool acpi_device_is_battery(struct acpi_device *adev) 11218c2ecf20Sopenharmony_ci{ 11228c2ecf20Sopenharmony_ci struct acpi_hardware_id *hwid; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci list_for_each_entry(hwid, &adev->pnp.ids, list) 11258c2ecf20Sopenharmony_ci if (!strcmp("PNP0C0A", hwid->id)) 11268c2ecf20Sopenharmony_ci return true; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci return false; 11298c2ecf20Sopenharmony_ci} 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_cistatic bool is_ejectable_bay(struct acpi_device *adev) 11328c2ecf20Sopenharmony_ci{ 11338c2ecf20Sopenharmony_ci acpi_handle handle = adev->handle; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci if (acpi_has_method(handle, "_EJ0") && acpi_device_is_battery(adev)) 11368c2ecf20Sopenharmony_ci return true; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci return acpi_bay_match(handle); 11398c2ecf20Sopenharmony_ci} 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci/* 11428c2ecf20Sopenharmony_ci * acpi_dock_match - see if an acpi object has a _DCK method 11438c2ecf20Sopenharmony_ci */ 11448c2ecf20Sopenharmony_cibool acpi_dock_match(acpi_handle handle) 11458c2ecf20Sopenharmony_ci{ 11468c2ecf20Sopenharmony_ci return acpi_has_method(handle, "_DCK"); 11478c2ecf20Sopenharmony_ci} 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_cistatic acpi_status 11508c2ecf20Sopenharmony_ciacpi_backlight_cap_match(acpi_handle handle, u32 level, void *context, 11518c2ecf20Sopenharmony_ci void **return_value) 11528c2ecf20Sopenharmony_ci{ 11538c2ecf20Sopenharmony_ci long *cap = context; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci if (acpi_has_method(handle, "_BCM") && 11568c2ecf20Sopenharmony_ci acpi_has_method(handle, "_BCL")) { 11578c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight " 11588c2ecf20Sopenharmony_ci "support\n")); 11598c2ecf20Sopenharmony_ci *cap |= ACPI_VIDEO_BACKLIGHT; 11608c2ecf20Sopenharmony_ci /* We have backlight support, no need to scan further */ 11618c2ecf20Sopenharmony_ci return AE_CTRL_TERMINATE; 11628c2ecf20Sopenharmony_ci } 11638c2ecf20Sopenharmony_ci return 0; 11648c2ecf20Sopenharmony_ci} 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci/* Returns true if the ACPI object is a video device which can be 11678c2ecf20Sopenharmony_ci * handled by video.ko. 11688c2ecf20Sopenharmony_ci * The device will get a Linux specific CID added in scan.c to 11698c2ecf20Sopenharmony_ci * identify the device as an ACPI graphics device 11708c2ecf20Sopenharmony_ci * Be aware that the graphics device may not be physically present 11718c2ecf20Sopenharmony_ci * Use acpi_video_get_capabilities() to detect general ACPI video 11728c2ecf20Sopenharmony_ci * capabilities of present cards 11738c2ecf20Sopenharmony_ci */ 11748c2ecf20Sopenharmony_cilong acpi_is_video_device(acpi_handle handle) 11758c2ecf20Sopenharmony_ci{ 11768c2ecf20Sopenharmony_ci long video_caps = 0; 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci /* Is this device able to support video switching ? */ 11798c2ecf20Sopenharmony_ci if (acpi_has_method(handle, "_DOD") || acpi_has_method(handle, "_DOS")) 11808c2ecf20Sopenharmony_ci video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci /* Is this device able to retrieve a video ROM ? */ 11838c2ecf20Sopenharmony_ci if (acpi_has_method(handle, "_ROM")) 11848c2ecf20Sopenharmony_ci video_caps |= ACPI_VIDEO_ROM_AVAILABLE; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci /* Is this device able to configure which video head to be POSTed ? */ 11878c2ecf20Sopenharmony_ci if (acpi_has_method(handle, "_VPO") && 11888c2ecf20Sopenharmony_ci acpi_has_method(handle, "_GPD") && 11898c2ecf20Sopenharmony_ci acpi_has_method(handle, "_SPD")) 11908c2ecf20Sopenharmony_ci video_caps |= ACPI_VIDEO_DEVICE_POSTING; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci /* Only check for backlight functionality if one of the above hit. */ 11938c2ecf20Sopenharmony_ci if (video_caps) 11948c2ecf20Sopenharmony_ci acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 11958c2ecf20Sopenharmony_ci ACPI_UINT32_MAX, acpi_backlight_cap_match, NULL, 11968c2ecf20Sopenharmony_ci &video_caps, NULL); 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci return video_caps; 11998c2ecf20Sopenharmony_ci} 12008c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_is_video_device); 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ciconst char *acpi_device_hid(struct acpi_device *device) 12038c2ecf20Sopenharmony_ci{ 12048c2ecf20Sopenharmony_ci struct acpi_hardware_id *hid; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci if (list_empty(&device->pnp.ids)) 12078c2ecf20Sopenharmony_ci return dummy_hid; 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci hid = list_first_entry(&device->pnp.ids, struct acpi_hardware_id, list); 12108c2ecf20Sopenharmony_ci return hid->id; 12118c2ecf20Sopenharmony_ci} 12128c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_device_hid); 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_cistatic void acpi_add_id(struct acpi_device_pnp *pnp, const char *dev_id) 12158c2ecf20Sopenharmony_ci{ 12168c2ecf20Sopenharmony_ci struct acpi_hardware_id *id; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci id = kmalloc(sizeof(*id), GFP_KERNEL); 12198c2ecf20Sopenharmony_ci if (!id) 12208c2ecf20Sopenharmony_ci return; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci id->id = kstrdup_const(dev_id, GFP_KERNEL); 12238c2ecf20Sopenharmony_ci if (!id->id) { 12248c2ecf20Sopenharmony_ci kfree(id); 12258c2ecf20Sopenharmony_ci return; 12268c2ecf20Sopenharmony_ci } 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci list_add_tail(&id->list, &pnp->ids); 12298c2ecf20Sopenharmony_ci pnp->type.hardware_id = 1; 12308c2ecf20Sopenharmony_ci} 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci/* 12338c2ecf20Sopenharmony_ci * Old IBM workstations have a DSDT bug wherein the SMBus object 12348c2ecf20Sopenharmony_ci * lacks the SMBUS01 HID and the methods do not have the necessary "_" 12358c2ecf20Sopenharmony_ci * prefix. Work around this. 12368c2ecf20Sopenharmony_ci */ 12378c2ecf20Sopenharmony_cistatic bool acpi_ibm_smbus_match(acpi_handle handle) 12388c2ecf20Sopenharmony_ci{ 12398c2ecf20Sopenharmony_ci char node_name[ACPI_PATH_SEGMENT_LENGTH]; 12408c2ecf20Sopenharmony_ci struct acpi_buffer path = { sizeof(node_name), node_name }; 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci if (!dmi_name_in_vendors("IBM")) 12438c2ecf20Sopenharmony_ci return false; 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci /* Look for SMBS object */ 12468c2ecf20Sopenharmony_ci if (ACPI_FAILURE(acpi_get_name(handle, ACPI_SINGLE_NAME, &path)) || 12478c2ecf20Sopenharmony_ci strcmp("SMBS", path.pointer)) 12488c2ecf20Sopenharmony_ci return false; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci /* Does it have the necessary (but misnamed) methods? */ 12518c2ecf20Sopenharmony_ci if (acpi_has_method(handle, "SBI") && 12528c2ecf20Sopenharmony_ci acpi_has_method(handle, "SBR") && 12538c2ecf20Sopenharmony_ci acpi_has_method(handle, "SBW")) 12548c2ecf20Sopenharmony_ci return true; 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci return false; 12578c2ecf20Sopenharmony_ci} 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_cistatic bool acpi_object_is_system_bus(acpi_handle handle) 12608c2ecf20Sopenharmony_ci{ 12618c2ecf20Sopenharmony_ci acpi_handle tmp; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(acpi_get_handle(NULL, "\\_SB", &tmp)) && 12648c2ecf20Sopenharmony_ci tmp == handle) 12658c2ecf20Sopenharmony_ci return true; 12668c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(acpi_get_handle(NULL, "\\_TZ", &tmp)) && 12678c2ecf20Sopenharmony_ci tmp == handle) 12688c2ecf20Sopenharmony_ci return true; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci return false; 12718c2ecf20Sopenharmony_ci} 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_cistatic void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp, 12748c2ecf20Sopenharmony_ci int device_type) 12758c2ecf20Sopenharmony_ci{ 12768c2ecf20Sopenharmony_ci acpi_status status; 12778c2ecf20Sopenharmony_ci struct acpi_device_info *info; 12788c2ecf20Sopenharmony_ci struct acpi_pnp_device_id_list *cid_list; 12798c2ecf20Sopenharmony_ci int i; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci switch (device_type) { 12828c2ecf20Sopenharmony_ci case ACPI_BUS_TYPE_DEVICE: 12838c2ecf20Sopenharmony_ci if (handle == ACPI_ROOT_OBJECT) { 12848c2ecf20Sopenharmony_ci acpi_add_id(pnp, ACPI_SYSTEM_HID); 12858c2ecf20Sopenharmony_ci break; 12868c2ecf20Sopenharmony_ci } 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci status = acpi_get_object_info(handle, &info); 12898c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 12908c2ecf20Sopenharmony_ci pr_err(PREFIX "%s: Error reading device info\n", 12918c2ecf20Sopenharmony_ci __func__); 12928c2ecf20Sopenharmony_ci return; 12938c2ecf20Sopenharmony_ci } 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci if (info->valid & ACPI_VALID_HID) { 12968c2ecf20Sopenharmony_ci acpi_add_id(pnp, info->hardware_id.string); 12978c2ecf20Sopenharmony_ci pnp->type.platform_id = 1; 12988c2ecf20Sopenharmony_ci } 12998c2ecf20Sopenharmony_ci if (info->valid & ACPI_VALID_CID) { 13008c2ecf20Sopenharmony_ci cid_list = &info->compatible_id_list; 13018c2ecf20Sopenharmony_ci for (i = 0; i < cid_list->count; i++) 13028c2ecf20Sopenharmony_ci acpi_add_id(pnp, cid_list->ids[i].string); 13038c2ecf20Sopenharmony_ci } 13048c2ecf20Sopenharmony_ci if (info->valid & ACPI_VALID_ADR) { 13058c2ecf20Sopenharmony_ci pnp->bus_address = info->address; 13068c2ecf20Sopenharmony_ci pnp->type.bus_address = 1; 13078c2ecf20Sopenharmony_ci } 13088c2ecf20Sopenharmony_ci if (info->valid & ACPI_VALID_UID) 13098c2ecf20Sopenharmony_ci pnp->unique_id = kstrdup(info->unique_id.string, 13108c2ecf20Sopenharmony_ci GFP_KERNEL); 13118c2ecf20Sopenharmony_ci if (info->valid & ACPI_VALID_CLS) 13128c2ecf20Sopenharmony_ci acpi_add_id(pnp, info->class_code.string); 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci kfree(info); 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci /* 13178c2ecf20Sopenharmony_ci * Some devices don't reliably have _HIDs & _CIDs, so add 13188c2ecf20Sopenharmony_ci * synthetic HIDs to make sure drivers can find them. 13198c2ecf20Sopenharmony_ci */ 13208c2ecf20Sopenharmony_ci if (acpi_is_video_device(handle)) 13218c2ecf20Sopenharmony_ci acpi_add_id(pnp, ACPI_VIDEO_HID); 13228c2ecf20Sopenharmony_ci else if (acpi_bay_match(handle)) 13238c2ecf20Sopenharmony_ci acpi_add_id(pnp, ACPI_BAY_HID); 13248c2ecf20Sopenharmony_ci else if (acpi_dock_match(handle)) 13258c2ecf20Sopenharmony_ci acpi_add_id(pnp, ACPI_DOCK_HID); 13268c2ecf20Sopenharmony_ci else if (acpi_ibm_smbus_match(handle)) 13278c2ecf20Sopenharmony_ci acpi_add_id(pnp, ACPI_SMBUS_IBM_HID); 13288c2ecf20Sopenharmony_ci else if (list_empty(&pnp->ids) && 13298c2ecf20Sopenharmony_ci acpi_object_is_system_bus(handle)) { 13308c2ecf20Sopenharmony_ci /* \_SB, \_TZ, LNXSYBUS */ 13318c2ecf20Sopenharmony_ci acpi_add_id(pnp, ACPI_BUS_HID); 13328c2ecf20Sopenharmony_ci strcpy(pnp->device_name, ACPI_BUS_DEVICE_NAME); 13338c2ecf20Sopenharmony_ci strcpy(pnp->device_class, ACPI_BUS_CLASS); 13348c2ecf20Sopenharmony_ci } 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci break; 13378c2ecf20Sopenharmony_ci case ACPI_BUS_TYPE_POWER: 13388c2ecf20Sopenharmony_ci acpi_add_id(pnp, ACPI_POWER_HID); 13398c2ecf20Sopenharmony_ci break; 13408c2ecf20Sopenharmony_ci case ACPI_BUS_TYPE_PROCESSOR: 13418c2ecf20Sopenharmony_ci acpi_add_id(pnp, ACPI_PROCESSOR_OBJECT_HID); 13428c2ecf20Sopenharmony_ci break; 13438c2ecf20Sopenharmony_ci case ACPI_BUS_TYPE_THERMAL: 13448c2ecf20Sopenharmony_ci acpi_add_id(pnp, ACPI_THERMAL_HID); 13458c2ecf20Sopenharmony_ci break; 13468c2ecf20Sopenharmony_ci case ACPI_BUS_TYPE_POWER_BUTTON: 13478c2ecf20Sopenharmony_ci acpi_add_id(pnp, ACPI_BUTTON_HID_POWERF); 13488c2ecf20Sopenharmony_ci break; 13498c2ecf20Sopenharmony_ci case ACPI_BUS_TYPE_SLEEP_BUTTON: 13508c2ecf20Sopenharmony_ci acpi_add_id(pnp, ACPI_BUTTON_HID_SLEEPF); 13518c2ecf20Sopenharmony_ci break; 13528c2ecf20Sopenharmony_ci case ACPI_BUS_TYPE_ECDT_EC: 13538c2ecf20Sopenharmony_ci acpi_add_id(pnp, ACPI_ECDT_HID); 13548c2ecf20Sopenharmony_ci break; 13558c2ecf20Sopenharmony_ci } 13568c2ecf20Sopenharmony_ci} 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_civoid acpi_free_pnp_ids(struct acpi_device_pnp *pnp) 13598c2ecf20Sopenharmony_ci{ 13608c2ecf20Sopenharmony_ci struct acpi_hardware_id *id, *tmp; 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci list_for_each_entry_safe(id, tmp, &pnp->ids, list) { 13638c2ecf20Sopenharmony_ci kfree_const(id->id); 13648c2ecf20Sopenharmony_ci kfree(id); 13658c2ecf20Sopenharmony_ci } 13668c2ecf20Sopenharmony_ci kfree(pnp->unique_id); 13678c2ecf20Sopenharmony_ci} 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci/** 13708c2ecf20Sopenharmony_ci * acpi_dma_supported - Check DMA support for the specified device. 13718c2ecf20Sopenharmony_ci * @adev: The pointer to acpi device 13728c2ecf20Sopenharmony_ci * 13738c2ecf20Sopenharmony_ci * Return false if DMA is not supported. Otherwise, return true 13748c2ecf20Sopenharmony_ci */ 13758c2ecf20Sopenharmony_cibool acpi_dma_supported(struct acpi_device *adev) 13768c2ecf20Sopenharmony_ci{ 13778c2ecf20Sopenharmony_ci if (!adev) 13788c2ecf20Sopenharmony_ci return false; 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci if (adev->flags.cca_seen) 13818c2ecf20Sopenharmony_ci return true; 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci /* 13848c2ecf20Sopenharmony_ci * Per ACPI 6.0 sec 6.2.17, assume devices can do cache-coherent 13858c2ecf20Sopenharmony_ci * DMA on "Intel platforms". Presumably that includes all x86 and 13868c2ecf20Sopenharmony_ci * ia64, and other arches will set CONFIG_ACPI_CCA_REQUIRED=y. 13878c2ecf20Sopenharmony_ci */ 13888c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_ACPI_CCA_REQUIRED)) 13898c2ecf20Sopenharmony_ci return true; 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci return false; 13928c2ecf20Sopenharmony_ci} 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci/** 13958c2ecf20Sopenharmony_ci * acpi_get_dma_attr - Check the supported DMA attr for the specified device. 13968c2ecf20Sopenharmony_ci * @adev: The pointer to acpi device 13978c2ecf20Sopenharmony_ci * 13988c2ecf20Sopenharmony_ci * Return enum dev_dma_attr. 13998c2ecf20Sopenharmony_ci */ 14008c2ecf20Sopenharmony_cienum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev) 14018c2ecf20Sopenharmony_ci{ 14028c2ecf20Sopenharmony_ci if (!acpi_dma_supported(adev)) 14038c2ecf20Sopenharmony_ci return DEV_DMA_NOT_SUPPORTED; 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci if (adev->flags.coherent_dma) 14068c2ecf20Sopenharmony_ci return DEV_DMA_COHERENT; 14078c2ecf20Sopenharmony_ci else 14088c2ecf20Sopenharmony_ci return DEV_DMA_NON_COHERENT; 14098c2ecf20Sopenharmony_ci} 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci/** 14128c2ecf20Sopenharmony_ci * acpi_dma_get_range() - Get device DMA parameters. 14138c2ecf20Sopenharmony_ci * 14148c2ecf20Sopenharmony_ci * @dev: device to configure 14158c2ecf20Sopenharmony_ci * @map: pointer to DMA ranges result 14168c2ecf20Sopenharmony_ci * 14178c2ecf20Sopenharmony_ci * Evaluate DMA regions and return pointer to DMA regions on 14188c2ecf20Sopenharmony_ci * parsing success; it does not update the passed in values on failure. 14198c2ecf20Sopenharmony_ci * 14208c2ecf20Sopenharmony_ci * Return 0 on success, < 0 on failure. 14218c2ecf20Sopenharmony_ci */ 14228c2ecf20Sopenharmony_ciint acpi_dma_get_range(struct device *dev, const struct bus_dma_region **map) 14238c2ecf20Sopenharmony_ci{ 14248c2ecf20Sopenharmony_ci struct acpi_device *adev; 14258c2ecf20Sopenharmony_ci LIST_HEAD(list); 14268c2ecf20Sopenharmony_ci struct resource_entry *rentry; 14278c2ecf20Sopenharmony_ci int ret; 14288c2ecf20Sopenharmony_ci struct device *dma_dev = dev; 14298c2ecf20Sopenharmony_ci struct bus_dma_region *r; 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci /* 14328c2ecf20Sopenharmony_ci * Walk the device tree chasing an ACPI companion with a _DMA 14338c2ecf20Sopenharmony_ci * object while we go. Stop if we find a device with an ACPI 14348c2ecf20Sopenharmony_ci * companion containing a _DMA method. 14358c2ecf20Sopenharmony_ci */ 14368c2ecf20Sopenharmony_ci do { 14378c2ecf20Sopenharmony_ci adev = ACPI_COMPANION(dma_dev); 14388c2ecf20Sopenharmony_ci if (adev && acpi_has_method(adev->handle, METHOD_NAME__DMA)) 14398c2ecf20Sopenharmony_ci break; 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci dma_dev = dma_dev->parent; 14428c2ecf20Sopenharmony_ci } while (dma_dev); 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci if (!dma_dev) 14458c2ecf20Sopenharmony_ci return -ENODEV; 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci if (!acpi_has_method(adev->handle, METHOD_NAME__CRS)) { 14488c2ecf20Sopenharmony_ci acpi_handle_warn(adev->handle, "_DMA is valid only if _CRS is present\n"); 14498c2ecf20Sopenharmony_ci return -EINVAL; 14508c2ecf20Sopenharmony_ci } 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci ret = acpi_dev_get_dma_resources(adev, &list); 14538c2ecf20Sopenharmony_ci if (ret > 0) { 14548c2ecf20Sopenharmony_ci r = kcalloc(ret + 1, sizeof(*r), GFP_KERNEL); 14558c2ecf20Sopenharmony_ci if (!r) { 14568c2ecf20Sopenharmony_ci ret = -ENOMEM; 14578c2ecf20Sopenharmony_ci goto out; 14588c2ecf20Sopenharmony_ci } 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci list_for_each_entry(rentry, &list, node) { 14618c2ecf20Sopenharmony_ci if (rentry->res->start >= rentry->res->end) { 14628c2ecf20Sopenharmony_ci kfree(r); 14638c2ecf20Sopenharmony_ci ret = -EINVAL; 14648c2ecf20Sopenharmony_ci dev_dbg(dma_dev, "Invalid DMA regions configuration\n"); 14658c2ecf20Sopenharmony_ci goto out; 14668c2ecf20Sopenharmony_ci } 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci r->cpu_start = rentry->res->start; 14698c2ecf20Sopenharmony_ci r->dma_start = rentry->res->start - rentry->offset; 14708c2ecf20Sopenharmony_ci r->size = resource_size(rentry->res); 14718c2ecf20Sopenharmony_ci r->offset = rentry->offset; 14728c2ecf20Sopenharmony_ci r++; 14738c2ecf20Sopenharmony_ci } 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci *map = r; 14768c2ecf20Sopenharmony_ci } 14778c2ecf20Sopenharmony_ci out: 14788c2ecf20Sopenharmony_ci acpi_dev_free_resource_list(&list); 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci return ret >= 0 ? 0 : ret; 14818c2ecf20Sopenharmony_ci} 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci/** 14848c2ecf20Sopenharmony_ci * acpi_dma_configure_id - Set-up DMA configuration for the device. 14858c2ecf20Sopenharmony_ci * @dev: The pointer to the device 14868c2ecf20Sopenharmony_ci * @attr: device dma attributes 14878c2ecf20Sopenharmony_ci * @input_id: input device id const value pointer 14888c2ecf20Sopenharmony_ci */ 14898c2ecf20Sopenharmony_ciint acpi_dma_configure_id(struct device *dev, enum dev_dma_attr attr, 14908c2ecf20Sopenharmony_ci const u32 *input_id) 14918c2ecf20Sopenharmony_ci{ 14928c2ecf20Sopenharmony_ci const struct iommu_ops *iommu; 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci if (attr == DEV_DMA_NOT_SUPPORTED) { 14958c2ecf20Sopenharmony_ci set_dma_ops(dev, &dma_dummy_ops); 14968c2ecf20Sopenharmony_ci return 0; 14978c2ecf20Sopenharmony_ci } 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci acpi_arch_dma_setup(dev); 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci iommu = iort_iommu_configure_id(dev, input_id); 15028c2ecf20Sopenharmony_ci if (PTR_ERR(iommu) == -EPROBE_DEFER) 15038c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci arch_setup_dma_ops(dev, 0, U64_MAX, 15068c2ecf20Sopenharmony_ci iommu, attr == DEV_DMA_COHERENT); 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci return 0; 15098c2ecf20Sopenharmony_ci} 15108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_dma_configure_id); 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_cistatic void acpi_init_coherency(struct acpi_device *adev) 15138c2ecf20Sopenharmony_ci{ 15148c2ecf20Sopenharmony_ci unsigned long long cca = 0; 15158c2ecf20Sopenharmony_ci acpi_status status; 15168c2ecf20Sopenharmony_ci struct acpi_device *parent = adev->parent; 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci if (parent && parent->flags.cca_seen) { 15198c2ecf20Sopenharmony_ci /* 15208c2ecf20Sopenharmony_ci * From ACPI spec, OSPM will ignore _CCA if an ancestor 15218c2ecf20Sopenharmony_ci * already saw one. 15228c2ecf20Sopenharmony_ci */ 15238c2ecf20Sopenharmony_ci adev->flags.cca_seen = 1; 15248c2ecf20Sopenharmony_ci cca = parent->flags.coherent_dma; 15258c2ecf20Sopenharmony_ci } else { 15268c2ecf20Sopenharmony_ci status = acpi_evaluate_integer(adev->handle, "_CCA", 15278c2ecf20Sopenharmony_ci NULL, &cca); 15288c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(status)) 15298c2ecf20Sopenharmony_ci adev->flags.cca_seen = 1; 15308c2ecf20Sopenharmony_ci else if (!IS_ENABLED(CONFIG_ACPI_CCA_REQUIRED)) 15318c2ecf20Sopenharmony_ci /* 15328c2ecf20Sopenharmony_ci * If architecture does not specify that _CCA is 15338c2ecf20Sopenharmony_ci * required for DMA-able devices (e.g. x86), 15348c2ecf20Sopenharmony_ci * we default to _CCA=1. 15358c2ecf20Sopenharmony_ci */ 15368c2ecf20Sopenharmony_ci cca = 1; 15378c2ecf20Sopenharmony_ci else 15388c2ecf20Sopenharmony_ci acpi_handle_debug(adev->handle, 15398c2ecf20Sopenharmony_ci "ACPI device is missing _CCA.\n"); 15408c2ecf20Sopenharmony_ci } 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci adev->flags.coherent_dma = cca; 15438c2ecf20Sopenharmony_ci} 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_cistatic int acpi_check_serial_bus_slave(struct acpi_resource *ares, void *data) 15468c2ecf20Sopenharmony_ci{ 15478c2ecf20Sopenharmony_ci bool *is_serial_bus_slave_p = data; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) 15508c2ecf20Sopenharmony_ci return 1; 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci *is_serial_bus_slave_p = true; 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci /* no need to do more checking */ 15558c2ecf20Sopenharmony_ci return -1; 15568c2ecf20Sopenharmony_ci} 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_cistatic bool acpi_is_indirect_io_slave(struct acpi_device *device) 15598c2ecf20Sopenharmony_ci{ 15608c2ecf20Sopenharmony_ci struct acpi_device *parent = device->parent; 15618c2ecf20Sopenharmony_ci static const struct acpi_device_id indirect_io_hosts[] = { 15628c2ecf20Sopenharmony_ci {"HISI0191", 0}, 15638c2ecf20Sopenharmony_ci {} 15648c2ecf20Sopenharmony_ci }; 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci return parent && !acpi_match_device_ids(parent, indirect_io_hosts); 15678c2ecf20Sopenharmony_ci} 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_cistatic bool acpi_device_enumeration_by_parent(struct acpi_device *device) 15708c2ecf20Sopenharmony_ci{ 15718c2ecf20Sopenharmony_ci struct list_head resource_list; 15728c2ecf20Sopenharmony_ci bool is_serial_bus_slave = false; 15738c2ecf20Sopenharmony_ci static const struct acpi_device_id ignore_serial_bus_ids[] = { 15748c2ecf20Sopenharmony_ci /* 15758c2ecf20Sopenharmony_ci * These devices have multiple I2cSerialBus resources and an i2c-client 15768c2ecf20Sopenharmony_ci * must be instantiated for each, each with its own i2c_device_id. 15778c2ecf20Sopenharmony_ci * Normally we only instantiate an i2c-client for the first resource, 15788c2ecf20Sopenharmony_ci * using the ACPI HID as id. These special cases are handled by the 15798c2ecf20Sopenharmony_ci * drivers/platform/x86/i2c-multi-instantiate.c driver, which knows 15808c2ecf20Sopenharmony_ci * which i2c_device_id to use for each resource. 15818c2ecf20Sopenharmony_ci */ 15828c2ecf20Sopenharmony_ci {"BSG1160", }, 15838c2ecf20Sopenharmony_ci {"BSG2150", }, 15848c2ecf20Sopenharmony_ci {"INT33FE", }, 15858c2ecf20Sopenharmony_ci {"INT3515", }, 15868c2ecf20Sopenharmony_ci /* 15878c2ecf20Sopenharmony_ci * HIDs of device with an UartSerialBusV2 resource for which userspace 15888c2ecf20Sopenharmony_ci * expects a regular tty cdev to be created (instead of the in kernel 15898c2ecf20Sopenharmony_ci * serdev) and which have a kernel driver which expects a platform_dev 15908c2ecf20Sopenharmony_ci * such as the rfkill-gpio driver. 15918c2ecf20Sopenharmony_ci */ 15928c2ecf20Sopenharmony_ci {"BCM4752", }, 15938c2ecf20Sopenharmony_ci {"LNV4752", }, 15948c2ecf20Sopenharmony_ci {} 15958c2ecf20Sopenharmony_ci }; 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci if (acpi_is_indirect_io_slave(device)) 15988c2ecf20Sopenharmony_ci return true; 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci /* Macs use device properties in lieu of _CRS resources */ 16018c2ecf20Sopenharmony_ci if (x86_apple_machine && 16028c2ecf20Sopenharmony_ci (fwnode_property_present(&device->fwnode, "spiSclkPeriod") || 16038c2ecf20Sopenharmony_ci fwnode_property_present(&device->fwnode, "i2cAddress") || 16048c2ecf20Sopenharmony_ci fwnode_property_present(&device->fwnode, "baud"))) 16058c2ecf20Sopenharmony_ci return true; 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci if (!acpi_match_device_ids(device, ignore_serial_bus_ids)) 16088c2ecf20Sopenharmony_ci return false; 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&resource_list); 16118c2ecf20Sopenharmony_ci acpi_dev_get_resources(device, &resource_list, 16128c2ecf20Sopenharmony_ci acpi_check_serial_bus_slave, 16138c2ecf20Sopenharmony_ci &is_serial_bus_slave); 16148c2ecf20Sopenharmony_ci acpi_dev_free_resource_list(&resource_list); 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci return is_serial_bus_slave; 16178c2ecf20Sopenharmony_ci} 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_civoid acpi_init_device_object(struct acpi_device *device, acpi_handle handle, 16208c2ecf20Sopenharmony_ci int type, unsigned long long sta) 16218c2ecf20Sopenharmony_ci{ 16228c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&device->pnp.ids); 16238c2ecf20Sopenharmony_ci device->device_type = type; 16248c2ecf20Sopenharmony_ci device->handle = handle; 16258c2ecf20Sopenharmony_ci device->parent = acpi_bus_get_parent(handle); 16268c2ecf20Sopenharmony_ci device->fwnode.ops = &acpi_device_fwnode_ops; 16278c2ecf20Sopenharmony_ci acpi_set_device_status(device, sta); 16288c2ecf20Sopenharmony_ci acpi_device_get_busid(device); 16298c2ecf20Sopenharmony_ci acpi_set_pnp_ids(handle, &device->pnp, type); 16308c2ecf20Sopenharmony_ci acpi_init_properties(device); 16318c2ecf20Sopenharmony_ci acpi_bus_get_flags(device); 16328c2ecf20Sopenharmony_ci device->flags.match_driver = false; 16338c2ecf20Sopenharmony_ci device->flags.initialized = true; 16348c2ecf20Sopenharmony_ci device->flags.enumeration_by_parent = 16358c2ecf20Sopenharmony_ci acpi_device_enumeration_by_parent(device); 16368c2ecf20Sopenharmony_ci acpi_device_clear_enumerated(device); 16378c2ecf20Sopenharmony_ci device_initialize(&device->dev); 16388c2ecf20Sopenharmony_ci dev_set_uevent_suppress(&device->dev, true); 16398c2ecf20Sopenharmony_ci acpi_init_coherency(device); 16408c2ecf20Sopenharmony_ci /* Assume there are unmet deps until acpi_device_dep_initialize() runs */ 16418c2ecf20Sopenharmony_ci device->dep_unmet = 1; 16428c2ecf20Sopenharmony_ci} 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_civoid acpi_device_add_finalize(struct acpi_device *device) 16458c2ecf20Sopenharmony_ci{ 16468c2ecf20Sopenharmony_ci dev_set_uevent_suppress(&device->dev, false); 16478c2ecf20Sopenharmony_ci kobject_uevent(&device->dev.kobj, KOBJ_ADD); 16488c2ecf20Sopenharmony_ci} 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_cistatic int acpi_add_single_object(struct acpi_device **child, 16518c2ecf20Sopenharmony_ci acpi_handle handle, int type, 16528c2ecf20Sopenharmony_ci unsigned long long sta) 16538c2ecf20Sopenharmony_ci{ 16548c2ecf20Sopenharmony_ci int result; 16558c2ecf20Sopenharmony_ci struct acpi_device *device; 16568c2ecf20Sopenharmony_ci struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci device = kzalloc(sizeof(struct acpi_device), GFP_KERNEL); 16598c2ecf20Sopenharmony_ci if (!device) { 16608c2ecf20Sopenharmony_ci printk(KERN_ERR PREFIX "Memory allocation error\n"); 16618c2ecf20Sopenharmony_ci return -ENOMEM; 16628c2ecf20Sopenharmony_ci } 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci acpi_init_device_object(device, handle, type, sta); 16658c2ecf20Sopenharmony_ci /* 16668c2ecf20Sopenharmony_ci * For ACPI_BUS_TYPE_DEVICE getting the status is delayed till here so 16678c2ecf20Sopenharmony_ci * that we can call acpi_bus_get_status() and use its quirk handling. 16688c2ecf20Sopenharmony_ci * Note this must be done before the get power-/wakeup_dev-flags calls. 16698c2ecf20Sopenharmony_ci */ 16708c2ecf20Sopenharmony_ci if (type == ACPI_BUS_TYPE_DEVICE) 16718c2ecf20Sopenharmony_ci if (acpi_bus_get_status(device) < 0) 16728c2ecf20Sopenharmony_ci acpi_set_device_status(device, 0); 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci acpi_bus_get_power_flags(device); 16758c2ecf20Sopenharmony_ci acpi_bus_get_wakeup_device_flags(device); 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci result = acpi_device_add(device, acpi_device_release); 16788c2ecf20Sopenharmony_ci if (result) { 16798c2ecf20Sopenharmony_ci acpi_device_release(&device->dev); 16808c2ecf20Sopenharmony_ci return result; 16818c2ecf20Sopenharmony_ci } 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci acpi_power_add_remove_device(device, true); 16848c2ecf20Sopenharmony_ci acpi_device_add_finalize(device); 16858c2ecf20Sopenharmony_ci acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); 16868c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Added %s [%s] parent %s\n", 16878c2ecf20Sopenharmony_ci dev_name(&device->dev), (char *) buffer.pointer, 16888c2ecf20Sopenharmony_ci device->parent ? dev_name(&device->parent->dev) : "(null)")); 16898c2ecf20Sopenharmony_ci kfree(buffer.pointer); 16908c2ecf20Sopenharmony_ci *child = device; 16918c2ecf20Sopenharmony_ci return 0; 16928c2ecf20Sopenharmony_ci} 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_cistatic acpi_status acpi_get_resource_memory(struct acpi_resource *ares, 16958c2ecf20Sopenharmony_ci void *context) 16968c2ecf20Sopenharmony_ci{ 16978c2ecf20Sopenharmony_ci struct resource *res = context; 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci if (acpi_dev_resource_memory(ares, res)) 17008c2ecf20Sopenharmony_ci return AE_CTRL_TERMINATE; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci return AE_OK; 17038c2ecf20Sopenharmony_ci} 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_cistatic bool acpi_device_should_be_hidden(acpi_handle handle) 17068c2ecf20Sopenharmony_ci{ 17078c2ecf20Sopenharmony_ci acpi_status status; 17088c2ecf20Sopenharmony_ci struct resource res; 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci /* Check if it should ignore the UART device */ 17118c2ecf20Sopenharmony_ci if (!(spcr_uart_addr && acpi_has_method(handle, METHOD_NAME__CRS))) 17128c2ecf20Sopenharmony_ci return false; 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_ci /* 17158c2ecf20Sopenharmony_ci * The UART device described in SPCR table is assumed to have only one 17168c2ecf20Sopenharmony_ci * memory resource present. So we only look for the first one here. 17178c2ecf20Sopenharmony_ci */ 17188c2ecf20Sopenharmony_ci status = acpi_walk_resources(handle, METHOD_NAME__CRS, 17198c2ecf20Sopenharmony_ci acpi_get_resource_memory, &res); 17208c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status) || res.start != spcr_uart_addr) 17218c2ecf20Sopenharmony_ci return false; 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci acpi_handle_info(handle, "The UART device @%pa in SPCR table will be hidden\n", 17248c2ecf20Sopenharmony_ci &res.start); 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci return true; 17278c2ecf20Sopenharmony_ci} 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_cistatic int acpi_bus_type_and_status(acpi_handle handle, int *type, 17308c2ecf20Sopenharmony_ci unsigned long long *sta) 17318c2ecf20Sopenharmony_ci{ 17328c2ecf20Sopenharmony_ci acpi_status status; 17338c2ecf20Sopenharmony_ci acpi_object_type acpi_type; 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci status = acpi_get_type(handle, &acpi_type); 17368c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 17378c2ecf20Sopenharmony_ci return -ENODEV; 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci switch (acpi_type) { 17408c2ecf20Sopenharmony_ci case ACPI_TYPE_ANY: /* for ACPI_ROOT_OBJECT */ 17418c2ecf20Sopenharmony_ci case ACPI_TYPE_DEVICE: 17428c2ecf20Sopenharmony_ci if (acpi_device_should_be_hidden(handle)) 17438c2ecf20Sopenharmony_ci return -ENODEV; 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci *type = ACPI_BUS_TYPE_DEVICE; 17468c2ecf20Sopenharmony_ci /* 17478c2ecf20Sopenharmony_ci * acpi_add_single_object updates this once we've an acpi_device 17488c2ecf20Sopenharmony_ci * so that acpi_bus_get_status' quirk handling can be used. 17498c2ecf20Sopenharmony_ci */ 17508c2ecf20Sopenharmony_ci *sta = ACPI_STA_DEFAULT; 17518c2ecf20Sopenharmony_ci break; 17528c2ecf20Sopenharmony_ci case ACPI_TYPE_PROCESSOR: 17538c2ecf20Sopenharmony_ci *type = ACPI_BUS_TYPE_PROCESSOR; 17548c2ecf20Sopenharmony_ci status = acpi_bus_get_status_handle(handle, sta); 17558c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 17568c2ecf20Sopenharmony_ci return -ENODEV; 17578c2ecf20Sopenharmony_ci break; 17588c2ecf20Sopenharmony_ci case ACPI_TYPE_THERMAL: 17598c2ecf20Sopenharmony_ci *type = ACPI_BUS_TYPE_THERMAL; 17608c2ecf20Sopenharmony_ci *sta = ACPI_STA_DEFAULT; 17618c2ecf20Sopenharmony_ci break; 17628c2ecf20Sopenharmony_ci case ACPI_TYPE_POWER: 17638c2ecf20Sopenharmony_ci *type = ACPI_BUS_TYPE_POWER; 17648c2ecf20Sopenharmony_ci *sta = ACPI_STA_DEFAULT; 17658c2ecf20Sopenharmony_ci break; 17668c2ecf20Sopenharmony_ci default: 17678c2ecf20Sopenharmony_ci return -ENODEV; 17688c2ecf20Sopenharmony_ci } 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci return 0; 17718c2ecf20Sopenharmony_ci} 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_cibool acpi_device_is_present(const struct acpi_device *adev) 17748c2ecf20Sopenharmony_ci{ 17758c2ecf20Sopenharmony_ci return adev->status.present || adev->status.functional; 17768c2ecf20Sopenharmony_ci} 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_cistatic bool acpi_scan_handler_matching(struct acpi_scan_handler *handler, 17798c2ecf20Sopenharmony_ci const char *idstr, 17808c2ecf20Sopenharmony_ci const struct acpi_device_id **matchid) 17818c2ecf20Sopenharmony_ci{ 17828c2ecf20Sopenharmony_ci const struct acpi_device_id *devid; 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci if (handler->match) 17858c2ecf20Sopenharmony_ci return handler->match(idstr, matchid); 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci for (devid = handler->ids; devid->id[0]; devid++) 17888c2ecf20Sopenharmony_ci if (!strcmp((char *)devid->id, idstr)) { 17898c2ecf20Sopenharmony_ci if (matchid) 17908c2ecf20Sopenharmony_ci *matchid = devid; 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci return true; 17938c2ecf20Sopenharmony_ci } 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci return false; 17968c2ecf20Sopenharmony_ci} 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_cistatic struct acpi_scan_handler *acpi_scan_match_handler(const char *idstr, 17998c2ecf20Sopenharmony_ci const struct acpi_device_id **matchid) 18008c2ecf20Sopenharmony_ci{ 18018c2ecf20Sopenharmony_ci struct acpi_scan_handler *handler; 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci list_for_each_entry(handler, &acpi_scan_handlers_list, list_node) 18048c2ecf20Sopenharmony_ci if (acpi_scan_handler_matching(handler, idstr, matchid)) 18058c2ecf20Sopenharmony_ci return handler; 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci return NULL; 18088c2ecf20Sopenharmony_ci} 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_civoid acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val) 18118c2ecf20Sopenharmony_ci{ 18128c2ecf20Sopenharmony_ci if (!!hotplug->enabled == !!val) 18138c2ecf20Sopenharmony_ci return; 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci mutex_lock(&acpi_scan_lock); 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci hotplug->enabled = val; 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci mutex_unlock(&acpi_scan_lock); 18208c2ecf20Sopenharmony_ci} 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_cistatic void acpi_scan_init_hotplug(struct acpi_device *adev) 18238c2ecf20Sopenharmony_ci{ 18248c2ecf20Sopenharmony_ci struct acpi_hardware_id *hwid; 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci if (acpi_dock_match(adev->handle) || is_ejectable_bay(adev)) { 18278c2ecf20Sopenharmony_ci acpi_dock_add(adev); 18288c2ecf20Sopenharmony_ci return; 18298c2ecf20Sopenharmony_ci } 18308c2ecf20Sopenharmony_ci list_for_each_entry(hwid, &adev->pnp.ids, list) { 18318c2ecf20Sopenharmony_ci struct acpi_scan_handler *handler; 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci handler = acpi_scan_match_handler(hwid->id, NULL); 18348c2ecf20Sopenharmony_ci if (handler) { 18358c2ecf20Sopenharmony_ci adev->flags.hotplug_notify = true; 18368c2ecf20Sopenharmony_ci break; 18378c2ecf20Sopenharmony_ci } 18388c2ecf20Sopenharmony_ci } 18398c2ecf20Sopenharmony_ci} 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_cistatic void acpi_device_dep_initialize(struct acpi_device *adev) 18428c2ecf20Sopenharmony_ci{ 18438c2ecf20Sopenharmony_ci struct acpi_dep_data *dep; 18448c2ecf20Sopenharmony_ci struct acpi_handle_list dep_devices; 18458c2ecf20Sopenharmony_ci acpi_status status; 18468c2ecf20Sopenharmony_ci int i; 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci adev->dep_unmet = 0; 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci if (!acpi_has_method(adev->handle, "_DEP")) 18518c2ecf20Sopenharmony_ci return; 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci status = acpi_evaluate_reference(adev->handle, "_DEP", NULL, 18548c2ecf20Sopenharmony_ci &dep_devices); 18558c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 18568c2ecf20Sopenharmony_ci dev_dbg(&adev->dev, "Failed to evaluate _DEP.\n"); 18578c2ecf20Sopenharmony_ci return; 18588c2ecf20Sopenharmony_ci } 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci for (i = 0; i < dep_devices.count; i++) { 18618c2ecf20Sopenharmony_ci struct acpi_device_info *info; 18628c2ecf20Sopenharmony_ci int skip; 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci status = acpi_get_object_info(dep_devices.handles[i], &info); 18658c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 18668c2ecf20Sopenharmony_ci dev_dbg(&adev->dev, "Error reading _DEP device info\n"); 18678c2ecf20Sopenharmony_ci continue; 18688c2ecf20Sopenharmony_ci } 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci /* 18718c2ecf20Sopenharmony_ci * Skip the dependency of Windows System Power 18728c2ecf20Sopenharmony_ci * Management Controller 18738c2ecf20Sopenharmony_ci */ 18748c2ecf20Sopenharmony_ci skip = info->valid & ACPI_VALID_HID && 18758c2ecf20Sopenharmony_ci !strcmp(info->hardware_id.string, "INT3396"); 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci kfree(info); 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci if (skip) 18808c2ecf20Sopenharmony_ci continue; 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci dep = kzalloc(sizeof(struct acpi_dep_data), GFP_KERNEL); 18838c2ecf20Sopenharmony_ci if (!dep) 18848c2ecf20Sopenharmony_ci return; 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci dep->master = dep_devices.handles[i]; 18878c2ecf20Sopenharmony_ci dep->slave = adev->handle; 18888c2ecf20Sopenharmony_ci adev->dep_unmet++; 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci mutex_lock(&acpi_dep_list_lock); 18918c2ecf20Sopenharmony_ci list_add_tail(&dep->node , &acpi_dep_list); 18928c2ecf20Sopenharmony_ci mutex_unlock(&acpi_dep_list_lock); 18938c2ecf20Sopenharmony_ci } 18948c2ecf20Sopenharmony_ci} 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_cistatic acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, 18978c2ecf20Sopenharmony_ci void *not_used, void **return_value) 18988c2ecf20Sopenharmony_ci{ 18998c2ecf20Sopenharmony_ci struct acpi_device *device = NULL; 19008c2ecf20Sopenharmony_ci int type; 19018c2ecf20Sopenharmony_ci unsigned long long sta; 19028c2ecf20Sopenharmony_ci int result; 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci acpi_bus_get_device(handle, &device); 19058c2ecf20Sopenharmony_ci if (device) 19068c2ecf20Sopenharmony_ci goto out; 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci result = acpi_bus_type_and_status(handle, &type, &sta); 19098c2ecf20Sopenharmony_ci if (result) 19108c2ecf20Sopenharmony_ci return AE_OK; 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci if (type == ACPI_BUS_TYPE_POWER) { 19138c2ecf20Sopenharmony_ci acpi_add_power_resource(handle); 19148c2ecf20Sopenharmony_ci return AE_OK; 19158c2ecf20Sopenharmony_ci } 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci acpi_add_single_object(&device, handle, type, sta); 19188c2ecf20Sopenharmony_ci if (!device) 19198c2ecf20Sopenharmony_ci return AE_CTRL_DEPTH; 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ci acpi_scan_init_hotplug(device); 19228c2ecf20Sopenharmony_ci acpi_device_dep_initialize(device); 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci out: 19258c2ecf20Sopenharmony_ci if (!*return_value) 19268c2ecf20Sopenharmony_ci *return_value = device; 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci return AE_OK; 19298c2ecf20Sopenharmony_ci} 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_cistatic void acpi_default_enumeration(struct acpi_device *device) 19328c2ecf20Sopenharmony_ci{ 19338c2ecf20Sopenharmony_ci /* 19348c2ecf20Sopenharmony_ci * Do not enumerate devices with enumeration_by_parent flag set as 19358c2ecf20Sopenharmony_ci * they will be enumerated by their respective parents. 19368c2ecf20Sopenharmony_ci */ 19378c2ecf20Sopenharmony_ci if (!device->flags.enumeration_by_parent) { 19388c2ecf20Sopenharmony_ci acpi_create_platform_device(device, NULL); 19398c2ecf20Sopenharmony_ci acpi_device_set_enumerated(device); 19408c2ecf20Sopenharmony_ci } else { 19418c2ecf20Sopenharmony_ci blocking_notifier_call_chain(&acpi_reconfig_chain, 19428c2ecf20Sopenharmony_ci ACPI_RECONFIG_DEVICE_ADD, device); 19438c2ecf20Sopenharmony_ci } 19448c2ecf20Sopenharmony_ci} 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_cistatic const struct acpi_device_id generic_device_ids[] = { 19478c2ecf20Sopenharmony_ci {ACPI_DT_NAMESPACE_HID, }, 19488c2ecf20Sopenharmony_ci {"", }, 19498c2ecf20Sopenharmony_ci}; 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_cistatic int acpi_generic_device_attach(struct acpi_device *adev, 19528c2ecf20Sopenharmony_ci const struct acpi_device_id *not_used) 19538c2ecf20Sopenharmony_ci{ 19548c2ecf20Sopenharmony_ci /* 19558c2ecf20Sopenharmony_ci * Since ACPI_DT_NAMESPACE_HID is the only ID handled here, the test 19568c2ecf20Sopenharmony_ci * below can be unconditional. 19578c2ecf20Sopenharmony_ci */ 19588c2ecf20Sopenharmony_ci if (adev->data.of_compatible) 19598c2ecf20Sopenharmony_ci acpi_default_enumeration(adev); 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci return 1; 19628c2ecf20Sopenharmony_ci} 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_cistatic struct acpi_scan_handler generic_device_handler = { 19658c2ecf20Sopenharmony_ci .ids = generic_device_ids, 19668c2ecf20Sopenharmony_ci .attach = acpi_generic_device_attach, 19678c2ecf20Sopenharmony_ci}; 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_cistatic int acpi_scan_attach_handler(struct acpi_device *device) 19708c2ecf20Sopenharmony_ci{ 19718c2ecf20Sopenharmony_ci struct acpi_hardware_id *hwid; 19728c2ecf20Sopenharmony_ci int ret = 0; 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci list_for_each_entry(hwid, &device->pnp.ids, list) { 19758c2ecf20Sopenharmony_ci const struct acpi_device_id *devid; 19768c2ecf20Sopenharmony_ci struct acpi_scan_handler *handler; 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci handler = acpi_scan_match_handler(hwid->id, &devid); 19798c2ecf20Sopenharmony_ci if (handler) { 19808c2ecf20Sopenharmony_ci if (!handler->attach) { 19818c2ecf20Sopenharmony_ci device->pnp.type.platform_id = 0; 19828c2ecf20Sopenharmony_ci continue; 19838c2ecf20Sopenharmony_ci } 19848c2ecf20Sopenharmony_ci device->handler = handler; 19858c2ecf20Sopenharmony_ci ret = handler->attach(device, devid); 19868c2ecf20Sopenharmony_ci if (ret > 0) 19878c2ecf20Sopenharmony_ci break; 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ci device->handler = NULL; 19908c2ecf20Sopenharmony_ci if (ret < 0) 19918c2ecf20Sopenharmony_ci break; 19928c2ecf20Sopenharmony_ci } 19938c2ecf20Sopenharmony_ci } 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci return ret; 19968c2ecf20Sopenharmony_ci} 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_cistatic void acpi_bus_attach(struct acpi_device *device) 19998c2ecf20Sopenharmony_ci{ 20008c2ecf20Sopenharmony_ci struct acpi_device *child; 20018c2ecf20Sopenharmony_ci acpi_handle ejd; 20028c2ecf20Sopenharmony_ci int ret; 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(acpi_bus_get_ejd(device->handle, &ejd))) 20058c2ecf20Sopenharmony_ci register_dock_dependent_device(device, ejd); 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci acpi_bus_get_status(device); 20088c2ecf20Sopenharmony_ci /* Skip devices that are not present. */ 20098c2ecf20Sopenharmony_ci if (!acpi_device_is_present(device)) { 20108c2ecf20Sopenharmony_ci device->flags.initialized = false; 20118c2ecf20Sopenharmony_ci acpi_device_clear_enumerated(device); 20128c2ecf20Sopenharmony_ci device->flags.power_manageable = 0; 20138c2ecf20Sopenharmony_ci return; 20148c2ecf20Sopenharmony_ci } 20158c2ecf20Sopenharmony_ci if (device->handler) 20168c2ecf20Sopenharmony_ci goto ok; 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci if (!device->flags.initialized) { 20198c2ecf20Sopenharmony_ci device->flags.power_manageable = 20208c2ecf20Sopenharmony_ci device->power.states[ACPI_STATE_D0].flags.valid; 20218c2ecf20Sopenharmony_ci if (acpi_bus_init_power(device)) 20228c2ecf20Sopenharmony_ci device->flags.power_manageable = 0; 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci device->flags.initialized = true; 20258c2ecf20Sopenharmony_ci } else if (device->flags.visited) { 20268c2ecf20Sopenharmony_ci goto ok; 20278c2ecf20Sopenharmony_ci } 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci ret = acpi_scan_attach_handler(device); 20308c2ecf20Sopenharmony_ci if (ret < 0) 20318c2ecf20Sopenharmony_ci return; 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci device->flags.match_driver = true; 20348c2ecf20Sopenharmony_ci if (ret > 0 && !device->flags.enumeration_by_parent) { 20358c2ecf20Sopenharmony_ci acpi_device_set_enumerated(device); 20368c2ecf20Sopenharmony_ci goto ok; 20378c2ecf20Sopenharmony_ci } 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_ci ret = device_attach(&device->dev); 20408c2ecf20Sopenharmony_ci if (ret < 0) 20418c2ecf20Sopenharmony_ci return; 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_ci if (device->pnp.type.platform_id || device->flags.enumeration_by_parent) 20448c2ecf20Sopenharmony_ci acpi_default_enumeration(device); 20458c2ecf20Sopenharmony_ci else 20468c2ecf20Sopenharmony_ci acpi_device_set_enumerated(device); 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci ok: 20498c2ecf20Sopenharmony_ci list_for_each_entry(child, &device->children, node) 20508c2ecf20Sopenharmony_ci acpi_bus_attach(child); 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci if (device->handler && device->handler->hotplug.notify_online) 20538c2ecf20Sopenharmony_ci device->handler->hotplug.notify_online(device); 20548c2ecf20Sopenharmony_ci} 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_civoid acpi_walk_dep_device_list(acpi_handle handle) 20578c2ecf20Sopenharmony_ci{ 20588c2ecf20Sopenharmony_ci struct acpi_dep_data *dep, *tmp; 20598c2ecf20Sopenharmony_ci struct acpi_device *adev; 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_ci mutex_lock(&acpi_dep_list_lock); 20628c2ecf20Sopenharmony_ci list_for_each_entry_safe(dep, tmp, &acpi_dep_list, node) { 20638c2ecf20Sopenharmony_ci if (dep->master == handle) { 20648c2ecf20Sopenharmony_ci acpi_bus_get_device(dep->slave, &adev); 20658c2ecf20Sopenharmony_ci if (!adev) 20668c2ecf20Sopenharmony_ci continue; 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ci adev->dep_unmet--; 20698c2ecf20Sopenharmony_ci if (!adev->dep_unmet) 20708c2ecf20Sopenharmony_ci acpi_bus_attach(adev); 20718c2ecf20Sopenharmony_ci list_del(&dep->node); 20728c2ecf20Sopenharmony_ci kfree(dep); 20738c2ecf20Sopenharmony_ci } 20748c2ecf20Sopenharmony_ci } 20758c2ecf20Sopenharmony_ci mutex_unlock(&acpi_dep_list_lock); 20768c2ecf20Sopenharmony_ci} 20778c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_walk_dep_device_list); 20788c2ecf20Sopenharmony_ci 20798c2ecf20Sopenharmony_ci/** 20808c2ecf20Sopenharmony_ci * acpi_bus_scan - Add ACPI device node objects in a given namespace scope. 20818c2ecf20Sopenharmony_ci * @handle: Root of the namespace scope to scan. 20828c2ecf20Sopenharmony_ci * 20838c2ecf20Sopenharmony_ci * Scan a given ACPI tree (probably recently hot-plugged) and create and add 20848c2ecf20Sopenharmony_ci * found devices. 20858c2ecf20Sopenharmony_ci * 20868c2ecf20Sopenharmony_ci * If no devices were found, -ENODEV is returned, but it does not mean that 20878c2ecf20Sopenharmony_ci * there has been a real error. There just have been no suitable ACPI objects 20888c2ecf20Sopenharmony_ci * in the table trunk from which the kernel could create a device and add an 20898c2ecf20Sopenharmony_ci * appropriate driver. 20908c2ecf20Sopenharmony_ci * 20918c2ecf20Sopenharmony_ci * Must be called under acpi_scan_lock. 20928c2ecf20Sopenharmony_ci */ 20938c2ecf20Sopenharmony_ciint acpi_bus_scan(acpi_handle handle) 20948c2ecf20Sopenharmony_ci{ 20958c2ecf20Sopenharmony_ci void *device = NULL; 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(acpi_bus_check_add(handle, 0, NULL, &device))) 20988c2ecf20Sopenharmony_ci acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, 20998c2ecf20Sopenharmony_ci acpi_bus_check_add, NULL, NULL, &device); 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci if (device) { 21028c2ecf20Sopenharmony_ci acpi_bus_attach(device); 21038c2ecf20Sopenharmony_ci return 0; 21048c2ecf20Sopenharmony_ci } 21058c2ecf20Sopenharmony_ci return -ENODEV; 21068c2ecf20Sopenharmony_ci} 21078c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_bus_scan); 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci/** 21108c2ecf20Sopenharmony_ci * acpi_bus_trim - Detach scan handlers and drivers from ACPI device objects. 21118c2ecf20Sopenharmony_ci * @adev: Root of the ACPI namespace scope to walk. 21128c2ecf20Sopenharmony_ci * 21138c2ecf20Sopenharmony_ci * Must be called under acpi_scan_lock. 21148c2ecf20Sopenharmony_ci */ 21158c2ecf20Sopenharmony_civoid acpi_bus_trim(struct acpi_device *adev) 21168c2ecf20Sopenharmony_ci{ 21178c2ecf20Sopenharmony_ci struct acpi_scan_handler *handler = adev->handler; 21188c2ecf20Sopenharmony_ci struct acpi_device *child; 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci list_for_each_entry_reverse(child, &adev->children, node) 21218c2ecf20Sopenharmony_ci acpi_bus_trim(child); 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_ci adev->flags.match_driver = false; 21248c2ecf20Sopenharmony_ci if (handler) { 21258c2ecf20Sopenharmony_ci if (handler->detach) 21268c2ecf20Sopenharmony_ci handler->detach(adev); 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ci adev->handler = NULL; 21298c2ecf20Sopenharmony_ci } else { 21308c2ecf20Sopenharmony_ci device_release_driver(&adev->dev); 21318c2ecf20Sopenharmony_ci } 21328c2ecf20Sopenharmony_ci /* 21338c2ecf20Sopenharmony_ci * Most likely, the device is going away, so put it into D3cold before 21348c2ecf20Sopenharmony_ci * that. 21358c2ecf20Sopenharmony_ci */ 21368c2ecf20Sopenharmony_ci acpi_device_set_power(adev, ACPI_STATE_D3_COLD); 21378c2ecf20Sopenharmony_ci adev->flags.initialized = false; 21388c2ecf20Sopenharmony_ci acpi_device_clear_enumerated(adev); 21398c2ecf20Sopenharmony_ci} 21408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_bus_trim); 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ciint acpi_bus_register_early_device(int type) 21438c2ecf20Sopenharmony_ci{ 21448c2ecf20Sopenharmony_ci struct acpi_device *device = NULL; 21458c2ecf20Sopenharmony_ci int result; 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci result = acpi_add_single_object(&device, NULL, 21488c2ecf20Sopenharmony_ci type, ACPI_STA_DEFAULT); 21498c2ecf20Sopenharmony_ci if (result) 21508c2ecf20Sopenharmony_ci return result; 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci device->flags.match_driver = true; 21538c2ecf20Sopenharmony_ci return device_attach(&device->dev); 21548c2ecf20Sopenharmony_ci} 21558c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_bus_register_early_device); 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_cistatic int acpi_bus_scan_fixed(void) 21588c2ecf20Sopenharmony_ci{ 21598c2ecf20Sopenharmony_ci int result = 0; 21608c2ecf20Sopenharmony_ci 21618c2ecf20Sopenharmony_ci /* 21628c2ecf20Sopenharmony_ci * Enumerate all fixed-feature devices. 21638c2ecf20Sopenharmony_ci */ 21648c2ecf20Sopenharmony_ci if (!(acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON)) { 21658c2ecf20Sopenharmony_ci struct acpi_device *device = NULL; 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci result = acpi_add_single_object(&device, NULL, 21688c2ecf20Sopenharmony_ci ACPI_BUS_TYPE_POWER_BUTTON, 21698c2ecf20Sopenharmony_ci ACPI_STA_DEFAULT); 21708c2ecf20Sopenharmony_ci if (result) 21718c2ecf20Sopenharmony_ci return result; 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci device->flags.match_driver = true; 21748c2ecf20Sopenharmony_ci result = device_attach(&device->dev); 21758c2ecf20Sopenharmony_ci if (result < 0) 21768c2ecf20Sopenharmony_ci return result; 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci device_init_wakeup(&device->dev, true); 21798c2ecf20Sopenharmony_ci } 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_ci if (!(acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON)) { 21828c2ecf20Sopenharmony_ci struct acpi_device *device = NULL; 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci result = acpi_add_single_object(&device, NULL, 21858c2ecf20Sopenharmony_ci ACPI_BUS_TYPE_SLEEP_BUTTON, 21868c2ecf20Sopenharmony_ci ACPI_STA_DEFAULT); 21878c2ecf20Sopenharmony_ci if (result) 21888c2ecf20Sopenharmony_ci return result; 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ci device->flags.match_driver = true; 21918c2ecf20Sopenharmony_ci result = device_attach(&device->dev); 21928c2ecf20Sopenharmony_ci } 21938c2ecf20Sopenharmony_ci 21948c2ecf20Sopenharmony_ci return result < 0 ? result : 0; 21958c2ecf20Sopenharmony_ci} 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_cistatic void __init acpi_get_spcr_uart_addr(void) 21988c2ecf20Sopenharmony_ci{ 21998c2ecf20Sopenharmony_ci acpi_status status; 22008c2ecf20Sopenharmony_ci struct acpi_table_spcr *spcr_ptr; 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_ci status = acpi_get_table(ACPI_SIG_SPCR, 0, 22038c2ecf20Sopenharmony_ci (struct acpi_table_header **)&spcr_ptr); 22048c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 22058c2ecf20Sopenharmony_ci pr_warn(PREFIX "STAO table present, but SPCR is missing\n"); 22068c2ecf20Sopenharmony_ci return; 22078c2ecf20Sopenharmony_ci } 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci spcr_uart_addr = spcr_ptr->serial_port.address; 22108c2ecf20Sopenharmony_ci acpi_put_table((struct acpi_table_header *)spcr_ptr); 22118c2ecf20Sopenharmony_ci} 22128c2ecf20Sopenharmony_ci 22138c2ecf20Sopenharmony_cistatic bool acpi_scan_initialized; 22148c2ecf20Sopenharmony_ci 22158c2ecf20Sopenharmony_ciint __init acpi_scan_init(void) 22168c2ecf20Sopenharmony_ci{ 22178c2ecf20Sopenharmony_ci int result; 22188c2ecf20Sopenharmony_ci acpi_status status; 22198c2ecf20Sopenharmony_ci struct acpi_table_stao *stao_ptr; 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ci acpi_pci_root_init(); 22228c2ecf20Sopenharmony_ci acpi_pci_link_init(); 22238c2ecf20Sopenharmony_ci acpi_processor_init(); 22248c2ecf20Sopenharmony_ci acpi_platform_init(); 22258c2ecf20Sopenharmony_ci acpi_lpss_init(); 22268c2ecf20Sopenharmony_ci acpi_apd_init(); 22278c2ecf20Sopenharmony_ci acpi_cmos_rtc_init(); 22288c2ecf20Sopenharmony_ci acpi_container_init(); 22298c2ecf20Sopenharmony_ci acpi_memory_hotplug_init(); 22308c2ecf20Sopenharmony_ci acpi_watchdog_init(); 22318c2ecf20Sopenharmony_ci acpi_pnp_init(); 22328c2ecf20Sopenharmony_ci acpi_int340x_thermal_init(); 22338c2ecf20Sopenharmony_ci acpi_amba_init(); 22348c2ecf20Sopenharmony_ci acpi_init_lpit(); 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ci acpi_scan_add_handler(&generic_device_handler); 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_ci /* 22398c2ecf20Sopenharmony_ci * If there is STAO table, check whether it needs to ignore the UART 22408c2ecf20Sopenharmony_ci * device in SPCR table. 22418c2ecf20Sopenharmony_ci */ 22428c2ecf20Sopenharmony_ci status = acpi_get_table(ACPI_SIG_STAO, 0, 22438c2ecf20Sopenharmony_ci (struct acpi_table_header **)&stao_ptr); 22448c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(status)) { 22458c2ecf20Sopenharmony_ci if (stao_ptr->header.length > sizeof(struct acpi_table_stao)) 22468c2ecf20Sopenharmony_ci pr_info(PREFIX "STAO Name List not yet supported.\n"); 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_ci if (stao_ptr->ignore_uart) 22498c2ecf20Sopenharmony_ci acpi_get_spcr_uart_addr(); 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci acpi_put_table((struct acpi_table_header *)stao_ptr); 22528c2ecf20Sopenharmony_ci } 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci acpi_gpe_apply_masked_gpes(); 22558c2ecf20Sopenharmony_ci acpi_update_all_gpes(); 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_ci /* 22588c2ecf20Sopenharmony_ci * Although we call __add_memory() that is documented to require the 22598c2ecf20Sopenharmony_ci * device_hotplug_lock, it is not necessary here because this is an 22608c2ecf20Sopenharmony_ci * early code when userspace or any other code path cannot trigger 22618c2ecf20Sopenharmony_ci * hotplug/hotunplug operations. 22628c2ecf20Sopenharmony_ci */ 22638c2ecf20Sopenharmony_ci mutex_lock(&acpi_scan_lock); 22648c2ecf20Sopenharmony_ci /* 22658c2ecf20Sopenharmony_ci * Enumerate devices in the ACPI namespace. 22668c2ecf20Sopenharmony_ci */ 22678c2ecf20Sopenharmony_ci result = acpi_bus_scan(ACPI_ROOT_OBJECT); 22688c2ecf20Sopenharmony_ci if (result) 22698c2ecf20Sopenharmony_ci goto out; 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci result = acpi_bus_get_device(ACPI_ROOT_OBJECT, &acpi_root); 22728c2ecf20Sopenharmony_ci if (result) 22738c2ecf20Sopenharmony_ci goto out; 22748c2ecf20Sopenharmony_ci 22758c2ecf20Sopenharmony_ci /* Fixed feature devices do not exist on HW-reduced platform */ 22768c2ecf20Sopenharmony_ci if (!acpi_gbl_reduced_hardware) { 22778c2ecf20Sopenharmony_ci result = acpi_bus_scan_fixed(); 22788c2ecf20Sopenharmony_ci if (result) { 22798c2ecf20Sopenharmony_ci acpi_detach_data(acpi_root->handle, 22808c2ecf20Sopenharmony_ci acpi_scan_drop_device); 22818c2ecf20Sopenharmony_ci acpi_device_del(acpi_root); 22828c2ecf20Sopenharmony_ci put_device(&acpi_root->dev); 22838c2ecf20Sopenharmony_ci goto out; 22848c2ecf20Sopenharmony_ci } 22858c2ecf20Sopenharmony_ci } 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci acpi_scan_initialized = true; 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci out: 22908c2ecf20Sopenharmony_ci mutex_unlock(&acpi_scan_lock); 22918c2ecf20Sopenharmony_ci return result; 22928c2ecf20Sopenharmony_ci} 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_cistatic struct acpi_probe_entry *ape; 22958c2ecf20Sopenharmony_cistatic int acpi_probe_count; 22968c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(acpi_probe_mutex); 22978c2ecf20Sopenharmony_ci 22988c2ecf20Sopenharmony_cistatic int __init acpi_match_madt(union acpi_subtable_headers *header, 22998c2ecf20Sopenharmony_ci const unsigned long end) 23008c2ecf20Sopenharmony_ci{ 23018c2ecf20Sopenharmony_ci if (!ape->subtable_valid || ape->subtable_valid(&header->common, ape)) 23028c2ecf20Sopenharmony_ci if (!ape->probe_subtbl(header, end)) 23038c2ecf20Sopenharmony_ci acpi_probe_count++; 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_ci return 0; 23068c2ecf20Sopenharmony_ci} 23078c2ecf20Sopenharmony_ci 23088c2ecf20Sopenharmony_ciint __init __acpi_probe_device_table(struct acpi_probe_entry *ap_head, int nr) 23098c2ecf20Sopenharmony_ci{ 23108c2ecf20Sopenharmony_ci int count = 0; 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_ci if (acpi_disabled) 23138c2ecf20Sopenharmony_ci return 0; 23148c2ecf20Sopenharmony_ci 23158c2ecf20Sopenharmony_ci mutex_lock(&acpi_probe_mutex); 23168c2ecf20Sopenharmony_ci for (ape = ap_head; nr; ape++, nr--) { 23178c2ecf20Sopenharmony_ci if (ACPI_COMPARE_NAMESEG(ACPI_SIG_MADT, ape->id)) { 23188c2ecf20Sopenharmony_ci acpi_probe_count = 0; 23198c2ecf20Sopenharmony_ci acpi_table_parse_madt(ape->type, acpi_match_madt, 0); 23208c2ecf20Sopenharmony_ci count += acpi_probe_count; 23218c2ecf20Sopenharmony_ci } else { 23228c2ecf20Sopenharmony_ci int res; 23238c2ecf20Sopenharmony_ci res = acpi_table_parse(ape->id, ape->probe_table); 23248c2ecf20Sopenharmony_ci if (!res) 23258c2ecf20Sopenharmony_ci count++; 23268c2ecf20Sopenharmony_ci } 23278c2ecf20Sopenharmony_ci } 23288c2ecf20Sopenharmony_ci mutex_unlock(&acpi_probe_mutex); 23298c2ecf20Sopenharmony_ci 23308c2ecf20Sopenharmony_ci return count; 23318c2ecf20Sopenharmony_ci} 23328c2ecf20Sopenharmony_ci 23338c2ecf20Sopenharmony_cistruct acpi_table_events_work { 23348c2ecf20Sopenharmony_ci struct work_struct work; 23358c2ecf20Sopenharmony_ci void *table; 23368c2ecf20Sopenharmony_ci u32 event; 23378c2ecf20Sopenharmony_ci}; 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_cistatic void acpi_table_events_fn(struct work_struct *work) 23408c2ecf20Sopenharmony_ci{ 23418c2ecf20Sopenharmony_ci struct acpi_table_events_work *tew; 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_ci tew = container_of(work, struct acpi_table_events_work, work); 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_ci if (tew->event == ACPI_TABLE_EVENT_LOAD) { 23468c2ecf20Sopenharmony_ci acpi_scan_lock_acquire(); 23478c2ecf20Sopenharmony_ci acpi_bus_scan(ACPI_ROOT_OBJECT); 23488c2ecf20Sopenharmony_ci acpi_scan_lock_release(); 23498c2ecf20Sopenharmony_ci } 23508c2ecf20Sopenharmony_ci 23518c2ecf20Sopenharmony_ci kfree(tew); 23528c2ecf20Sopenharmony_ci} 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_civoid acpi_scan_table_handler(u32 event, void *table, void *context) 23558c2ecf20Sopenharmony_ci{ 23568c2ecf20Sopenharmony_ci struct acpi_table_events_work *tew; 23578c2ecf20Sopenharmony_ci 23588c2ecf20Sopenharmony_ci if (!acpi_scan_initialized) 23598c2ecf20Sopenharmony_ci return; 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_ci if (event != ACPI_TABLE_EVENT_LOAD) 23628c2ecf20Sopenharmony_ci return; 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci tew = kmalloc(sizeof(*tew), GFP_KERNEL); 23658c2ecf20Sopenharmony_ci if (!tew) 23668c2ecf20Sopenharmony_ci return; 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci INIT_WORK(&tew->work, acpi_table_events_fn); 23698c2ecf20Sopenharmony_ci tew->table = table; 23708c2ecf20Sopenharmony_ci tew->event = event; 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci schedule_work(&tew->work); 23738c2ecf20Sopenharmony_ci} 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_ciint acpi_reconfig_notifier_register(struct notifier_block *nb) 23768c2ecf20Sopenharmony_ci{ 23778c2ecf20Sopenharmony_ci return blocking_notifier_chain_register(&acpi_reconfig_chain, nb); 23788c2ecf20Sopenharmony_ci} 23798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_reconfig_notifier_register); 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_ciint acpi_reconfig_notifier_unregister(struct notifier_block *nb) 23828c2ecf20Sopenharmony_ci{ 23838c2ecf20Sopenharmony_ci return blocking_notifier_chain_unregister(&acpi_reconfig_chain, nb); 23848c2ecf20Sopenharmony_ci} 23858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_reconfig_notifier_unregister); 2386