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