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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 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/types.h> 30 #include <sys/esunddi.h> 31 #include <sys/promif_impl.h> 32 33 #ifdef _KMDB 34 static pnode_t chosennode; 35 static pnode_t optionsnode; 36 #else 37 static char *gettoken(char *tp, char *token); 38 static pnode_t finddevice(char *path); 39 #endif 40 41 /* 42 * Routines for walking the PROMs devinfo tree 43 */ 44 45 #ifdef _KMDB 46 47 void 48 promif_set_nodes(pnode_t chosen, pnode_t options) 49 { 50 chosennode = chosen; 51 optionsnode = options; 52 } 53 54 int 55 promif_finddevice(void *p) 56 { 57 cell_t *ci = (cell_t *)p; 58 char *path; 59 60 ASSERT(ci[1] == 1); 61 62 path = p1275_cell2ptr(ci[3]); 63 64 if (strcmp("/chosen", path) == 0) { 65 ci[4] = p1275_dnode2cell(chosennode); 66 } else if (strcmp("/options", path) == 0) { 67 ci[4] = p1275_dnode2cell(optionsnode); 68 } else { 69 /* only supports known nodes */ 70 ASSERT(0); 71 } 72 73 return (0); 74 } 75 76 #else 77 78 int 79 promif_finddevice(void *p) 80 { 81 cell_t *ci = (cell_t *)p; 82 pnode_t node; 83 84 ASSERT(ci[1] == 1); 85 86 node = finddevice(p1275_cell2ptr(ci[3])); 87 88 ci[4] = p1275_dnode2cell(node); 89 90 return (0); 91 } 92 93 #endif 94 95 int 96 promif_nextnode(void *p) 97 { 98 cell_t *ci = (cell_t *)p; 99 pnode_t next; 100 101 ASSERT(ci[1] == 1); 102 103 next = promif_stree_nextnode(p1275_cell2dnode(ci[3])); 104 105 ci[4] = p1275_dnode2cell(next); 106 107 return (0); 108 } 109 110 int 111 promif_childnode(void *p) 112 { 113 cell_t *ci = (cell_t *)p; 114 pnode_t child; 115 116 ASSERT(ci[1] == 1); 117 118 child = promif_stree_childnode(p1275_cell2dnode(ci[3])); 119 120 ci[4] = p1275_dnode2cell(child); 121 122 return (0); 123 } 124 125 int 126 promif_parentnode(void *p) 127 { 128 cell_t *ci = (cell_t *)p; 129 pnode_t parent; 130 131 ASSERT(ci[1] == 1); 132 133 parent = promif_stree_parentnode(p1275_cell2dnode(ci[3])); 134 135 ci[4] = p1275_dnode2cell(parent); 136 137 return (0); 138 } 139 140 #ifndef _KMDB 141 142 /* 143 * Get a token from a prom pathname, collecting everything 144 * until a non-comma, non-colon separator is found. Any 145 * options, including the ':' option separator, on the end 146 * of the token are removed. 147 */ 148 static char * 149 gettoken(char *tp, char *token) 150 { 151 char *result = token; 152 153 for (;;) { 154 tp = prom_path_gettoken(tp, token); 155 token += prom_strlen(token); 156 if ((*tp == ',') || (*tp == ':')) { 157 *token++ = *tp++; 158 *token = '\0'; 159 continue; 160 } 161 break; 162 } 163 164 /* strip off any options from the token */ 165 prom_strip_options(result, result); 166 167 return (tp); 168 } 169 170 /* 171 * Retrieve the unit address for a node by looking it up 172 * in the corresponding dip. -1 is returned if no unit 173 * address can be determined. 174 */ 175 static int 176 get_unit_addr(pnode_t np, char *paddr) 177 { 178 dev_info_t *dip; 179 char *addr; 180 181 if ((dip = e_ddi_nodeid_to_dip(np)) == NULL) { 182 return (-1); 183 } 184 185 if ((addr = ddi_get_name_addr(dip)) == NULL) { 186 ddi_release_devi(dip); 187 return (-1); 188 } 189 190 (void) prom_strcpy(paddr, addr); 191 192 ddi_release_devi(dip); 193 194 return (0); 195 } 196 197 /* 198 * Get node id of node in prom tree that path identifies 199 */ 200 static pnode_t 201 finddevice(char *path) 202 { 203 char name[OBP_MAXPROPNAME]; 204 char addr[OBP_MAXPROPNAME]; 205 char pname[OBP_MAXPROPNAME]; 206 char paddr[OBP_MAXPROPNAME]; 207 char *tp; 208 pnode_t np; 209 pnode_t device; 210 211 CIF_DBG_NODE("finddevice: %s\n", path); 212 213 tp = path; 214 np = prom_rootnode(); 215 device = OBP_BADNODE; 216 217 /* must be a fully specified path */ 218 if (*tp++ != '/') 219 goto done; 220 221 for (;;) { 222 /* get the name from the path */ 223 tp = gettoken(tp, name); 224 if (*name == '\0') 225 break; 226 227 /* get the address from the path */ 228 if (*tp == '@') { 229 tp++; 230 tp = gettoken(tp, addr); 231 } else { 232 addr[0] = '\0'; 233 } 234 235 CIF_DBG_NODE("looking for: %s%s%s\n", name, 236 (*addr != '\0') ? "@" : "", addr); 237 238 if ((np = prom_childnode(np)) == OBP_NONODE) 239 break; 240 241 while (np != OBP_NONODE) { 242 243 /* get the name from the current node */ 244 if (prom_getprop(np, OBP_NAME, pname) < 0) 245 goto done; 246 247 /* get the address from the current node */ 248 if (get_unit_addr(np, paddr) < 0) 249 paddr[0] = '\0'; 250 251 /* compare the names and addresses */ 252 if ((prom_strcmp(name, pname) == 0) && 253 (prom_strcmp(addr, paddr) == 0)) { 254 CIF_DBG_NODE("found dev: %s%s%s (0x%x)\n", 255 pname, (*paddr != '\0') ? "@" : "", 256 paddr, np); 257 break; 258 } else { 259 CIF_DBG_NODE(" no match: %s%s%s vs %s%s%s\n", 260 name, (*addr != '\0') ? "@" : "", addr, 261 pname, (*paddr != '\0') ? "@" : "", paddr); 262 } 263 np = prom_nextnode(np); 264 } 265 266 /* path does not map to a node */ 267 if (np == OBP_NONODE) 268 break; 269 270 if (*tp == '\0') { 271 /* found a matching node */ 272 device = np; 273 break; 274 } 275 276 /* 277 * Continue the loop with the 278 * next component of the path. 279 */ 280 tp++; 281 } 282 done: 283 284 if (device == OBP_BADNODE) { 285 CIF_DBG_NODE("device not found\n\n"); 286 } else { 287 CIF_DBG_NODE("returning 0x%x\n\n", device); 288 } 289 290 return (device); 291 } 292 293 #endif 294