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