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