]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/acpi/property.c
UBUNTU: Ubuntu-4.15.0-96.97
[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
7245ea46
PLB
999 /*
1000 * We can have a combination of device and data nodes, e.g. with
1001 * hierarchical _DSD properties. Make sure the adev pointer is
1002 * restored before going through data nodes, otherwise we will
1003 * be looking for data_nodes below the last device found instead
1004 * of the common fwnode shared by device_nodes and data_nodes.
1005 */
1006 adev = to_acpi_device_node(fwnode);
0c0bceb7
SA
1007 if (adev)
1008 head = &adev->data.subnodes;
34055190
MW
1009 else if (data)
1010 head = &data->data.subnodes;
1011 else
1012 return NULL;
1013
504a3374
RW
1014 if (list_empty(head))
1015 return NULL;
1016
1017 if (child) {
1018 dn = to_acpi_data_node(child);
1019 next = dn->sibling.next;
1020 if (next == head)
1021 return NULL;
1022
1023 dn = list_entry(next, struct acpi_data_node, sibling);
1024 } else {
1025 dn = list_first_entry(head, struct acpi_data_node, sibling);
1026 }
1027 return &dn->fwnode;
1028 }
1029 return NULL;
1030}
dfa672fb
MW
1031
1032/**
1033 * acpi_node_get_parent - Return parent fwnode of this fwnode
1034 * @fwnode: Firmware node whose parent to get
1035 *
1036 * Returns parent node of an ACPI device or data firmware node or %NULL if
1037 * not available.
1038 */
37ba983c 1039struct fwnode_handle *acpi_node_get_parent(const struct fwnode_handle *fwnode)
dfa672fb
MW
1040{
1041 if (is_acpi_data_node(fwnode)) {
1042 /* All data nodes have parent pointer so just return that */
1043 return to_acpi_data_node(fwnode)->parent;
1044 } else if (is_acpi_device_node(fwnode)) {
1045 acpi_handle handle, parent_handle;
1046
1047 handle = to_acpi_device_node(fwnode)->handle;
1048 if (ACPI_SUCCESS(acpi_get_parent(handle, &parent_handle))) {
1049 struct acpi_device *adev;
1050
1051 if (!acpi_bus_get_device(parent_handle, &adev))
1052 return acpi_fwnode_handle(adev);
1053 }
1054 }
1055
1056 return NULL;
1057}
79389a83
MW
1058
1059/**
1060 * acpi_graph_get_next_endpoint - Get next endpoint ACPI firmware node
1061 * @fwnode: Pointer to the parent firmware node
1062 * @prev: Previous endpoint node or %NULL to get the first
1063 *
1064 * Looks up next endpoint ACPI firmware node below a given @fwnode. Returns
1065 * %NULL if there is no next endpoint, ERR_PTR() in case of error. In case
1066 * of success the next endpoint is returned.
1067 */
37ba983c
SA
1068struct fwnode_handle *acpi_graph_get_next_endpoint(
1069 const struct fwnode_handle *fwnode, struct fwnode_handle *prev)
79389a83
MW
1070{
1071 struct fwnode_handle *port = NULL;
1072 struct fwnode_handle *endpoint;
1073
1074 if (!prev) {
1075 do {
1076 port = fwnode_get_next_child_node(fwnode, port);
1077 /* Ports must have port property */
1078 if (fwnode_property_present(port, "port"))
1079 break;
1080 } while (port);
1081 } else {
1082 port = fwnode_get_parent(prev);
1083 }
1084
1085 if (!port)
1086 return NULL;
1087
1088 endpoint = fwnode_get_next_child_node(port, prev);
1089 while (!endpoint) {
1090 port = fwnode_get_next_child_node(fwnode, port);
1091 if (!port)
1092 break;
1093 if (fwnode_property_present(port, "port"))
1094 endpoint = fwnode_get_next_child_node(port, NULL);
1095 }
1096
1097 if (endpoint) {
1098 /* Endpoints must have "endpoint" property */
1099 if (!fwnode_property_present(endpoint, "endpoint"))
1100 return ERR_PTR(-EPROTO);
1101 }
1102
1103 return endpoint;
1104}
1105
1106/**
1107 * acpi_graph_get_child_prop_value - Return a child with a given property value
1108 * @fwnode: device fwnode
1109 * @prop_name: The name of the property to look for
1110 * @val: the desired property value
1111 *
1112 * Return the port node corresponding to a given port number. Returns
1113 * the child node on success, NULL otherwise.
1114 */
1115static struct fwnode_handle *acpi_graph_get_child_prop_value(
37ba983c
SA
1116 const struct fwnode_handle *fwnode, const char *prop_name,
1117 unsigned int val)
79389a83
MW
1118{
1119 struct fwnode_handle *child;
1120
1121 fwnode_for_each_child_node(fwnode, child) {
1122 u32 nr;
1123
b5212f57 1124 if (fwnode_property_read_u32(child, prop_name, &nr))
79389a83
MW
1125 continue;
1126
1127 if (val == nr)
1128 return child;
1129 }
1130
1131 return NULL;
1132}
1133
1134
1135/**
1136 * acpi_graph_get_remote_enpoint - Parses and returns remote end of an endpoint
1137 * @fwnode: Endpoint firmware node pointing to a remote device
1138 * @parent: Firmware node of remote port parent is filled here if not %NULL
1139 * @port: Firmware node of remote port is filled here if not %NULL
1140 * @endpoint: Firmware node of remote endpoint is filled here if not %NULL
1141 *
1142 * Function parses remote end of ACPI firmware remote endpoint and fills in
1143 * fields requested by the caller. Returns %0 in case of success and
1144 * negative errno otherwise.
1145 */
37ba983c 1146int acpi_graph_get_remote_endpoint(const struct fwnode_handle *__fwnode,
79389a83
MW
1147 struct fwnode_handle **parent,
1148 struct fwnode_handle **port,
1149 struct fwnode_handle **endpoint)
1150{
37ba983c 1151 struct fwnode_handle *fwnode;
79389a83
MW
1152 unsigned int port_nr, endpoint_nr;
1153 struct acpi_reference_args args;
1154 int ret;
1155
1156 memset(&args, 0, sizeof(args));
37ba983c 1157 ret = acpi_node_get_property_reference(__fwnode, "remote-endpoint", 0,
79389a83
MW
1158 &args);
1159 if (ret)
1160 return ret;
1161
1162 /*
1163 * Always require two arguments with the reference: port and
1164 * endpoint indices.
1165 */
1166 if (args.nargs != 2)
1167 return -EPROTO;
1168
1169 fwnode = acpi_fwnode_handle(args.adev);
1170 port_nr = args.args[0];
1171 endpoint_nr = args.args[1];
1172
1173 if (parent)
1174 *parent = fwnode;
1175
1176 if (!port && !endpoint)
1177 return 0;
1178
1179 fwnode = acpi_graph_get_child_prop_value(fwnode, "port", port_nr);
1180 if (!fwnode)
1181 return -EPROTO;
1182
1183 if (port)
1184 *port = fwnode;
1185
1186 if (!endpoint)
1187 return 0;
1188
1189 fwnode = acpi_graph_get_child_prop_value(fwnode, "endpoint",
1190 endpoint_nr);
1191 if (!fwnode)
1192 return -EPROTO;
1193
1194 *endpoint = fwnode;
1195
1196 return 0;
1197}
3708184a 1198
37ba983c 1199static bool acpi_fwnode_device_is_available(const struct fwnode_handle *fwnode)
2294b3af
SA
1200{
1201 if (!is_acpi_device_node(fwnode))
1202 return false;
1203
1204 return acpi_device_is_present(to_acpi_device_node(fwnode));
1205}
1206
37ba983c 1207static bool acpi_fwnode_property_present(const struct fwnode_handle *fwnode,
3708184a
SA
1208 const char *propname)
1209{
1210 return !acpi_node_prop_get(fwnode, propname, NULL);
1211}
1212
37ba983c
SA
1213static int
1214acpi_fwnode_property_read_int_array(const struct fwnode_handle *fwnode,
1215 const char *propname,
1216 unsigned int elem_size, void *val,
1217 size_t nval)
3708184a
SA
1218{
1219 enum dev_prop_type type;
1220
1221 switch (elem_size) {
1222 case sizeof(u8):
1223 type = DEV_PROP_U8;
1224 break;
1225 case sizeof(u16):
1226 type = DEV_PROP_U16;
1227 break;
1228 case sizeof(u32):
1229 type = DEV_PROP_U32;
1230 break;
1231 case sizeof(u64):
1232 type = DEV_PROP_U64;
1233 break;
1234 default:
1235 return -ENXIO;
1236 }
1237
1238 return acpi_node_prop_read(fwnode, propname, type, val, nval);
1239}
1240
37ba983c
SA
1241static int
1242acpi_fwnode_property_read_string_array(const struct fwnode_handle *fwnode,
1243 const char *propname, const char **val,
1244 size_t nval)
3708184a
SA
1245{
1246 return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,
1247 val, nval);
1248}
1249
1250static struct fwnode_handle *
37ba983c 1251acpi_fwnode_get_named_child_node(const struct fwnode_handle *fwnode,
3708184a
SA
1252 const char *childname)
1253{
1254 struct fwnode_handle *child;
1255
1256 /*
1257 * Find first matching named child node of this fwnode.
1258 * For ACPI this will be a data only sub-node.
1259 */
1260 fwnode_for_each_child_node(fwnode, child)
1261 if (acpi_data_node_match(child, childname))
1262 return child;
1263
1264 return NULL;
1265}
1266
3e3119d3
SA
1267static int
1268acpi_fwnode_get_reference_args(const struct fwnode_handle *fwnode,
1269 const char *prop, const char *nargs_prop,
1270 unsigned int args_count, unsigned int index,
1271 struct fwnode_reference_args *args)
1272{
1273 struct acpi_reference_args acpi_args;
1274 unsigned int i;
1275 int ret;
1276
1277 ret = __acpi_node_get_property_reference(fwnode, prop, index,
1278 args_count, &acpi_args);
1279 if (ret < 0)
1280 return ret;
1281 if (!args)
1282 return 0;
1283
1284 args->nargs = acpi_args.nargs;
1285 args->fwnode = acpi_fwnode_handle(acpi_args.adev);
1286
1287 for (i = 0; i < NR_FWNODE_REFERENCE_ARGS; i++)
1288 args->args[i] = i < acpi_args.nargs ? acpi_args.args[i] : 0;
1289
1290 return 0;
1291}
1292
3b27d00e 1293static struct fwnode_handle *
37ba983c 1294acpi_fwnode_graph_get_next_endpoint(const struct fwnode_handle *fwnode,
3b27d00e
SA
1295 struct fwnode_handle *prev)
1296{
1297 struct fwnode_handle *endpoint;
1298
1299 endpoint = acpi_graph_get_next_endpoint(fwnode, prev);
1300 if (IS_ERR(endpoint))
1301 return NULL;
1302
1303 return endpoint;
1304}
1305
1306static struct fwnode_handle *
37ba983c 1307acpi_fwnode_graph_get_remote_endpoint(const struct fwnode_handle *fwnode)
3b27d00e
SA
1308{
1309 struct fwnode_handle *endpoint = NULL;
1310
1311 acpi_graph_get_remote_endpoint(fwnode, NULL, NULL, &endpoint);
1312
1313 return endpoint;
1314}
1315
37ba983c
SA
1316static struct fwnode_handle *
1317acpi_fwnode_get_parent(struct fwnode_handle *fwnode)
1318{
1319 return acpi_node_get_parent(fwnode);
1320}
1321
1322static int acpi_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode,
3b27d00e
SA
1323 struct fwnode_endpoint *endpoint)
1324{
1325 struct fwnode_handle *port_fwnode = fwnode_get_parent(fwnode);
1326
1327 endpoint->local_fwnode = fwnode;
1328
1329 fwnode_property_read_u32(port_fwnode, "port", &endpoint->port);
1330 fwnode_property_read_u32(fwnode, "endpoint", &endpoint->id);
1331
1332 return 0;
1333}
1334
db3e50f3
SA
1335#define DECLARE_ACPI_FWNODE_OPS(ops) \
1336 const struct fwnode_operations ops = { \
1337 .device_is_available = acpi_fwnode_device_is_available, \
1338 .property_present = acpi_fwnode_property_present, \
1339 .property_read_int_array = \
1340 acpi_fwnode_property_read_int_array, \
1341 .property_read_string_array = \
1342 acpi_fwnode_property_read_string_array, \
1343 .get_parent = acpi_node_get_parent, \
1344 .get_next_child_node = acpi_get_next_subnode, \
1345 .get_named_child_node = acpi_fwnode_get_named_child_node, \
3e3119d3 1346 .get_reference_args = acpi_fwnode_get_reference_args, \
db3e50f3
SA
1347 .graph_get_next_endpoint = \
1348 acpi_fwnode_graph_get_next_endpoint, \
1349 .graph_get_remote_endpoint = \
1350 acpi_fwnode_graph_get_remote_endpoint, \
37ba983c 1351 .graph_get_port_parent = acpi_fwnode_get_parent, \
db3e50f3
SA
1352 .graph_parse_endpoint = acpi_fwnode_graph_parse_endpoint, \
1353 }; \
1354 EXPORT_SYMBOL_GPL(ops)
1355
1356DECLARE_ACPI_FWNODE_OPS(acpi_device_fwnode_ops);
1357DECLARE_ACPI_FWNODE_OPS(acpi_data_fwnode_ops);
1358const struct fwnode_operations acpi_static_fwnode_ops;
9e987b70
JH
1359
1360bool is_acpi_device_node(const struct fwnode_handle *fwnode)
1361{
1362 return !IS_ERR_OR_NULL(fwnode) &&
1363 fwnode->ops == &acpi_device_fwnode_ops;
1364}
1365EXPORT_SYMBOL(is_acpi_device_node);
1366
1367bool is_acpi_data_node(const struct fwnode_handle *fwnode)
1368{
1369 return !IS_ERR_OR_NULL(fwnode) && fwnode->ops == &acpi_data_fwnode_ops;
1370}
1371EXPORT_SYMBOL(is_acpi_data_node);