|
@@ -79,6 +79,9 @@ static struct acpi_bus_type *acpi_get_bus_type(struct device *dev)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+#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)
|
|
|
{
|
|
@@ -92,14 +95,17 @@ static acpi_status acpi_dev_present(acpi_handle handle, u32 lvl_not_used,
|
|
|
return AE_OK;
|
|
|
}
|
|
|
|
|
|
-static bool acpi_extra_checks_passed(acpi_handle handle, bool is_bridge)
|
|
|
+static int do_find_child_checks(acpi_handle handle, bool is_bridge)
|
|
|
{
|
|
|
+ bool sta_present = true;
|
|
|
unsigned long long sta;
|
|
|
acpi_status status;
|
|
|
|
|
|
- status = acpi_bus_get_status_handle(handle, &sta);
|
|
|
- if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED))
|
|
|
- return false;
|
|
|
+ status = acpi_evaluate_integer(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;
|
|
@@ -107,16 +113,17 @@ static bool acpi_extra_checks_passed(acpi_handle handle, bool is_bridge)
|
|
|
/* Check if this object has at least one child device. */
|
|
|
acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
|
|
|
acpi_dev_present, NULL, NULL, &test);
|
|
|
- return !!test;
|
|
|
+ if (!test)
|
|
|
+ return -ENODEV;
|
|
|
}
|
|
|
- return true;
|
|
|
+ return sta_present ? FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE;
|
|
|
}
|
|
|
|
|
|
struct find_child_context {
|
|
|
u64 addr;
|
|
|
bool is_bridge;
|
|
|
acpi_handle ret;
|
|
|
- bool ret_checked;
|
|
|
+ int ret_score;
|
|
|
};
|
|
|
|
|
|
static acpi_status do_find_child(acpi_handle handle, u32 lvl_not_used,
|
|
@@ -125,6 +132,7 @@ static acpi_status do_find_child(acpi_handle handle, u32 lvl_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)
|
|
@@ -144,15 +152,20 @@ static acpi_status do_find_child(acpi_handle handle, u32 lvl_not_used,
|
|
|
* its handle if so. Second, check the same for the object that we've
|
|
|
* just found.
|
|
|
*/
|
|
|
- if (!context->ret_checked) {
|
|
|
- if (acpi_extra_checks_passed(context->ret, context->is_bridge))
|
|
|
+ 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_checked = true;
|
|
|
+ context->ret_score = score;
|
|
|
}
|
|
|
- if (acpi_extra_checks_passed(handle, context->is_bridge)) {
|
|
|
+ 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;
|
|
|
}
|