]> git.karo-electronics.de Git - linux-beck.git/blobdiff - drivers/acpi/scan.c
Merge branch 'acpi-cleanup'
[linux-beck.git] / drivers / acpi / scan.c
index c1bc608339a6007b9d1ecbbd0f2669626d4a538f..d5993e339a26d72885c1af9afb7e6673e4f38f58 100644 (file)
@@ -27,9 +27,14 @@ extern struct acpi_device *acpi_root;
 
 #define ACPI_IS_ROOT_DEVICE(device)    (!(device)->parent)
 
+/*
+ * 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_device_list);
 static LIST_HEAD(acpi_bus_id_list);
 static DEFINE_MUTEX(acpi_scan_lock);
 static LIST_HEAD(acpi_scan_handlers_list);
@@ -120,12 +125,75 @@ acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, cha
 }
 static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
 
+static acpi_status acpi_bus_offline_companions(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;
+
+       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_companions(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_hot_remove(struct acpi_device *device)
 {
        acpi_handle handle = device->handle;
-       acpi_handle not_used;
-       struct acpi_object_list arg_list;
-       union acpi_object arg;
+       struct device *errdev;
        acpi_status status;
        unsigned long long sta;
 
@@ -136,40 +204,66 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
                return -EINVAL;
        }
 
+       lock_device_hotplug();
+
+       /*
+        * 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.
+        */
+       errdev = NULL;
+       acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
+                           NULL, acpi_bus_offline_companions,
+                           (void *)false, (void **)&errdev);
+       acpi_bus_offline_companions(handle, 0, (void *)false, (void **)&errdev);
+       if (errdev) {
+               errdev = NULL;
+               acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
+                                   NULL, acpi_bus_offline_companions,
+                                   (void *)true , (void **)&errdev);
+               if (!errdev || acpi_force_hot_remove)
+                       acpi_bus_offline_companions(handle, 0, (void *)true,
+                                                   (void **)&errdev);
+
+               if (errdev && !acpi_force_hot_remove) {
+                       dev_warn(errdev, "Offline failed.\n");
+                       acpi_bus_online_companions(handle, 0, NULL, NULL);
+                       acpi_walk_namespace(ACPI_TYPE_ANY, handle,
+                                           ACPI_UINT32_MAX,
+                                           acpi_bus_online_companions, NULL,
+                                           NULL, NULL);
+
+                       unlock_device_hotplug();
+
+                       put_device(&device->dev);
+                       return -EBUSY;
+               }
+       }
+
        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                "Hot-removing device %s...\n", dev_name(&device->dev)));
 
        acpi_bus_trim(device);
+
+       unlock_device_hotplug();
+
        /* Device node has been unregistered. */
        put_device(&device->dev);
        device = NULL;
 
-       if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &not_used))) {
-               arg_list.count = 1;
-               arg_list.pointer = &arg;
-               arg.type = ACPI_TYPE_INTEGER;
-               arg.integer.value = 0;
-               acpi_evaluate_object(handle, "_LCK", &arg_list, NULL);
-       }
-
-       arg_list.count = 1;
-       arg_list.pointer = &arg;
-       arg.type = ACPI_TYPE_INTEGER;
-       arg.integer.value = 1;
-
+       acpi_evaluate_lck(handle, 0);
        /*
         * TBD: _EJD support.
         */
-       status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
-       if (ACPI_FAILURE(status)) {
-               if (status == AE_NOT_FOUND) {
-                       return -ENODEV;
-               } else {
-                       acpi_handle_warn(handle, "Eject failed (0x%x)\n",
-                                                               status);
-                       return -EIO;
-               }
-       }
+       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
@@ -236,11 +330,14 @@ static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
        int error;
 
        mutex_lock(&acpi_scan_lock);
+       lock_device_hotplug();
 
