1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <linux/ctype.h>
21#include <linux/module.h>
22#include <linux/of.h>
23#include <linux/spinlock.h>
24#include <linux/slab.h>
25#include <linux/proc_fs.h>
26
27
28
29
30
31
32
33
34
35
36
37
38struct alias_prop {
39 struct list_head link;
40 const char *alias;
41 struct device_node *np;
42 int id;
43 char stem[0];
44};
45
46static LIST_HEAD(aliases_lookup);
47
48struct device_node *allnodes;
49struct device_node *of_chosen;
50struct device_node *of_aliases;
51
52static DEFINE_MUTEX(of_aliases_mutex);
53
54
55
56
57DEFINE_RWLOCK(devtree_lock);
58
59int of_n_addr_cells(struct device_node *np)
60{
61 const __be32 *ip;
62
63 do {
64 if (np->parent)
65 np = np->parent;
66 ip = of_get_property(np, "#address-cells", NULL);
67 if (ip)
68 return be32_to_cpup(ip);
69 } while (np->parent);
70
71 return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
72}
73EXPORT_SYMBOL(of_n_addr_cells);
74
75int of_n_size_cells(struct device_node *np)
76{
77 const __be32 *ip;
78
79 do {
80 if (np->parent)
81 np = np->parent;
82 ip = of_get_property(np, "#size-cells", NULL);
83 if (ip)
84 return be32_to_cpup(ip);
85 } while (np->parent);
86
87 return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
88}
89EXPORT_SYMBOL(of_n_size_cells);
90
91#if !defined(CONFIG_SPARC)
92
93
94
95
96
97
98
99struct device_node *of_node_get(struct device_node *node)
100{
101 if (node)
102 kref_get(&node->kref);
103 return node;
104}
105EXPORT_SYMBOL(of_node_get);
106
107static inline struct device_node *kref_to_device_node(struct kref *kref)
108{
109 return container_of(kref, struct device_node, kref);
110}
111
112
113
114
115
116
117
118
119static void of_node_release(struct kref *kref)
120{
121 struct device_node *node = kref_to_device_node(kref);
122 struct property *prop = node->properties;
123
124
125 if (!of_node_check_flag(node, OF_DETACHED)) {
126 pr_err("ERROR: Bad of_node_put() on %s\n", node->full_name);
127 dump_stack();
128 kref_init(&node->kref);
129 return;
130 }
131
132 if (!of_node_check_flag(node, OF_DYNAMIC))
133 return;
134
135 while (prop) {
136 struct property *next = prop->next;
137 kfree(prop->name);
138 kfree(prop->value);
139 kfree(prop);
140 prop = next;
141
142 if (!prop) {
143 prop = node->deadprops;
144 node->deadprops = NULL;
145 }
146 }
147 kfree(node->full_name);
148 kfree(node->data);
149 kfree(node);
150}
151
152
153
154
155
156
157
158void of_node_put(struct device_node *node)
159{
160 if (node)
161 kref_put(&node->kref, of_node_release);
162}
163EXPORT_SYMBOL(of_node_put);
164#endif
165
166struct property *of_find_property(const struct device_node *np,
167 const char *name,
168 int *lenp)
169{
170 struct property *pp;
171
172 if (!np)
173 return NULL;
174
175 read_lock(&devtree_lock);
176 for (pp = np->properties; pp != 0; pp = pp->next) {
177 if (of_prop_cmp(pp->name, name) == 0) {
178 if (lenp != 0)
179 *lenp = pp->length;
180 break;
181 }
182 }
183 read_unlock(&devtree_lock);
184
185 return pp;
186}
187EXPORT_SYMBOL(of_find_property);
188
189
190
191
192
193
194
195
196
197struct device_node *of_find_all_nodes(struct device_node *prev)
198{
199 struct device_node *np;
200
201 read_lock(&devtree_lock);
202 np = prev ? prev->allnext : allnodes;
203 for (; np != NULL; np = np->allnext)
204 if (of_node_get(np))
205 break;
206 of_node_put(prev);
207 read_unlock(&devtree_lock);
208 return np;
209}
210EXPORT_SYMBOL(of_find_all_nodes);
211
212
213
214
215
216const void *of_get_property(const struct device_node *np, const char *name,
217 int *lenp)
218{
219 struct property *pp = of_find_property(np, name, lenp);
220
221 return pp ? pp->value : NULL;
222}
223EXPORT_SYMBOL(of_get_property);
224
225
226
227
228int of_device_is_compatible(const struct device_node *device,
229 const char *compat)
230{
231 const char* cp;
232 int cplen, l;
233
234 cp = of_get_property(device, "compatible", &cplen);
235 if (cp == NULL)
236 return 0;
237 while (cplen > 0) {
238 if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
239 return 1;
240 l = strlen(cp) + 1;
241 cp += l;
242 cplen -= l;
243 }
244
245 return 0;
246}
247EXPORT_SYMBOL(of_device_is_compatible);
248
249
250
251
252
253
254
255
256int of_machine_is_compatible(const char *compat)
257{
258 struct device_node *root;
259 int rc = 0;
260
261 root = of_find_node_by_path("/");
262 if (root) {
263 rc = of_device_is_compatible(root, compat);
264 of_node_put(root);
265 }
266 return rc;
267}
268EXPORT_SYMBOL(of_machine_is_compatible);
269
270
271
272
273
274
275
276
277
278int of_device_is_available(const struct device_node *device)
279{
280 const char *status;
281 int statlen;
282
283 status = of_get_property(device, "status", &statlen);
284 if (status == NULL)
285 return 1;
286
287 if (statlen > 0) {
288 if (!strcmp(status, "okay") || !strcmp(status, "ok"))
289 return 1;
290 }
291
292 return 0;
293}
294EXPORT_SYMBOL(of_device_is_available);
295
296
297
298
299
300
301
302
303struct device_node *of_get_parent(const struct device_node *node)
304{
305 struct device_node *np;
306
307 if (!node)
308 return NULL;
309
310 read_lock(&devtree_lock);
311 np = of_node_get(node->parent);
312 read_unlock(&devtree_lock);
313 return np;
314}
315EXPORT_SYMBOL(of_get_parent);
316
317
318
319
320
321
322
323
324
325
326
327
328struct device_node *of_get_next_parent(struct device_node *node)
329{
330 struct device_node *parent;
331
332 if (!node)
333 return NULL;
334
335 read_lock(&devtree_lock);
336 parent = of_node_get(node->parent);
337 of_node_put(node);
338 read_unlock(&devtree_lock);
339 return parent;
340}
341
342
343
344
345
346
347
348
349
350struct device_node *of_get_next_child(const struct device_node *node,
351 struct device_node *prev)
352{
353 struct device_node *next;
354
355 read_lock(&devtree_lock);
356 next = prev ? prev->sibling : node->child;
357 for (; next; next = next->sibling)
358 if (of_node_get(next))
359 break;
360 of_node_put(prev);
361 read_unlock(&devtree_lock);
362 return next;
363}
364EXPORT_SYMBOL(of_get_next_child);
365
366
367
368
369
370
371
372
373struct device_node *of_find_node_by_path(const char *path)
374{
375 struct device_node *np = allnodes;
376
377 read_lock(&devtree_lock);
378 for (; np; np = np->allnext) {
379 if (np->full_name && (of_node_cmp(np->full_name, path) == 0)
380 && of_node_get(np))
381 break;
382 }
383 read_unlock(&devtree_lock);
384 return np;
385}
386EXPORT_SYMBOL(of_find_node_by_path);
387
388
389
390
391
392
393
394
395
396
397
398
399struct device_node *of_find_node_by_name(struct device_node *from,
400 const char *name)
401{
402 struct device_node *np;
403
404 read_lock(&devtree_lock);
405 np = from ? from->allnext : allnodes;
406 for (; np; np = np->allnext)
407 if (np->name && (of_node_cmp(np->name, name) == 0)
408 && of_node_get(np))
409 break;
410 of_node_put(from);
411 read_unlock(&devtree_lock);
412 return np;
413}
414EXPORT_SYMBOL(of_find_node_by_name);
415
416
417
418
419
420
421
422
423
424
425
426
427
428struct device_node *of_find_node_by_type(struct device_node *from,
429 const char *type)
430{
431 struct device_node *np;
432
433 read_lock(&devtree_lock);
434 np = from ? from->allnext : allnodes;
435 for (; np; np = np->allnext)
436 if (np->type && (of_node_cmp(np->type, type) == 0)
437 && of_node_get(np))
438 break;
439 of_node_put(from);
440 read_unlock(&devtree_lock);
441 return np;
442}
443EXPORT_SYMBOL(of_find_node_by_type);
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459struct device_node *of_find_compatible_node(struct device_node *from,
460 const char *type, const char *compatible)
461{
462 struct device_node *np;
463
464 read_lock(&devtree_lock);
465 np = from ? from->allnext : allnodes;
466 for (; np; np = np->allnext) {
467 if (type
468 && !(np->type && (of_node_cmp(np->type, type) == 0)))
469 continue;
470 if (of_device_is_compatible(np, compatible) && of_node_get(np))
471 break;
472 }
473 of_node_put(from);
474 read_unlock(&devtree_lock);
475 return np;
476}
477EXPORT_SYMBOL(of_find_compatible_node);
478
479
480
481
482
483
484
485
486
487
488
489
490
491struct device_node *of_find_node_with_property(struct device_node *from,
492 const char *prop_name)
493{
494 struct device_node *np;
495 struct property *pp;
496
497 read_lock(&devtree_lock);
498 np = from ? from->allnext : allnodes;
499 for (; np; np = np->allnext) {
500 for (pp = np->properties; pp != 0; pp = pp->next) {
501 if (of_prop_cmp(pp->name, prop_name) == 0) {
502 of_node_get(np);
503 goto out;
504 }
505 }
506 }
507out:
508 of_node_put(from);
509 read_unlock(&devtree_lock);
510 return np;
511}
512EXPORT_SYMBOL(of_find_node_with_property);
513
514
515
516
517
518
519
520
521const struct of_device_id *of_match_node(const struct of_device_id *matches,
522 const struct device_node *node)
523{
524 if (!matches)
525 return NULL;
526
527 while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
528 int match = 1;
529 if (matches->name[0])
530 match &= node->name
531 && !strcmp(matches->name, node->name);
532 if (matches->type[0])
533 match &= node->type
534 && !strcmp(matches->type, node->type);
535 if (matches->compatible[0])
536 match &= of_device_is_compatible(node,
537 matches->compatible);
538 if (match)
539 return matches;
540 matches++;
541 }
542 return NULL;
543}
544EXPORT_SYMBOL(of_match_node);
545
546
547
548
549
550
551
552
553
554
555
556
557
558struct device_node *of_find_matching_node(struct device_node *from,
559 const struct of_device_id *matches)
560{
561 struct device_node *np;
562
563 read_lock(&devtree_lock);
564 np = from ? from->allnext : allnodes;
565 for (; np; np = np->allnext) {
566 if (of_match_node(matches, np) && of_node_get(np))
567 break;
568 }
569 of_node_put(from);
570 read_unlock(&devtree_lock);
571 return np;
572}
573EXPORT_SYMBOL(of_find_matching_node);
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588int of_modalias_node(struct device_node *node, char *modalias, int len)
589{
590 const char *compatible, *p;
591 int cplen;
592
593 compatible = of_get_property(node, "compatible", &cplen);
594 if (!compatible || strlen(compatible) > cplen)
595 return -ENODEV;
596 p = strchr(compatible, ',');
597 strlcpy(modalias, p ? p + 1 : compatible, len);
598 return 0;
599}
600EXPORT_SYMBOL_GPL(of_modalias_node);
601
602
603
604
605
606
607
608
609struct device_node *of_find_node_by_phandle(phandle handle)
610{
611 struct device_node *np;
612
613 read_lock(&devtree_lock);
614 for (np = allnodes; np; np = np->allnext)
615 if (np->phandle == handle)
616 break;
617 of_node_get(np);
618 read_unlock(&devtree_lock);
619 return np;
620}
621EXPORT_SYMBOL(of_find_node_by_phandle);
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638int of_property_read_u32_array(const struct device_node *np,
639 const char *propname, u32 *out_values,
640 size_t sz)
641{
642 struct property *prop = of_find_property(np, propname, NULL);
643 const __be32 *val;
644
645 if (!prop)
646 return -EINVAL;
647 if (!prop->value)
648 return -ENODATA;
649 if ((sz * sizeof(*out_values)) > prop->length)
650 return -EOVERFLOW;
651
652 val = prop->value;
653 while (sz--)
654 *out_values++ = be32_to_cpup(val++);
655 return 0;
656}
657EXPORT_SYMBOL_GPL(of_property_read_u32_array);
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672int of_property_read_u64(const struct device_node *np, const char *propname,
673 u64 *out_value)
674{
675 struct property *prop = of_find_property(np, propname, NULL);
676
677 if (!prop)
678 return -EINVAL;
679 if (!prop->value)
680 return -ENODATA;
681 if (sizeof(*out_value) > prop->length)
682 return -EOVERFLOW;
683 *out_value = of_read_number(prop->value, 2);
684 return 0;
685}
686EXPORT_SYMBOL_GPL(of_property_read_u64);
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703int of_property_read_string(struct device_node *np, const char *propname,
704 const char **out_string)
705{
706 struct property *prop = of_find_property(np, propname, NULL);
707 if (!prop)
708 return -EINVAL;
709 if (!prop->value)
710 return -ENODATA;
711 if (strnlen(prop->value, prop->length) >= prop->length)
712 return -EILSEQ;
713 *out_string = prop->value;
714 return 0;
715}
716EXPORT_SYMBOL_GPL(of_property_read_string);
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736int of_property_read_string_index(struct device_node *np, const char *propname,
737 int index, const char **output)
738{
739 struct property *prop = of_find_property(np, propname, NULL);
740 int i = 0;
741 size_t l = 0, total = 0;
742 const char *p;
743
744 if (!prop)
745 return -EINVAL;
746 if (!prop->value)
747 return -ENODATA;
748 if (strnlen(prop->value, prop->length) >= prop->length)
749 return -EILSEQ;
750
751 p = prop->value;
752
753 for (i = 0; total < prop->length; total += l, p += l) {
754 l = strlen(p) + 1;
755 if ((*p != 0) && (i++ == index)) {
756 *output = p;
757 return 0;
758 }
759 }
760 return -ENODATA;
761}
762EXPORT_SYMBOL_GPL(of_property_read_string_index);
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777int of_property_count_strings(struct device_node *np, const char *propname)
778{
779 struct property *prop = of_find_property(np, propname, NULL);
780 int i = 0;
781 size_t l = 0, total = 0;
782 const char *p;
783
784 if (!prop)
785 return -EINVAL;
786 if (!prop->value)
787 return -ENODATA;
788 if (strnlen(prop->value, prop->length) >= prop->length)
789 return -EILSEQ;
790
791 p = prop->value;
792
793 for (i = 0; total < prop->length; total += l, p += l) {
794 l = strlen(p) + 1;
795 if (*p != 0)
796 i++;
797 }
798 return i;
799}
800EXPORT_SYMBOL_GPL(of_property_count_strings);
801
802
803
804
805
806
807
808
809
810
811
812struct device_node *
813of_parse_phandle(struct device_node *np, const char *phandle_name, int index)
814{
815 const __be32 *phandle;
816 int size;
817
818 phandle = of_get_property(np, phandle_name, &size);
819 if ((!phandle) || (size < sizeof(*phandle) * (index + 1)))
820 return NULL;
821
822 return of_find_node_by_phandle(be32_to_cpup(phandle + index));
823}
824EXPORT_SYMBOL(of_parse_phandle);
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856int of_parse_phandles_with_args(struct device_node *np, const char *list_name,
857 const char *cells_name, int index,
858 struct device_node **out_node,
859 const void **out_args)
860{
861 int ret = -EINVAL;
862 const __be32 *list;
863 const __be32 *list_end;
864 int size;
865 int cur_index = 0;
866 struct device_node *node = NULL;
867 const void *args = NULL;
868
869 list = of_get_property(np, list_name, &size);
870 if (!list) {
871 ret = -ENOENT;
872 goto err0;
873 }
874 list_end = list + size / sizeof(*list);
875
876 while (list < list_end) {
877 const __be32 *cells;
878 phandle phandle;
879
880 phandle = be32_to_cpup(list++);
881 args = list;
882
883
884 if (!phandle)
885 goto next;
886
887 node = of_find_node_by_phandle(phandle);
888 if (!node) {
889 pr_debug("%s: could not find phandle\n",
890 np->full_name);
891 goto err0;
892 }
893
894 cells = of_get_property(node, cells_name, &size);
895 if (!cells || size != sizeof(*cells)) {
896 pr_debug("%s: could not get %s for %s\n",
897 np->full_name, cells_name, node->full_name);
898 goto err1;
899 }
900
901 list += be32_to_cpup(cells);
902 if (list > list_end) {
903 pr_debug("%s: insufficient arguments length\n",
904 np->full_name);
905 goto err1;
906 }
907next:
908 if (cur_index == index)
909 break;
910
911 of_node_put(node);
912 node = NULL;
913 args = NULL;
914 cur_index++;
915 }
916
917 if (!node) {
918
919
920
921
922 if (args)
923 ret = -EEXIST;
924 else
925 ret = -ENOENT;
926 goto err0;
927 }
928
929 if (out_node)
930 *out_node = node;
931 if (out_args)
932 *out_args = args;
933
934 return 0;
935err1:
936 of_node_put(node);
937err0:
938 pr_debug("%s failed with status %d\n", __func__, ret);
939 return ret;
940}
941EXPORT_SYMBOL(of_parse_phandles_with_args);
942
943
944
945
946int prom_add_property(struct device_node *np, struct property *prop)
947{
948 struct property **next;
949 unsigned long flags;
950
951 prop->next = NULL;
952 write_lock_irqsave(&devtree_lock, flags);
953 next = &np->properties;
954 while (*next) {
955 if (strcmp(prop->name, (*next)->name) == 0) {
956
957 write_unlock_irqrestore(&devtree_lock, flags);
958 return -1;
959 }
960 next = &(*next)->next;
961 }
962 *next = prop;
963 write_unlock_irqrestore(&devtree_lock, flags);
964
965#ifdef CONFIG_PROC_DEVICETREE
966
967 if (np->pde)
968 proc_device_tree_add_prop(np->pde, prop);
969#endif
970
971 return 0;
972}
973
974
975
976
977
978
979
980
981
982int prom_remove_property(struct device_node *np, struct property *prop)
983{
984 struct property **next;
985 unsigned long flags;
986 int found = 0;
987
988 write_lock_irqsave(&devtree_lock, flags);
989 next = &np->properties;
990 while (*next) {
991 if (*next == prop) {
992
993 *next = prop->next;
994 prop->next = np->deadprops;
995 np->deadprops = prop;
996 found = 1;
997 break;
998 }
999 next = &(*next)->next;
1000 }
1001 write_unlock_irqrestore(&devtree_lock, flags);
1002
1003 if (!found)
1004 return -ENODEV;
1005
1006#ifdef CONFIG_PROC_DEVICETREE
1007
1008 if (np->pde)
1009 proc_device_tree_remove_prop(np->pde, prop);
1010#endif
1011
1012 return 0;
1013}
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023int prom_update_property(struct device_node *np,
1024 struct property *newprop,
1025 struct property *oldprop)
1026{
1027 struct property **next;
1028 unsigned long flags;
1029 int found = 0;
1030
1031 write_lock_irqsave(&devtree_lock, flags);
1032 next = &np->properties;
1033 while (*next) {
1034 if (*next == oldprop) {
1035
1036 newprop->next = oldprop->next;
1037 *next = newprop;
1038 oldprop->next = np->deadprops;
1039 np->deadprops = oldprop;
1040 found = 1;
1041 break;
1042 }
1043 next = &(*next)->next;
1044 }
1045 write_unlock_irqrestore(&devtree_lock, flags);
1046
1047 if (!found)
1048 return -ENODEV;
1049
1050#ifdef CONFIG_PROC_DEVICETREE
1051
1052 if (np->pde)
1053 proc_device_tree_update_prop(np->pde, newprop, oldprop);
1054#endif
1055
1056 return 0;
1057}
1058
1059#if defined(CONFIG_OF_DYNAMIC)
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071void of_attach_node(struct device_node *np)
1072{
1073 unsigned long flags;
1074
1075 write_lock_irqsave(&devtree_lock, flags);
1076 np->sibling = np->parent->child;
1077 np->allnext = allnodes;
1078 np->parent->child = np;
1079 allnodes = np;
1080 write_unlock_irqrestore(&devtree_lock, flags);
1081}
1082
1083
1084
1085
1086
1087
1088
1089void of_detach_node(struct device_node *np)
1090{
1091 struct device_node *parent;
1092 unsigned long flags;
1093
1094 write_lock_irqsave(&devtree_lock, flags);
1095
1096 parent = np->parent;
1097 if (!parent)
1098 goto out_unlock;
1099
1100 if (allnodes == np)
1101 allnodes = np->allnext;
1102 else {
1103 struct device_node *prev;
1104 for (prev = allnodes;
1105 prev->allnext != np;
1106 prev = prev->allnext)
1107 ;
1108 prev->allnext = np->allnext;
1109 }
1110
1111 if (parent->child == np)
1112 parent->child = np->sibling;
1113 else {
1114 struct device_node *prevsib;
1115 for (prevsib = np->parent->child;
1116 prevsib->sibling != np;
1117 prevsib = prevsib->sibling)
1118 ;
1119 prevsib->sibling = np->sibling;
1120 }
1121
1122 of_node_set_flag(np, OF_DETACHED);
1123
1124out_unlock:
1125 write_unlock_irqrestore(&devtree_lock, flags);
1126}
1127#endif
1128
1129static void of_alias_add(struct alias_prop *ap, struct device_node *np,
1130 int id, const char *stem, int stem_len)
1131{
1132 ap->np = np;
1133 ap->id = id;
1134 strncpy(ap->stem, stem, stem_len);
1135 ap->stem[stem_len] = 0;
1136 list_add_tail(&ap->link, &aliases_lookup);
1137 pr_debug("adding DT alias:%s: stem=%s id=%i node=%s\n",
1138 ap->alias, ap->stem, ap->id, np ? np->full_name : NULL);
1139}
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))
1152{
1153 struct property *pp;
1154
1155 of_chosen = of_find_node_by_path("/chosen");
1156 if (of_chosen == NULL)
1157 of_chosen = of_find_node_by_path("/chosen@0");
1158 of_aliases = of_find_node_by_path("/aliases");
1159 if (!of_aliases)
1160 return;
1161
1162 for_each_property(pp, of_aliases->properties) {
1163 const char *start = pp->name;
1164 const char *end = start + strlen(start);
1165 struct device_node *np;
1166 struct alias_prop *ap;
1167 int id, len;
1168
1169
1170 if (!strcmp(pp->name, "name") ||
1171 !strcmp(pp->name, "phandle") ||
1172 !strcmp(pp->name, "linux,phandle"))
1173 continue;
1174
1175 np = of_find_node_by_path(pp->value);
1176 if (!np)
1177 continue;
1178
1179
1180
1181 while (isdigit(*(end-1)) && end > start)
1182 end--;
1183 len = end - start;
1184
1185 if (kstrtoint(end, 10, &id) < 0)
1186 continue;
1187
1188
1189 ap = dt_alloc(sizeof(*ap) + len + 1, 4);
1190 if (!ap)
1191 continue;
1192 ap->alias = start;
1193 of_alias_add(ap, np, id, start, len);
1194 }
1195}
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205int of_alias_get_id(struct device_node *np, const char *stem)
1206{
1207 struct alias_prop *app;
1208 int id = -ENODEV;
1209
1210 mutex_lock(&of_aliases_mutex);
1211 list_for_each_entry(app, &aliases_lookup, link) {
1212 if (strcmp(app->stem, stem) != 0)
1213 continue;
1214
1215 if (np == app->np) {
1216 id = app->id;
1217 break;
1218 }
1219 }
1220 mutex_unlock(&of_aliases_mutex);
1221
1222 return id;
1223}
1224EXPORT_SYMBOL_GPL(of_alias_get_id);
1225