tree.c 31 KB

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