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