xref: /linux/drivers/acpi/container.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
368a67f6cSRafael J. Wysocki  * container.c  - ACPI Generic Container Driver
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Copyright (C) 2004 Anil S Keshavamurthy (anil.s.keshavamurthy@intel.com)
61da177e4SLinus Torvalds  * Copyright (C) 2004 Keiichiro Tokunaga (tokunaga.keiich@jp.fujitsu.com)
71da177e4SLinus Torvalds  * Copyright (C) 2004 Motoyuki Ito (motoyuki@soft.fujitsu.com)
81da177e4SLinus Torvalds  * Copyright (C) 2004 FUJITSU LIMITED
968a67f6cSRafael J. Wysocki  * Copyright (C) 2004, 2013 Intel Corp.
1068a67f6cSRafael J. Wysocki  * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
111da177e4SLinus Torvalds  */
121da177e4SLinus Torvalds #include <linux/acpi.h>
13caa73ea1SRafael J. Wysocki #include <linux/container.h>
141da177e4SLinus Torvalds 
152f9b06fcSAndy Shevchenko #include "internal.h"
162f9b06fcSAndy Shevchenko 
171ba90e3aSThomas Renninger static const struct acpi_device_id container_device_ids[] = {
181ba90e3aSThomas Renninger 	{"ACPI0004", 0},
191ba90e3aSThomas Renninger 	{"PNP0A05", 0},
201ba90e3aSThomas Renninger 	{"PNP0A06", 0},
211ba90e3aSThomas Renninger 	{"", 0},
221ba90e3aSThomas Renninger };
231ba90e3aSThomas Renninger 
24a1ec6572SRafael J. Wysocki #ifdef CONFIG_ACPI_CONTAINER
25a1ec6572SRafael J. Wysocki 
check_offline(struct acpi_device * adev,void * not_used)26*abda0af4SRafael J. Wysocki static int check_offline(struct acpi_device *adev, void *not_used)
27*abda0af4SRafael J. Wysocki {
28*abda0af4SRafael J. Wysocki 	if (acpi_scan_is_offline(adev, false))
29*abda0af4SRafael J. Wysocki 		return 0;
30*abda0af4SRafael J. Wysocki 
31*abda0af4SRafael J. Wysocki 	return -EBUSY;
32*abda0af4SRafael J. Wysocki }
33*abda0af4SRafael J. Wysocki 
acpi_container_offline(struct container_dev * cdev)34caa73ea1SRafael J. Wysocki static int acpi_container_offline(struct container_dev *cdev)
35caa73ea1SRafael J. Wysocki {
36caa73ea1SRafael J. Wysocki 	/* Check all of the dependent devices' physical companions. */
37*abda0af4SRafael J. Wysocki 	return acpi_dev_for_each_child(ACPI_COMPANION(&cdev->dev), check_offline, NULL);
38caa73ea1SRafael J. Wysocki }
39caa73ea1SRafael J. Wysocki 
acpi_container_release(struct device * dev)40caa73ea1SRafael J. Wysocki static void acpi_container_release(struct device *dev)
41caa73ea1SRafael J. Wysocki {
42caa73ea1SRafael J. Wysocki 	kfree(to_container_dev(dev));
43caa73ea1SRafael J. Wysocki }
44caa73ea1SRafael J. Wysocki 
container_device_attach(struct acpi_device * adev,const struct acpi_device_id * not_used)4546394fd0SRafael J. Wysocki static int container_device_attach(struct acpi_device *adev,
46737f1a9fSRafael J. Wysocki 				   const struct acpi_device_id *not_used)
47737f1a9fSRafael J. Wysocki {
48caa73ea1SRafael J. Wysocki 	struct container_dev *cdev;
49caa73ea1SRafael J. Wysocki 	struct device *dev;
50caa73ea1SRafael J. Wysocki 	int ret;
51caa73ea1SRafael J. Wysocki 
521e2380cdSRafael J. Wysocki 	if (adev->flags.is_dock_station)
531e2380cdSRafael J. Wysocki 		return 0;
541e2380cdSRafael J. Wysocki 
55caa73ea1SRafael J. Wysocki 	cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
56caa73ea1SRafael J. Wysocki 	if (!cdev)
57caa73ea1SRafael J. Wysocki 		return -ENOMEM;
58caa73ea1SRafael J. Wysocki 
59caa73ea1SRafael J. Wysocki 	cdev->offline = acpi_container_offline;
60caa73ea1SRafael J. Wysocki 	dev = &cdev->dev;
61caa73ea1SRafael J. Wysocki 	dev->bus = &container_subsys;
62caa73ea1SRafael J. Wysocki 	dev_set_name(dev, "%s", dev_name(&adev->dev));
63caa73ea1SRafael J. Wysocki 	ACPI_COMPANION_SET(dev, adev);
64caa73ea1SRafael J. Wysocki 	dev->release = acpi_container_release;
65caa73ea1SRafael J. Wysocki 	ret = device_register(dev);
660f6aa09eSRafael J. Wysocki 	if (ret) {
670f6aa09eSRafael J. Wysocki 		put_device(dev);
68caa73ea1SRafael J. Wysocki 		return ret;
690f6aa09eSRafael J. Wysocki 	}
70caa73ea1SRafael J. Wysocki 	adev->driver_data = dev;
71737f1a9fSRafael J. Wysocki 	return 1;
72737f1a9fSRafael J. Wysocki }
73737f1a9fSRafael J. Wysocki 
container_device_detach(struct acpi_device * adev)7446394fd0SRafael J. Wysocki static void container_device_detach(struct acpi_device *adev)
7546394fd0SRafael J. Wysocki {
76caa73ea1SRafael J. Wysocki 	struct device *dev = acpi_driver_data(adev);
77caa73ea1SRafael J. Wysocki 
78caa73ea1SRafael J. Wysocki 	adev->driver_data = NULL;
79caa73ea1SRafael J. Wysocki 	if (dev)
80caa73ea1SRafael J. Wysocki 		device_unregister(dev);
8146394fd0SRafael J. Wysocki }
8246394fd0SRafael J. Wysocki 
container_device_online(struct acpi_device * adev)838ab17fc9SRafael J. Wysocki static void container_device_online(struct acpi_device *adev)
848ab17fc9SRafael J. Wysocki {
858ab17fc9SRafael J. Wysocki 	struct device *dev = acpi_driver_data(adev);
868ab17fc9SRafael J. Wysocki 
878ab17fc9SRafael J. Wysocki 	kobject_uevent(&dev->kobj, KOBJ_ONLINE);
888ab17fc9SRafael J. Wysocki }
898ab17fc9SRafael J. Wysocki 
9079917f34SRafael J. Wysocki static struct acpi_scan_handler container_handler = {
911ba90e3aSThomas Renninger 	.ids = container_device_ids,
92737f1a9fSRafael J. Wysocki 	.attach = container_device_attach,
9346394fd0SRafael J. Wysocki 	.detach = container_device_detach,
9468a67f6cSRafael J. Wysocki 	.hotplug = {
9568a67f6cSRafael J. Wysocki 		.enabled = true,
96caa73ea1SRafael J. Wysocki 		.demand_offline = true,
978ab17fc9SRafael J. Wysocki 		.notify_online = container_device_online,
9868a67f6cSRafael J. Wysocki 	},
991da177e4SLinus Torvalds };
1001da177e4SLinus Torvalds 
acpi_container_init(void)101737f1a9fSRafael J. Wysocki void __init acpi_container_init(void)
1021da177e4SLinus Torvalds {
103a1ec6572SRafael J. Wysocki 	acpi_scan_add_handler(&container_handler);
104a1ec6572SRafael J. Wysocki }
105a1ec6572SRafael J. Wysocki 
106a1ec6572SRafael J. Wysocki #else
107a1ec6572SRafael J. Wysocki 
108a1ec6572SRafael J. Wysocki static struct acpi_scan_handler container_handler = {
109a1ec6572SRafael J. Wysocki 	.ids = container_device_ids,
110a1ec6572SRafael J. Wysocki };
111a1ec6572SRafael J. Wysocki 
acpi_container_init(void)112a1ec6572SRafael J. Wysocki void __init acpi_container_init(void)
113a1ec6572SRafael J. Wysocki {
11479917f34SRafael J. Wysocki 	acpi_scan_add_handler_with_hotplug(&container_handler, "container");
1151da177e4SLinus Torvalds }
116a1ec6572SRafael J. Wysocki 
117a1ec6572SRafael J. Wysocki #endif /* CONFIG_ACPI_CONTAINER */
118