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