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 dn->fwnode.ops = &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 (!val)
791 return -EINVAL;
792
793 if (proptype >= DEV_PROP_U8 && proptype <= DEV_PROP_U64) {
794 ret = acpi_data_get_property(data, propname, ACPI_TYPE_INTEGER, &obj);
795 if (ret)
796 return ret;
797
798 switch (proptype) {
799 case DEV_PROP_U8:
800 if (obj->integer.value > U8_MAX)
801 return -EOVERFLOW;
802 *(u8 *)val = obj->integer.value;
803 break;
804 case DEV_PROP_U16:
805 if (obj->integer.value > U16_MAX)
806 return -EOVERFLOW;
807 *(u16 *)val = obj->integer.value;
808 break;
809 case DEV_PROP_U32:
810 if (obj->integer.value > U32_MAX)
811 return -EOVERFLOW;
812 *(u32 *)val = obj->integer.value;
813 break;
814 default:
815 *(u64 *)val = obj->integer.value;
816 break;
817 }
818 } else if (proptype == DEV_PROP_STRING) {
819 ret = acpi_data_get_property(data, propname, ACPI_TYPE_STRING, &obj);
820 if (ret)
821 return ret;
822
823 *(char **)val = obj->string.pointer;
824
825 return 1;
826 } else {
827 ret = -EINVAL;
828 }
829 return ret;
830}
831
832int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname,
833 enum dev_prop_type proptype, void *val)
834{
835 int ret;
836
837 if (!adev)
838 return -EINVAL;
839
840 ret = acpi_data_prop_read_single(&adev->data, propname, proptype, val);
841 if (ret < 0 || proptype != ACPI_TYPE_STRING)
842 return ret;
843 return 0;
844}
845
846static int acpi_copy_property_array_u8(const union acpi_object *items, u8 *val,
847 size_t nval)
848{
849 int i;
850
851 for (i = 0; i < nval; i++) {
852 if (items[i].type != ACPI_TYPE_INTEGER)
853 return -EPROTO;
854 if (items[i].integer.value > U8_MAX)
855 return -EOVERFLOW;
856
857 val[i] = items[i].integer.value;
858 }
859 return 0;
860}
861
862static int acpi_copy_property_array_u16(const union acpi_object *items,
863 u16 *val, size_t nval)
864{
865 int i;
866
867 for (i = 0; i < nval; i++) {
868 if (items[i].type != ACPI_TYPE_INTEGER)
869 return -EPROTO;
870 if (items[i].integer.value > U16_MAX)
871 return -EOVERFLOW;
872
873 val[i] = items[i].integer.value;
874 }
875 return 0;
876}
877
878static int acpi_copy_property_array_u32(const union acpi_object *items,
879 u32 *val, size_t nval)
880{
881 int i;
882
883 for (i = 0; i < nval; i++) {
884 if (items[i].type != ACPI_TYPE_INTEGER)
885 return -EPROTO;
886 if (items[i].integer.value > U32_MAX)
887 return -EOVERFLOW;
888
889 val[i] = items[i].integer.value;
890 }
891 return 0;
892}
893
894static int acpi_copy_property_array_u64(const union acpi_object *items,
895 u64 *val, size_t nval)
896{
897 int i;
898
899 for (i = 0; i < nval; i++) {
900 if (items[i].type != ACPI_TYPE_INTEGER)
901 return -EPROTO;
902
903 val[i] = items[i].integer.value;
904 }
905 return 0;
906}
907
908static int acpi_copy_property_array_string(const union acpi_object *items,
909 char **val, size_t nval)
910{
911 int i;
912
913 for (i = 0; i < nval; i++) {
914 if (items[i].type != ACPI_TYPE_STRING)
915 return -EPROTO;
916
917 val[i] = items[i].string.pointer;
918 }
919 return nval;
920}
921
922static int acpi_data_prop_read(const struct acpi_device_data *data,
923 const char *propname,
924 enum dev_prop_type proptype,
925 void *val, size_t nval)
926{
927 const union acpi_object *obj;
928 const union acpi_object *items;
929 int ret;
930
931 if (val && nval == 1) {
932 ret = acpi_data_prop_read_single(data, propname, proptype, val);
933 if (ret >= 0)
934 return ret;
935 }
936
937 ret = acpi_data_get_property_array(data, propname, ACPI_TYPE_ANY, &obj);
938 if (ret)
939 return ret;
940
941 if (!val)
942 return obj->package.count;
943
944 if (proptype != DEV_PROP_STRING && nval > obj->package.count)
945 return -EOVERFLOW;
946 else if (nval <= 0)
947 return -EINVAL;
948
949 items = obj->package.elements;
950
951 switch (proptype) {
952 case DEV_PROP_U8:
953 ret = acpi_copy_property_array_u8(items, (u8 *)val, nval);
954 break;
955 case DEV_PROP_U16:
956 ret = acpi_copy_property_array_u16(items, (u16 *)val, nval);
957 break;
958 case DEV_PROP_U32:
959 ret = acpi_copy_property_array_u32(items, (u32 *)val, nval);
960 break;
961 case DEV_PROP_U64:
962 ret = acpi_copy_property_array_u64(items, (u64 *)val, nval);
963 break;
964 case DEV_PROP_STRING:
965 ret = acpi_copy_property_array_string(
966 items, (char **)val,
967 min_t(u32, nval, obj->package.count));
968 break;
969 default:
970 ret = -EINVAL;
971 break;
972 }
973 return ret;
974}
975
976int acpi_dev_prop_read(const struct acpi_device *adev, const char *propname,
977 enum dev_prop_type proptype, void *val, size_t nval)
978{
979 return adev ? acpi_data_prop_read(&adev->data, propname, proptype, val, nval) : -EINVAL;
980}
981
982
983
984
985
986
987
988
989
990
991
992
993
994int acpi_node_prop_read(const struct fwnode_handle *fwnode,
995 const char *propname, enum dev_prop_type proptype,
996 void *val, size_t nval)
997{
998 return acpi_data_prop_read(acpi_device_data_of_node(fwnode),
999 propname, proptype, val, nval);
1000}
1001
1002
1003
1004
1005
1006
1007struct fwnode_handle *acpi_get_next_subnode(const struct fwnode_handle *fwnode,
1008 struct fwnode_handle *child)
1009{
1010 const struct acpi_device *adev = to_acpi_device_node(fwnode);
1011 const struct list_head *head;
1012 struct list_head *next;
1013
1014 if (!child || is_acpi_device_node(child)) {
1015 struct acpi_device *child_adev;
1016
1017 if (adev)
1018 head = &adev->children;
1019 else
1020 goto nondev;
1021
1022 if (list_empty(head))
1023 goto nondev;
1024
1025 if (child) {
1026 adev = to_acpi_device_node(child);
1027 next = adev->node.next;
1028 if (next == head) {
1029 child = NULL;
1030 goto nondev;
1031 }
1032 child_adev = list_entry(next, struct acpi_device, node);
1033 } else {
1034 child_adev = list_first_entry(head, struct acpi_device,
1035 node);
1036 }
1037 return acpi_fwnode_handle(child_adev);
1038 }
1039
1040 nondev:
1041 if (!child || is_acpi_data_node(child)) {
1042 const struct acpi_data_node *data = to_acpi_data_node(fwnode);
1043 struct acpi_data_node *dn;
1044
1045
1046
1047
1048
1049
1050
1051
1052 adev = to_acpi_device_node(fwnode);
1053 if (adev)
1054 head = &adev->data.subnodes;
1055 else if (data)
1056 head = &data->data.subnodes;
1057 else
1058 return NULL;
1059
1060 if (list_empty(head))
1061 return NULL;
1062
1063 if (child) {
1064 dn = to_acpi_data_node(child);
1065 next = dn->sibling.next;
1066 if (next == head)
1067 return NULL;
1068
1069 dn = list_entry(next, struct acpi_data_node, sibling);
1070 } else {
1071 dn = list_first_entry(head, struct acpi_data_node, sibling);
1072 }
1073 return &dn->fwnode;
1074 }
1075 return NULL;
1076}
1077
1078
1079
1080
1081
1082
1083
1084
1085struct fwnode_handle *acpi_node_get_parent(const struct fwnode_handle *fwnode)
1086{
1087 if (is_acpi_data_node(fwnode)) {
1088
1089 return to_acpi_data_node(fwnode)->parent;
1090 } else if (is_acpi_device_node(fwnode)) {
1091 acpi_handle handle, parent_handle;
1092
1093 handle = to_acpi_device_node(fwnode)->handle;
1094 if (ACPI_SUCCESS(acpi_get_parent(handle, &parent_handle))) {
1095 struct acpi_device *adev;
1096
1097 if (!acpi_bus_get_device(parent_handle, &adev))
1098 return acpi_fwnode_handle(adev);
1099 }
1100 }
1101
1102 return NULL;
1103}
1104
1105
1106
1107
1108
1109static bool is_acpi_graph_node(struct fwnode_handle *fwnode,
1110 const char *str)
1111{
1112 unsigned int len = strlen(str);
1113 const char *name;
1114
1115 if (!len || !is_acpi_data_node(fwnode))
1116 return false;
1117
1118 name = to_acpi_data_node(fwnode)->name;
1119
1120 return (fwnode_property_present(fwnode, "reg") &&
1121 !strncmp(name, str, len) && name[len] == '@') ||
1122 fwnode_property_present(fwnode, str);
1123}
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134static struct fwnode_handle *acpi_graph_get_next_endpoint(
1135 const struct fwnode_handle *fwnode, struct fwnode_handle *prev)
1136{
1137 struct fwnode_handle *port = NULL;
1138 struct fwnode_handle *endpoint;
1139
1140 if (!prev) {
1141 do {
1142 port = fwnode_get_next_child_node(fwnode, port);
1143
1144
1145
1146
1147
1148
1149
1150 if (is_acpi_graph_node(port, "port"))
1151 break;
1152 } while (port);
1153 } else {
1154 port = fwnode_get_parent(prev);
1155 }
1156
1157 if (!port)
1158 return NULL;
1159
1160 endpoint = fwnode_get_next_child_node(port, prev);
1161 while (!endpoint) {
1162 port = fwnode_get_next_child_node(fwnode, port);
1163 if (!port)
1164 break;
1165 if (is_acpi_graph_node(port, "port"))
1166 endpoint = fwnode_get_next_child_node(port, NULL);
1167 }
1168
1169
1170
1171
1172
1173
1174
1175
1176 if (!is_acpi_graph_node(endpoint, "endpoint"))
1177 return NULL;
1178
1179 return endpoint;
1180}
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191static struct fwnode_handle *acpi_graph_get_child_prop_value(
1192 const struct fwnode_handle *fwnode, const char *prop_name,
1193 unsigned int val)
1194{
1195 struct fwnode_handle *child;
1196
1197 fwnode_for_each_child_node(fwnode, child) {
1198 u32 nr;
1199
1200 if (fwnode_property_read_u32(child, prop_name, &nr))
1201 continue;
1202
1203 if (val == nr)
1204 return child;
1205 }
1206
1207 return NULL;
1208}
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218static struct fwnode_handle *
1219acpi_graph_get_remote_endpoint(const struct fwnode_handle *__fwnode)
1220{
1221 struct fwnode_handle *fwnode;
1222 unsigned int port_nr, endpoint_nr;
1223 struct fwnode_reference_args args;
1224 int ret;
1225
1226 memset(&args, 0, sizeof(args));
1227 ret = acpi_node_get_property_reference(__fwnode, "remote-endpoint", 0,
1228 &args);
1229 if (ret)
1230 return NULL;
1231
1232
1233 if (!is_acpi_device_node(args.fwnode))
1234 return args.nargs ? NULL : args.fwnode;
1235
1236
1237
1238
1239
1240 if (args.nargs != 2)
1241 return NULL;
1242
1243 fwnode = args.fwnode;
1244 port_nr = args.args[0];
1245 endpoint_nr = args.args[1];
1246
1247 fwnode = acpi_graph_get_child_prop_value(fwnode, "port", port_nr);
1248
1249 return acpi_graph_get_child_prop_value(fwnode, "endpoint", endpoint_nr);
1250}
1251
1252static bool acpi_fwnode_device_is_available(const struct fwnode_handle *fwnode)
1253{
1254 if (!is_acpi_device_node(fwnode))
1255 return false;
1256
1257 return acpi_device_is_present(to_acpi_device_node(fwnode));
1258}
1259
1260static bool acpi_fwnode_property_present(const struct fwnode_handle *fwnode,
1261 const char *propname)
1262{
1263 return !acpi_node_prop_get(fwnode, propname, NULL);
1264}
1265
1266static int
1267acpi_fwnode_property_read_int_array(const struct fwnode_handle *fwnode,
1268 const char *propname,
1269 unsigned int elem_size, void *val,
1270 size_t nval)
1271{
1272 enum dev_prop_type type;
1273
1274 switch (elem_size) {
1275 case sizeof(u8):
1276 type = DEV_PROP_U8;
1277 break;
1278 case sizeof(u16):
1279 type = DEV_PROP_U16;
1280 break;
1281 case sizeof(u32):
1282 type = DEV_PROP_U32;
1283 break;
1284 case sizeof(u64):
1285 type = DEV_PROP_U64;
1286 break;
1287 default:
1288 return -ENXIO;
1289 }
1290
1291 return acpi_node_prop_read(fwnode, propname, type, val, nval);
1292}
1293
1294static int
1295acpi_fwnode_property_read_string_array(const struct fwnode_handle *fwnode,
1296 const char *propname, const char **val,
1297 size_t nval)
1298{
1299 return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,
1300 val, nval);
1301}
1302
1303static int
1304acpi_fwnode_get_reference_args(const struct fwnode_handle *fwnode,
1305 const char *prop, const char *nargs_prop,
1306 unsigned int args_count, unsigned int index,
1307 struct fwnode_reference_args *args)
1308{
1309 return __acpi_node_get_property_reference(fwnode, prop, index,
1310 args_count, args);
1311}
1312
1313static const char *acpi_fwnode_get_name(const struct fwnode_handle *fwnode)
1314{
1315 const struct acpi_device *adev;
1316 struct fwnode_handle *parent;
1317
1318
1319 parent = fwnode_get_parent(fwnode);
1320 if (!parent)
1321 return "\\";
1322
1323 fwnode_handle_put(parent);
1324
1325 if (is_acpi_data_node(fwnode)) {
1326 const struct acpi_data_node *dn = to_acpi_data_node(fwnode);
1327
1328 return dn->name;
1329 }
1330
1331 adev = to_acpi_device_node(fwnode);
1332 if (WARN_ON(!adev))
1333 return NULL;
1334
1335 return acpi_device_bid(adev);
1336}
1337
1338static const char *
1339acpi_fwnode_get_name_prefix(const struct fwnode_handle *fwnode)
1340{
1341 struct fwnode_handle *parent;
1342
1343
1344 parent = fwnode_get_parent(fwnode);
1345 if (!parent)
1346 return "";
1347
1348
1349 parent = fwnode_get_next_parent(parent);
1350 if (!parent)
1351 return "";
1352
1353 fwnode_handle_put(parent);
1354
1355
1356 return ".";
1357}
1358
1359static struct fwnode_handle *
1360acpi_fwnode_get_parent(struct fwnode_handle *fwnode)
1361{
1362 return acpi_node_get_parent(fwnode);
1363}
1364
1365static int acpi_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode,
1366 struct fwnode_endpoint *endpoint)
1367{
1368 struct fwnode_handle *port_fwnode = fwnode_get_parent(fwnode);
1369
1370 endpoint->local_fwnode = fwnode;
1371
1372 if (fwnode_property_read_u32(port_fwnode, "reg", &endpoint->port))
1373 fwnode_property_read_u32(port_fwnode, "port", &endpoint->port);
1374 if (fwnode_property_read_u32(fwnode, "reg", &endpoint->id))
1375 fwnode_property_read_u32(fwnode, "endpoint", &endpoint->id);
1376
1377 return 0;
1378}
1379
1380static const void *
1381acpi_fwnode_device_get_match_data(const struct fwnode_handle *fwnode,
1382 const struct device *dev)
1383{
1384 return acpi_device_get_match_data(dev);
1385}
1386
1387#define DECLARE_ACPI_FWNODE_OPS(ops) \
1388 const struct fwnode_operations ops = { \
1389 .device_is_available = acpi_fwnode_device_is_available, \
1390 .device_get_match_data = acpi_fwnode_device_get_match_data, \
1391 .property_present = acpi_fwnode_property_present, \
1392 .property_read_int_array = \
1393 acpi_fwnode_property_read_int_array, \
1394 .property_read_string_array = \
1395 acpi_fwnode_property_read_string_array, \
1396 .get_parent = acpi_node_get_parent, \
1397 .get_next_child_node = acpi_get_next_subnode, \
1398 .get_named_child_node = acpi_fwnode_get_named_child_node, \
1399 .get_name = acpi_fwnode_get_name, \
1400 .get_name_prefix = acpi_fwnode_get_name_prefix, \
1401 .get_reference_args = acpi_fwnode_get_reference_args, \
1402 .graph_get_next_endpoint = \
1403 acpi_graph_get_next_endpoint, \
1404 .graph_get_remote_endpoint = \
1405 acpi_graph_get_remote_endpoint, \
1406 .graph_get_port_parent = acpi_fwnode_get_parent, \
1407 .graph_parse_endpoint = acpi_fwnode_graph_parse_endpoint, \
1408 }; \
1409 EXPORT_SYMBOL_GPL(ops)
1410
1411DECLARE_ACPI_FWNODE_OPS(acpi_device_fwnode_ops);
1412DECLARE_ACPI_FWNODE_OPS(acpi_data_fwnode_ops);
1413const struct fwnode_operations acpi_static_fwnode_ops;
1414
1415bool is_acpi_device_node(const struct fwnode_handle *fwnode)
1416{
1417 return !IS_ERR_OR_NULL(fwnode) &&
1418 fwnode->ops == &acpi_device_fwnode_ops;
1419}
1420EXPORT_SYMBOL(is_acpi_device_node);
1421
1422bool is_acpi_data_node(const struct fwnode_handle *fwnode)
1423{
1424 return !IS_ERR_OR_NULL(fwnode) && fwnode->ops == &acpi_data_fwnode_ops;
1425}
1426EXPORT_SYMBOL(is_acpi_data_node);
1427