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