-       acpi_bus_get_device(handle, &device);
-       if (device) {
-               dev_warn(&device->dev, "Attempt to re-insert\n");
-               goto out;
+       if (ost_source != ACPI_NOTIFY_BUS_CHECK) {
+               acpi_bus_get_device(handle, &device);
+               if (device) {
+                       dev_warn(&device->dev, "Attempt to re-insert\n");
+                       goto out;
+               }
        }
        acpi_evaluate_hotplug_ost(handle, ost_source,
                                  ACPI_OST_SC_INSERT_IN_PROGRESS, NULL);
@@ -259,6 +356,7 @@ static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
                kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
 
  out:
+       unlock_device_hotplug();
        acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
        mutex_unlock(&acpi_scan_lock);
 }
@@ -536,7 +634,6 @@ static int acpi_device_setup_files(struct acpi_device *dev)
 {
        struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
        acpi_status status;
-       acpi_handle temp;
        unsigned long long sun;
        int result = 0;
 
@@ -562,8 +659,7 @@ static int acpi_device_setup_files(struct acpi_device *dev)
        /*
         * If device has _STR, 'description' file is created
         */
-       status = acpi_get_handle(dev->handle, "_STR", &temp);
-       if (ACPI_SUCCESS(status)) {
+       if (acpi_has_method(dev->handle, "_STR")) {
                status = acpi_evaluate_object(dev->handle, "_STR",
                                        NULL, &buffer);
                if (ACPI_FAILURE(status))
@@ -593,8 +689,7 @@ static int acpi_device_setup_files(struct acpi_device *dev)
          * If device has _EJ0, 'eject' file is created that is used to trigger
          * hot-removal function from userland.
          */
-       status = acpi_get_handle(dev->handle, "_EJ0", &temp);
-       if (ACPI_SUCCESS(status)) {
+       if (acpi_has_method(dev->handle, "_EJ0")) {
                result = device_create_file(&dev->dev, &dev_attr_eject);
                if (result)
                        return result;
@@ -616,9 +711,6 @@ end:
 
 static void acpi_device_remove_files(struct acpi_device *dev)
 {
-       acpi_status status;
-       acpi_handle temp;
-
        if (dev->flags.power_manageable) {
                device_remove_file(&dev->dev, &dev_attr_power_state);
                if (dev->power.flags.power_resources)
@@ -629,20 +721,17 @@ static void acpi_device_remove_files(struct acpi_device *dev)
        /*
         * If device has _STR, remove 'description' file
         */
-       status = acpi_get_handle(dev->handle, "_STR", &temp);
-       if (ACPI_SUCCESS(status)) {
+       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.
         */
-       status = acpi_get_handle(dev->handle, "_EJ0", &temp);
-       if (ACPI_SUCCESS(status))
+       if (acpi_has_method(dev->handle, "_EJ0"))
                device_remove_file(&dev->dev, &dev_attr_eject);
 
-       status = acpi_get_handle(dev->handle, "_SUN", &temp);
-       if (ACPI_SUCCESS(status))
+       if (acpi_has_method(dev->handle, "_SUN"))
                device_remove_file(&dev->dev, &dev_attr_sun);
 
        if (dev->pnp.unique_id)
@@ -816,32 +905,43 @@ static void acpi_device_remove_notify_handler(struct acpi_device *device)
                                           acpi_device_notify);
 }
 
-static int acpi_bus_driver_init(struct acpi_device *, struct acpi_driver *);
-static int acpi_device_probe(struct device * dev)
+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;
 
-       ret = acpi_bus_driver_init(acpi_dev, acpi_drv);
-       if (!ret) {
-               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;
-                       }
-               }
+       if (acpi_dev->handler)
+               return -EINVAL;
 
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                       "Found driver [%s] for device [%s]\n",
-                       acpi_drv->name, acpi_dev->pnp.bus_id));
-               get_device(dev);
+       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;
+               }
        }
-       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)
@@ -952,7 +1052,6 @@ int acpi_device_add(struct acpi_device *device,
                printk(KERN_ERR PREFIX "Error creating sysfs interface for device %s\n",
                       dev_name(&device->dev));
 
-       device->removal_type = ACPI_BUS_REMOVAL_NORMAL;
        return 0;
 
  err:
@@ -997,44 +1096,6 @@ static void acpi_device_unregister(struct acpi_device *device)
 /* --------------------------------------------------------------------------
                                  Driver Management
    -------------------------------------------------------------------------- */
-/**
- * acpi_bus_driver_init - add a device to a driver
- * @device: the device to add and initialize
- * @driver: driver for the device
- *
- * Used to initialize a device via its device driver.  Called whenever a
- * driver is bound to a device.  Invokes the driver's add() ops.
- */
-static int
-acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver)
-{
-       int result = 0;
-
-       if (!device || !driver)
-               return -EINVAL;
-
-       if (!driver->ops.add)
-               return -ENOSYS;
-
-       result = driver->ops.add(device);
-       if (result) {
-               device->driver = NULL;
-               device->driver_data = NULL;
-               return result;
-       }
-
-       device->driver = driver;
-
-       /*
-        * TBD - Configuration Management: Assign resources to device based
-        * upon possible configuration and currently allocated resources.
-        */
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                         "Driver successfully bound to device\n"));
-       return 0;
-}
-
 /**
  * acpi_bus_register_driver - register a driver with the ACPI bus
  * @driver: driver being registered
@@ -1246,13 +1307,10 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device)
 
 static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
 {
-       acpi_handle temp;
-       acpi_status status = 0;
        int err;
 
        /* Presence of _PRW indicates wake capable */
