]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/acpi/property.c
iommu/amd: Add support for higher 64-bit IOMMU Control Register
[mirror_ubuntu-bionic-kernel.git] / drivers / acpi / property.c
CommitLineData
ffdcd955
MW
1/*
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
99a85464 22static int acpi_data_get_property_array(const struct acpi_device_data *data,
3a7a2ab8
RW
23 const char *name,
24 acpi_object_type type,
25 const union acpi_object **obj);
26
4fcbcb08
MW
27/*
28 * The GUIDs here are made equivalent to each other in order to avoid extra
29 * complexity in the properties handling code, with the caveat that the
30 * kernel will accept certain combinations of GUID and properties that are
31 * not defined without a warning. For instance if any of the properties
32 * from different GUID appear in a property list of another, it will be
33 * accepted by the kernel. Firmware validation tools should catch these.
34 */
997d2b15
MW
35static const guid_t prp_guids[] = {
36 /* ACPI _DSD device properties GUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */
3689d3d6 37 GUID_INIT(0xdaffd814, 0x6eba, 0x4d8c,
997d2b15 38 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01),
4fcbcb08
MW
39 /* External facing port GUID: efcc06cc-73ac-4bc3-bff0-76143807c389 */
40 GUID_INIT(0xefcc06cc, 0x73ac, 0x4bc3,
41 0xbf, 0xf0, 0x76, 0x14, 0x38, 0x07, 0xc3, 0x89),
997d2b15
MW
42};
43
3689d3d6
AS
44static const guid_t ads_guid =
45 GUID_INIT(0xdbb8e3e6, 0x5886, 0x4ba6,
46 0x87, 0x95, 0x13, 0x19, 0xf5, 0x2a, 0x96, 0x6b);
445b0eb0
RW
47
48static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
49 const union acpi_object *desc,
dfa672fb
MW
50 struct acpi_device_data *data,
51 struct fwnode_handle *parent);
445b0eb0
RW
52static bool acpi_extract_properties(const union acpi_object *desc,
53 struct acpi_device_data *data);
54
99db5ff7
RW
55static bool acpi_nondev_subnode_extract(const union acpi_object *desc,
56 acpi_handle handle,
57 const union acpi_object *link,
dfa672fb
MW
58 struct list_head *list,
59 struct fwnode_handle *parent)
445b0eb0 60{
445b0eb0 61 struct acpi_data_node *dn;
99db5ff7 62 bool result;
445b0eb0
RW
63
64 dn = kzalloc(sizeof(*dn), GFP_KERNEL);
65 if (!dn)
66 return false;
67
68 dn->name = link->package.elements[0].string.pointer;
db3e50f3 69 dn->fwnode.ops = &acpi_data_fwnode_ops;
dfa672fb 70 dn->parent = parent;
997d2b15 71 INIT_LIST_HEAD(&dn->data.properties);
445b0eb0
RW
72 INIT_LIST_HEAD(&dn->data.subnodes);
73
99db5ff7 74 result = acpi_extract_properties(desc, &dn->data);
445b0eb0 75
99db5ff7
RW
76 if (handle) {
77 acpi_handle scope;
78 acpi_status status;
445b0eb0 79
99db5ff7
RW
80 /*
81 * The scope for the subnode object lookup is the one of the
82 * namespace node (device) containing the object that has
83 * returned the package. That is, it's the scope of that
84 * object's parent.
85 */
86 status = acpi_get_parent(handle, &scope);
87 if (ACPI_SUCCESS(status)
dfa672fb
MW
88 && acpi_enumerate_nondev_subnodes(scope, desc, &dn->data,
89 &dn->fwnode))
99db5ff7 90 result = true;
dfa672fb
MW
91 } else if (acpi_enumerate_nondev_subnodes(NULL, desc, &dn->data,
92 &dn->fwnode)) {
99db5ff7
RW
93 result = true;
94 }
445b0eb0 95
99db5ff7 96 if (result) {
263b4c1a 97 dn->handle = handle;
99db5ff7 98 dn->data.pointer = desc;
445b0eb0
RW
99 list_add_tail(&dn->sibling, list);
100 return true;
101 }
102
99db5ff7 103 kfree(dn);
445b0eb0 104 acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping\n");
99db5ff7
RW
105 return false;
106}
107
108static bool acpi_nondev_subnode_data_ok(acpi_handle handle,
109 const union acpi_object *link,
dfa672fb
MW
110 struct list_head *list,
111 struct fwnode_handle *parent)
99db5ff7
RW
112{
113 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
114 acpi_status status;
115
116 status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf,
117 ACPI_TYPE_PACKAGE);
118 if (ACPI_FAILURE(status))
119 return false;
120
dfa672fb
MW
121 if (acpi_nondev_subnode_extract(buf.pointer, handle, link, list,
122 parent))
99db5ff7 123 return true;
445b0eb0 124
445b0eb0 125 ACPI_FREE(buf.pointer);
445b0eb0
RW
126 return false;
127}
128
99db5ff7
RW
129static bool acpi_nondev_subnode_ok(acpi_handle scope,
130 const union acpi_object *link,
dfa672fb
MW
131 struct list_head *list,
132 struct fwnode_handle *parent)
99db5ff7
RW
133{
134 acpi_handle handle;
135 acpi_status status;
136
137 if (!scope)
138 return false;
139
140 status = acpi_get_handle(scope, link->package.elements[1].string.pointer,
141 &handle);
142 if (ACPI_FAILURE(status))
143 return false;
144
dfa672fb 145 return acpi_nondev_subnode_data_ok(handle, link, list, parent);
99db5ff7
RW
146}
147
445b0eb0
RW
148static int acpi_add_nondev_subnodes(acpi_handle scope,
149 const union acpi_object *links,
dfa672fb
MW
150 struct list_head *list,
151 struct fwnode_handle *parent)
445b0eb0
RW
152{
153 bool ret = false;
154 int i;
155
156 for (i = 0; i < links->package.count; i++) {
99db5ff7
RW
157 const union acpi_object *link, *desc;
158 acpi_handle handle;
159 bool result;
445b0eb0
RW
160
161 link = &links->package.elements[i];
99db5ff7
RW
162 /* Only two elements allowed. */
163 if (link->package.count != 2)
164 continue;
165
166 /* The first one must be a string. */
167 if (link->package.elements[0].type != ACPI_TYPE_STRING)
168 continue;
169
170 /* The second one may be a string, a reference or a package. */
171 switch (link->package.elements[1].type) {
172 case ACPI_TYPE_STRING:
dfa672fb
MW
173 result = acpi_nondev_subnode_ok(scope, link, list,
174 parent);
99db5ff7
RW
175 break;
176 case ACPI_TYPE_LOCAL_REFERENCE:
177 handle = link->package.elements[1].reference.handle;
dfa672fb
MW
178 result = acpi_nondev_subnode_data_ok(handle, link, list,
179 parent);
99db5ff7
RW
180 break;
181 case ACPI_TYPE_PACKAGE:
182 desc = &link->package.elements[1];
dfa672fb
MW
183 result = acpi_nondev_subnode_extract(desc, NULL, link,
184 list, parent);
99db5ff7
RW
185 break;
186 default:
187 result = false;
188 break;
189 }
190 ret = ret || result;
445b0eb0
RW
191 }
192
193 return ret;
194}
195
196static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
197 const union acpi_object *desc,
dfa672fb
MW
198 struct acpi_device_data *data,
199 struct fwnode_handle *parent)
445b0eb0
RW
200{
201 int i;
202
3689d3d6 203 /* Look for the ACPI data subnodes GUID. */
445b0eb0 204 for (i = 0; i < desc->package.count; i += 2) {
3689d3d6 205 const union acpi_object *guid, *links;
445b0eb0 206
3689d3d6 207 guid = &desc->package.elements[i];
445b0eb0
RW
208 links = &desc->package.elements[i + 1];
209
210 /*
3689d3d6 211 * The first element must be a GUID and the second one must be
445b0eb0
RW
212 * a package.
213 */
3689d3d6
AS
214 if (guid->type != ACPI_TYPE_BUFFER ||
215 guid->buffer.length != 16 ||
216 links->type != ACPI_TYPE_PACKAGE)
445b0eb0
RW
217 break;
218
3689d3d6 219 if (!guid_equal((guid_t *)guid->buffer.pointer, &ads_guid))
445b0eb0
RW
220 continue;
221
dfa672fb
MW
222 return acpi_add_nondev_subnodes(scope, links, &data->subnodes,
223 parent);
445b0eb0
RW
224 }
225
226 return false;
227}
ffdcd955
MW
228
229static bool acpi_property_value_ok(const union acpi_object *value)
230{
231 int j;
232
233 /*
234 * The value must be an integer, a string, a reference, or a package
235 * whose every element must be an integer, a string, or a reference.
236 */
237 switch (value->type) {
238 case ACPI_TYPE_INTEGER:
239 case ACPI_TYPE_STRING:
240 case ACPI_TYPE_LOCAL_REFERENCE:
241 return true;
242
243 case ACPI_TYPE_PACKAGE:
244 for (j = 0; j < value->package.count; j++)
245 switch (value->package.elements[j].type) {
246 case ACPI_TYPE_INTEGER:
247 case ACPI_TYPE_STRING:
248 case ACPI_TYPE_LOCAL_REFERENCE:
249 continue;
250
251 default:
252 return false;
253 }
254
255 return true;
256 }
257 return false;
258}
259
260static bool acpi_properties_format_valid(const union acpi_object *properties)
261{
262 int i;
263
264 for (i = 0; i < properties->package.count; i++) {
265 const union acpi_object *property;
266
267 property = &properties->package.elements[i];
268 /*
269 * Only two elements allowed, the first one must be a string and
270 * the second one has to satisfy certain conditions.
271 */
272 if (property->package.count != 2
273 || property->package.elements[0].type != ACPI_TYPE_STRING
274 || !acpi_property_value_ok(&property->package.elements[1]))
275 return false;
276 }
277 return true;
278}
279
733e6251
MW
280static void acpi_init_of_compatible(struct acpi_device *adev)
281{
282 const union acpi_object *of_compatible;
733e6251
MW
283 int ret;
284
3a7a2ab8
RW
285 ret = acpi_data_get_property_array(&adev->data, "compatible",
286 ACPI_TYPE_STRING, &of_compatible);
733e6251
MW
287 if (ret) {
288 ret = acpi_dev_get_property(adev, "compatible",
289 ACPI_TYPE_STRING, &of_compatible);
290 if (ret) {
5c53b262
RW
291 if (adev->parent
292 && adev->parent->flags.of_compatible_ok)
293 goto out;
294
733e6251
MW
295 return;
296 }
297 }
298 adev->data.of_compatible = of_compatible;
5c53b262
RW
299
300 out:
301 adev->flags.of_compatible_ok = 1;
733e6251
MW
302}
303
997d2b15
MW
304static bool acpi_is_property_guid(const guid_t *guid)
305{
306 int i;
307
308 for (i = 0; i < ARRAY_SIZE(prp_guids); i++) {
309 if (guid_equal(guid, &prp_guids[i]))
310 return true;
311 }
312
313 return false;
314}
315
316struct acpi_device_properties *
317acpi_data_add_props(struct acpi_device_data *data, const guid_t *guid,
318 const union acpi_object *properties)
319{
320 struct acpi_device_properties *props;
321
322 props = kzalloc(sizeof(*props), GFP_KERNEL);
323 if (props) {
324 INIT_LIST_HEAD(&props->list);
325 props->guid = guid;
326 props->properties = properties;
327 list_add_tail(&props->list, &data->properties);
328 }
329
330 return props;
331}
332
bd8191cc
RW
333static bool acpi_extract_properties(const union acpi_object *desc,
334 struct acpi_device_data *data)
ffdcd955 335{
ffdcd955
MW
336 int i;
337
ffdcd955 338 if (desc->package.count % 2)
bd8191cc 339 return false;
ffdcd955 340
3689d3d6 341 /* Look for the device properties GUID. */
ffdcd955 342 for (i = 0; i < desc->package.count; i += 2) {
3689d3d6 343 const union acpi_object *guid, *properties;
ffdcd955 344
3689d3d6 345 guid = &desc->package.elements[i];
ffdcd955
MW
346 properties = &desc->package.elements[i + 1];
347
348 /*
3689d3d6 349 * The first element must be a GUID and the second one must be
ffdcd955
MW
350 * a package.
351 */
3689d3d6
AS
352 if (guid->type != ACPI_TYPE_BUFFER ||
353 guid->buffer.length != 16 ||
354 properties->type != ACPI_TYPE_PACKAGE)
ffdcd955
MW
355 break;
356
997d2b15 357 if (!acpi_is_property_guid((guid_t *)guid->buffer.pointer))
ffdcd955
MW
358 continue;
359
360 /*
3689d3d6 361 * We found the matching GUID. Now validate the format of the
ffdcd955
MW
362 * package immediately following it.
363 */
364 if (!acpi_properties_format_valid(properties))
997d2b15 365 continue;
ffdcd955 366
997d2b15
MW
367 acpi_data_add_props(data, (const guid_t *)guid->buffer.pointer,
368 properties);
bd8191cc 369 }
733e6251 370
997d2b15 371 return !list_empty(&data->properties);
bd8191cc 372}
5c53b262 373
bd8191cc
RW
374void acpi_init_properties(struct acpi_device *adev)
375{
376 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
377 struct acpi_hardware_id *hwid;
378 acpi_status status;
379 bool acpi_of = false;
380
997d2b15 381 INIT_LIST_HEAD(&adev->data.properties);
445b0eb0
RW
382 INIT_LIST_HEAD(&adev->data.subnodes);
383
75fc70e0
LW
384 if (!adev->handle)
385 return;
386
bd8191cc
RW
387 /*
388 * Check if ACPI_DT_NAMESPACE_HID is present and inthat case we fill in
389 * Device Tree compatible properties for this device.
390 */
391 list_for_each_entry(hwid, &adev->pnp.ids, list) {
392 if (!strcmp(hwid->id, ACPI_DT_NAMESPACE_HID)) {
393 acpi_of = true;
394 break;
395 }
ffdcd955
MW
396 }
397
bd8191cc
RW
398 status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL, &buf,
399 ACPI_TYPE_PACKAGE);
400 if (ACPI_FAILURE(status))
401 goto out;
402
403 if (acpi_extract_properties(buf.pointer, &adev->data)) {
404 adev->data.pointer = buf.pointer;
405 if (acpi_of)
406 acpi_init_of_compatible(adev);
445b0eb0 407 }
dfa672fb
MW
408 if (acpi_enumerate_nondev_subnodes(adev->handle, buf.pointer,
409 &adev->data, acpi_fwnode_handle(adev)))
445b0eb0
RW
410 adev->data.pointer = buf.pointer;
411
412 if (!adev->data.pointer) {
bd8191cc
RW
413 acpi_handle_debug(adev->handle, "Invalid _DSD data, skipping\n");
414 ACPI_FREE(buf.pointer);
415 }
5c53b262
RW
416
417 out:
418 if (acpi_of && !adev->flags.of_compatible_ok)
419 acpi_handle_info(adev->handle,
ee892094 420 ACPI_DT_NAMESPACE_HID " requires 'compatible' property\n");
899596e0
LW
421
422 if (!adev->data.pointer)
423 acpi_extract_apple_properties(adev);
ffdcd955
MW
424}
425
445b0eb0
RW
426static void acpi_destroy_nondev_subnodes(struct list_head *list)
427{
428 struct acpi_data_node *dn, *next;
429
430 if (list_empty(list))
431 return;
432
433 list_for_each_entry_safe_reverse(dn, next, list, sibling) {
434 acpi_destroy_nondev_subnodes(&dn->data.subnodes);
263b4c1a 435 wait_for_completion(&dn->kobj_done);
445b0eb0
RW
436 list_del(&dn->sibling);
437 ACPI_FREE((void *)dn->data.pointer);
438 kfree(dn);
439 }
440}
441
ffdcd955
MW
442void acpi_free_properties(struct acpi_device *adev)
443{
997d2b15
MW
444 struct acpi_device_properties *props, *tmp;
445
445b0eb0 446 acpi_destroy_nondev_subnodes(&adev->data.subnodes);
ffdcd955 447 ACPI_FREE((void *)adev->data.pointer);
733e6251 448 adev->data.of_compatible = NULL;
ffdcd955 449 adev->data.pointer = NULL;
997d2b15
MW
450 list_for_each_entry_safe(props, tmp, &adev->data.properties, list) {
451 list_del(&props->list);
452 kfree(props);
453 }
ffdcd955
MW
454}
455
456/**
3a7a2ab8
RW
457 * acpi_data_get_property - return an ACPI property with given name
458 * @data: ACPI device deta object to get the property from
ffdcd955
MW
459 * @name: Name of the property
460 * @type: Expected property type
461 * @obj: Location to store the property value (if not %NULL)
462 *
463 * Look up a property with @name and store a pointer to the resulting ACPI
464 * object at the location pointed to by @obj if found.
465 *
466 * Callers must not attempt to free the returned objects. These objects will be
3a7a2ab8 467 * freed by the ACPI core automatically during the removal of @data.
ffdcd955
MW
468 *
469 * Return: %0 if property with @name has been found (success),
470 * %-EINVAL if the arguments are invalid,
3c60f114 471 * %-EINVAL if the property doesn't exist,
ffdcd955
MW
472 * %-EPROTO if the property value type doesn't match @type.
473 */
99a85464 474static int acpi_data_get_property(const struct acpi_device_data *data,
3a7a2ab8
RW
475 const char *name, acpi_object_type type,
476 const union acpi_object **obj)
ffdcd955 477{
997d2b15 478 const struct acpi_device_properties *props;
ffdcd955 479
3a7a2ab8 480 if (!data || !name)
ffdcd955
MW
481 return -EINVAL;
482
997d2b15 483 if (!data->pointer || list_empty(&data->properties))
3c60f114 484 return -EINVAL;
ffdcd955 485
997d2b15
MW
486 list_for_each_entry(props, &data->properties, list) {
487 const union acpi_object *properties;
488 unsigned int i;
ffdcd955 489
997d2b15
MW
490 properties = props->properties;
491 for (i = 0; i < properties->package.count; i++) {
492 const union acpi_object *propname, *propvalue;
493 const union acpi_object *property;
494
495 property = &properties->package.elements[i];
ffdcd955 496
997d2b15
MW
497 propname = &property->package.elements[0];
498 propvalue = &property->package.elements[1];
ffdcd955 499
997d2b15
MW
500 if (!strcmp(name, propname->string.pointer)) {
501 if (type != ACPI_TYPE_ANY &&
502 propvalue->type != type)
503 return -EPROTO;
504 if (obj)
505 *obj = propvalue;
ffdcd955 506
997d2b15
MW
507 return 0;
508 }
ffdcd955
MW
509 }
510 }
3c60f114 511 return -EINVAL;
ffdcd955 512}
3a7a2ab8
RW
513
514/**
515 * acpi_dev_get_property - return an ACPI property with given name.
516 * @adev: ACPI device to get the property from.
517 * @name: Name of the property.
518 * @type: Expected property type.
519 * @obj: Location to store the property value (if not %NULL).
520 */
99a85464 521int acpi_dev_get_property(const struct acpi_device *adev, const char *name,
3a7a2ab8
RW
522 acpi_object_type type, const union acpi_object **obj)
523{
524 return adev ? acpi_data_get_property(&adev->data, name, type, obj) : -EINVAL;
525}
ffdcd955
MW
526EXPORT_SYMBOL_GPL(acpi_dev_get_property);
527
99a85464
SA
528static const struct acpi_device_data *
529acpi_device_data_of_node(const struct fwnode_handle *fwnode)
3a7a2ab8 530{
db3e50f3 531 if (is_acpi_device_node(fwnode)) {
99a85464 532 const struct acpi_device *adev = to_acpi_device_node(fwnode);
3a7a2ab8 533 return &adev->data;
db3e50f3 534 } else if (is_acpi_data_node(fwnode)) {
99a85464 535 const struct acpi_data_node *dn = to_acpi_data_node(fwnode);
3a7a2ab8
RW
536 return &dn->data;
537 }
538 return NULL;
539}
540
ffdcd955 541/**
3a7a2ab8
RW
542 * acpi_node_prop_get - return an ACPI property with given name.
543 * @fwnode: Firmware node to get the property from.
544 * @propname: Name of the property.
545 * @valptr: Location to store a pointer to the property value (if not %NULL).
546 */
99a85464
SA
547int acpi_node_prop_get(const struct fwnode_handle *fwnode,
548 const char *propname, void **valptr)
3a7a2ab8
RW
549{
550 return acpi_data_get_property(acpi_device_data_of_node(fwnode),
551 propname, ACPI_TYPE_ANY,
552 (const union acpi_object **)valptr);
553}
554
555/**
556 * acpi_data_get_property_array - return an ACPI array property with given name
557 * @adev: ACPI data object to get the property from
ffdcd955
MW
558 * @name: Name of the property
559 * @type: Expected type of array elements
560 * @obj: Location to store a pointer to the property value (if not NULL)
561 *
562 * Look up an array property with @name and store a pointer to the resulting
563 * ACPI object at the location pointed to by @obj if found.
564 *
565 * Callers must not attempt to free the returned objects. Those objects will be
3a7a2ab8 566 * freed by the ACPI core automatically during the removal of @data.
ffdcd955
MW
567 *
568 * Return: %0 if array property (package) with @name has been found (success),
569 * %-EINVAL if the arguments are invalid,
3c60f114 570 * %-EINVAL if the property doesn't exist,
ffdcd955
MW
571 * %-EPROTO if the property is not a package or the type of its elements
572 * doesn't match @type.
573 */
99a85464 574static int acpi_data_get_property_array(const struct acpi_device_data *data,
3a7a2ab8
RW
575 const char *name,
576 acpi_object_type type,
577 const union acpi_object **obj)
ffdcd955
MW
578{
579 const union acpi_object *prop;
580 int ret, i;
581
3a7a2ab8 582 ret = acpi_data_get_property(data, name, ACPI_TYPE_PACKAGE, &prop);
ffdcd955
MW
583 if (ret)
584 return ret;
585
586 if (type != ACPI_TYPE_ANY) {
587 /* Check that all elements are of correct type. */
588 for (i = 0; i < prop->package.count; i++)
589 if (prop->package.elements[i].type != type)
590 return -EPROTO;
591 }
592 if (obj)
593 *obj = prop;
594
595 return 0;
596}
ffdcd955
MW
597
598/**
b60e4ea4
MW
599 * __acpi_node_get_property_reference - returns handle to the referenced object
600 * @fwnode: Firmware node to get the property from
504a3374 601 * @propname: Name of the property
ffdcd955 602 * @index: Index of the reference to return
b60e4ea4 603 * @num_args: Maximum number of arguments after each reference
ffdcd955
MW
604 * @args: Location to store the returned reference with optional arguments
605 *
606 * Find property with @name, verifify that it is a package containing at least
607 * one object reference and if so, store the ACPI device object pointer to the
60ba032e
RW
608 * target object in @args->adev. If the reference includes arguments, store
609 * them in the @args->args[] array.
ffdcd955 610 *
60ba032e
RW
611 * If there's more than one reference in the property value package, @index is
612 * used to select the one to return.
ffdcd955 613 *
b60e4ea4
MW
614 * It is possible to leave holes in the property value set like in the
615 * example below:
616 *
617 * Package () {
618 * "cs-gpios",
619 * Package () {
620 * ^GPIO, 19, 0, 0,
621 * ^GPIO, 20, 0, 0,
622 * 0,
623 * ^GPIO, 21, 0, 0,
624 * }
625 * }
626 *
c343bc2c
SA
627 * Calling this function with index %2 or index %3 return %-ENOENT. If the
628 * property does not contain any more values %-ENOENT is returned. The NULL
629 * entry must be single integer and preferably contain value %0.
b60e4ea4 630 *
ffdcd955
MW
631 * Return: %0 on success, negative error code on failure.
632 */
99a85464 633int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode,
b60e4ea4
MW
634 const char *propname, size_t index, size_t num_args,
635 struct acpi_reference_args *args)
ffdcd955
MW
636{
637 const union acpi_object *element, *end;
638 const union acpi_object *obj;
99a85464 639 const struct acpi_device_data *data;
ffdcd955
MW
640 struct acpi_device *device;
641 int ret, idx = 0;
642
b60e4ea4
MW
643 data = acpi_device_data_of_node(fwnode);
644 if (!data)
c343bc2c 645 return -ENOENT;
b60e4ea4 646
504a3374 647 ret = acpi_data_get_property(data, propname, ACPI_TYPE_ANY, &obj);
ffdcd955 648 if (ret)
51858a27 649 return ret == -EINVAL ? -ENOENT : -EINVAL;
ffdcd955
MW
650
651 /*
652 * The simplest case is when the value is a single reference. Just
653 * return that reference then.
654 */
655 if (obj->type == ACPI_TYPE_LOCAL_REFERENCE) {
60ba032e 656 if (index)
ffdcd955
MW
657 return -EINVAL;
658
659 ret = acpi_bus_get_device(obj->reference.handle, &device);
660 if (ret)
51858a27 661 return ret == -ENODEV ? -EINVAL : ret;
ffdcd955
MW
662
663 args->adev = device;
664 args->nargs = 0;
665 return 0;
666 }
667
668 /*
669 * If it is not a single reference, then it is a package of
670 * references followed by number of ints as follows:
671 *
672 * Package () { REF, INT, REF, INT, INT }
673 *
674 * The index argument is then used to determine which reference
675 * the caller wants (along with the arguments).
676 */
51858a27
SA
677 if (obj->type != ACPI_TYPE_PACKAGE)
678 return -EINVAL;
679 if (index >= obj->package.count)
680 return -ENOENT;
ffdcd955
MW
681
682 element = obj->package.elements;
683 end = element + obj->package.count;
684
685 while (element < end) {
686 u32 nargs, i;
687
b60e4ea4
MW
688 if (element->type == ACPI_TYPE_LOCAL_REFERENCE) {
689 ret = acpi_bus_get_device(element->reference.handle,
690 &device);
691 if (ret)
c343bc2c 692 return -EINVAL;
b60e4ea4
MW
693
694 nargs = 0;
695 element++;
696
697 /* assume following integer elements are all args */
698 for (i = 0; element + i < end && i < num_args; i++) {
699 int type = element[i].type;
700
701 if (type == ACPI_TYPE_INTEGER)
702 nargs++;
703 else if (type == ACPI_TYPE_LOCAL_REFERENCE)
704 break;
705 else
c343bc2c 706 return -EINVAL;
b60e4ea4 707 }
ffdcd955 708
b60e4ea4 709 if (nargs > MAX_ACPI_REFERENCE_ARGS)
c343bc2c 710 return -EINVAL;
ffdcd955 711
b60e4ea4
MW
712 if (idx == index) {
713 args->adev = device;
714 args->nargs = nargs;
715 for (i = 0; i < nargs; i++)
716 args->args[i] = element[i].integer.value;
ffdcd955 717
b60e4ea4
MW
718 return 0;
719 }
720
721 element += nargs;
722 } else if (element->type == ACPI_TYPE_INTEGER) {
723 if (idx == index)
724 return -ENOENT;
725 element++;
726 } else {
c343bc2c 727 return -EINVAL;
ffdcd955
MW
728 }
729
b60e4ea4 730 idx++;
ffdcd955
MW
731 }
732
c343bc2c 733 return -ENOENT;
504a3374 734}
b60e4ea4 735EXPORT_SYMBOL_GPL(__acpi_node_get_property_reference);
b31384fa 736
99a85464 737static int acpi_data_prop_read_single(const struct acpi_device_data *data,
3a7a2ab8
RW
738 const char *propname,
739 enum dev_prop_type proptype, void *val)
b31384fa
RW
740{
741 const union acpi_object *obj;
742 int ret;
743
744 if (!val)
745 return -EINVAL;
746
747 if (proptype >= DEV_PROP_U8 && proptype <= DEV_PROP_U64) {
3a7a2ab8 748 ret = acpi_data_get_property(data, propname, ACPI_TYPE_INTEGER, &obj);
b31384fa
RW
749 if (ret)
750 return ret;
751
752 switch (proptype) {
753 case DEV_PROP_U8:
754 if (obj->integer.value > U8_MAX)
755 return -EOVERFLOW;
756 *(u8 *)val = obj->integer.value;
757 break;
758 case DEV_PROP_U16:
759 if (obj->integer.value > U16_MAX)
760 return -EOVERFLOW;
761 *(u16 *)val = obj->integer.value;
762 break;
763 case DEV_PROP_U32:
764 if (obj->integer.value > U32_MAX)
765 return -EOVERFLOW;
766 *(u32 *)val = obj->integer.value;
767 break;
768 default:
769 *(u64 *)val = obj->integer.value;
770 break;
771 }
772 } else if (proptype == DEV_PROP_STRING) {
3a7a2ab8 773 ret = acpi_data_get_property(data, propname, ACPI_TYPE_STRING, &obj);
b31384fa
RW
774 if (ret)
775 return ret;
776
777 *(char **)val = obj->string.pointer;
b0b027ce
SA
778
779 return 1;
b31384fa
RW
780 } else {
781 ret = -EINVAL;
782 }
783 return ret;
784}
785
3a7a2ab8
RW
786int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname,
787 enum dev_prop_type proptype, void *val)
788{
b0b027ce
SA
789 int ret;
790
791 if (!adev)
792 return -EINVAL;
793
794 ret = acpi_data_prop_read_single(&adev->data, propname, proptype, val);
795 if (ret < 0 || proptype != ACPI_TYPE_STRING)
796 return ret;
797 return 0;
3a7a2ab8
RW
798}
799
b31384fa
RW
800static int acpi_copy_property_array_u8(const union acpi_object *items, u8 *val,
801 size_t nval)
802{
803 int i;
804
805 for (i = 0; i < nval; i++) {
806 if (items[i].type != ACPI_TYPE_INTEGER)
807 return -EPROTO;
808 if (items[i].integer.value > U8_MAX)
809 return -EOVERFLOW;
810
811 val[i] = items[i].integer.value;
812 }
813 return 0;
814}
815
816static int acpi_copy_property_array_u16(const union acpi_object *items,
817 u16 *val, size_t nval)
818{
819 int i;
820
821 for (i = 0; i < nval; i++) {
822 if (items[i].type != ACPI_TYPE_INTEGER)
823 return -EPROTO;
824 if (items[i].integer.value > U16_MAX)
825 return -EOVERFLOW;
826
827 val[i] = items[i].integer.value;
828 }
829 return 0;
830}
831
832static int acpi_copy_property_array_u32(const union acpi_object *items,
833 u32 *val, size_t nval)
834{
835 int i;
836
837 for (i = 0; i < nval; i++) {
838 if (items[i].type != ACPI_TYPE_INTEGER)
839 return -EPROTO;
840 if (items[i].integer.value > U32_MAX)
841 return -EOVERFLOW;
842
843 val[i] = items[i].integer.value;
844 }
845 return 0;
846}
847
848static int acpi_copy_property_array_u64(const union acpi_object *items,
849 u64 *val, size_t nval)
850{
851 int i;
852
853 for (i = 0; i < nval; i++) {
854 if (items[i].type != ACPI_TYPE_INTEGER)
855 return -EPROTO;
856
857 val[i] = items[i].integer.value;
858 }
859 return 0;
860}
861
862static int acpi_copy_property_array_string(const union acpi_object *items,
863 char **val, size_t nval)
864{
865 int i;
866
867 for (i = 0; i < nval; i++) {
868 if (items[i].type != ACPI_TYPE_STRING)
869 return -EPROTO;
870
871 val[i] = items[i].string.pointer;
872 }
b0b027ce 873 return nval;
b31384fa
RW
874}
875
99a85464 876static int acpi_data_prop_read(const struct acpi_device_data *data,
3a7a2ab8
RW
877 const char *propname,
878 enum dev_prop_type proptype,
879 void *val, size_t nval)
b31384fa
RW
880{
881 const union acpi_object *obj;
882 const union acpi_object *items;
883 int ret;
884
885 if (val && nval == 1) {
3a7a2ab8 886 ret = acpi_data_prop_read_single(data, propname, proptype, val);
b0b027ce 887 if (ret >= 0)
b31384fa
RW
888 return ret;
889 }
890
3a7a2ab8 891 ret = acpi_data_get_property_array(data, propname, ACPI_TYPE_ANY, &obj);
b31384fa
RW
892 if (ret)
893 return ret;
894
895 if (!val)
896 return obj->package.count;
b31384fa 897
b0b027ce 898 if (proptype != DEV_PROP_STRING && nval > obj->package.count)
b31384fa 899 return -EOVERFLOW;
7dc59dc9
AS
900 else if (nval <= 0)
901 return -EINVAL;
b31384fa
RW
902
903 items = obj->package.elements;
7dc59dc9 904
b31384fa
RW
905 switch (proptype) {
906 case DEV_PROP_U8:
907 ret = acpi_copy_property_array_u8(items, (u8 *)val, nval);
908 break;
909 case DEV_PROP_U16:
910 ret = acpi_copy_property_array_u16(items, (u16 *)val, nval);
911 break;
912 case DEV_PROP_U32:
913 ret = acpi_copy_property_array_u32(items, (u32 *)val, nval);
914 break;
915 case DEV_PROP_U64:
916 ret = acpi_copy_property_array_u64(items, (u64 *)val, nval);
917 break;
918 case DEV_PROP_STRING:
b0b027ce
SA
919 ret = acpi_copy_property_array_string(
920 items, (char **)val,
921 min_t(u32, nval, obj->package.count));
b31384fa
RW
922 break;
923 default:
924 ret = -EINVAL;
925 break;
926 }
927 return ret;
928}
3a7a2ab8 929
99a85464 930int acpi_dev_prop_read(const struct acpi_device *adev, const char *propname,
3a7a2ab8
RW
931 enum dev_prop_type proptype, void *val, size_t nval)
932{
933 return adev ? acpi_data_prop_read(&adev->data, propname, proptype, val, nval) : -EINVAL;
934}
935
936/**
937 * acpi_node_prop_read - retrieve the value of an ACPI property with given name.
938 * @fwnode: Firmware node to get the property from.
939 * @propname: Name of the property.
940 * @proptype: Expected property type.
941 * @val: Location to store the property value (if not %NULL).
942 * @nval: Size of the array pointed to by @val.
943 *
944 * If @val is %NULL, return the number of array elements comprising the value
945 * of the property. Otherwise, read at most @nval values to the array at the
946 * location pointed to by @val.
947 */
99a85464
SA
948int acpi_node_prop_read(const struct fwnode_handle *fwnode,
949 const char *propname, enum dev_prop_type proptype,
950 void *val, size_t nval)
3a7a2ab8
RW
951{
952 return acpi_data_prop_read(acpi_device_data_of_node(fwnode),
953 propname, proptype, val, nval);
954}
504a3374
RW
955
956/**
34055190
MW
957 * acpi_get_next_subnode - Return the next child node handle for a fwnode
958 * @fwnode: Firmware node to find the next child node for.
504a3374
RW
959 * @child: Handle to one of the device's child nodes or a null handle.
960 */
37ba983c 961struct fwnode_handle *acpi_get_next_subnode(const struct fwnode_handle *fwnode,
504a3374
RW
962 struct fwnode_handle *child)
963{
01c1da28 964 const struct acpi_device *adev = to_acpi_device_node(fwnode);
01c1da28
SA
965 const struct list_head *head;
966 struct list_head *next;
504a3374 967
db3e50f3 968 if (!child || is_acpi_device_node(child)) {
0c0bceb7
SA
969 struct acpi_device *child_adev;
970
34055190
MW
971 if (adev)
972 head = &adev->children;
973 else
974 goto nondev;
975
504a3374
RW
976 if (list_empty(head))
977 goto nondev;
978
979 if (child) {
0c0bceb7
SA
980 adev = to_acpi_device_node(child);
981 next = adev->node.next;
504a3374
RW
982 if (next == head) {
983 child = NULL;
984 goto nondev;
985 }
01c1da28 986 child_adev = list_entry(next, struct acpi_device, node);
504a3374 987 } else {
01c1da28
SA
988 child_adev = list_first_entry(head, struct acpi_device,
989 node);
504a3374 990 }
01c1da28 991 return acpi_fwnode_handle(child_adev);
504a3374
RW
992 }
993
994 nondev:
db3e50f3 995 if (!child || is_acpi_data_node(child)) {
01c1da28 996 const struct acpi_data_node *data = to_acpi_data_node(fwnode);
504a3374
RW
997 struct acpi_data_node *dn;
998
0c0bceb7
SA
999 if (adev)
1000 head = &adev->data.subnodes;
34055190
MW
1001 else if (data)
1002 head = &data->data.subnodes;
1003 else
1004 return NULL;
1005
504a3374
RW
1006 if (list_empty(head))
1007 return NULL;
1008
1009 if (child) {
1010 dn = to_acpi_data_node(child);
1011 next = dn->sibling.next;
1012 if (next == head)
1013 return NULL;
1014
1015 dn = list_entry(next, struct acpi_data_node, sibling);
1016 } else {
1017 dn = list_first_entry(head, struct acpi_data_node, sibling);
1018 }
1019 return &dn->fwnode;
1020 }
1021 return NULL;
1022}
dfa672fb
MW
1023
1024/**
1025 * acpi_node_get_parent - Return parent fwnode of this fwnode
1026 * @fwnode: Firmware node whose parent to get
1027 *
1028 * Returns parent node of an ACPI device or data firmware node or %NULL if
1029 * not available.
1030 */
37ba983c 1031struct fwnode_handle *acpi_node_get_parent(const struct fwnode_handle *fwnode)
dfa672fb
MW
1032{
1033 if (is_acpi_data_node(fwnode)) {
1034 /* All data nodes have parent pointer so just return that */
1035 return to_acpi_data_node(fwnode)->parent;
1036 } else if (is_acpi_device_node(fwnode)) {
1037 acpi_handle handle, parent_handle;
1038
1039 handle = to_acpi_device_node(fwnode)->handle;
1040 if (ACPI_SUCCESS(acpi_get_parent(handle, &parent_handle))) {
1041 struct acpi_device *adev;
1042
1043 if (!acpi_bus_get_device(parent_handle, &adev))
1044 return acpi_fwnode_handle(adev);
1045 }
1046 }
1047
1048 return NULL;
1049}
79389a83
MW
1050
1051/**
1052 * acpi_graph_get_next_endpoint - Get next endpoint ACPI firmware node
1053 * @fwnode: Pointer to the parent firmware node
1054 * @prev: Previous endpoint node or %NULL to get the first
1055 *
1056 * Looks up next endpoint ACPI firmware node below a given @fwnode. Returns
1057 * %NULL if there is no next endpoint, ERR_PTR() in case of error. In case
1058 * of success the next endpoint is returned.
1059 */
37ba983c
SA
1060struct fwnode_handle *acpi_graph_get_next_endpoint(
1061 const struct fwnode_handle *fwnode, struct fwnode_handle *prev)
79389a83
MW
1062{
1063 struct fwnode_handle *port = NULL;
1064 struct fwnode_handle *endpoint;
1065
1066 if (!prev) {
1067 do {
1068 port = fwnode_get_next_child_node(fwnode, port);
1069 /* Ports must have port property */
1070 if (fwnode_property_present(port, "port"))
1071 break;
1072 } while (port);
1073 } else {
1074 port = fwnode_get_parent(prev);
1075 }
1076
1077 if (!port)
1078 return NULL;
1079
1080 endpoint = fwnode_get_next_child_node(port, prev);
1081 while (!endpoint) {
1082 port = fwnode_get_next_child_node(fwnode, port);
1083 if (!port)
1084 break;
1085 if (fwnode_property_present(port, "port"))
1086 endpoint = fwnode_get_next_child_node(port, NULL);
1087 }
1088
1089 if (endpoint) {
1090 /* Endpoints must have "endpoint" property */
1091 if (!fwnode_property_present(endpoint, "endpoint"))
1092 return ERR_PTR(-EPROTO);
1093 }
1094
1095 return endpoint;
1096}
1097
1098/**
1099 * acpi_graph_get_child_prop_value - Return a child with a given property value
1100 * @fwnode: device fwnode
1101 * @prop_name: The name of the property to look for
1102 * @val: the desired property value
1103 *
1104 * Return the port node corresponding to a given port number. Returns
1105 * the child node on success, NULL otherwise.
1106 */
1107static struct fwnode_handle *acpi_graph_get_child_prop_value(
37ba983c
SA
1108 const struct fwnode_handle *fwnode, const char *prop_name,
1109 unsigned int val)
79389a83
MW
1110{
1111 struct fwnode_handle *child;
1112
1113 fwnode_for_each_child_node(fwnode, child) {
1114 u32 nr;
1115
b5212f57 1116 if (fwnode_property_read_u32(child, prop_name, &nr))
79389a83
MW
1117 continue;
1118
1119 if (val == nr)
1120 return child;
1121 }
1122
1123 return NULL;
1124}
1125
1126
1127/**
1128 * acpi_graph_get_remote_enpoint - Parses and returns remote end of an endpoint
1129 * @fwnode: Endpoint firmware node pointing to a remote device
1130 * @parent: Firmware node of remote port parent is filled here if not %NULL
1131 * @port: Firmware node of remote port is filled here if not %NULL
1132 * @endpoint: Firmware node of remote endpoint is filled here if not %NULL
1133 *
1134 * Function parses remote end of ACPI firmware remote endpoint and fills in
1135 * fields requested by the caller. Returns %0 in case of success and
1136 * negative errno otherwise.
1137 */
37ba983c 1138int acpi_graph_get_remote_endpoint(const struct fwnode_handle *__fwnode,
79389a83
MW
1139 struct fwnode_handle **parent,
1140 struct fwnode_handle **port,
1141 struct fwnode_handle **endpoint)
1142{
37ba983c 1143 struct fwnode_handle *fwnode;
79389a83
MW
1144 unsigned int port_nr, endpoint_nr;
1145 struct acpi_reference_args args;
1146 int ret;
1147
1148 memset(&args, 0, sizeof(args));
37ba983c 1149 ret = acpi_node_get_property_reference(__fwnode, "remote-endpoint", 0,
79389a83
MW
1150 &args);
1151 if (ret)
1152 return ret;
1153
1154 /*
1155 * Always require two arguments with the reference: port and
1156 * endpoint indices.
1157 */
1158 if (args.nargs != 2)
1159 return -EPROTO;
1160
1161 fwnode = acpi_fwnode_handle(args.adev);
1162 port_nr = args.args[0];
1163 endpoint_nr = args.args[1];
1164
1165 if (parent)
1166 *parent = fwnode;
1167
1168 if (!port && !endpoint)
1169 return 0;
1170
1171 fwnode = acpi_graph_get_child_prop_value(fwnode, "port", port_nr);
1172 if (!fwnode)
1173 return -EPROTO;
1174
1175 if (port)
1176 *port = fwnode;
1177
1178 if (!endpoint)
1179 return 0;
1180
1181 fwnode = acpi_graph_get_child_prop_value(fwnode, "endpoint",
1182 endpoint_nr);
1183 if (!fwnode)
1184 return -EPROTO;
1185
1186 *endpoint = fwnode;
1187
1188 return 0;
1189}
3708184a 1190
37ba983c 1191static bool acpi_fwnode_device_is_available(const struct fwnode_handle *fwnode)
2294b3af
SA
1192{
1193 if (!is_acpi_device_node(fwnode))
1194 return false;
1195
1196 return acpi_device_is_present(to_acpi_device_node(fwnode));
1197}
1198
37ba983c 1199static bool acpi_fwnode_property_present(const struct fwnode_handle *fwnode,
3708184a
SA
1200 const char *propname)
1201{
1202 return !acpi_node_prop_get(fwnode, propname, NULL);
1203}
1204
37ba983c
SA
1205static int
1206acpi_fwnode_property_read_int_array(const struct fwnode_handle *fwnode,
1207 const char *propname,
1208 unsigned int elem_size, void *val,
1209 size_t nval)
3708184a
SA
1210{
1211 enum dev_prop_type type;
1212
1213 switch (elem_size) {
1214 case sizeof(u8):
1215 type = DEV_PROP_U8;
1216 break;
1217 case sizeof(u16):
1218 type = DEV_PROP_U16;
1219 break;
1220 case sizeof(u32):
1221 type = DEV_PROP_U32;
1222 break;
1223 case sizeof(u64):
1224 type = DEV_PROP_U64;
1225 break;
1226 default:
1227 return -ENXIO;
1228 }
1229
1230 return acpi_node_prop_read(fwnode, propname, type, val, nval);
1231}
1232
37ba983c
SA
1233static int
1234acpi_fwnode_property_read_string_array(const struct fwnode_handle *fwnode,
1235 const char *propname, const char **val,
1236 size_t nval)
3708184a
SA
1237{
1238 return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,
1239 val, nval);
1240}
1241
1242static struct fwnode_handle *
37ba983c 1243acpi_fwnode_get_named_child_node(const struct fwnode_handle *fwnode,
3708184a
SA
1244 const char *childname)
1245{
1246 struct fwnode_handle *child;
1247
1248 /*
1249 * Find first matching named child node of this fwnode.
1250 * For ACPI this will be a data only sub-node.
1251 */
1252 fwnode_for_each_child_node(fwnode, child)
1253 if (acpi_data_node_match(child, childname))
1254 return child;
1255
1256 return NULL;
1257}
1258
3e3119d3
SA
1259static int
1260acpi_fwnode_get_reference_args(const struct fwnode_handle *fwnode,
1261 const char *prop, const char *nargs_prop,
1262 unsigned int args_count, unsigned int index,
1263 struct fwnode_reference_args *args)
1264{
1265 struct acpi_reference_args acpi_args;
1266 unsigned int i;
1267 int ret;
1268
1269 ret = __acpi_node_get_property_reference(fwnode, prop, index,
1270 args_count, &acpi_args);
1271 if (ret < 0)
1272 return ret;
1273 if (!args)
1274 return 0;
1275
1276 args->nargs = acpi_args.nargs;
1277 args->fwnode = acpi_fwnode_handle(acpi_args.adev);
1278
1279 for (i = 0; i < NR_FWNODE_REFERENCE_ARGS; i++)
1280 args->args[i] = i < acpi_args.nargs ? acpi_args.args[i] : 0;
1281
1282 return 0;
1283}
1284
3b27d00e 1285static struct fwnode_handle *
37ba983c 1286acpi_fwnode_graph_get_next_endpoint(const struct fwnode_handle *fwnode,
3b27d00e
SA
1287 struct fwnode_handle *prev)
1288{
1289 struct fwnode_handle *endpoint;
1290
1291 endpoint = acpi_graph_get_next_endpoint(fwnode, prev);
1292 if (IS_ERR(endpoint))
1293 return NULL;
1294
1295 return endpoint;
1296}
1297
1298static struct fwnode_handle *
37ba983c 1299acpi_fwnode_graph_get_remote_endpoint(const struct fwnode_handle *fwnode)
3b27d00e
SA
1300{
1301 struct fwnode_handle *endpoint = NULL;
1302
1303 acpi_graph_get_remote_endpoint(fwnode, NULL, NULL, &endpoint);
1304
1305 return endpoint;
1306}
1307
37ba983c
SA
1308static struct fwnode_handle *
1309acpi_fwnode_get_parent(struct fwnode_handle *fwnode)
1310{
1311 return acpi_node_get_parent(fwnode);
1312}
1313
1314static int acpi_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode,
3b27d00e
SA
1315 struct fwnode_endpoint *endpoint)
1316{
1317 struct fwnode_handle *port_fwnode = fwnode_get_parent(fwnode);
1318
1319 endpoint->local_fwnode = fwnode;
1320
1321 fwnode_property_read_u32(port_fwnode, "port", &endpoint->port);
1322 fwnode_property_read_u32(fwnode, "endpoint", &endpoint->id);
1323
1324 return 0;
1325}
1326
db3e50f3
SA
1327#define DECLARE_ACPI_FWNODE_OPS(ops) \
1328 const struct fwnode_operations ops = { \
1329 .device_is_available = acpi_fwnode_device_is_available, \
1330 .property_present = acpi_fwnode_property_present, \
1331 .property_read_int_array = \
1332 acpi_fwnode_property_read_int_array, \
1333 .property_read_string_array = \
1334 acpi_fwnode_property_read_string_array, \
1335 .get_parent = acpi_node_get_parent, \
1336 .get_next_child_node = acpi_get_next_subnode, \
1337 .get_named_child_node = acpi_fwnode_get_named_child_node, \
3e3119d3 1338 .get_reference_args = acpi_fwnode_get_reference_args, \
db3e50f3
SA
1339 .graph_get_next_endpoint = \
1340 acpi_fwnode_graph_get_next_endpoint, \
1341 .graph_get_remote_endpoint = \
1342 acpi_fwnode_graph_get_remote_endpoint, \
37ba983c 1343 .graph_get_port_parent = acpi_fwnode_get_parent, \
db3e50f3
SA
1344 .graph_parse_endpoint = acpi_fwnode_graph_parse_endpoint, \
1345 }; \
1346 EXPORT_SYMBOL_GPL(ops)
1347
1348DECLARE_ACPI_FWNODE_OPS(acpi_device_fwnode_ops);
1349DECLARE_ACPI_FWNODE_OPS(acpi_data_fwnode_ops);
1350const struct fwnode_operations acpi_static_fwnode_ops;
9e987b70
JH
1351
1352bool is_acpi_device_node(const struct fwnode_handle *fwnode)
1353{
1354 return !IS_ERR_OR_NULL(fwnode) &&
1355 fwnode->ops == &acpi_device_fwnode_ops;
1356}
1357EXPORT_SYMBOL(is_acpi_device_node);
1358
1359bool is_acpi_data_node(const struct fwnode_handle *fwnode)
1360{
1361 return !IS_ERR_OR_NULL(fwnode) && fwnode->ops == &acpi_data_fwnode_ops;
1362}
1363EXPORT_SYMBOL(is_acpi_data_node);