blob: 17c436de376b7c80f2648be33535dbaf52193c47 [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
22/* ACPI _DSD device properties UUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */
23static const u8 prp_uuid[16] = {
24 0x14, 0xd8, 0xff, 0xda, 0xba, 0x6e, 0x8c, 0x4d,
25 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01
26};
Rafael J. Wysocki445b0eb2015-08-27 04:36:14 +020027/* ACPI _DSD data subnodes UUID: dbb8e3e6-5886-4ba6-8795-1319f52a966b */
28static const u8 ads_uuid[16] = {
29 0xe6, 0xe3, 0xb8, 0xdb, 0x86, 0x58, 0xa6, 0x4b,
30 0x87, 0x95, 0x13, 0x19, 0xf5, 0x2a, 0x96, 0x6b
31};
32
33static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
34 const union acpi_object *desc,
35 struct acpi_device_data *data);
36static bool acpi_extract_properties(const union acpi_object *desc,
37 struct acpi_device_data *data);
38
39static bool acpi_nondev_subnode_ok(acpi_handle scope,
40 const union acpi_object *link,
41 struct list_head *list)
42{
43 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
44 struct acpi_data_node *dn;
45 acpi_handle handle;
46 acpi_status status;
47
48 dn = kzalloc(sizeof(*dn), GFP_KERNEL);
49 if (!dn)
50 return false;
51
52 dn->name = link->package.elements[0].string.pointer;
53 dn->fwnode.type = FWNODE_ACPI_DATA;
54 INIT_LIST_HEAD(&dn->data.subnodes);
55
56 status = acpi_get_handle(scope, link->package.elements[1].string.pointer,
57 &handle);
58 if (ACPI_FAILURE(status))
59 goto fail;
60
61 status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf,
62 ACPI_TYPE_PACKAGE);
63 if (ACPI_FAILURE(status))
64 goto fail;
65
66 if (acpi_extract_properties(buf.pointer, &dn->data))
67 dn->data.pointer = buf.pointer;
68
69 if (acpi_enumerate_nondev_subnodes(scope, buf.pointer, &dn->data))
70 dn->data.pointer = buf.pointer;
71
72 if (dn->data.pointer) {
73 list_add_tail(&dn->sibling, list);
74 return true;
75 }
76
77 acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping\n");
78
79 fail:
80 ACPI_FREE(buf.pointer);
81 kfree(dn);
82 return false;
83}
84
85static int acpi_add_nondev_subnodes(acpi_handle scope,
86 const union acpi_object *links,
87 struct list_head *list)
88{
89 bool ret = false;
90 int i;
91
92 for (i = 0; i < links->package.count; i++) {
93 const union acpi_object *link;
94
95 link = &links->package.elements[i];
96 /* Only two elements allowed, both must be strings. */
97 if (link->package.count == 2
98 && link->package.elements[0].type == ACPI_TYPE_STRING
99 && link->package.elements[1].type == ACPI_TYPE_STRING
100 && acpi_nondev_subnode_ok(scope, link, list))
101 ret = true;
102 }
103
104 return ret;
105}
106
107static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
108 const union acpi_object *desc,
109 struct acpi_device_data *data)
110{
111 int i;
112
113 /* Look for the ACPI data subnodes UUID. */
114 for (i = 0; i < desc->package.count; i += 2) {
115 const union acpi_object *uuid, *links;
116
117 uuid = &desc->package.elements[i];
118 links = &desc->package.elements[i + 1];
119
120 /*
121 * The first element must be a UUID and the second one must be
122 * a package.
123 */
124 if (uuid->type != ACPI_TYPE_BUFFER || uuid->buffer.length != 16
125 || links->type != ACPI_TYPE_PACKAGE)
126 break;
127
128 if (memcmp(uuid->buffer.pointer, ads_uuid, sizeof(ads_uuid)))
129 continue;
130
131 return acpi_add_nondev_subnodes(scope, links, &data->subnodes);
132 }
133
134 return false;
135}
Mika Westerbergffdcd952014-10-21 13:33:55 +0200136
137static bool acpi_property_value_ok(const union acpi_object *value)
138{
139 int j;
140
141 /*
142 * The value must be an integer, a string, a reference, or a package
143 * whose every element must be an integer, a string, or a reference.
144 */
145 switch (value->type) {
146 case ACPI_TYPE_INTEGER:
147 case ACPI_TYPE_STRING:
148 case ACPI_TYPE_LOCAL_REFERENCE:
149 return true;
150
151 case ACPI_TYPE_PACKAGE:
152 for (j = 0; j < value->package.count; j++)
153 switch (value->package.elements[j].type) {
154 case ACPI_TYPE_INTEGER:
155 case ACPI_TYPE_STRING:
156 case ACPI_TYPE_LOCAL_REFERENCE:
157 continue;
158
159 default:
160 return false;
161 }
162
163 return true;
164 }
165 return false;
166}
167
168static bool acpi_properties_format_valid(const union acpi_object *properties)
169{
170 int i;
171
172 for (i = 0; i < properties->package.count; i++) {
173 const union acpi_object *property;
174
175 property = &properties->package.elements[i];
176 /*
177 * Only two elements allowed, the first one must be a string and
178 * the second one has to satisfy certain conditions.
179 */
180 if (property->package.count != 2
181 || property->package.elements[0].type != ACPI_TYPE_STRING
182 || !acpi_property_value_ok(&property->package.elements[1]))
183 return false;
184 }
185 return true;
186}
187
Mika Westerberg733e6252014-10-21 13:33:56 +0200188static void acpi_init_of_compatible(struct acpi_device *adev)
189{
190 const union acpi_object *of_compatible;
Mika Westerberg733e6252014-10-21 13:33:56 +0200191 int ret;
192
Rafael J. Wysocki5c53b262015-05-05 15:43:07 +0200193 ret = acpi_dev_get_property_array(adev, "compatible", ACPI_TYPE_STRING,
194 &of_compatible);
195 if (ret) {
196 ret = acpi_dev_get_property(adev, "compatible",
197 ACPI_TYPE_STRING, &of_compatible);
198 if (ret) {
199 if (adev->parent
200 && adev->parent->flags.of_compatible_ok)
201 goto out;
202
203 return;
204 }
205 }
206 adev->data.of_compatible = of_compatible;
207
208 out:
209 adev->flags.of_compatible_ok = 1;
210}
211
Rafael J. Wysockibd8191c2015-08-27 04:35:14 +0200212static bool acpi_extract_properties(const union acpi_object *desc,
213 struct acpi_device_data *data)
Rafael J. Wysocki5c53b262015-05-05 15:43:07 +0200214{
Rafael J. Wysocki5c53b262015-05-05 15:43:07 +0200215 int i;
216
Mika Westerbergffdcd952014-10-21 13:33:55 +0200217 if (desc->package.count % 2)
Rafael J. Wysockibd8191c2015-08-27 04:35:14 +0200218 return false;
Mika Westerbergffdcd952014-10-21 13:33:55 +0200219
220 /* Look for the device properties UUID. */
221 for (i = 0; i < desc->package.count; i += 2) {
222 const union acpi_object *uuid, *properties;
223
224 uuid = &desc->package.elements[i];
225 properties = &desc->package.elements[i + 1];
226
227 /*
228 * The first element must be a UUID and the second one must be
229 * a package.
230 */
231 if (uuid->type != ACPI_TYPE_BUFFER || uuid->buffer.length != 16
232 || properties->type != ACPI_TYPE_PACKAGE)
233 break;
234
235 if (memcmp(uuid->buffer.pointer, prp_uuid, sizeof(prp_uuid)))
236 continue;
237
238 /*
239 * We found the matching UUID. Now validate the format of the
240 * package immediately following it.
241 */
242 if (!acpi_properties_format_valid(properties))
243 break;
244
Rafael J. Wysockibd8191c2015-08-27 04:35:14 +0200245 data->properties = properties;
246 return true;
Mika Westerbergffdcd952014-10-21 13:33:55 +0200247 }
248
Rafael J. Wysockibd8191c2015-08-27 04:35:14 +0200249 return false;
250}
251
252void acpi_init_properties(struct acpi_device *adev)
253{
254 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
255 struct acpi_hardware_id *hwid;
256 acpi_status status;
257 bool acpi_of = false;
258
Rafael J. Wysocki445b0eb2015-08-27 04:36:14 +0200259 INIT_LIST_HEAD(&adev->data.subnodes);
260
Rafael J. Wysockibd8191c2015-08-27 04:35:14 +0200261 /*
262 * Check if ACPI_DT_NAMESPACE_HID is present and inthat case we fill in
263 * Device Tree compatible properties for this device.
264 */
265 list_for_each_entry(hwid, &adev->pnp.ids, list) {
266 if (!strcmp(hwid->id, ACPI_DT_NAMESPACE_HID)) {
267 acpi_of = true;
268 break;
269 }
270 }
271
272 status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL, &buf,
273 ACPI_TYPE_PACKAGE);
274 if (ACPI_FAILURE(status))
275 goto out;
276
277 if (acpi_extract_properties(buf.pointer, &adev->data)) {
278 adev->data.pointer = buf.pointer;
279 if (acpi_of)
280 acpi_init_of_compatible(adev);
Rafael J. Wysocki445b0eb2015-08-27 04:36:14 +0200281 }
282 if (acpi_enumerate_nondev_subnodes(adev->handle, buf.pointer, &adev->data))
283 adev->data.pointer = buf.pointer;
284
285 if (!adev->data.pointer) {
Rafael J. Wysockibd8191c2015-08-27 04:35:14 +0200286 acpi_handle_debug(adev->handle, "Invalid _DSD data, skipping\n");
287 ACPI_FREE(buf.pointer);
288 }
Rafael J. Wysocki5c53b262015-05-05 15:43:07 +0200289
290 out:
291 if (acpi_of && !adev->flags.of_compatible_ok)
292 acpi_handle_info(adev->handle,
Rafael J. Wysockiee892092015-05-22 04:24:34 +0200293 ACPI_DT_NAMESPACE_HID " requires 'compatible' property\n");
Mika Westerbergffdcd952014-10-21 13:33:55 +0200294}
295
Rafael J. Wysocki445b0eb2015-08-27 04:36:14 +0200296static void acpi_destroy_nondev_subnodes(struct list_head *list)
297{
298 struct acpi_data_node *dn, *next;
299
300 if (list_empty(list))
301 return;
302
303 list_for_each_entry_safe_reverse(dn, next, list, sibling) {
304 acpi_destroy_nondev_subnodes(&dn->data.subnodes);
305 list_del(&dn->sibling);
306 ACPI_FREE((void *)dn->data.pointer);
307 kfree(dn);
308 }
309}
310
Mika Westerbergffdcd952014-10-21 13:33:55 +0200311void acpi_free_properties(struct acpi_device *adev)
312{
Rafael J. Wysocki445b0eb2015-08-27 04:36:14 +0200313 acpi_destroy_nondev_subnodes(&adev->data.subnodes);
Mika Westerbergffdcd952014-10-21 13:33:55 +0200314 ACPI_FREE((void *)adev->data.pointer);
Mika Westerberg733e6252014-10-21 13:33:56 +0200315 adev->data.of_compatible = NULL;
Mika Westerbergffdcd952014-10-21 13:33:55 +0200316 adev->data.pointer = NULL;
317 adev->data.properties = NULL;
318}
319
320/**
321 * acpi_dev_get_property - return an ACPI property with given name
322 * @adev: ACPI device to get property
323 * @name: Name of the property
324 * @type: Expected property type
325 * @obj: Location to store the property value (if not %NULL)
326 *
327 * Look up a property with @name and store a pointer to the resulting ACPI
328 * object at the location pointed to by @obj if found.
329 *
330 * Callers must not attempt to free the returned objects. These objects will be
331 * freed by the ACPI core automatically during the removal of @adev.
332 *
333 * Return: %0 if property with @name has been found (success),
334 * %-EINVAL if the arguments are invalid,
335 * %-ENODATA if the property doesn't exist,
336 * %-EPROTO if the property value type doesn't match @type.
337 */
338int acpi_dev_get_property(struct acpi_device *adev, const char *name,
339 acpi_object_type type, const union acpi_object **obj)
340{
341 const union acpi_object *properties;
342 int i;
343
344 if (!adev || !name)
345 return -EINVAL;
346
347 if (!adev->data.pointer || !adev->data.properties)
348 return -ENODATA;
349
350 properties = adev->data.properties;
351 for (i = 0; i < properties->package.count; i++) {
352 const union acpi_object *propname, *propvalue;
353 const union acpi_object *property;
354
355 property = &properties->package.elements[i];
356
357 propname = &property->package.elements[0];
358 propvalue = &property->package.elements[1];
359
360 if (!strcmp(name, propname->string.pointer)) {
361 if (type != ACPI_TYPE_ANY && propvalue->type != type)
362 return -EPROTO;
363 else if (obj)
364 *obj = propvalue;
365
366 return 0;
367 }
368 }
369 return -ENODATA;
370}
371EXPORT_SYMBOL_GPL(acpi_dev_get_property);
372
373/**
374 * acpi_dev_get_property_array - return an ACPI array property with given name
375 * @adev: ACPI device to get property
376 * @name: Name of the property
377 * @type: Expected type of array elements
378 * @obj: Location to store a pointer to the property value (if not NULL)
379 *
380 * Look up an array property with @name and store a pointer to the resulting
381 * ACPI object at the location pointed to by @obj if found.
382 *
383 * Callers must not attempt to free the returned objects. Those objects will be
384 * freed by the ACPI core automatically during the removal of @adev.
385 *
386 * Return: %0 if array property (package) with @name has been found (success),
387 * %-EINVAL if the arguments are invalid,
388 * %-ENODATA if the property doesn't exist,
389 * %-EPROTO if the property is not a package or the type of its elements
390 * doesn't match @type.
391 */
392int acpi_dev_get_property_array(struct acpi_device *adev, const char *name,
393 acpi_object_type type,
394 const union acpi_object **obj)
395{
396 const union acpi_object *prop;
397 int ret, i;
398
399 ret = acpi_dev_get_property(adev, name, ACPI_TYPE_PACKAGE, &prop);
400 if (ret)
401 return ret;
402
403 if (type != ACPI_TYPE_ANY) {
404 /* Check that all elements are of correct type. */
405 for (i = 0; i < prop->package.count; i++)
406 if (prop->package.elements[i].type != type)
407 return -EPROTO;
408 }
409 if (obj)
410 *obj = prop;
411
412 return 0;
413}
414EXPORT_SYMBOL_GPL(acpi_dev_get_property_array);
415
416/**
417 * acpi_dev_get_property_reference - returns handle to the referenced object
418 * @adev: ACPI device to get property
419 * @name: Name of the property
Mika Westerbergffdcd952014-10-21 13:33:55 +0200420 * @index: Index of the reference to return
421 * @args: Location to store the returned reference with optional arguments
422 *
423 * Find property with @name, verifify that it is a package containing at least
424 * one object reference and if so, store the ACPI device object pointer to the
Rafael J. Wysocki60ba0322014-11-05 00:29:07 +0100425 * target object in @args->adev. If the reference includes arguments, store
426 * them in the @args->args[] array.
Mika Westerbergffdcd952014-10-21 13:33:55 +0200427 *
Rafael J. Wysocki60ba0322014-11-05 00:29:07 +0100428 * If there's more than one reference in the property value package, @index is
429 * used to select the one to return.
Mika Westerbergffdcd952014-10-21 13:33:55 +0200430 *
431 * Return: %0 on success, negative error code on failure.
432 */
Rafael J. Wysocki60ba0322014-11-05 00:29:07 +0100433int acpi_dev_get_property_reference(struct acpi_device *adev,
434 const char *name, size_t index,
Mika Westerbergffdcd952014-10-21 13:33:55 +0200435 struct acpi_reference_args *args)
436{
437 const union acpi_object *element, *end;
438 const union acpi_object *obj;
439 struct acpi_device *device;
440 int ret, idx = 0;
441
442 ret = acpi_dev_get_property(adev, name, ACPI_TYPE_ANY, &obj);
443 if (ret)
444 return ret;
445
446 /*
447 * The simplest case is when the value is a single reference. Just
448 * return that reference then.
449 */
450 if (obj->type == ACPI_TYPE_LOCAL_REFERENCE) {
Rafael J. Wysocki60ba0322014-11-05 00:29:07 +0100451 if (index)
Mika Westerbergffdcd952014-10-21 13:33:55 +0200452 return -EINVAL;
453
454 ret = acpi_bus_get_device(obj->reference.handle, &device);
455 if (ret)
456 return ret;
457
458 args->adev = device;
459 args->nargs = 0;
460 return 0;
461 }
462
463 /*
464 * If it is not a single reference, then it is a package of
465 * references followed by number of ints as follows:
466 *
467 * Package () { REF, INT, REF, INT, INT }
468 *
469 * The index argument is then used to determine which reference
470 * the caller wants (along with the arguments).
471 */
472 if (obj->type != ACPI_TYPE_PACKAGE || index >= obj->package.count)
473 return -EPROTO;
474
475 element = obj->package.elements;
476 end = element + obj->package.count;
477
478 while (element < end) {
479 u32 nargs, i;
480
481 if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
482 return -EPROTO;
483
484 ret = acpi_bus_get_device(element->reference.handle, &device);
485 if (ret)
486 return -ENODEV;
487
488 element++;
489 nargs = 0;
490
Rafael J. Wysocki60ba0322014-11-05 00:29:07 +0100491 /* assume following integer elements are all args */
492 for (i = 0; element + i < end; i++) {
493 int type = element[i].type;
Mika Westerbergffdcd952014-10-21 13:33:55 +0200494
Rafael J. Wysocki60ba0322014-11-05 00:29:07 +0100495 if (type == ACPI_TYPE_INTEGER)
496 nargs++;
497 else if (type == ACPI_TYPE_LOCAL_REFERENCE)
498 break;
499 else
Mika Westerbergffdcd952014-10-21 13:33:55 +0200500 return -EPROTO;
Mika Westerbergffdcd952014-10-21 13:33:55 +0200501 }
502
503 if (idx++ == index) {
504 args->adev = device;
505 args->nargs = nargs;
506 for (i = 0; i < nargs; i++)
507 args->args[i] = element[i].integer.value;
508
509 return 0;
510 }
511
512 element += nargs;
513 }
514
515 return -EPROTO;
516}
517EXPORT_SYMBOL_GPL(acpi_dev_get_property_reference);
Rafael J. Wysockib31384f2014-11-04 01:28:56 +0100518
519int acpi_dev_prop_get(struct acpi_device *adev, const char *propname,
520 void **valptr)
521{
522 return acpi_dev_get_property(adev, propname, ACPI_TYPE_ANY,
523 (const union acpi_object **)valptr);
524}
525
526int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname,
527 enum dev_prop_type proptype, void *val)
528{
529 const union acpi_object *obj;
530 int ret;
531
532 if (!val)
533 return -EINVAL;
534
535 if (proptype >= DEV_PROP_U8 && proptype <= DEV_PROP_U64) {
536 ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_INTEGER, &obj);
537 if (ret)
538 return ret;
539
540 switch (proptype) {
541 case DEV_PROP_U8:
542 if (obj->integer.value > U8_MAX)
543 return -EOVERFLOW;
544 *(u8 *)val = obj->integer.value;
545 break;
546 case DEV_PROP_U16:
547 if (obj->integer.value > U16_MAX)
548 return -EOVERFLOW;
549 *(u16 *)val = obj->integer.value;
550 break;
551 case DEV_PROP_U32:
552 if (obj->integer.value > U32_MAX)
553 return -EOVERFLOW;
554 *(u32 *)val = obj->integer.value;
555 break;
556 default:
557 *(u64 *)val = obj->integer.value;
558 break;
559 }
560 } else if (proptype == DEV_PROP_STRING) {
561 ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_STRING, &obj);
562 if (ret)
563 return ret;
564
565 *(char **)val = obj->string.pointer;
566 } else {
567 ret = -EINVAL;
568 }
569 return ret;
570}
571
572static int acpi_copy_property_array_u8(const union acpi_object *items, u8 *val,
573 size_t nval)
574{
575 int i;
576
577 for (i = 0; i < nval; i++) {
578 if (items[i].type != ACPI_TYPE_INTEGER)
579 return -EPROTO;
580 if (items[i].integer.value > U8_MAX)
581 return -EOVERFLOW;
582
583 val[i] = items[i].integer.value;
584 }
585 return 0;
586}
587
588static int acpi_copy_property_array_u16(const union acpi_object *items,
589 u16 *val, size_t nval)
590{
591 int i;
592
593 for (i = 0; i < nval; i++) {
594 if (items[i].type != ACPI_TYPE_INTEGER)
595 return -EPROTO;
596 if (items[i].integer.value > U16_MAX)
597 return -EOVERFLOW;
598
599 val[i] = items[i].integer.value;
600 }
601 return 0;
602}
603
604static int acpi_copy_property_array_u32(const union acpi_object *items,
605 u32 *val, size_t nval)
606{
607 int i;
608
609 for (i = 0; i < nval; i++) {
610 if (items[i].type != ACPI_TYPE_INTEGER)
611 return -EPROTO;
612 if (items[i].integer.value > U32_MAX)
613 return -EOVERFLOW;
614
615 val[i] = items[i].integer.value;
616 }
617 return 0;
618}
619
620static int acpi_copy_property_array_u64(const union acpi_object *items,
621 u64 *val, size_t nval)
622{
623 int i;
624
625 for (i = 0; i < nval; i++) {
626 if (items[i].type != ACPI_TYPE_INTEGER)
627 return -EPROTO;
628
629 val[i] = items[i].integer.value;
630 }
631 return 0;
632}
633
634static int acpi_copy_property_array_string(const union acpi_object *items,
635 char **val, size_t nval)
636{
637 int i;
638
639 for (i = 0; i < nval; i++) {
640 if (items[i].type != ACPI_TYPE_STRING)
641 return -EPROTO;
642
643 val[i] = items[i].string.pointer;
644 }
645 return 0;
646}
647
648int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
649 enum dev_prop_type proptype, void *val, size_t nval)
650{
651 const union acpi_object *obj;
652 const union acpi_object *items;
653 int ret;
654
655 if (val && nval == 1) {
656 ret = acpi_dev_prop_read_single(adev, propname, proptype, val);
657 if (!ret)
658 return ret;
659 }
660
661 ret = acpi_dev_get_property_array(adev, propname, ACPI_TYPE_ANY, &obj);
662 if (ret)
663 return ret;
664
665 if (!val)
666 return obj->package.count;
Rafael J. Wysockib31384f2014-11-04 01:28:56 +0100667
668 if (nval > obj->package.count)
669 return -EOVERFLOW;
Andy Shevchenko7dc59dc2015-08-10 19:56:48 +0300670 else if (nval <= 0)
671 return -EINVAL;
Rafael J. Wysockib31384f2014-11-04 01:28:56 +0100672
673 items = obj->package.elements;
Andy Shevchenko7dc59dc2015-08-10 19:56:48 +0300674
Rafael J. Wysockib31384f2014-11-04 01:28:56 +0100675 switch (proptype) {
676 case DEV_PROP_U8:
677 ret = acpi_copy_property_array_u8(items, (u8 *)val, nval);
678 break;
679 case DEV_PROP_U16:
680 ret = acpi_copy_property_array_u16(items, (u16 *)val, nval);
681 break;
682 case DEV_PROP_U32:
683 ret = acpi_copy_property_array_u32(items, (u32 *)val, nval);
684 break;
685 case DEV_PROP_U64:
686 ret = acpi_copy_property_array_u64(items, (u64 *)val, nval);
687 break;
688 case DEV_PROP_STRING:
689 ret = acpi_copy_property_array_string(items, (char **)val, nval);
690 break;
691 default:
692 ret = -EINVAL;
693 break;
694 }
695 return ret;
696}