Home | History | Annotate | Line # | Download | only in pylibfdt
libfdt.i revision 1.1
      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 (at) 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  */
     21 static 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 
     31 import 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.
     57 QUIET_NOTFOUND = (NOTFOUND,)
     58 QUIET_NOSPACE = (NOSPACE,)
     59 
     60 
     61 class 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 
     69 def 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 
     80 def 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 
    100 def 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 
    124 class 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 
    477 class 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 
    689 class 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 
    728 class 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 
    970 class 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  */
    998 typedef 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 */
   1098 uint32_t fdt_magic(const void *fdt);
   1099 uint32_t fdt_totalsize(const void *fdt);
   1100 uint32_t fdt_off_dt_struct(const void *fdt);
   1101 uint32_t fdt_off_dt_strings(const void *fdt);
   1102 uint32_t fdt_off_mem_rsvmap(const void *fdt);
   1103 uint32_t fdt_version(const void *fdt);
   1104 uint32_t fdt_last_comp_version(const void *fdt);
   1105 uint32_t fdt_boot_cpuid_phys(const void *fdt);
   1106 uint32_t fdt_size_dt_strings(const void *fdt);
   1107 uint32_t fdt_size_dt_struct(const void *fdt);
   1108 
   1109 int fdt_property_string(void *fdt, const char *name, const char *val);
   1110 int 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  */
   1116 int fdt_property_stub(void *fdt, const char *name, const char *val, int len);
   1117 
   1118 %include <libfdt.h>
   1119