xref: /kernel/linux/linux-5.10/drivers/acpi/glue.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Link physical devices with ACPI devices support
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2005 David Shaohua Li <shaohua.li@intel.com>
68c2ecf20Sopenharmony_ci * Copyright (c) 2005 Intel Corp.
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/acpi_iort.h>
108c2ecf20Sopenharmony_ci#include <linux/export.h>
118c2ecf20Sopenharmony_ci#include <linux/init.h>
128c2ecf20Sopenharmony_ci#include <linux/list.h>
138c2ecf20Sopenharmony_ci#include <linux/device.h>
148c2ecf20Sopenharmony_ci#include <linux/slab.h>
158c2ecf20Sopenharmony_ci#include <linux/rwsem.h>
168c2ecf20Sopenharmony_ci#include <linux/acpi.h>
178c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
188c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include "internal.h"
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define ACPI_GLUE_DEBUG	0
238c2ecf20Sopenharmony_ci#if ACPI_GLUE_DEBUG
248c2ecf20Sopenharmony_ci#define DBG(fmt, ...)						\
258c2ecf20Sopenharmony_ci	printk(KERN_DEBUG PREFIX fmt, ##__VA_ARGS__)
268c2ecf20Sopenharmony_ci#else
278c2ecf20Sopenharmony_ci#define DBG(fmt, ...)						\
288c2ecf20Sopenharmony_cido {								\
298c2ecf20Sopenharmony_ci	if (0)							\
308c2ecf20Sopenharmony_ci		printk(KERN_DEBUG PREFIX fmt, ##__VA_ARGS__);	\
318c2ecf20Sopenharmony_ci} while (0)
328c2ecf20Sopenharmony_ci#endif
338c2ecf20Sopenharmony_cistatic LIST_HEAD(bus_type_list);
348c2ecf20Sopenharmony_cistatic DECLARE_RWSEM(bus_type_sem);
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define PHYSICAL_NODE_STRING "physical_node"
378c2ecf20Sopenharmony_ci#define PHYSICAL_NODE_NAME_SIZE (sizeof(PHYSICAL_NODE_STRING) + 10)
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ciint register_acpi_bus_type(struct acpi_bus_type *type)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	if (acpi_disabled)
428c2ecf20Sopenharmony_ci		return -ENODEV;
438c2ecf20Sopenharmony_ci	if (type && type->match && type->find_companion) {
448c2ecf20Sopenharmony_ci		down_write(&bus_type_sem);
458c2ecf20Sopenharmony_ci		list_add_tail(&type->list, &bus_type_list);
468c2ecf20Sopenharmony_ci		up_write(&bus_type_sem);
478c2ecf20Sopenharmony_ci		printk(KERN_INFO PREFIX "bus type %s registered\n", type->name);
488c2ecf20Sopenharmony_ci		return 0;
498c2ecf20Sopenharmony_ci	}
508c2ecf20Sopenharmony_ci	return -ENODEV;
518c2ecf20Sopenharmony_ci}
528c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(register_acpi_bus_type);
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ciint unregister_acpi_bus_type(struct acpi_bus_type *type)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	if (acpi_disabled)
578c2ecf20Sopenharmony_ci		return 0;
588c2ecf20Sopenharmony_ci	if (type) {
598c2ecf20Sopenharmony_ci		down_write(&bus_type_sem);
608c2ecf20Sopenharmony_ci		list_del_init(&type->list);
618c2ecf20Sopenharmony_ci		up_write(&bus_type_sem);
628c2ecf20Sopenharmony_ci		printk(KERN_INFO PREFIX "bus type %s unregistered\n",
638c2ecf20Sopenharmony_ci		       type->name);
648c2ecf20Sopenharmony_ci		return 0;
658c2ecf20Sopenharmony_ci	}
668c2ecf20Sopenharmony_ci	return -ENODEV;
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(unregister_acpi_bus_type);
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic struct acpi_bus_type *acpi_get_bus_type(struct device *dev)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	struct acpi_bus_type *tmp, *ret = NULL;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	down_read(&bus_type_sem);
758c2ecf20Sopenharmony_ci	list_for_each_entry(tmp, &bus_type_list, list) {
768c2ecf20Sopenharmony_ci		if (tmp->match(dev)) {
778c2ecf20Sopenharmony_ci			ret = tmp;
788c2ecf20Sopenharmony_ci			break;
798c2ecf20Sopenharmony_ci		}
808c2ecf20Sopenharmony_ci	}
818c2ecf20Sopenharmony_ci	up_read(&bus_type_sem);
828c2ecf20Sopenharmony_ci	return ret;
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci#define FIND_CHILD_MIN_SCORE	1
868c2ecf20Sopenharmony_ci#define FIND_CHILD_MAX_SCORE	2
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic int find_child_checks(struct acpi_device *adev, bool check_children)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	bool sta_present = true;
918c2ecf20Sopenharmony_ci	unsigned long long sta;
928c2ecf20Sopenharmony_ci	acpi_status status;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta);
958c2ecf20Sopenharmony_ci	if (status == AE_NOT_FOUND)
968c2ecf20Sopenharmony_ci		sta_present = false;
978c2ecf20Sopenharmony_ci	else if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED))
988c2ecf20Sopenharmony_ci		return -ENODEV;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	if (check_children && list_empty(&adev->children))
1018c2ecf20Sopenharmony_ci		return -ENODEV;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	/*
1048c2ecf20Sopenharmony_ci	 * If the device has a _HID returning a valid ACPI/PNP device ID, it is
1058c2ecf20Sopenharmony_ci	 * better to make it look less attractive here, so that the other device
1068c2ecf20Sopenharmony_ci	 * with the same _ADR value (that may not have a valid device ID) can be
1078c2ecf20Sopenharmony_ci	 * matched going forward.  [This means a second spec violation in a row,
1088c2ecf20Sopenharmony_ci	 * so whatever we do here is best effort anyway.]
1098c2ecf20Sopenharmony_ci	 */
1108c2ecf20Sopenharmony_ci	return sta_present && !adev->pnp.type.platform_id ?
1118c2ecf20Sopenharmony_ci			FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE;
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistruct acpi_device *acpi_find_child_device(struct acpi_device *parent,
1158c2ecf20Sopenharmony_ci					   u64 address, bool check_children)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	struct acpi_device *adev, *ret = NULL;
1188c2ecf20Sopenharmony_ci	int ret_score = 0;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	if (!parent)
1218c2ecf20Sopenharmony_ci		return NULL;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	list_for_each_entry(adev, &parent->children, node) {
1248c2ecf20Sopenharmony_ci		unsigned long long addr;
1258c2ecf20Sopenharmony_ci		acpi_status status;
1268c2ecf20Sopenharmony_ci		int score;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci		status = acpi_evaluate_integer(adev->handle, METHOD_NAME__ADR,
1298c2ecf20Sopenharmony_ci					       NULL, &addr);
1308c2ecf20Sopenharmony_ci		if (ACPI_FAILURE(status) || addr != address)
1318c2ecf20Sopenharmony_ci			continue;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci		if (!ret) {
1348c2ecf20Sopenharmony_ci			/* This is the first matching object.  Save it. */
1358c2ecf20Sopenharmony_ci			ret = adev;
1368c2ecf20Sopenharmony_ci			continue;
1378c2ecf20Sopenharmony_ci		}
1388c2ecf20Sopenharmony_ci		/*
1398c2ecf20Sopenharmony_ci		 * There is more than one matching device object with the same
1408c2ecf20Sopenharmony_ci		 * _ADR value.  That really is unexpected, so we are kind of
1418c2ecf20Sopenharmony_ci		 * beyond the scope of the spec here.  We have to choose which
1428c2ecf20Sopenharmony_ci		 * one to return, though.
1438c2ecf20Sopenharmony_ci		 *
1448c2ecf20Sopenharmony_ci		 * First, check if the previously found object is good enough
1458c2ecf20Sopenharmony_ci		 * and return it if so.  Second, do the same for the object that
1468c2ecf20Sopenharmony_ci		 * we've just found.
1478c2ecf20Sopenharmony_ci		 */
1488c2ecf20Sopenharmony_ci		if (!ret_score) {
1498c2ecf20Sopenharmony_ci			ret_score = find_child_checks(ret, check_children);
1508c2ecf20Sopenharmony_ci			if (ret_score == FIND_CHILD_MAX_SCORE)
1518c2ecf20Sopenharmony_ci				return ret;
1528c2ecf20Sopenharmony_ci		}
1538c2ecf20Sopenharmony_ci		score = find_child_checks(adev, check_children);
1548c2ecf20Sopenharmony_ci		if (score == FIND_CHILD_MAX_SCORE) {
1558c2ecf20Sopenharmony_ci			return adev;
1568c2ecf20Sopenharmony_ci		} else if (score > ret_score) {
1578c2ecf20Sopenharmony_ci			ret = adev;
1588c2ecf20Sopenharmony_ci			ret_score = score;
1598c2ecf20Sopenharmony_ci		}
1608c2ecf20Sopenharmony_ci	}
1618c2ecf20Sopenharmony_ci	return ret;
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_find_child_device);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_cistatic void acpi_physnode_link_name(char *buf, unsigned int node_id)
1668c2ecf20Sopenharmony_ci{
1678c2ecf20Sopenharmony_ci	if (node_id > 0)
1688c2ecf20Sopenharmony_ci		snprintf(buf, PHYSICAL_NODE_NAME_SIZE,
1698c2ecf20Sopenharmony_ci			 PHYSICAL_NODE_STRING "%u", node_id);
1708c2ecf20Sopenharmony_ci	else
1718c2ecf20Sopenharmony_ci		strcpy(buf, PHYSICAL_NODE_STRING);
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ciint acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	struct acpi_device_physical_node *physical_node, *pn;
1778c2ecf20Sopenharmony_ci	char physical_node_name[PHYSICAL_NODE_NAME_SIZE];
1788c2ecf20Sopenharmony_ci	struct list_head *physnode_list;
1798c2ecf20Sopenharmony_ci	unsigned int node_id;
1808c2ecf20Sopenharmony_ci	int retval = -EINVAL;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	if (has_acpi_companion(dev)) {
1838c2ecf20Sopenharmony_ci		if (acpi_dev) {
1848c2ecf20Sopenharmony_ci			dev_warn(dev, "ACPI companion already set\n");
1858c2ecf20Sopenharmony_ci			return -EINVAL;
1868c2ecf20Sopenharmony_ci		} else {
1878c2ecf20Sopenharmony_ci			acpi_dev = ACPI_COMPANION(dev);
1888c2ecf20Sopenharmony_ci		}
1898c2ecf20Sopenharmony_ci	}
1908c2ecf20Sopenharmony_ci	if (!acpi_dev)
1918c2ecf20Sopenharmony_ci		return -EINVAL;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	get_device(&acpi_dev->dev);
1948c2ecf20Sopenharmony_ci	get_device(dev);
1958c2ecf20Sopenharmony_ci	physical_node = kzalloc(sizeof(*physical_node), GFP_KERNEL);
1968c2ecf20Sopenharmony_ci	if (!physical_node) {
1978c2ecf20Sopenharmony_ci		retval = -ENOMEM;
1988c2ecf20Sopenharmony_ci		goto err;
1998c2ecf20Sopenharmony_ci	}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	mutex_lock(&acpi_dev->physical_node_lock);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	/*
2048c2ecf20Sopenharmony_ci	 * Keep the list sorted by node_id so that the IDs of removed nodes can
2058c2ecf20Sopenharmony_ci	 * be recycled easily.
2068c2ecf20Sopenharmony_ci	 */
2078c2ecf20Sopenharmony_ci	physnode_list = &acpi_dev->physical_node_list;
2088c2ecf20Sopenharmony_ci	node_id = 0;
2098c2ecf20Sopenharmony_ci	list_for_each_entry(pn, &acpi_dev->physical_node_list, node) {
2108c2ecf20Sopenharmony_ci		/* Sanity check. */
2118c2ecf20Sopenharmony_ci		if (pn->dev == dev) {
2128c2ecf20Sopenharmony_ci			mutex_unlock(&acpi_dev->physical_node_lock);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci			dev_warn(dev, "Already associated with ACPI node\n");
2158c2ecf20Sopenharmony_ci			kfree(physical_node);
2168c2ecf20Sopenharmony_ci			if (ACPI_COMPANION(dev) != acpi_dev)
2178c2ecf20Sopenharmony_ci				goto err;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci			put_device(dev);
2208c2ecf20Sopenharmony_ci			put_device(&acpi_dev->dev);
2218c2ecf20Sopenharmony_ci			return 0;
2228c2ecf20Sopenharmony_ci		}
2238c2ecf20Sopenharmony_ci		if (pn->node_id == node_id) {
2248c2ecf20Sopenharmony_ci			physnode_list = &pn->node;
2258c2ecf20Sopenharmony_ci			node_id++;
2268c2ecf20Sopenharmony_ci		}
2278c2ecf20Sopenharmony_ci	}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	physical_node->node_id = node_id;
2308c2ecf20Sopenharmony_ci	physical_node->dev = dev;
2318c2ecf20Sopenharmony_ci	list_add(&physical_node->node, physnode_list);
2328c2ecf20Sopenharmony_ci	acpi_dev->physical_node_count++;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	if (!has_acpi_companion(dev))
2358c2ecf20Sopenharmony_ci		ACPI_COMPANION_SET(dev, acpi_dev);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	acpi_physnode_link_name(physical_node_name, node_id);
2388c2ecf20Sopenharmony_ci	retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
2398c2ecf20Sopenharmony_ci				   physical_node_name);
2408c2ecf20Sopenharmony_ci	if (retval)
2418c2ecf20Sopenharmony_ci		dev_err(&acpi_dev->dev, "Failed to create link %s (%d)\n",
2428c2ecf20Sopenharmony_ci			physical_node_name, retval);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	retval = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj,
2458c2ecf20Sopenharmony_ci				   "firmware_node");
2468c2ecf20Sopenharmony_ci	if (retval)
2478c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to create link firmware_node (%d)\n",
2488c2ecf20Sopenharmony_ci			retval);
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	mutex_unlock(&acpi_dev->physical_node_lock);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	if (acpi_dev->wakeup.flags.valid)
2538c2ecf20Sopenharmony_ci		device_set_wakeup_capable(dev, true);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	return 0;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci err:
2588c2ecf20Sopenharmony_ci	ACPI_COMPANION_SET(dev, NULL);
2598c2ecf20Sopenharmony_ci	put_device(dev);
2608c2ecf20Sopenharmony_ci	put_device(&acpi_dev->dev);
2618c2ecf20Sopenharmony_ci	return retval;
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_bind_one);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ciint acpi_unbind_one(struct device *dev)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	struct acpi_device *acpi_dev = ACPI_COMPANION(dev);
2688c2ecf20Sopenharmony_ci	struct acpi_device_physical_node *entry;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	if (!acpi_dev)
2718c2ecf20Sopenharmony_ci		return 0;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	mutex_lock(&acpi_dev->physical_node_lock);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	list_for_each_entry(entry, &acpi_dev->physical_node_list, node)
2768c2ecf20Sopenharmony_ci		if (entry->dev == dev) {
2778c2ecf20Sopenharmony_ci			char physnode_name[PHYSICAL_NODE_NAME_SIZE];
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci			list_del(&entry->node);
2808c2ecf20Sopenharmony_ci			acpi_dev->physical_node_count--;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci			acpi_physnode_link_name(physnode_name, entry->node_id);
2838c2ecf20Sopenharmony_ci			sysfs_remove_link(&acpi_dev->dev.kobj, physnode_name);
2848c2ecf20Sopenharmony_ci			sysfs_remove_link(&dev->kobj, "firmware_node");
2858c2ecf20Sopenharmony_ci			ACPI_COMPANION_SET(dev, NULL);
2868c2ecf20Sopenharmony_ci			/* Drop references taken by acpi_bind_one(). */
2878c2ecf20Sopenharmony_ci			put_device(dev);
2888c2ecf20Sopenharmony_ci			put_device(&acpi_dev->dev);
2898c2ecf20Sopenharmony_ci			kfree(entry);
2908c2ecf20Sopenharmony_ci			break;
2918c2ecf20Sopenharmony_ci		}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	mutex_unlock(&acpi_dev->physical_node_lock);
2948c2ecf20Sopenharmony_ci	return 0;
2958c2ecf20Sopenharmony_ci}
2968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_unbind_one);
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_cistatic int acpi_device_notify(struct device *dev)
2998c2ecf20Sopenharmony_ci{
3008c2ecf20Sopenharmony_ci	struct acpi_bus_type *type = acpi_get_bus_type(dev);
3018c2ecf20Sopenharmony_ci	struct acpi_device *adev;
3028c2ecf20Sopenharmony_ci	int ret;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	ret = acpi_bind_one(dev, NULL);
3058c2ecf20Sopenharmony_ci	if (ret && type) {
3068c2ecf20Sopenharmony_ci		struct acpi_device *adev;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci		adev = type->find_companion(dev);
3098c2ecf20Sopenharmony_ci		if (!adev) {
3108c2ecf20Sopenharmony_ci			DBG("Unable to get handle for %s\n", dev_name(dev));
3118c2ecf20Sopenharmony_ci			ret = -ENODEV;
3128c2ecf20Sopenharmony_ci			goto out;
3138c2ecf20Sopenharmony_ci		}
3148c2ecf20Sopenharmony_ci		ret = acpi_bind_one(dev, adev);
3158c2ecf20Sopenharmony_ci		if (ret)
3168c2ecf20Sopenharmony_ci			goto out;
3178c2ecf20Sopenharmony_ci	}
3188c2ecf20Sopenharmony_ci	adev = ACPI_COMPANION(dev);
3198c2ecf20Sopenharmony_ci	if (!adev)
3208c2ecf20Sopenharmony_ci		goto out;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	if (dev_is_platform(dev))
3238c2ecf20Sopenharmony_ci		acpi_configure_pmsi_domain(dev);
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	if (type && type->setup)
3268c2ecf20Sopenharmony_ci		type->setup(dev);
3278c2ecf20Sopenharmony_ci	else if (adev->handler && adev->handler->bind)
3288c2ecf20Sopenharmony_ci		adev->handler->bind(dev);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci out:
3318c2ecf20Sopenharmony_ci#if ACPI_GLUE_DEBUG
3328c2ecf20Sopenharmony_ci	if (!ret) {
3338c2ecf20Sopenharmony_ci		struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci		acpi_get_name(ACPI_HANDLE(dev), ACPI_FULL_PATHNAME, &buffer);
3368c2ecf20Sopenharmony_ci		DBG("Device %s -> %s\n", dev_name(dev), (char *)buffer.pointer);
3378c2ecf20Sopenharmony_ci		kfree(buffer.pointer);
3388c2ecf20Sopenharmony_ci	} else
3398c2ecf20Sopenharmony_ci		DBG("Device %s -> No ACPI support\n", dev_name(dev));
3408c2ecf20Sopenharmony_ci#endif
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	return ret;
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_cistatic int acpi_device_notify_remove(struct device *dev)
3468c2ecf20Sopenharmony_ci{
3478c2ecf20Sopenharmony_ci	struct acpi_device *adev = ACPI_COMPANION(dev);
3488c2ecf20Sopenharmony_ci	struct acpi_bus_type *type;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	if (!adev)
3518c2ecf20Sopenharmony_ci		return 0;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	type = acpi_get_bus_type(dev);
3548c2ecf20Sopenharmony_ci	if (type && type->cleanup)
3558c2ecf20Sopenharmony_ci		type->cleanup(dev);
3568c2ecf20Sopenharmony_ci	else if (adev->handler && adev->handler->unbind)
3578c2ecf20Sopenharmony_ci		adev->handler->unbind(dev);
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	acpi_unbind_one(dev);
3608c2ecf20Sopenharmony_ci	return 0;
3618c2ecf20Sopenharmony_ci}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ciint acpi_platform_notify(struct device *dev, enum kobject_action action)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	switch (action) {
3668c2ecf20Sopenharmony_ci	case KOBJ_ADD:
3678c2ecf20Sopenharmony_ci		acpi_device_notify(dev);
3688c2ecf20Sopenharmony_ci		break;
3698c2ecf20Sopenharmony_ci	case KOBJ_REMOVE:
3708c2ecf20Sopenharmony_ci		acpi_device_notify_remove(dev);
3718c2ecf20Sopenharmony_ci		break;
3728c2ecf20Sopenharmony_ci	default:
3738c2ecf20Sopenharmony_ci		break;
3748c2ecf20Sopenharmony_ci	}
3758c2ecf20Sopenharmony_ci	return 0;
3768c2ecf20Sopenharmony_ci}
377