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 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 * 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 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 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 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 * 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 * 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 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 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 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 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 * 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 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 * 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 * 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