2 * pylibfdt - Flat Device Tree manipulation in Python
3 * Copyright (C) 2017 Google, Inc.
4 * Written by Simon Glass <sjg@chromium.org>
6 * SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause
12 #define SWIG_FILE_WITH_INIT
20 # Error codes, corresponding to FDT_ERR_... in libfdt.h
37 NOPHANDLES) = QUIET_ALL = range(1, 18)
38 # QUIET_ALL can be passed as the 'quiet' parameter to avoid exceptions
39 # altogether. All # functions passed this value will return an error instead
40 # of raising an exception.
42 # Pass this as the 'quiet' parameter to return -ENOTFOUND on NOTFOUND errors,
43 # instead of raising an exception.
44 QUIET_NOTFOUND = (NOTFOUND,)
47 class FdtException(Exception):
48 """An exception caused by an error such as one of the codes above"""
49 def __init__(self, err):
53 return 'pylibfdt error %d: %s' % (self.err, fdt_strerror(self.err))
55 def strerror(fdt_err):
56 """Get the string for an error number
59 fdt_err: Error number (-ve)
62 String containing the associated error
64 return fdt_strerror(fdt_err)
66 def check_err(val, quiet=()):
67 """Raise an error if the return value is -ve
69 This is used to check for errors returned by libfdt C functions.
72 val: Return value from a libfdt function
73 quiet: Errors to ignore (empty to raise on all errors)
79 FdtException if val < 0
83 raise FdtException(val)
86 def check_err_null(val, quiet=()):
87 """Raise an error if the return value is NULL
89 This is used to check for a NULL return value from certain libfdt C
93 val: Return value from a libfdt function
94 quiet: Errors to ignore (empty to raise on all errors)
97 val if val is a list, None if not
100 FdtException if val indicates an error was reported and the error
103 # Normally a list is returned which contains the data and its length.
104 # If we get just an integer error code, it means the function failed.
105 if not isinstance(val, list):
106 if -val not in quiet:
107 raise FdtException(val)
111 """Device tree class, supporting all operations
113 The Fdt object is created is created from a device tree binary file,
114 e.g. with something like:
116 fdt = Fdt(open("filename.dtb").read())
118 Operations can then be performed using the methods in this class. Each
119 method xxx(args...) corresponds to a libfdt function fdt_xxx(fdt, args...).
121 All methods raise an FdtException if an error occurs. To avoid this
122 behaviour a 'quiet' parameter is provided for some functions. This
123 defaults to empty, but you can pass a list of errors that you expect.
124 If one of these errors occurs, the function will return an error number
127 def __init__(self, data):
128 self._fdt = bytearray(data)
129 check_err(fdt_check_header(self._fdt));
131 def path_offset(self, path, quiet=()):
132 """Get the offset for a given path
135 path: Path to the required node, e.g. '/node@3/subnode@1'
136 quiet: Errors to ignore (empty to raise on all errors)
142 FdtException if the path is not valid or not found
144 return check_err(fdt_path_offset(self._fdt, path), quiet)
146 def first_property_offset(self, nodeoffset, quiet=()):
147 """Get the offset of the first property in a node offset
150 nodeoffset: Offset to the node to check
151 quiet: Errors to ignore (empty to raise on all errors)
154 Offset of the first property
157 FdtException if the associated node has no properties, or some
160 return check_err(fdt_first_property_offset(self._fdt, nodeoffset),
163 def next_property_offset(self, prop_offset, quiet=()):
164 """Get the next property in a node
167 prop_offset: Offset of the previous property
168 quiet: Errors to ignore (empty to raise on all errors)
171 Offset of the next property
174 FdtException if the associated node has no more properties, or
175 some other error occurred
177 return check_err(fdt_next_property_offset(self._fdt, prop_offset),
180 def get_name(self, nodeoffset):
181 """Get the name of a node
184 nodeoffset: Offset of node to check
190 FdtException on error (e.g. nodeoffset is invalid)
192 return check_err_null(fdt_get_name(self._fdt, nodeoffset))[0]
194 def get_property_by_offset(self, prop_offset, quiet=()):
195 """Obtains a property that can be examined
198 prop_offset: Offset of property (e.g. from first_property_offset())
199 quiet: Errors to ignore (empty to raise on all errors)
202 Property object, or None if not found
205 FdtException on error (e.g. invalid prop_offset or device
208 pdata = check_err_null(
209 fdt_get_property_by_offset(self._fdt, prop_offset), quiet)
210 if isinstance(pdata, (int)):
212 return Property(pdata[0], pdata[1])
214 def first_subnode(self, nodeoffset, quiet=()):
215 """Find the first subnode of a parent node
218 nodeoffset: Node offset of parent node
219 quiet: Errors to ignore (empty to raise on all errors)
222 The offset of the first subnode, if any
225 FdtException if no subnode found or other error occurs
227 return check_err(fdt_first_subnode(self._fdt, nodeoffset), quiet)
229 def next_subnode(self, nodeoffset, quiet=()):
230 """Find the next subnode
233 nodeoffset: Node offset of previous subnode
234 quiet: Errors to ignore (empty to raise on all errors)
237 The offset of the next subnode, if any
240 FdtException if no more subnode found or other error occurs
242 return check_err(fdt_next_subnode(self._fdt, nodeoffset), quiet)
245 """Return the total size of the device tree
248 Total tree size in bytes
250 return check_err(fdt_totalsize(self._fdt))
252 def off_dt_struct(self):
253 """Return the start of the device tree struct area
256 Start offset of struct area
258 return check_err(fdt_off_dt_struct(self._fdt))
260 def pack(self, quiet=()):
261 """Pack the device tree to remove unused space
263 This adjusts the tree in place.
266 quiet: Errors to ignore (empty to raise on all errors)
269 FdtException if any error occurs
271 return check_err(fdt_pack(self._fdt), quiet)
273 def delprop(self, nodeoffset, prop_name):
274 """Delete a property from a node
277 nodeoffset: Node offset containing property to delete
278 prop_name: Name of property to delete
281 FdtError if the property does not exist, or another error occurs
283 return check_err(fdt_delprop(self._fdt, nodeoffset, prop_name))
285 def getprop(self, nodeoffset, prop_name, quiet=()):
286 """Get a property from a node
289 nodeoffset: Node offset containing property to get
290 prop_name: Name of property to get
291 quiet: Errors to ignore (empty to raise on all errors)
294 Value of property as a bytearray, or -ve error number
297 FdtError if any error occurs (e.g. the property is not found)
299 pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name),
301 if isinstance(pdata, (int)):
303 return bytearray(pdata[0])
307 """Holds a device tree property name and value.
309 This holds a copy of a property taken from the device tree. It does not
310 reference the device tree, so if anything changes in the device tree,
311 a Property object will remain valid.
315 value: Proper value as a bytearray
317 def __init__(self, name, value):
322 %rename(fdt_property) fdt_property_func;
326 %include "libfdt/fdt.h"
328 %include "typemaps.i"
330 /* Most functions don't change the device tree, so use a const void * */
331 %typemap(in) (const void *)(const void *fdt) {
332 if (!PyByteArray_Check($input)) {
333 SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
334 "', argument " "$argnum"" of type '" "$type""'");
336 $1 = (void *)PyByteArray_AsString($input);
338 fdt = fdt; /* avoid unused variable warning */
341 /* Some functions do change the device tree, so use void * */
342 %typemap(in) (void *)(const void *fdt) {
343 if (!PyByteArray_Check($input)) {
344 SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
345 "', argument " "$argnum"" of type '" "$type""'");
347 $1 = PyByteArray_AsString($input);
349 fdt = fdt; /* avoid unused variable warning */
352 %typemap(out) (struct fdt_property *) {
356 resultobj = PyString_FromString(
357 fdt_string(fdt1, fdt32_to_cpu($1->nameoff)));
358 buff = PyByteArray_FromStringAndSize(
359 (const char *)($1 + 1), fdt32_to_cpu($1->len));
360 resultobj = SWIG_Python_AppendOutput(resultobj, buff);
364 %apply int *OUTPUT { int *lenp };
366 /* typemap used for fdt_getprop() */
367 %typemap(out) (const void *) {
371 $result = Py_BuildValue("s#", $1, *arg4);
374 /* We have both struct fdt_property and a function fdt_property() */
375 %warnfilter(302) fdt_property;
377 /* These are macros in the header so have to be redefined here */
378 int fdt_magic(const void *fdt);
379 int fdt_totalsize(const void *fdt);
380 int fdt_off_dt_struct(const void *fdt);
381 int fdt_off_dt_strings(const void *fdt);
382 int fdt_off_mem_rsvmap(const void *fdt);
383 int fdt_version(const void *fdt);
384 int fdt_last_comp_version(const void *fdt);
385 int fdt_boot_cpuid_phys(const void *fdt);
386 int fdt_size_dt_strings(const void *fdt);
387 int fdt_size_dt_struct(const void *fdt);
389 %include <../libfdt/libfdt.h>