blob: 5b1a8cf4d493a9a492e1b8060d68c7e9ca234fa9 [file] [log] [blame]
Simon Glassa13d9022017-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 Glass1c879312017-08-13 16:02:54 -060011%include <stdint.i>
12
Simon Glassa13d9022017-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
Simon Glass460b2522017-08-29 14:15:46 -0600133 def subnode_offset(self, parentoffset, name, quiet=()):
134 """Get the offset of a named subnode
135
136 Args:
137 parentoffset: Offset of the parent node to check
138 name: Name of the required subnode, e.g. 'subnode@1'
139 quiet: Errors to ignore (empty to raise on all errors)
140
141 Returns:
142 The node offset of the found node, if any
143
144 Raises
145 FdtException if there is no node with that name, or other error
146 """
147 return check_err(fdt_subnode_offset(self._fdt, parentoffset, name),
148 quiet)
149
Simon Glassa13d9022017-05-27 07:38:11 -0600150 def path_offset(self, path, quiet=()):
151 """Get the offset for a given path
152
153 Args:
154 path: Path to the required node, e.g. '/node@3/subnode@1'
155 quiet: Errors to ignore (empty to raise on all errors)
156
157 Returns:
158 Node offset
159
160 Raises
161 FdtException if the path is not valid or not found
162 """
163 return check_err(fdt_path_offset(self._fdt, path), quiet)
164
165 def first_property_offset(self, nodeoffset, quiet=()):
166 """Get the offset of the first property in a node offset
167
168 Args:
169 nodeoffset: Offset to the node to check
170 quiet: Errors to ignore (empty to raise on all errors)
171
172 Returns:
173 Offset of the first property
174
175 Raises
176 FdtException if the associated node has no properties, or some
177 other error occurred
178 """
179 return check_err(fdt_first_property_offset(self._fdt, nodeoffset),
180 quiet)
181
182 def next_property_offset(self, prop_offset, quiet=()):
183 """Get the next property in a node
184
185 Args:
186 prop_offset: Offset of the previous property
187 quiet: Errors to ignore (empty to raise on all errors)
188
189 Returns:
190 Offset of the next property
191
192 Raises:
193 FdtException if the associated node has no more properties, or
194 some other error occurred
195 """
196 return check_err(fdt_next_property_offset(self._fdt, prop_offset),
197 quiet)
198
199 def get_name(self, nodeoffset):
200 """Get the name of a node
201
202 Args:
203 nodeoffset: Offset of node to check
204
205 Returns:
206 Node name
207
208 Raises:
209 FdtException on error (e.g. nodeoffset is invalid)
210 """
211 return check_err_null(fdt_get_name(self._fdt, nodeoffset))[0]
212
213 def get_property_by_offset(self, prop_offset, quiet=()):
214 """Obtains a property that can be examined
215
216 Args:
217 prop_offset: Offset of property (e.g. from first_property_offset())
218 quiet: Errors to ignore (empty to raise on all errors)
219
220 Returns:
221 Property object, or None if not found
222
223 Raises:
224 FdtException on error (e.g. invalid prop_offset or device
225 tree format)
226 """
227 pdata = check_err_null(
228 fdt_get_property_by_offset(self._fdt, prop_offset), quiet)
229 if isinstance(pdata, (int)):
230 return pdata
231 return Property(pdata[0], pdata[1])
232
233 def first_subnode(self, nodeoffset, quiet=()):
234 """Find the first subnode of a parent node
235
236 Args:
237 nodeoffset: Node offset of parent node
238 quiet: Errors to ignore (empty to raise on all errors)
239
240 Returns:
241 The offset of the first subnode, if any
242
243 Raises:
244 FdtException if no subnode found or other error occurs
245 """
246 return check_err(fdt_first_subnode(self._fdt, nodeoffset), quiet)
247
248 def next_subnode(self, nodeoffset, quiet=()):
249 """Find the next subnode
250
251 Args:
252 nodeoffset: Node offset of previous subnode
253 quiet: Errors to ignore (empty to raise on all errors)
254
255 Returns:
256 The offset of the next subnode, if any
257
258 Raises:
259 FdtException if no more subnode found or other error occurs
260 """
261 return check_err(fdt_next_subnode(self._fdt, nodeoffset), quiet)
262
263 def totalsize(self):
264 """Return the total size of the device tree
265
266 Returns:
267 Total tree size in bytes
268 """
269 return check_err(fdt_totalsize(self._fdt))
270
271 def off_dt_struct(self):
272 """Return the start of the device tree struct area
273
274 Returns:
275 Start offset of struct area
276 """
277 return check_err(fdt_off_dt_struct(self._fdt))
278
279 def pack(self, quiet=()):
280 """Pack the device tree to remove unused space
281
282 This adjusts the tree in place.
283
284 Args:
285 quiet: Errors to ignore (empty to raise on all errors)
286
287 Raises:
288 FdtException if any error occurs
289 """
290 return check_err(fdt_pack(self._fdt), quiet)
291
292 def delprop(self, nodeoffset, prop_name):
293 """Delete a property from a node
294
295 Args:
296 nodeoffset: Node offset containing property to delete
297 prop_name: Name of property to delete
298
299 Raises:
300 FdtError if the property does not exist, or another error occurs
301 """
302 return check_err(fdt_delprop(self._fdt, nodeoffset, prop_name))
303
304 def getprop(self, nodeoffset, prop_name, quiet=()):
305 """Get a property from a node
306
307 Args:
308 nodeoffset: Node offset containing property to get
309 prop_name: Name of property to get
310 quiet: Errors to ignore (empty to raise on all errors)
311
312 Returns:
313 Value of property as a bytearray, or -ve error number
314
315 Raises:
316 FdtError if any error occurs (e.g. the property is not found)
317 """
318 pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name),
319 quiet)
320 if isinstance(pdata, (int)):
321 return pdata
322 return bytearray(pdata[0])
323
Simon Glass460b2522017-08-29 14:15:46 -0600324 def get_phandle(self, nodeoffset):
325 """Get the phandle of a node
326
327 Args:
328 nodeoffset: Node offset to check
329
330 Returns:
331 phandle of node, or 0 if the node has no phandle or another error
332 occurs
333 """
334 return fdt_get_phandle(self._fdt, nodeoffset)
335
336 def parent_offset(self, nodeoffset, quiet=()):
337 """Get the offset of a node's parent
338
339 Args:
340 nodeoffset: Node offset to check
341 quiet: Errors to ignore (empty to raise on all errors)
342
343 Returns:
344 The offset of the parent node, if any
345
346 Raises:
347 FdtException if no parent found or other error occurs
348 """
349 return check_err(fdt_parent_offset(self._fdt, nodeoffset), quiet)
350
351 def node_offset_by_phandle(self, phandle, quiet=()):
352 """Get the offset of a node with the given phandle
353
354 Args:
355 phandle: Phandle to search for
356 quiet: Errors to ignore (empty to raise on all errors)
357
358 Returns:
359 The offset of node with that phandle, if any
360
361 Raises:
362 FdtException if no node found or other error occurs
363 """
364 return check_err(fdt_node_offset_by_phandle(self._fdt, phandle), quiet)
Simon Glassa13d9022017-05-27 07:38:11 -0600365
366class Property:
367 """Holds a device tree property name and value.
368
369 This holds a copy of a property taken from the device tree. It does not
370 reference the device tree, so if anything changes in the device tree,
371 a Property object will remain valid.
372
373 Properties:
374 name: Property name
375 value: Proper value as a bytearray
376 """
377 def __init__(self, name, value):
378 self.name = name
379 self.value = value
380%}
381
382%rename(fdt_property) fdt_property_func;
383
384typedef int fdt32_t;
385
386%include "libfdt/fdt.h"
387
388%include "typemaps.i"
389
390/* Most functions don't change the device tree, so use a const void * */
391%typemap(in) (const void *)(const void *fdt) {
392 if (!PyByteArray_Check($input)) {
393 SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
394 "', argument " "$argnum"" of type '" "$type""'");
395 }
396 $1 = (void *)PyByteArray_AsString($input);
397 fdt = $1;
398 fdt = fdt; /* avoid unused variable warning */
399}
400
401/* Some functions do change the device tree, so use void * */
402%typemap(in) (void *)(const void *fdt) {
403 if (!PyByteArray_Check($input)) {
404 SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
405 "', argument " "$argnum"" of type '" "$type""'");
406 }
407 $1 = PyByteArray_AsString($input);
408 fdt = $1;
409 fdt = fdt; /* avoid unused variable warning */
410}
411
412%typemap(out) (struct fdt_property *) {
413 PyObject *buff;
414
415 if ($1) {
416 resultobj = PyString_FromString(
417 fdt_string(fdt1, fdt32_to_cpu($1->nameoff)));
418 buff = PyByteArray_FromStringAndSize(
419 (const char *)($1 + 1), fdt32_to_cpu($1->len));
420 resultobj = SWIG_Python_AppendOutput(resultobj, buff);
421 }
422}
423
424%apply int *OUTPUT { int *lenp };
425
426/* typemap used for fdt_getprop() */
427%typemap(out) (const void *) {
428 if (!$1)
429 $result = Py_None;
430 else
431 $result = Py_BuildValue("s#", $1, *arg4);
432}
433
434/* We have both struct fdt_property and a function fdt_property() */
435%warnfilter(302) fdt_property;
436
437/* These are macros in the header so have to be redefined here */
438int fdt_magic(const void *fdt);
439int fdt_totalsize(const void *fdt);
440int fdt_off_dt_struct(const void *fdt);
441int fdt_off_dt_strings(const void *fdt);
442int fdt_off_mem_rsvmap(const void *fdt);
443int fdt_version(const void *fdt);
444int fdt_last_comp_version(const void *fdt);
445int fdt_boot_cpuid_phys(const void *fdt);
446int fdt_size_dt_strings(const void *fdt);
447int fdt_size_dt_struct(const void *fdt);
448
449%include <../libfdt/libfdt.h>