-       status = acpi_get_handle(device->handle, "_PRW", &temp);
-       if (ACPI_FAILURE(status))
+       if (!acpi_has_method(device->handle, "_PRW"))
                return;
 
        err = acpi_bus_extract_wakeup_device_power_package(device->handle,
@@ -1282,7 +1340,6 @@ 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_handle handle;
        acpi_status status;
 
        INIT_LIST_HEAD(&ps->resources);
@@ -1305,8 +1362,7 @@ static void acpi_bus_init_power_state(struct acpi_device *device, int state)
 
        /* Evaluate "_PSx" to see if we can do explicit sets */
        pathname[2] = 'S';
-       status = acpi_get_handle(device->handle, pathname, &handle);
-       if (ACPI_SUCCESS(status))
+       if (acpi_has_method(device->handle, pathname))
                ps->flags.explicit_set = 1;
 
        /*
@@ -1325,28 +1381,21 @@ static void acpi_bus_init_power_state(struct acpi_device *device, int state)
 
 static void acpi_bus_get_power_flags(struct acpi_device *device)
 {
-       acpi_status status;
-       acpi_handle handle;
        u32 i;
 
        /* Presence of _PS0|_PR0 indicates 'power manageable' */
-       status = acpi_get_handle(device->handle, "_PS0", &handle);
-       if (ACPI_FAILURE(status)) {
-               status = acpi_get_handle(device->handle, "_PR0", &handle);
-               if (ACPI_FAILURE(status))
-                       return;
-       }
+       if (!acpi_has_method(device->handle, "_PS0") &&
+           !acpi_has_method(device->handle, "_PR0"))
+               return;
 
        device->flags.power_manageable = 1;
 
        /*
         * Power Management Flags
         */
-       status = acpi_get_handle(device->handle, "_PSC", &handle);
-       if (ACPI_SUCCESS(status))
+       if (acpi_has_method(device->handle, "_PSC"))
                device->power.flags.explicit_get = 1;
-       status = acpi_get_handle(device->handle, "_IRC", &handle);
-       if (ACPI_SUCCESS(status))
+       if (acpi_has_method(device->handle, "_IRC"))
                device->power.flags.inrush_current = 1;
 
        /*
@@ -1380,28 +1429,18 @@ static void acpi_bus_get_power_flags(struct acpi_device *device)
 
 static void acpi_bus_get_flags(struct acpi_device *device)
 {
-       acpi_status status = AE_OK;
-       acpi_handle temp = NULL;
-
        /* Presence of _STA indicates 'dynamic_status' */
-       status = acpi_get_handle(device->handle, "_STA", &temp);
-       if (ACPI_SUCCESS(status))
+       if (acpi_has_method(device->handle, "_STA"))
                device->flags.dynamic_status = 1;
 
        /* Presence of _RMV indicates 'removable' */
-       status = acpi_get_handle(device->handle, "_RMV", &temp);
-       if (ACPI_SUCCESS(status))
+       if (acpi_has_method(device->handle, "_RMV"))
                device->flags.removable = 1;
 
        /* Presence of _EJD|_EJ0 indicates 'ejectable' */
-       status = acpi_get_handle(device->handle, "_EJD", &temp);
-       if (ACPI_SUCCESS(status))
+       if (acpi_has_method(device->handle, "_EJD") ||
+           acpi_has_method(device->handle, "_EJ0"))
                device->flags.ejectable = 1;
-       else {
-               status = acpi_get_handle(device->handle, "_EJ0", &temp);
-               if (ACPI_SUCCESS(status))
-                       device->flags.ejectable = 1;
-       }
 }
 
 static void acpi_device_get_busid(struct acpi_device *device)
