struct acpi_device *acpi_dev = to_acpi_device(dev);
struct acpi_driver *acpi_drv = to_acpi_driver(drv);
- return !acpi_match_device_ids(acpi_dev, acpi_drv->ids);
+ return acpi_dev->add_type >= ACPI_BUS_ADD_MATCH
+ && !acpi_match_device_ids(acpi_dev, acpi_drv->ids);
}
static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env)
ret = acpi_bus_driver_init(acpi_dev, acpi_drv);
if (!ret) {
- if (acpi_dev->bus_ops.acpi_op_start)
+ if (acpi_dev->add_type == ACPI_BUS_ADD_START)
acpi_start_single_object(acpi_dev);
if (acpi_drv->ops.notify) {
return 0;
}
+/*
+ * acpi_hot_add_bind - Bind _ADR-based devices on hot-add.
+ * @device: ACPI device node to bind.
+ */
+static void acpi_hot_add_bind(struct acpi_device *device)
+{
+ if (device->flags.bus_address
+ && device->parent && device->parent->ops.bind)
+ device->parent->ops.bind(device);
+}
+
static int acpi_add_single_object(struct acpi_device **child,
acpi_handle handle, int type,
unsigned long long sta,
- struct acpi_bus_ops *ops)
+ enum acpi_bus_add_type add_type)
{
int result;
struct acpi_device *device;
device->device_type = type;
device->handle = handle;
device->parent = acpi_bus_get_parent(handle);
- device->bus_ops = *ops; /* workround for not call .start */
+ device->add_type = add_type;
STRUCT_TO_INT(device->status) = sta;
acpi_device_get_busid(device);
result = acpi_device_register(device);
- /*
- * Bind _ADR-Based Devices when hot add
- */
- if (device->flags.bus_address) {
- if (device->parent && device->parent->ops.bind)
- device->parent->ops.bind(device);
- }
+ if (device->add_type >= ACPI_BUS_ADD_MATCH)
+ acpi_hot_add_bind(device);
end:
if (!result) {
static void acpi_bus_add_power_resource(acpi_handle handle)
{
- struct acpi_bus_ops ops = {
- .acpi_op_add = 1,
- .acpi_op_start = 1,
- };
struct acpi_device *device = NULL;
acpi_bus_get_device(handle, &device);
if (!device)
acpi_add_single_object(&device, handle, ACPI_BUS_TYPE_POWER,
- ACPI_STA_DEFAULT, &ops);
+ ACPI_STA_DEFAULT, ACPI_BUS_ADD_START);
}
static int acpi_bus_type_and_status(acpi_handle handle, int *type,
static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl,
void *context, void **return_value)
{
- struct acpi_bus_ops *ops = context;
+ struct acpi_device *device = NULL;
int type;
unsigned long long sta;
- struct acpi_device *device;
acpi_status status;
int result;
return AE_CTRL_DEPTH;
}
- /*
- * We may already have an acpi_device from a previous enumeration. If
- * so, we needn't add it again, but we may still have to start it.
- */
- device = NULL;
acpi_bus_get_device(handle, &device);
- if (ops->acpi_op_add && !device) {
- acpi_add_single_object(&device, handle, type, sta, ops);
- /* Is the device a known good platform device? */
- if (device
- && !acpi_match_device_ids(device, acpi_platform_device_ids))
- acpi_create_platform_device(device);
- }
-
- if (!device)
- return AE_CTRL_DEPTH;
-
- if (ops->acpi_op_start && !(ops->acpi_op_add)) {
- status = acpi_start_single_object(device);
- if (ACPI_FAILURE(status))
+ if (!device) {
+ acpi_add_single_object(&device, handle, type, sta,
+ ACPI_BUS_ADD_BASIC);
+ if (!device)
return AE_CTRL_DEPTH;
+
+ device->add_type = context ?
+ ACPI_BUS_ADD_START : ACPI_BUS_ADD_MATCH;
+ acpi_hot_add_bind(device);
}
if (!*return_value)
*return_value = device;
+
return AE_OK;
}
-static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops,
+static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used,
+ void *not_used, void **ret_not_used)
+{
+ acpi_status status = AE_OK;
+ struct acpi_device *device;
+ unsigned long long sta_not_used;
+ int type_not_used;
+
+ /*
+ * Ignore errors ignored by acpi_bus_check_add() to avoid terminating
+ * namespace walks prematurely.
+ */
+ if (acpi_bus_type_and_status(handle, &type_not_used, &sta_not_used))
+ return AE_OK;
+
+ if (acpi_bus_get_device(handle, &device))
+ return AE_CTRL_DEPTH;
+
+ if (!acpi_match_device_ids(device, acpi_platform_device_ids)) {
+ /* This is a known good platform device. */
+ acpi_create_platform_device(device);
+ } else if (device_attach(&device->dev)) {
+ status = AE_CTRL_DEPTH;
+ }
+ return status;
+}
+
+static int acpi_bus_scan(acpi_handle handle, bool start,
struct acpi_device **child)
{
- acpi_status status;
void *device = NULL;
+ acpi_status status;
+ int ret = -ENODEV;
+
+ status = acpi_bus_check_add(handle, 0, (void *)start, &device);
+ if (ACPI_SUCCESS(status))
+ acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
+ acpi_bus_check_add, NULL, (void *)start,
+ &device);
+
+ if (!device)
+ goto out;
- status = acpi_bus_check_add(handle, 0, ops, &device);
+ ret = 0;
+ status = acpi_bus_device_attach(handle, 0, NULL, NULL);
if (ACPI_SUCCESS(status))
acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
- acpi_bus_check_add, NULL, ops, &device);
+ acpi_bus_device_attach, NULL, NULL, NULL);
+ out:
if (child)
*child = device;
- if (device)
- return 0;
- else
- return -ENODEV;
+ return ret;
}
/*
acpi_bus_add(struct acpi_device **child,
struct acpi_device *parent, acpi_handle handle, int type)
{
- struct acpi_bus_ops ops;
+ return acpi_bus_scan(handle, false, child);
+}
+EXPORT_SYMBOL(acpi_bus_add);
- memset(&ops, 0, sizeof(ops));
- ops.acpi_op_add = 1;
+static acpi_status acpi_bus_start_device(acpi_handle handle, u32 lvl,
+ void *not_used, void **ret_not_used)
+{
+ struct acpi_device *device;
+ unsigned long long sta_not_used;
+ int type_not_used;
+
+ /*
+ * Ignore errors ignored by acpi_bus_check_add() to avoid terminating
+ * namespace walks prematurely.
+ */
+ if (acpi_bus_type_and_status(handle, &type_not_used, &sta_not_used))
+ return AE_OK;
- return acpi_bus_scan(handle, &ops, child);
+ if (acpi_bus_get_device(handle, &device))
+ return AE_CTRL_DEPTH;
+
+ return acpi_start_single_object(device);
}
-EXPORT_SYMBOL(acpi_bus_add);
int acpi_bus_start(struct acpi_device *device)
{
- struct acpi_bus_ops ops;
- int result;
-
if (!device)
return -EINVAL;
- memset(&ops, 0, sizeof(ops));
- ops.acpi_op_start = 1;
-
- result = acpi_bus_scan(device->handle, &ops, NULL);
+ if (ACPI_SUCCESS(acpi_start_single_object(device)))
+ acpi_walk_namespace(ACPI_TYPE_ANY, device->handle,
+ ACPI_UINT32_MAX, acpi_bus_start_device,
+ NULL, NULL, NULL);
acpi_update_all_gpes();
-
- return result;
+ return 0;
}
EXPORT_SYMBOL(acpi_bus_start);
{
int result = 0;
struct acpi_device *device = NULL;
- struct acpi_bus_ops ops;
-
- memset(&ops, 0, sizeof(ops));
- ops.acpi_op_add = 1;
- ops.acpi_op_start = 1;
/*
* Enumerate all fixed-feature devices.
result = acpi_add_single_object(&device, NULL,
ACPI_BUS_TYPE_POWER_BUTTON,
ACPI_STA_DEFAULT,
- &ops);
+ ACPI_BUS_ADD_START);
device_init_wakeup(&device->dev, true);
}
result = acpi_add_single_object(&device, NULL,
ACPI_BUS_TYPE_SLEEP_BUTTON,
ACPI_STA_DEFAULT,
- &ops);
+ ACPI_BUS_ADD_START);
}
return result;
int __init acpi_scan_init(void)
{
int result;
- struct acpi_bus_ops ops;
-
- memset(&ops, 0, sizeof(ops));
- ops.acpi_op_add = 1;
- ops.acpi_op_start = 1;
result = bus_register(&acpi_bus_type);
if (result) {
}
acpi_power_init();
+ acpi_pci_root_init();
/*
* Enumerate devices in the ACPI namespace.
*/
- result = acpi_bus_scan(ACPI_ROOT_OBJECT, &ops, &acpi_root);
+ result = acpi_bus_scan(ACPI_ROOT_OBJECT, true, &acpi_root);
if (!result)
result = acpi_bus_scan_fixed();