|
@@ -494,6 +494,8 @@ static void acpi_device_del(struct acpi_device *device)
|
|
|
device_del(&device->dev);
|
|
|
}
|
|
|
|
|
|
+static BLOCKING_NOTIFIER_HEAD(acpi_reconfig_chain);
|
|
|
+
|
|
|
static LIST_HEAD(acpi_device_del_list);
|
|
|
static DEFINE_MUTEX(acpi_device_del_lock);
|
|
|
|
|
@@ -514,6 +516,9 @@ static void acpi_device_del_work_fn(struct work_struct *work_not_used)
|
|
|
|
|
|
mutex_unlock(&acpi_device_del_lock);
|
|
|
|
|
|
+ blocking_notifier_call_chain(&acpi_reconfig_chain,
|
|
|
+ ACPI_RECONFIG_DEVICE_REMOVE, adev);
|
|
|
+
|
|
|
acpi_device_del(adev);
|
|
|
/*
|
|
|
* Drop references to all power resources that might have been
|
|
@@ -1676,7 +1681,7 @@ static void acpi_default_enumeration(struct acpi_device *device)
|
|
|
bool is_spi_i2c_slave = false;
|
|
|
|
|
|
/*
|
|
|
- * Do not enemerate SPI/I2C slaves as they will be enuerated by their
|
|
|
+ * Do not enumerate SPI/I2C slaves as they will be enumerated by their
|
|
|
* respective parents.
|
|
|
*/
|
|
|
INIT_LIST_HEAD(&resource_list);
|
|
@@ -1686,6 +1691,9 @@ static void acpi_default_enumeration(struct acpi_device *device)
|
|
|
if (!is_spi_i2c_slave) {
|
|
|
acpi_create_platform_device(device);
|
|
|
acpi_device_set_enumerated(device);
|
|
|
+ } else {
|
|
|
+ blocking_notifier_call_chain(&acpi_reconfig_chain,
|
|
|
+ ACPI_RECONFIG_DEVICE_ADD, device);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1917,6 +1925,8 @@ static int acpi_bus_scan_fixed(void)
|
|
|
return result < 0 ? result : 0;
|
|
|
}
|
|
|
|
|
|
+static bool acpi_scan_initialized;
|
|
|
+
|
|
|
int __init acpi_scan_init(void)
|
|
|
{
|
|
|
int result;
|
|
@@ -1961,6 +1971,8 @@ int __init acpi_scan_init(void)
|
|
|
|
|
|
acpi_update_all_gpes();
|
|
|
|
|
|
+ acpi_scan_initialized = true;
|
|
|
+
|
|
|
out:
|
|
|
mutex_unlock(&acpi_scan_lock);
|
|
|
return result;
|
|
@@ -2004,3 +2016,57 @@ int __init __acpi_probe_device_table(struct acpi_probe_entry *ap_head, int nr)
|
|
|
|
|
|
return count;
|
|
|
}
|
|
|
+
|
|
|
+struct acpi_table_events_work {
|
|
|
+ struct work_struct work;
|
|
|
+ void *table;
|
|
|
+ u32 event;
|
|
|
+};
|
|
|
+
|
|
|
+static void acpi_table_events_fn(struct work_struct *work)
|
|
|
+{
|
|
|
+ struct acpi_table_events_work *tew;
|
|
|
+
|
|
|
+ tew = container_of(work, struct acpi_table_events_work, work);
|
|
|
+
|
|
|
+ if (tew->event == ACPI_TABLE_EVENT_LOAD) {
|
|
|
+ acpi_scan_lock_acquire();
|
|
|
+ acpi_bus_scan(ACPI_ROOT_OBJECT);
|
|
|
+ acpi_scan_lock_release();
|
|
|
+ }
|
|
|
+
|
|
|
+ kfree(tew);
|
|
|
+}
|
|
|
+
|
|
|
+void acpi_scan_table_handler(u32 event, void *table, void *context)
|
|
|
+{
|
|
|
+ struct acpi_table_events_work *tew;
|
|
|
+
|
|
|
+ if (!acpi_scan_initialized)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (event != ACPI_TABLE_EVENT_LOAD)
|
|
|
+ return;
|
|
|
+
|
|
|
+ tew = kmalloc(sizeof(*tew), GFP_KERNEL);
|
|
|
+ if (!tew)
|
|
|
+ return;
|
|
|
+
|
|
|
+ INIT_WORK(&tew->work, acpi_table_events_fn);
|
|
|
+ tew->table = table;
|
|
|
+ tew->event = event;
|
|
|
+
|
|
|
+ schedule_work(&tew->work);
|
|
|
+}
|
|
|
+
|
|
|
+int acpi_reconfig_notifier_register(struct notifier_block *nb)
|
|
|
+{
|
|
|
+ return blocking_notifier_chain_register(&acpi_reconfig_chain, nb);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(acpi_reconfig_notifier_register);
|
|
|
+
|
|
|
+int acpi_reconfig_notifier_unregister(struct notifier_block *nb)
|
|
|
+{
|
|
|
+ return blocking_notifier_chain_unregister(&acpi_reconfig_chain, nb);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(acpi_reconfig_notifier_unregister);
|