1 1.1 christos /* This file is part of the program psim. 2 1.1 christos 3 1.1 christos Copyright (C) 1994-1997, Andrew Cagney <cagney (at) highland.com.au> 4 1.1 christos 5 1.1 christos This program is free software; you can redistribute it and/or modify 6 1.1 christos it under the terms of the GNU General Public License as published by 7 1.1.1.2 christos the Free Software Foundation; either version 3 of the License, or 8 1.1 christos (at your option) any later version. 9 1.1 christos 10 1.1 christos This program is distributed in the hope that it will be useful, 11 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 12 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 1.1 christos GNU General Public License for more details. 14 1.1 christos 15 1.1 christos You should have received a copy of the GNU General Public License 16 1.1.1.2 christos along with this program; if not, see <http://www.gnu.org/licenses/>. 17 1.1 christos 18 1.1 christos */ 19 1.1 christos 20 1.1 christos 21 1.1 christos #ifndef _PARSE_C_ 22 1.1 christos #define _PARSE_C_ 23 1.1 christos 24 1.1 christos #include <stdio.h> 25 1.1 christos #include <stdarg.h> 26 1.1 christos 27 1.1 christos #include "basics.h" 28 1.1 christos 29 1.1 christos #include "device.h" 30 1.1 christos #include "tree.h" 31 1.1 christos 32 1.1 christos #include <stdlib.h> 33 1.1 christos #include <string.h> 34 1.1 christos #include <ctype.h> 35 1.1 christos 36 1.1 christos #include "libiberty.h" 37 1.1 christos 38 1.1 christos /* manipulate/lookup device names */ 39 1.1 christos 40 1.1 christos typedef struct _name_specifier { 41 1.1 christos /* components in the full length name */ 42 1.1 christos char *path; 43 1.1 christos char *property; 44 1.1 christos char *value; 45 1.1 christos /* current device */ 46 1.1 christos char *name; 47 1.1 christos char *base; 48 1.1 christos char *unit; 49 1.1 christos char *args; 50 1.1 christos /* previous device */ 51 1.1 christos char *last_name; 52 1.1 christos char *last_base; 53 1.1 christos char *last_unit; 54 1.1 christos char *last_args; 55 1.1 christos /* work area */ 56 1.1 christos char buf[1024]; 57 1.1 christos } name_specifier; 58 1.1 christos 59 1.1 christos 60 1.1 christos 61 1.1 christos /* Given a device specifier, break it up into its main components: 62 1.1 christos path (and if present) property name and property value. */ 63 1.1 christos 64 1.1 christos STATIC_INLINE_TREE\ 65 1.1 christos (int) 66 1.1 christos split_device_specifier(device *current, 67 1.1 christos const char *device_specifier, 68 1.1 christos name_specifier *spec) 69 1.1 christos { 70 1.1 christos char *chp = NULL; 71 1.1 christos 72 1.1 christos /* expand any leading alias if present */ 73 1.1 christos if (current != NULL 74 1.1 christos && *device_specifier != '\0' 75 1.1 christos && *device_specifier != '.' 76 1.1 christos && *device_specifier != '/') { 77 1.1 christos device *aliases = tree_find_device(current, "/aliases"); 78 1.1 christos char alias[32]; 79 1.1 christos int len = 0; 80 1.1 christos while (device_specifier[len] != '\0' 81 1.1 christos && device_specifier[len] != '/' 82 1.1 christos && device_specifier[len] != ':' 83 1.1 christos && !isspace(device_specifier[len])) { 84 1.1 christos alias[len] = device_specifier[len]; 85 1.1 christos len++; 86 1.1 christos if (len >= sizeof(alias)) 87 1.1 christos error("split_device_specifier: buffer overflow"); 88 1.1 christos } 89 1.1 christos alias[len] = '\0'; 90 1.1 christos if (aliases != NULL 91 1.1 christos && device_find_property(aliases, alias)) { 92 1.1 christos strcpy(spec->buf, device_find_string_property(aliases, alias)); 93 1.1 christos strcat(spec->buf, device_specifier + len); 94 1.1 christos } 95 1.1 christos else { 96 1.1 christos strcpy(spec->buf, device_specifier); 97 1.1 christos } 98 1.1 christos } 99 1.1 christos else { 100 1.1 christos strcpy(spec->buf, device_specifier); 101 1.1 christos } 102 1.1 christos 103 1.1 christos /* check no overflow */ 104 1.1 christos if (strlen(spec->buf) >= sizeof(spec->buf)) 105 1.1 christos error("split_device_specifier: buffer overflow\n"); 106 1.1 christos 107 1.1 christos /* strip leading spaces */ 108 1.1 christos chp = spec->buf; 109 1.1 christos while (*chp != '\0' && isspace(*chp)) 110 1.1 christos chp++; 111 1.1 christos if (*chp == '\0') 112 1.1 christos return 0; 113 1.1 christos 114 1.1 christos /* find the path and terminate it with null */ 115 1.1 christos spec->path = chp; 116 1.1 christos while (*chp != '\0' && !isspace(*chp)) 117 1.1 christos chp++; 118 1.1 christos if (*chp != '\0') { 119 1.1 christos *chp = '\0'; 120 1.1 christos chp++; 121 1.1 christos } 122 1.1 christos 123 1.1 christos /* and any value */ 124 1.1 christos while (*chp != '\0' && isspace(*chp)) 125 1.1 christos chp++; 126 1.1 christos spec->value = chp; 127 1.1 christos 128 1.1 christos /* now go back and chop the property off of the path */ 129 1.1 christos if (spec->value[0] == '\0') { 130 1.1 christos spec->property = NULL; /*not a property*/ 131 1.1 christos spec->value = NULL; 132 1.1 christos } 133 1.1 christos else if (spec->value[0] == '>' 134 1.1 christos || spec->value[0] == '<') { 135 1.1 christos /* an interrupt spec */ 136 1.1 christos spec->property = NULL; 137 1.1 christos } 138 1.1 christos else { 139 1.1 christos chp = strrchr(spec->path, '/'); 140 1.1 christos if (chp == NULL) { 141 1.1 christos spec->property = spec->path; 142 1.1 christos spec->path = strchr(spec->property, '\0'); 143 1.1 christos } 144 1.1 christos else { 145 1.1 christos *chp = '\0'; 146 1.1 christos spec->property = chp+1; 147 1.1 christos } 148 1.1 christos } 149 1.1 christos 150 1.1 christos /* and mark the rest as invalid */ 151 1.1 christos spec->name = NULL; 152 1.1 christos spec->base = NULL; 153 1.1 christos spec->unit = NULL; 154 1.1 christos spec->args = NULL; 155 1.1 christos spec->last_name = NULL; 156 1.1 christos spec->last_base = NULL; 157 1.1 christos spec->last_unit = NULL; 158 1.1 christos spec->last_args = NULL; 159 1.1 christos 160 1.1 christos return 1; 161 1.1 christos } 162 1.1 christos 163 1.1 christos 164 1.1 christos /* given a device specifier break it up into its main components - 165 1.1 christos path and property name - assuming that the last `device' is a 166 1.1 christos property name. */ 167 1.1 christos 168 1.1 christos STATIC_INLINE_DEVICE\ 169 1.1 christos (int) 170 1.1 christos split_property_specifier(device *current, 171 1.1 christos const char *property_specifier, 172 1.1 christos name_specifier *spec) 173 1.1 christos { 174 1.1 christos if (split_device_specifier(current, property_specifier, spec)) { 175 1.1 christos if (spec->property == NULL) { 176 1.1 christos /* force the last name to be a property name */ 177 1.1 christos char *chp = strrchr(spec->path, '/'); 178 1.1 christos if (chp == NULL) { 179 1.1 christos spec->property = spec->path; 180 1.1 christos spec->path = strrchr(spec->property, '\0');; 181 1.1 christos } 182 1.1 christos else { 183 1.1 christos *chp = '\0'; 184 1.1 christos spec->property = chp+1; 185 1.1 christos } 186 1.1 christos } 187 1.1 christos return 1; 188 1.1 christos } 189 1.1 christos else 190 1.1 christos return 0; 191 1.1 christos } 192 1.1 christos 193 1.1 christos 194 1.1 christos /* device the next device name and split it up, return 0 when no more 195 1.1 christos names to device */ 196 1.1 christos 197 1.1 christos STATIC_INLINE_TREE\ 198 1.1 christos (int) 199 1.1 christos split_device_name(name_specifier *spec) 200 1.1 christos { 201 1.1 christos char *chp; 202 1.1 christos /* remember what came before */ 203 1.1 christos spec->last_name = spec->name; 204 1.1 christos spec->last_base = spec->base; 205 1.1 christos spec->last_unit = spec->unit; 206 1.1 christos spec->last_args = spec->args; 207 1.1 christos /* finished? */ 208 1.1 christos if (spec->path[0] == '\0') { 209 1.1 christos spec->name = NULL; 210 1.1 christos spec->base = NULL; 211 1.1 christos spec->unit = NULL; 212 1.1 christos spec->args = NULL; 213 1.1 christos return 0; 214 1.1 christos } 215 1.1 christos /* break the current device spec from the path */ 216 1.1 christos spec->name = spec->path; 217 1.1 christos chp = strchr(spec->name, '/'); 218 1.1 christos if (chp == NULL) 219 1.1 christos spec->path = strchr(spec->name, '\0'); 220 1.1 christos else { 221 1.1 christos spec->path = chp+1; 222 1.1 christos *chp = '\0'; 223 1.1 christos } 224 1.1 christos /* break out the base */ 225 1.1 christos if (spec->name[0] == '(') { 226 1.1 christos chp = strchr(spec->name, ')'); 227 1.1 christos if (chp == NULL) { 228 1.1 christos spec->base = spec->name; 229 1.1 christos } 230 1.1 christos else { 231 1.1 christos *chp = '\0'; 232 1.1 christos spec->base = spec->name + 1; 233 1.1 christos spec->name = chp + 1; 234 1.1 christos } 235 1.1 christos } 236 1.1 christos else { 237 1.1 christos spec->base = spec->name; 238 1.1 christos } 239 1.1 christos /* now break out the unit */ 240 1.1 christos chp = strchr(spec->name, '@'); 241 1.1 christos if (chp == NULL) { 242 1.1 christos spec->unit = NULL; 243 1.1 christos chp = spec->name; 244 1.1 christos } 245 1.1 christos else { 246 1.1 christos *chp = '\0'; 247 1.1 christos chp += 1; 248 1.1 christos spec->unit = chp; 249 1.1 christos } 250 1.1 christos /* finally any args */ 251 1.1 christos chp = strchr(chp, ':'); 252 1.1 christos if (chp == NULL) 253 1.1 christos spec->args = NULL; 254 1.1 christos else { 255 1.1 christos *chp = '\0'; 256 1.1 christos spec->args = chp+1; 257 1.1 christos } 258 1.1 christos return 1; 259 1.1 christos } 260 1.1 christos 261 1.1 christos 262 1.1 christos /* device the value, returning the next non-space token */ 263 1.1 christos 264 1.1 christos STATIC_INLINE_TREE\ 265 1.1 christos (char *) 266 1.1 christos split_value(name_specifier *spec) 267 1.1 christos { 268 1.1 christos char *token; 269 1.1 christos if (spec->value == NULL) 270 1.1 christos return NULL; 271 1.1 christos /* skip leading white space */ 272 1.1 christos while (isspace(spec->value[0])) 273 1.1 christos spec->value++; 274 1.1 christos if (spec->value[0] == '\0') { 275 1.1 christos spec->value = NULL; 276 1.1 christos return NULL; 277 1.1 christos } 278 1.1 christos token = spec->value; 279 1.1 christos /* find trailing space */ 280 1.1 christos while (spec->value[0] != '\0' && !isspace(spec->value[0])) 281 1.1 christos spec->value++; 282 1.1 christos /* chop this value out */ 283 1.1 christos if (spec->value[0] != '\0') { 284 1.1 christos spec->value[0] = '\0'; 285 1.1 christos spec->value++; 286 1.1 christos } 287 1.1 christos return token; 288 1.1 christos } 289 1.1 christos 290 1.1 christos 291 1.1 christos 292 1.1 christos /* traverse the path specified by spec starting at current */ 293 1.1 christos 294 1.1 christos STATIC_INLINE_TREE\ 295 1.1 christos (device *) 296 1.1 christos split_find_device(device *current, 297 1.1 christos name_specifier *spec) 298 1.1 christos { 299 1.1 christos /* strip off (and process) any leading ., .., ./ and / */ 300 1.1 christos while (1) { 301 1.1 christos if (strncmp(spec->path, "/", strlen("/")) == 0) { 302 1.1 christos /* cd /... */ 303 1.1 christos while (current != NULL && device_parent(current) != NULL) 304 1.1 christos current = device_parent(current); 305 1.1 christos spec->path += strlen("/"); 306 1.1 christos } 307 1.1 christos else if (strncmp(spec->path, "./", strlen("./")) == 0) { 308 1.1 christos /* cd ./... */ 309 1.1 christos spec->path += strlen("./"); 310 1.1 christos } 311 1.1 christos else if (strncmp(spec->path, "../", strlen("../")) == 0) { 312 1.1 christos /* cd ../... */ 313 1.1 christos if (current != NULL && device_parent(current) != NULL) 314 1.1 christos current = device_parent(current); 315 1.1 christos spec->path += strlen("../"); 316 1.1 christos } 317 1.1 christos else if (strcmp(spec->path, ".") == 0) { 318 1.1 christos /* cd . */ 319 1.1 christos spec->path += strlen("."); 320 1.1 christos } 321 1.1 christos else if (strcmp(spec->path, "..") == 0) { 322 1.1 christos /* cd . */ 323 1.1 christos if (current != NULL && device_parent(current) != NULL) 324 1.1 christos current = device_parent(current); 325 1.1 christos spec->path += strlen(".."); 326 1.1 christos } 327 1.1 christos else 328 1.1 christos break; 329 1.1 christos } 330 1.1 christos 331 1.1 christos /* now go through the path proper */ 332 1.1 christos 333 1.1 christos if (current == NULL) { 334 1.1 christos split_device_name(spec); 335 1.1 christos return NULL; 336 1.1 christos } 337 1.1 christos 338 1.1 christos while (split_device_name(spec)) { 339 1.1 christos device *child; 340 1.1 christos for (child = device_child(current); 341 1.1 christos child != NULL; child = device_sibling(child)) { 342 1.1 christos if (strcmp(spec->name, device_name(child)) == 0) { 343 1.1 christos if (spec->unit == NULL) 344 1.1 christos break; 345 1.1 christos else { 346 1.1 christos device_unit phys; 347 1.1 christos device_decode_unit(current, spec->unit, &phys); 348 1.1 christos if (memcmp(&phys, device_unit_address(child), 349 1.1 christos sizeof(device_unit)) == 0) 350 1.1 christos break; 351 1.1 christos } 352 1.1 christos } 353 1.1 christos } 354 1.1 christos if (child == NULL) 355 1.1 christos return current; /* search failed */ 356 1.1 christos current = child; 357 1.1 christos } 358 1.1 christos 359 1.1 christos return current; 360 1.1 christos } 361 1.1 christos 362 1.1 christos 363 1.1 christos STATIC_INLINE_TREE\ 364 1.1 christos (device *) 365 1.1 christos split_fill_path(device *current, 366 1.1 christos const char *device_specifier, 367 1.1 christos name_specifier *spec) 368 1.1 christos { 369 1.1 christos /* break it up */ 370 1.1 christos if (!split_device_specifier(current, device_specifier, spec)) 371 1.1 christos device_error(current, "error parsing %s\n", device_specifier); 372 1.1 christos 373 1.1 christos /* fill our tree with its contents */ 374 1.1 christos current = split_find_device(current, spec); 375 1.1 christos 376 1.1 christos /* add any additional devices as needed */ 377 1.1 christos if (spec->name != NULL) { 378 1.1 christos do { 379 1.1 christos current = device_create(current, spec->base, spec->name, 380 1.1 christos spec->unit, spec->args); 381 1.1 christos } while (split_device_name(spec)); 382 1.1 christos } 383 1.1 christos 384 1.1 christos return current; 385 1.1 christos } 386 1.1 christos 387 1.1 christos 388 1.1 christos INLINE_TREE\ 389 1.1 christos (void) 390 1.1 christos tree_init(device *root, 391 1.1 christos psim *system) 392 1.1 christos { 393 1.1.1.3 christos TRACE(trace_device_tree, ("tree_init(root=%p, system=%p)\n", 394 1.1.1.3 christos root, 395 1.1.1.3 christos system)); 396 1.1 christos /* remove the old, rebuild the new */ 397 1.1 christos tree_traverse(root, device_clean, NULL, system); 398 1.1 christos tree_traverse(root, device_init_static_properties, NULL, system); 399 1.1 christos tree_traverse(root, device_init_address, NULL, system); 400 1.1 christos tree_traverse(root, device_init_runtime_properties, NULL, system); 401 1.1 christos tree_traverse(root, device_init_data, NULL, system); 402 1.1 christos } 403 1.1 christos 404 1.1 christos 405 1.1 christos 406 1.1 christos /* <non-white-space> */ 408 1.1 christos 409 1.1 christos STATIC_INLINE_TREE\ 410 1.1 christos (const char *) 411 1.1 christos skip_token(const char *chp) 412 1.1 christos { 413 1.1 christos while (!isspace(*chp) && *chp != '\0') 414 1.1 christos chp++; 415 1.1 christos while (isspace(*chp) && *chp != '\0') 416 1.1 christos chp++; 417 1.1 christos return chp; 418 1.1 christos } 419 1.1 christos 420 1.1 christos 421 1.1 christos /* count the number of entries */ 422 1.1 christos 423 1.1 christos STATIC_INLINE_TREE\ 424 1.1 christos (int) 425 1.1 christos count_entries(device *current, 426 1.1 christos const char *property_name, 427 1.1 christos const char *property_value, 428 1.1 christos int modulo) 429 1.1 christos { 430 1.1 christos const char *chp = property_value; 431 1.1 christos int nr_entries = 0; 432 1.1 christos while (*chp != '\0') { 433 1.1 christos nr_entries += 1; 434 1.1 christos chp = skip_token(chp); 435 1.1 christos } 436 1.1 christos if ((nr_entries % modulo) != 0) { 437 1.1 christos device_error(current, "incorrect number of entries for %s property %s, should be multiple of %d", 438 1.1 christos property_name, property_value, modulo); 439 1.1 christos } 440 1.1 christos return nr_entries / modulo; 441 1.1 christos } 442 1.1 christos 443 1.1 christos 444 1.1 christos 445 1.1 christos /* parse: <address> ::= <token> ; device dependant */ 446 1.1 christos 447 1.1 christos STATIC_INLINE_TREE\ 448 1.1 christos (const char *) 449 1.1 christos parse_address(device *current, 450 1.1 christos device *bus, 451 1.1 christos const char *chp, 452 1.1 christos device_unit *address) 453 1.1 christos { 454 1.1 christos ASSERT(device_nr_address_cells(bus) > 0); 455 1.1 christos if (device_decode_unit(bus, chp, address) < 0) 456 1.1 christos device_error(current, "invalid unit address in %s", chp); 457 1.1 christos return skip_token(chp); 458 1.1 christos } 459 1.1 christos 460 1.1 christos 461 1.1 christos /* parse: <size> ::= <number> { "," <number> } ; */ 462 1.1 christos 463 1.1 christos STATIC_INLINE_TREE\ 464 1.1 christos (const char *) 465 1.1 christos parse_size(device *current, 466 1.1 christos device *bus, 467 1.1 christos const char *chp, 468 1.1 christos device_unit *size) 469 1.1 christos { 470 1.1 christos int i; 471 1.1 christos int nr; 472 1.1 christos const char *curr = chp; 473 1.1 christos memset(size, 0, sizeof(*size)); 474 1.1 christos /* parse the numeric list */ 475 1.1 christos size->nr_cells = device_nr_size_cells(bus); 476 1.1 christos nr = 0; 477 1.1 christos ASSERT(size->nr_cells > 0); 478 1.1 christos while (1) { 479 1.1 christos char *next; 480 1.1 christos size->cells[nr] = strtoul(curr, &next, 0); 481 1.1 christos if (curr == next) 482 1.1 christos device_error(current, "Problem parsing <size> %s", chp); 483 1.1 christos nr += 1; 484 1.1 christos if (next[0] != ',') 485 1.1 christos break; 486 1.1 christos if (nr == size->nr_cells) 487 1.1 christos device_error(current, "Too many values in <size> %s", chp); 488 1.1 christos curr = next + 1; 489 1.1 christos } 490 1.1 christos ASSERT(nr > 0 && nr <= size->nr_cells); 491 1.1 christos /* right align the numbers */ 492 1.1 christos for (i = 1; i <= size->nr_cells; i++) { 493 1.1 christos if (i <= nr) 494 1.1 christos size->cells[size->nr_cells - i] = size->cells[nr - i]; 495 1.1 christos else 496 1.1 christos size->cells[size->nr_cells - i] = 0; 497 1.1 christos } 498 1.1 christos return skip_token(chp); 499 1.1 christos } 500 1.1 christos 501 1.1 christos 502 1.1 christos /* parse: <reg> ::= { <address> <size> } ; */ 503 1.1 christos 504 1.1 christos STATIC_INLINE_TREE\ 505 1.1 christos (void) 506 1.1 christos parse_reg_property(device *current, 507 1.1 christos const char *property_name, 508 1.1 christos const char *property_value) 509 1.1 christos { 510 1.1 christos int nr_regs; 511 1.1 christos int reg_nr; 512 1.1 christos reg_property_spec *regs; 513 1.1 christos const char *chp; 514 1.1 christos device *bus = device_parent(current); 515 1.1 christos 516 1.1 christos /* determine the number of reg entries by counting tokens */ 517 1.1 christos nr_regs = count_entries(current, property_name, property_value, 518 1.1 christos 1 + (device_nr_size_cells(bus) > 0)); 519 1.1 christos 520 1.1 christos /* create working space */ 521 1.1 christos regs = zalloc(nr_regs * sizeof(*regs)); 522 1.1 christos 523 1.1 christos /* fill it in */ 524 1.1 christos chp = property_value; 525 1.1 christos for (reg_nr = 0; reg_nr < nr_regs; reg_nr++) { 526 1.1 christos chp = parse_address(current, bus, chp, ®s[reg_nr].address); 527 1.1 christos if (device_nr_size_cells(bus) > 0) 528 1.1 christos chp = parse_size(current, bus, chp, ®s[reg_nr].size); 529 1.1.1.3 christos else 530 1.1 christos memset(®s[reg_nr].size, 0, sizeof (regs[reg_nr].size)); 531 1.1 christos } 532 1.1 christos 533 1.1 christos /* create it */ 534 1.1 christos device_add_reg_array_property(current, property_name, 535 1.1 christos regs, nr_regs); 536 1.1 christos 537 1.1 christos free(regs); 538 1.1 christos } 539 1.1 christos 540 1.1 christos 541 1.1 christos /* { <child-address> <parent-address> <child-size> }* */ 542 1.1 christos 543 1.1 christos STATIC_INLINE_TREE\ 544 1.1 christos (void) 545 1.1 christos parse_ranges_property(device *current, 546 1.1 christos const char *property_name, 547 1.1 christos const char *property_value) 548 1.1 christos { 549 1.1 christos int nr_ranges; 550 1.1 christos int range_nr; 551 1.1 christos range_property_spec *ranges; 552 1.1 christos const char *chp; 553 1.1 christos 554 1.1 christos /* determine the number of ranges specified */ 555 1.1 christos nr_ranges = count_entries(current, property_name, property_value, 3); 556 1.1 christos 557 1.1 christos /* create a property of that size */ 558 1.1 christos ranges = zalloc(nr_ranges * sizeof(*ranges)); 559 1.1 christos 560 1.1 christos /* fill it in */ 561 1.1 christos chp = property_value; 562 1.1 christos for (range_nr = 0; range_nr < nr_ranges; range_nr++) { 563 1.1 christos chp = parse_address(current, current, 564 1.1 christos chp, &ranges[range_nr].child_address); 565 1.1 christos chp = parse_address(current, device_parent(current), 566 1.1 christos chp, &ranges[range_nr].parent_address); 567 1.1 christos chp = parse_size(current, current, 568 1.1 christos chp, &ranges[range_nr].size); 569 1.1 christos } 570 1.1 christos 571 1.1 christos /* create it */ 572 1.1 christos device_add_range_array_property(current, property_name, ranges, nr_ranges); 573 1.1 christos 574 1.1 christos free(ranges); 575 1.1 christos } 576 1.1 christos 577 1.1 christos 578 1.1 christos /* <integer> ... */ 579 1.1 christos 580 1.1 christos STATIC_INLINE_TREE\ 581 1.1 christos (void) 582 1.1 christos parse_integer_property(device *current, 583 1.1 christos const char *property_name, 584 1.1 christos const char *property_value) 585 1.1 christos { 586 1.1 christos int nr_entries; 587 1.1 christos unsigned_cell words[1024]; 588 1.1 christos /* integer or integer array? */ 589 1.1 christos nr_entries = 0; 590 1.1 christos while (1) { 591 1.1 christos char *end; 592 1.1 christos words[nr_entries] = strtoul(property_value, &end, 0); 593 1.1 christos if (property_value == end) 594 1.1 christos break; 595 1.1 christos nr_entries += 1; 596 1.1 christos if (nr_entries * sizeof(words[0]) >= sizeof(words)) 597 1.1 christos device_error(current, "buffer overflow"); 598 1.1 christos property_value = end; 599 1.1 christos } 600 1.1 christos if (nr_entries == 0) 601 1.1 christos device_error(current, "error parsing integer property %s (%s)", 602 1.1 christos property_name, property_value); 603 1.1 christos else if (nr_entries == 1) 604 1.1 christos device_add_integer_property(current, property_name, words[0]); 605 1.1 christos else { 606 1.1 christos int i; 607 1.1 christos for (i = 0; i < nr_entries; i++) { 608 1.1 christos H2BE(words[i]); 609 1.1 christos } 610 1.1 christos /* perhaps integer array property is better */ 611 1.1 christos device_add_array_property(current, property_name, words, 612 1.1 christos sizeof(words[0]) * nr_entries); 613 1.1 christos } 614 1.1 christos } 615 1.1 christos 616 1.1 christos /* PROPERTY_VALUE is a raw property value. Quote it as required by 617 1.1 christos parse_string_property. It is the caller's responsibility to free 618 1.1 christos the memory returned. */ 619 1.1 christos 620 1.1 christos EXTERN_TREE\ 621 1.1 christos (char *) 622 1.1 christos tree_quote_property(const char *property_value) 623 1.1 christos { 624 1.1 christos char *p; 625 1.1 christos char *ret; 626 1.1 christos const char *chp; 627 1.1 christos int quotees; 628 1.1 christos 629 1.1 christos /* Count characters needing quotes in PROPERTY_VALUE. */ 630 1.1 christos quotees = 0; 631 1.1 christos for (chp = property_value; *chp; ++chp) 632 1.1 christos if (*chp == '\\' || *chp == '"') 633 1.1 christos ++quotees; 634 1.1 christos 635 1.1 christos ret = (char *) xmalloc (strlen (property_value) 636 1.1 christos + 2 /* quotes */ 637 1.1 christos + quotees 638 1.1 christos + 1 /* terminator */); 639 1.1 christos 640 1.1 christos p = ret; 641 1.1 christos /* Add the opening quote. */ 642 1.1 christos *p++ = '"'; 643 1.1 christos /* Copy the value. */ 644 1.1 christos for (chp = property_value; *chp; ++chp) 645 1.1 christos if (*chp == '\\' || *chp == '"') 646 1.1 christos { 647 1.1 christos /* Quote this character. */ 648 1.1 christos *p++ = '\\'; 649 1.1 christos *p++ = *chp; 650 1.1 christos } 651 1.1 christos else 652 1.1 christos *p++ = *chp; 653 1.1 christos /* Add the closing quote. */ 654 1.1 christos *p++ = '"'; 655 1.1 christos /* Terminate the string. */ 656 1.1 christos *p++ = '\0'; 657 1.1 christos 658 1.1 christos return ret; 659 1.1 christos } 660 1.1 christos 661 1.1 christos /* <string> ... */ 662 1.1 christos 663 1.1 christos STATIC_INLINE_TREE\ 664 1.1 christos (void) 665 1.1 christos parse_string_property(device *current, 666 1.1 christos const char *property_name, 667 1.1 christos const char *property_value) 668 1.1 christos { 669 1.1 christos char **strings; 670 1.1 christos const char *chp; 671 1.1 christos int nr_strings; 672 1.1 christos int approx_nr_strings; 673 1.1 christos 674 1.1 christos /* get an estimate as to the number of strings by counting double 675 1.1 christos quotes */ 676 1.1 christos approx_nr_strings = 2; 677 1.1 christos for (chp = property_value; *chp; chp++) { 678 1.1 christos if (*chp == '"') 679 1.1 christos approx_nr_strings++; 680 1.1 christos } 681 1.1 christos approx_nr_strings = (approx_nr_strings) / 2; 682 1.1 christos 683 1.1 christos /* create a string buffer for that many (plus a null) */ 684 1.1 christos strings = (char**)zalloc((approx_nr_strings + 1) * sizeof(char*)); 685 1.1 christos 686 1.1 christos /* now find all the strings */ 687 1.1 christos chp = property_value; 688 1.1 christos nr_strings = 0; 689 1.1 christos while (1) { 690 1.1 christos 691 1.1 christos /* skip leading space */ 692 1.1 christos while (*chp != '\0' && isspace(*chp)) 693 1.1 christos chp += 1; 694 1.1 christos if (*chp == '\0') 695 1.1 christos break; 696 1.1 christos 697 1.1 christos /* copy it in */ 698 1.1 christos if (*chp == '"') { 699 1.1 christos /* a quoted string - watch for '\' et.al. */ 700 1.1 christos /* estimate the size and allocate space for it */ 701 1.1 christos int pos; 702 1.1 christos chp++; 703 1.1 christos pos = 0; 704 1.1 christos while (chp[pos] != '\0' && chp[pos] != '"') { 705 1.1 christos if (chp[pos] == '\\' && chp[pos+1] != '\0') 706 1.1 christos pos += 2; 707 1.1 christos else 708 1.1 christos pos += 1; 709 1.1 christos } 710 1.1 christos strings[nr_strings] = zalloc(pos + 1); 711 1.1 christos /* copy the string over */ 712 1.1 christos pos = 0; 713 1.1 christos while (*chp != '\0' && *chp != '"') { 714 1.1 christos if (*chp == '\\' && *(chp+1) != '\0') { 715 1.1 christos strings[nr_strings][pos] = *(chp+1); 716 1.1 christos chp += 2; 717 1.1 christos pos++; 718 1.1 christos } 719 1.1 christos else { 720 1.1 christos strings[nr_strings][pos] = *chp; 721 1.1 christos chp += 1; 722 1.1 christos pos++; 723 1.1 christos } 724 1.1 christos } 725 1.1 christos if (*chp != '\0') 726 1.1 christos chp++; 727 1.1 christos strings[nr_strings][pos] = '\0'; 728 1.1 christos } 729 1.1 christos else { 730 1.1 christos /* copy over a single unquoted token */ 731 1.1 christos int len = 0; 732 1.1 christos while (chp[len] != '\0' && !isspace(chp[len])) 733 1.1 christos len++; 734 1.1 christos strings[nr_strings] = zalloc(len + 1); 735 1.1 christos strncpy(strings[nr_strings], chp, len); 736 1.1 christos strings[nr_strings][len] = '\0'; 737 1.1 christos chp += len; 738 1.1 christos } 739 1.1 christos nr_strings++; 740 1.1 christos if (nr_strings > approx_nr_strings) 741 1.1 christos device_error(current, "String property %s badly formatted", 742 1.1 christos property_name); 743 1.1 christos } 744 1.1 christos ASSERT(strings[nr_strings] == NULL); /* from zalloc */ 745 1.1 christos 746 1.1 christos /* install it */ 747 1.1 christos if (nr_strings == 0) 748 1.1 christos device_add_string_property(current, property_name, ""); 749 1.1 christos else if (nr_strings == 1) 750 1.1 christos device_add_string_property(current, property_name, strings[0]); 751 1.1 christos else { 752 1.1 christos const char **specs = (const char**)strings; /* stop a bogus error */ 753 1.1 christos device_add_string_array_property(current, property_name, 754 1.1 christos specs, nr_strings); 755 1.1 christos } 756 1.1 christos 757 1.1 christos /* flush the created string */ 758 1.1 christos while (nr_strings > 0) { 759 1.1 christos nr_strings--; 760 1.1 christos free(strings[nr_strings]); 761 1.1 christos } 762 1.1 christos free(strings); 763 1.1 christos } 764 1.1 christos 765 1.1 christos 766 1.1 christos /* <path-to-ihandle-device> */ 767 1.1 christos 768 1.1 christos STATIC_INLINE_TREE\ 769 1.1 christos (void) 770 1.1 christos parse_ihandle_property(device *current, 771 1.1 christos const char *property, 772 1.1 christos const char *value) 773 1.1 christos { 774 1.1 christos ihandle_runtime_property_spec ihandle; 775 1.1 christos 776 1.1 christos /* pass the full path */ 777 1.1 christos ihandle.full_path = value; 778 1.1 christos 779 1.1 christos /* save this ready for the ihandle create */ 780 1.1 christos device_add_ihandle_runtime_property(current, property, 781 1.1 christos &ihandle); 782 1.1 christos } 783 1.1 christos 784 1.1 christos 785 1.1 christos 786 1.1 christos EXTERN_TREE\ 787 1.1 christos (device *) 788 1.1 christos tree_parse(device *current, 789 1.1 christos const char *fmt, 790 1.1 christos ...) 791 1.1 christos { 792 1.1 christos char device_specifier[1024]; 793 1.1 christos name_specifier spec; 794 1.1 christos 795 1.1 christos /* format the path */ 796 1.1 christos { 797 1.1 christos va_list ap; 798 1.1 christos va_start(ap, fmt); 799 1.1 christos vsprintf(device_specifier, fmt, ap); 800 1.1 christos va_end(ap); 801 1.1 christos if (strlen(device_specifier) >= sizeof(device_specifier)) 802 1.1 christos error("device_tree_add_deviced: buffer overflow\n"); 803 1.1 christos } 804 1.1 christos 805 1.1 christos /* construct the tree down to the final device */ 806 1.1 christos current = split_fill_path(current, device_specifier, &spec); 807 1.1 christos 808 1.1 christos /* is there an interrupt spec */ 809 1.1 christos if (spec.property == NULL 810 1.1 christos && spec.value != NULL) { 811 1.1 christos char *op = split_value(&spec); 812 1.1 christos switch (op[0]) { 813 1.1 christos case '>': 814 1.1 christos { 815 1.1 christos char *my_port_name = split_value(&spec); 816 1.1 christos int my_port; 817 1.1 christos char *dest_port_name = split_value(&spec); 818 1.1 christos int dest_port; 819 1.1 christos name_specifier dest_spec; 820 1.1 christos char *dest_device_name = split_value(&spec); 821 1.1 christos device *dest; 822 1.1 christos /* find my name */ 823 1.1 christos my_port = device_interrupt_decode(current, my_port_name, 824 1.1 christos output_port); 825 1.1 christos /* find the dest device and port */ 826 1.1 christos dest = split_fill_path(current, dest_device_name, &dest_spec); 827 1.1 christos dest_port = device_interrupt_decode(dest, dest_port_name, 828 1.1 christos input_port); 829 1.1 christos /* connect the two */ 830 1.1 christos device_interrupt_attach(current, 831 1.1 christos my_port, 832 1.1 christos dest, 833 1.1.1.4 christos dest_port, 834 1.1 christos permanent_object); 835 1.1 christos } 836 1.1 christos break; 837 1.1 christos default: 838 1.1 christos device_error(current, "unreconised interrupt spec %s\n", spec.value); 839 1.1 christos break; 840 1.1 christos } 841 1.1 christos } 842 1.1 christos 843 1.1 christos /* is there a property */ 844 1.1 christos if (spec.property != NULL) { 845 1.1 christos if (strcmp(spec.value, "true") == 0) 846 1.1 christos device_add_boolean_property(current, spec.property, 1); 847 1.1 christos else if (strcmp(spec.value, "false") == 0) 848 1.1 christos device_add_boolean_property(current, spec.property, 0); 849 1.1 christos else { 850 1.1 christos const device_property *property; 851 1.1 christos switch (spec.value[0]) { 852 1.1 christos case '*': 853 1.1 christos parse_ihandle_property(current, spec.property, spec.value + 1); 854 1.1 christos break; 855 1.1 christos case '[': 856 1.1.1.3 christos { 857 1.1 christos uint8_t words[1024]; 858 1.1 christos char *curr = spec.value + 1; 859 1.1 christos int nr_words = 0; 860 1.1 christos while (1) { 861 1.1 christos char *next; 862 1.1 christos words[nr_words] = H2BE_1(strtoul(curr, &next, 0)); 863 1.1 christos if (curr == next) 864 1.1 christos break; 865 1.1 christos curr = next; 866 1.1 christos nr_words += 1; 867 1.1 christos } 868 1.1 christos device_add_array_property(current, spec.property, 869 1.1 christos words, sizeof(words[0]) * nr_words); 870 1.1 christos } 871 1.1 christos break; 872 1.1 christos case '"': 873 1.1 christos parse_string_property(current, spec.property, spec.value); 874 1.1 christos break; 875 1.1 christos case '!': 876 1.1 christos spec.value++; 877 1.1 christos property = tree_find_property(current, spec.value); 878 1.1 christos if (property == NULL) 879 1.1 christos device_error(current, "property %s not found\n", spec.value); 880 1.1 christos device_add_duplicate_property(current, 881 1.1 christos spec.property, 882 1.1 christos property); 883 1.1 christos break; 884 1.1 christos default: 885 1.1 christos if (strcmp(spec.property, "reg") == 0 886 1.1 christos || strcmp(spec.property, "assigned-addresses") == 0 887 1.1 christos || strcmp(spec.property, "alternate-reg") == 0){ 888 1.1 christos parse_reg_property(current, spec.property, spec.value); 889 1.1 christos } 890 1.1 christos else if (strcmp(spec.property, "ranges") == 0) { 891 1.1 christos parse_ranges_property(current, spec.property, spec.value); 892 1.1 christos } 893 1.1 christos else if (isdigit(spec.value[0]) 894 1.1 christos || (spec.value[0] == '-' && isdigit(spec.value[1])) 895 1.1 christos || (spec.value[0] == '+' && isdigit(spec.value[1]))) { 896 1.1 christos parse_integer_property(current, spec.property, spec.value); 897 1.1 christos } 898 1.1 christos else 899 1.1 christos parse_string_property(current, spec.property, spec.value); 900 1.1 christos break; 901 1.1 christos } 902 1.1 christos } 903 1.1 christos } 904 1.1 christos return current; 905 1.1 christos } 906 1.1 christos 907 1.1 christos 908 1.1 christos INLINE_TREE\ 909 1.1 christos (void) 910 1.1 christos tree_traverse(device *root, 911 1.1 christos tree_traverse_function *prefix, 912 1.1 christos tree_traverse_function *postfix, 913 1.1 christos void *data) 914 1.1 christos { 915 1.1 christos device *child; 916 1.1 christos if (prefix != NULL) 917 1.1 christos prefix(root, data); 918 1.1 christos for (child = device_child(root); 919 1.1 christos child != NULL; 920 1.1 christos child = device_sibling(child)) { 921 1.1 christos tree_traverse(child, prefix, postfix, data); 922 1.1 christos } 923 1.1 christos if (postfix != NULL) 924 1.1 christos postfix(root, data); 925 1.1 christos } 926 1.1 christos 927 1.1 christos 928 1.1 christos STATIC_INLINE_TREE\ 929 1.1 christos (void) 930 1.1 christos print_address(device *bus, 931 1.1 christos const device_unit *phys) 932 1.1 christos { 933 1.1 christos char unit[32]; 934 1.1 christos device_encode_unit(bus, phys, unit, sizeof(unit)); 935 1.1 christos printf_filtered(" %s", unit); 936 1.1 christos } 937 1.1 christos 938 1.1 christos STATIC_INLINE_TREE\ 939 1.1 christos (void) 940 1.1 christos print_size(device *bus, 941 1.1 christos const device_unit *size) 942 1.1 christos { 943 1.1 christos int i; 944 1.1 christos for (i = 0; i < size->nr_cells; i++) 945 1.1 christos if (size->cells[i] != 0) 946 1.1 christos break; 947 1.1 christos if (i < size->nr_cells) { 948 1.1 christos printf_filtered(" 0x%lx", (unsigned long)size->cells[i]); 949 1.1 christos i++; 950 1.1 christos for (; i < size->nr_cells; i++) 951 1.1 christos printf_filtered(",0x%lx", (unsigned long)size->cells[i]); 952 1.1 christos } 953 1.1 christos else 954 1.1 christos printf_filtered(" 0"); 955 1.1 christos } 956 1.1 christos 957 1.1 christos STATIC_INLINE_TREE\ 958 1.1 christos (void) 959 1.1 christos print_reg_property(device *me, 960 1.1 christos const device_property *property) 961 1.1 christos { 962 1.1 christos int reg_nr; 963 1.1 christos reg_property_spec reg; 964 1.1 christos for (reg_nr = 0; 965 1.1 christos device_find_reg_array_property(me, property->name, reg_nr, ®); 966 1.1 christos reg_nr++) { 967 1.1 christos print_address(device_parent(me), ®.address); 968 1.1 christos print_size(me, ®.size); 969 1.1 christos } 970 1.1 christos } 971 1.1 christos 972 1.1 christos STATIC_INLINE_TREE\ 973 1.1 christos (void) 974 1.1 christos print_ranges_property(device *me, 975 1.1 christos const device_property *property) 976 1.1 christos { 977 1.1 christos int range_nr; 978 1.1 christos range_property_spec range; 979 1.1 christos for (range_nr = 0; 980 1.1 christos device_find_range_array_property(me, property->name, range_nr, &range); 981 1.1 christos range_nr++) { 982 1.1 christos print_address(me, &range.child_address); 983 1.1 christos print_address(device_parent(me), &range.parent_address); 984 1.1 christos print_size(me, &range.size); 985 1.1 christos } 986 1.1 christos } 987 1.1 christos 988 1.1 christos STATIC_INLINE_TREE\ 989 1.1 christos (void) 990 1.1 christos print_string(const char *string) 991 1.1 christos { 992 1.1 christos printf_filtered(" \""); 993 1.1 christos while (*string != '\0') { 994 1.1 christos switch (*string) { 995 1.1 christos case '"': 996 1.1 christos printf_filtered("\\\""); 997 1.1 christos break; 998 1.1 christos case '\\': 999 1.1 christos printf_filtered("\\\\"); 1000 1.1 christos break; 1001 1.1 christos default: 1002 1.1 christos printf_filtered("%c", *string); 1003 1.1 christos break; 1004 1.1 christos } 1005 1.1 christos string++; 1006 1.1 christos } 1007 1.1 christos printf_filtered("\""); 1008 1.1 christos } 1009 1.1 christos 1010 1.1 christos STATIC_INLINE_TREE\ 1011 1.1 christos (void) 1012 1.1 christos print_string_array_property(device *me, 1013 1.1 christos const device_property *property) 1014 1.1 christos { 1015 1.1 christos int nr; 1016 1.1 christos string_property_spec string; 1017 1.1 christos for (nr = 0; 1018 1.1 christos device_find_string_array_property(me, property->name, nr, &string); 1019 1.1 christos nr++) { 1020 1.1 christos print_string(string); 1021 1.1 christos } 1022 1.1 christos } 1023 1.1 christos 1024 1.1 christos STATIC_INLINE_TREE\ 1025 1.1 christos (void) 1026 1.1 christos print_properties(device *me) 1027 1.1 christos { 1028 1.1 christos const device_property *property; 1029 1.1 christos for (property = device_find_property(me, NULL); 1030 1.1 christos property != NULL; 1031 1.1 christos property = device_next_property(property)) { 1032 1.1 christos printf_filtered("%s/%s", device_path(me), property->name); 1033 1.1 christos if (property->original != NULL) { 1034 1.1 christos printf_filtered(" !"); 1035 1.1 christos printf_filtered("%s/%s", 1036 1.1 christos device_path(property->original->owner), 1037 1.1 christos property->original->name); 1038 1.1 christos } 1039 1.1 christos else { 1040 1.1 christos switch (property->type) { 1041 1.1 christos case array_property: 1042 1.1 christos if ((property->sizeof_array % sizeof(signed_cell)) == 0) { 1043 1.1 christos unsigned_cell *w = (unsigned_cell*)property->array; 1044 1.1 christos int cell_nr; 1045 1.1 christos for (cell_nr = 0; 1046 1.1 christos cell_nr < (property->sizeof_array / sizeof(unsigned_cell)); 1047 1.1 christos cell_nr++) { 1048 1.1 christos printf_filtered(" 0x%lx", (unsigned long)BE2H_cell(w[cell_nr])); 1049 1.1 christos } 1050 1.1 christos } 1051 1.1.1.3 christos else { 1052 1.1 christos uint8_t *w = (uint8_t*)property->array; 1053 1.1 christos printf_filtered(" ["); 1054 1.1 christos while ((char*)w - (char*)property->array < property->sizeof_array) { 1055 1.1 christos printf_filtered(" 0x%2x", BE2H_1(*w)); 1056 1.1 christos w++; 1057 1.1 christos } 1058 1.1 christos } 1059 1.1 christos break; 1060 1.1 christos case boolean_property: 1061 1.1 christos { 1062 1.1 christos int b = device_find_boolean_property(me, property->name); 1063 1.1 christos printf_filtered(" %s", b ? "true" : "false"); 1064 1.1 christos } 1065 1.1 christos break; 1066 1.1 christos case ihandle_property: 1067 1.1 christos { 1068 1.1 christos if (property->array != NULL) { 1069 1.1 christos device_instance *instance = device_find_ihandle_property(me, property->name); 1070 1.1 christos printf_filtered(" *%s", device_instance_path(instance)); 1071 1.1 christos } 1072 1.1 christos else { 1073 1.1 christos /* not yet initialized, ask the device for the path */ 1074 1.1 christos ihandle_runtime_property_spec spec; 1075 1.1 christos device_find_ihandle_runtime_property(me, property->name, &spec); 1076 1.1 christos printf_filtered(" *%s", spec.full_path); 1077 1.1 christos } 1078 1.1 christos } 1079 1.1 christos break; 1080 1.1 christos case integer_property: 1081 1.1 christos { 1082 1.1 christos unsigned_word w = device_find_integer_property(me, property->name); 1083 1.1 christos printf_filtered(" 0x%lx", (unsigned long)w); 1084 1.1 christos } 1085 1.1 christos break; 1086 1.1 christos case range_array_property: 1087 1.1 christos print_ranges_property(me, property); 1088 1.1 christos break; 1089 1.1 christos case reg_array_property: 1090 1.1 christos print_reg_property(me, property); 1091 1.1 christos break; 1092 1.1 christos case string_property: 1093 1.1 christos { 1094 1.1 christos const char *s = device_find_string_property(me, property->name); 1095 1.1 christos print_string(s); 1096 1.1 christos } 1097 1.1 christos break; 1098 1.1 christos case string_array_property: 1099 1.1 christos print_string_array_property(me, property); 1100 1.1 christos break; 1101 1.1 christos } 1102 1.1 christos } 1103 1.1 christos printf_filtered("\n"); 1104 1.1 christos } 1105 1.1 christos } 1106 1.1 christos 1107 1.1 christos STATIC_INLINE_TREE\ 1108 1.1 christos (void) 1109 1.1 christos print_interrupts(device *me, 1110 1.1 christos int my_port, 1111 1.1 christos device *dest, 1112 1.1 christos int dest_port, 1113 1.1 christos void *ignore_or_null) 1114 1.1 christos { 1115 1.1 christos char src[32]; 1116 1.1 christos char dst[32]; 1117 1.1 christos device_interrupt_encode(me, my_port, src, sizeof(src), output_port); 1118 1.1 christos device_interrupt_encode(dest, dest_port, dst, sizeof(dst), input_port); 1119 1.1 christos printf_filtered("%s > %s %s %s\n", 1120 1.1 christos device_path(me), 1121 1.1 christos src, dst, 1122 1.1 christos device_path(dest)); 1123 1.1 christos } 1124 1.1 christos 1125 1.1 christos STATIC_INLINE_TREE\ 1126 1.1 christos (void) 1127 1.1 christos print_device(device *me, 1128 1.1 christos void *ignore_or_null) 1129 1.1 christos { 1130 1.1 christos printf_filtered("%s\n", device_path(me)); 1131 1.1 christos print_properties(me); 1132 1.1 christos device_interrupt_traverse(me, print_interrupts, NULL); 1133 1.1 christos } 1134 1.1 christos 1135 1.1 christos INLINE_TREE\ 1136 1.1 christos (void) 1137 1.1 christos tree_print(device *root) 1138 1.1 christos { 1139 1.1 christos tree_traverse(root, 1140 1.1 christos print_device, NULL, 1141 1.1 christos NULL); 1142 1.1 christos } 1143 1.1 christos 1144 1.1 christos 1145 1.1 christos INLINE_TREE\ 1146 1.1 christos (void) 1147 1.1 christos tree_usage(int verbose) 1148 1.1 christos { 1149 1.1 christos if (verbose == 1) { 1150 1.1 christos printf_filtered("\n"); 1151 1.1 christos printf_filtered("A device/property specifier has the form:\n"); 1152 1.1 christos printf_filtered("\n"); 1153 1.1 christos printf_filtered(" /path/to/a/device [ property-value ]\n"); 1154 1.1 christos printf_filtered("\n"); 1155 1.1 christos printf_filtered("and a possible device is\n"); 1156 1.1 christos printf_filtered("\n"); 1157 1.1 christos } 1158 1.1 christos if (verbose > 1) { 1159 1.1 christos printf_filtered("\n"); 1160 1.1 christos printf_filtered("A device/property specifier (<spec>) has the format:\n"); 1161 1.1 christos printf_filtered("\n"); 1162 1.1 christos printf_filtered(" <spec> ::= <path> [ <value> ] ;\n"); 1163 1.1 christos printf_filtered(" <path> ::= { <prefix> } { <node> \"/\" } <node> ;\n"); 1164 1.1 christos printf_filtered(" <prefix> ::= ( | \"/\" | \"../\" | \"./\" ) ;\n"); 1165 1.1 christos printf_filtered(" <node> ::= <name> [ \"@\" <unit> ] [ \":\" <args> ] ;\n"); 1166 1.1 christos printf_filtered(" <unit> ::= <number> { \",\" <number> } ;\n"); 1167 1.1 christos printf_filtered("\n"); 1168 1.1 christos printf_filtered("Where:\n"); 1169 1.1 christos printf_filtered("\n"); 1170 1.1 christos printf_filtered(" <name> is the name of a device (list below)\n"); 1171 1.1 christos printf_filtered(" <unit> is the unit-address relative to the parent bus\n"); 1172 1.1 christos printf_filtered(" <args> additional arguments used when creating the device\n"); 1173 1.1 christos printf_filtered(" <value> ::= ( <number> # integer property\n"); 1174 1.1 christos printf_filtered(" | \"[\" { <number> } # array property (byte)\n"); 1175 1.1 christos printf_filtered(" | \"{\" { <number> } # array property (cell)\n"); 1176 1.1 christos printf_filtered(" | [ \"true\" | \"false\" ] # boolean property\n"); 1177 1.1 christos printf_filtered(" | \"*\" <path> # ihandle property\n"); 1178 1.1 christos printf_filtered(" | \"!\" <path> # copy property\n"); 1179 1.1 christos printf_filtered(" | \">\" [ <number> ] <path> # attach interrupt\n"); 1180 1.1 christos printf_filtered(" | \"<\" <path> # attach child interrupt\n"); 1181 1.1 christos printf_filtered(" | \"\\\"\" <text> # string property\n"); 1182 1.1 christos printf_filtered(" | <text> # string property\n"); 1183 1.1 christos printf_filtered(" ) ;\n"); 1184 1.1 christos printf_filtered("\n"); 1185 1.1 christos printf_filtered("And the following are valid device names:\n"); 1186 1.1 christos printf_filtered("\n"); 1187 1.1 christos } 1188 1.1 christos } 1189 1.1 christos 1190 1.1 christos 1191 1.1 christos 1192 1.1 christos INLINE_TREE\ 1193 1.1 christos (device_instance *) 1194 1.1 christos tree_instance(device *root, 1195 1.1 christos const char *device_specifier) 1196 1.1 christos { 1197 1.1 christos /* find the device node */ 1198 1.1 christos device *me; 1199 1.1 christos name_specifier spec; 1200 1.1 christos if (!split_device_specifier(root, device_specifier, &spec)) 1201 1.1 christos return NULL; 1202 1.1 christos me = split_find_device(root, &spec); 1203 1.1 christos if (spec.name != NULL) 1204 1.1 christos return NULL; 1205 1.1 christos /* create the instance */ 1206 1.1 christos return device_create_instance(me, device_specifier, spec.last_args); 1207 1.1 christos } 1208 1.1 christos 1209 1.1 christos 1210 1.1 christos INLINE_TREE\ 1211 1.1 christos (device *) 1212 1.1 christos tree_find_device(device *root, 1213 1.1 christos const char *path_to_device) 1214 1.1 christos { 1215 1.1 christos device *node; 1216 1.1 christos name_specifier spec; 1217 1.1 christos 1218 1.1 christos /* parse the path */ 1219 1.1 christos split_device_specifier(root, path_to_device, &spec); 1220 1.1.1.5 christos if (spec.value != NULL) 1221 1.1 christos return NULL; /* something weird */ 1222 1.1 christos 1223 1.1 christos /* now find it */ 1224 1.1 christos node = split_find_device(root, &spec); 1225 1.1 christos if (spec.name != NULL) 1226 1.1 christos return NULL; /* not a leaf */ 1227 1.1 christos 1228 1.1 christos return node; 1229 1.1 christos } 1230 1.1 christos 1231 1.1 christos 1232 1.1 christos INLINE_TREE\ 1233 1.1 christos (const device_property *) 1234 1.1 christos tree_find_property(device *root, 1235 1.1 christos const char *path_to_property) 1236 1.1 christos { 1237 1.1 christos name_specifier spec; 1238 1.1 christos if (!split_property_specifier(root, path_to_property, &spec)) 1239 1.1 christos device_error(root, "Invalid property path %s", path_to_property); 1240 1.1 christos root = split_find_device(root, &spec); 1241 1.1 christos return device_find_property(root, spec.property); 1242 1.1 christos } 1243 1.1 christos 1244 1.1 christos INLINE_TREE\ 1245 1.1 christos (int) 1246 1.1 christos tree_find_boolean_property(device *root, 1247 1.1 christos const char *path_to_property) 1248 1.1 christos { 1249 1.1 christos name_specifier spec; 1250 1.1 christos if (!split_property_specifier(root, path_to_property, &spec)) 1251 1.1 christos device_error(root, "Invalid property path %s", path_to_property); 1252 1.1 christos root = split_find_device(root, &spec); 1253 1.1 christos return device_find_boolean_property(root, spec.property); 1254 1.1 christos } 1255 1.1 christos 1256 1.1 christos INLINE_TREE\ 1257 1.1 christos (signed_cell) 1258 1.1 christos tree_find_integer_property(device *root, 1259 1.1 christos const char *path_to_property) 1260 1.1 christos { 1261 1.1 christos name_specifier spec; 1262 1.1 christos if (!split_property_specifier(root, path_to_property, &spec)) 1263 1.1 christos device_error(root, "Invalid property path %s", path_to_property); 1264 1.1 christos root = split_find_device(root, &spec); 1265 1.1 christos return device_find_integer_property(root, spec.property); 1266 1.1 christos } 1267 1.1 christos 1268 1.1 christos INLINE_TREE\ 1269 1.1 christos (device_instance *) 1270 1.1 christos tree_find_ihandle_property(device *root, 1271 1.1 christos const char *path_to_property) 1272 1.1 christos { 1273 1.1 christos name_specifier spec; 1274 1.1 christos if (!split_property_specifier(root, path_to_property, &spec)) 1275 1.1 christos device_error(root, "Invalid property path %s", path_to_property); 1276 1.1 christos root = split_find_device(root, &spec); 1277 1.1 christos return device_find_ihandle_property(root, spec.property); 1278 1.1 christos } 1279 1.1 christos 1280 1.1 christos INLINE_TREE\ 1281 1.1 christos (const char *) 1282 1.1 christos tree_find_string_property(device *root, 1283 1.1 christos const char *path_to_property) 1284 1.1 christos { 1285 1.1 christos name_specifier spec; 1286 1.1 christos if (!split_property_specifier(root, path_to_property, &spec)) 1287 1.1 christos device_error(root, "Invalid property path %s", path_to_property); 1288 1.1 christos root = split_find_device(root, &spec); 1289 1.1 christos return device_find_string_property(root, spec.property); 1290 1.1 christos } 1291 1.1 christos 1292 1.1 christos 1293 #endif /* _PARSE_C_ */ 1294