linux/drivers/acpi/container.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * container.c  - ACPI Generic Container Driver
   4 *
   5 * Copyright (C) 2004 Anil S Keshavamurthy (anil.s.keshavamurthy@intel.com)
   6 * Copyright (C) 2004 Keiichiro Tokunaga (tokunaga.keiich@jp.fujitsu.com)
   7 * Copyright (C) 2004 Motoyuki Ito (motoyuki@soft.fujitsu.com)
   8 * Copyright (C) 2004 FUJITSU LIMITED
   9 * Copyright (C) 2004, 2013 Intel Corp.
  10 * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  11 */
  12#include <linux/acpi.h>
  13#include <linux/container.h>
  14
  15#include "internal.h"
  16
  17static const struct acpi_device_id container_device_ids[] = {
  18        {"ACPI0004", 0},
  19        {"PNP0A05", 0},
  20        {"PNP0A06", 0},
  21        {"", 0},
  22};
  23
  24#ifdef CONFIG_ACPI_CONTAINER
  25
  26static int acpi_container_offline(struct container_dev *cdev)
  27{
  28        struct acpi_device *adev = ACPI_COMPANION(&cdev->dev);
  29        struct acpi_device *child;
  30
  31        /* Check all of the dependent devices' physical companions. */
  32        list_for_each_entry(child, &adev->children, node)
  33                if (!acpi_scan_is_offline(child, false))
  34                        return -EBUSY;
  35
  36        return 0;
  37}
  38
  39static void acpi_container_release(struct device *dev)
  40{
  41        kfree(to_container_dev(dev));
  42}
  43
  44static int container_device_attach(struct acpi_device *adev,
  45                                   const struct acpi_device_id *not_used)
  46{
  47        struct container_dev *cdev;
  48        struct device *dev;
  49        int ret;
  50
  51        if (adev->flags.is_dock_station)
  52                return 0;
  53
  54        cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
  55        if (!cdev)
  56                return -ENOMEM;
  57
  58        cdev->offline = acpi_container_offline;
  59        dev = &cdev->dev;
  60        dev->bus = &container_subsys;
  61        dev_set_name(dev, "%s", dev_name(&adev->dev));
  62        ACPI_COMPANION_SET(dev, adev);
  63        dev->release = acpi_container_release;
  64        ret = device_register(dev);
  65        if (ret) {
  66                put_device(dev);
  67                return ret;
  68        }
  69        adev->driver_data = dev;
  70        return 1;
  71}
  72
  73static void container_device_detach(struct acpi_device *adev)
  74{
  75        struct device *dev = acpi_driver_data(adev);
  76
  77        adev->driver_data = NULL;
  78        if (dev)
  79                device_unregister(dev);
  80}
  81
  82static void container_device_online(struct acpi_device *adev)
  83{
  84        struct device *dev = acpi_driver_data(adev);
  85
  86        kobject_uevent(&dev->kobj, KOBJ_ONLINE);
  87}
  88
  89static struct acpi_scan_handler container_handler = {
  90        .ids = container_device_ids,
  91        .attach = container_device_attach,
  92        .detach = container_device_detach,
  93        .hotplug = {
  94                .enabled = true,
  95                .demand_offline = true,
  96                .notify_online = container_device_online,
  97        },
  98};
  99
 100void __init acpi_container_init(void)
 101{
 102        acpi_scan_add_handler(&container_handler);
 103}
 104
 105#else
 106
 107static struct acpi_scan_handler container_handler = {
 108        .ids = container_device_ids,
 109};
 110
 111void __init acpi_container_init(void)
 112{
 113        acpi_scan_add_handler_with_hotplug(&container_handler, "container");
 114}
 115
 116#endif /* CONFIG_ACPI_CONTAINER */
 117