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