1*03831d35Sstevel /* 2*03831d35Sstevel * CDDL HEADER START 3*03831d35Sstevel * 4*03831d35Sstevel * The contents of this file are subject to the terms of the 5*03831d35Sstevel * Common Development and Distribution License, Version 1.0 only 6*03831d35Sstevel * (the "License"). You may not use this file except in compliance 7*03831d35Sstevel * with the License. 8*03831d35Sstevel * 9*03831d35Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*03831d35Sstevel * or http://www.opensolaris.org/os/licensing. 11*03831d35Sstevel * See the License for the specific language governing permissions 12*03831d35Sstevel * and limitations under the License. 13*03831d35Sstevel * 14*03831d35Sstevel * When distributing Covered Code, include this CDDL HEADER in each 15*03831d35Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*03831d35Sstevel * If applicable, add the following below this CDDL HEADER, with the 17*03831d35Sstevel * fields enclosed by brackets "[]" replaced with your own identifying 18*03831d35Sstevel * information: Portions Copyright [yyyy] [name of copyright owner] 19*03831d35Sstevel * 20*03831d35Sstevel * CDDL HEADER END 21*03831d35Sstevel */ 22*03831d35Sstevel /* 23*03831d35Sstevel * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*03831d35Sstevel * Use is subject to license terms. 25*03831d35Sstevel */ 26*03831d35Sstevel 27*03831d35Sstevel #pragma ident "%Z%%M% %I% %E% SMI" 28*03831d35Sstevel 29*03831d35Sstevel #include <stdio.h> 30*03831d35Sstevel #include <stdlib.h> 31*03831d35Sstevel #include <string.h> 32*03831d35Sstevel #include <fcntl.h> 33*03831d35Sstevel #include <stdarg.h> 34*03831d35Sstevel #include <errno.h> 35*03831d35Sstevel #include <unistd.h> 36*03831d35Sstevel #include <sys/utsname.h> 37*03831d35Sstevel #include <sys/openpromio.h> 38*03831d35Sstevel #include <libintl.h> 39*03831d35Sstevel #include "pdevinfo.h" 40*03831d35Sstevel #include "display.h" 41*03831d35Sstevel #include "pdevinfo_sun4u.h" 42*03831d35Sstevel 43*03831d35Sstevel /* 44*03831d35Sstevel * For machines that support the openprom, fetch and print the list 45*03831d35Sstevel * of devices that the kernel has fetched from the prom or conjured up. 46*03831d35Sstevel * 47*03831d35Sstevel */ 48*03831d35Sstevel 49*03831d35Sstevel 50*03831d35Sstevel static int prom_fd; 51*03831d35Sstevel extern char *progname; 52*03831d35Sstevel extern char *promdev; 53*03831d35Sstevel extern void getppdata(); 54*03831d35Sstevel extern void printppdata(); 55*03831d35Sstevel 56*03831d35Sstevel /* 57*03831d35Sstevel * Define DPRINT for run-time debugging printf's... 58*03831d35Sstevel * #define DPRINT 1 59*03831d35Sstevel */ 60*03831d35Sstevel 61*03831d35Sstevel #ifdef DPRINT 62*03831d35Sstevel static char vdebug_flag = 1; 63*03831d35Sstevel #define dprintf if (vdebug_flag) printf 64*03831d35Sstevel static void dprint_dev_info(caddr_t, dev_info_t *); 65*03831d35Sstevel #endif /* DPRINT */ 66*03831d35Sstevel 67*03831d35Sstevel #if !defined(TEXT_DOMAIN) 68*03831d35Sstevel #define TEXT_DOMAIN "SYS_TEST" 69*03831d35Sstevel #endif 70*03831d35Sstevel 71*03831d35Sstevel /*VARARGS1*/ 72*03831d35Sstevel int 73*03831d35Sstevel _error(char *fmt, ...) 74*03831d35Sstevel { 75*03831d35Sstevel int saved_errno; 76*03831d35Sstevel va_list ap; 77*03831d35Sstevel extern int errno; 78*03831d35Sstevel saved_errno = errno; 79*03831d35Sstevel 80*03831d35Sstevel if (progname) 81*03831d35Sstevel (void) fprintf(stderr, "%s: ", progname); 82*03831d35Sstevel 83*03831d35Sstevel va_start(ap, fmt); 84*03831d35Sstevel 85*03831d35Sstevel (void) vfprintf(stderr, fmt, ap); 86*03831d35Sstevel 87*03831d35Sstevel va_end(ap); 88*03831d35Sstevel 89*03831d35Sstevel (void) fprintf(stderr, ": "); 90*03831d35Sstevel errno = saved_errno; 91*03831d35Sstevel perror(""); 92*03831d35Sstevel 93*03831d35Sstevel return (2); 94*03831d35Sstevel } 95*03831d35Sstevel 96*03831d35Sstevel int 97*03831d35Sstevel is_openprom(void) 98*03831d35Sstevel { 99*03831d35Sstevel Oppbuf oppbuf; 100*03831d35Sstevel register struct openpromio *opp = &(oppbuf.opp); 101*03831d35Sstevel register unsigned int i; 102*03831d35Sstevel 103*03831d35Sstevel opp->oprom_size = MAXVALSIZE; 104*03831d35Sstevel if (ioctl(prom_fd, OPROMGETCONS, opp) < 0) 105*03831d35Sstevel exit(_error("OPROMGETCONS")); 106*03831d35Sstevel 107*03831d35Sstevel i = (unsigned int)((unsigned char)opp->oprom_array[0]); 108*03831d35Sstevel return ((i & OPROMCONS_OPENPROM) == OPROMCONS_OPENPROM); 109*03831d35Sstevel } 110*03831d35Sstevel 111*03831d35Sstevel /* 112*03831d35Sstevel * Read all properties and values from nodes. 113*03831d35Sstevel * Copy the properties read into the prom_node passsed in. 114*03831d35Sstevel */ 115*03831d35Sstevel void 116*03831d35Sstevel dump_node(Prom_node *node) 117*03831d35Sstevel { 118*03831d35Sstevel Oppbuf oppbuf; 119*03831d35Sstevel register struct openpromio *opp = &oppbuf.opp; 120*03831d35Sstevel Prop *prop = NULL; /* tail of properties list */ 121*03831d35Sstevel StaticProp *temp; 122*03831d35Sstevel 123*03831d35Sstevel /* clear out pointers in pnode */ 124*03831d35Sstevel node->props = NULL; 125*03831d35Sstevel 126*03831d35Sstevel /* get first prop by asking for null string */ 127*03831d35Sstevel (void) memset((void *) oppbuf.buf, 0, BUFSIZE); 128*03831d35Sstevel 129*03831d35Sstevel /* allocate space for the property */ 130*03831d35Sstevel if ((temp = malloc(sizeof (StaticProp))) == NULL) { 131*03831d35Sstevel perror("malloc"); 132*03831d35Sstevel exit(1); 133*03831d35Sstevel } 134*03831d35Sstevel 135*03831d35Sstevel opp->oprom_size = MAXPROPSIZE; 136*03831d35Sstevel while (opp->oprom_size != 0) { 137*03831d35Sstevel Prop *new; 138*03831d35Sstevel int i; 139*03831d35Sstevel char *tempp, *newp; 140*03831d35Sstevel 141*03831d35Sstevel /* 142*03831d35Sstevel * get property 143*03831d35Sstevel */ 144*03831d35Sstevel opp->oprom_size = MAXPROPSIZE; 145*03831d35Sstevel 146*03831d35Sstevel if (ioctl(prom_fd, OPROMNXTPROP, opp) < 0) 147*03831d35Sstevel exit(_error("OPROMNXTPROP")); 148*03831d35Sstevel 149*03831d35Sstevel if (opp->oprom_size != 0) { 150*03831d35Sstevel temp->name.opp.oprom_size = opp->oprom_size; 151*03831d35Sstevel (void) strcpy(temp->name.opp.oprom_array, 152*03831d35Sstevel opp->oprom_array); 153*03831d35Sstevel 154*03831d35Sstevel (void) strcpy(temp->value.opp.oprom_array, 155*03831d35Sstevel temp->name.opp.oprom_array); 156*03831d35Sstevel getpropval(&temp->value.opp); 157*03831d35Sstevel temp->size = temp->value.opp.oprom_size; 158*03831d35Sstevel 159*03831d35Sstevel /* Now copy over temp's data to new. */ 160*03831d35Sstevel if ((new = malloc(sizeof (Prop))) == NULL) { 161*03831d35Sstevel perror("malloc"); 162*03831d35Sstevel exit(1); 163*03831d35Sstevel } 164*03831d35Sstevel 165*03831d35Sstevel /* 166*03831d35Sstevel * First copy over temp->name's data. The 167*03831d35Sstevel * temp->name.opp.opio_u union always contains char[] 168*03831d35Sstevel * (as opposed to an int or int []). 169*03831d35Sstevel */ 170*03831d35Sstevel new->name.opp.oprom_size = temp->name.opp.oprom_size; 171*03831d35Sstevel 172*03831d35Sstevel if ((new->name.opp.oprom_array = 173*03831d35Sstevel malloc(new->name.opp.oprom_size)) == NULL) { 174*03831d35Sstevel perror("malloc"); 175*03831d35Sstevel exit(1); 176*03831d35Sstevel } 177*03831d35Sstevel (void) strcpy(new->name.opp.oprom_array, 178*03831d35Sstevel temp->name.opp.oprom_array); 179*03831d35Sstevel 180*03831d35Sstevel new->name.opp.holds_array = 1; 181*03831d35Sstevel 182*03831d35Sstevel /* 183*03831d35Sstevel * Then copy over temp->value's data. 184*03831d35Sstevel * temp->value.opp.opio_u could contain char[], int or 185*03831d35Sstevel * int []. If *(temp->value.opp.oprom_array) is '\0', 186*03831d35Sstevel * this indicates int or int []. int is the norm, but 187*03831d35Sstevel * to be safe we assume int [] and copy over 188*03831d35Sstevel * OPROM_NODE_SIZE int elements. 189*03831d35Sstevel */ 190*03831d35Sstevel new->value.opp.oprom_size = temp->value.opp.oprom_size; 191*03831d35Sstevel 192*03831d35Sstevel if (*(temp->value.opp.oprom_array) == '\0') { 193*03831d35Sstevel for (i = 0; i < OPROM_NODE_SIZE; i++) 194*03831d35Sstevel new->value.opp.oprom_node[i] = 195*03831d35Sstevel *(&temp->value.opp.oprom_node+i); 196*03831d35Sstevel 197*03831d35Sstevel new->value.opp.holds_array = 0; 198*03831d35Sstevel } else { 199*03831d35Sstevel if ((new->value.opp.oprom_array = 200*03831d35Sstevel malloc(new->value.opp.oprom_size)) 201*03831d35Sstevel == NULL) { 202*03831d35Sstevel perror("malloc"); 203*03831d35Sstevel exit(1); 204*03831d35Sstevel } 205*03831d35Sstevel 206*03831d35Sstevel /* 207*03831d35Sstevel * temp->value.opp.oprom_array can contain one 208*03831d35Sstevel * or more embedded NULLs. These trip-up the 209*03831d35Sstevel * standard string copying functions, so we do 210*03831d35Sstevel * the copy by hand. temp->value.opp.oprom_array 211*03831d35Sstevel * will be NULL-terminated. oprom_size includes 212*03831d35Sstevel * this terminating NULL. 213*03831d35Sstevel */ 214*03831d35Sstevel newp = new->value.opp.oprom_array; 215*03831d35Sstevel tempp = temp->value.opp.oprom_array; 216*03831d35Sstevel for (i = new->value.opp.oprom_size; i > 0; i--) 217*03831d35Sstevel *newp++ = *tempp++; 218*03831d35Sstevel 219*03831d35Sstevel new->value.opp.holds_array = 1; 220*03831d35Sstevel } 221*03831d35Sstevel 222*03831d35Sstevel new->size = temp->size; 223*03831d35Sstevel 224*03831d35Sstevel /* everything worked so link the property list */ 225*03831d35Sstevel if (node->props == NULL) 226*03831d35Sstevel node->props = new; 227*03831d35Sstevel else if (prop != NULL) 228*03831d35Sstevel prop->next = new; 229*03831d35Sstevel prop = new; 230*03831d35Sstevel prop->next = NULL; 231*03831d35Sstevel } 232*03831d35Sstevel } 233*03831d35Sstevel free(temp); 234*03831d35Sstevel } 235*03831d35Sstevel 236*03831d35Sstevel int 237*03831d35Sstevel promopen(int oflag) 238*03831d35Sstevel { 239*03831d35Sstevel /*CONSTCOND*/ 240*03831d35Sstevel while (1) { 241*03831d35Sstevel if ((prom_fd = open(promdev, oflag)) < 0) { 242*03831d35Sstevel if (errno == EAGAIN) { 243*03831d35Sstevel (void) sleep(5); 244*03831d35Sstevel continue; 245*03831d35Sstevel } 246*03831d35Sstevel if (errno == ENXIO) 247*03831d35Sstevel return (-1); 248*03831d35Sstevel exit(_error(dgettext(TEXT_DOMAIN, "cannot open %s"), 249*03831d35Sstevel promdev)); 250*03831d35Sstevel } else 251*03831d35Sstevel return (0); 252*03831d35Sstevel } 253*03831d35Sstevel /*NOTREACHED*/ 254*03831d35Sstevel } 255*03831d35Sstevel 256*03831d35Sstevel void 257*03831d35Sstevel promclose(void) 258*03831d35Sstevel { 259*03831d35Sstevel if (close(prom_fd) < 0) 260*03831d35Sstevel exit(_error(dgettext(TEXT_DOMAIN, "close error on %s"), 261*03831d35Sstevel promdev)); 262*03831d35Sstevel } 263*03831d35Sstevel 264*03831d35Sstevel /* 265*03831d35Sstevel * Read the value of the property from the PROM device tree 266*03831d35Sstevel */ 267*03831d35Sstevel void 268*03831d35Sstevel getpropval(struct openpromio *opp) 269*03831d35Sstevel { 270*03831d35Sstevel opp->oprom_size = MAXVALSIZE; 271*03831d35Sstevel 272*03831d35Sstevel if (ioctl(prom_fd, OPROMGETPROP, opp) < 0) 273*03831d35Sstevel exit(_error("OPROMGETPROP")); 274*03831d35Sstevel } 275*03831d35Sstevel 276*03831d35Sstevel int 277*03831d35Sstevel next(int id) 278*03831d35Sstevel { 279*03831d35Sstevel Oppbuf oppbuf; 280*03831d35Sstevel register struct openpromio *opp = &(oppbuf.opp); 281*03831d35Sstevel /* LINTED */ 282*03831d35Sstevel int *ip = (int *)(opp->oprom_array); 283*03831d35Sstevel 284*03831d35Sstevel (void) memset((void *) oppbuf.buf, 0, BUFSIZE); 285*03831d35Sstevel 286*03831d35Sstevel opp->oprom_size = MAXVALSIZE; 287*03831d35Sstevel *ip = id; 288*03831d35Sstevel if (ioctl(prom_fd, OPROMNEXT, opp) < 0) 289*03831d35Sstevel return (_error("OPROMNEXT")); 290*03831d35Sstevel /* LINTED */ 291*03831d35Sstevel return (*(int *)opp->oprom_array); 292*03831d35Sstevel } 293*03831d35Sstevel 294*03831d35Sstevel int 295*03831d35Sstevel child(int id) 296*03831d35Sstevel { 297*03831d35Sstevel Oppbuf oppbuf; 298*03831d35Sstevel register struct openpromio *opp = &(oppbuf.opp); 299*03831d35Sstevel /* LINTED */ 300*03831d35Sstevel int *ip = (int *)(opp->oprom_array); 301*03831d35Sstevel 302*03831d35Sstevel (void) memset((void *) oppbuf.buf, 0, BUFSIZE); 303*03831d35Sstevel opp->oprom_size = MAXVALSIZE; 304*03831d35Sstevel *ip = id; 305*03831d35Sstevel if (ioctl(prom_fd, OPROMCHILD, opp) < 0) 306*03831d35Sstevel return (_error("OPROMCHILD")); 307*03831d35Sstevel /* LINTED */ 308*03831d35Sstevel return (*(int *)opp->oprom_array); 309*03831d35Sstevel } 310*03831d35Sstevel 311*03831d35Sstevel /* 312*03831d35Sstevel * Check if the Prom node passed in contains a property called 313*03831d35Sstevel * "board#". 314*03831d35Sstevel */ 315*03831d35Sstevel int 316*03831d35Sstevel has_board_num(Prom_node *node) 317*03831d35Sstevel { 318*03831d35Sstevel Prop *prop = node->props; 319*03831d35Sstevel 320*03831d35Sstevel /* 321*03831d35Sstevel * walk thru all properties in this PROM node and look for 322*03831d35Sstevel * board# prop 323*03831d35Sstevel */ 324*03831d35Sstevel while (prop != NULL) { 325*03831d35Sstevel if (strcmp(prop->name.opp.oprom_array, "board#") == 0) 326*03831d35Sstevel return (1); 327*03831d35Sstevel 328*03831d35Sstevel prop = prop->next; 329*03831d35Sstevel } 330*03831d35Sstevel 331*03831d35Sstevel return (0); 332*03831d35Sstevel } /* end of has_board_num() */ 333*03831d35Sstevel 334*03831d35Sstevel /* 335*03831d35Sstevel * Retrieve the value of the board number property from this Prom 336*03831d35Sstevel * node. It has the type of int. 337*03831d35Sstevel */ 338*03831d35Sstevel int 339*03831d35Sstevel get_board_num(Prom_node *node) 340*03831d35Sstevel { 341*03831d35Sstevel Prop *prop = node->props; 342*03831d35Sstevel 343*03831d35Sstevel /* 344*03831d35Sstevel * walk thru all properties in this PROM node and look for 345*03831d35Sstevel * board# prop 346*03831d35Sstevel */ 347*03831d35Sstevel while (prop != NULL) { 348*03831d35Sstevel if (strcmp(prop->name.opp.oprom_array, "board#") == 0) 349*03831d35Sstevel return (prop->value.opp.oprom_node[0]); 350*03831d35Sstevel 351*03831d35Sstevel prop = prop->next; 352*03831d35Sstevel } 353*03831d35Sstevel 354*03831d35Sstevel return (-1); 355*03831d35Sstevel } /* end of get_board_num() */ 356*03831d35Sstevel 357*03831d35Sstevel /* 358*03831d35Sstevel * Find the requested board struct in the system device tree. 359*03831d35Sstevel */ 360*03831d35Sstevel Board_node * 361*03831d35Sstevel find_board(Sys_tree *root, int board) 362*03831d35Sstevel { 363*03831d35Sstevel Board_node *bnode = root->bd_list; 364*03831d35Sstevel 365*03831d35Sstevel while ((bnode != NULL) && (board != bnode->board_num)) 366*03831d35Sstevel bnode = bnode->next; 367*03831d35Sstevel 368*03831d35Sstevel return (bnode); 369*03831d35Sstevel } /* end of find_board() */ 370*03831d35Sstevel 371*03831d35Sstevel /* 372*03831d35Sstevel * Add a board to the system list in order. Initialize all pointer 373*03831d35Sstevel * fields to NULL. 374*03831d35Sstevel */ 375*03831d35Sstevel Board_node * 376*03831d35Sstevel insert_board(Sys_tree *root, int board) 377*03831d35Sstevel { 378*03831d35Sstevel Board_node *bnode; 379*03831d35Sstevel Board_node *temp = root->bd_list; 380*03831d35Sstevel 381*03831d35Sstevel if ((bnode = (Board_node *) malloc(sizeof (Board_node))) == NULL) { 382*03831d35Sstevel perror("malloc"); 383*03831d35Sstevel exit(1); 384*03831d35Sstevel } 385*03831d35Sstevel bnode->nodes = NULL; 386*03831d35Sstevel bnode->next = NULL; 387*03831d35Sstevel bnode->board_num = board; 388*03831d35Sstevel 389*03831d35Sstevel if (temp == NULL) 390*03831d35Sstevel root->bd_list = bnode; 391*03831d35Sstevel else if (temp->board_num > board) { 392*03831d35Sstevel bnode->next = temp; 393*03831d35Sstevel root->bd_list = bnode; 394*03831d35Sstevel } else { 395*03831d35Sstevel while ((temp->next != NULL) && (board > temp->next->board_num)) 396*03831d35Sstevel temp = temp->next; 397*03831d35Sstevel bnode->next = temp->next; 398*03831d35Sstevel temp->next = bnode; 399*03831d35Sstevel } 400*03831d35Sstevel root->board_cnt++; 401*03831d35Sstevel 402*03831d35Sstevel return (bnode); 403*03831d35Sstevel } /* end of insert_board() */ 404*03831d35Sstevel 405*03831d35Sstevel /* 406*03831d35Sstevel * This function searches through the properties of the node passed in 407*03831d35Sstevel * and returns a pointer to the value of the name property. 408*03831d35Sstevel */ 409*03831d35Sstevel char * 410*03831d35Sstevel get_node_name(Prom_node *pnode) 411*03831d35Sstevel { 412*03831d35Sstevel Prop *prop; 413*03831d35Sstevel 414*03831d35Sstevel if (pnode == NULL) { 415*03831d35Sstevel return (NULL); 416*03831d35Sstevel } 417*03831d35Sstevel 418*03831d35Sstevel prop = pnode->props; 419*03831d35Sstevel while (prop != NULL) { 420*03831d35Sstevel if (strcmp("name", prop->name.opp.oprom_array) == 0) 421*03831d35Sstevel return (prop->value.opp.oprom_array); 422*03831d35Sstevel prop = prop->next; 423*03831d35Sstevel } 424*03831d35Sstevel return (NULL); 425*03831d35Sstevel } /* end of get_node_name() */ 426*03831d35Sstevel 427*03831d35Sstevel /* 428*03831d35Sstevel * This function searches through the properties of the node passed in 429*03831d35Sstevel * and returns a pointer to the value of the name property. 430*03831d35Sstevel */ 431*03831d35Sstevel char * 432*03831d35Sstevel get_node_type(Prom_node *pnode) 433*03831d35Sstevel { 434*03831d35Sstevel Prop *prop; 435*03831d35Sstevel 436*03831d35Sstevel if (pnode == NULL) { 437*03831d35Sstevel return (NULL); 438*03831d35Sstevel } 439*03831d35Sstevel 440*03831d35Sstevel prop = pnode->props; 441*03831d35Sstevel while (prop != NULL) { 442*03831d35Sstevel if (strcmp("device_type", prop->name.opp.oprom_array) == 0) 443*03831d35Sstevel return (prop->value.opp.oprom_array); 444*03831d35Sstevel prop = prop->next; 445*03831d35Sstevel } 446*03831d35Sstevel return (NULL); 447*03831d35Sstevel } /* end of get_node_type() */ 448*03831d35Sstevel 449*03831d35Sstevel /* 450*03831d35Sstevel * Do a depth-first walk of a device tree and 451*03831d35Sstevel * return the first node with the name matching. 452*03831d35Sstevel */ 453*03831d35Sstevel 454*03831d35Sstevel Prom_node * 455*03831d35Sstevel dev_find_node(Prom_node *root, char *name) 456*03831d35Sstevel { 457*03831d35Sstevel Prom_node *node; 458*03831d35Sstevel 459*03831d35Sstevel node = dev_find_node_by_type(root, "name", name); 460*03831d35Sstevel 461*03831d35Sstevel return (node); 462*03831d35Sstevel } 463*03831d35Sstevel 464*03831d35Sstevel Prom_node * 465*03831d35Sstevel dev_next_node(Prom_node *root, char *name) 466*03831d35Sstevel { 467*03831d35Sstevel Prom_node *node; 468*03831d35Sstevel 469*03831d35Sstevel node = dev_next_node_by_type(root, "name", name); 470*03831d35Sstevel 471*03831d35Sstevel return (node); 472*03831d35Sstevel } 473*03831d35Sstevel 474*03831d35Sstevel /* 475*03831d35Sstevel * Search for and return a node of the required type. If no node is found, 476*03831d35Sstevel * then return NULL. 477*03831d35Sstevel */ 478*03831d35Sstevel Prom_node * 479*03831d35Sstevel dev_find_type(Prom_node *root, char *type) 480*03831d35Sstevel { 481*03831d35Sstevel Prom_node *node; 482*03831d35Sstevel 483*03831d35Sstevel node = dev_find_node_by_type(root, "device_type", type); 484*03831d35Sstevel 485*03831d35Sstevel return (node); /* not found */ 486*03831d35Sstevel } 487*03831d35Sstevel 488*03831d35Sstevel /* 489*03831d35Sstevel * Start from the current node and return the next node besides the 490*03831d35Sstevel * current one which has the requested type property. 491*03831d35Sstevel */ 492*03831d35Sstevel Prom_node * 493*03831d35Sstevel dev_next_type(Prom_node *root, char *type) 494*03831d35Sstevel { 495*03831d35Sstevel Prom_node *node; 496*03831d35Sstevel 497*03831d35Sstevel node = dev_next_node_by_type(root, "device_type", type); 498*03831d35Sstevel 499*03831d35Sstevel return (node); /* not found */ 500*03831d35Sstevel } 501*03831d35Sstevel 502*03831d35Sstevel /* 503*03831d35Sstevel * Search a device tree and return the first failed node that is found. 504*03831d35Sstevel * (has a 'status' property) 505*03831d35Sstevel */ 506*03831d35Sstevel Prom_node * 507*03831d35Sstevel find_failed_node(Prom_node * root) 508*03831d35Sstevel { 509*03831d35Sstevel Prom_node *pnode; 510*03831d35Sstevel 511*03831d35Sstevel if (root == NULL) 512*03831d35Sstevel return (NULL); 513*03831d35Sstevel 514*03831d35Sstevel if (node_failed(root)) { 515*03831d35Sstevel return (root); 516*03831d35Sstevel } 517*03831d35Sstevel 518*03831d35Sstevel /* search the child */ 519*03831d35Sstevel if ((pnode = find_failed_node(root->child)) != NULL) 520*03831d35Sstevel return (pnode); 521*03831d35Sstevel 522*03831d35Sstevel /* search the siblings */ 523*03831d35Sstevel if ((pnode = find_failed_node(root->sibling)) != NULL) 524*03831d35Sstevel return (pnode); 525*03831d35Sstevel 526*03831d35Sstevel return (NULL); 527*03831d35Sstevel } /* end of find_failed_node() */ 528*03831d35Sstevel 529*03831d35Sstevel /* 530*03831d35Sstevel * Start from the current node and return the next node besides 531*03831d35Sstevel * the current one which is failed. (has a 'status' property) 532*03831d35Sstevel */ 533*03831d35Sstevel Prom_node * 534*03831d35Sstevel next_failed_node(Prom_node * root) 535*03831d35Sstevel { 536*03831d35Sstevel Prom_node *pnode; 537*03831d35Sstevel Prom_node *parent; 538*03831d35Sstevel 539*03831d35Sstevel if (root == NULL) 540*03831d35Sstevel return (NULL); 541*03831d35Sstevel 542*03831d35Sstevel /* search the child */ 543*03831d35Sstevel if ((pnode = find_failed_node(root->child)) != NULL) { 544*03831d35Sstevel return (pnode); 545*03831d35Sstevel } 546*03831d35Sstevel 547*03831d35Sstevel /* search the siblings */ 548*03831d35Sstevel if ((pnode = find_failed_node(root->sibling)) != NULL) { 549*03831d35Sstevel return (pnode); 550*03831d35Sstevel } 551*03831d35Sstevel 552*03831d35Sstevel /* backtracking the search up through parents' siblings */ 553*03831d35Sstevel parent = root->parent; 554*03831d35Sstevel while (parent != NULL) { 555*03831d35Sstevel if ((pnode = find_failed_node(parent->sibling)) != NULL) 556*03831d35Sstevel return (pnode); 557*03831d35Sstevel else 558*03831d35Sstevel parent = parent->parent; 559*03831d35Sstevel } 560*03831d35Sstevel 561*03831d35Sstevel return (NULL); 562*03831d35Sstevel } /* end of find_failed_node() */ 563*03831d35Sstevel 564*03831d35Sstevel /* 565*03831d35Sstevel * node_failed 566*03831d35Sstevel * 567*03831d35Sstevel * This function determines if the current Prom node is failed. This 568*03831d35Sstevel * is defined by having a status property containing the token 'fail'. 569*03831d35Sstevel */ 570*03831d35Sstevel int 571*03831d35Sstevel node_failed(Prom_node *node) 572*03831d35Sstevel { 573*03831d35Sstevel return (node_status(node, "fail")); 574*03831d35Sstevel } 575*03831d35Sstevel 576*03831d35Sstevel int 577*03831d35Sstevel node_status(Prom_node *node, char *status) 578*03831d35Sstevel { 579*03831d35Sstevel void *value; 580*03831d35Sstevel 581*03831d35Sstevel if (status == NULL) 582*03831d35Sstevel return (0); 583*03831d35Sstevel 584*03831d35Sstevel /* search the local node */ 585*03831d35Sstevel if ((value = get_prop_val(find_prop(node, "status"))) != NULL) { 586*03831d35Sstevel if ((value != NULL) && strstr((char *)value, status)) 587*03831d35Sstevel return (1); 588*03831d35Sstevel } 589*03831d35Sstevel return (0); 590*03831d35Sstevel } 591*03831d35Sstevel 592*03831d35Sstevel /* 593*03831d35Sstevel * Get a property's value. Must be void * since the property can 594*03831d35Sstevel * be any data type. Caller must know the *PROPER* way to use this 595*03831d35Sstevel * data. 596*03831d35Sstevel */ 597*03831d35Sstevel void * 598*03831d35Sstevel get_prop_val(Prop *prop) 599*03831d35Sstevel { 600*03831d35Sstevel if (prop == NULL) 601*03831d35Sstevel return (NULL); 602*03831d35Sstevel 603*03831d35Sstevel if (prop->value.opp.holds_array) 604*03831d35Sstevel return ((void *)(prop->value.opp.oprom_array)); 605*03831d35Sstevel else 606*03831d35Sstevel return ((void *)(&prop->value.opp.oprom_node[0])); 607*03831d35Sstevel } /* end of get_prop_val() */ 608*03831d35Sstevel 609*03831d35Sstevel /* 610*03831d35Sstevel * Search a Prom node and retrieve the property with the correct 611*03831d35Sstevel * name. 612*03831d35Sstevel */ 613*03831d35Sstevel Prop * 614*03831d35Sstevel find_prop(Prom_node *pnode, char *name) 615*03831d35Sstevel { 616*03831d35Sstevel Prop *prop; 617*03831d35Sstevel 618*03831d35Sstevel if (pnode == NULL) { 619*03831d35Sstevel return (NULL); 620*03831d35Sstevel } 621*03831d35Sstevel 622*03831d35Sstevel if (pnode->props == NULL) { 623*03831d35Sstevel (void) printf("%s", dgettext(TEXT_DOMAIN, "Prom node has " 624*03831d35Sstevel "no properties\n")); 625*03831d35Sstevel return (NULL); 626*03831d35Sstevel } 627*03831d35Sstevel 628*03831d35Sstevel prop = pnode->props; 629*03831d35Sstevel while ((prop != NULL) && (strcmp(prop->name.opp.oprom_array, name))) 630*03831d35Sstevel prop = prop->next; 631*03831d35Sstevel 632*03831d35Sstevel return (prop); 633*03831d35Sstevel } 634*03831d35Sstevel 635*03831d35Sstevel /* 636*03831d35Sstevel * This function adds a board node to the board structure where that 637*03831d35Sstevel * that node's physical component lives. 638*03831d35Sstevel */ 639*03831d35Sstevel void 640*03831d35Sstevel add_node(Sys_tree *root, Prom_node *pnode) 641*03831d35Sstevel { 642*03831d35Sstevel int board; 643*03831d35Sstevel Board_node *bnode; 644*03831d35Sstevel Prom_node *p; 645*03831d35Sstevel 646*03831d35Sstevel /* add this node to the Board list of the appropriate board */ 647*03831d35Sstevel if ((board = get_board_num(pnode)) == -1) { 648*03831d35Sstevel /* board is 0 if not on Sunfire */ 649*03831d35Sstevel board = 0; 650*03831d35Sstevel } 651*03831d35Sstevel 652*03831d35Sstevel /* find the node with the same board number */ 653*03831d35Sstevel if ((bnode = find_board(root, board)) == NULL) { 654*03831d35Sstevel bnode = insert_board(root, board); 655*03831d35Sstevel bnode->board_type = UNKNOWN_BOARD; 656*03831d35Sstevel } 657*03831d35Sstevel 658*03831d35Sstevel /* now attach this prom node to the board list */ 659*03831d35Sstevel /* Insert this node at the end of the list */ 660*03831d35Sstevel pnode->sibling = NULL; 661*03831d35Sstevel if (bnode->nodes == NULL) 662*03831d35Sstevel bnode->nodes = pnode; 663*03831d35Sstevel else { 664*03831d35Sstevel p = bnode->nodes; 665*03831d35Sstevel while (p->sibling != NULL) 666*03831d35Sstevel p = p->sibling; 667*03831d35Sstevel p->sibling = pnode; 668*03831d35Sstevel } 669*03831d35Sstevel 670*03831d35Sstevel } 671*03831d35Sstevel 672*03831d35Sstevel /* 673*03831d35Sstevel * Find the device on the current board with the requested device ID 674*03831d35Sstevel * and name. If this rountine is passed a NULL pointer, it simply returns 675*03831d35Sstevel * NULL. 676*03831d35Sstevel */ 677*03831d35Sstevel Prom_node * 678*03831d35Sstevel find_device(Board_node *board, int id, char *name) 679*03831d35Sstevel { 680*03831d35Sstevel Prom_node *pnode; 681*03831d35Sstevel int mask; 682*03831d35Sstevel 683*03831d35Sstevel /* find the first cpu node */ 684*03831d35Sstevel pnode = dev_find_node(board->nodes, name); 685*03831d35Sstevel 686*03831d35Sstevel mask = 0x1F; 687*03831d35Sstevel while (pnode != NULL) { 688*03831d35Sstevel if ((get_id(pnode) & mask) == id) 689*03831d35Sstevel return (pnode); 690*03831d35Sstevel 691*03831d35Sstevel pnode = dev_next_node(pnode, name); 692*03831d35Sstevel } 693*03831d35Sstevel return (NULL); 694*03831d35Sstevel } 695*03831d35Sstevel 696*03831d35Sstevel Prom_node * 697*03831d35Sstevel dev_find_node_by_type(Prom_node *root, char *type, char *property) 698*03831d35Sstevel { 699*03831d35Sstevel Prom_node *node; 700*03831d35Sstevel char *type_prop; 701*03831d35Sstevel 702*03831d35Sstevel if (root == NULL || property == NULL) 703*03831d35Sstevel return (NULL); 704*03831d35Sstevel 705*03831d35Sstevel type_prop = (char *)get_prop_val(find_prop(root, type)); 706*03831d35Sstevel 707*03831d35Sstevel if (type_prop != NULL) { 708*03831d35Sstevel if (strcmp(type_prop, property) == 0) { 709*03831d35Sstevel return (root); 710*03831d35Sstevel } 711*03831d35Sstevel } 712*03831d35Sstevel 713*03831d35Sstevel /* look at your children first */ 714*03831d35Sstevel if ((node = dev_find_node_by_type(root->child, type, 715*03831d35Sstevel property)) != NULL) 716*03831d35Sstevel return (node); 717*03831d35Sstevel 718*03831d35Sstevel /* now look at your siblings */ 719*03831d35Sstevel if ((node = dev_find_node_by_type(root->sibling, type, 720*03831d35Sstevel property)) != NULL) 721*03831d35Sstevel return (node); 722*03831d35Sstevel 723*03831d35Sstevel return (NULL); /* not found */ 724*03831d35Sstevel } 725*03831d35Sstevel 726*03831d35Sstevel Prom_node * 727*03831d35Sstevel dev_next_node_by_type(Prom_node *root, char *type, char *property) 728*03831d35Sstevel { 729*03831d35Sstevel Prom_node *node; 730*03831d35Sstevel 731*03831d35Sstevel if (root == NULL || property == NULL) 732*03831d35Sstevel return (NULL); 733*03831d35Sstevel 734*03831d35Sstevel /* look at your children first */ 735*03831d35Sstevel if ((node = dev_find_node_by_type(root->child, type, 736*03831d35Sstevel property)) != NULL) 737*03831d35Sstevel return (node); 738*03831d35Sstevel 739*03831d35Sstevel /* now look at your siblings */ 740*03831d35Sstevel if ((node = dev_find_node_by_type(root->sibling, type, 741*03831d35Sstevel property)) != NULL) 742*03831d35Sstevel return (node); 743*03831d35Sstevel 744*03831d35Sstevel /* now look at papa's siblings */ 745*03831d35Sstevel if ((node = dev_find_node_by_type(root->parent->sibling, 746*03831d35Sstevel type, property)) != NULL) 747*03831d35Sstevel return (node); 748*03831d35Sstevel 749*03831d35Sstevel return (NULL); /* not found */ 750*03831d35Sstevel } 751*03831d35Sstevel 752*03831d35Sstevel /* 753*03831d35Sstevel * Do a depth-first walk of a device tree and 754*03831d35Sstevel * return the first node with the matching compatible. 755*03831d35Sstevel */ 756*03831d35Sstevel Prom_node * 757*03831d35Sstevel dev_find_node_by_compatible(Prom_node *root, char *compatible) 758*03831d35Sstevel { 759*03831d35Sstevel Prom_node *node; 760*03831d35Sstevel Prop *prop; 761*03831d35Sstevel char *compatible_array; 762*03831d35Sstevel int size, nbytes; 763*03831d35Sstevel 764*03831d35Sstevel if (root == NULL || compatible == NULL) 765*03831d35Sstevel return (NULL); 766*03831d35Sstevel 767*03831d35Sstevel if ((prop = find_prop(root, "compatible")) != NULL && 768*03831d35Sstevel (compatible_array = (char *)get_prop_val(prop)) != NULL) { 769*03831d35Sstevel /* 770*03831d35Sstevel * The Prop structure returned by find_prop() is supposed 771*03831d35Sstevel * to contain an indication of how big the value of the 772*03831d35Sstevel * compatible property is. Since it is an array of strings 773*03831d35Sstevel * this is our only means of determining just how many 774*03831d35Sstevel * strings might be in this property. However, this size 775*03831d35Sstevel * is often left as zero even though there is at least one 776*03831d35Sstevel * string present. When this is the case, all we can do 777*03831d35Sstevel * is examine the first string in the compatible property. 778*03831d35Sstevel */ 779*03831d35Sstevel 780*03831d35Sstevel for (size = prop->size; size >= 0; size -= nbytes) { 781*03831d35Sstevel if (strcmp(compatible_array, compatible) == 0) 782*03831d35Sstevel return (root); /* found a match */ 783*03831d35Sstevel 784*03831d35Sstevel nbytes = strlen(compatible_array) + 1; 785*03831d35Sstevel compatible_array += nbytes; 786*03831d35Sstevel } 787*03831d35Sstevel } 788*03831d35Sstevel 789*03831d35Sstevel node = dev_find_node_by_compatible(root->child, compatible); 790*03831d35Sstevel if (node != NULL) 791*03831d35Sstevel return (node); 792*03831d35Sstevel 793*03831d35Sstevel /* 794*03831d35Sstevel * Note the very deliberate use of tail recursion here. A good 795*03831d35Sstevel * compiler (such as Sun's) will recognize this and generate code 796*03831d35Sstevel * that does not allocate another stack frame. Instead, it will 797*03831d35Sstevel * overlay the existing stack frame with the new one, the only change 798*03831d35Sstevel * having been to replace the original root with its sibling. 799*03831d35Sstevel * This has the potential to create some confusion for anyone 800*03831d35Sstevel * trying to debug this code from a core dump, since the stack 801*03831d35Sstevel * trace will not reveal recursion on siblings, only on children. 802*03831d35Sstevel */ 803*03831d35Sstevel 804*03831d35Sstevel return (dev_find_node_by_compatible(root->sibling, compatible)); 805*03831d35Sstevel } 806*03831d35Sstevel 807*03831d35Sstevel /* 808*03831d35Sstevel * Start from the current node and return the next node besides 809*03831d35Sstevel * the current one which has the requested compatible property. 810*03831d35Sstevel */ 811*03831d35Sstevel Prom_node * 812*03831d35Sstevel dev_next_node_by_compatible(Prom_node *root, char *compatible) 813*03831d35Sstevel { 814*03831d35Sstevel Prom_node *node; 815*03831d35Sstevel 816*03831d35Sstevel if (root == NULL || compatible == NULL) 817*03831d35Sstevel return (NULL); 818*03831d35Sstevel 819*03831d35Sstevel node = dev_find_node_by_compatible(root->child, compatible); 820*03831d35Sstevel if (node != NULL) 821*03831d35Sstevel return (node); 822*03831d35Sstevel 823*03831d35Sstevel /* 824*03831d35Sstevel * More tail recursion. Even though it is a different function, 825*03831d35Sstevel * this will overlay the current stack frame. Caveat exterminator. 826*03831d35Sstevel */ 827*03831d35Sstevel 828*03831d35Sstevel node = dev_find_node_by_compatible(root->sibling, compatible); 829*03831d35Sstevel if (node != NULL) 830*03831d35Sstevel return (node); 831*03831d35Sstevel 832*03831d35Sstevel return (dev_find_node_by_compatible(root->parent->sibling, compatible)); 833*03831d35Sstevel } 834