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