summaryrefslogtreecommitdiff
path: root/drivers/acpi/glue.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/glue.c')
-rw-r--r--drivers/acpi/glue.c165
1 files changed, 60 insertions, 105 deletions
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index a22a295edb69..0c789224d40d 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -37,7 +37,7 @@ int register_acpi_bus_type(struct acpi_bus_type *type)
{
if (acpi_disabled)
return -ENODEV;
- if (type && type->match && type->find_device) {
+ if (type && type->match && type->find_companion) {
down_write(&bus_type_sem);
list_add_tail(&type->list, &bus_type_list);
up_write(&bus_type_sem);
@@ -82,109 +82,74 @@ static struct acpi_bus_type *acpi_get_bus_type(struct device *dev)
#define FIND_CHILD_MIN_SCORE 1
#define FIND_CHILD_MAX_SCORE 2
-static acpi_status acpi_dev_present(acpi_handle handle, u32 lvl_not_used,
- void *not_used, void **ret_p)
-{
- struct acpi_device *adev = NULL;
-
- acpi_bus_get_device(handle, &adev);
- if (adev) {
- *ret_p = handle;
- return AE_CTRL_TERMINATE;
- }
- return AE_OK;
-}
-
-static int do_find_child_checks(acpi_handle handle, bool is_bridge)
+static int find_child_checks(struct acpi_device *adev, bool check_children)
{
bool sta_present = true;
unsigned long long sta;
acpi_status status;
- status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+ status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta);
if (status == AE_NOT_FOUND)
sta_present = false;
else if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED))
return -ENODEV;
- if (is_bridge) {
- void *test = NULL;
+ if (check_children && list_empty(&adev->children))
+ return -ENODEV;
- /* Check if this object has at least one child device. */
- acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
- acpi_dev_present, NULL, NULL, &test);
- if (!test)
- return -ENODEV;
- }
return sta_present ? FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE;
}
-struct find_child_context {
- u64 addr;
- bool is_bridge;
- acpi_handle ret;
- int ret_score;
-};
-
-static acpi_status do_find_child(acpi_handle handle, u32 lvl_not_used,
- void *data, void **not_used)
-{
- struct find_child_context *context = data;
- unsigned long long addr;
- acpi_status status;
- int score;
-
- status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &addr);
- if (ACPI_FAILURE(status) || addr != context->addr)
- return AE_OK;
-
- if (!context->ret) {
- /* This is the first matching object. Save its handle. */
- context->ret = handle;
- return AE_OK;
- }
- /*
- * There is more than one matching object with the same _ADR value.
- * That really is unexpected, so we are kind of beyond the scope of the
- * spec here. We have to choose which one to return, though.
- *
- * First, check if the previously found object is good enough and return
- * its handle if so. Second, check the same for the object that we've
- * just found.
- */
- if (!context->ret_score) {
- score = do_find_child_checks(context->ret, context->is_bridge);
- if (score == FIND_CHILD_MAX_SCORE)
- return AE_CTRL_TERMINATE;
- else
- context->ret_score = score;
- }
- score = do_find_child_checks(handle, context->is_bridge);
- if (score == FIND_CHILD_MAX_SCORE) {
- context->ret = handle;
- return AE_CTRL_TERMINATE;
- } else if (score > context->ret_score) {
- context->ret = handle;
- context->ret_score = score;
- }
- return AE_OK;
-}
-
-acpi_handle acpi_find_child(acpi_handle parent, u64 addr, bool is_bridge)
+struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
+ u64 address, bool check_children)
{
- if (parent) {
- struct find_child_context context = {
- .addr = addr,
- .is_bridge = is_bridge,
- };
-
- acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, 1, do_find_child,
- NULL, &context, NULL);
- return context.ret;
+ struct acpi_device *adev, *ret = NULL;
+ int ret_score = 0;
+
+ if (!parent)
+ return NULL;
+
+ list_for_each_entry(adev, &parent->children, node) {
+ unsigned long long addr;
+ acpi_status status;
+ int score;
+
+ status = acpi_evaluate_integer(adev->handle, METHOD_NAME__ADR,
+ NULL, &addr);
+ if (ACPI_FAILURE(status) || addr != address)
+ continue;
+
+ if (!ret) {
+ /* This is the first matching object. Save it. */
+ ret = adev;
+ continue;
+ }
+ /*
+ * There is more than one matching device object with the same
+ * _ADR value. That really is unexpected, so we are kind of
+ * beyond the scope of the spec here. We have to choose which
+ * one to return, though.
+ *
+ * First, check if the previously found object is good enough
+ * and return it if so. Second, do the same for the object that
+ * we've just found.
+ */
+ if (!ret_score) {
+ ret_score = find_child_checks(ret, check_children);
+ if (ret_score == FIND_CHILD_MAX_SCORE)
+ return ret;
+ }
+ score = find_child_checks(adev, check_children);
+ if (score == FIND_CHILD_MAX_SCORE) {
+ return adev;
+ } else if (score > ret_score) {
+ ret = adev;
+ ret_score = score;
+ }
}
- return NULL;
+ return ret;
}
-EXPORT_SYMBOL_GPL(acpi_find_child);
+EXPORT_SYMBOL_GPL(acpi_find_child_device);
static void acpi_physnode_link_name(char *buf, unsigned int node_id)
{
@@ -195,9 +160,8 @@ static void acpi_physnode_link_name(char *buf, unsigned int node_id)
strcpy(buf, PHYSICAL_NODE_STRING);
}
-int acpi_bind_one(struct device *dev, acpi_handle handle)
+int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
{
- struct acpi_device *acpi_dev = NULL;
struct acpi_device_physical_node *physical_node, *pn;
char physical_node_name[PHYSICAL_NODE_NAME_SIZE];
struct list_head *physnode_list;
@@ -205,14 +169,12 @@ int acpi_bind_one(struct device *dev, acpi_handle handle)
int retval = -EINVAL;
if (ACPI_COMPANION(dev)) {
- if (handle) {
+ if (acpi_dev) {
dev_warn(dev, "ACPI companion already set\n");
return -EINVAL;
} else {
acpi_dev = ACPI_COMPANION(dev);
}
- } else {
- acpi_bus_get_device(handle, &acpi_dev);
}
if (!acpi_dev)
return -EINVAL;
@@ -322,29 +284,22 @@ int acpi_unbind_one(struct device *dev)
}
EXPORT_SYMBOL_GPL(acpi_unbind_one);
-void acpi_preset_companion(struct device *dev, acpi_handle parent, u64 addr)
-{
- struct acpi_device *adev;
-
- if (!acpi_bus_get_device(acpi_get_child(parent, addr), &adev))
- ACPI_COMPANION_SET(dev, adev);
-}
-EXPORT_SYMBOL_GPL(acpi_preset_companion);
-
static int acpi_platform_notify(struct device *dev)
{
struct acpi_bus_type *type = acpi_get_bus_type(dev);
- acpi_handle handle;
int ret;
ret = acpi_bind_one(dev, NULL);
if (ret && type) {
- ret = type->find_device(dev, &handle);
- if (ret) {
+ struct acpi_device *adev;
+
+ adev = type->find_companion(dev);
+ if (!adev) {
DBG("Unable to get handle for %s\n", dev_name(dev));
+ ret = -ENODEV;
goto out;
}
- ret = acpi_bind_one(dev, handle);
+ ret = acpi_bind_one(dev, adev);
if (ret)
goto out;
}