|
@@ -41,14 +41,13 @@ static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
|
|
static bool acpi_extract_properties(const union acpi_object *desc,
|
|
static bool acpi_extract_properties(const union acpi_object *desc,
|
|
struct acpi_device_data *data);
|
|
struct acpi_device_data *data);
|
|
|
|
|
|
-static bool acpi_nondev_subnode_ok(acpi_handle scope,
|
|
|
|
- const union acpi_object *link,
|
|
|
|
- struct list_head *list)
|
|
|
|
|
|
+static bool acpi_nondev_subnode_extract(const union acpi_object *desc,
|
|
|
|
+ acpi_handle handle,
|
|
|
|
+ const union acpi_object *link,
|
|
|
|
+ struct list_head *list)
|
|
{
|
|
{
|
|
- struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
|
|
|
|
struct acpi_data_node *dn;
|
|
struct acpi_data_node *dn;
|
|
- acpi_handle handle;
|
|
|
|
- acpi_status status;
|
|
|
|
|
|
+ bool result;
|
|
|
|
|
|
dn = kzalloc(sizeof(*dn), GFP_KERNEL);
|
|
dn = kzalloc(sizeof(*dn), GFP_KERNEL);
|
|
if (!dn)
|
|
if (!dn)
|
|
@@ -58,43 +57,75 @@ static bool acpi_nondev_subnode_ok(acpi_handle scope,
|
|
dn->fwnode.type = FWNODE_ACPI_DATA;
|
|
dn->fwnode.type = FWNODE_ACPI_DATA;
|
|
INIT_LIST_HEAD(&dn->data.subnodes);
|
|
INIT_LIST_HEAD(&dn->data.subnodes);
|
|
|
|
|
|
- status = acpi_get_handle(scope, link->package.elements[1].string.pointer,
|
|
|
|
- &handle);
|
|
|
|
- if (ACPI_FAILURE(status))
|
|
|
|
- goto fail;
|
|
|
|
|
|
+ result = acpi_extract_properties(desc, &dn->data);
|
|
|
|
|
|
- status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf,
|
|
|
|
- ACPI_TYPE_PACKAGE);
|
|
|
|
- if (ACPI_FAILURE(status))
|
|
|
|
- goto fail;
|
|
|
|
|
|
+ if (handle) {
|
|
|
|
+ acpi_handle scope;
|
|
|
|
+ acpi_status status;
|
|
|
|
|
|
- if (acpi_extract_properties(buf.pointer, &dn->data))
|
|
|
|
- dn->handle = handle;
|
|
|
|
|
|
+ /*
|
|
|
|
+ * The scope for the subnode object lookup is the one of the
|
|
|
|
+ * namespace node (device) containing the object that has
|
|
|
|
+ * returned the package. That is, it's the scope of that
|
|
|
|
+ * object's parent.
|
|
|
|
+ */
|
|
|
|
+ status = acpi_get_parent(handle, &scope);
|
|
|
|
+ if (ACPI_SUCCESS(status)
|
|
|
|
+ && acpi_enumerate_nondev_subnodes(scope, desc, &dn->data))
|
|
|
|
+ result = true;
|
|
|
|
+ } else if (acpi_enumerate_nondev_subnodes(NULL, desc, &dn->data)) {
|
|
|
|
+ result = true;
|
|
|
|
+ }
|
|
|
|
|
|
- /*
|
|
|
|
- * The scope for the subnode object lookup is the one of the namespace
|
|
|
|
- * node (device) containing the object that has returned the package.
|
|
|
|
- * That is, it's the scope of that object's parent.
|
|
|
|
- */
|
|
|
|
- status = acpi_get_parent(handle, &scope);
|
|
|
|
- if (ACPI_SUCCESS(status)
|
|
|
|
- && acpi_enumerate_nondev_subnodes(scope, buf.pointer, &dn->data))
|
|
|
|
|
|
+ if (result) {
|
|
dn->handle = handle;
|
|
dn->handle = handle;
|
|
-
|
|
|
|
- if (dn->handle) {
|
|
|
|
- dn->data.pointer = buf.pointer;
|
|
|
|
|
|
+ dn->data.pointer = desc;
|
|
list_add_tail(&dn->sibling, list);
|
|
list_add_tail(&dn->sibling, list);
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ kfree(dn);
|
|
acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping\n");
|
|
acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping\n");
|
|
|
|
+ return false;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static bool acpi_nondev_subnode_data_ok(acpi_handle handle,
|
|
|
|
+ const union acpi_object *link,
|
|
|
|
+ struct list_head *list)
|
|
|
|
+{
|
|
|
|
+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
|
|
|
|
+ acpi_status status;
|
|
|
|
+
|
|
|
|
+ status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf,
|
|
|
|
+ ACPI_TYPE_PACKAGE);
|
|
|
|
+ if (ACPI_FAILURE(status))
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ if (acpi_nondev_subnode_extract(buf.pointer, handle, link, list))
|
|
|
|
+ return true;
|
|
|
|
|
|
- fail:
|
|
|
|
ACPI_FREE(buf.pointer);
|
|
ACPI_FREE(buf.pointer);
|
|
- kfree(dn);
|
|
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static bool acpi_nondev_subnode_ok(acpi_handle scope,
|
|
|
|
+ const union acpi_object *link,
|
|
|
|
+ struct list_head *list)
|
|
|
|
+{
|
|
|
|
+ acpi_handle handle;
|
|
|
|
+ acpi_status status;
|
|
|
|
+
|
|
|
|
+ if (!scope)
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ status = acpi_get_handle(scope, link->package.elements[1].string.pointer,
|
|
|
|
+ &handle);
|
|
|
|
+ if (ACPI_FAILURE(status))
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ return acpi_nondev_subnode_data_ok(handle, link, list);
|
|
|
|
+}
|
|
|
|
+
|
|
static int acpi_add_nondev_subnodes(acpi_handle scope,
|
|
static int acpi_add_nondev_subnodes(acpi_handle scope,
|
|
const union acpi_object *links,
|
|
const union acpi_object *links,
|
|
struct list_head *list)
|
|
struct list_head *list)
|
|
@@ -103,15 +134,37 @@ static int acpi_add_nondev_subnodes(acpi_handle scope,
|
|
int i;
|
|
int i;
|
|
|
|
|
|
for (i = 0; i < links->package.count; i++) {
|
|
for (i = 0; i < links->package.count; i++) {
|
|
- const union acpi_object *link;
|
|
|
|
|
|
+ const union acpi_object *link, *desc;
|
|
|
|
+ acpi_handle handle;
|
|
|
|
+ bool result;
|
|
|
|
|
|
link = &links->package.elements[i];
|
|
link = &links->package.elements[i];
|
|
- /* Only two elements allowed, both must be strings. */
|
|
|
|
- if (link->package.count == 2
|
|
|
|
- && link->package.elements[0].type == ACPI_TYPE_STRING
|
|
|
|
- && link->package.elements[1].type == ACPI_TYPE_STRING
|
|
|
|
- && acpi_nondev_subnode_ok(scope, link, list))
|
|
|
|
- ret = true;
|
|
|
|
|
|
+ /* Only two elements allowed. */
|
|
|
|
+ if (link->package.count != 2)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ /* The first one must be a string. */
|
|
|
|
+ if (link->package.elements[0].type != ACPI_TYPE_STRING)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ /* The second one may be a string, a reference or a package. */
|
|
|
|
+ switch (link->package.elements[1].type) {
|
|
|
|
+ case ACPI_TYPE_STRING:
|
|
|
|
+ result = acpi_nondev_subnode_ok(scope, link, list);
|
|
|
|
+ break;
|
|
|
|
+ case ACPI_TYPE_LOCAL_REFERENCE:
|
|
|
|
+ handle = link->package.elements[1].reference.handle;
|
|
|
|
+ result = acpi_nondev_subnode_data_ok(handle, link, list);
|
|
|
|
+ break;
|
|
|
|
+ case ACPI_TYPE_PACKAGE:
|
|
|
|
+ desc = &link->package.elements[1];
|
|
|
|
+ result = acpi_nondev_subnode_extract(desc, NULL, link, list);
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ result = false;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ ret = ret || result;
|
|
}
|
|
}
|
|
|
|
|
|
return ret;
|
|
return ret;
|