1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <sys/promif.h>
30 #include <sys/promimpl.h>
31 #include <sys/prom_emul.h>
32 #include <sys/obpdefs.h>
33 #include <sys/sunddi.h>
34
35 static prom_node_t *promif_top;
36
37 static prom_node_t *promif_find_node(pnode_t nodeid);
38 static int getproplen(prom_node_t *pnp, char *name);
39 static void *getprop(prom_node_t *pnp, char *name);
40
41 static void
promif_create_prop(prom_node_t * pnp,char * name,void * val,int len,int flags)42 promif_create_prop(prom_node_t *pnp, char *name, void *val, int len, int flags)
43 {
44 struct prom_prop *p, *q;
45
46 q = kmem_zalloc(sizeof (*q), KM_SLEEP);
47 q->pp_name = kmem_zalloc(strlen(name) + 1, KM_SLEEP);
48 (void) strcpy(q->pp_name, name);
49 q->pp_val = kmem_alloc(len, KM_SLEEP);
50 q->pp_len = len;
51 switch (flags) {
52 case DDI_PROP_TYPE_INT:
53 case DDI_PROP_TYPE_INT64:
54 /*
55 * Technically, we need byte-swapping to conform to 1275.
56 * However, the old x86 prom simulator used little endian
57 * representation, so we don't swap here either.
58 *
59 * NOTE: this is inconsistent with ddi_prop_lookup_*()
60 * which does byte-swapping when looking up prom properties.
61 * Since all kernel nodes are SID nodes, drivers no longer
62 * access PROM properties on x86.
63 */
64 default: /* no byte swapping */
65 (void) bcopy(val, q->pp_val, len);
66 break;
67 }
68
69 if (pnp->pn_propp == NULL) {
70 pnp->pn_propp = q;
71 return;
72 }
73
74 for (p = pnp->pn_propp; p->pp_next != NULL; p = p->pp_next)
75 /* empty */;
76
77 p->pp_next = q;
78 }
79
80 static prom_node_t *
promif_create_node(dev_info_t * dip)81 promif_create_node(dev_info_t *dip)
82 {
83 prom_node_t *pnp;
84 ddi_prop_t *hwprop;
85 char *nodename;
86
87 pnp = kmem_zalloc(sizeof (prom_node_t), KM_SLEEP);
88 pnp->pn_nodeid = DEVI(dip)->devi_nodeid;
89
90 hwprop = DEVI(dip)->devi_hw_prop_ptr;
91 while (hwprop != NULL) {
92 /* need to encode to proper endianness */
93 promif_create_prop(pnp, hwprop->prop_name, hwprop->prop_val,
94 hwprop->prop_len, hwprop->prop_flags & DDI_PROP_TYPE_MASK);
95 hwprop = hwprop->prop_next;
96 }
97 nodename = ddi_node_name(dip);
98 promif_create_prop(pnp, "name", nodename, strlen(nodename) + 1,
99 DDI_PROP_TYPE_STRING);
100
101 return (pnp);
102 }
103
104 static void promif_create_children(prom_node_t *, dev_info_t *);
105
106 static void
promif_create_peers(prom_node_t * pnp,dev_info_t * dip)107 promif_create_peers(prom_node_t *pnp, dev_info_t *dip)
108 {
109 dev_info_t *ndip = ddi_get_next_sibling(dip);
110
111 while (ndip) {
112 pnp->pn_sibling = promif_create_node(ndip);
113 promif_create_children(pnp->pn_sibling, ndip);
114 pnp = pnp->pn_sibling;
115 ndip = ddi_get_next_sibling(ndip);
116 }
117 }
118
119 static void
promif_create_children(prom_node_t * pnp,dev_info_t * dip)120 promif_create_children(prom_node_t *pnp, dev_info_t *dip)
121 {
122 dev_info_t *cdip = ddi_get_child(dip);
123
124 while (cdip) {
125 pnp->pn_child = promif_create_node(cdip);
126 promif_create_peers(pnp->pn_child, cdip);
127 pnp = pnp->pn_child;
128 cdip = ddi_get_child(cdip);
129 }
130 }
131
132 void
promif_create_device_tree(void)133 promif_create_device_tree(void)
134 {
135 promif_top = promif_create_node(ddi_root_node());
136 promif_create_children(promif_top, ddi_root_node());
137 }
138
139 static prom_node_t *
find_node_work(prom_node_t * pnp,pnode_t n)140 find_node_work(prom_node_t *pnp, pnode_t n)
141 {
142 prom_node_t *qnp;
143
144 if (pnp->pn_nodeid == n)
145 return (pnp);
146
147 if (pnp->pn_child)
148 if ((qnp = find_node_work(pnp->pn_child, n)) != NULL)
149 return (qnp);
150
151 if (pnp->pn_sibling)
152 if ((qnp = find_node_work(pnp->pn_sibling, n)) != NULL)
153 return (qnp);
154
155 return (NULL);
156 }
157
158 static prom_node_t *
promif_find_node(pnode_t nodeid)159 promif_find_node(pnode_t nodeid)
160 {
161 if (nodeid == OBP_NONODE)
162 return (promif_top);
163
164 if (promif_top == NULL)
165 return (NULL);
166
167 return (find_node_work(promif_top, nodeid));
168 }
169
170 pnode_t
promif_nextnode(pnode_t nodeid)171 promif_nextnode(pnode_t nodeid)
172 {
173 prom_node_t *pnp;
174
175 /*
176 * Note: next(0) returns the root node
177 */
178 pnp = promif_find_node(nodeid);
179 if (pnp && (nodeid == OBP_NONODE))
180 return (pnp->pn_nodeid);
181 if (pnp && pnp->pn_sibling)
182 return (pnp->pn_sibling->pn_nodeid);
183
184 return (OBP_NONODE);
185 }
186
187 pnode_t
promif_childnode(pnode_t nodeid)188 promif_childnode(pnode_t nodeid)
189 {
190 prom_node_t *pnp;
191
192 pnp = promif_find_node(nodeid);
193 if (pnp && pnp->pn_child)
194 return (pnp->pn_child->pn_nodeid);
195
196 return (OBP_NONODE);
197 }
198
199 /*
200 * Retrieve a PROM property (len and value)
201 */
202
203 static int
getproplen(prom_node_t * pnp,char * name)204 getproplen(prom_node_t *pnp, char *name)
205 {
206 struct prom_prop *propp;
207
208 for (propp = pnp->pn_propp; propp != NULL; propp = propp->pp_next)
209 if (strcmp(propp->pp_name, name) == 0)
210 return (propp->pp_len);
211
212 return (-1);
213 }
214
215 int
promif_getproplen(pnode_t nodeid,char * name)216 promif_getproplen(pnode_t nodeid, char *name)
217 {
218 prom_node_t *pnp;
219
220 pnp = promif_find_node(nodeid);
221 if (pnp == NULL)
222 return (-1);
223
224 return (getproplen(pnp, name));
225 }
226
227 static void *
getprop(prom_node_t * pnp,char * name)228 getprop(prom_node_t *pnp, char *name)
229 {
230 struct prom_prop *propp;
231
232 for (propp = pnp->pn_propp; propp != NULL; propp = propp->pp_next)
233 if (strcmp(propp->pp_name, name) == 0)
234 return (propp->pp_val);
235
236 return (NULL);
237 }
238
239 int
promif_getprop(pnode_t nodeid,char * name,void * value)240 promif_getprop(pnode_t nodeid, char *name, void *value)
241 {
242 prom_node_t *pnp;
243 void *v;
244 int len;
245
246 pnp = promif_find_node(nodeid);
247 if (pnp == NULL)
248 return (-1);
249
250 len = getproplen(pnp, name);
251 if (len > 0) {
252 v = getprop(pnp, name);
253 bcopy(v, value, len);
254 }
255 return (len);
256 }
257
258 static char *
nextprop(prom_node_t * pnp,char * name)259 nextprop(prom_node_t *pnp, char *name)
260 {
261 struct prom_prop *propp;
262
263 /*
264 * getting next of NULL or a null string returns the first prop name
265 */
266 if (name == NULL || *name == '\0')
267 if (pnp->pn_propp)
268 return (pnp->pn_propp->pp_name);
269
270 for (propp = pnp->pn_propp; propp != NULL; propp = propp->pp_next)
271 if (strcmp(propp->pp_name, name) == 0)
272 if (propp->pp_next)
273 return (propp->pp_next->pp_name);
274
275 return (NULL);
276 }
277
278 char *
promif_nextprop(pnode_t nodeid,char * name,char * next)279 promif_nextprop(pnode_t nodeid, char *name, char *next)
280 {
281 prom_node_t *pnp;
282 char *s;
283
284 next[0] = '\0';
285
286 pnp = promif_find_node(nodeid);
287 if (pnp == NULL)
288 return (NULL);
289
290 s = nextprop(pnp, name);
291 if (s == NULL)
292 return (next);
293
294 (void) strcpy(next, s);
295 return (next);
296 }
297