xref: /aosp_15_r20/external/dtc/pylibfdt/libfdt.i (revision cd60bc56d4bea3af4ec04523e4d71c2b272c8aff)
1 // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
2 /*
3  * pylibfdt - Flat Device Tree manipulation in Python
4  * Copyright (C) 2017 Google, Inc.
5  * Written by Simon Glass <[email protected]>
6  */
7 
8 %module libfdt
9 
10 %include <stdint.i>
11 
12 %{
13 #define SWIG_FILE_WITH_INIT
14 #include "libfdt.h"
15 
16 /*
17  * We rename this function here to avoid problems with swig, since we also have
18  * a struct called fdt_property. That struct causes swig to create a class in
19  * libfdt.py called fdt_property(), which confuses things.
20  */
fdt_property_stub(void * fdt,const char * name,const void * val,int len)21 static int fdt_property_stub(void *fdt, const char *name, const void *val,
22                              int len)
23 {
24     return fdt_property(fdt, name, val, len);
25 }
26 
27 %}
28 
29 %pythoncode %{
30 
31 import struct
32 
33 # Error codes, corresponding to FDT_ERR_... in libfdt.h
34 (NOTFOUND,
35         EXISTS,
36         NOSPACE,
37         BADOFFSET,
38         BADPATH,
39         BADPHANDLE,
40         BADSTATE,
41         TRUNCATED,
42         BADMAGIC,
43         BADVERSION,
44         BADSTRUCTURE,
45         BADLAYOUT,
46         INTERNAL,
47         BADNCELLS,
48         BADVALUE,
49         BADOVERLAY,
50         NOPHANDLES) = QUIET_ALL = range(1, 18)
51 # QUIET_ALL can be passed as the 'quiet' parameter to avoid exceptions
52 # altogether. All # functions passed this value will return an error instead
53 # of raising an exception.
54 
55 # Pass this as the 'quiet' parameter to return -ENOTFOUND on NOTFOUND errors,
56 # instead of raising an exception.
57 QUIET_NOTFOUND = (NOTFOUND,)
58 QUIET_NOSPACE = (NOSPACE,)
59 
60 
61 class FdtException(Exception):
62     """An exception caused by an error such as one of the codes above"""
63     def __init__(self, err):
64         self.err = err
65 
66     def __str__(self):
67         return 'pylibfdt error %d: %s' % (self.err, fdt_strerror(self.err))
68 
69 def strerror(fdt_err):
70     """Get the string for an error number
71 
72     Args:
73         fdt_err: Error number (-ve)
74 
75     Returns:
76         String containing the associated error
77     """
78     return fdt_strerror(fdt_err)
79 
80 def check_err(val, quiet=()):
81     """Raise an error if the return value is -ve
82 
83     This is used to check for errors returned by libfdt C functions.
84 
85     Args:
86         val: Return value from a libfdt function
87         quiet: Errors to ignore (empty to raise on all errors)
88 
89     Returns:
90         val if val >= 0
91 
92     Raises
93         FdtException if val < 0
94     """
95     if isinstance(val, int) and val < 0:
96         if -val not in quiet:
97             raise FdtException(val)
98     return val
99 
100 def check_err_null(val, quiet=()):
101     """Raise an error if the return value is NULL
102 
103     This is used to check for a NULL return value from certain libfdt C
104     functions
105 
106     Args:
107         val: Return value from a libfdt function
108         quiet: Errors to ignore (empty to raise on all errors)
109 
110     Returns:
111         val if val is a list, None if not
112 
113     Raises
114         FdtException if val indicates an error was reported and the error
115         is not in @quiet.
116     """
117     # Normally a list is returned which contains the data and its length.
118     # If we get just an integer error code, it means the function failed.
119     if not isinstance(val, list):
120         if -val not in quiet:
121             raise FdtException(val)
122     return val
123 
124 class FdtRo(object):
125     """Class for a read-only device-tree
126 
127     This is a base class used by FdtRw (read-write access) and FdtSw
128     (sequential-write access). It implements read-only access to the
129     device tree.
130 
131     Here are the three classes and when you should use them:
132 
133         FdtRo - read-only access to an existing FDT
134         FdtRw - read-write access to an existing FDT (most common case)
135         FdtSw - for creating a new FDT, as well as allowing read-only access
136     """
137     def __init__(self, data):
138         self._fdt = bytearray(data)
139         check_err(fdt_check_header(self._fdt));
140 
141     def as_bytearray(self):
142         """Get the device tree contents as a bytearray
143 
144         This can be passed directly to libfdt functions that access a
145         const void * for the device tree.
146 
147         Returns:
148             bytearray containing the device tree
149         """
150         return bytearray(self._fdt)
151 
152     def next_node(self, nodeoffset, depth, quiet=()):
153         """Find the next subnode
154 
155         Args:
156             nodeoffset: Node offset of previous node
157             depth: The depth of the node at nodeoffset. This is used to
158                 calculate the depth of the returned node
159             quiet: Errors to ignore (empty to raise on all errors)
160 
161         Returns:
162             Typle:
163                 Offset of the next node, if any, else a -ve error
164                 Depth of the returned node, if any, else undefined
165 
166         Raises:
167             FdtException if no more nodes found or other error occurs
168         """
169         return check_err(fdt_next_node(self._fdt, nodeoffset, depth), quiet)
170 
171     def first_subnode(self, nodeoffset, quiet=()):
172         """Find the first subnode of a parent node
173 
174         Args:
175             nodeoffset: Node offset of parent node
176             quiet: Errors to ignore (empty to raise on all errors)
177 
178         Returns:
179             The offset of the first subnode, if any
180 
181         Raises:
182             FdtException if no subnodes found or other error occurs
183         """
184         return check_err(fdt_first_subnode(self._fdt, nodeoffset), quiet)
185 
186     def next_subnode(self, nodeoffset, quiet=()):
187         """Find the next subnode
188 
189         Args:
190             nodeoffset: Node offset of previous subnode
191             quiet: Errors to ignore (empty to raise on all errors)
192 
193         Returns:
194             The offset of the next subnode, if any
195 
196         Raises:
197             FdtException if no more subnodes found or other error occurs
198         """
199         return check_err(fdt_next_subnode(self._fdt, nodeoffset), quiet)
200 
201     def magic(self):
202         """Return the magic word from the header
203 
204         Returns:
205             Magic word
206         """
207         return fdt_magic(self._fdt)
208 
209     def totalsize(self):
210         """Return the total size of the device tree
211 
212         Returns:
213             Total tree size in bytes
214         """
215         return fdt_totalsize(self._fdt)
216 
217     def off_dt_struct(self):
218         """Return the start of the device-tree struct area
219 
220         Returns:
221             Start offset of struct area
222         """
223         return fdt_off_dt_struct(self._fdt)
224 
225     def off_dt_strings(self):
226         """Return the start of the device-tree string area
227 
228         Returns:
229             Start offset of string area
230         """
231         return fdt_off_dt_strings(self._fdt)
232 
233     def off_mem_rsvmap(self):
234         """Return the start of the memory reserve map
235 
236         Returns:
237             Start offset of memory reserve map
238         """
239         return fdt_off_mem_rsvmap(self._fdt)
240 
241     def version(self):
242         """Return the version of the device tree
243 
244         Returns:
245             Version number of the device tree
246         """
247         return fdt_version(self._fdt)
248 
249     def last_comp_version(self):
250         """Return the last compatible version of the device tree
251 
252         Returns:
253             Last compatible version number of the device tree
254         """
255         return fdt_last_comp_version(self._fdt)
256 
257     def boot_cpuid_phys(self):
258         """Return the physical boot CPU ID
259 
260         Returns:
261             Physical boot CPU ID
262         """
263         return fdt_boot_cpuid_phys(self._fdt)
264 
265     def size_dt_strings(self):
266         """Return the start of the device-tree string area
267 
268         Returns:
269             Start offset of string area
270         """
271         return fdt_size_dt_strings(self._fdt)
272 
273     def size_dt_struct(self):
274         """Return the start of the device-tree struct area
275 
276         Returns:
277             Start offset of struct area
278         """
279         return fdt_size_dt_struct(self._fdt)
280 
281     def num_mem_rsv(self, quiet=()):
282         """Return the number of memory reserve-map records
283 
284         Returns:
285             Number of memory reserve-map records
286         """
287         return check_err(fdt_num_mem_rsv(self._fdt), quiet)
288 
289     def get_mem_rsv(self, index, quiet=()):
290         """Return the indexed memory reserve-map record
291 
292         Args:
293             index: Record to return (0=first)
294 
295         Returns:
296             Number of memory reserve-map records
297         """
298         return check_err(fdt_get_mem_rsv(self._fdt, index), quiet)
299 
300     def subnode_offset(self, parentoffset, name, quiet=()):
301         """Get the offset of a named subnode
302 
303         Args:
304             parentoffset: Offset of the parent node to check
305             name: Name of the required subnode, e.g. 'subnode@1'
306             quiet: Errors to ignore (empty to raise on all errors)
307 
308         Returns:
309             The node offset of the found node, if any
310 
311         Raises
312             FdtException if there is no node with that name, or other error
313         """
314         return check_err(fdt_subnode_offset(self._fdt, parentoffset, name),
315                          quiet)
316 
317     def path_offset(self, path, quiet=()):
318         """Get the offset for a given path
319 
320         Args:
321             path: Path to the required node, e.g. '/node@3/subnode@1'
322             quiet: Errors to ignore (empty to raise on all errors)
323 
324         Returns:
325             Node offset
326 
327         Raises
328             FdtException if the path is not valid or not found
329         """
330         return check_err(fdt_path_offset(self._fdt, path), quiet)
331 
332     def get_name(self, nodeoffset):
333         """Get the name of a node
334 
335         Args:
336             nodeoffset: Offset of node to check
337 
338         Returns:
339             Node name
340 
341         Raises:
342             FdtException on error (e.g. nodeoffset is invalid)
343         """
344         return check_err_null(fdt_get_name(self._fdt, nodeoffset))[0]
345 
346     def first_property_offset(self, nodeoffset, quiet=()):
347         """Get the offset of the first property in a node offset
348 
349         Args:
350             nodeoffset: Offset to the node to check
351             quiet: Errors to ignore (empty to raise on all errors)
352 
353         Returns:
354             Offset of the first property
355 
356         Raises
357             FdtException if the associated node has no properties, or some
358                 other error occurred
359         """
360         return check_err(fdt_first_property_offset(self._fdt, nodeoffset),
361                          quiet)
362 
363     def next_property_offset(self, prop_offset, quiet=()):
364         """Get the next property in a node
365 
366         Args:
367             prop_offset: Offset of the previous property
368             quiet: Errors to ignore (empty to raise on all errors)
369 
370         Returns:
371             Offset of the next property
372 
373         Raises:
374             FdtException if the associated node has no more properties, or
375                 some other error occurred
376         """
377         return check_err(fdt_next_property_offset(self._fdt, prop_offset),
378                          quiet)
379 
380     def get_property_by_offset(self, prop_offset, quiet=()):
381         """Obtains a property that can be examined
382 
383         Args:
384             prop_offset: Offset of property (e.g. from first_property_offset())
385             quiet: Errors to ignore (empty to raise on all errors)
386 
387         Returns:
388             Property object, or None if not found
389 
390         Raises:
391             FdtException on error (e.g. invalid prop_offset or device
392             tree format)
393         """
394         pdata = check_err_null(
395                 fdt_get_property_by_offset(self._fdt, prop_offset), quiet)
396         if isinstance(pdata, (int)):
397             return pdata
398         return Property(pdata[0], pdata[1])
399 
400     def getprop(self, nodeoffset, prop_name, quiet=()):
401         """Get a property from a node
402 
403         Args:
404             nodeoffset: Node offset containing property to get
405             prop_name: Name of property to get
406             quiet: Errors to ignore (empty to raise on all errors)
407 
408         Returns:
409             Value of property as a Property object (which can be used as a
410                bytearray/string), or -ve error number. On failure, returns an
411                integer error
412 
413         Raises:
414             FdtError if any error occurs (e.g. the property is not found)
415         """
416         pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name),
417                                quiet)
418         if isinstance(pdata, (int)):
419             return pdata
420         return Property(prop_name, bytearray(pdata[0]))
421 
422     def get_phandle(self, nodeoffset):
423         """Get the phandle of a node
424 
425         Args:
426             nodeoffset: Node offset to check
427 
428         Returns:
429             phandle of node, or 0 if the node has no phandle or another error
430             occurs
431         """
432         return fdt_get_phandle(self._fdt, nodeoffset)
433 
434     def get_alias(self, name):
435         """Get the full path referenced by a given alias
436 
437         Args:
438             name: name of the alias to lookup
439 
440         Returns:
441             Full path to the node for the alias named 'name', if it exists
442             None, if the given alias or the /aliases node does not exist
443         """
444         return fdt_get_alias(self._fdt, name)
445 
446     def get_path(self, nodeoffset, size_hint=1024, quiet=()):
447         """Get the full path of a node
448 
449         Args:
450             nodeoffset: Node offset to check
451             size_hint: Hint for size of returned string
452 
453         Returns:
454             Full path to the node
455 
456         Raises:
457             FdtException if an error occurs
458         """
459         while True:
460             ret, path = fdt_get_path(self._fdt, nodeoffset, size_hint)
461             if ret == -NOSPACE:
462                 size_hint *= 2
463                 continue
464             err = check_err(ret, quiet)
465             if err:
466                 return err
467             return path
468 
469     def parent_offset(self, nodeoffset, quiet=()):
470         """Get the offset of a node's parent
471 
472         Args:
473             nodeoffset: Node offset to check
474             quiet: Errors to ignore (empty to raise on all errors)
475 
476         Returns:
477             The offset of the parent node, if any
478 
479         Raises:
480             FdtException if no parent found or other error occurs
481         """
482         return check_err(fdt_parent_offset(self._fdt, nodeoffset), quiet)
483 
484     def node_offset_by_phandle(self, phandle, quiet=()):
485         """Get the offset of a node with the given phandle
486 
487         Args:
488             phandle: Phandle to search for
489             quiet: Errors to ignore (empty to raise on all errors)
490 
491         Returns:
492             The offset of node with that phandle, if any
493 
494         Raises:
495             FdtException if no node found or other error occurs
496         """
497         return check_err(fdt_node_offset_by_phandle(self._fdt, phandle), quiet)
498 
499 
500 class Fdt(FdtRo):
501     """Device tree class, supporting all operations
502 
503     The Fdt object is created is created from a device tree binary file,
504     e.g. with something like:
505 
506        fdt = Fdt(open("filename.dtb").read())
507 
508     Operations can then be performed using the methods in this class. Each
509     method xxx(args...) corresponds to a libfdt function fdt_xxx(fdt, args...).
510 
511     All methods raise an FdtException if an error occurs. To avoid this
512     behaviour a 'quiet' parameter is provided for some functions. This
513     defaults to empty, but you can pass a list of errors that you expect.
514     If one of these errors occurs, the function will return an error number
515     (e.g. -NOTFOUND).
516     """
517     def __init__(self, data):
518         FdtRo.__init__(self, data)
519 
520     @staticmethod
521     def create_empty_tree(size, quiet=()):
522         """Create an empty device tree ready for use
523 
524         Args:
525             size: Size of device tree in bytes
526 
527         Returns:
528             Fdt object containing the device tree
529         """
530         data = bytearray(size)
531         err = check_err(fdt_create_empty_tree(data, size), quiet)
532         if err:
533             return err
534         return Fdt(data)
535 
536     def resize(self, size, quiet=()):
537         """Move the device tree into a larger or smaller space
538 
539         This creates a new device tree of size @size and moves the existing
540         device tree contents over to that. It can be used to create more space
541         in a device tree. Note that the Fdt object remains the same, but it
542         now has a new bytearray holding the contents.
543 
544         Args:
545             size: Required new size of device tree in bytes
546         """
547         fdt = bytearray(size)
548         err = check_err(fdt_open_into(self._fdt, fdt, size), quiet)
549         if err:
550             return err
551         self._fdt = fdt
552 
553     def pack(self, quiet=()):
554         """Pack the device tree to remove unused space
555 
556         This adjusts the tree in place.
557 
558         Args:
559             quiet: Errors to ignore (empty to raise on all errors)
560 
561         Returns:
562             Error code, or 0 if OK
563 
564         Raises:
565             FdtException if any error occurs
566         """
567         err = check_err(fdt_pack(self._fdt), quiet)
568         if err:
569             return err
570         del self._fdt[self.totalsize():]
571         return err
572 
573     def set_name(self, nodeoffset, name, quiet=()):
574         """Set the name of a node
575 
576         Args:
577             nodeoffset: Node offset of node to update
578             name: New node name (string without \0)
579 
580         Returns:
581             Error code, or 0 if OK
582 
583         Raises:
584             FdtException if no parent found or other error occurs
585         """
586         if chr(0) in name:
587             raise ValueError('Property contains embedded nul characters')
588         return check_err(fdt_set_name(self._fdt, nodeoffset, name), quiet)
589 
590     def setprop(self, nodeoffset, prop_name, val, quiet=()):
591         """Set the value of a property
592 
593         Args:
594             nodeoffset: Node offset containing the property to create/update
595             prop_name: Name of property
596             val: Value to write (string or bytearray)
597             quiet: Errors to ignore (empty to raise on all errors)
598 
599         Returns:
600             Error code, or 0 if OK
601 
602         Raises:
603             FdtException if no parent found or other error occurs
604         """
605         return check_err(fdt_setprop(self._fdt, nodeoffset, prop_name, val,
606                                      len(val)), quiet)
607 
608     def setprop_u32(self, nodeoffset, prop_name, val, quiet=()):
609         """Set the value of a property
610 
611         Args:
612             nodeoffset: Node offset containing the property to create/update
613             prop_name: Name of property
614             val: Value to write (integer)
615             quiet: Errors to ignore (empty to raise on all errors)
616 
617         Returns:
618             Error code, or 0 if OK
619 
620         Raises:
621             FdtException if no parent found or other error occurs
622         """
623         return check_err(fdt_setprop_u32(self._fdt, nodeoffset, prop_name, val),
624                          quiet)
625 
626     def setprop_u64(self, nodeoffset, prop_name, val, quiet=()):
627         """Set the value of a property
628 
629         Args:
630             nodeoffset: Node offset containing the property to create/update
631             prop_name: Name of property
632             val: Value to write (integer)
633             quiet: Errors to ignore (empty to raise on all errors)
634 
635         Returns:
636             Error code, or 0 if OK
637 
638         Raises:
639             FdtException if no parent found or other error occurs
640         """
641         return check_err(fdt_setprop_u64(self._fdt, nodeoffset, prop_name, val),
642                          quiet)
643 
644     def setprop_str(self, nodeoffset, prop_name, val, quiet=()):
645         """Set the string value of a property
646 
647         The property is set to the string, with a nul terminator added
648 
649         Args:
650             nodeoffset: Node offset containing the property to create/update
651             prop_name: Name of property
652             val: Value to write (string without nul terminator). Unicode is
653                 supposed by encoding to UTF-8
654             quiet: Errors to ignore (empty to raise on all errors)
655 
656         Returns:
657             Error code, or 0 if OK
658 
659         Raises:
660             FdtException if no parent found or other error occurs
661         """
662         val = val.encode('utf-8') + b'\0'
663         return check_err(fdt_setprop(self._fdt, nodeoffset, prop_name,
664                                      val, len(val)), quiet)
665 
666     def delprop(self, nodeoffset, prop_name, quiet=()):
667         """Delete a property from a node
668 
669         Args:
670             nodeoffset: Node offset containing property to delete
671             prop_name: Name of property to delete
672             quiet: Errors to ignore (empty to raise on all errors)
673 
674         Returns:
675             Error code, or 0 if OK
676 
677         Raises:
678             FdtError if the property does not exist, or another error occurs
679         """
680         return check_err(fdt_delprop(self._fdt, nodeoffset, prop_name), quiet)
681 
682     def add_subnode(self, parentoffset, name, quiet=()):
683         """Add a new subnode to a node
684 
685         Args:
686             parentoffset: Parent offset to add the subnode to
687             name: Name of node to add
688 
689         Returns:
690             offset of the node created, or negative error code on failure
691 
692         Raises:
693             FdtError if there is not enough space, or another error occurs
694         """
695         return check_err(fdt_add_subnode(self._fdt, parentoffset, name), quiet)
696 
697     def del_node(self, nodeoffset, quiet=()):
698         """Delete a node
699 
700         Args:
701             nodeoffset: Offset of node to delete
702 
703         Returns:
704             Error code, or 0 if OK
705 
706         Raises:
707             FdtError if an error occurs
708         """
709         return check_err(fdt_del_node(self._fdt, nodeoffset), quiet)
710 
711 
712 class Property(bytearray):
713     """Holds a device tree property name and value.
714 
715     This holds a copy of a property taken from the device tree. It does not
716     reference the device tree, so if anything changes in the device tree,
717     a Property object will remain valid.
718 
719     Properties:
720         name: Property name
721         value: Property value as a bytearray
722     """
723     def __init__(self, name, value):
724         bytearray.__init__(self, value)
725         self.name = name
726 
727     def as_cell(self, fmt):
728         return struct.unpack('>' + fmt, self)[0]
729 
730     def as_uint32(self):
731         return self.as_cell('L')
732 
733     def as_int32(self):
734         return self.as_cell('l')
735 
736     def as_uint64(self):
737         return self.as_cell('Q')
738 
739     def as_int64(self):
740         return self.as_cell('q')
741 
742     def as_list(self, fmt):
743         return list(map(lambda x: x[0], struct.iter_unpack('>' + fmt, self)))
744 
745     def as_uint32_list(self):
746         return self.as_list('L')
747 
748     def as_int32_list(self):
749         return self.as_list('l')
750 
751     def as_uint64_list(self):
752         return self.as_list('Q')
753 
754     def as_int64_list(self):
755         return self.as_list('q')
756 
757     def as_str(self):
758         """Unicode is supported by decoding from UTF-8"""
759         if self[-1] != 0:
760             raise ValueError('Property lacks nul termination')
761         if 0 in self[:-1]:
762             raise ValueError('Property contains embedded nul characters')
763         return self[:-1].decode('utf-8')
764 
765     def as_stringlist(self):
766         """Unicode is supported by decoding from UTF-8"""
767         if self[-1] != 0:
768             raise ValueError('Property lacks nul termination')
769         parts = self[:-1].split(b'\x00')
770         return list(map(lambda x: x.decode('utf-8'), parts))
771 
772 
773 class FdtSw(FdtRo):
774     """Software interface to create a device tree from scratch
775 
776     The methods in this class work by adding to an existing 'partial' device
777     tree buffer of a fixed size created by instantiating this class. When the
778     tree is complete, call as_fdt() to obtain a device tree ready to be used.
779 
780     Similarly with nodes, a new node is started with begin_node() and finished
781     with end_node().
782 
783     The context manager functions can be used to make this a bit easier:
784 
785     # First create the device tree with a node and property:
786     sw = FdtSw()
787     sw.finish_reservemap()
788     with sw.add_node(''):
789         with sw.add_node('node'):
790             sw.property_u32('reg', 2)
791     fdt = sw.as_fdt()
792 
793     # Now we can use it as a real device tree
794     fdt.setprop_u32(0, 'reg', 3)
795 
796     The size hint provides a starting size for the space to be used by the
797     device tree. This will be increased automatically as needed as new items
798     are added to the tree.
799     """
800     INC_SIZE = 1024  # Expand size by this much when out of space
801 
802     def __init__(self, size_hint=None):
803         """Create a new FdtSw object
804 
805         Args:
806             size_hint: A hint as to the initial size to use
807 
808         Raises:
809             ValueError if size_hint is negative
810 
811         Returns:
812             FdtSw object on success, else integer error code (if not raising)
813         """
814         if not size_hint:
815             size_hint = self.INC_SIZE
816         fdtsw = bytearray(size_hint)
817         err = check_err(fdt_create(fdtsw, size_hint))
818         if err:
819             return err
820         self._fdt = fdtsw
821 
822     def as_fdt(self):
823         """Convert a FdtSw into an Fdt so it can be accessed as normal
824 
825         Creates a new Fdt object from the work-in-progress device tree. This
826         does not call fdt_finish() on the current object, so it is possible to
827         add more nodes/properties and call as_fdt() again to get an updated
828         tree.
829 
830         Returns:
831             Fdt object allowing access to the newly created device tree
832         """
833         fdtsw = bytearray(self._fdt)
834         check_err(fdt_finish(fdtsw))
835         return Fdt(fdtsw)
836 
837     def check_space(self, val):
838         """Check if we need to add more space to the FDT
839 
840         This should be called with the error code from an operation. If this is
841         -NOSPACE then the FDT will be expanded to have more space, and True will
842         be returned, indicating that the operation needs to be tried again.
843 
844         Args:
845             val: Return value from the operation that was attempted
846 
847         Returns:
848             True if the operation must be retried, else False
849         """
850         if check_err(val, QUIET_NOSPACE) < 0:
851             self.resize(len(self._fdt) + self.INC_SIZE)
852             return True
853         return False
854 
855     def resize(self, size):
856         """Resize the buffer to accommodate a larger tree
857 
858         Args:
859             size: New size of tree
860 
861         Raises:
862             FdtException on any error
863         """
864         fdt = bytearray(size)
865         err = check_err(fdt_resize(self._fdt, fdt, size))
866         self._fdt = fdt
867 
868     def add_reservemap_entry(self, addr, size):
869         """Add a new memory reserve map entry
870 
871         Once finished adding, you must call finish_reservemap().
872 
873         Args:
874             addr: 64-bit start address
875             size: 64-bit size
876 
877         Raises:
878             FdtException on any error
879         """
880         while self.check_space(fdt_add_reservemap_entry(self._fdt, addr,
881                                                         size)):
882             pass
883 
884     def finish_reservemap(self):
885         """Indicate that there are no more reserve map entries to add
886 
887         Raises:
888             FdtException on any error
889         """
890         while self.check_space(fdt_finish_reservemap(self._fdt)):
891             pass
892 
893     def begin_node(self, name):
894         """Begin a new node
895 
896         Use this before adding properties to the node. Then call end_node() to
897         finish it. You can also use the context manager as shown in the FdtSw
898         class comment.
899 
900         Args:
901             name: Name of node to begin
902 
903         Raises:
904             FdtException on any error
905         """
906         while self.check_space(fdt_begin_node(self._fdt, name)):
907             pass
908 
909     def property_string(self, name, string):
910         """Add a property with a string value
911 
912         The string will be nul-terminated when written to the device tree
913 
914         Args:
915             name: Name of property to add
916             string: String value of property
917 
918         Raises:
919             FdtException on any error
920         """
921         while self.check_space(fdt_property_string(self._fdt, name, string)):
922             pass
923 
924     def property_u32(self, name, val):
925         """Add a property with a 32-bit value
926 
927         Write a single-cell value to the device tree
928 
929         Args:
930             name: Name of property to add
931             val: Value of property
932 
933         Raises:
934             FdtException on any error
935         """
936         while self.check_space(fdt_property_u32(self._fdt, name, val)):
937             pass
938 
939     def property_u64(self, name, val):
940         """Add a property with a 64-bit value
941 
942         Write a double-cell value to the device tree in big-endian format
943 
944         Args:
945             name: Name of property to add
946             val: Value of property
947 
948         Raises:
949             FdtException on any error
950         """
951         while self.check_space(fdt_property_u64(self._fdt, name, val)):
952             pass
953 
954     def property_cell(self, name, val):
955         """Add a property with a single-cell value
956 
957         Write a single-cell value to the device tree
958 
959         Args:
960             name: Name of property to add
961             val: Value of property
962             quiet: Errors to ignore (empty to raise on all errors)
963 
964         Raises:
965             FdtException on any error
966         """
967         while self.check_space(fdt_property_cell(self._fdt, name, val)):
968             pass
969 
970     def property(self, name, val):
971         """Add a property
972 
973         Write a new property with the given value to the device tree. The value
974         is taken as is and is not nul-terminated
975 
976         Args:
977             name: Name of property to add
978             val: Value of property (bytes)
979             quiet: Errors to ignore (empty to raise on all errors)
980 
981         Raises:
982             FdtException on any error
983         """
984         while self.check_space(fdt_property_stub(self._fdt, name, val,
985                                                  len(val))):
986             pass
987 
988     def end_node(self):
989         """End a node
990 
991         Use this after adding properties to a node to close it off. You can also
992         use the context manager as shown in the FdtSw class comment.
993 
994         Args:
995             quiet: Errors to ignore (empty to raise on all errors)
996 
997         Raises:
998             FdtException on any error
999         """
1000         while self.check_space(fdt_end_node(self._fdt)):
1001             pass
1002 
1003     def add_node(self, name):
1004         """Create a new context for adding a node
1005 
1006         When used in a 'with' clause this starts a new node and finishes it
1007         afterward.
1008 
1009         Args:
1010             name: Name of node to add
1011         """
1012         return NodeAdder(self, name)
1013 
1014 
1015 class NodeAdder():
1016     """Class to provide a node context
1017 
1018     This allows you to add nodes in a more natural way:
1019 
1020         with fdtsw.add_node('name'):
1021             fdtsw.property_string('test', 'value')
1022 
1023     The node is automatically completed with a call to end_node() when the
1024     context exits.
1025     """
1026     def __init__(self, fdtsw, name):
1027         self._fdt = fdtsw
1028         self._name = name
1029 
1030     def __enter__(self):
1031         self._fdt.begin_node(self._name)
1032 
1033     def __exit__(self, type, value, traceback):
1034         self._fdt.end_node()
1035 %}
1036 
1037 %rename(fdt_property) fdt_property_func;
1038 
1039 %immutable fdt_property::data;
1040 %immutable fdt_node_header::name;
1041 
1042 /*
1043  * fdt32_t is a big-endian 32-bit value defined to uint32_t in libfdt_env.h
1044  * so use the same type here.
1045  */
1046 typedef uint32_t fdt32_t;
1047 
1048 %include "fdt.h"
1049 
1050 %include "typemaps.i"
1051 
1052 /* Most functions don't change the device tree, so use a const void * */
1053 %typemap(in) (const void *)(const void *fdt) {
1054 	if (!PyByteArray_Check($input)) {
1055 		SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
1056 			"', argument " "$argnum"" of type '" "$type""'");
1057 	}
1058 	$1 = (void *)PyByteArray_AsString($input);
1059         fdt = $1;
1060         (void)fdt; /* avoid unused variable warning */
1061 }
1062 
1063 /* Some functions do change the device tree, so use void * */
1064 %typemap(in) (void *)(const void *fdt) {
1065 	if (!PyByteArray_Check($input)) {
1066 		SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
1067 			"', argument " "$argnum"" of type '" "$type""'");
1068 	}
1069 	$1 = PyByteArray_AsString($input);
1070         fdt = $1;
1071         (void)fdt; /* avoid unused variable warning */
1072 }
1073 
1074 /* typemap used for fdt_get_property_by_offset() */
1075 %typemap(out) (struct fdt_property *) {
1076 	PyObject *buff;
1077 
1078 	if ($1) {
1079 		resultobj = PyString_FromString(
1080 			fdt_string(fdt1, fdt32_to_cpu($1->nameoff)));
1081 		buff = PyByteArray_FromStringAndSize(
1082 			(const char *)($1 + 1), fdt32_to_cpu($1->len));
1083 		resultobj = SWIG_Python_AppendOutput(resultobj, buff);
1084 	}
1085 }
1086 
1087 %apply int *OUTPUT { int *lenp };
1088 
1089 /* typemap used for fdt_getprop() */
1090 %typemap(out) (const void *) {
1091 	if (!$1) {
1092 		$result = Py_None;
1093 		Py_INCREF($result);
1094 	} else {
1095         %#if PY_VERSION_HEX >= 0x03000000
1096             $result = Py_BuildValue("y#", $1, (Py_ssize_t)*arg4);
1097         %#else
1098             $result = Py_BuildValue("s#", $1, (Py_ssize_t)*arg4);
1099         %#endif
1100     }
1101 }
1102 
1103 /* typemap used for fdt_setprop() */
1104 %typemap(in) (const void *val) {
1105     %#if PY_VERSION_HEX >= 0x03000000
1106         if (!PyBytes_Check($input)) {
1107             SWIG_exception_fail(SWIG_TypeError, "bytes expected in method '" "$symname"
1108                 "', argument " "$argnum"" of type '" "$type""'");
1109         }
1110         $1 = PyBytes_AsString($input);
1111     %#else
1112         $1 = PyString_AsString($input);   /* char *str */
1113     %#endif
1114 }
1115 
1116 /* typemaps used for fdt_next_node() */
1117 %typemap(in, numinputs=1) int *depth (int depth) {
1118    depth = (int) PyInt_AsLong($input);
1119    $1 = &depth;
1120 }
1121 
1122 %typemap(argout) int *depth {
1123         PyObject *val = Py_BuildValue("i", *arg$argnum);
1124         resultobj = SWIG_Python_AppendOutput(resultobj, val);
1125 }
1126 
1127 %apply int *depth { int *depth };
1128 
1129 /* typemaps for fdt_get_mem_rsv */
1130 %typemap(in, numinputs=0) uint64_t * (uint64_t temp) {
1131    $1 = &temp;
1132 }
1133 
1134 %typemap(argout) uint64_t * {
1135         PyObject *val = PyLong_FromUnsignedLongLong(*arg$argnum);
1136         if (!result) {
1137            if (PyTuple_GET_SIZE(resultobj) == 0)
1138               resultobj = val;
1139            else
1140               resultobj = SWIG_Python_AppendOutput(resultobj, val);
1141         }
1142 }
1143 
1144 %include "cstring.i"
1145 
1146 %cstring_output_maxsize(char *buf, int buflen);
1147 int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen);
1148 
1149 /* We have both struct fdt_property and a function fdt_property() */
1150 %warnfilter(302) fdt_property;
1151 
1152 /* These are macros in the header so have to be redefined here */
1153 uint32_t fdt_magic(const void *fdt);
1154 uint32_t fdt_totalsize(const void *fdt);
1155 uint32_t fdt_off_dt_struct(const void *fdt);
1156 uint32_t fdt_off_dt_strings(const void *fdt);
1157 uint32_t fdt_off_mem_rsvmap(const void *fdt);
1158 uint32_t fdt_version(const void *fdt);
1159 uint32_t fdt_last_comp_version(const void *fdt);
1160 uint32_t fdt_boot_cpuid_phys(const void *fdt);
1161 uint32_t fdt_size_dt_strings(const void *fdt);
1162 uint32_t fdt_size_dt_struct(const void *fdt);
1163 
1164 int fdt_property_string(void *fdt, const char *name, const char *val);
1165 int fdt_property_cell(void *fdt, const char *name, uint32_t val);
1166 
1167 /*
1168  * This function has a stub since the name fdt_property is used for both a
1169   * function and a struct, which confuses SWIG.
1170  */
1171 int fdt_property_stub(void *fdt, const char *name, const void *val, int len);
1172 
1173 %include <libfdt.h>
1174