libfdt.i 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. /*
  2. * pylibfdt - Flat Device Tree manipulation in Python
  3. * Copyright (C) 2017 Google, Inc.
  4. * Written by Simon Glass <sjg@chromium.org>
  5. *
  6. * SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause
  7. */
  8. %module libfdt
  9. %include <stdint.i>
  10. %{
  11. #define SWIG_FILE_WITH_INIT
  12. #include "libfdt.h"
  13. %}
  14. %pythoncode %{
  15. import struct
  16. # Error codes, corresponding to FDT_ERR_... in libfdt.h
  17. (NOTFOUND,
  18. EXISTS,
  19. NOSPACE,
  20. BADOFFSET,
  21. BADPATH,
  22. BADPHANDLE,
  23. BADSTATE,
  24. TRUNCATED,
  25. BADMAGIC,
  26. BADVERSION,
  27. BADSTRUCTURE,
  28. BADLAYOUT,
  29. INTERNAL,
  30. BADNCELLS,
  31. BADVALUE,
  32. BADOVERLAY,
  33. NOPHANDLES) = QUIET_ALL = range(1, 18)
  34. # QUIET_ALL can be passed as the 'quiet' parameter to avoid exceptions
  35. # altogether. All # functions passed this value will return an error instead
  36. # of raising an exception.
  37. # Pass this as the 'quiet' parameter to return -ENOTFOUND on NOTFOUND errors,
  38. # instead of raising an exception.
  39. QUIET_NOTFOUND = (NOTFOUND,)
  40. class FdtException(Exception):
  41. """An exception caused by an error such as one of the codes above"""
  42. def __init__(self, err):
  43. self.err = err
  44. def __str__(self):
  45. return 'pylibfdt error %d: %s' % (self.err, fdt_strerror(self.err))
  46. def strerror(fdt_err):
  47. """Get the string for an error number
  48. Args:
  49. fdt_err: Error number (-ve)
  50. Returns:
  51. String containing the associated error
  52. """
  53. return fdt_strerror(fdt_err)
  54. def check_err(val, quiet=()):
  55. """Raise an error if the return value is -ve
  56. This is used to check for errors returned by libfdt C functions.
  57. Args:
  58. val: Return value from a libfdt function
  59. quiet: Errors to ignore (empty to raise on all errors)
  60. Returns:
  61. val if val >= 0
  62. Raises
  63. FdtException if val < 0
  64. """
  65. if val < 0:
  66. if -val not in quiet:
  67. raise FdtException(val)
  68. return val
  69. def check_err_null(val, quiet=()):
  70. """Raise an error if the return value is NULL
  71. This is used to check for a NULL return value from certain libfdt C
  72. functions
  73. Args:
  74. val: Return value from a libfdt function
  75. quiet: Errors to ignore (empty to raise on all errors)
  76. Returns:
  77. val if val is a list, None if not
  78. Raises
  79. FdtException if val indicates an error was reported and the error
  80. is not in @quiet.
  81. """
  82. # Normally a list is returned which contains the data and its length.
  83. # If we get just an integer error code, it means the function failed.
  84. if not isinstance(val, list):
  85. if -val not in quiet:
  86. raise FdtException(val)
  87. return val
  88. class Fdt:
  89. """Device tree class, supporting all operations
  90. The Fdt object is created is created from a device tree binary file,
  91. e.g. with something like:
  92. fdt = Fdt(open("filename.dtb").read())
  93. Operations can then be performed using the methods in this class. Each
  94. method xxx(args...) corresponds to a libfdt function fdt_xxx(fdt, args...).
  95. All methods raise an FdtException if an error occurs. To avoid this
  96. behaviour a 'quiet' parameter is provided for some functions. This
  97. defaults to empty, but you can pass a list of errors that you expect.
  98. If one of these errors occurs, the function will return an error number
  99. (e.g. -NOTFOUND).
  100. """
  101. def __init__(self, data):
  102. self._fdt = bytearray(data)
  103. check_err(fdt_check_header(self._fdt));
  104. def subnode_offset(self, parentoffset, name, quiet=()):
  105. """Get the offset of a named subnode
  106. Args:
  107. parentoffset: Offset of the parent node to check
  108. name: Name of the required subnode, e.g. 'subnode@1'
  109. quiet: Errors to ignore (empty to raise on all errors)
  110. Returns:
  111. The node offset of the found node, if any
  112. Raises
  113. FdtException if there is no node with that name, or other error
  114. """
  115. return check_err(fdt_subnode_offset(self._fdt, parentoffset, name),
  116. quiet)
  117. def path_offset(self, path, quiet=()):
  118. """Get the offset for a given path
  119. Args:
  120. path: Path to the required node, e.g. '/node@3/subnode@1'
  121. quiet: Errors to ignore (empty to raise on all errors)
  122. Returns:
  123. Node offset
  124. Raises
  125. FdtException if the path is not valid or not found
  126. """
  127. return check_err(fdt_path_offset(self._fdt, path), quiet)
  128. def first_property_offset(self, nodeoffset, quiet=()):
  129. """Get the offset of the first property in a node offset
  130. Args:
  131. nodeoffset: Offset to the node to check
  132. quiet: Errors to ignore (empty to raise on all errors)
  133. Returns:
  134. Offset of the first property
  135. Raises
  136. FdtException if the associated node has no properties, or some
  137. other error occurred
  138. """
  139. return check_err(fdt_first_property_offset(self._fdt, nodeoffset),
  140. quiet)
  141. def next_property_offset(self, prop_offset, quiet=()):
  142. """Get the next property in a node
  143. Args:
  144. prop_offset: Offset of the previous property
  145. quiet: Errors to ignore (empty to raise on all errors)
  146. Returns:
  147. Offset of the next property
  148. Raises:
  149. FdtException if the associated node has no more properties, or
  150. some other error occurred
  151. """
  152. return check_err(fdt_next_property_offset(self._fdt, prop_offset),
  153. quiet)
  154. def get_name(self, nodeoffset):
  155. """Get the name of a node
  156. Args:
  157. nodeoffset: Offset of node to check
  158. Returns:
  159. Node name
  160. Raises:
  161. FdtException on error (e.g. nodeoffset is invalid)
  162. """
  163. return check_err_null(fdt_get_name(self._fdt, nodeoffset))[0]
  164. def get_property_by_offset(self, prop_offset, quiet=()):
  165. """Obtains a property that can be examined
  166. Args:
  167. prop_offset: Offset of property (e.g. from first_property_offset())
  168. quiet: Errors to ignore (empty to raise on all errors)
  169. Returns:
  170. Property object, or None if not found
  171. Raises:
  172. FdtException on error (e.g. invalid prop_offset or device
  173. tree format)
  174. """
  175. pdata = check_err_null(
  176. fdt_get_property_by_offset(self._fdt, prop_offset), quiet)
  177. if isinstance(pdata, (int)):
  178. return pdata
  179. return Property(pdata[0], pdata[1])
  180. def first_subnode(self, nodeoffset, quiet=()):
  181. """Find the first subnode of a parent node
  182. Args:
  183. nodeoffset: Node offset of parent node
  184. quiet: Errors to ignore (empty to raise on all errors)
  185. Returns:
  186. The offset of the first subnode, if any
  187. Raises:
  188. FdtException if no subnode found or other error occurs
  189. """
  190. return check_err(fdt_first_subnode(self._fdt, nodeoffset), quiet)
  191. def next_subnode(self, nodeoffset, quiet=()):
  192. """Find the next subnode
  193. Args:
  194. nodeoffset: Node offset of previous subnode
  195. quiet: Errors to ignore (empty to raise on all errors)
  196. Returns:
  197. The offset of the next subnode, if any
  198. Raises:
  199. FdtException if no more subnode found or other error occurs
  200. """
  201. return check_err(fdt_next_subnode(self._fdt, nodeoffset), quiet)
  202. def totalsize(self):
  203. """Return the total size of the device tree
  204. Returns:
  205. Total tree size in bytes
  206. """
  207. return check_err(fdt_totalsize(self._fdt))
  208. def off_dt_struct(self):
  209. """Return the start of the device tree struct area
  210. Returns:
  211. Start offset of struct area
  212. """
  213. return check_err(fdt_off_dt_struct(self._fdt))
  214. def pack(self, quiet=()):
  215. """Pack the device tree to remove unused space
  216. This adjusts the tree in place.
  217. Args:
  218. quiet: Errors to ignore (empty to raise on all errors)
  219. Raises:
  220. FdtException if any error occurs
  221. """
  222. return check_err(fdt_pack(self._fdt), quiet)
  223. def delprop(self, nodeoffset, prop_name):
  224. """Delete a property from a node
  225. Args:
  226. nodeoffset: Node offset containing property to delete
  227. prop_name: Name of property to delete
  228. Raises:
  229. FdtError if the property does not exist, or another error occurs
  230. """
  231. return check_err(fdt_delprop(self._fdt, nodeoffset, prop_name))
  232. def getprop(self, nodeoffset, prop_name, quiet=()):
  233. """Get a property from a node
  234. Args:
  235. nodeoffset: Node offset containing property to get
  236. prop_name: Name of property to get
  237. quiet: Errors to ignore (empty to raise on all errors)
  238. Returns:
  239. Value of property as a bytearray, or -ve error number
  240. Raises:
  241. FdtError if any error occurs (e.g. the property is not found)
  242. """
  243. pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name),
  244. quiet)
  245. if isinstance(pdata, (int)):
  246. return pdata
  247. return bytearray(pdata[0])
  248. def get_phandle(self, nodeoffset):
  249. """Get the phandle of a node
  250. Args:
  251. nodeoffset: Node offset to check
  252. Returns:
  253. phandle of node, or 0 if the node has no phandle or another error
  254. occurs
  255. """
  256. return fdt_get_phandle(self._fdt, nodeoffset)
  257. def parent_offset(self, nodeoffset, quiet=()):
  258. """Get the offset of a node's parent
  259. Args:
  260. nodeoffset: Node offset to check
  261. quiet: Errors to ignore (empty to raise on all errors)
  262. Returns:
  263. The offset of the parent node, if any
  264. Raises:
  265. FdtException if no parent found or other error occurs
  266. """
  267. return check_err(fdt_parent_offset(self._fdt, nodeoffset), quiet)
  268. def node_offset_by_phandle(self, phandle, quiet=()):
  269. """Get the offset of a node with the given phandle
  270. Args:
  271. phandle: Phandle to search for
  272. quiet: Errors to ignore (empty to raise on all errors)
  273. Returns:
  274. The offset of node with that phandle, if any
  275. Raises:
  276. FdtException if no node found or other error occurs
  277. """
  278. return check_err(fdt_node_offset_by_phandle(self._fdt, phandle), quiet)
  279. class Property:
  280. """Holds a device tree property name and value.
  281. This holds a copy of a property taken from the device tree. It does not
  282. reference the device tree, so if anything changes in the device tree,
  283. a Property object will remain valid.
  284. Properties:
  285. name: Property name
  286. value: Proper value as a bytearray
  287. """
  288. def __init__(self, name, value):
  289. self.name = name
  290. self.value = value
  291. %}
  292. %rename(fdt_property) fdt_property_func;
  293. typedef int fdt32_t;
  294. %include "libfdt/fdt.h"
  295. %include "typemaps.i"
  296. /* Most functions don't change the device tree, so use a const void * */
  297. %typemap(in) (const void *)(const void *fdt) {
  298. if (!PyByteArray_Check($input)) {
  299. SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
  300. "', argument " "$argnum"" of type '" "$type""'");
  301. }
  302. $1 = (void *)PyByteArray_AsString($input);
  303. fdt = $1;
  304. fdt = fdt; /* avoid unused variable warning */
  305. }
  306. /* Some functions do change the device tree, so use void * */
  307. %typemap(in) (void *)(const void *fdt) {
  308. if (!PyByteArray_Check($input)) {
  309. SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
  310. "', argument " "$argnum"" of type '" "$type""'");
  311. }
  312. $1 = PyByteArray_AsString($input);
  313. fdt = $1;
  314. fdt = fdt; /* avoid unused variable warning */
  315. }
  316. %typemap(out) (struct fdt_property *) {
  317. PyObject *buff;
  318. if ($1) {
  319. resultobj = PyString_FromString(
  320. fdt_string(fdt1, fdt32_to_cpu($1->nameoff)));
  321. buff = PyByteArray_FromStringAndSize(
  322. (const char *)($1 + 1), fdt32_to_cpu($1->len));
  323. resultobj = SWIG_Python_AppendOutput(resultobj, buff);
  324. }
  325. }
  326. %apply int *OUTPUT { int *lenp };
  327. /* typemap used for fdt_getprop() */
  328. %typemap(out) (const void *) {
  329. if (!$1)
  330. $result = Py_None;
  331. else
  332. $result = Py_BuildValue("s#", $1, *arg4);
  333. }
  334. /* We have both struct fdt_property and a function fdt_property() */
  335. %warnfilter(302) fdt_property;
  336. /* These are macros in the header so have to be redefined here */
  337. int fdt_magic(const void *fdt);
  338. int fdt_totalsize(const void *fdt);
  339. int fdt_off_dt_struct(const void *fdt);
  340. int fdt_off_dt_strings(const void *fdt);
  341. int fdt_off_mem_rsvmap(const void *fdt);
  342. int fdt_version(const void *fdt);
  343. int fdt_last_comp_version(const void *fdt);
  344. int fdt_boot_cpuid_phys(const void *fdt);
  345. int fdt_size_dt_strings(const void *fdt);
  346. int fdt_size_dt_struct(const void *fdt);
  347. %include <../libfdt/libfdt.h>