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