aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-03-03 17:08:16 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-03-04 08:25:32 -0500
commit3f8055c3583640ed3e4c81864dd76e06a7faa505 (patch)
treec77ae4121942fc43be57cd603435f1a9dcb78b3d /drivers/acpi
parent4b59cc1fd6fd1dac1d4468b4f327ae9f59d1c0aa (diff)
ACPI / hotplug: Introduce user space interface for hotplug profiles
Introduce user space interface for manipulating hotplug profiles associated with ACPI scan handlers. The interface consists of sysfs directories under /sys/firmware/acpi/hotplug/, one for each hotplug profile, containing an attribute allowing user space to manipulate the enabled field of the corresponding profile. Namely, switching the enabled attribute from '0' to '1' will cause the common hotplug notify handler to be installed for all ACPI namespace objects representing devices matching the scan handler associated with the given hotplug profile (and analogously for the converse switch). Drivers willing to use the new user space interface should add their ACPI scan handlers with the help of new funtion acpi_scan_add_handler_with_hotplug(). Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Acked-by: Toshi Kani <toshi.kani@hp.com> Tested-by: Toshi Kani <toshi.kani@hp.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/internal.h6
-rw-r--r--drivers/acpi/scan.c59
-rw-r--r--drivers/acpi/sysfs.c66
3 files changed, 131 insertions, 0 deletions
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 3c94a732b4b3..c708e4bad967 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -42,6 +42,12 @@ void acpi_container_init(void);
42static inline void acpi_container_init(void) {} 42static inline void acpi_container_init(void) {}
43#endif 43#endif
44 44
45void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug,
46 const char *name);
47int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
48 const char *hotplug_profile_name);
49void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val);
50
45#ifdef CONFIG_DEBUG_FS 51#ifdef CONFIG_DEBUG_FS
46extern struct dentry *acpi_debugfs_dir; 52extern struct dentry *acpi_debugfs_dir;
47int acpi_debugfs_init(void); 53int acpi_debugfs_init(void);
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 45fbe95ba1f3..5458403c8249 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -63,6 +63,19 @@ int acpi_scan_add_handler(struct acpi_scan_handler *handler)
63 return 0; 63 return 0;
64} 64}
65 65
66int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
67 const char *hotplug_profile_name)
68{
69 int error;
70
71 error = acpi_scan_add_handler(handler);
72 if (error)
73 return error;
74
75 acpi_sysfs_add_hotplug_profile(&handler->hotplug, hotplug_profile_name);
76 return 0;
77}
78
66/* 79/*
67 * Creates hid/cid(s) string needed for modalias and uevent 80 * Creates hid/cid(s) string needed for modalias and uevent
68 * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get: 81 * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
@@ -1690,6 +1703,52 @@ static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler,
1690 return false; 1703 return false;
1691} 1704}
1692 1705
1706static acpi_status acpi_scan_hotplug_modify(acpi_handle handle,
1707 u32 lvl_not_used, void *data,
1708 void **ret_not_used)
1709{
1710 struct acpi_scan_handler *handler = data;
1711 struct acpi_device_info *info;
1712 bool match = false;
1713
1714 if (ACPI_FAILURE(acpi_get_object_info(handle, &info)))
1715 return AE_OK;
1716
1717 if (info->valid & ACPI_VALID_HID) {
1718 char *idstr = info->hardware_id.string;
1719 match = acpi_scan_handler_matching(handler, idstr, NULL);
1720 }
1721 kfree(info);
1722 if (!match)
1723 return AE_OK;
1724
1725 if (handler->hotplug.enabled)
1726 acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
1727 acpi_hotplug_notify_cb, NULL);
1728 else
1729 acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
1730 acpi_hotplug_notify_cb);
1731
1732 return AE_OK;
1733}
1734
1735void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val)
1736{
1737 struct acpi_scan_handler *handler;
1738
1739 if (!!hotplug->enabled == !!val)
1740 return;
1741
1742 mutex_lock(&acpi_scan_lock);
1743
1744 hotplug->enabled = val;
1745 handler = container_of(hotplug, struct acpi_scan_handler, hotplug);
1746 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
1747 acpi_scan_hotplug_modify, NULL, handler, NULL);
1748
1749 mutex_unlock(&acpi_scan_lock);
1750}
1751
1693static struct acpi_scan_handler *acpi_scan_match_handler(char *idstr, 1752static struct acpi_scan_handler *acpi_scan_match_handler(char *idstr,
1694 const struct acpi_device_id **matchid) 1753 const struct acpi_device_id **matchid)
1695{ 1754{
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index 41c0504470db..83db3a68a7ee 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -7,6 +7,8 @@
7#include <linux/moduleparam.h> 7#include <linux/moduleparam.h>
8#include <acpi/acpi_drivers.h> 8#include <acpi/acpi_drivers.h>
9 9
10#include "internal.h"
11
10#define _COMPONENT ACPI_SYSTEM_COMPONENT 12#define _COMPONENT ACPI_SYSTEM_COMPONENT
11ACPI_MODULE_NAME("sysfs"); 13ACPI_MODULE_NAME("sysfs");
12 14
@@ -249,6 +251,7 @@ module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);
249static LIST_HEAD(acpi_table_attr_list); 251static LIST_HEAD(acpi_table_attr_list);
250static struct kobject *tables_kobj; 252static struct kobject *tables_kobj;
251static struct kobject *dynamic_tables_kobj; 253static struct kobject *dynamic_tables_kobj;
254static struct kobject *hotplug_kobj;
252 255
253struct acpi_table_attr { 256struct acpi_table_attr {
254 struct bin_attribute attr; 257 struct bin_attribute attr;
@@ -716,6 +719,67 @@ acpi_show_profile(struct device *dev, struct device_attribute *attr,
716static const struct device_attribute pm_profile_attr = 719static const struct device_attribute pm_profile_attr =
717 __ATTR(pm_profile, S_IRUGO, acpi_show_profile, NULL); 720 __ATTR(pm_profile, S_IRUGO, acpi_show_profile, NULL);
718 721
722static ssize_t hotplug_enabled_show(struct kobject *kobj,
723 struct kobj_attribute *attr, char *buf)
724{
725 struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj);
726
727 return sprintf(buf, "%d\n", hotplug->enabled);
728}
729
730static ssize_t hotplug_enabled_store(struct kobject *kobj,
731 struct kobj_attribute *attr,
732 const char *buf, size_t size)
733{
734 struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj);
735 unsigned int val;
736
737 if (kstrtouint(buf, 10, &val) || val > 1)
738 return -EINVAL;
739
740 acpi_scan_hotplug_enabled(hotplug, val);
741 return size;
742}
743
744static struct kobj_attribute hotplug_enabled_attr =
745 __ATTR(enabled, S_IRUGO | S_IWUSR, hotplug_enabled_show,
746 hotplug_enabled_store);
747
748static struct attribute *hotplug_profile_attrs[] = {
749 &hotplug_enabled_attr.attr,
750 NULL
751};
752
753struct kobj_type acpi_hotplug_profile_ktype = {
754 .sysfs_ops = &kobj_sysfs_ops,
755 .default_attrs = hotplug_profile_attrs,
756};
757
758void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug,
759 const char *name)
760{
761 int error;
762
763 if (!hotplug_kobj)
764 goto err_out;
765
766 kobject_init(&hotplug->kobj, &acpi_hotplug_profile_ktype);
767 error = kobject_set_name(&hotplug->kobj, "%s", name);
768 if (error)
769 goto err_out;
770
771 hotplug->kobj.parent = hotplug_kobj;
772 error = kobject_add(&hotplug->kobj, hotplug_kobj, NULL);
773 if (error)
774 goto err_out;
775
776 kobject_uevent(&hotplug->kobj, KOBJ_ADD);
777 return;
778
779 err_out:
780 pr_err(PREFIX "Unable to add hotplug profile '%s'\n", name);
781}
782
719int __init acpi_sysfs_init(void) 783int __init acpi_sysfs_init(void)
720{ 784{
721 int result; 785 int result;
@@ -723,6 +787,8 @@ int __init acpi_sysfs_init(void)
723 result = acpi_tables_sysfs_init(); 787 result = acpi_tables_sysfs_init();
724 if (result) 788 if (result)
725 return result; 789 return result;
790
791 hotplug_kobj = kobject_create_and_add("hotplug", acpi_kobj);
726 result = sysfs_create_file(acpi_kobj, &pm_profile_attr.attr); 792 result = sysfs_create_file(acpi_kobj, &pm_profile_attr.attr);
727 return result; 793 return result;
728} 794}