blob: e78551726acb510ac86b98185e3cee3a1ca7e9af [file] [log] [blame]
Mika Westerbergffdcd952014-10-21 13:33:55 +02001/*
2 * ACPI device specific properties support.
3 *
4 * Copyright (C) 2014, Intel Corporation
5 * All rights reserved.
6 *
7 * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
8 * Darren Hart <dvhart@linux.intel.com>
9 * Rafael J. Wysocki <rafael.j.wysocki@intel.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 */
15
16#include <linux/acpi.h>
17#include <linux/device.h>
18#include <linux/export.h>
19
20#include "internal.h"
21
Rafael J. Wysocki3a7a2ab2015-08-27 04:40:05 +020022static int acpi_data_get_property_array(struct acpi_device_data *data,
23 const char *name,
24 acpi_object_type type,
25 const union acpi_object **obj);
26
Mika Westerbergffdcd952014-10-21 13:33:55 +020027/* ACPI _DSD device properties UUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */
28static const u8 prp_uuid[16] = {
29 0x14, 0xd8, 0xff, 0xda, 0xba, 0x6e, 0x8c, 0x4d,
30 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01
31};
Rafael J. Wysocki445b0eb2015-08-27 04:36:14 +020032/* ACPI _DSD data subnodes UUID: dbb8e3e6-5886-4ba6-8795-1319f52a966b */
33static const u8 ads_uuid[16] = {
34 0xe6, 0xe3, 0xb8, 0xdb, 0x86, 0x58, 0xa6, 0x4b,
35 0x87, 0x95, 0x13, 0x19, 0xf5, 0x2a, 0x96, 0x6b
36};
37
38static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
39 const union acpi_object *desc,
40 struct acpi_device_data *data);
41static bool acpi_extract_properties(const union acpi_object *desc,
42 struct acpi_device_data *data);
43
44static bool acpi_nondev_subnode_ok(acpi_handle scope,
45 const union acpi_object *link,
46 struct list_head *list)
47{
48 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
49 struct acpi_data_node *dn;
50 acpi_handle handle;
51 acpi_status status;
52
53 dn = kzalloc(sizeof(*dn), GFP_KERNEL);
54 if (!dn)
55 return false;
56
57 dn->name = link->package.elements[0].string.pointer;
58 dn->fwnode.type = FWNODE_ACPI_DATA;
59 INIT_LIST_HEAD(&dn->data.subnodes);
60
61 status = acpi_get_handle(scope, link->package.elements[1].string.pointer,
62 &handle);
63 if (ACPI_FAILURE(status))
64 goto fail;
65
66 status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf,
67 ACPI_TYPE_PACKAGE);
68 if (ACPI_FAILURE(status))
69 goto fail;
70
71 if (acpi_extract_properties(buf.pointer, &dn->data))
Rafael J. Wysocki263b4c12015-08-27 04:37:19 +020072 dn->handle = handle;
Rafael J. Wysocki445b0eb2015-08-27 04:36:14 +020073
74 if (acpi_enumerate_nondev_subnodes(scope, buf.pointer, &dn->data))
Rafael J. Wysocki263b4c12015-08-27 04:37:19 +020075 dn->handle = handle;
Rafael J. Wysocki445b0eb2015-08-27 04:36:14 +020076
Rafael J. Wysocki263b4c12015-08-27 04:37:19 +020077 if (dn->handle) {
78 dn->data.pointer = buf.pointer;
Rafael J. Wysocki445b0eb2015-08-27 04:36:14 +020079 list_add_tail(&dn->sibling, list);
80 return true;
81 }
82
83 acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping\n");
84
85 fail:
86 ACPI_FREE(buf.pointer);
87 kfree(dn);
88 return false;
89}
90
91static int acpi_add_nondev_subnodes(acpi_handle scope,
92 const union acpi_object *links,
93 struct list_head *list)
94{
95 bool ret = false;
96 int i;
97
98 for (i = 0; i < links->package.count; i++) {
99 const union acpi_object *link;
100
101 link = &links->package.elements[i];
102 /* Only two elements allowed, both must be strings. */
103 if (link->package.count == 2
104 && link->package.elements[0].type == ACPI_TYPE_STRING
105 && link->package.elements[1].type == ACPI_TYPE_STRING
106 && acpi_nondev_subnode_ok(scope, link, list))
107 ret = true;
108 }
109
110 return ret;
111}
112
113static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
114 const union acpi_object *desc,
115 struct acpi_device_data *data)
116{
117 int i;
118
119 /* Look for the ACPI data subnodes UUID. */
120 for (i = 0; i < desc->package.count; i += 2) {
121 const union acpi_object *uuid, *links;
122
123 uuid = &desc->package.elements[i];
124 links = &desc->package.elements[i + 1];
125
126 /*
127 * The first element must be a UUID and the second one must be
128 * a package.
129 */
130 if (uuid->type != ACPI_TYPE_BUFFER || uuid->buffer.length != 16
131 || links->type != ACPI_TYPE_PACKAGE)
132 break;
133
134 if (memcmp(uuid->buffer.pointer, ads_uuid, sizeof(ads_uuid)))
135 continue;
136
137 return acpi_add_nondev_subnodes(scope, links, &data->subnodes);
138 }
139
140 return false;
141}
Mika Westerbergffdcd952014-10-21 13:33:55 +0200142
143static bool acpi_property_value_ok(const union acpi_object *value)
144{
145 int j;
146
147 /*
148 * The value must be an integer, a string, a reference, or a package
149 * whose every element must be an integer, a string, or a reference.
150 */
151 switch (value->type) {
152 case ACPI_TYPE_INTEGER:
153 case ACPI_TYPE_STRING:
154 case ACPI_TYPE_LOCAL_REFERENCE:
155 return true;
156
157 case ACPI_TYPE_PACKAGE:
158 for (j = 0; j < value->package.count; j++)
159 switch (value->package.elements[j].type) {
160 case ACPI_TYPE_INTEGER:
161 case ACPI_TYPE_STRING:
162 case ACPI_TYPE_LOCAL_REFERENCE:
163 continue;
164
165 default:
166 return false;
167 }
168
169 return true;
170 }
171 return false;
172}
173
174static bool acpi_properties_format_valid(const union acpi_object *properties)
175{
176 int i;
177
178 for (i = 0; i < properties->package.count; i++) {
179 const union acpi_object *property;
180
181 property = &properties->package.elements[i];
182 /*
183 * Only two elements allowed, the first one must be a string and
184 * the second one has to satisfy certain conditions.
185 */
186 if (property->package.count != 2
187 || property->package.elements[0].type != ACPI_TYPE_STRING
188 || !acpi_property_value_ok(&property->package.elements[1]))
189 return false;
190 }
191 return true;
192}
193
Mika Westerberg733e6252014-10-21 13:33:56 +0200194static void acpi_init_of_compatible(struct acpi_device *adev)
195{
196 const union acpi_object *of_compatible;
Mika Westerberg733e6252014-10-21 13:33:56 +0200197 int ret;
198
Rafael J. Wysocki3a7a2ab2015-08-27 04:40:05 +0200199 ret = acpi_data_get_property_array(&adev->data, "compatible",
200 ACPI_TYPE_STRING, &of_compatible);
Rafael J. Wysocki5c53b262015-05-05 15:43:07 +0200201 if (ret) {
202 ret = acpi_dev_get_property(adev, "compatible",
203 ACPI_TYPE_STRING, &of_compatible);
204 if (ret) {
205 if (adev->parent
206 && adev->parent->flags.of_compatible_ok)
207 goto out;
208
209 return;
210 }
211 }
212 adev->data.of_compatible = of_compatible;
213
214 out:
215 adev->flags.of_compatible_ok = 1;
216}
217
Rafael J. Wysockibd8191c2015-08-27 04:35:14 +0200218static bool acpi_extract_properties(const union acpi_object *desc,
219 struct acpi_device_data *data)
Rafael J. Wysocki5c53b262015-05-05 15:43:07 +0200220{
Rafael J. Wysocki5c53b262015-05-05 15:43:07 +0200221 int i;
222
Mika Westerbergffdcd952014-10-21 13:33:55 +0200223 if (desc->package.count % 2)
Rafael J. Wysockibd8191c2015-08-27 04:35:14 +0200224 return false;
Mika Westerbergffdcd952014-10-21 13:33:55 +0200225
226 /* Look for the device properties UUID. */
227 for (i = 0; i < desc->package.count; i += 2) {
228 const union acpi_object *uuid, *properties;
229
230 uuid = &desc->package.elements[i];
231 properties = &desc->package.elements[i + 1];
232
233 /*
234 * The first element must be a UUID and the second one must be
235 * a package.
236 */
237 if (uuid->type != ACPI_TYPE_BUFFER || uuid->buffer.length != 16
238 || properties->type != ACPI_TYPE_PACKAGE)
239 break;
240
241 if (memcmp(uuid->buffer.pointer, prp_uuid, sizeof(prp_uuid)))
242 continue;
243
244 /*
245 * We found the matching UUID. Now validate the format of the
246 * package immediately following it.
247 */
248 if (!acpi_properties_format_valid(properties))
249 break;
250
Rafael J. Wysockibd8191c2015-08-27 04:35:14 +0200251 data->properties = properties;
252 return true;
Mika Westerbergffdcd952014-10-21 13:33:55 +0200253 }
254
Rafael J. Wysockibd8191c2015-08-27 04:35:14 +0200255 return false;
256}
257
258void acpi_init_properties(struct acpi_device *adev)
259{
260 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
261 struct acpi_hardware_id *hwid;
262 acpi_status status;
263 bool acpi_of = false;
264
Rafael J. Wysocki445b0eb2015-08-27 04:36:14 +0200265 INIT_LIST_HEAD(&adev->data.subnodes);
266
Rafael J. Wysockibd8191c2015-08-27 04:35:14 +0200267 /*
268 * Check if ACPI_DT_NAMESPACE_HID is present and inthat case we fill in
269 * Device Tree compatible properties for this device.
270 */
271 list_for_each_entry(hwid, &adev->pnp.ids, list) {
272 if (!strcmp(hwid->id, ACPI_DT_NAMESPACE_HID)) {
273 acpi_of = true;
274 break;
275 }
276 }
277
278 status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL, &buf,
279 ACPI_TYPE_PACKAGE);
280 if (ACPI_FAILURE(status))
281 goto out;
282
283 if (acpi_extract_properties(buf.pointer, &adev->data)) {
284 adev->data.pointer = buf.pointer;
285 if (acpi_of)
286 acpi_init_of_compatible(adev);
Rafael J. Wysocki445b0eb2015-08-27 04:36:14 +0200287 }
288 if (acpi_enumerate_nondev_subnodes(adev->handle, buf.pointer, &adev->data))
289 adev->data.pointer = buf.pointer;
290
291 if (!adev->data.pointer) {
Rafael J. Wysockibd8191c2015-08-27 04:35:14 +0200292 acpi_handle_debug(adev->handle, "Invalid _DSD data, skipping\n");
293 ACPI_FREE(buf.pointer);
294 }
Rafael J. Wysocki5c53b262015-05-05 15:43:07 +0200295
296 out:
297 if (acpi_of && !adev->flags.of_compatible_ok)
298 acpi_handle_info(adev->handle,
Rafael J. Wysockiee892092015-05-22 04:24:34 +0200299 ACPI_DT_NAMESPACE_HID " requires 'compatible' property\n");
Mika Westerbergffdcd952014-10-21 13:33:55 +0200300}
301
Rafael J. Wysocki445b0eb2015-08-27 04:36:14 +0200302static void acpi_destroy_nondev_subnodes(struct list_head *list)
303{
304 struct acpi_data_node *dn, *next;
305
306 if (list_empty(list))
307 return;
308
309 list_for_each_entry_safe_reverse(dn, next, list, sibling) {
310 acpi_destroy_nondev_subnodes(&dn->data.subnodes);
Rafael J. Wysocki263b4c12015-08-27 04:37:19 +0200311 wait_for_completion(&dn->kobj_done);
Rafael J. Wysocki445b0eb2015-08-27 04:36:14 +0200312 list_del(&dn->sibling);
313 ACPI_FREE((void *)dn->data.pointer);
314 kfree(dn);
315 }
316}
317
Mika Westerbergffdcd952014-10-21 13:33:55 +0200318void acpi_free_properties(struct acpi_device *adev)
319{
Rafael J. Wysocki445b0eb2015-08-27 04:36:14 +0200320 acpi_destroy_nondev_subnodes(&adev->data.subnodes);
Mika Westerbergffdcd952014-10-21 13:33:55 +0200321 ACPI_FREE((void *)adev->data.pointer);
Mika Westerberg733e6252014-10-21 13:33:56 +0200322 adev->data.of_compatible = NULL;
Mika Westerbergffdcd952014-10-21 13:33:55 +0200323 adev->data.pointer = NULL;
324 adev->data.properties = NULL;
325}
326
327/**
Rafael J. Wysocki3a7a2ab2015-08-27 04:40:05 +0200328 * acpi_data_get_property - return an ACPI property with given name
329 * @data: ACPI device deta object to get the property from
Mika Westerbergffdcd952014-10-21 13:33:55 +0200330 * @name: Name of the property
331 * @type: Expected property type
332 * @obj: Location to store the property value (if not %NULL)
333 *
334 * Look up a property with @name and store a pointer to the resulting ACPI
335 * object at the location pointed to by @obj if found.
336 *
337 * Callers must not attempt to free the returned objects. These objects will be
Rafael J. Wysocki3a7a2ab2015-08-27 04:40:05 +0200338 * freed by the ACPI core automatically during the removal of @data.
Mika Westerbergffdcd952014-10-21 13:33:55 +0200339 *
340 * Return: %0 if property with @name has been found (success),
341 * %-EINVAL if the arguments are invalid,
342 * %-ENODATA if the property doesn't exist,
343 * %-EPROTO if the property value type doesn't match @type.
344 */
Rafael J. Wysocki3a7a2ab2015-08-27 04:40:05 +0200345static int acpi_data_get_property(struct acpi_device_data *data,
346 const char *name, acpi_object_type type,
347 const union acpi_object **obj)
Mika Westerbergffdcd952014-10-21 13:33:55 +0200348{
349 const union acpi_object *properties;
350 int i;
351
Rafael J. Wysocki3a7a2ab2015-08-27 04:40:05 +0200352 if (!data || !name)
Mika Westerbergffdcd952014-10-21 13:33:55 +0200353 return -EINVAL;
354
Rafael J. Wysocki3a7a2ab2015-08-27 04:40:05 +0200355 if (!data->pointer || !data->properties)
Mika Westerbergffdcd952014-10-21 13:33:55 +0200356 return -ENODATA;
357
Rafael J. Wysocki3a7a2ab2015-08-27 04:40:05 +0200358 properties = data->properties;
Mika Westerbergffdcd952014-10-21 13:33:55 +0200359 for (i = 0; i < properties->package.count; i++) {
360 const union acpi_object *propname, *propvalue;
361 const union acpi_object *property;
362
363 property = &properties->package.elements[i];
364
365 propname = &property->package.elements[0];
366 propvalue = &property->package.elements[1];
367
368 if (!strcmp(name, propname->string.pointer)) {
369 if (type != ACPI_TYPE_ANY && propvalue->type != type)
370 return -EPROTO;
371 else if (obj)
372 *obj = propvalue;
373
374 return 0;
375 }
376 }
377 return -ENODATA;
378}
Mika Westerbergffdcd952014-10-21 13:33:55 +0200379
380/**
Rafael J. Wysocki3a7a2ab2015-08-27 04:40:05 +0200381 * acpi_dev_get_property - return an ACPI property with given name.
382 * @adev: ACPI device to get the property from.
383 * @name: Name of the property.
384 * @type: Expected property type.
385 * @obj: Location to store the property value (if not %NULL).
386 */
387int acpi_dev_get_property(struct acpi_device *adev, const char *name,
388 acpi_object_type type, const union acpi_object **obj)
389{
390 return adev ? acpi_data_get_property(&adev->data, name, type, obj) : -EINVAL;
391}
392EXPORT_SYMBOL_GPL(acpi_dev_get_property);
393
394static struct acpi_device_data *acpi_device_data_of_node(struct fwnode_handle *fwnode)
395{
396 if (fwnode->type == FWNODE_ACPI) {
397 struct acpi_device *adev = to_acpi_device_node(fwnode);
398 return &adev->data;
399 } else if (fwnode->type == FWNODE_ACPI_DATA) {
400 struct acpi_data_node *dn = to_acpi_data_node(fwnode);
401 return &dn->data;
402 }
403 return NULL;
404}
405
406/**
407 * acpi_node_prop_get - return an ACPI property with given name.
408 * @fwnode: Firmware node to get the property from.
409 * @propname: Name of the property.
410 * @valptr: Location to store a pointer to the property value (if not %NULL).
411 */
412int acpi_node_prop_get(struct fwnode_handle *fwnode, const char *propname,
413 void **valptr)
414{
415 return acpi_data_get_property(acpi_device_data_of_node(fwnode),
416 propname, ACPI_TYPE_ANY,
417 (const union acpi_object **)valptr);
418}
419
420/**
421 * acpi_data_get_property_array - return an ACPI array property with given name
422 * @adev: ACPI data object to get the property from
Mika Westerbergffdcd952014-10-21 13:33:55 +0200423 * @name: Name of the property
424 * @type: Expected type of array elements
425 * @obj: Location to store a pointer to the property value (if not NULL)
426 *
427 * Look up an array property with @name and store a pointer to the resulting
428 * ACPI object at the location pointed to by @obj if found.
429 *
430 * Callers must not attempt to free the returned objects. Those objects will be
Rafael J. Wysocki3a7a2ab2015-08-27 04:40:05 +0200431 * freed by the ACPI core automatically during the removal of @data.
Mika Westerbergffdcd952014-10-21 13:33:55 +0200432 *
433 * Return: %0 if array property (package) with @name has been found (success),
434 * %-EINVAL if the arguments are invalid,
435 * %-ENODATA if the property doesn't exist,
436 * %-EPROTO if the property is not a package or the type of its elements
437 * doesn't match @type.
438 */
Rafael J. Wysocki3a7a2ab2015-08-27 04:40:05 +0200439static int acpi_data_get_property_array(struct acpi_device_data *data,
440 const char *name,
441 acpi_object_type type,
442 const union acpi_object **obj)
Mika Westerbergffdcd952014-10-21 13:33:55 +0200443{
444 const union acpi_object *prop;
445 int ret, i;
446
Rafael J. Wysocki3a7a2ab2015-08-27 04:40:05 +0200447 ret = acpi_data_get_property(data, name, ACPI_TYPE_PACKAGE, &prop);
Mika Westerbergffdcd952014-10-21 13:33:55 +0200448 if (ret)
449 return ret;
450
451 if (type != ACPI_TYPE_ANY) {
452 /* Check that all elements are of correct type. */
453 for (i = 0; i < prop->package.count; i++)
454 if (prop->package.elements[i].type != type)
455 return -EPROTO;
456 }
457 if (obj)
458 *obj = prop;
459
460 return 0;
461}
Mika Westerbergffdcd952014-10-21 13:33:55 +0200462
463/**
464 * acpi_dev_get_property_reference - returns handle to the referenced object
465 * @adev: ACPI device to get property
466 * @name: Name of the property
Mika Westerbergffdcd952014-10-21 13:33:55 +0200467 * @index: Index of the reference to return
468 * @args: Location to store the returned reference with optional arguments
469 *
470 * Find property with @name, verifify that it is a package containing at least
471 * one object reference and if so, store the ACPI device object pointer to the
Rafael J. Wysocki60ba0322014-11-05 00:29:07 +0100472 * target object in @args->adev. If the reference includes arguments, store
473 * them in the @args->args[] array.
Mika Westerbergffdcd952014-10-21 13:33:55 +0200474 *
Rafael J. Wysocki60ba0322014-11-05 00:29:07 +0100475 * If there's more than one reference in the property value package, @index is
476 * used to select the one to return.
Mika Westerbergffdcd952014-10-21 13:33:55 +0200477 *
478 * Return: %0 on success, negative error code on failure.
479 */
Rafael J. Wysocki60ba0322014-11-05 00:29:07 +0100480int acpi_dev_get_property_reference(struct acpi_device *adev,
481 const char *name, size_t index,
Mika Westerbergffdcd952014-10-21 13:33:55 +0200482 struct acpi_reference_args *args)
483{
484 const union acpi_object *element, *end;
485 const union acpi_object *obj;
486 struct acpi_device *device;
487 int ret, idx = 0;
488
489 ret = acpi_dev_get_property(adev, name, ACPI_TYPE_ANY, &obj);
490 if (ret)
491 return ret;
492
493 /*
494 * The simplest case is when the value is a single reference. Just
495 * return that reference then.
496 */
497 if (obj->type == ACPI_TYPE_LOCAL_REFERENCE) {
Rafael J. Wysocki60ba0322014-11-05 00:29:07 +0100498 if (index)
Mika Westerbergffdcd952014-10-21 13:33:55 +0200499 return -EINVAL;
500
501 ret = acpi_bus_get_device(obj->reference.handle, &device);
502 if (ret)
503 return ret;
504
505 args->adev = device;
506 args->nargs = 0;
507 return 0;
508 }
509
510 /*
511 * If it is not a single reference, then it is a package of
512 * references followed by number of ints as follows:
513 *
514 * Package () { REF, INT, REF, INT, INT }
515 *
516 * The index argument is then used to determine which reference
517 * the caller wants (along with the arguments).
518 */
519 if (obj->type != ACPI_TYPE_PACKAGE || index >= obj->package.count)
520 return -EPROTO;
521
522 element = obj->package.elements;
523 end = element + obj->package.count;
524
525 while (element < end) {
526 u32 nargs, i;
527
528 if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
529 return -EPROTO;
530
531 ret = acpi_bus_get_device(element->reference.handle, &device);
532 if (ret)
533 return -ENODEV;
534
535 element++;
536 nargs = 0;
537
Rafael J. Wysocki60ba0322014-11-05 00:29:07 +0100538 /* assume following integer elements are all args */
539 for (i = 0; element + i < end; i++) {
540 int type = element[i].type;
Mika Westerbergffdcd952014-10-21 13:33:55 +0200541
Rafael J. Wysocki60ba0322014-11-05 00:29:07 +0100542 if (type == ACPI_TYPE_INTEGER)
543 nargs++;
544 else if (type == ACPI_TYPE_LOCAL_REFERENCE)
545 break;
546 else
Mika Westerbergffdcd952014-10-21 13:33:55 +0200547 return -EPROTO;
Mika Westerbergffdcd952014-10-21 13:33:55 +0200548 }
549
550 if (idx++ == index) {
551 args->adev = device;
552 args->nargs = nargs;
553 for (i = 0; i < nargs; i++)
554 args->args[i] = element[i].integer.value;
555
556 return 0;
557 }
558
559 element += nargs;
560 }
561
562 return -EPROTO;
563}
564EXPORT_SYMBOL_GPL(acpi_dev_get_property_reference);
Rafael J. Wysockib31384f2014-11-04 01:28:56 +0100565
Rafael J. Wysocki3a7a2ab2015-08-27 04:40:05 +0200566static int acpi_data_prop_read_single(struct acpi_device_data *data,
567 const char *propname,
568 enum dev_prop_type proptype, void *val)
Rafael J. Wysockib31384f2014-11-04 01:28:56 +0100569{
570 const union acpi_object *obj;
571 int ret;
572
573 if (!val)
574 return -EINVAL;
575
576 if (proptype >= DEV_PROP_U8 && proptype <= DEV_PROP_U64) {
Rafael J. Wysocki3a7a2ab2015-08-27 04:40:05 +0200577 ret = acpi_data_get_property(data, propname, ACPI_TYPE_INTEGER, &obj);
Rafael J. Wysockib31384f2014-11-04 01:28:56 +0100578 if (ret)
579 return ret;
580
581 switch (proptype) {
582 case DEV_PROP_U8:
583 if (obj->integer.value > U8_MAX)
584 return -EOVERFLOW;
585 *(u8 *)val = obj->integer.value;
586 break;
587 case DEV_PROP_U16:
588 if (obj->integer.value > U16_MAX)
589 return -EOVERFLOW;
590 *(u16 *)val = obj->integer.value;
591 break;
592 case DEV_PROP_U32:
593 if (obj->integer.value > U32_MAX)
594 return -EOVERFLOW;
595 *(u32 *)val = obj->integer.value;
596 break;
597 default:
598 *(u64 *)val = obj->integer.value;
599 break;
600 }
601 } else if (proptype == DEV_PROP_STRING) {
Rafael J. Wysocki3a7a2ab2015-08-27 04:40:05 +0200602 ret = acpi_data_get_property(data, propname, ACPI_TYPE_STRING, &obj);
Rafael J. Wysockib31384f2014-11-04 01:28:56 +0100603 if (ret)
604 return ret;
605
606 *(char **)val = obj->string.pointer;
607 } else {
608 ret = -EINVAL;
609 }
610 return ret;
611}
612
Rafael J. Wysocki3a7a2ab2015-08-27 04:40:05 +0200613int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname,
614 enum dev_prop_type proptype, void *val)
615{
616 return adev ? acpi_data_prop_read_single(&adev->data, propname, proptype, val) : -EINVAL;
617}
618
Rafael J. Wysockib31384f2014-11-04 01:28:56 +0100619static int acpi_copy_property_array_u8(const union acpi_object *items, u8 *val,
620 size_t nval)
621{
622 int i;
623
624 for (i = 0; i < nval; i++) {
625 if (items[i].type != ACPI_TYPE_INTEGER)
626 return -EPROTO;
627 if (items[i].integer.value > U8_MAX)
628 return -EOVERFLOW;
629
630 val[i] = items[i].integer.value;
631 }
632 return 0;
633}
634
635static int acpi_copy_property_array_u16(const union acpi_object *items,
636 u16 *val, size_t nval)
637{
638 int i;
639
640 for (i = 0; i < nval; i++) {
641 if (items[i].type != ACPI_TYPE_INTEGER)
642 return -EPROTO;
643 if (items[i].integer.value > U16_MAX)
644 return -EOVERFLOW;
645
646 val[i] = items[i].integer.value;
647 }
648 return 0;
649}
650
651static int acpi_copy_property_array_u32(const union acpi_object *items,
652 u32 *val, size_t nval)
653{
654 int i;
655
656 for (i = 0; i < nval; i++) {
657 if (items[i].type != ACPI_TYPE_INTEGER)
658 return -EPROTO;
659 if (items[i].integer.value > U32_MAX)
660 return -EOVERFLOW;
661
662 val[i] = items[i].integer.value;
663 }
664 return 0;
665}
666
667static int acpi_copy_property_array_u64(const union acpi_object *items,
668 u64 *val, size_t nval)
669{
670 int i;
671
672 for (i = 0; i < nval; i++) {
673 if (items[i].type != ACPI_TYPE_INTEGER)
674 return -EPROTO;
675
676 val[i] = items[i].integer.value;
677 }
678 return 0;
679}
680
681static int acpi_copy_property_array_string(const union acpi_object *items,
682 char **val, size_t nval)
683{
684 int i;
685
686 for (i = 0; i < nval; i++) {
687 if (items[i].type != ACPI_TYPE_STRING)
688 return -EPROTO;
689
690 val[i] = items[i].string.pointer;
691 }
692 return 0;
693}
694
Rafael J. Wysocki3a7a2ab2015-08-27 04:40:05 +0200695static int acpi_data_prop_read(struct acpi_device_data *data,
696 const char *propname,
697 enum dev_prop_type proptype,
698 void *val, size_t nval)
Rafael J. Wysockib31384f2014-11-04 01:28:56 +0100699{
700 const union acpi_object *obj;
701 const union acpi_object *items;
702 int ret;
703
704 if (val && nval == 1) {
Rafael J. Wysocki3a7a2ab2015-08-27 04:40:05 +0200705 ret = acpi_data_prop_read_single(data, propname, proptype, val);
Rafael J. Wysockib31384f2014-11-04 01:28:56 +0100706 if (!ret)
707 return ret;
708 }
709
Rafael J. Wysocki3a7a2ab2015-08-27 04:40:05 +0200710 ret = acpi_data_get_property_array(data, propname, ACPI_TYPE_ANY, &obj);
Rafael J. Wysockib31384f2014-11-04 01:28:56 +0100711 if (ret)
712 return ret;
713
714 if (!val)
715 return obj->package.count;
Rafael J. Wysockib31384f2014-11-04 01:28:56 +0100716
717 if (nval > obj->package.count)
718 return -EOVERFLOW;
Andy Shevchenko7dc59dc2015-08-10 19:56:48 +0300719 else if (nval <= 0)
720 return -EINVAL;
Rafael J. Wysockib31384f2014-11-04 01:28:56 +0100721
722 items = obj->package.elements;
Andy Shevchenko7dc59dc2015-08-10 19:56:48 +0300723
Rafael J. Wysockib31384f2014-11-04 01:28:56 +0100724 switch (proptype) {
725 case DEV_PROP_U8:
726 ret = acpi_copy_property_array_u8(items, (u8 *)val, nval);
727 break;
728 case DEV_PROP_U16:
729 ret = acpi_copy_property_array_u16(items, (u16 *)val, nval);
730 break;
731 case DEV_PROP_U32:
732 ret = acpi_copy_property_array_u32(items, (u32 *)val, nval);
733 break;
734 case DEV_PROP_U64:
735 ret = acpi_copy_property_array_u64(items, (u64 *)val, nval);
736 break;
737 case DEV_PROP_STRING:
738 ret = acpi_copy_property_array_string(items, (char **)val, nval);
739 break;
740 default:
741 ret = -EINVAL;
742 break;
743 }
744 return ret;
745}
Rafael J. Wysocki3a7a2ab2015-08-27 04:40:05 +0200746
747int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
748 enum dev_prop_type proptype, void *val, size_t nval)
749{
750 return adev ? acpi_data_prop_read(&adev->data, propname, proptype, val, nval) : -EINVAL;
751}
752
753/**
754 * acpi_node_prop_read - retrieve the value of an ACPI property with given name.
755 * @fwnode: Firmware node to get the property from.
756 * @propname: Name of the property.
757 * @proptype: Expected property type.
758 * @val: Location to store the property value (if not %NULL).
759 * @nval: Size of the array pointed to by @val.
760 *
761 * If @val is %NULL, return the number of array elements comprising the value
762 * of the property. Otherwise, read at most @nval values to the array at the
763 * location pointed to by @val.
764 */
765int acpi_node_prop_read(struct fwnode_handle *fwnode, const char *propname,
766 enum dev_prop_type proptype, void *val, size_t nval)
767{
768 return acpi_data_prop_read(acpi_device_data_of_node(fwnode),
769 propname, proptype, val, nval);
770}