Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / acpi / scan.c
diff --git a/kernel/drivers/acpi/scan.c b/kernel/drivers/acpi/scan.c
new file mode 100644 (file)
index 0000000..03141aa
--- /dev/null
@@ -0,0 +1,2688 @@
+/*
+ * scan.c - support for transforming the ACPI namespace into individual objects
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/acpi.h>
+#include <linux/signal.h>
+#include <linux/kthread.h>
+#include <linux/dmi.h>
+#include <linux/nls.h>
+
+#include <asm/pgtable.h>
+
+#include "internal.h"
+
+#define _COMPONENT             ACPI_BUS_COMPONENT
+ACPI_MODULE_NAME("scan");
+extern struct acpi_device *acpi_root;
+
+#define ACPI_BUS_CLASS                 "system_bus"
+#define ACPI_BUS_HID                   "LNXSYBUS"
+#define ACPI_BUS_DEVICE_NAME           "System Bus"
+
+#define ACPI_IS_ROOT_DEVICE(device)    (!(device)->parent)
+
+#define INVALID_ACPI_HANDLE    ((acpi_handle)empty_zero_page)
+
+/*
+ * If set, devices will be hot-removed even if they cannot be put offline
+ * gracefully (from the kernel's standpoint).
+ */
+bool acpi_force_hot_remove;
+
+static const char *dummy_hid = "device";
+
+static LIST_HEAD(acpi_dep_list);
+static DEFINE_MUTEX(acpi_dep_list_lock);
+static LIST_HEAD(acpi_bus_id_list);
+static DEFINE_MUTEX(acpi_scan_lock);
+static LIST_HEAD(acpi_scan_handlers_list);
+DEFINE_MUTEX(acpi_device_lock);
+LIST_HEAD(acpi_wakeup_device_list);
+static DEFINE_MUTEX(acpi_hp_context_lock);
+
+struct acpi_dep_data {
+       struct list_head node;
+       acpi_handle master;
+       acpi_handle slave;
+};
+
+struct acpi_device_bus_id{
+       char bus_id[15];
+       unsigned int instance_no;
+       struct list_head node;
+};
+
+void acpi_scan_lock_acquire(void)
+{
+       mutex_lock(&acpi_scan_lock);
+}
+EXPORT_SYMBOL_GPL(acpi_scan_lock_acquire);
+
+void acpi_scan_lock_release(void)
+{
+       mutex_unlock(&acpi_scan_lock);
+}
+EXPORT_SYMBOL_GPL(acpi_scan_lock_release);
+
+void acpi_lock_hp_context(void)
+{
+       mutex_lock(&acpi_hp_context_lock);
+}
+
+void acpi_unlock_hp_context(void)
+{
+       mutex_unlock(&acpi_hp_context_lock);
+}
+
+void acpi_initialize_hp_context(struct acpi_device *adev,
+                               struct acpi_hotplug_context *hp,
+                               int (*notify)(struct acpi_device *, u32),
+                               void (*uevent)(struct acpi_device *, u32))
+{
+       acpi_lock_hp_context();
+       hp->notify = notify;
+       hp->uevent = uevent;
+       acpi_set_hp_context(adev, hp);
+       acpi_unlock_hp_context();
+}
+EXPORT_SYMBOL_GPL(acpi_initialize_hp_context);
+
+int acpi_scan_add_handler(struct acpi_scan_handler *handler)
+{
+       if (!handler)
+               return -EINVAL;
+
+       list_add_tail(&handler->list_node, &acpi_scan_handlers_list);
+       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;
+}
+
+/**
+ * create_pnp_modalias - Create hid/cid(s) string for modalias and uevent
+ * @acpi_dev: ACPI device object.
+ * @modalias: Buffer to print into.
+ * @size: Size of the buffer.
+ *
+ * Creates hid/cid(s) string needed for modalias and uevent
+ * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
+ * char *modalias: "acpi:IBM0001:ACPI0001"
+ * Return: 0: no _HID and no _CID
+ *         -EINVAL: output error
+ *         -ENOMEM: output is truncated
+*/
+static int create_pnp_modalias(struct acpi_device *acpi_dev, char *modalias,
+                              int size)
+{
+       int len;
+       int count;
+       struct acpi_hardware_id *id;
+
+       /*
+        * Since we skip PRP0001 from the modalias below, 0 should be returned
+        * if PRP0001 is the only ACPI/PNP ID in the device's list.
+        */
+       count = 0;
+       list_for_each_entry(id, &acpi_dev->pnp.ids, list)
+               if (strcmp(id->id, "PRP0001"))
+                       count++;
+
+       if (!count)
+               return 0;
+
+       len = snprintf(modalias, size, "acpi:");
+       if (len <= 0)
+               return len;
+
+       size -= len;
+
+       list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
+               if (!strcmp(id->id, "PRP0001"))
+                       continue;
+
+               count = snprintf(&modalias[len], size, "%s:", id->id);
+               if (count < 0)
+                       return -EINVAL;
+
+               if (count >= size)
+                       return -ENOMEM;
+
+               len += count;
+               size -= count;
+       }
+       modalias[len] = '\0';
+       return len;
+}
+
+/**
+ * create_of_modalias - Creates DT compatible string for modalias and uevent
+ * @acpi_dev: ACPI device object.
+ * @modalias: Buffer to print into.
+ * @size: Size of the buffer.
+ *
+ * Expose DT compatible modalias as of:NnameTCcompatible.  This function should
+ * only be called for devices having PRP0001 in their list of ACPI/PNP IDs.
+ */
+static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias,
+                             int size)
+{
+       struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+       const union acpi_object *of_compatible, *obj;
+       int len, count;
+       int i, nval;
+       char *c;
+
+       acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
+       /* DT strings are all in lower case */
+       for (c = buf.pointer; *c != '\0'; c++)
+               *c = tolower(*c);
+
+       len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer);
+       ACPI_FREE(buf.pointer);
+
+       if (len <= 0)
+               return len;
+
+       of_compatible = acpi_dev->data.of_compatible;
+       if (of_compatible->type == ACPI_TYPE_PACKAGE) {
+               nval = of_compatible->package.count;
+               obj = of_compatible->package.elements;
+       } else { /* Must be ACPI_TYPE_STRING. */
+               nval = 1;
+               obj = of_compatible;
+       }
+       for (i = 0; i < nval; i++, obj++) {
+               count = snprintf(&modalias[len], size, "C%s",
+                                obj->string.pointer);
+               if (count < 0)
+                       return -EINVAL;
+
+               if (count >= size)
+                       return -ENOMEM;
+
+               len += count;
+               size -= count;
+       }
+       modalias[len] = '\0';
+       return len;
+}
+
+/*
+ * acpi_companion_match() - Can we match via ACPI companion device
+ * @dev: Device in question
+ *
+ * Check if the given device has an ACPI companion and if that companion has
+ * a valid list of PNP IDs, and if the device is the first (primary) physical
+ * device associated with it.  Return the companion pointer if that's the case
+ * or NULL otherwise.
+ *
+ * If multiple physical devices are attached to a single ACPI companion, we need
+ * to be careful.  The usage scenario for this kind of relationship is that all
+ * of the physical devices in question use resources provided by the ACPI
+ * companion.  A typical case is an MFD device where all the sub-devices share
+ * the parent's ACPI companion.  In such cases we can only allow the primary
+ * (first) physical device to be matched with the help of the companion's PNP
+ * IDs.
+ *
+ * Additional physical devices sharing the ACPI companion can still use
+ * resources available from it but they will be matched normally using functions
+ * provided by their bus types (and analogously for their modalias).
+ */
+static struct acpi_device *acpi_companion_match(const struct device *dev)
+{
+       struct acpi_device *adev;
+       struct mutex *physical_node_lock;
+
+       adev = ACPI_COMPANION(dev);
+       if (!adev)
+               return NULL;
+
+       if (list_empty(&adev->pnp.ids))
+               return NULL;
+
+       physical_node_lock = &adev->physical_node_lock;
+       mutex_lock(physical_node_lock);
+       if (list_empty(&adev->physical_node_list)) {
+               adev = NULL;
+       } else {
+               const struct acpi_device_physical_node *node;
+
+               node = list_first_entry(&adev->physical_node_list,
+                                       struct acpi_device_physical_node, node);
+               if (node->dev != dev)
+                       adev = NULL;
+       }
+       mutex_unlock(physical_node_lock);
+
+       return adev;
+}
+
+static int __acpi_device_uevent_modalias(struct acpi_device *adev,
+                                        struct kobj_uevent_env *env)
+{
+       int len;
+
+       if (!adev)
+               return -ENODEV;
+
+       if (list_empty(&adev->pnp.ids))
+               return 0;
+
+       if (add_uevent_var(env, "MODALIAS="))
+               return -ENOMEM;
+
+       len = create_pnp_modalias(adev, &env->buf[env->buflen - 1],
+                                 sizeof(env->buf) - env->buflen);
+       if (len < 0)
+               return len;
+
+       env->buflen += len;
+       if (!adev->data.of_compatible)
+               return 0;
+
+       if (len > 0 && add_uevent_var(env, "MODALIAS="))
+               return -ENOMEM;
+
+       len = create_of_modalias(adev, &env->buf[env->buflen - 1],
+                                sizeof(env->buf) - env->buflen);
+       if (len < 0)
+               return len;
+
+       env->buflen += len;
+
+       return 0;
+}
+
+/*
+ * Creates uevent modalias field for ACPI enumerated devices.
+ * Because the other buses does not support ACPI HIDs & CIDs.
+ * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get:
+ * "acpi:IBM0001:ACPI0001"
+ */
+int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
+{
+       return __acpi_device_uevent_modalias(acpi_companion_match(dev), env);
+}
+EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias);
+
+static int __acpi_device_modalias(struct acpi_device *adev, char *buf, int size)
+{
+       int len, count;
+
+       if (!adev)
+               return -ENODEV;
+
+       if (list_empty(&adev->pnp.ids))
+               return 0;
+
+       len = create_pnp_modalias(adev, buf, size - 1);
+       if (len < 0) {
+               return len;
+       } else if (len > 0) {
+               buf[len++] = '\n';
+               size -= len;
+       }
+       if (!adev->data.of_compatible)
+               return len;
+
+       count = create_of_modalias(adev, buf + len, size - 1);
+       if (count < 0) {
+               return count;
+       } else if (count > 0) {
+               len += count;
+               buf[len++] = '\n';
+       }
+
+       return len;
+}
+
+/*
+ * Creates modalias sysfs attribute for ACPI enumerated devices.
+ * Because the other buses does not support ACPI HIDs & CIDs.
+ * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get:
+ * "acpi:IBM0001:ACPI0001"
+ */
+int acpi_device_modalias(struct device *dev, char *buf, int size)
+{
+       return __acpi_device_modalias(acpi_companion_match(dev), buf, size);
+}
+EXPORT_SYMBOL_GPL(acpi_device_modalias);
+
+static ssize_t
+acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf) {
+       return __acpi_device_modalias(to_acpi_device(dev), buf, 1024);
+}
+static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
+
+bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent)
+{
+       struct acpi_device_physical_node *pn;
+       bool offline = true;
+
+       /*
+        * acpi_container_offline() calls this for all of the container's
+        * children under the container's physical_node_lock lock.
+        */
+       mutex_lock_nested(&adev->physical_node_lock, SINGLE_DEPTH_NESTING);
+
+       list_for_each_entry(pn, &adev->physical_node_list, node)
+               if (device_supports_offline(pn->dev) && !pn->dev->offline) {
+                       if (uevent)
+                               kobject_uevent(&pn->dev->kobj, KOBJ_CHANGE);
+
+                       offline = false;
+                       break;
+               }
+
+       mutex_unlock(&adev->physical_node_lock);
+       return offline;
+}
+
+static acpi_status acpi_bus_offline(acpi_handle handle, u32 lvl, void *data,
+                                   void **ret_p)
+{
+       struct acpi_device *device = NULL;
+       struct acpi_device_physical_node *pn;
+       bool second_pass = (bool)data;
+       acpi_status status = AE_OK;
+
+       if (acpi_bus_get_device(handle, &device))
+               return AE_OK;
+
+       if (device->handler && !device->handler->hotplug.enabled) {
+               *ret_p = &device->dev;
+               return AE_SUPPORT;
+       }
+
+       mutex_lock(&device->physical_node_lock);
+
+       list_for_each_entry(pn, &device->physical_node_list, node) {
+               int ret;
+
+               if (second_pass) {
+                       /* Skip devices offlined by the first pass. */
+                       if (pn->put_online)
+                               continue;
+               } else {
+                       pn->put_online = false;
+               }
+               ret = device_offline(pn->dev);
+               if (acpi_force_hot_remove)
+                       continue;
+
+               if (ret >= 0) {
+                       pn->put_online = !ret;
+               } else {
+                       *ret_p = pn->dev;
+                       if (second_pass) {
+                               status = AE_ERROR;
+                               break;
+                       }
+               }
+       }
+
+       mutex_unlock(&device->physical_node_lock);
+
+       return status;
+}
+
+static acpi_status acpi_bus_online(acpi_handle handle, u32 lvl, void *data,
+                                  void **ret_p)
+{
+       struct acpi_device *device = NULL;
+       struct acpi_device_physical_node *pn;
+
+       if (acpi_bus_get_device(handle, &device))
+               return AE_OK;
+
+       mutex_lock(&device->physical_node_lock);
+
+       list_for_each_entry(pn, &device->physical_node_list, node)
+               if (pn->put_online) {
+                       device_online(pn->dev);
+                       pn->put_online = false;
+               }
+
+       mutex_unlock(&device->physical_node_lock);
+
+       return AE_OK;
+}
+
+static int acpi_scan_try_to_offline(struct acpi_device *device)
+{
+       acpi_handle handle = device->handle;
+       struct device *errdev = NULL;
+       acpi_status status;
+
+       /*
+        * Carry out two passes here and ignore errors in the first pass,
+        * because if the devices in question are memory blocks and
+        * CONFIG_MEMCG is set, one of the blocks may hold data structures
+        * that the other blocks depend on, but it is not known in advance which
+        * block holds them.
+        *
+        * If the first pass is successful, the second one isn't needed, though.
+        */
+       status = acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
+                                    NULL, acpi_bus_offline, (void *)false,
+                                    (void **)&errdev);
+       if (status == AE_SUPPORT) {
+               dev_warn(errdev, "Offline disabled.\n");
+               acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
+                                   acpi_bus_online, NULL, NULL, NULL);
+               return -EPERM;
+       }
+       acpi_bus_offline(handle, 0, (void *)false, (void **)&errdev);
+       if (errdev) {
+               errdev = NULL;
+               acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
+                                   NULL, acpi_bus_offline, (void *)true,
+                                   (void **)&errdev);
+               if (!errdev || acpi_force_hot_remove)
+                       acpi_bus_offline(handle, 0, (void *)true,
+                                        (void **)&errdev);
+
+               if (errdev && !acpi_force_hot_remove) {
+                       dev_warn(errdev, "Offline failed.\n");
+                       acpi_bus_online(handle, 0, NULL, NULL);
+                       acpi_walk_namespace(ACPI_TYPE_ANY, handle,
+                                           ACPI_UINT32_MAX, acpi_bus_online,
+                                           NULL, NULL, NULL);
+                       return -EBUSY;
+               }
+       }
+       return 0;
+}
+
+static int acpi_scan_hot_remove(struct acpi_device *device)
+{
+       acpi_handle handle = device->handle;
+       unsigned long long sta;
+       acpi_status status;
+
+       if (device->handler && device->handler->hotplug.demand_offline
+           && !acpi_force_hot_remove) {
+               if (!acpi_scan_is_offline(device, true))
+                       return -EBUSY;
+       } else {
+               int error = acpi_scan_try_to_offline(device);
+               if (error)
+                       return error;
+       }
+
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+               "Hot-removing device %s...\n", dev_name(&device->dev)));
+
+       acpi_bus_trim(device);
+
+       acpi_evaluate_lck(handle, 0);
+       /*
+        * TBD: _EJD support.
+        */
+       status = acpi_evaluate_ej0(handle);
+       if (status == AE_NOT_FOUND)
+               return -ENODEV;
+       else if (ACPI_FAILURE(status))
+               return -EIO;
+
+       /*
+        * Verify if eject was indeed successful.  If not, log an error
+        * message.  No need to call _OST since _EJ0 call was made OK.
+        */
+       status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+       if (ACPI_FAILURE(status)) {
+               acpi_handle_warn(handle,
+                       "Status check after eject failed (0x%x)\n", status);
+       } else if (sta & ACPI_STA_DEVICE_ENABLED) {
+               acpi_handle_warn(handle,
+                       "Eject incomplete - status 0x%llx\n", sta);
+       }
+
+       return 0;
+}
+
+static int acpi_scan_device_not_present(struct acpi_device *adev)
+{
+       if (!acpi_device_enumerated(adev)) {
+               dev_warn(&adev->dev, "Still not present\n");
+               return -EALREADY;
+       }
+       acpi_bus_trim(adev);
+       return 0;
+}
+
+static int acpi_scan_device_check(struct acpi_device *adev)
+{
+       int error;
+
+       acpi_bus_get_status(adev);
+       if (adev->status.present || adev->status.functional) {
+               /*
+                * This function is only called for device objects for which
+                * matching scan handlers exist.  The only situation in which
+                * the scan handler is not attached to this device object yet
+                * is when the device has just appeared (either it wasn't
+                * present at all before or it was removed and then added
+                * again).
+                */
+               if (adev->handler) {
+                       dev_warn(&adev->dev, "Already enumerated\n");
+                       return -EALREADY;
+               }
+               error = acpi_bus_scan(adev->handle);
+               if (error) {
+                       dev_warn(&adev->dev, "Namespace scan failure\n");
+                       return error;
+               }
+               if (!adev->handler) {
+                       dev_warn(&adev->dev, "Enumeration failure\n");
+                       error = -ENODEV;
+               }
+       } else {
+               error = acpi_scan_device_not_present(adev);
+       }
+       return error;
+}
+
+static int acpi_scan_bus_check(struct acpi_device *adev)
+{
+       struct acpi_scan_handler *handler = adev->handler;
+       struct acpi_device *child;
+       int error;
+
+       acpi_bus_get_status(adev);
+       if (!(adev->status.present || adev->status.functional)) {
+               acpi_scan_device_not_present(adev);
+               return 0;
+       }
+       if (handler && handler->hotplug.scan_dependent)
+               return handler->hotplug.scan_dependent(adev);
+
+       error = acpi_bus_scan(adev->handle);
+       if (error) {
+               dev_warn(&adev->dev, "Namespace scan failure\n");
+               return error;
+       }
+       list_for_each_entry(child, &adev->children, node) {
+               error = acpi_scan_bus_check(child);
+               if (error)
+                       return error;
+       }
+       return 0;
+}
+
+static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type)
+{
+       switch (type) {
+       case ACPI_NOTIFY_BUS_CHECK:
+               return acpi_scan_bus_check(adev);
+       case ACPI_NOTIFY_DEVICE_CHECK:
+               return acpi_scan_device_check(adev);
+       case ACPI_NOTIFY_EJECT_REQUEST:
+       case ACPI_OST_EC_OSPM_EJECT:
+               if (adev->handler && !adev->handler->hotplug.enabled) {
+                       dev_info(&adev->dev, "Eject disabled\n");
+                       return -EPERM;
+               }
+               acpi_evaluate_ost(adev->handle, ACPI_NOTIFY_EJECT_REQUEST,
+                                 ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+               return acpi_scan_hot_remove(adev);
+       }
+       return -EINVAL;
+}
+
+void acpi_device_hotplug(struct acpi_device *adev, u32 src)
+{
+       u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+       int error = -ENODEV;
+
+       lock_device_hotplug();
+       mutex_lock(&acpi_scan_lock);
+
+       /*
+        * The device object's ACPI handle cannot become invalid as long as we
+        * are holding acpi_scan_lock, but it might have become invalid before
+        * that lock was acquired.
+        */
+       if (adev->handle == INVALID_ACPI_HANDLE)
+               goto err_out;
+
+       if (adev->flags.is_dock_station) {
+               error = dock_notify(adev, src);
+       } else if (adev->flags.hotplug_notify) {
+               error = acpi_generic_hotplug_event(adev, src);
+               if (error == -EPERM) {
+                       ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
+                       goto err_out;
+               }
+       } else {
+               int (*notify)(struct acpi_device *, u32);
+
+               acpi_lock_hp_context();
+               notify = adev->hp ? adev->hp->notify : NULL;
+               acpi_unlock_hp_context();
+               /*
+                * There may be additional notify handlers for device objects
+                * without the .event() callback, so ignore them here.
+                */
+               if (notify)
+                       error = notify(adev, src);
+               else
+                       goto out;
+       }
+       if (!error)
+               ost_code = ACPI_OST_SC_SUCCESS;
+
+ err_out:
+       acpi_evaluate_ost(adev->handle, src, ost_code, NULL);
+
+ out:
+       acpi_bus_put_acpi_device(adev);
+       mutex_unlock(&acpi_scan_lock);
+       unlock_device_hotplug();
+}
+
+static ssize_t real_power_state_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       struct acpi_device *adev = to_acpi_device(dev);
+       int state;
+       int ret;
+
+       ret = acpi_device_get_power(adev, &state);
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%s\n", acpi_power_state_string(state));
+}
+
+static DEVICE_ATTR(real_power_state, 0444, real_power_state_show, NULL);
+
+static ssize_t power_state_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct acpi_device *adev = to_acpi_device(dev);
+
+       return sprintf(buf, "%s\n", acpi_power_state_string(adev->power.state));
+}
+
+static DEVICE_ATTR(power_state, 0444, power_state_show, NULL);
+
+static ssize_t
+acpi_eject_store(struct device *d, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct acpi_device *acpi_device = to_acpi_device(d);
+       acpi_object_type not_used;
+       acpi_status status;
+
+       if (!count || buf[0] != '1')
+               return -EINVAL;
+
+       if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled)
+           && !acpi_device->driver)
+               return -ENODEV;
+
+       status = acpi_get_type(acpi_device->handle, &not_used);
+       if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable)
+               return -ENODEV;
+
+       get_device(&acpi_device->dev);
+       status = acpi_hotplug_schedule(acpi_device, ACPI_OST_EC_OSPM_EJECT);
+       if (ACPI_SUCCESS(status))
+               return count;
+
+       put_device(&acpi_device->dev);
+       acpi_evaluate_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT,
+                         ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
+       return status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN;
+}
+
+static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
+
+static ssize_t
+acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) {
+       struct acpi_device *acpi_dev = to_acpi_device(dev);
+
+       return sprintf(buf, "%s\n", acpi_device_hid(acpi_dev));
+}
+static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL);
+
+static ssize_t acpi_device_uid_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct acpi_device *acpi_dev = to_acpi_device(dev);
+
+       return sprintf(buf, "%s\n", acpi_dev->pnp.unique_id);
+}
+static DEVICE_ATTR(uid, 0444, acpi_device_uid_show, NULL);
+
+static ssize_t acpi_device_adr_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct acpi_device *acpi_dev = to_acpi_device(dev);
+
+       return sprintf(buf, "0x%08x\n",
+                      (unsigned int)(acpi_dev->pnp.bus_address));
+}
+static DEVICE_ATTR(adr, 0444, acpi_device_adr_show, NULL);
+
+static ssize_t
+acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) {
+       struct acpi_device *acpi_dev = to_acpi_device(dev);
+       struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
+       int result;
+
+       result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path);
+       if (result)
+               goto end;
+
+       result = sprintf(buf, "%s\n", (char*)path.pointer);
+       kfree(path.pointer);
+end:
+       return result;
+}
+static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL);
+
+/* sysfs file that shows description text from the ACPI _STR method */
+static ssize_t description_show(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf) {
+       struct acpi_device *acpi_dev = to_acpi_device(dev);
+       int result;
+
+       if (acpi_dev->pnp.str_obj == NULL)
+               return 0;
+
+       /*
+        * The _STR object contains a Unicode identifier for a device.
+        * We need to convert to utf-8 so it can be displayed.
+        */
+       result = utf16s_to_utf8s(
+               (wchar_t *)acpi_dev->pnp.str_obj->buffer.pointer,
+               acpi_dev->pnp.str_obj->buffer.length,
+               UTF16_LITTLE_ENDIAN, buf,
+               PAGE_SIZE);
+
+       buf[result++] = '\n';
+
+       return result;
+}
+static DEVICE_ATTR(description, 0444, description_show, NULL);
+
+static ssize_t
+acpi_device_sun_show(struct device *dev, struct device_attribute *attr,
+                    char *buf) {
+       struct acpi_device *acpi_dev = to_acpi_device(dev);
+       acpi_status status;
+       unsigned long long sun;
+
+       status = acpi_evaluate_integer(acpi_dev->handle, "_SUN", NULL, &sun);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+
+       return sprintf(buf, "%llu\n", sun);
+}
+static DEVICE_ATTR(sun, 0444, acpi_device_sun_show, NULL);
+
+static ssize_t status_show(struct device *dev, struct device_attribute *attr,
+                               char *buf) {
+       struct acpi_device *acpi_dev = to_acpi_device(dev);
+       acpi_status status;
+       unsigned long long sta;
+
+       status = acpi_evaluate_integer(acpi_dev->handle, "_STA", NULL, &sta);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+
+       return sprintf(buf, "%llu\n", sta);
+}
+static DEVICE_ATTR_RO(status);
+
+static int acpi_device_setup_files(struct acpi_device *dev)
+{
+       struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+       acpi_status status;
+       int result = 0;
+
+       /*
+        * Devices gotten from FADT don't have a "path" attribute
+        */
+       if (dev->handle) {
+               result = device_create_file(&dev->dev, &dev_attr_path);
+               if (result)
+                       goto end;
+       }
+
+       if (!list_empty(&dev->pnp.ids)) {
+               result = device_create_file(&dev->dev, &dev_attr_hid);
+               if (result)
+                       goto end;
+
+               result = device_create_file(&dev->dev, &dev_attr_modalias);
+               if (result)
+                       goto end;
+       }
+
+       /*
+        * If device has _STR, 'description' file is created
+        */
+       if (acpi_has_method(dev->handle, "_STR")) {
+               status = acpi_evaluate_object(dev->handle, "_STR",
+                                       NULL, &buffer);
+               if (ACPI_FAILURE(status))
+                       buffer.pointer = NULL;
+               dev->pnp.str_obj = buffer.pointer;
+               result = device_create_file(&dev->dev, &dev_attr_description);
+               if (result)
+                       goto end;
+       }
+
+       if (dev->pnp.type.bus_address)
+               result = device_create_file(&dev->dev, &dev_attr_adr);
+       if (dev->pnp.unique_id)
+               result = device_create_file(&dev->dev, &dev_attr_uid);
+
+       if (acpi_has_method(dev->handle, "_SUN")) {
+               result = device_create_file(&dev->dev, &dev_attr_sun);
+               if (result)
+                       goto end;
+       }
+
+       if (acpi_has_method(dev->handle, "_STA")) {
+               result = device_create_file(&dev->dev, &dev_attr_status);
+               if (result)
+                       goto end;
+       }
+
+        /*
+         * If device has _EJ0, 'eject' file is created that is used to trigger
+         * hot-removal function from userland.
+         */
+       if (acpi_has_method(dev->handle, "_EJ0")) {
+               result = device_create_file(&dev->dev, &dev_attr_eject);
+               if (result)
+                       return result;
+       }
+
+       if (dev->flags.power_manageable) {
+               result = device_create_file(&dev->dev, &dev_attr_power_state);
+               if (result)
+                       return result;
+
+               if (dev->power.flags.power_resources)
+                       result = device_create_file(&dev->dev,
+                                                   &dev_attr_real_power_state);
+       }
+
+end:
+       return result;
+}
+
+static void acpi_device_remove_files(struct acpi_device *dev)
+{
+       if (dev->flags.power_manageable) {
+               device_remove_file(&dev->dev, &dev_attr_power_state);
+               if (dev->power.flags.power_resources)
+                       device_remove_file(&dev->dev,
+                                          &dev_attr_real_power_state);
+       }
+
+       /*
+        * If device has _STR, remove 'description' file
+        */
+       if (acpi_has_method(dev->handle, "_STR")) {
+               kfree(dev->pnp.str_obj);
+               device_remove_file(&dev->dev, &dev_attr_description);
+       }
+       /*
+        * If device has _EJ0, remove 'eject' file.
+        */
+       if (acpi_has_method(dev->handle, "_EJ0"))
+               device_remove_file(&dev->dev, &dev_attr_eject);
+
+       if (acpi_has_method(dev->handle, "_SUN"))
+               device_remove_file(&dev->dev, &dev_attr_sun);
+
+       if (dev->pnp.unique_id)
+               device_remove_file(&dev->dev, &dev_attr_uid);
+       if (dev->pnp.type.bus_address)
+               device_remove_file(&dev->dev, &dev_attr_adr);
+       device_remove_file(&dev->dev, &dev_attr_modalias);
+       device_remove_file(&dev->dev, &dev_attr_hid);
+       if (acpi_has_method(dev->handle, "_STA"))
+               device_remove_file(&dev->dev, &dev_attr_status);
+       if (dev->handle)
+               device_remove_file(&dev->dev, &dev_attr_path);
+}
+/* --------------------------------------------------------------------------
+                       ACPI Bus operations
+   -------------------------------------------------------------------------- */
+
+/**
+ * acpi_of_match_device - Match device object using the "compatible" property.
+ * @adev: ACPI device object to match.
+ * @of_match_table: List of device IDs to match against.
+ *
+ * If @dev has an ACPI companion which has the special PRP0001 device ID in its
+ * list of identifiers and a _DSD object with the "compatible" property, use
+ * that property to match against the given list of identifiers.
+ */
+static bool acpi_of_match_device(struct acpi_device *adev,
+                                const struct of_device_id *of_match_table)
+{
+       const union acpi_object *of_compatible, *obj;
+       int i, nval;
+
+       if (!adev)
+               return false;
+
+       of_compatible = adev->data.of_compatible;
+       if (!of_match_table || !of_compatible)
+               return false;
+
+       if (of_compatible->type == ACPI_TYPE_PACKAGE) {
+               nval = of_compatible->package.count;
+               obj = of_compatible->package.elements;
+       } else { /* Must be ACPI_TYPE_STRING. */
+               nval = 1;
+               obj = of_compatible;
+       }
+       /* Now we can look for the driver DT compatible strings */
+       for (i = 0; i < nval; i++, obj++) {
+               const struct of_device_id *id;
+
+               for (id = of_match_table; id->compatible[0]; id++)
+                       if (!strcasecmp(obj->string.pointer, id->compatible))
+                               return true;
+       }
+
+       return false;
+}
+
+static const struct acpi_device_id *__acpi_match_device(
+       struct acpi_device *device,
+       const struct acpi_device_id *ids,
+       const struct of_device_id *of_ids)
+{
+       const struct acpi_device_id *id;
+       struct acpi_hardware_id *hwid;
+
+       /*
+        * If the device is not present, it is unnecessary to load device
+        * driver for it.
+        */
+       if (!device || !device->status.present)
+               return NULL;
+
+       list_for_each_entry(hwid, &device->pnp.ids, list) {
+               /* First, check the ACPI/PNP IDs provided by the caller. */
+               for (id = ids; id->id[0]; id++)
+                       if (!strcmp((char *) id->id, hwid->id))
+                               return id;
+
+               /*
+                * Next, check the special "PRP0001" ID and try to match the
+                * "compatible" property if found.
+                *
+                * The id returned by the below is not valid, but the only
+                * caller passing non-NULL of_ids here is only interested in
+                * whether or not the return value is NULL.
+                */
+               if (!strcmp("PRP0001", hwid->id)
+                   && acpi_of_match_device(device, of_ids))
+                       return id;
+       }
+       return NULL;
+}
+
+/**
+ * acpi_match_device - Match a struct device against a given list of ACPI IDs
+ * @ids: Array of struct acpi_device_id object to match against.
+ * @dev: The device structure to match.
+ *
+ * Check if @dev has a valid ACPI handle and if there is a struct acpi_device
+ * object for that handle and use that object to match against a given list of
+ * device IDs.
+ *
+ * Return a pointer to the first matching ID on success or %NULL on failure.
+ */
+const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
+                                              const struct device *dev)
+{
+       return __acpi_match_device(acpi_companion_match(dev), ids, NULL);
+}
+EXPORT_SYMBOL_GPL(acpi_match_device);
+
+int acpi_match_device_ids(struct acpi_device *device,
+                         const struct acpi_device_id *ids)
+{
+       return __acpi_match_device(device, ids, NULL) ? 0 : -ENOENT;
+}
+EXPORT_SYMBOL(acpi_match_device_ids);
+
+bool acpi_driver_match_device(struct device *dev,
+                             const struct device_driver *drv)
+{
+       if (!drv->acpi_match_table)
+               return acpi_of_match_device(ACPI_COMPANION(dev),
+                                           drv->of_match_table);
+
+       return !!__acpi_match_device(acpi_companion_match(dev),
+                                    drv->acpi_match_table, drv->of_match_table);
+}
+EXPORT_SYMBOL_GPL(acpi_driver_match_device);
+
+static void acpi_free_power_resources_lists(struct acpi_device *device)
+{
+       int i;
+
+       if (device->wakeup.flags.valid)
+               acpi_power_resources_list_free(&device->wakeup.resources);
+
+       if (!device->power.flags.power_resources)
+               return;
+
+       for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) {
+               struct acpi_device_power_state *ps = &device->power.states[i];
+               acpi_power_resources_list_free(&ps->resources);
+       }
+}
+
+static void acpi_device_release(struct device *dev)
+{
+       struct acpi_device *acpi_dev = to_acpi_device(dev);
+
+       acpi_free_properties(acpi_dev);
+       acpi_free_pnp_ids(&acpi_dev->pnp);
+       acpi_free_power_resources_lists(acpi_dev);
+       kfree(acpi_dev);
+}
+
+static int acpi_bus_match(struct device *dev, struct device_driver *drv)
+{
+       struct acpi_device *acpi_dev = to_acpi_device(dev);
+       struct acpi_driver *acpi_drv = to_acpi_driver(drv);
+
+       return acpi_dev->flags.match_driver
+               && !acpi_match_device_ids(acpi_dev, acpi_drv->ids);
+}
+
+static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       return __acpi_device_uevent_modalias(to_acpi_device(dev), env);
+}
+
+static void acpi_device_notify(acpi_handle handle, u32 event, void *data)
+{
+       struct acpi_device *device = data;
+
+       device->driver->ops.notify(device, event);
+}
+
+static void acpi_device_notify_fixed(void *data)
+{
+       struct acpi_device *device = data;
+
+       /* Fixed hardware devices have no handles */
+       acpi_device_notify(NULL, ACPI_FIXED_HARDWARE_EVENT, device);
+}
+
+static u32 acpi_device_fixed_event(void *data)
+{
+       acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_device_notify_fixed, data);
+       return ACPI_INTERRUPT_HANDLED;
+}
+
+static int acpi_device_install_notify_handler(struct acpi_device *device)
+{
+       acpi_status status;
+
+       if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON)
+               status =
+                   acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
+                                                    acpi_device_fixed_event,
+                                                    device);
+       else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON)
+               status =
+                   acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
+                                                    acpi_device_fixed_event,
+                                                    device);
+       else
+               status = acpi_install_notify_handler(device->handle,
+                                                    ACPI_DEVICE_NOTIFY,
+                                                    acpi_device_notify,
+                                                    device);
+
+       if (ACPI_FAILURE(status))
+               return -EINVAL;
+       return 0;
+}
+
+static void acpi_device_remove_notify_handler(struct acpi_device *device)
+{
+       if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON)
+               acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
+                                               acpi_device_fixed_event);
+       else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON)
+               acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
+                                               acpi_device_fixed_event);
+       else
+               acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
+                                          acpi_device_notify);
+}
+
+static int acpi_device_probe(struct device *dev)
+{
+       struct acpi_device *acpi_dev = to_acpi_device(dev);
+       struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver);
+       int ret;
+
+       if (acpi_dev->handler && !acpi_is_pnp_device(acpi_dev))
+               return -EINVAL;
+
+       if (!acpi_drv->ops.add)
+               return -ENOSYS;
+
+       ret = acpi_drv->ops.add(acpi_dev);
+       if (ret)
+               return ret;
+
+       acpi_dev->driver = acpi_drv;
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                         "Driver [%s] successfully bound to device [%s]\n",
+                         acpi_drv->name, acpi_dev->pnp.bus_id));
+
+       if (acpi_drv->ops.notify) {
+               ret = acpi_device_install_notify_handler(acpi_dev);
+               if (ret) {
+                       if (acpi_drv->ops.remove)
+                               acpi_drv->ops.remove(acpi_dev);
+
+                       acpi_dev->driver = NULL;
+                       acpi_dev->driver_data = NULL;
+                       return ret;
+               }
+       }
+
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n",
+                         acpi_drv->name, acpi_dev->pnp.bus_id));
+       get_device(dev);
+       return 0;
+}
+
+static int acpi_device_remove(struct device * dev)
+{
+       struct acpi_device *acpi_dev = to_acpi_device(dev);
+       struct acpi_driver *acpi_drv = acpi_dev->driver;
+
+       if (acpi_drv) {
+               if (acpi_drv->ops.notify)
+                       acpi_device_remove_notify_handler(acpi_dev);
+               if (acpi_drv->ops.remove)
+                       acpi_drv->ops.remove(acpi_dev);
+       }
+       acpi_dev->driver = NULL;
+       acpi_dev->driver_data = NULL;
+
+       put_device(dev);
+       return 0;
+}
+
+struct bus_type acpi_bus_type = {
+       .name           = "acpi",
+       .match          = acpi_bus_match,
+       .probe          = acpi_device_probe,
+       .remove         = acpi_device_remove,
+       .uevent         = acpi_device_uevent,
+};
+
+static void acpi_device_del(struct acpi_device *device)
+{
+       mutex_lock(&acpi_device_lock);
+       if (device->parent)
+               list_del(&device->node);
+
+       list_del(&device->wakeup_list);
+       mutex_unlock(&acpi_device_lock);
+
+       acpi_power_add_remove_device(device, false);
+       acpi_device_remove_files(device);
+       if (device->remove)
+               device->remove(device);
+
+       device_del(&device->dev);
+}
+
+static LIST_HEAD(acpi_device_del_list);
+static DEFINE_MUTEX(acpi_device_del_lock);
+
+static void acpi_device_del_work_fn(struct work_struct *work_not_used)
+{
+       for (;;) {
+               struct acpi_device *adev;
+
+               mutex_lock(&acpi_device_del_lock);
+
+               if (list_empty(&acpi_device_del_list)) {
+                       mutex_unlock(&acpi_device_del_lock);
+                       break;
+               }
+               adev = list_first_entry(&acpi_device_del_list,
+                                       struct acpi_device, del_list);
+               list_del(&adev->del_list);
+
+               mutex_unlock(&acpi_device_del_lock);
+
+               acpi_device_del(adev);
+               /*
+                * Drop references to all power resources that might have been
+                * used by the device.
+                */
+               acpi_power_transition(adev, ACPI_STATE_D3_COLD);
+               put_device(&adev->dev);
+       }
+}
+
+/**
+ * acpi_scan_drop_device - Drop an ACPI device object.
+ * @handle: Handle of an ACPI namespace node, not used.
+ * @context: Address of the ACPI device object to drop.
+ *
+ * This is invoked by acpi_ns_delete_node() during the removal of the ACPI
+ * namespace node the device object pointed to by @context is attached to.
+ *
+ * The unregistration is carried out asynchronously to avoid running
+ * acpi_device_del() under the ACPICA's namespace mutex and the list is used to
+ * ensure the correct ordering (the device objects must be unregistered in the
+ * same order in which the corresponding namespace nodes are deleted).
+ */
+static void acpi_scan_drop_device(acpi_handle handle, void *context)
+{
+       static DECLARE_WORK(work, acpi_device_del_work_fn);
+       struct acpi_device *adev = context;
+
+       mutex_lock(&acpi_device_del_lock);
+
+       /*
+        * Use the ACPI hotplug workqueue which is ordered, so this work item
+        * won't run after any hotplug work items submitted subsequently.  That
+        * prevents attempts to register device objects identical to those being
+        * deleted from happening concurrently (such attempts result from
+        * hotplug events handled via the ACPI hotplug workqueue).  It also will
+        * run after all of the work items submitted previosuly, which helps
+        * those work items to ensure that they are not accessing stale device
+        * objects.
+        */
+       if (list_empty(&acpi_device_del_list))
+               acpi_queue_hotplug_work(&work);
+
+       list_add_tail(&adev->del_list, &acpi_device_del_list);
+       /* Make acpi_ns_validate_handle() return NULL for this handle. */
+       adev->handle = INVALID_ACPI_HANDLE;
+
+       mutex_unlock(&acpi_device_del_lock);
+}
+
+static int acpi_get_device_data(acpi_handle handle, struct acpi_device **device,
+                               void (*callback)(void *))
+{
+       acpi_status status;
+
+       if (!device)
+               return -EINVAL;
+
+       status = acpi_get_data_full(handle, acpi_scan_drop_device,
+                                   (void **)device, callback);
+       if (ACPI_FAILURE(status) || !*device) {
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
+                                 handle));
+               return -ENODEV;
+       }
+       return 0;
+}
+
+int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
+{
+       return acpi_get_device_data(handle, device, NULL);
+}
+EXPORT_SYMBOL(acpi_bus_get_device);
+
+static void get_acpi_device(void *dev)
+{
+       if (dev)
+               get_device(&((struct acpi_device *)dev)->dev);
+}
+
+struct acpi_device *acpi_bus_get_acpi_device(acpi_handle handle)
+{
+       struct acpi_device *adev = NULL;
+
+       acpi_get_device_data(handle, &adev, get_acpi_device);
+       return adev;
+}
+
+void acpi_bus_put_acpi_device(struct acpi_device *adev)
+{
+       put_device(&adev->dev);
+}
+
+int acpi_device_add(struct acpi_device *device,
+                   void (*release)(struct device *))
+{
+       int result;
+       struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id;
+       int found = 0;
+
+       if (device->handle) {
+               acpi_status status;
+
+               status = acpi_attach_data(device->handle, acpi_scan_drop_device,
+                                         device);
+               if (ACPI_FAILURE(status)) {
+                       acpi_handle_err(device->handle,
+                                       "Unable to attach device data\n");
+                       return -ENODEV;
+               }
+       }
+
+       /*
+        * Linkage
+        * -------
+        * Link this device to its parent and siblings.
+        */
+       INIT_LIST_HEAD(&device->children);
+       INIT_LIST_HEAD(&device->node);
+       INIT_LIST_HEAD(&device->wakeup_list);
+       INIT_LIST_HEAD(&device->physical_node_list);
+       INIT_LIST_HEAD(&device->del_list);
+       mutex_init(&device->physical_node_lock);
+
+       new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL);
+       if (!new_bus_id) {
+               pr_err(PREFIX "Memory allocation error\n");
+               result = -ENOMEM;
+               goto err_detach;
+       }
+
+       mutex_lock(&acpi_device_lock);
+       /*
+        * Find suitable bus_id and instance number in acpi_bus_id_list
+        * If failed, create one and link it into acpi_bus_id_list
+        */
+       list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) {
+               if (!strcmp(acpi_device_bus_id->bus_id,
+                           acpi_device_hid(device))) {
+                       acpi_device_bus_id->instance_no++;
+                       found = 1;
+                       kfree(new_bus_id);
+                       break;
+               }
+       }
+       if (!found) {
+               acpi_device_bus_id = new_bus_id;
+               strcpy(acpi_device_bus_id->bus_id, acpi_device_hid(device));
+               acpi_device_bus_id->instance_no = 0;
+               list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list);
+       }
+       dev_set_name(&device->dev, "%s:%02x", acpi_device_bus_id->bus_id, acpi_device_bus_id->instance_no);
+
+       if (device->parent)
+               list_add_tail(&device->node, &device->parent->children);
+
+       if (device->wakeup.flags.valid)
+               list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list);
+       mutex_unlock(&acpi_device_lock);
+
+       if (device->parent)
+               device->dev.parent = &device->parent->dev;
+       device->dev.bus = &acpi_bus_type;
+       device->dev.release = release;
+       result = device_add(&device->dev);
+       if (result) {
+               dev_err(&device->dev, "Error registering device\n");
+               goto err;
+       }
+
+       result = acpi_device_setup_files(device);
+       if (result)
+               printk(KERN_ERR PREFIX "Error creating sysfs interface for device %s\n",
+                      dev_name(&device->dev));
+
+       return 0;
+
+ err:
+       mutex_lock(&acpi_device_lock);
+       if (device->parent)
+               list_del(&device->node);
+       list_del(&device->wakeup_list);
+       mutex_unlock(&acpi_device_lock);
+
+ err_detach:
+       acpi_detach_data(device->handle, acpi_scan_drop_device);
+       return result;
+}
+
+struct acpi_device *acpi_get_next_child(struct device *dev,
+                                       struct acpi_device *child)
+{
+       struct acpi_device *adev = ACPI_COMPANION(dev);
+       struct list_head *head, *next;
+
+       if (!adev)
+               return NULL;
+
+       head = &adev->children;
+       if (list_empty(head))
+               return NULL;
+
+       if (!child)
+               return list_first_entry(head, struct acpi_device, node);
+
+       next = child->node.next;
+       return next == head ? NULL : list_entry(next, struct acpi_device, node);
+}
+
+/* --------------------------------------------------------------------------
+                                 Driver Management
+   -------------------------------------------------------------------------- */
+/**
+ * acpi_bus_register_driver - register a driver with the ACPI bus
+ * @driver: driver being registered
+ *
+ * Registers a driver with the ACPI bus.  Searches the namespace for all
+ * devices that match the driver's criteria and binds.  Returns zero for
+ * success or a negative error status for failure.
+ */
+int acpi_bus_register_driver(struct acpi_driver *driver)
+{
+       int ret;
+
+       if (acpi_disabled)
+               return -ENODEV;
+       driver->drv.name = driver->name;
+       driver->drv.bus = &acpi_bus_type;
+       driver->drv.owner = driver->owner;
+
+       ret = driver_register(&driver->drv);
+       return ret;
+}
+
+EXPORT_SYMBOL(acpi_bus_register_driver);
+
+/**
+ * acpi_bus_unregister_driver - unregisters a driver with the ACPI bus
+ * @driver: driver to unregister
+ *
+ * Unregisters a driver with the ACPI bus.  Searches the namespace for all
+ * devices that match the driver's criteria and unbinds.
+ */
+void acpi_bus_unregister_driver(struct acpi_driver *driver)
+{
+       driver_unregister(&driver->drv);
+}
+
+EXPORT_SYMBOL(acpi_bus_unregister_driver);
+
+/* --------------------------------------------------------------------------
+                                 Device Enumeration
+   -------------------------------------------------------------------------- */
+static struct acpi_device *acpi_bus_get_parent(acpi_handle handle)
+{
+       struct acpi_device *device = NULL;
+       acpi_status status;
+
+       /*
+        * Fixed hardware devices do not appear in the namespace and do not
+        * have handles, but we fabricate acpi_devices for them, so we have
+        * to deal with them specially.
+        */
+       if (!handle)
+               return acpi_root;
+
+       do {
+               status = acpi_get_parent(handle, &handle);
+               if (ACPI_FAILURE(status))
+                       return status == AE_NULL_ENTRY ? NULL : acpi_root;
+       } while (acpi_bus_get_device(handle, &device));
+       return device;
+}
+
+acpi_status
+acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd)
+{
+       acpi_status status;
+       acpi_handle tmp;
+       struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+       union acpi_object *obj;
+
+       status = acpi_get_handle(handle, "_EJD", &tmp);
+       if (ACPI_FAILURE(status))
+               return status;
+
+       status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer);
+       if (ACPI_SUCCESS(status)) {
+               obj = buffer.pointer;
+               status = acpi_get_handle(ACPI_ROOT_OBJECT, obj->string.pointer,
+                                        ejd);
+               kfree(buffer.pointer);
+       }
+       return status;
+}
+EXPORT_SYMBOL_GPL(acpi_bus_get_ejd);
+
+static int acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
+                                       struct acpi_device_wakeup *wakeup)
+{
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *package = NULL;
+       union acpi_object *element = NULL;
+       acpi_status status;
+       int err = -ENODATA;
+
+       if (!wakeup)
+               return -EINVAL;
+
+       INIT_LIST_HEAD(&wakeup->resources);
+
+       /* _PRW */
+       status = acpi_evaluate_object(handle, "_PRW", NULL, &buffer);
+       if (ACPI_FAILURE(status)) {
+               ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW"));
+               return err;
+       }
+
+       package = (union acpi_object *)buffer.pointer;
+
+       if (!package || package->package.count < 2)
+               goto out;
+
+       element = &(package->package.elements[0]);
+       if (!element)
+               goto out;
+
+       if (element->type == ACPI_TYPE_PACKAGE) {
+               if ((element->package.count < 2) ||
+                   (element->package.elements[0].type !=
+                    ACPI_TYPE_LOCAL_REFERENCE)
+                   || (element->package.elements[1].type != ACPI_TYPE_INTEGER))
+                       goto out;
+
+               wakeup->gpe_device =
+                   element->package.elements[0].reference.handle;
+               wakeup->gpe_number =
+                   (u32) element->package.elements[1].integer.value;
+       } else if (element->type == ACPI_TYPE_INTEGER) {
+               wakeup->gpe_device = NULL;
+               wakeup->gpe_number = element->integer.value;
+       } else {
+               goto out;
+       }
+
+       element = &(package->package.elements[1]);
+       if (element->type != ACPI_TYPE_INTEGER)
+               goto out;
+
+       wakeup->sleep_state = element->integer.value;
+
+       err = acpi_extract_power_resources(package, 2, &wakeup->resources);
+       if (err)
+               goto out;
+
+       if (!list_empty(&wakeup->resources)) {
+               int sleep_state;
+
+               err = acpi_power_wakeup_list_init(&wakeup->resources,
+                                                 &sleep_state);
+               if (err) {
+                       acpi_handle_warn(handle, "Retrieving current states "
+                                        "of wakeup power resources failed\n");
+                       acpi_power_resources_list_free(&wakeup->resources);
+                       goto out;
+               }
+               if (sleep_state < wakeup->sleep_state) {
+                       acpi_handle_warn(handle, "Overriding _PRW sleep state "
+                                        "(S%d) by S%d from power resources\n",
+                                        (int)wakeup->sleep_state, sleep_state);
+                       wakeup->sleep_state = sleep_state;
+               }
+       }
+
+ out:
+       kfree(buffer.pointer);
+       return err;
+}
+
+static void acpi_wakeup_gpe_init(struct acpi_device *device)
+{
+       struct acpi_device_id button_device_ids[] = {
+               {"PNP0C0C", 0},
+               {"PNP0C0D", 0},
+               {"PNP0C0E", 0},
+               {"", 0},
+       };
+       struct acpi_device_wakeup *wakeup = &device->wakeup;
+       acpi_status status;
+       acpi_event_status event_status;
+
+       wakeup->flags.notifier_present = 0;
+
+       /* Power button, Lid switch always enable wakeup */
+       if (!acpi_match_device_ids(device, button_device_ids)) {
+               wakeup->flags.run_wake = 1;
+               if (!acpi_match_device_ids(device, &button_device_ids[1])) {
+                       /* Do not use Lid/sleep button for S5 wakeup */
+                       if (wakeup->sleep_state == ACPI_STATE_S5)
+                               wakeup->sleep_state = ACPI_STATE_S4;
+               }
+               acpi_mark_gpe_for_wake(wakeup->gpe_device, wakeup->gpe_number);
+               device_set_wakeup_capable(&device->dev, true);
+               return;
+       }
+
+       acpi_setup_gpe_for_wake(device->handle, wakeup->gpe_device,
+                               wakeup->gpe_number);
+       status = acpi_get_gpe_status(wakeup->gpe_device, wakeup->gpe_number,
+                                    &event_status);
+       if (ACPI_FAILURE(status))
+               return;
+
+       wakeup->flags.run_wake = !!(event_status & ACPI_EVENT_FLAG_HAS_HANDLER);
+}
+
+static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
+{
+       int err;
+
+       /* Presence of _PRW indicates wake capable */
+       if (!acpi_has_method(device->handle, "_PRW"))
+               return;
+
+       err = acpi_bus_extract_wakeup_device_power_package(device->handle,
+                                                          &device->wakeup);
+       if (err) {
+               dev_err(&device->dev, "_PRW evaluation error: %d\n", err);
+               return;
+       }
+
+       device->wakeup.flags.valid = 1;
+       device->wakeup.prepare_count = 0;
+       acpi_wakeup_gpe_init(device);
+       /* Call _PSW/_DSW object to disable its ability to wake the sleeping
+        * system for the ACPI device with the _PRW object.
+        * The _PSW object is depreciated in ACPI 3.0 and is replaced by _DSW.
+        * So it is necessary to call _DSW object first. Only when it is not
+        * present will the _PSW object used.
+        */
+       err = acpi_device_sleep_wake(device, 0, 0, 0);
+       if (err)
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                               "error in _DSW or _PSW evaluation\n"));
+}
+
+static void acpi_bus_init_power_state(struct acpi_device *device, int state)
+{
+       struct acpi_device_power_state *ps = &device->power.states[state];
+       char pathname[5] = { '_', 'P', 'R', '0' + state, '\0' };
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       acpi_status status;
+
+       INIT_LIST_HEAD(&ps->resources);
+
+       /* Evaluate "_PRx" to get referenced power resources */
+       status = acpi_evaluate_object(device->handle, pathname, NULL, &buffer);
+       if (ACPI_SUCCESS(status)) {
+               union acpi_object *package = buffer.pointer;
+
+               if (buffer.length && package
+                   && package->type == ACPI_TYPE_PACKAGE
+                   && package->package.count) {
+                       int err = acpi_extract_power_resources(package, 0,
+                                                              &ps->resources);
+                       if (!err)
+                               device->power.flags.power_resources = 1;
+               }
+               ACPI_FREE(buffer.pointer);
+       }
+
+       /* Evaluate "_PSx" to see if we can do explicit sets */
+       pathname[2] = 'S';
+       if (acpi_has_method(device->handle, pathname))
+               ps->flags.explicit_set = 1;
+
+       /*
+        * State is valid if there are means to put the device into it.
+        * D3hot is only valid if _PR3 present.
+        */
+       if (!list_empty(&ps->resources)
+           || (ps->flags.explicit_set && state < ACPI_STATE_D3_HOT)) {
+               ps->flags.valid = 1;
+               ps->flags.os_accessible = 1;
+       }
+
+       ps->power = -1;         /* Unknown - driver assigned */
+       ps->latency = -1;       /* Unknown - driver assigned */
+}
+
+static void acpi_bus_get_power_flags(struct acpi_device *device)
+{
+       u32 i;
+
+       /* Presence of _PS0|_PR0 indicates 'power manageable' */
+       if (!acpi_has_method(device->handle, "_PS0") &&
+           !acpi_has_method(device->handle, "_PR0"))
+               return;
+
+       device->flags.power_manageable = 1;
+
+       /*
+        * Power Management Flags
+        */
+       if (acpi_has_method(device->handle, "_PSC"))
+               device->power.flags.explicit_get = 1;
+
+       if (acpi_has_method(device->handle, "_IRC"))
+               device->power.flags.inrush_current = 1;
+
+       if (acpi_has_method(device->handle, "_DSW"))
+               device->power.flags.dsw_present = 1;
+
+       /*
+        * Enumerate supported power management states
+        */
+       for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++)
+               acpi_bus_init_power_state(device, i);
+
+       INIT_LIST_HEAD(&device->power.states[ACPI_STATE_D3_COLD].resources);
+
+       /* Set defaults for D0 and D3 states (always valid) */
+       device->power.states[ACPI_STATE_D0].flags.valid = 1;
+       device->power.states[ACPI_STATE_D0].power = 100;
+       device->power.states[ACPI_STATE_D3_COLD].flags.valid = 1;
+       device->power.states[ACPI_STATE_D3_COLD].power = 0;
+
+       /* Set D3cold's explicit_set flag if _PS3 exists. */
+       if (device->power.states[ACPI_STATE_D3_HOT].flags.explicit_set)
+               device->power.states[ACPI_STATE_D3_COLD].flags.explicit_set = 1;
+
+       /* Presence of _PS3 or _PRx means we can put the device into D3 cold */
+       if (device->power.states[ACPI_STATE_D3_HOT].flags.explicit_set ||
+                       device->power.flags.power_resources)
+               device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible = 1;
+
+       if (acpi_bus_init_power(device))
+               device->flags.power_manageable = 0;
+}
+
+static void acpi_bus_get_flags(struct acpi_device *device)
+{
+       /* Presence of _STA indicates 'dynamic_status' */
+       if (acpi_has_method(device->handle, "_STA"))
+               device->flags.dynamic_status = 1;
+
+       /* Presence of _RMV indicates 'removable' */
+       if (acpi_has_method(device->handle, "_RMV"))
+               device->flags.removable = 1;
+
+       /* Presence of _EJD|_EJ0 indicates 'ejectable' */
+       if (acpi_has_method(device->handle, "_EJD") ||
+           acpi_has_method(device->handle, "_EJ0"))
+               device->flags.ejectable = 1;
+}
+
+static void acpi_device_get_busid(struct acpi_device *device)
+{
+       char bus_id[5] = { '?', 0 };
+       struct acpi_buffer buffer = { sizeof(bus_id), bus_id };
+       int i = 0;
+
+       /*
+        * Bus ID
+        * ------
+        * The device's Bus ID is simply the object name.
+        * TBD: Shouldn't this value be unique (within the ACPI namespace)?
+        */
+       if (ACPI_IS_ROOT_DEVICE(device)) {
+               strcpy(device->pnp.bus_id, "ACPI");
+               return;
+       }
+
+       switch (device->device_type) {
+       case ACPI_BUS_TYPE_POWER_BUTTON:
+               strcpy(device->pnp.bus_id, "PWRF");
+               break;
+       case ACPI_BUS_TYPE_SLEEP_BUTTON:
+               strcpy(device->pnp.bus_id, "SLPF");
+               break;
+       default:
+               acpi_get_name(device->handle, ACPI_SINGLE_NAME, &buffer);
+               /* Clean up trailing underscores (if any) */
+               for (i = 3; i > 1; i--) {
+                       if (bus_id[i] == '_')
+                               bus_id[i] = '\0';
+                       else
+                               break;
+               }
+               strcpy(device->pnp.bus_id, bus_id);
+               break;
+       }
+}
+
+/*
+ * acpi_ata_match - see if an acpi object is an ATA device
+ *
+ * If an acpi object has one of the ACPI ATA methods defined,
+ * then we can safely call it an ATA device.
+ */
+bool acpi_ata_match(acpi_handle handle)
+{
+       return acpi_has_method(handle, "_GTF") ||
+              acpi_has_method(handle, "_GTM") ||
+              acpi_has_method(handle, "_STM") ||
+              acpi_has_method(handle, "_SDD");
+}
+
+/*
+ * acpi_bay_match - see if an acpi object is an ejectable driver bay
+ *
+ * If an acpi object is ejectable and has one of the ACPI ATA methods defined,
+ * then we can safely call it an ejectable drive bay
+ */
+bool acpi_bay_match(acpi_handle handle)
+{
+       acpi_handle phandle;
+
+       if (!acpi_has_method(handle, "_EJ0"))
+               return false;
+       if (acpi_ata_match(handle))
+               return true;
+       if (ACPI_FAILURE(acpi_get_parent(handle, &phandle)))
+               return false;
+
+       return acpi_ata_match(phandle);
+}
+
+bool acpi_device_is_battery(struct acpi_device *adev)
+{
+       struct acpi_hardware_id *hwid;
+
+       list_for_each_entry(hwid, &adev->pnp.ids, list)
+               if (!strcmp("PNP0C0A", hwid->id))
+                       return true;
+
+       return false;
+}
+
+static bool is_ejectable_bay(struct acpi_device *adev)
+{
+       acpi_handle handle = adev->handle;
+
+       if (acpi_has_method(handle, "_EJ0") && acpi_device_is_battery(adev))
+               return true;
+
+       return acpi_bay_match(handle);
+}
+
+/*
+ * acpi_dock_match - see if an acpi object has a _DCK method
+ */
+bool acpi_dock_match(acpi_handle handle)
+{
+       return acpi_has_method(handle, "_DCK");
+}
+
+const char *acpi_device_hid(struct acpi_device *device)
+{
+       struct acpi_hardware_id *hid;
+
+       if (list_empty(&device->pnp.ids))
+               return dummy_hid;
+
+       hid = list_first_entry(&device->pnp.ids, struct acpi_hardware_id, list);
+       return hid->id;
+}
+EXPORT_SYMBOL(acpi_device_hid);
+
+static void acpi_add_id(struct acpi_device_pnp *pnp, const char *dev_id)
+{
+       struct acpi_hardware_id *id;
+
+       id = kmalloc(sizeof(*id), GFP_KERNEL);
+       if (!id)
+               return;
+
+       id->id = kstrdup(dev_id, GFP_KERNEL);
+       if (!id->id) {
+               kfree(id);
+               return;
+       }
+
+       list_add_tail(&id->list, &pnp->ids);
+       pnp->type.hardware_id = 1;
+}
+
+/*
+ * Old IBM workstations have a DSDT bug wherein the SMBus object
+ * lacks the SMBUS01 HID and the methods do not have the necessary "_"
+ * prefix.  Work around this.
+ */
+static bool acpi_ibm_smbus_match(acpi_handle handle)
+{
+       char node_name[ACPI_PATH_SEGMENT_LENGTH];
+       struct acpi_buffer path = { sizeof(node_name), node_name };
+
+       if (!dmi_name_in_vendors("IBM"))
+               return false;
+
+       /* Look for SMBS object */
+       if (ACPI_FAILURE(acpi_get_name(handle, ACPI_SINGLE_NAME, &path)) ||
+           strcmp("SMBS", path.pointer))
+               return false;
+
+       /* Does it have the necessary (but misnamed) methods? */
+       if (acpi_has_method(handle, "SBI") &&
+           acpi_has_method(handle, "SBR") &&
+           acpi_has_method(handle, "SBW"))
+               return true;
+
+       return false;
+}
+
+static bool acpi_object_is_system_bus(acpi_handle handle)
+{
+       acpi_handle tmp;
+
+       if (ACPI_SUCCESS(acpi_get_handle(NULL, "\\_SB", &tmp)) &&
+           tmp == handle)
+               return true;
+       if (ACPI_SUCCESS(acpi_get_handle(NULL, "\\_TZ", &tmp)) &&
+           tmp == handle)
+               return true;
+
+       return false;
+}
+
+static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
+                               int device_type)
+{
+       acpi_status status;
+       struct acpi_device_info *info;
+       struct acpi_pnp_device_id_list *cid_list;
+       int i;
+
+       switch (device_type) {
+       case ACPI_BUS_TYPE_DEVICE:
+               if (handle == ACPI_ROOT_OBJECT) {
+                       acpi_add_id(pnp, ACPI_SYSTEM_HID);
+                       break;
+               }
+
+               status = acpi_get_object_info(handle, &info);
+               if (ACPI_FAILURE(status)) {
+                       pr_err(PREFIX "%s: Error reading device info\n",
+                                       __func__);
+                       return;
+               }
+
+               if (info->valid & ACPI_VALID_HID) {
+                       acpi_add_id(pnp, info->hardware_id.string);
+                       pnp->type.platform_id = 1;
+               }
+               if (info->valid & ACPI_VALID_CID) {
+                       cid_list = &info->compatible_id_list;
+                       for (i = 0; i < cid_list->count; i++)
+                               acpi_add_id(pnp, cid_list->ids[i].string);
+               }
+               if (info->valid & ACPI_VALID_ADR) {
+                       pnp->bus_address = info->address;
+                       pnp->type.bus_address = 1;
+               }
+               if (info->valid & ACPI_VALID_UID)
+                       pnp->unique_id = kstrdup(info->unique_id.string,
+                                                       GFP_KERNEL);
+
+               kfree(info);
+
+               /*
+                * Some devices don't reliably have _HIDs & _CIDs, so add
+                * synthetic HIDs to make sure drivers can find them.
+                */
+               if (acpi_is_video_device(handle))
+                       acpi_add_id(pnp, ACPI_VIDEO_HID);
+               else if (acpi_bay_match(handle))
+                       acpi_add_id(pnp, ACPI_BAY_HID);
+               else if (acpi_dock_match(handle))
+                       acpi_add_id(pnp, ACPI_DOCK_HID);
+               else if (acpi_ibm_smbus_match(handle))
+                       acpi_add_id(pnp, ACPI_SMBUS_IBM_HID);
+               else if (list_empty(&pnp->ids) &&
+                        acpi_object_is_system_bus(handle)) {
+                       /* \_SB, \_TZ, LNXSYBUS */
+                       acpi_add_id(pnp, ACPI_BUS_HID);
+                       strcpy(pnp->device_name, ACPI_BUS_DEVICE_NAME);
+                       strcpy(pnp->device_class, ACPI_BUS_CLASS);
+               }
+
+               break;
+       case ACPI_BUS_TYPE_POWER:
+               acpi_add_id(pnp, ACPI_POWER_HID);
+               break;
+       case ACPI_BUS_TYPE_PROCESSOR:
+               acpi_add_id(pnp, ACPI_PROCESSOR_OBJECT_HID);
+               break;
+       case ACPI_BUS_TYPE_THERMAL:
+               acpi_add_id(pnp, ACPI_THERMAL_HID);
+               break;
+       case ACPI_BUS_TYPE_POWER_BUTTON:
+               acpi_add_id(pnp, ACPI_BUTTON_HID_POWERF);
+               break;
+       case ACPI_BUS_TYPE_SLEEP_BUTTON:
+               acpi_add_id(pnp, ACPI_BUTTON_HID_SLEEPF);
+               break;
+       }
+}
+
+void acpi_free_pnp_ids(struct acpi_device_pnp *pnp)
+{
+       struct acpi_hardware_id *id, *tmp;
+
+       list_for_each_entry_safe(id, tmp, &pnp->ids, list) {
+               kfree(id->id);
+               kfree(id);
+       }
+       kfree(pnp->unique_id);
+}
+
+void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
+                            int type, unsigned long long sta)
+{
+       INIT_LIST_HEAD(&device->pnp.ids);
+       device->device_type = type;
+       device->handle = handle;
+       device->parent = acpi_bus_get_parent(handle);
+       device->fwnode.type = FWNODE_ACPI;
+       acpi_set_device_status(device, sta);
+       acpi_device_get_busid(device);
+       acpi_set_pnp_ids(handle, &device->pnp, type);
+       acpi_init_properties(device);
+       acpi_bus_get_flags(device);
+       device->flags.match_driver = false;
+       device->flags.initialized = true;
+       device->flags.visited = false;
+       device_initialize(&device->dev);
+       dev_set_uevent_suppress(&device->dev, true);
+}
+
+void acpi_device_add_finalize(struct acpi_device *device)
+{
+       dev_set_uevent_suppress(&device->dev, false);
+       kobject_uevent(&device->dev.kobj, KOBJ_ADD);
+}
+
+static int acpi_add_single_object(struct acpi_device **child,
+                                 acpi_handle handle, int type,
+                                 unsigned long long sta)
+{
+       int result;
+       struct acpi_device *device;
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+
+       device = kzalloc(sizeof(struct acpi_device), GFP_KERNEL);
+       if (!device) {
+               printk(KERN_ERR PREFIX "Memory allocation error\n");
+               return -ENOMEM;
+       }
+
+       acpi_init_device_object(device, handle, type, sta);
+       acpi_bus_get_power_flags(device);
+       acpi_bus_get_wakeup_device_flags(device);
+
+       result = acpi_device_add(device, acpi_device_release);
+       if (result) {
+               acpi_device_release(&device->dev);
+               return result;
+       }
+
+       acpi_power_add_remove_device(device, true);
+       acpi_device_add_finalize(device);
+       acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Added %s [%s] parent %s\n",
+               dev_name(&device->dev), (char *) buffer.pointer,
+               device->parent ? dev_name(&device->parent->dev) : "(null)"));
+       kfree(buffer.pointer);
+       *child = device;
+       return 0;
+}
+
+static int acpi_bus_type_and_status(acpi_handle handle, int *type,
+                                   unsigned long long *sta)
+{
+       acpi_status status;
+       acpi_object_type acpi_type;
+
+       status = acpi_get_type(handle, &acpi_type);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+
+       switch (acpi_type) {
+       case ACPI_TYPE_ANY:             /* for ACPI_ROOT_OBJECT */
+       case ACPI_TYPE_DEVICE:
+               *type = ACPI_BUS_TYPE_DEVICE;
+               status = acpi_bus_get_status_handle(handle, sta);
+               if (ACPI_FAILURE(status))
+                       return -ENODEV;
+               break;
+       case ACPI_TYPE_PROCESSOR:
+               *type = ACPI_BUS_TYPE_PROCESSOR;
+               status = acpi_bus_get_status_handle(handle, sta);
+               if (ACPI_FAILURE(status))
+                       return -ENODEV;
+               break;
+       case ACPI_TYPE_THERMAL:
+               *type = ACPI_BUS_TYPE_THERMAL;
+               *sta = ACPI_STA_DEFAULT;
+               break;
+       case ACPI_TYPE_POWER:
+               *type = ACPI_BUS_TYPE_POWER;
+               *sta = ACPI_STA_DEFAULT;
+               break;
+       default:
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+bool acpi_device_is_present(struct acpi_device *adev)
+{
+       if (adev->status.present || adev->status.functional)
+               return true;
+
+       adev->flags.initialized = false;
+       return false;
+}
+
+static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler,
+                                      char *idstr,
+                                      const struct acpi_device_id **matchid)
+{
+       const struct acpi_device_id *devid;
+
+       if (handler->match)
+               return handler->match(idstr, matchid);
+
+       for (devid = handler->ids; devid->id[0]; devid++)
+               if (!strcmp((char *)devid->id, idstr)) {
+                       if (matchid)
+                               *matchid = devid;
+
+                       return true;
+               }
+
+       return false;
+}
+
+static struct acpi_scan_handler *acpi_scan_match_handler(char *idstr,
+                                       const struct acpi_device_id **matchid)
+{
+       struct acpi_scan_handler *handler;
+
+       list_for_each_entry(handler, &acpi_scan_handlers_list, list_node)
+               if (acpi_scan_handler_matching(handler, idstr, matchid))
+                       return handler;
+
+       return NULL;
+}
+
+void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val)
+{
+       if (!!hotplug->enabled == !!val)
+               return;
+
+       mutex_lock(&acpi_scan_lock);
+
+       hotplug->enabled = val;
+
+       mutex_unlock(&acpi_scan_lock);
+}
+
+static void acpi_scan_init_hotplug(struct acpi_device *adev)
+{
+       struct acpi_hardware_id *hwid;
+
+       if (acpi_dock_match(adev->handle) || is_ejectable_bay(adev)) {
+               acpi_dock_add(adev);
+               return;
+       }
+       list_for_each_entry(hwid, &adev->pnp.ids, list) {
+               struct acpi_scan_handler *handler;
+
+               handler = acpi_scan_match_handler(hwid->id, NULL);
+               if (handler) {
+                       adev->flags.hotplug_notify = true;
+                       break;
+               }
+       }
+}
+
+static void acpi_device_dep_initialize(struct acpi_device *adev)
+{
+       struct acpi_dep_data *dep;
+       struct acpi_handle_list dep_devices;
+       acpi_status status;
+       int i;
+
+       if (!acpi_has_method(adev->handle, "_DEP"))
+               return;
+
+       status = acpi_evaluate_reference(adev->handle, "_DEP", NULL,
+                                       &dep_devices);
+       if (ACPI_FAILURE(status)) {
+               dev_dbg(&adev->dev, "Failed to evaluate _DEP.\n");
+               return;
+       }
+
+       for (i = 0; i < dep_devices.count; i++) {
+               struct acpi_device_info *info;
+               int skip;
+
+               status = acpi_get_object_info(dep_devices.handles[i], &info);
+               if (ACPI_FAILURE(status)) {
+                       dev_dbg(&adev->dev, "Error reading _DEP device info\n");
+                       continue;
+               }
+
+               /*
+                * Skip the dependency of Windows System Power
+                * Management Controller
+                */
+               skip = info->valid & ACPI_VALID_HID &&
+                       !strcmp(info->hardware_id.string, "INT3396");
+
+               kfree(info);
+
+               if (skip)
+                       continue;
+
+               dep = kzalloc(sizeof(struct acpi_dep_data), GFP_KERNEL);
+               if (!dep)
+                       return;
+
+               dep->master = dep_devices.handles[i];
+               dep->slave  = adev->handle;
+               adev->dep_unmet++;
+
+               mutex_lock(&acpi_dep_list_lock);
+               list_add_tail(&dep->node , &acpi_dep_list);
+               mutex_unlock(&acpi_dep_list_lock);
+       }
+}
+
+static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
+                                     void *not_used, void **return_value)
+{
+       struct acpi_device *device = NULL;
+       int type;
+       unsigned long long sta;
+       int result;
+
+       acpi_bus_get_device(handle, &device);
+       if (device)
+               goto out;
+
+       result = acpi_bus_type_and_status(handle, &type, &sta);
+       if (result)
+               return AE_OK;
+
+       if (type == ACPI_BUS_TYPE_POWER) {
+               acpi_add_power_resource(handle);
+               return AE_OK;
+       }
+
+       acpi_add_single_object(&device, handle, type, sta);
+       if (!device)
+               return AE_CTRL_DEPTH;
+
+       acpi_scan_init_hotplug(device);
+       acpi_device_dep_initialize(device);
+
+ out:
+       if (!*return_value)
+               *return_value = device;
+
+       return AE_OK;
+}
+
+static int acpi_check_spi_i2c_slave(struct acpi_resource *ares, void *data)
+{
+       bool *is_spi_i2c_slave_p = data;
+
+       if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
+               return 1;
+
+       /*
+        * devices that are connected to UART still need to be enumerated to
+        * platform bus
+        */
+       if (ares->data.common_serial_bus.type != ACPI_RESOURCE_SERIAL_TYPE_UART)
+               *is_spi_i2c_slave_p = true;
+
+        /* no need to do more checking */
+       return -1;
+}
+
+static void acpi_default_enumeration(struct acpi_device *device)
+{
+       struct list_head resource_list;
+       bool is_spi_i2c_slave = false;
+
+       /*
+        * Do not enemerate SPI/I2C slaves as they will be enuerated by their
+        * respective parents.
+        */
+       INIT_LIST_HEAD(&resource_list);
+       acpi_dev_get_resources(device, &resource_list, acpi_check_spi_i2c_slave,
+                              &is_spi_i2c_slave);
+       acpi_dev_free_resource_list(&resource_list);
+       if (!is_spi_i2c_slave)
+               acpi_create_platform_device(device);
+}
+
+static const struct acpi_device_id generic_device_ids[] = {
+       {"PRP0001", },
+       {"", },
+};
+
+static int acpi_generic_device_attach(struct acpi_device *adev,
+                                     const struct acpi_device_id *not_used)
+{
+       /*
+        * Since PRP0001 is the only ID handled here, the test below can be
+        * unconditional.
+        */
+       if (adev->data.of_compatible)
+               acpi_default_enumeration(adev);
+
+       return 1;
+}
+
+static struct acpi_scan_handler generic_device_handler = {
+       .ids = generic_device_ids,
+       .attach = acpi_generic_device_attach,
+};
+
+static int acpi_scan_attach_handler(struct acpi_device *device)
+{
+       struct acpi_hardware_id *hwid;
+       int ret = 0;
+
+       list_for_each_entry(hwid, &device->pnp.ids, list) {
+               const struct acpi_device_id *devid;
+               struct acpi_scan_handler *handler;
+
+               handler = acpi_scan_match_handler(hwid->id, &devid);
+               if (handler) {
+                       if (!handler->attach) {
+                               device->pnp.type.platform_id = 0;
+                               continue;
+                       }
+                       device->handler = handler;
+                       ret = handler->attach(device, devid);
+                       if (ret > 0)
+                               break;
+
+                       device->handler = NULL;
+                       if (ret < 0)
+                               break;
+               }
+       }
+
+       return ret;
+}
+
+static void acpi_bus_attach(struct acpi_device *device)
+{
+       struct acpi_device *child;
+       acpi_handle ejd;
+       int ret;
+
+       if (ACPI_SUCCESS(acpi_bus_get_ejd(device->handle, &ejd)))
+               register_dock_dependent_device(device, ejd);
+
+       acpi_bus_get_status(device);
+       /* Skip devices that are not present. */
+       if (!acpi_device_is_present(device)) {
+               device->flags.visited = false;
+               device->flags.power_manageable = 0;
+               return;
+       }
+       if (device->handler)
+               goto ok;
+
+       if (!device->flags.initialized) {
+               device->flags.power_manageable =
+                       device->power.states[ACPI_STATE_D0].flags.valid;
+               if (acpi_bus_init_power(device))
+                       device->flags.power_manageable = 0;
+
+               device->flags.initialized = true;
+       }
+       device->flags.visited = false;
+       ret = acpi_scan_attach_handler(device);
+       if (ret < 0)
+               return;
+
+       device->flags.match_driver = true;
+       if (!ret) {
+               ret = device_attach(&device->dev);
+               if (ret < 0)
+                       return;
+
+               if (!ret && device->pnp.type.platform_id)
+                       acpi_default_enumeration(device);
+       }
+       device->flags.visited = true;
+
+ ok:
+       list_for_each_entry(child, &device->children, node)
+               acpi_bus_attach(child);
+
+       if (device->handler && device->handler->hotplug.notify_online)
+               device->handler->hotplug.notify_online(device);
+}
+
+void acpi_walk_dep_device_list(acpi_handle handle)
+{
+       struct acpi_dep_data *dep, *tmp;
+       struct acpi_device *adev;
+
+       mutex_lock(&acpi_dep_list_lock);
+       list_for_each_entry_safe(dep, tmp, &acpi_dep_list, node) {
+               if (dep->master == handle) {
+                       acpi_bus_get_device(dep->slave, &adev);
+                       if (!adev)
+                               continue;
+
+                       adev->dep_unmet--;
+                       if (!adev->dep_unmet)
+                               acpi_bus_attach(adev);
+                       list_del(&dep->node);
+                       kfree(dep);
+               }
+       }
+       mutex_unlock(&acpi_dep_list_lock);
+}
+EXPORT_SYMBOL_GPL(acpi_walk_dep_device_list);
+
+/**
+ * acpi_bus_scan - Add ACPI device node objects in a given namespace scope.
+ * @handle: Root of the namespace scope to scan.
+ *
+ * Scan a given ACPI tree (probably recently hot-plugged) and create and add
+ * found devices.
+ *
+ * If no devices were found, -ENODEV is returned, but it does not mean that
+ * there has been a real error.  There just have been no suitable ACPI objects
+ * in the table trunk from which the kernel could create a device and add an
+ * appropriate driver.
+ *
+ * Must be called under acpi_scan_lock.
+ */
+int acpi_bus_scan(acpi_handle handle)
+{
+       void *device = NULL;
+
+       if (ACPI_SUCCESS(acpi_bus_check_add(handle, 0, NULL, &device)))
+               acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
+                                   acpi_bus_check_add, NULL, NULL, &device);
+
+       if (device) {
+               acpi_bus_attach(device);
+               return 0;
+       }
+       return -ENODEV;
+}
+EXPORT_SYMBOL(acpi_bus_scan);
+
+/**
+ * acpi_bus_trim - Detach scan handlers and drivers from ACPI device objects.
+ * @adev: Root of the ACPI namespace scope to walk.
+ *
+ * Must be called under acpi_scan_lock.
+ */
+void acpi_bus_trim(struct acpi_device *adev)
+{
+       struct acpi_scan_handler *handler = adev->handler;
+       struct acpi_device *child;
+
+       list_for_each_entry_reverse(child, &adev->children, node)
+               acpi_bus_trim(child);
+
+       adev->flags.match_driver = false;
+       if (handler) {
+               if (handler->detach)
+                       handler->detach(adev);
+
+               adev->handler = NULL;
+       } else {
+               device_release_driver(&adev->dev);
+       }
+       /*
+        * Most likely, the device is going away, so put it into D3cold before
+        * that.
+        */
+       acpi_device_set_power(adev, ACPI_STATE_D3_COLD);
+       adev->flags.initialized = false;
+       adev->flags.visited = false;
+}
+EXPORT_SYMBOL_GPL(acpi_bus_trim);
+
+static int acpi_bus_scan_fixed(void)
+{
+       int result = 0;
+
+       /*
+        * Enumerate all fixed-feature devices.
+        */
+       if (!(acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON)) {
+               struct acpi_device *device = NULL;
+
+               result = acpi_add_single_object(&device, NULL,
+                                               ACPI_BUS_TYPE_POWER_BUTTON,
+                                               ACPI_STA_DEFAULT);
+               if (result)
+                       return result;
+
+               device->flags.match_driver = true;
+               result = device_attach(&device->dev);
+               if (result < 0)
+                       return result;
+
+               device_init_wakeup(&device->dev, true);
+       }
+
+       if (!(acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON)) {
+               struct acpi_device *device = NULL;
+
+               result = acpi_add_single_object(&device, NULL,
+                                               ACPI_BUS_TYPE_SLEEP_BUTTON,
+                                               ACPI_STA_DEFAULT);
+               if (result)
+                       return result;
+
+               device->flags.match_driver = true;
+               result = device_attach(&device->dev);
+       }
+
+       return result < 0 ? result : 0;
+}
+
+int __init acpi_scan_init(void)
+{
+       int result;
+
+       result = bus_register(&acpi_bus_type);
+       if (result) {
+               /* We don't want to quit even if we failed to add suspend/resume */
+               printk(KERN_ERR PREFIX "Could not register bus type\n");
+       }
+
+       acpi_pci_root_init();
+       acpi_pci_link_init();
+       acpi_processor_init();
+       acpi_lpss_init();
+       acpi_apd_init();
+       acpi_cmos_rtc_init();
+       acpi_container_init();
+       acpi_memory_hotplug_init();
+       acpi_pnp_init();
+       acpi_int340x_thermal_init();
+
+       acpi_scan_add_handler(&generic_device_handler);
+
+       mutex_lock(&acpi_scan_lock);
+       /*
+        * Enumerate devices in the ACPI namespace.
+        */
+       result = acpi_bus_scan(ACPI_ROOT_OBJECT);
+       if (result)
+               goto out;
+
+       result = acpi_bus_get_device(ACPI_ROOT_OBJECT, &acpi_root);
+       if (result)
+               goto out;
+
+       /* Fixed feature devices do not exist on HW-reduced platform */
+       if (!acpi_gbl_reduced_hardware) {
+               result = acpi_bus_scan_fixed();
+               if (result) {
+                       acpi_detach_data(acpi_root->handle,
+                                        acpi_scan_drop_device);
+                       acpi_device_del(acpi_root);
+                       put_device(&acpi_root->dev);
+                       goto out;
+               }
+       }
+
+       acpi_update_all_gpes();
+
+ out:
+       mutex_unlock(&acpi_scan_lock);
+       return result;
+}