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    def get_property(self, nodeoffset, prop_name, quiet=()):
402        """Obtains a property by name
403
404        Args:
405            nodeoffset: Offset to the node to check
406            prop_name: Name of property to get
407            quiet: Errors to ignore (empty to raise on all errors)
408
409        Returns:
410            Property object, or None if not found
411
412        Raises:
413            FdtException on error (e.g. invalid prop_offset or device
414            tree format)
415        """
416        pdata = check_err_null(
417                fdt_get_property(self._fdt, nodeoffset, prop_name), quiet)
418        if isinstance(pdata, (int)):
419            return pdata
420        return Property(pdata[0], pdata[1])
421
422    @staticmethod
423    def create_empty_tree(size, quiet=()):
424        """Create an empty device tree ready for use
425
426        Args:
427            size: Size of device tree in bytes
428
429        Returns:
430            Fdt object containing the device tree
431        """
432        data = bytearray(size)
433        err = check_err(fdt_create_empty_tree(data, size), quiet)
434        if err:
435            return err
436        return Fdt(data)
437
438    def open_into(self, size, quiet=()):
439        """Move the device tree into a larger or smaller space
440
441        This creates a new device tree of size @size and moves the existing
442        device tree contents over to that. It can be used to create more space
443        in a device tree.
444
445        Args:
446            size: Required new size of device tree in bytes
447        """
448        fdt = bytearray(size)
449        fdt[:len(self._fdt)] = self._fdt
450        err = check_err(fdt_open_into(self._fdt, fdt, size), quiet)
451        if err:
452            return err
453        self._fdt = fdt
454
455    def pack(self, quiet=()):
456        """Pack the device tree to remove unused space
457
458        This adjusts the tree in place.
459
460        Args:
461            quiet: Errors to ignore (empty to raise on all errors)
462
463        Raises:
464            FdtException if any error occurs
465        """
466        err = check_err(fdt_pack(self._fdt), quiet)
467        if err:
468            return err
469        del self._fdt[self.totalsize():]
470        return err
471
472    def getprop(self, nodeoffset, prop_name, quiet=()):
473        """Get a property from a node
474
475        Args:
476            nodeoffset: Node offset containing property to get
477            prop_name: Name of property to get
478            quiet: Errors to ignore (empty to raise on all errors)
479
480        Returns:
481            Value of property as a string, or -ve error number
482
483        Raises:
484            FdtError if any error occurs (e.g. the property is not found)
485        """
486        pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name),
487                               quiet)
488        if isinstance(pdata, (int)):
489            return pdata
490        return str(pdata[0])
491
492    def getprop_obj(self, nodeoffset, prop_name, quiet=()):
493        """Get a property from a node as a Property object
494
495        Args:
496            nodeoffset: Node offset containing property to get
497            prop_name: Name of property to get
498            quiet: Errors to ignore (empty to raise on all errors)
499
500        Returns:
501            Property object, or None if not found
502
503        Raises:
504            FdtError if any error occurs (e.g. the property is not found)
505        """
506        pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name),
507                               quiet)
508        if isinstance(pdata, (int)):
509            return None
510        return Property(prop_name, bytearray(pdata[0]))
511
512    def get_phandle(self, nodeoffset):
513        """Get the phandle of a node
514
515        Args:
516            nodeoffset: Node offset to check
517
518        Returns:
519            phandle of node, or 0 if the node has no phandle or another error
520            occurs
521        """
522        return fdt_get_phandle(self._fdt, nodeoffset)
523
524    def parent_offset(self, nodeoffset, quiet=()):
525        """Get the offset of a node's parent
526
527        Args:
528            nodeoffset: Node offset to check
529            quiet: Errors to ignore (empty to raise on all errors)
530
531        Returns:
532            The offset of the parent node, if any
533
534        Raises:
535            FdtException if no parent found or other error occurs
536        """
537        return check_err(fdt_parent_offset(self._fdt, nodeoffset), quiet)
538
539    def set_name(self, nodeoffset, name, quiet=()):
540        """Set the name of a node
541
542        Args:
543            nodeoffset: Node offset of node to update
544            name: New node name
545
546        Returns:
547            Error code, or 0 if OK
548
549        Raises:
550            FdtException if no parent found or other error occurs
551        """
552        return check_err(fdt_set_name(self._fdt, nodeoffset, name), quiet)
553
554    def setprop(self, nodeoffset, prop_name, val, quiet=()):
555        """Set the value of a property
556
557        Args:
558            nodeoffset: Node offset containing the property to create/update
559            prop_name: Name of property
560            val: Value to write (string or bytearray)
561            quiet: Errors to ignore (empty to raise on all errors)
562
563        Returns:
564            Error code, or 0 if OK
565
566        Raises:
567            FdtException if no parent found or other error occurs
568        """
569        return check_err(fdt_setprop(self._fdt, nodeoffset, prop_name, val,
570                                     len(val)), quiet)
571
572    def setprop_u32(self, nodeoffset, prop_name, val, quiet=()):
573        """Set the value of a property
574
575        Args:
576            nodeoffset: Node offset containing the property to create/update
577            prop_name: Name of property
578            val: Value to write (integer)
579            quiet: Errors to ignore (empty to raise on all errors)
580
581        Returns:
582            Error code, or 0 if OK
583
584        Raises:
585            FdtException if no parent found or other error occurs
586        """
587        return check_err(fdt_setprop_u32(self._fdt, nodeoffset, prop_name, val),
588                         quiet)
589
590    def setprop_u64(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 (integer)
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_u64(self._fdt, nodeoffset, prop_name, val),
606                         quiet)
607
608    def setprop_str(self, nodeoffset, prop_name, val, quiet=()):
609        """Set the string value of a property
610
611        The property is set to the string, with a nul terminator added
612
613        Args:
614            nodeoffset: Node offset containing the property to create/update
615            prop_name: Name of property
616            val: Value to write (string without nul terminator)
617            quiet: Errors to ignore (empty to raise on all errors)
618
619        Returns:
620            Error code, or 0 if OK
621
622        Raises:
623            FdtException if no parent found or other error occurs
624        """
625        val += '\0'
626        return check_err(fdt_setprop(self._fdt, nodeoffset, prop_name,
627                                     val, len(val)), quiet)
628
629    def delprop(self, nodeoffset, prop_name):
630        """Delete a property from a node
631
632        Args:
633            nodeoffset: Node offset containing property to delete
634            prop_name: Name of property to delete
635
636        Raises:
637            FdtError if the property does not exist, or another error occurs
638        """
639        return check_err(fdt_delprop(self._fdt, nodeoffset, prop_name))
640
641    def node_offset_by_phandle(self, phandle, quiet=()):
642        """Get the offset of a node with the given phandle
643
644        Args:
645            phandle: Phandle to search for
646            quiet: Errors to ignore (empty to raise on all errors)
647
648        Returns:
649            The offset of node with that phandle, if any
650
651        Raises:
652            FdtException if no node found or other error occurs
653        """
654        return check_err(fdt_node_offset_by_phandle(self._fdt, phandle), quiet)
655
656    def del_node(self, nodeoffset):
657        """Delete a node
658
659        Args:
660            nodeoffset: Node offset containing property to delete
661
662        Raises:
663            FdtError if the node does not exist, or another error occurs
664        """
665        return check_err(fdt_del_node(self._fdt, nodeoffset))
666
667
668class Property(bytearray):
669    """Holds a device tree property name and value.
670
671    This holds a copy of a property taken from the device tree. It does not
672    reference the device tree, so if anything changes in the device tree,
673    a Property object will remain valid.
674
675    Properties:
676        name: Property name
677        value: Property value as a bytearray
678    """
679    def __init__(self, name, value):
680        bytearray.__init__(self, value)
681        self.name = name
682
683    def as_cell(self, fmt):
684        return struct.unpack('>' + fmt, self)[0]
685
686    def as_uint32(self):
687        return self.as_cell('L')
688
689    def as_int32(self):
690        return self.as_cell('l')
691
692    def as_uint64(self):
693        return self.as_cell('Q')
694
695    def as_int64(self):
696        return self.as_cell('q')
697
698    def as_str(self):
699        return self[:-1]
700
701
702class FdtSw(object):
703    """Software interface to create a device tree from scratch
704
705    The methods in this class work by adding to an existing 'partial' device
706    tree buffer of a fixed size created by instantiating this class. When the
707    tree is complete, call finish() to complete the device tree so that it can
708    be used.
709
710    Similarly with nodes, a new node is started with begin_node() and finished
711    with end_node().
712
713    The context manager functions can be used to make this a bit easier:
714
715    # First create the device tree with a node and property:
716    with FdtSw(small_size) as sw:
717        with sw.AddNode('node'):
718            sw.property_u32('reg', 2)
719    fdt = sw.AsFdt()
720
721    # Now we can use it as a real device tree
722    fdt.setprop_u32(0, 'reg', 3)
723    """
724    def __init__(self, size, quiet=()):
725        fdtrw = bytearray(size)
726        err = check_err(fdt_create(fdtrw, size))
727        if err:
728            return err
729        self._fdtrw = fdtrw
730
731    def __enter__(self):
732        """Contact manager to use to create a device tree via software"""
733        return self
734
735    def __exit__(self, type, value, traceback):
736        check_err(fdt_finish(self._fdtrw))
737
738    def AsFdt(self):
739        """Convert a FdtSw into an Fdt so it can be accessed as normal
740
741        Note that finish() must be called before this function will work. If
742        you are using the context manager (see 'with' code in the FdtSw class
743        comment) then this will happen automatically.
744
745        Returns:
746            Fdt object allowing access to the newly created device tree
747        """
748        return Fdt(self._fdtrw)
749
750    def resize(self, size, quiet=()):
751        """Resize the buffer to accommodate a larger tree
752
753        Args:
754            size: New size of tree
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        fdt = bytearray(size)
761        fdt[:len(self._fdtrw)] = self._fdtrw
762        err = check_err(fdt_resize(self._fdtrw, fdt, size), quiet)
763        if err:
764            return err
765        self._fdtrw = fdt
766
767    def add_reservemap_entry(self, addr, size, quiet=()):
768        """Add a new memory reserve map entry
769
770        Once finished adding, you must call finish_reservemap().
771
772        Args:
773            addr: 64-bit start address
774            size: 64-bit size
775            quiet: Errors to ignore (empty to raise on all errors)
776
777        Raises:
778            FdtException if no node found or other error occurs
779        """
780        return check_err(fdt_add_reservemap_entry(self._fdtrw, addr, size),
781                         quiet)
782
783    def finish_reservemap(self, quiet=()):
784        """Indicate that there are no more reserve map entries to add
785
786        Args:
787            quiet: Errors to ignore (empty to raise on all errors)
788
789        Raises:
790            FdtException if no node found or other error occurs
791        """
792        return check_err(fdt_finish_reservemap(self._fdtrw), quiet)
793
794    def begin_node(self, name, quiet=()):
795        """Begin a new node
796
797        Use this before adding properties to the node. Then call end_node() to
798        finish it. You can also use the context manager as shown in the FdtSw
799        class comment.
800
801        Args:
802            name: Name of node to begin
803            quiet: Errors to ignore (empty to raise on all errors)
804
805        Raises:
806            FdtException if no node found or other error occurs
807        """
808        return check_err(fdt_begin_node(self._fdtrw, name), quiet)
809
810    def property_string(self, name, string, quiet=()):
811        """Add a property with a string value
812
813        The string will be nul-terminated when written to the device tree
814
815        Args:
816            name: Name of property to add
817            string: String value of property
818            quiet: Errors to ignore (empty to raise on all errors)
819
820        Raises:
821            FdtException if no node found or other error occurs
822        """
823        return check_err(fdt_property_string(self._fdtrw, name, string), quiet)
824
825    def property_u32(self, name, val, quiet=()):
826        """Add a property with a 32-bit value
827
828        Write a single-cell value to the device tree
829
830        Args:
831            name: Name of property to add
832            val: Value of property
833            quiet: Errors to ignore (empty to raise on all errors)
834
835        Raises:
836            FdtException if no node found or other error occurs
837        """
838        return check_err(fdt_property_u32(self._fdtrw, name, val), quiet)
839
840    def property_u64(self, name, val, quiet=()):
841        """Add a property with a 64-bit value
842
843        Write a double-cell value to the device tree in big-endian format
844
845        Args:
846            name: Name of property to add
847            val: Value of property
848            quiet: Errors to ignore (empty to raise on all errors)
849
850        Raises:
851            FdtException if no node found or other error occurs
852        """
853        return check_err(fdt_property_u64(self._fdtrw, name, val), quiet)
854
855    def property_cell(self, name, val, quiet=()):
856        """Add a property with a single-cell value
857
858        Write a single-cell value to the device tree
859
860        Args:
861            name: Name of property to add
862            val: Value of property
863            quiet: Errors to ignore (empty to raise on all errors)
864
865        Raises:
866            FdtException if no node found or other error occurs
867        """
868        return check_err(fdt_property_cell(self._fdtrw, name, val), quiet)
869
870    def property(self, name, val, quiet=()):
871        """Add a property
872
873        Write a new property with the given value to the device tree. The value
874        is taken as is and is not nul-terminated
875
876        Args:
877            name: Name of property to add
878            val: Value of property
879            quiet: Errors to ignore (empty to raise on all errors)
880
881        Raises:
882            FdtException if no node found or other error occurs
883        """
884        return check_err(_fdt_property(self._fdtrw, name, val, len(val)), quiet)
885
886    def end_node(self, quiet=()):
887        """End a node
888
889        Use this after adding properties to a node to close it off. You can also
890        use the context manager as shown in the FdtSw class comment.
891
892        Args:
893            quiet: Errors to ignore (empty to raise on all errors)
894
895        Raises:
896            FdtException if no node found or other error occurs
897        """
898        return check_err(fdt_end_node(self._fdtrw), quiet)
899
900    def finish(self, quiet=()):
901        """Finish writing the device tree
902
903        This closes off the device tree ready for use
904
905        Args:
906            quiet: Errors to ignore (empty to raise on all errors)
907
908        Raises:
909            FdtException if no node found or other error occurs
910        """
911        return check_err(fdt_finish(self._fdtrw), quiet)
912
913    def AddNode(self, name):
914        """Create a new context for adding a node
915
916        When used in a 'with' clause this starts a new node and finishes it
917        afterward.
918
919        Args:
920            name: Name of node to add
921        """
922        return NodeAdder(self._fdtrw, name)
923
924
925class NodeAdder():
926    """Class to provide a node context
927
928    This allows you to add nodes in a more natural way:
929
930        with fdtsw.AddNode('name'):
931            fdtsw.property_string('test', 'value')
932
933    The node is automatically completed with a call to end_node() when the
934    context exits.
935    """
936    def __init__(self, fdt, name):
937        self._fdt = fdt
938        self._name = name
939
940    def __enter__(self):
941        check_err(fdt_begin_node(self._fdt, self._name))
942
943    def __exit__(self, type, value, traceback):
944        check_err(fdt_end_node(self._fdt))
945%}
946
947%rename(fdt_property) fdt_property_func;
948
949typedef int fdt32_t;
950
951%include "libfdt/fdt.h"
952
953%include "typemaps.i"
954
955/* Most functions don't change the device tree, so use a const void * */
956%typemap(in) (const void *)(const void *fdt) {
957	if (!PyByteArray_Check($input)) {
958		SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
959			"', argument " "$argnum"" of type '" "$type""'");
960	}
961	$1 = (void *)PyByteArray_AsString($input);
962        fdt = $1;
963        fdt = fdt; /* avoid unused variable warning */
964}
965
966/* Some functions do change the device tree, so use void * */
967%typemap(in) (void *)(const void *fdt) {
968	if (!PyByteArray_Check($input)) {
969		SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
970			"', argument " "$argnum"" of type '" "$type""'");
971	}
972	$1 = PyByteArray_AsString($input);
973        fdt = $1;
974        fdt = fdt; /* avoid unused variable warning */
975}
976
977/* typemap used for fdt_get_property_by_offset() */
978%typemap(out) (struct fdt_property *) {
979	PyObject *buff;
980
981	if ($1) {
982		resultobj = PyString_FromString(
983			fdt_string(fdt1, fdt32_to_cpu($1->nameoff)));
984		buff = PyByteArray_FromStringAndSize(
985			(const char *)($1 + 1), fdt32_to_cpu($1->len));
986		resultobj = SWIG_Python_AppendOutput(resultobj, buff);
987	}
988}
989
990%apply int *OUTPUT { int *lenp };
991
992/* typemap used for fdt_getprop() */
993%typemap(out) (const void *) {
994	if (!$1)
995		$result = Py_None;
996	else
997		$result = Py_BuildValue("s#", $1, *arg4);
998}
999
1000/* typemap used for fdt_setprop() */
1001%typemap(in) (const void *val) {
1002    $1 = PyString_AsString($input);   /* char *str */
1003}
1004
1005/* typemap used for fdt_add_reservemap_entry() */
1006%typemap(in) uint64_t {
1007   $1 = PyLong_AsUnsignedLong($input);
1008}
1009
1010/* typemaps used for fdt_next_node() */
1011%typemap(in, numinputs=1) int *depth (int depth) {
1012   depth = (int) PyInt_AsLong($input);
1013   $1 = &depth;
1014}
1015
1016%typemap(argout) int *depth {
1017        PyObject *val = Py_BuildValue("i", *arg$argnum);
1018        resultobj = SWIG_Python_AppendOutput(resultobj, val);
1019}
1020
1021%apply int *depth { int *depth };
1022
1023/* typemaps for fdt_get_mem_rsv */
1024%typemap(in, numinputs=0) uint64_t * (uint64_t temp) {
1025   $1 = &temp;
1026}
1027
1028%typemap(argout) uint64_t * {
1029        PyObject *val = PyLong_FromUnsignedLong(*arg$argnum);
1030        if (!result) {
1031           if (PyTuple_GET_SIZE(resultobj) == 0)
1032              resultobj = val;
1033           else
1034              resultobj = SWIG_Python_AppendOutput(resultobj, val);
1035        }
1036}
1037
1038/* We have both struct fdt_property and a function fdt_property() */
1039%warnfilter(302) fdt_property;
1040
1041/* These are macros in the header so have to be redefined here */
1042int fdt_magic(const void *fdt);
1043int fdt_totalsize(const void *fdt);
1044int fdt_off_dt_struct(const void *fdt);
1045int fdt_off_dt_strings(const void *fdt);
1046int fdt_off_mem_rsvmap(const void *fdt);
1047int fdt_version(const void *fdt);
1048int fdt_last_comp_version(const void *fdt);
1049int fdt_boot_cpuid_phys(const void *fdt);
1050int fdt_size_dt_strings(const void *fdt);
1051int fdt_size_dt_struct(const void *fdt);
1052int fdt_property_string(void *fdt, const char *name, const char *val);
1053int fdt_property_cell(void *fdt, const char *name, uint32_t val);
1054
1055/*
1056 * This function has a stub since the name fdt_property is used for both a
1057  * function and a struct, which confuses SWIG.
1058 */
1059int _fdt_property(void *fdt, const char *name, const char *val, int len);
1060
1061%include <../libfdt/libfdt.h>
1062