diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2016-12-12 14:48:18 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2016-12-12 14:48:18 -0500 |
commit | 80f1b3dea9d4262817b5510547b1313681669f66 (patch) | |
tree | 1a084972bb36a9a51d75ad6f68c41743bc11e0c8 /drivers/acpi | |
parent | d2c2ba690180da366bdc5ca037c2d4f077bd5ffd (diff) | |
parent | ee39222d45839284f91e882df8a985e1af0f7e18 (diff) |
Merge branch 'device-properties'
* device-properties:
ACPI / property: Document usage rules for _DSD properties
ACPI / property: Hierarchical properties support update
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/device_sysfs.c | 8 | ||||
-rw-r--r-- | drivers/acpi/property.c | 125 |
2 files changed, 93 insertions, 40 deletions
diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c index 7b2c48fde4e2..24418932612e 100644 --- a/drivers/acpi/device_sysfs.c +++ b/drivers/acpi/device_sysfs.c | |||
@@ -52,7 +52,7 @@ struct acpi_data_node_attr { | |||
52 | 52 | ||
53 | static ssize_t data_node_show_path(struct acpi_data_node *dn, char *buf) | 53 | static ssize_t data_node_show_path(struct acpi_data_node *dn, char *buf) |
54 | { | 54 | { |
55 | return acpi_object_path(dn->handle, buf); | 55 | return dn->handle ? acpi_object_path(dn->handle, buf) : 0; |
56 | } | 56 | } |
57 | 57 | ||
58 | DATA_NODE_ATTR(path); | 58 | DATA_NODE_ATTR(path); |
@@ -105,10 +105,10 @@ static void acpi_expose_nondev_subnodes(struct kobject *kobj, | |||
105 | init_completion(&dn->kobj_done); | 105 | init_completion(&dn->kobj_done); |
106 | ret = kobject_init_and_add(&dn->kobj, &acpi_data_node_ktype, | 106 | ret = kobject_init_and_add(&dn->kobj, &acpi_data_node_ktype, |
107 | kobj, "%s", dn->name); | 107 | kobj, "%s", dn->name); |
108 | if (ret) | 108 | if (!ret) |
109 | acpi_handle_err(dn->handle, "Failed to expose (%d)\n", ret); | ||
110 | else | ||
111 | acpi_expose_nondev_subnodes(&dn->kobj, &dn->data); | 109 | acpi_expose_nondev_subnodes(&dn->kobj, &dn->data); |
110 | else if (dn->handle) | ||
111 | acpi_handle_err(dn->handle, "Failed to expose (%d)\n", ret); | ||
112 | } | 112 | } |
113 | } | 113 | } |
114 | 114 | ||
diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 03f5ec11ab31..3afddcd834ef 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c | |||
@@ -41,14 +41,13 @@ static bool acpi_enumerate_nondev_subnodes(acpi_handle scope, | |||
41 | static bool acpi_extract_properties(const union acpi_object *desc, | 41 | static bool acpi_extract_properties(const union acpi_object *desc, |
42 | struct acpi_device_data *data); | 42 | struct acpi_device_data *data); |
43 | 43 | ||
44 | static bool acpi_nondev_subnode_ok(acpi_handle scope, | 44 | static bool acpi_nondev_subnode_extract(const union acpi_object *desc, |
45 | const union acpi_object *link, | 45 | acpi_handle handle, |
46 | struct list_head *list) | 46 | const union acpi_object *link, |
47 | struct list_head *list) | ||
47 | { | 48 | { |
48 | struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; | ||
49 | struct acpi_data_node *dn; | 49 | struct acpi_data_node *dn; |
50 | acpi_handle handle; | 50 | bool result; |
51 | acpi_status status; | ||
52 | 51 | ||
53 | dn = kzalloc(sizeof(*dn), GFP_KERNEL); | 52 | dn = kzalloc(sizeof(*dn), GFP_KERNEL); |
54 | if (!dn) | 53 | if (!dn) |
@@ -58,43 +57,75 @@ static bool acpi_nondev_subnode_ok(acpi_handle scope, | |||
58 | dn->fwnode.type = FWNODE_ACPI_DATA; | 57 | dn->fwnode.type = FWNODE_ACPI_DATA; |
59 | INIT_LIST_HEAD(&dn->data.subnodes); | 58 | INIT_LIST_HEAD(&dn->data.subnodes); |
60 | 59 | ||
61 | status = acpi_get_handle(scope, link->package.elements[1].string.pointer, | 60 | result = acpi_extract_properties(desc, &dn->data); |
62 | &handle); | ||
63 | if (ACPI_FAILURE(status)) | ||
64 | goto fail; | ||
65 | 61 | ||
66 | status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf, | 62 | if (handle) { |
67 | ACPI_TYPE_PACKAGE); | 63 | acpi_handle scope; |
68 | if (ACPI_FAILURE(status)) | 64 | acpi_status status; |
69 | goto fail; | ||
70 | 65 | ||
71 | if (acpi_extract_properties(buf.pointer, &dn->data)) | 66 | /* |
72 | dn->handle = handle; | 67 | * The scope for the subnode object lookup is the one of the |
68 | * namespace node (device) containing the object that has | ||
69 | * returned the package. That is, it's the scope of that | ||
70 | * object's parent. | ||
71 | */ | ||
72 | status = acpi_get_parent(handle, &scope); | ||
73 | if (ACPI_SUCCESS(status) | ||
74 | && acpi_enumerate_nondev_subnodes(scope, desc, &dn->data)) | ||
75 | result = true; | ||
76 | } else if (acpi_enumerate_nondev_subnodes(NULL, desc, &dn->data)) { | ||
77 | result = true; | ||
78 | } | ||
73 | 79 | ||
74 | /* | 80 | if (result) { |
75 | * The scope for the subnode object lookup is the one of the namespace | ||
76 | * node (device) containing the object that has returned the package. | ||
77 | * That is, it's the scope of that object's parent. | ||
78 | */ | ||
79 | status = acpi_get_parent(handle, &scope); | ||
80 | if (ACPI_SUCCESS(status) | ||
81 | && acpi_enumerate_nondev_subnodes(scope, buf.pointer, &dn->data)) | ||
82 | dn->handle = handle; | 81 | dn->handle = handle; |
83 | 82 | dn->data.pointer = desc; | |
84 | if (dn->handle) { | ||
85 | dn->data.pointer = buf.pointer; | ||
86 | list_add_tail(&dn->sibling, list); | 83 | list_add_tail(&dn->sibling, list); |
87 | return true; | 84 | return true; |
88 | } | 85 | } |
89 | 86 | ||
87 | kfree(dn); | ||
90 | acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping\n"); | 88 | acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping\n"); |
89 | return false; | ||
90 | } | ||
91 | |||
92 | static bool acpi_nondev_subnode_data_ok(acpi_handle handle, | ||
93 | const union acpi_object *link, | ||
94 | struct list_head *list) | ||
95 | { | ||
96 | struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; | ||
97 | acpi_status status; | ||
98 | |||
99 | status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf, | ||
100 | ACPI_TYPE_PACKAGE); | ||
101 | if (ACPI_FAILURE(status)) | ||
102 | return false; | ||
103 | |||
104 | if (acpi_nondev_subnode_extract(buf.pointer, handle, link, list)) | ||
105 | return true; | ||
91 | 106 | ||
92 | fail: | ||
93 | ACPI_FREE(buf.pointer); | 107 | ACPI_FREE(buf.pointer); |
94 | kfree(dn); | ||
95 | return false; | 108 | return false; |
96 | } | 109 | } |
97 | 110 | ||
111 | static bool acpi_nondev_subnode_ok(acpi_handle scope, | ||
112 | const union acpi_object *link, | ||
113 | struct list_head *list) | ||
114 | { | ||
115 | acpi_handle handle; | ||
116 | acpi_status status; | ||
117 | |||
118 | if (!scope) | ||
119 | return false; | ||
120 | |||
121 | status = acpi_get_handle(scope, link->package.elements[1].string.pointer, | ||
122 | &handle); | ||
123 | if (ACPI_FAILURE(status)) | ||
124 | return false; | ||
125 | |||
126 | return acpi_nondev_subnode_data_ok(handle, link, list); | ||
127 | } | ||
128 | |||
98 | static int acpi_add_nondev_subnodes(acpi_handle scope, | 129 | static int acpi_add_nondev_subnodes(acpi_handle scope, |
99 | const union acpi_object *links, | 130 | const union acpi_object *links, |
100 | struct list_head *list) | 131 | struct list_head *list) |
@@ -103,15 +134,37 @@ static int acpi_add_nondev_subnodes(acpi_handle scope, | |||
103 | int i; | 134 | int i; |
104 | 135 | ||
105 | for (i = 0; i < links->package.count; i++) { | 136 | for (i = 0; i < links->package.count; i++) { |
106 | const union acpi_object *link; | 137 | const union acpi_object *link, *desc; |
138 | acpi_handle handle; | ||
139 | bool result; | ||
107 | 140 | ||
108 | link = &links->package.elements[i]; | 141 | link = &links->package.elements[i]; |
109 | /* Only two elements allowed, both must be strings. */ | 142 | /* Only two elements allowed. */ |
110 | if (link->package.count == 2 | 143 | if (link->package.count != 2) |
111 | && link->package.elements[0].type == ACPI_TYPE_STRING | 144 | continue; |
112 | && link->package.elements[1].type == ACPI_TYPE_STRING | 145 | |
113 | && acpi_nondev_subnode_ok(scope, link, list)) | 146 | /* The first one must be a string. */ |
114 | ret = true; | 147 | if (link->package.elements[0].type != ACPI_TYPE_STRING) |
148 | continue; | ||
149 | |||
150 | /* The second one may be a string, a reference or a package. */ | ||
151 | switch (link->package.elements[1].type) { | ||
152 | case ACPI_TYPE_STRING: | ||
153 | result = acpi_nondev_subnode_ok(scope, link, list); | ||
154 | break; | ||
155 | case ACPI_TYPE_LOCAL_REFERENCE: | ||
156 | handle = link->package.elements[1].reference.handle; | ||
157 | result = acpi_nondev_subnode_data_ok(handle, link, list); | ||
158 | break; | ||
159 | case ACPI_TYPE_PACKAGE: | ||
160 | desc = &link->package.elements[1]; | ||
161 | result = acpi_nondev_subnode_extract(desc, NULL, link, list); | ||
162 | break; | ||
163 | default: | ||
164 | result = false; | ||
165 | break; | ||
166 | } | ||
167 | ret = ret || result; | ||
115 | } | 168 | } |
116 | 169 | ||
117 | return ret; | 170 | return ret; |