@@ -1442,47 +1481,46 @@ static void acpi_device_get_busid(struct acpi_device *device)
        }
 }
 
+/*
+ * 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
  */
-static int acpi_bay_match(acpi_handle handle)
+bool acpi_bay_match(acpi_handle handle)
 {
-       acpi_status status;
-       acpi_handle tmp;
        acpi_handle phandle;
 
-       status = acpi_get_handle(handle, "_EJ0", &tmp);
-       if (ACPI_FAILURE(status))
-               return -ENODEV;
-
-       if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
-               (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
-               (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
-               (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
-               return 0;
-
-       if (acpi_get_parent(handle, &phandle))
-               return -ENODEV;
-
-        if ((ACPI_SUCCESS(acpi_get_handle(phandle, "_GTF", &tmp))) ||
-                (ACPI_SUCCESS(acpi_get_handle(phandle, "_GTM", &tmp))) ||
-                (ACPI_SUCCESS(acpi_get_handle(phandle, "_STM", &tmp))) ||
-                (ACPI_SUCCESS(acpi_get_handle(phandle, "_SDD", &tmp))))
-                return 0;
+       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 -ENODEV;
+       return acpi_ata_match(phandle);
 }
 
 /*
  * acpi_dock_match - see if an acpi object has a _DCK method
  */
-static int acpi_dock_match(acpi_handle handle)
+bool acpi_dock_match(acpi_handle handle)
 {
-       acpi_handle tmp;
-       return acpi_get_handle(handle, "_DCK", &tmp);
+       return acpi_has_method(handle, "_DCK");
 }
 
 const char *acpi_device_hid(struct acpi_device *device)
@@ -1520,34 +1558,26 @@ static void acpi_add_id(struct acpi_device_pnp *pnp, const char *dev_id)
  * lacks the SMBUS01 HID and the methods do not have the necessary "_"
  * prefix.  Work around this.
  */
-static int acpi_ibm_smbus_match(acpi_handle handle)
+static bool acpi_ibm_smbus_match(acpi_handle handle)
 {
-       acpi_handle h_dummy;
-       struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
-       int result;
+       char node_name[ACPI_PATH_SEGMENT_LENGTH];
+       struct acpi_buffer path = { sizeof(node_name), node_name };
 
        if (!dmi_name_in_vendors("IBM"))
-               return -ENODEV;
+               return false;
 
        /* Look for SMBS object */
-       result = acpi_get_name(handle, ACPI_SINGLE_NAME, &path);
-       if (result)
-               return result;
-
-       if (strcmp("SMBS", path.pointer)) {
-               result = -ENODEV;
-               goto out;
-       }
+       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? */
-       result = -ENODEV;
-       if (ACPI_SUCCESS(acpi_get_handle(handle, "SBI", &h_dummy)) &&
-           ACPI_SUCCESS(acpi_get_handle(handle, "SBR", &h_dummy)) &&
-           ACPI_SUCCESS(acpi_get_handle(handle, "SBW", &h_dummy)))
-               result = 0;
-out:
-       kfree(path.pointer);
-       return result;
+       if (acpi_has_method(handle, "SBI") &&
+           acpi_has_method(handle, "SBR") &&
+           acpi_has_method(handle, "SBW"))
+               return true;
+
+       return false;
 }
 
 static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
@@ -1595,11 +1625,11 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
                 */
                if (acpi_is_video_device(handle))
                        acpi_add_id(pnp, ACPI_VIDEO_HID);
-               else if (ACPI_SUCCESS(acpi_bay_match(handle)))
+               else if (acpi_bay_match(handle))
                        acpi_add_id(pnp, ACPI_BAY_HID);
-               else if (ACPI_SUCCESS(acpi_dock_match(handle)))
+               else if (acpi_dock_match(handle))
                        acpi_add_id(pnp, ACPI_DOCK_HID);
-               else if (!acpi_ibm_smbus_match(handle))
+               else if (acpi_ibm_smbus_match(handle))
                        acpi_add_id(pnp, ACPI_SMBUS_IBM_HID);
                else if (list_empty(&pnp->ids) && handle == ACPI_ROOT_OBJECT) {
                        acpi_add_id(pnp, ACPI_BUS_HID); /* \_SB, LNXSYBUS */
@@ -1810,7 +1840,6 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
        struct acpi_device *device = NULL;
        int type;
        unsigned long long sta;
-       acpi_status status;
        int result;
 
        acpi_bus_get_device(handle, &device);
@@ -1831,10 +1860,8 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
        if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
            !(sta & ACPI_STA_DEVICE_FUNCTIONING)) {
                struct acpi_device_wakeup wakeup;
-               acpi_handle temp;
 
-               status = acpi_get_handle(handle, "_PRW", &temp);
-               if (ACPI_SUCCESS(status)) {
+               if (acpi_has_method(handle, "_PRW")) {
                        acpi_bus_extract_wakeup_device_power_package(handle,
                                                                     &wakeup);
                        acpi_power_resources_list_free(&wakeup.resources);
@@ -1893,6 +1920,9 @@ static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used,
        if (acpi_bus_get_device(handle, &device))
                return AE_CTRL_DEPTH;
 
+       if (device->handler)
+               return AE_OK;
+
        ret = acpi_scan_attach_handler(device);
        if (ret)
                return ret > 0 ? AE_OK : AE_CTRL_DEPTH;
@@ -1942,7 +1972,6 @@ static acpi_status acpi_bus_device_detach(acpi_handle handle, u32 lvl_not_used,
        if (!acpi_bus_get_device(handle, &device)) {
                struct acpi_scan_handler *dev_handler = device->handler;
 
-               device->removal_type = ACPI_BUS_REMOVAL_EJECT;
                if (dev_handler) {
                        if (dev_handler->detach)
                                dev_handler->detach(device);
@@ -2041,11 +2070,13 @@ int __init acpi_scan_init(void)
 
        acpi_pci_root_init();
        acpi_pci_link_init();
+       acpi_processor_init();
        acpi_platform_init();
        acpi_lpss_init();
-       acpi_csrt_init();
+       acpi_cmos_rtc_init();
        acpi_container_init();
        acpi_memory_hotplug_init();
+       acpi_dock_init();
 
        mutex_lock(&acpi_scan_lock);
        /*