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