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 1996-2002 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 "benv.h" 30 #include <sys/sunddi.h> 31 #include <sys/ddi_impldefs.h> 32 #include <sys/openpromio.h> 33 #include <stdio.h> 34 35 static int getpropval(struct openpromio *opp, char *prop); 36 37 static char *promdev = "/dev/openprom"; 38 static int prom_fd; 39 static char *mfail = "malloc"; 40 41 /* 42 * 128 is the size of the largest (currently) property name 43 * 16384 - MAXPROPSIZE - sizeof (int) is the size of the largest 44 * (currently) property value that is allowed. 45 * the sizeof (u_int) is from struct openpromio 46 */ 47 48 #define MAXPROPSIZE 128 49 #define MAXVALSIZE (16384 - MAXPROPSIZE - sizeof (u_int)) 50 #define BUFSIZE (MAXPROPSIZE + MAXVALSIZE + sizeof (u_int)) 51 #define MINVALSIZE (4 * sizeof (u_long)) 52 #define MINBUFSIZE (MINVALSIZE + sizeof (u_long)) 53 54 typedef union { 55 char buf[BUFSIZE]; 56 struct openpromio opp; 57 } Oppbuf; 58 59 typedef union { 60 char buf[MINVALSIZE + sizeof (u_int)]; 61 struct openpromio opp; 62 } Oppbuf_small; 63 64 static Oppbuf oppbuf; 65 66 static unsigned long 67 next(unsigned long id) 68 { 69 Oppbuf_small oppbuf; 70 struct openpromio *opp = &(oppbuf.opp); 71 unsigned long *ip = (unsigned long *)(opp->oprom_array); 72 73 memset(oppbuf.buf, 0, MINBUFSIZE); 74 opp->oprom_size = MINVALSIZE; 75 *ip = id; 76 if (ioctl(prom_fd, OPROMNEXT, opp) < 0) 77 return (0); 78 return (*(unsigned long *)opp->oprom_array); 79 } 80 81 static unsigned long 82 child(unsigned long id) 83 { 84 Oppbuf_small oppbuf; 85 struct openpromio *opp = &(oppbuf.opp); 86 unsigned long *ip = (unsigned long *)(opp->oprom_array); 87 88 memset(oppbuf.buf, 0, MINBUFSIZE); 89 opp->oprom_size = MINVALSIZE; 90 *ip = id; 91 if (ioctl(prom_fd, OPROMCHILD, opp) < 0) 92 return (0); 93 return (*(unsigned long *)opp->oprom_array); 94 } 95 96 /* 97 * Find a node by name from the prom device tree. 98 * Return the id or 0 if it is not found. 99 */ 100 static unsigned long 101 prom_findnode_byname(unsigned long id, char *name) 102 { 103 struct openpromio *opp = &(oppbuf.opp); 104 unsigned long nid; 105 106 if (id == 0) 107 return (0); 108 if (!getpropval(opp, "name")) 109 return (0); 110 if (strcmp(opp->oprom_array, name) == 0) 111 return (id); 112 if (nid = prom_findnode_byname(child(id), name)) 113 return (nid); 114 if (nid = prom_findnode_byname(next(id), name)) 115 return (nid); 116 return (0); 117 } 118 119 /* 120 * Make the current prom node be the rootnode and return its id. 121 */ 122 static unsigned long 123 prom_rootnode() 124 { 125 return (next(0)); 126 } 127 128 static int 129 getpropval(struct openpromio *opp, char *prop) 130 { 131 opp->oprom_size = MAXVALSIZE; 132 133 (void) strlcpy(opp->oprom_array, prop, MAXPROPSIZE); 134 if (ioctl(prom_fd, OPROMGETPROP, opp) < 0) 135 return (0); 136 if (opp->oprom_size == 0) 137 return (0); 138 return (1); 139 } 140 141 static int 142 getnextprop(struct openpromio *opp, char *prop) 143 { 144 opp->oprom_size = MAXVALSIZE; 145 146 (void) strlcpy(opp->oprom_array, prop, MAXPROPSIZE); 147 if (ioctl(prom_fd, OPROMNXTPROP, opp) < 0) 148 return (0); 149 if (opp->oprom_size == 0) 150 return (0); 151 return (1); 152 } 153 154 /* 155 * Get a pointer to the requested property from the current node. 156 * The property is stored in static storage and the returned pointer 157 * points into the static storage. The property length is placed in 158 * the location pointed to by the third argument. 159 */ 160 static unsigned char * 161 prom_getprop(char *prop, int *lenp) 162 { 163 struct openpromio *opp = &(oppbuf.opp); 164 165 if (!getpropval(opp, prop)) 166 return (NULL); 167 *lenp = opp->oprom_size; 168 return ((unsigned char *)opp->oprom_array); 169 } 170 171 static unsigned char * 172 prom_nextprop(char *prop) 173 { 174 struct openpromio *opp = &(oppbuf.opp); 175 176 if (!getnextprop(opp, prop)) 177 return ((unsigned char *)0); 178 return ((unsigned char *)opp->oprom_array); 179 } 180 181 ddi_prop_t * 182 get_proplist(char *name) 183 { 184 ddi_prop_t *plist, *npp, *plast; 185 char *curprop, *newprop; 186 unsigned char *propval; 187 unsigned long id; 188 189 plist = NULL; 190 plast = NULL; 191 id = prom_findnode_byname(prom_rootnode(), name); 192 if (id == 0) 193 return (plist); 194 curprop = ""; 195 while (newprop = (char *)prom_nextprop(curprop)) { 196 curprop = strdup(newprop); 197 npp = (ddi_prop_t *)malloc(sizeof (ddi_prop_t)); 198 if (npp == 0) 199 exit(_error(PERROR, mfail)); 200 propval = prom_getprop(curprop, &npp->prop_len); 201 npp->prop_name = curprop; 202 if (propval != NULL) { 203 npp->prop_val = (char *)malloc(npp->prop_len); 204 if (npp->prop_val == 0) 205 exit(_error(PERROR, mfail)); 206 memcpy(npp->prop_val, propval, npp->prop_len); 207 } else 208 npp->prop_val = NULL; 209 npp->prop_next = NULL; 210 if (plast == NULL) { 211 plist = npp; 212 } else { 213 plast->prop_next = npp; 214 } 215 plast = npp; 216 } 217 return (plist); 218 } 219 220 caddr_t 221 get_propval(char *name, char *node) 222 { 223 ddi_prop_t *prop, *plist; 224 225 if ((plist = get_proplist(node)) == NULL) 226 return (NULL); 227 228 for (prop = plist; prop != NULL; prop = prop->prop_next) 229 if (strcmp(prop->prop_name, name) == 0) 230 return (prop->prop_val); 231 232 return (NULL); 233 } 234 235 void 236 get_kbenv(void) 237 { 238 if ((prom_fd = open(promdev, O_RDONLY)) < 0) { 239 exit(_error(PERROR, "prom open failed")); 240 } 241 } 242 243 void 244 close_kbenv(void) 245 { 246 (void) close(prom_fd); 247 } 248