yoffset: The number of pixels between the top of the screen
                         and the top edge of the image.
 
+What:          /sys/firmware/acpi/hotplug/
+Date:          February 2013
+Contact:       Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Description:
+               There are separate hotplug profiles for different classes of
+               devices supported by ACPI, such as containers, memory modules,
+               processors, PCI root bridges etc.  A hotplug profile for a given
+               class of devices is a collection of settings defining the way
+               that class of devices will be handled by the ACPI core hotplug
+               code.  Those profiles are represented in sysfs as subdirectories
+               of /sys/firmware/acpi/hotplug/.
+
+               The following setting is available to user space for each
+               hotplug profile:
+
+               enabled: If set, the ACPI core will handle notifications of
+                       hotplug events associated with the given class of
+                       devices and will allow those devices to be ejected with
+                       the help of the _EJ0 control method.  Unsetting it
+                       effectively disables hotplug for the correspoinding
+                       class of devices.
+
+               The value of the above attribute is an integer number: 1 (set)
+               or 0 (unset).  Attempts to write any other values to it will
+               cause -EINVAL to be returned.
+
 What:          /sys/firmware/acpi/interrupts/
 Date:          February 2008
 Contact:       Len Brown <lenb@kernel.org>
 
 static inline void acpi_container_init(void) {}
 #endif
 
+void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug,
+                                   const char *name);
+int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
+                                      const char *hotplug_profile_name);
+void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val);
+
 #ifdef CONFIG_DEBUG_FS
 extern struct dentry *acpi_debugfs_dir;
 int acpi_debugfs_init(void);
 
        return 0;
 }
 
+int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
+                                      const char *hotplug_profile_name)
+{
+       int error;
+
+       error = acpi_scan_add_handler(handler);
+       if (error)
+               return error;
+
+       acpi_sysfs_add_hotplug_profile(&handler->hotplug, hotplug_profile_name);
+       return 0;
+}
+
 /*
  * Creates hid/cid(s) string needed for modalias and uevent
  * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
        return false;
 }
 
+static acpi_status acpi_scan_hotplug_modify(acpi_handle handle,
+                                           u32 lvl_not_used, void *data,
+                                           void **ret_not_used)
+{
+       struct acpi_scan_handler *handler = data;
+       struct acpi_device_info *info;
+       bool match = false;
+
+       if (ACPI_FAILURE(acpi_get_object_info(handle, &info)))
+               return AE_OK;
+
+       if (info->valid & ACPI_VALID_HID) {
+               char *idstr = info->hardware_id.string;
+               match = acpi_scan_handler_matching(handler, idstr, NULL);
+       }
+       kfree(info);
+       if (!match)
+               return AE_OK;
+
+       if (handler->hotplug.enabled)
+               acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+                                           acpi_hotplug_notify_cb, NULL);
+       else
+               acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+                                          acpi_hotplug_notify_cb);
+
+       return AE_OK;
+}
+
+void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val)
+{
+       struct acpi_scan_handler *handler;
+
+       if (!!hotplug->enabled == !!val)
+               return;
+
+       mutex_lock(&acpi_scan_lock);
+
+       hotplug->enabled = val;
+       handler = container_of(hotplug, struct acpi_scan_handler, hotplug);
+       acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
+                           acpi_scan_hotplug_modify, NULL, handler, NULL);
+
+       mutex_unlock(&acpi_scan_lock);
+}
+
 static struct acpi_scan_handler *acpi_scan_match_handler(char *idstr,
                                        const struct acpi_device_id **matchid)
 {
 
 #include <linux/moduleparam.h>
 #include <acpi/acpi_drivers.h>
 
+#include "internal.h"
+
 #define _COMPONENT             ACPI_SYSTEM_COMPONENT
 ACPI_MODULE_NAME("sysfs");
 
 static LIST_HEAD(acpi_table_attr_list);
 static struct kobject *tables_kobj;
 static struct kobject *dynamic_tables_kobj;
+static struct kobject *hotplug_kobj;
 
 struct acpi_table_attr {
        struct bin_attribute attr;
 static const struct device_attribute pm_profile_attr =
        __ATTR(pm_profile, S_IRUGO, acpi_show_profile, NULL);
 
+static ssize_t hotplug_enabled_show(struct kobject *kobj,
+                                   struct kobj_attribute *attr, char *buf)
+{
+       struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj);
+
+       return sprintf(buf, "%d\n", hotplug->enabled);
+}
+
+static ssize_t hotplug_enabled_store(struct kobject *kobj,
+                                    struct kobj_attribute *attr,
+                                    const char *buf, size_t size)
+{
+       struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj);
+       unsigned int val;
+
+       if (kstrtouint(buf, 10, &val) || val > 1)
+               return -EINVAL;
+
+       acpi_scan_hotplug_enabled(hotplug, val);
+       return size;
+}
+
+static struct kobj_attribute hotplug_enabled_attr =
+       __ATTR(enabled, S_IRUGO | S_IWUSR, hotplug_enabled_show,
+               hotplug_enabled_store);
+
+static struct attribute *hotplug_profile_attrs[] = {
+       &hotplug_enabled_attr.attr,
+       NULL
+};
+
+struct kobj_type acpi_hotplug_profile_ktype = {
+       .sysfs_ops = &kobj_sysfs_ops,
+       .default_attrs = hotplug_profile_attrs,
+};
+
+void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug,
+                                   const char *name)
+{
+       int error;
+
+       if (!hotplug_kobj)
+               goto err_out;
+
+       kobject_init(&hotplug->kobj, &acpi_hotplug_profile_ktype);
+       error = kobject_set_name(&hotplug->kobj, "%s", name);
+       if (error)
+               goto err_out;
+
+       hotplug->kobj.parent = hotplug_kobj;
+       error = kobject_add(&hotplug->kobj, hotplug_kobj, NULL);
+       if (error)
+               goto err_out;
+
+       kobject_uevent(&hotplug->kobj, KOBJ_ADD);
+       return;
+
+ err_out:
+       pr_err(PREFIX "Unable to add hotplug profile '%s'\n", name);
+}
+
 int __init acpi_sysfs_init(void)
 {
        int result;
        result = acpi_tables_sysfs_init();
        if (result)
                return result;
+
+       hotplug_kobj = kobject_create_and_add("hotplug", acpi_kobj);
        result = sysfs_create_file(acpi_kobj, &pm_profile_attr.attr);
        return result;
 }
 
 };
 
 struct acpi_hotplug_profile {
+       struct kobject kobj;
        bool enabled:1;
        enum acpi_hotplug_mode mode;
 };
 
+static inline struct acpi_hotplug_profile *to_acpi_hotplug_profile(
+                                               struct kobject *kobj)
+{
+       return container_of(kobj, struct acpi_hotplug_profile, kobj);
+}
+
 struct acpi_scan_handler {
        const struct acpi_device_id *ids;
        struct list_head list_node;