diff options
Diffstat (limited to 'drivers/acpi/container.c')
| -rw-r--r-- | drivers/acpi/container.c | 107 |
1 files changed, 79 insertions, 28 deletions
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index e23151667655..5b7e3b9ae370 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * container.c - ACPI Generic Container Driver * @@ -7,36 +8,12 @@ * Copyright (C) 2004 FUJITSU LIMITED * Copyright (C) 2004, 2013 Intel Corp. * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com> - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #include <linux/acpi.h> +#include <linux/container.h> #include "internal.h" -#include "internal.h" - -#define PREFIX "ACPI: " - -#define _COMPONENT ACPI_CONTAINER_COMPONENT -ACPI_MODULE_NAME("container"); - static const struct acpi_device_id container_device_ids[] = { {"ACPI0004", 0}, {"PNP0A05", 0}, @@ -44,23 +21,97 @@ static const struct acpi_device_id container_device_ids[] = { {"", 0}, }; -static int container_device_attach(struct acpi_device *device, +#ifdef CONFIG_ACPI_CONTAINER + +static int check_offline(struct acpi_device *adev, void *not_used) +{ + if (acpi_scan_is_offline(adev, false)) + return 0; + + return -EBUSY; +} + +static int acpi_container_offline(struct container_dev *cdev) +{ + /* Check all of the dependent devices' physical companions. */ + return acpi_dev_for_each_child(ACPI_COMPANION(&cdev->dev), check_offline, NULL); +} + +static void acpi_container_release(struct device *dev) +{ + kfree(to_container_dev(dev)); +} + +static int container_device_attach(struct acpi_device *adev, const struct acpi_device_id *not_used) { - /* This is necessary for container hotplug to work. */ + struct container_dev *cdev; + struct device *dev; + int ret; + + if (adev->flags.is_dock_station) + return 0; + + cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); + if (!cdev) + return -ENOMEM; + + cdev->offline = acpi_container_offline; + dev = &cdev->dev; + dev->bus = &container_subsys; + dev_set_name(dev, "%s", dev_name(&adev->dev)); + ACPI_COMPANION_SET(dev, adev); + dev->release = acpi_container_release; + ret = device_register(dev); + if (ret) { + put_device(dev); + return ret; + } + adev->driver_data = dev; return 1; } +static void container_device_detach(struct acpi_device *adev) +{ + struct device *dev = acpi_driver_data(adev); + + adev->driver_data = NULL; + if (dev) + device_unregister(dev); +} + +static void container_device_online(struct acpi_device *adev) +{ + struct device *dev = acpi_driver_data(adev); + + kobject_uevent(&dev->kobj, KOBJ_ONLINE); +} + static struct acpi_scan_handler container_handler = { .ids = container_device_ids, .attach = container_device_attach, + .detach = container_device_detach, .hotplug = { .enabled = true, - .mode = AHM_CONTAINER, + .demand_offline = true, + .notify_online = container_device_online, }, }; void __init acpi_container_init(void) { + acpi_scan_add_handler(&container_handler); +} + +#else + +static struct acpi_scan_handler container_handler = { + .ids = container_device_ids, +}; + +void __init acpi_container_init(void) +{ acpi_scan_add_handler_with_hotplug(&container_handler, "container"); } + +#endif /* CONFIG_ACPI_CONTAINER */ |
