1// SPDX-License-Identifier: (GPL-2.0-or-later 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 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, 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 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        check_err(fdt_finish(fdtsw))
790        return Fdt(fdtsw)
791
792    def check_space(self, val):
793        """Check if we need to add more space to the FDT
794
795        This should be called with the error code from an operation. If this is
796        -NOSPACE then the FDT will be expanded to have more space, and True will
797        be returned, indicating that the operation needs to be tried again.
798
799        Args:
800            val: Return value from the operation that was attempted
801
802        Returns:
803            True if the operation must be retried, else False
804        """
805        if check_err(val, QUIET_NOSPACE) < 0:
806            self.resize(len(self._fdt) + self.INC_SIZE)
807            return True
808        return False
809
810    def resize(self, size):
811        """Resize the buffer to accommodate a larger tree
812
813        Args:
814            size: New size of tree
815
816        Raises:
817            FdtException on any error
818        """
819        fdt = bytearray(size)
820        err = check_err(fdt_resize(self._fdt, fdt, size))
821        self._fdt = fdt
822
823    def add_reservemap_entry(self, addr, size):
824        """Add a new memory reserve map entry
825
826        Once finished adding, you must call finish_reservemap().
827
828        Args:
829            addr: 64-bit start address
830            size: 64-bit size
831
832        Raises:
833            FdtException on any error
834        """
835        while self.check_space(fdt_add_reservemap_entry(self._fdt, addr,
836                                                        size)):
837            pass
838
839    def finish_reservemap(self):
840        """Indicate that there are no more reserve map entries to add
841
842        Raises:
843            FdtException on any error
844        """
845        while self.check_space(fdt_finish_reservemap(self._fdt)):
846            pass
847
848    def begin_node(self, name):
849        """Begin a new node
850
851        Use this before adding properties to the node. Then call end_node() to
852        finish it. You can also use the context manager as shown in the FdtSw
853        class comment.
854
855        Args:
856            name: Name of node to begin
857
858        Raises:
859            FdtException on any error
860        """
861        while self.check_space(fdt_begin_node(self._fdt, name)):
862            pass
863
864    def property_string(self, name, string):
865        """Add a property with a string value
866
867        The string will be nul-terminated when written to the device tree
868
869        Args:
870            name: Name of property to add
871            string: String value of property
872
873        Raises:
874            FdtException on any error
875        """
876        while self.check_space(fdt_property_string(self._fdt, name, string)):
877            pass
878
879    def property_u32(self, name, val):
880        """Add a property with a 32-bit value
881
882        Write a single-cell value to the device tree
883
884        Args:
885            name: Name of property to add
886            val: Value of property
887
888        Raises:
889            FdtException on any error
890        """
891        while self.check_space(fdt_property_u32(self._fdt, name, val)):
892            pass
893
894    def property_u64(self, name, val):
895        """Add a property with a 64-bit value
896
897        Write a double-cell value to the device tree in big-endian format
898
899        Args:
900            name: Name of property to add
901            val: Value of property
902
903        Raises:
904            FdtException on any error
905        """
906        while self.check_space(fdt_property_u64(self._fdt, name, val)):
907            pass
908
909    def property_cell(self, name, val):
910        """Add a property with a single-cell value
911
912        Write a single-cell value to the device tree
913
914        Args:
915            name: Name of property to add
916            val: Value of property
917            quiet: Errors to ignore (empty to raise on all errors)
918
919        Raises:
920            FdtException on any error
921        """
922        while self.check_space(fdt_property_cell(self._fdt, name, val)):
923            pass
924
925    def property(self, name, val):
926        """Add a property
927
928        Write a new property with the given value to the device tree. The value
929        is taken as is and is not nul-terminated
930
931        Args:
932            name: Name of property to add
933            val: Value of property
934            quiet: Errors to ignore (empty to raise on all errors)
935
936        Raises:
937            FdtException on any error
938        """
939        while self.check_space(fdt_property_stub(self._fdt, name, val,
940                                                 len(val))):
941            pass
942
943    def end_node(self):
944        """End a node
945
946        Use this after adding properties to a node to close it off. You can also
947        use the context manager as shown in the FdtSw class comment.
948
949        Args:
950            quiet: Errors to ignore (empty to raise on all errors)
951
952        Raises:
953            FdtException on any error
954        """
955        while self.check_space(fdt_end_node(self._fdt)):
956            pass
957
958    def add_node(self, name):
959        """Create a new context for adding a node
960
961        When used in a 'with' clause this starts a new node and finishes it
962        afterward.
963
964        Args:
965            name: Name of node to add
966        """
967        return NodeAdder(self, name)
968
969
970class NodeAdder():
971    """Class to provide a node context
972
973    This allows you to add nodes in a more natural way:
974
975        with fdtsw.add_node('name'):
976            fdtsw.property_string('test', 'value')
977
978    The node is automatically completed with a call to end_node() when the
979    context exits.
980    """
981    def __init__(self, fdtsw, name):
982        self._fdt = fdtsw
983        self._name = name
984
985    def __enter__(self):
986        self._fdt.begin_node(self._name)
987
988    def __exit__(self, type, value, traceback):
989        self._fdt.end_node()
990%}
991
992%rename(fdt_property) fdt_property_func;
993
994/*
995 * fdt32_t is a big-endian 32-bit value defined to uint32_t in libfdt_env.h
996 * so use the same type here.
997 */
998typedef uint32_t fdt32_t;
999
1000%include "fdt.h"
1001
1002%include "typemaps.i"
1003
1004/* Most functions don't change the device tree, so use a const void * */
1005%typemap(in) (const void *)(const void *fdt) {
1006	if (!PyByteArray_Check($input)) {
1007		SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
1008			"', argument " "$argnum"" of type '" "$type""'");
1009	}
1010	$1 = (void *)PyByteArray_AsString($input);
1011        fdt = $1;
1012        fdt = fdt; /* avoid unused variable warning */
1013}
1014
1015/* Some functions do change the device tree, so use void * */
1016%typemap(in) (void *)(const void *fdt) {
1017	if (!PyByteArray_Check($input)) {
1018		SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
1019			"', argument " "$argnum"" of type '" "$type""'");
1020	}
1021	$1 = PyByteArray_AsString($input);
1022        fdt = $1;
1023        fdt = fdt; /* avoid unused variable warning */
1024}
1025
1026/* typemap used for fdt_get_property_by_offset() */
1027%typemap(out) (struct fdt_property *) {
1028	PyObject *buff;
1029
1030	if ($1) {
1031		resultobj = PyString_FromString(
1032			fdt_string(fdt1, fdt32_to_cpu($1->nameoff)));
1033		buff = PyByteArray_FromStringAndSize(
1034			(const char *)($1 + 1), fdt32_to_cpu($1->len));
1035		resultobj = SWIG_Python_AppendOutput(resultobj, buff);
1036	}
1037}
1038
1039%apply int *OUTPUT { int *lenp };
1040
1041/* typemap used for fdt_getprop() */
1042%typemap(out) (const void *) {
1043	if (!$1)
1044		$result = Py_None;
1045	else
1046        %#if PY_VERSION_HEX >= 0x03000000
1047            $result = Py_BuildValue("y#", $1, *arg4);
1048        %#else
1049            $result = Py_BuildValue("s#", $1, *arg4);
1050        %#endif
1051}
1052
1053/* typemap used for fdt_setprop() */
1054%typemap(in) (const void *val) {
1055    %#if PY_VERSION_HEX >= 0x03000000
1056        if (!PyBytes_Check($input)) {
1057            SWIG_exception_fail(SWIG_TypeError, "bytes expected in method '" "$symname"
1058                "', argument " "$argnum"" of type '" "$type""'");
1059        }
1060        $1 = PyBytes_AsString($input);
1061    %#else
1062        $1 = PyString_AsString($input);   /* char *str */
1063    %#endif
1064}
1065
1066/* typemaps used for fdt_next_node() */
1067%typemap(in, numinputs=1) int *depth (int depth) {
1068   depth = (int) PyInt_AsLong($input);
1069   $1 = &depth;
1070}
1071
1072%typemap(argout) int *depth {
1073        PyObject *val = Py_BuildValue("i", *arg$argnum);
1074        resultobj = SWIG_Python_AppendOutput(resultobj, val);
1075}
1076
1077%apply int *depth { int *depth };
1078
1079/* typemaps for fdt_get_mem_rsv */
1080%typemap(in, numinputs=0) uint64_t * (uint64_t temp) {
1081   $1 = &temp;
1082}
1083
1084%typemap(argout) uint64_t * {
1085        PyObject *val = PyLong_FromUnsignedLongLong(*arg$argnum);
1086        if (!result) {
1087           if (PyTuple_GET_SIZE(resultobj) == 0)
1088              resultobj = val;
1089           else
1090              resultobj = SWIG_Python_AppendOutput(resultobj, val);
1091        }
1092}
1093
1094/* We have both struct fdt_property and a function fdt_property() */
1095%warnfilter(302) fdt_property;
1096
1097/* These are macros in the header so have to be redefined here */
1098uint32_t fdt_magic(const void *fdt);
1099uint32_t fdt_totalsize(const void *fdt);
1100uint32_t fdt_off_dt_struct(const void *fdt);
1101uint32_t fdt_off_dt_strings(const void *fdt);
1102uint32_t fdt_off_mem_rsvmap(const void *fdt);
1103uint32_t fdt_version(const void *fdt);
1104uint32_t fdt_last_comp_version(const void *fdt);
1105uint32_t fdt_boot_cpuid_phys(const void *fdt);
1106uint32_t fdt_size_dt_strings(const void *fdt);
1107uint32_t fdt_size_dt_struct(const void *fdt);
1108
1109int fdt_property_string(void *fdt, const char *name, const char *val);
1110int fdt_property_cell(void *fdt, const char *name, uint32_t val);
1111
1112/*
1113 * This function has a stub since the name fdt_property is used for both a
1114  * function and a struct, which confuses SWIG.
1115 */
1116int fdt_property_stub(void *fdt, const char *name, const char *val, int len);
1117
1118%include <libfdt.h>
1119