fdt_ro.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963
  1. /*
  2. * libfdt - Flat Device Tree manipulation
  3. * Copyright (C) 2006 David Gibson, IBM Corporation.
  4. *
  5. * libfdt is dual licensed: you can use it either under the terms of
  6. * the GPL, or the BSD license, at your option.
  7. *
  8. * a) This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 of the
  11. * License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public
  19. * License along with this library; if not, write to the Free
  20. * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
  21. * MA 02110-1301 USA
  22. *
  23. * Alternatively,
  24. *
  25. * b) Redistribution and use in source and binary forms, with or
  26. * without modification, are permitted provided that the following
  27. * conditions are met:
  28. *
  29. * 1. Redistributions of source code must retain the above
  30. * copyright notice, this list of conditions and the following
  31. * disclaimer.
  32. * 2. Redistributions in binary form must reproduce the above
  33. * copyright notice, this list of conditions and the following
  34. * disclaimer in the documentation and/or other materials
  35. * provided with the distribution.
  36. *
  37. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  38. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  39. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  40. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  41. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  42. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  43. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  44. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  45. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  46. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  47. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  48. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  49. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  50. */
  51. #include "libfdt_env.h"
  52. #include <fdt.h>
  53. #include <libfdt.h>
  54. #include "libfdt_internal.h"
  55. static int
  56. _fdt_nodename_eq (
  57. const void *fdt,
  58. int offset,
  59. const char *s,
  60. int len
  61. )
  62. {
  63. const char *p = fdt_offset_ptr (fdt, offset + FDT_TAGSIZE, len+1);
  64. if (!p) {
  65. /* short match */
  66. return 0;
  67. }
  68. if (memcmp (p, s, len) != 0) {
  69. return 0;
  70. }
  71. if (p[len] == '\0') {
  72. return 1;
  73. } else if (!memchr (s, '@', len) && (p[len] == '@')) {
  74. return 1;
  75. } else {
  76. return 0;
  77. }
  78. }
  79. const char *
  80. fdt_string (
  81. const void *fdt,
  82. int stroffset
  83. )
  84. {
  85. return (const char *)fdt + fdt_off_dt_strings (fdt) + stroffset;
  86. }
  87. static int
  88. _fdt_string_eq (
  89. const void *fdt,
  90. int stroffset,
  91. const char *s,
  92. int len
  93. )
  94. {
  95. const char *p = fdt_string (fdt, stroffset);
  96. return (strlen (p) == len) && (memcmp (p, s, len) == 0);
  97. }
  98. uint32_t
  99. fdt_get_max_phandle (
  100. const void *fdt
  101. )
  102. {
  103. uint32_t max_phandle = 0;
  104. int offset;
  105. for (offset = fdt_next_node (fdt, -1, NULL); ;
  106. offset = fdt_next_node (fdt, offset, NULL))
  107. {
  108. uint32_t phandle;
  109. if (offset == -FDT_ERR_NOTFOUND) {
  110. return max_phandle;
  111. }
  112. if (offset < 0) {
  113. return (uint32_t)-1;
  114. }
  115. phandle = fdt_get_phandle (fdt, offset);
  116. if (phandle == (uint32_t)-1) {
  117. continue;
  118. }
  119. if (phandle > max_phandle) {
  120. max_phandle = phandle;
  121. }
  122. }
  123. return 0;
  124. }
  125. int
  126. fdt_get_mem_rsv (
  127. const void *fdt,
  128. int n,
  129. uint64_t *address,
  130. uint64_t *size
  131. )
  132. {
  133. FDT_CHECK_HEADER (fdt);
  134. *address = fdt64_to_cpu (_fdt_mem_rsv (fdt, n)->address);
  135. *size = fdt64_to_cpu (_fdt_mem_rsv (fdt, n)->size);
  136. return 0;
  137. }
  138. int
  139. fdt_num_mem_rsv (
  140. const void *fdt
  141. )
  142. {
  143. int i = 0;
  144. while (fdt64_to_cpu (_fdt_mem_rsv (fdt, i)->size) != 0) {
  145. i++;
  146. }
  147. return i;
  148. }
  149. static int
  150. _nextprop (
  151. const void *fdt,
  152. int offset
  153. )
  154. {
  155. uint32_t tag;
  156. int nextoffset;
  157. do {
  158. tag = fdt_next_tag (fdt, offset, &nextoffset);
  159. switch (tag) {
  160. case FDT_END:
  161. if (nextoffset >= 0) {
  162. return -FDT_ERR_BADSTRUCTURE;
  163. } else {
  164. return nextoffset;
  165. }
  166. case FDT_PROP:
  167. return offset;
  168. }
  169. offset = nextoffset;
  170. } while (tag == FDT_NOP);
  171. return -FDT_ERR_NOTFOUND;
  172. }
  173. int
  174. fdt_subnode_offset_namelen (
  175. const void *fdt,
  176. int offset,
  177. const char *name,
  178. int namelen
  179. )
  180. {
  181. int depth;
  182. FDT_CHECK_HEADER (fdt);
  183. for (depth = 0;
  184. (offset >= 0) && (depth >= 0);
  185. offset = fdt_next_node (fdt, offset, &depth))
  186. {
  187. if ( (depth == 1)
  188. && _fdt_nodename_eq (fdt, offset, name, namelen))
  189. {
  190. return offset;
  191. }
  192. }
  193. if (depth < 0) {
  194. return -FDT_ERR_NOTFOUND;
  195. }
  196. return offset; /* error */
  197. }
  198. int
  199. fdt_subnode_offset (
  200. const void *fdt,
  201. int parentoffset,
  202. const char *name
  203. )
  204. {
  205. return fdt_subnode_offset_namelen (fdt, parentoffset, name, strlen (name));
  206. }
  207. int
  208. fdt_path_offset_namelen (
  209. const void *fdt,
  210. const char *path,
  211. int namelen
  212. )
  213. {
  214. const char *end = path + namelen;
  215. const char *p = path;
  216. int offset = 0;
  217. FDT_CHECK_HEADER (fdt);
  218. /* see if we have an alias */
  219. if (*path != '/') {
  220. const char *q = memchr (path, '/', end - p);
  221. if (!q) {
  222. q = end;
  223. }
  224. p = fdt_get_alias_namelen (fdt, p, q - p);
  225. if (!p) {
  226. return -FDT_ERR_BADPATH;
  227. }
  228. offset = fdt_path_offset (fdt, p);
  229. p = q;
  230. }
  231. while (p < end) {
  232. const char *q;
  233. while (*p == '/') {
  234. p++;
  235. if (p == end) {
  236. return offset;
  237. }
  238. }
  239. q = memchr (p, '/', end - p);
  240. if (!q) {
  241. q = end;
  242. }
  243. offset = fdt_subnode_offset_namelen (fdt, offset, p, q-p);
  244. if (offset < 0) {
  245. return offset;
  246. }
  247. p = q;
  248. }
  249. return offset;
  250. }
  251. int
  252. fdt_path_offset (
  253. const void *fdt,
  254. const char *path
  255. )
  256. {
  257. return fdt_path_offset_namelen (fdt, path, strlen (path));
  258. }
  259. const char *
  260. fdt_get_name (
  261. const void *fdt,
  262. int nodeoffset,
  263. int *len
  264. )
  265. {
  266. const struct fdt_node_header *nh = _fdt_offset_ptr (fdt, nodeoffset);
  267. int err;
  268. if ( ((err = fdt_check_header (fdt)) != 0)
  269. || ((err = _fdt_check_node_offset (fdt, nodeoffset)) < 0))
  270. {
  271. goto fail;
  272. }
  273. if (len) {
  274. *len = strlen (nh->name);
  275. }
  276. return nh->name;
  277. fail:
  278. if (len) {
  279. *len = err;
  280. }
  281. return NULL;
  282. }
  283. int
  284. fdt_first_property_offset (
  285. const void *fdt,
  286. int nodeoffset
  287. )
  288. {
  289. int offset;
  290. if ((offset = _fdt_check_node_offset (fdt, nodeoffset)) < 0) {
  291. return offset;
  292. }
  293. return _nextprop (fdt, offset);
  294. }
  295. int
  296. fdt_next_property_offset (
  297. const void *fdt,
  298. int offset
  299. )
  300. {
  301. if ((offset = _fdt_check_prop_offset (fdt, offset)) < 0) {
  302. return offset;
  303. }
  304. return _nextprop (fdt, offset);
  305. }
  306. const struct fdt_property *
  307. fdt_get_property_by_offset (
  308. const void *fdt,
  309. int offset,
  310. int *lenp
  311. )
  312. {
  313. int err;
  314. const struct fdt_property *prop;
  315. if ((err = _fdt_check_prop_offset (fdt, offset)) < 0) {
  316. if (lenp) {
  317. *lenp = err;
  318. }
  319. return NULL;
  320. }
  321. prop = _fdt_offset_ptr (fdt, offset);
  322. if (lenp) {
  323. *lenp = fdt32_to_cpu (prop->len);
  324. }
  325. return prop;
  326. }
  327. const struct fdt_property *
  328. fdt_get_property_namelen (
  329. const void *fdt,
  330. int offset,
  331. const char *name,
  332. int namelen,
  333. int *lenp
  334. )
  335. {
  336. for (offset = fdt_first_property_offset (fdt, offset);
  337. (offset >= 0);
  338. (offset = fdt_next_property_offset (fdt, offset)))
  339. {
  340. const struct fdt_property *prop;
  341. if (!(prop = fdt_get_property_by_offset (fdt, offset, lenp))) {
  342. offset = -FDT_ERR_INTERNAL;
  343. break;
  344. }
  345. if (_fdt_string_eq (
  346. fdt,
  347. fdt32_to_cpu (prop->nameoff),
  348. name,
  349. namelen
  350. ))
  351. {
  352. return prop;
  353. }
  354. }
  355. if (lenp) {
  356. *lenp = offset;
  357. }
  358. return NULL;
  359. }
  360. const struct fdt_property *
  361. fdt_get_property (
  362. const void *fdt,
  363. int nodeoffset,
  364. const char *name,
  365. int *lenp
  366. )
  367. {
  368. return fdt_get_property_namelen (
  369. fdt,
  370. nodeoffset,
  371. name,
  372. strlen (name),
  373. lenp
  374. );
  375. }
  376. const void *
  377. fdt_getprop_namelen (
  378. const void *fdt,
  379. int nodeoffset,
  380. const char *name,
  381. int namelen,
  382. int *lenp
  383. )
  384. {
  385. const struct fdt_property *prop;
  386. prop = fdt_get_property_namelen (fdt, nodeoffset, name, namelen, lenp);
  387. if (!prop) {
  388. return NULL;
  389. }
  390. return prop->data;
  391. }
  392. const void *
  393. fdt_getprop_by_offset (
  394. const void *fdt,
  395. int offset,
  396. const char **namep,
  397. int *lenp
  398. )
  399. {
  400. const struct fdt_property *prop;
  401. prop = fdt_get_property_by_offset (fdt, offset, lenp);
  402. if (!prop) {
  403. return NULL;
  404. }
  405. if (namep) {
  406. *namep = fdt_string (fdt, fdt32_to_cpu (prop->nameoff));
  407. }
  408. return prop->data;
  409. }
  410. const void *
  411. fdt_getprop (
  412. const void *fdt,
  413. int nodeoffset,
  414. const char *name,
  415. int *lenp
  416. )
  417. {
  418. return fdt_getprop_namelen (fdt, nodeoffset, name, strlen (name), lenp);
  419. }
  420. uint32_t
  421. fdt_get_phandle (
  422. const void *fdt,
  423. int nodeoffset
  424. )
  425. {
  426. const fdt32_t *php;
  427. int len;
  428. /* FIXME: This is a bit sub-optimal, since we potentially scan
  429. * over all the properties twice. */
  430. php = fdt_getprop (fdt, nodeoffset, "phandle", &len);
  431. if (!php || (len != sizeof (*php))) {
  432. php = fdt_getprop (fdt, nodeoffset, "linux,phandle", &len);
  433. if (!php || (len != sizeof (*php))) {
  434. return 0;
  435. }
  436. }
  437. return fdt32_to_cpu (*php);
  438. }
  439. const char *
  440. fdt_get_alias_namelen (
  441. const void *fdt,
  442. const char *name,
  443. int namelen
  444. )
  445. {
  446. int aliasoffset;
  447. aliasoffset = fdt_path_offset (fdt, "/aliases");
  448. if (aliasoffset < 0) {
  449. return NULL;
  450. }
  451. return fdt_getprop_namelen (fdt, aliasoffset, name, namelen, NULL);
  452. }
  453. const char *
  454. fdt_get_alias (
  455. const void *fdt,
  456. const char *name
  457. )
  458. {
  459. return fdt_get_alias_namelen (fdt, name, strlen (name));
  460. }
  461. int
  462. fdt_get_path (
  463. const void *fdt,
  464. int nodeoffset,
  465. char *buf,
  466. int buflen
  467. )
  468. {
  469. int pdepth = 0, p = 0;
  470. int offset, depth, namelen;
  471. const char *name;
  472. FDT_CHECK_HEADER (fdt);
  473. if (buflen < 2) {
  474. return -FDT_ERR_NOSPACE;
  475. }
  476. for (offset = 0, depth = 0;
  477. (offset >= 0) && (offset <= nodeoffset);
  478. offset = fdt_next_node (fdt, offset, &depth))
  479. {
  480. while (pdepth > depth) {
  481. do {
  482. p--;
  483. } while (buf[p-1] != '/');
  484. pdepth--;
  485. }
  486. if (pdepth >= depth) {
  487. name = fdt_get_name (fdt, offset, &namelen);
  488. if (!name) {
  489. return namelen;
  490. }
  491. if ((p + namelen + 1) <= buflen) {
  492. memcpy (buf + p, name, namelen);
  493. p += namelen;
  494. buf[p++] = '/';
  495. pdepth++;
  496. }
  497. }
  498. if (offset == nodeoffset) {
  499. if (pdepth < (depth + 1)) {
  500. return -FDT_ERR_NOSPACE;
  501. }
  502. if (p > 1) {
  503. /* special case so that root path is "/", not "" */
  504. p--;
  505. }
  506. buf[p] = '\0';
  507. return 0;
  508. }
  509. }
  510. if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) {
  511. return -FDT_ERR_BADOFFSET;
  512. } else if (offset == -FDT_ERR_BADOFFSET) {
  513. return -FDT_ERR_BADSTRUCTURE;
  514. }
  515. return offset; /* error from fdt_next_node() */
  516. }
  517. int
  518. fdt_supernode_atdepth_offset (
  519. const void *fdt,
  520. int nodeoffset,
  521. int supernodedepth,
  522. int *nodedepth
  523. )
  524. {
  525. int offset, depth;
  526. int supernodeoffset = -FDT_ERR_INTERNAL;
  527. FDT_CHECK_HEADER (fdt);
  528. if (supernodedepth < 0) {
  529. return -FDT_ERR_NOTFOUND;
  530. }
  531. for (offset = 0, depth = 0;
  532. (offset >= 0) && (offset <= nodeoffset);
  533. offset = fdt_next_node (fdt, offset, &depth))
  534. {
  535. if (depth == supernodedepth) {
  536. supernodeoffset = offset;
  537. }
  538. if (offset == nodeoffset) {
  539. if (nodedepth) {
  540. *nodedepth = depth;
  541. }
  542. if (supernodedepth > depth) {
  543. return -FDT_ERR_NOTFOUND;
  544. } else {
  545. return supernodeoffset;
  546. }
  547. }
  548. }
  549. if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) {
  550. return -FDT_ERR_BADOFFSET;
  551. } else if (offset == -FDT_ERR_BADOFFSET) {
  552. return -FDT_ERR_BADSTRUCTURE;
  553. }
  554. return offset; /* error from fdt_next_node() */
  555. }
  556. int
  557. fdt_node_depth (
  558. const void *fdt,
  559. int nodeoffset
  560. )
  561. {
  562. int nodedepth;
  563. int err;
  564. err = fdt_supernode_atdepth_offset (fdt, nodeoffset, 0, &nodedepth);
  565. if (err) {
  566. return (err < 0) ? err : -FDT_ERR_INTERNAL;
  567. }
  568. return nodedepth;
  569. }
  570. int
  571. fdt_parent_offset (
  572. const void *fdt,
  573. int nodeoffset
  574. )
  575. {
  576. int nodedepth = fdt_node_depth (fdt, nodeoffset);
  577. if (nodedepth < 0) {
  578. return nodedepth;
  579. }
  580. return fdt_supernode_atdepth_offset (
  581. fdt,
  582. nodeoffset,
  583. nodedepth - 1,
  584. NULL
  585. );
  586. }
  587. int
  588. fdt_node_offset_by_prop_value (
  589. const void *fdt,
  590. int startoffset,
  591. const char *propname,
  592. const void *propval,
  593. int proplen
  594. )
  595. {
  596. int offset;
  597. const void *val;
  598. int len;
  599. FDT_CHECK_HEADER (fdt);
  600. /* FIXME: The algorithm here is pretty horrible: we scan each
  601. * property of a node in fdt_getprop(), then if that didn't
  602. * find what we want, we scan over them again making our way
  603. * to the next node. Still it's the easiest to implement
  604. * approach; performance can come later. */
  605. for (offset = fdt_next_node (fdt, startoffset, NULL);
  606. offset >= 0;
  607. offset = fdt_next_node (fdt, offset, NULL))
  608. {
  609. val = fdt_getprop (fdt, offset, propname, &len);
  610. if ( val && (len == proplen)
  611. && (memcmp (val, propval, len) == 0))
  612. {
  613. return offset;
  614. }
  615. }
  616. return offset; /* error from fdt_next_node() */
  617. }
  618. int
  619. fdt_node_offset_by_phandle (
  620. const void *fdt,
  621. uint32_t phandle
  622. )
  623. {
  624. int offset;
  625. if ((phandle == 0) || (phandle == -1)) {
  626. return -FDT_ERR_BADPHANDLE;
  627. }
  628. FDT_CHECK_HEADER (fdt);
  629. /* FIXME: The algorithm here is pretty horrible: we
  630. * potentially scan each property of a node in
  631. * fdt_get_phandle(), then if that didn't find what
  632. * we want, we scan over them again making our way to the next
  633. * node. Still it's the easiest to implement approach;
  634. * performance can come later. */
  635. for (offset = fdt_next_node (fdt, -1, NULL);
  636. offset >= 0;
  637. offset = fdt_next_node (fdt, offset, NULL))
  638. {
  639. if (fdt_get_phandle (fdt, offset) == phandle) {
  640. return offset;
  641. }
  642. }
  643. return offset; /* error from fdt_next_node() */
  644. }
  645. int
  646. fdt_stringlist_contains (
  647. const char *strlist,
  648. int listlen,
  649. const char *str
  650. )
  651. {
  652. int len = strlen (str);
  653. const char *p;
  654. while (listlen >= len) {
  655. if (memcmp (str, strlist, len+1) == 0) {
  656. return 1;
  657. }
  658. p = memchr (strlist, '\0', listlen);
  659. if (!p) {
  660. return 0; /* malformed strlist.. */
  661. }
  662. listlen -= (p-strlist) + 1;
  663. strlist = p + 1;
  664. }
  665. return 0;
  666. }
  667. int
  668. fdt_stringlist_count (
  669. const void *fdt,
  670. int nodeoffset,
  671. const char *property
  672. )
  673. {
  674. const char *list, *end;
  675. int length, count = 0;
  676. list = fdt_getprop (fdt, nodeoffset, property, &length);
  677. if (!list) {
  678. return length;
  679. }
  680. end = list + length;
  681. while (list < end) {
  682. length = strnlen (list, end - list) + 1;
  683. /* Abort if the last string isn't properly NUL-terminated. */
  684. if (list + length > end) {
  685. return -FDT_ERR_BADVALUE;
  686. }
  687. list += length;
  688. count++;
  689. }
  690. return count;
  691. }
  692. int
  693. fdt_stringlist_search (
  694. const void *fdt,
  695. int nodeoffset,
  696. const char *property,
  697. const char *string
  698. )
  699. {
  700. int length, len, idx = 0;
  701. const char *list, *end;
  702. list = fdt_getprop (fdt, nodeoffset, property, &length);
  703. if (!list) {
  704. return length;
  705. }
  706. len = strlen (string) + 1;
  707. end = list + length;
  708. while (list < end) {
  709. length = strnlen (list, end - list) + 1;
  710. /* Abort if the last string isn't properly NUL-terminated. */
  711. if (list + length > end) {
  712. return -FDT_ERR_BADVALUE;
  713. }
  714. if ((length == len) && (memcmp (list, string, length) == 0)) {
  715. return idx;
  716. }
  717. list += length;
  718. idx++;
  719. }
  720. return -FDT_ERR_NOTFOUND;
  721. }
  722. const char *
  723. fdt_stringlist_get (
  724. const void *fdt,
  725. int nodeoffset,
  726. const char *property,
  727. int idx,
  728. int *lenp
  729. )
  730. {
  731. const char *list, *end;
  732. int length;
  733. list = fdt_getprop (fdt, nodeoffset, property, &length);
  734. if (!list) {
  735. if (lenp) {
  736. *lenp = length;
  737. }
  738. return NULL;
  739. }
  740. end = list + length;
  741. while (list < end) {
  742. length = strnlen (list, end - list) + 1;
  743. /* Abort if the last string isn't properly NUL-terminated. */
  744. if (list + length > end) {
  745. if (lenp) {
  746. *lenp = -FDT_ERR_BADVALUE;
  747. }
  748. return NULL;
  749. }
  750. if (idx == 0) {
  751. if (lenp) {
  752. *lenp = length - 1;
  753. }
  754. return list;
  755. }
  756. list += length;
  757. idx--;
  758. }
  759. if (lenp) {
  760. *lenp = -FDT_ERR_NOTFOUND;
  761. }
  762. return NULL;
  763. }
  764. int
  765. fdt_node_check_compatible (
  766. const void *fdt,
  767. int nodeoffset,
  768. const char *compatible
  769. )
  770. {
  771. const void *prop;
  772. int len;
  773. prop = fdt_getprop (fdt, nodeoffset, "compatible", &len);
  774. if (!prop) {
  775. return len;
  776. }
  777. return !fdt_stringlist_contains (prop, len, compatible);
  778. }
  779. int
  780. fdt_node_offset_by_compatible (
  781. const void *fdt,
  782. int startoffset,
  783. const char *compatible
  784. )
  785. {
  786. int offset, err;
  787. FDT_CHECK_HEADER (fdt);
  788. /* FIXME: The algorithm here is pretty horrible: we scan each
  789. * property of a node in fdt_node_check_compatible(), then if
  790. * that didn't find what we want, we scan over them again
  791. * making our way to the next node. Still it's the easiest to
  792. * implement approach; performance can come later. */
  793. for (offset = fdt_next_node (fdt, startoffset, NULL);
  794. offset >= 0;
  795. offset = fdt_next_node (fdt, offset, NULL))
  796. {
  797. err = fdt_node_check_compatible (fdt, offset, compatible);
  798. if ((err < 0) && (err != -FDT_ERR_NOTFOUND)) {
  799. return err;
  800. } else if (err == 0) {
  801. return offset;
  802. }
  803. }
  804. return offset; /* error from fdt_next_node() */
  805. }