Skip to content
Snippets Groups Projects
libfdt.i 12.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • Simon Glass's avatar
    Simon Glass committed
    /*
     * pylibfdt - Flat Device Tree manipulation in Python
     * Copyright (C) 2017 Google, Inc.
     * Written by Simon Glass <sjg@chromium.org>
     *
     * SPDX-License-Identifier:	GPL-2.0+ BSD-2-Clause
     */
    
    %module libfdt
    
    
    Simon Glass's avatar
    Simon Glass committed
    %{
    #define SWIG_FILE_WITH_INIT
    #include "libfdt.h"
    %}
    
    %pythoncode %{
    
    import struct
    
    # Error codes, corresponding to FDT_ERR_... in libfdt.h
    (NOTFOUND,
            EXISTS,
            NOSPACE,
            BADOFFSET,
            BADPATH,
            BADPHANDLE,
            BADSTATE,
            TRUNCATED,
            BADMAGIC,
            BADVERSION,
            BADSTRUCTURE,
            BADLAYOUT,
            INTERNAL,
            BADNCELLS,
            BADVALUE,
            BADOVERLAY,
            NOPHANDLES) = QUIET_ALL = range(1, 18)
    # QUIET_ALL can be passed as the 'quiet' parameter to avoid exceptions
    # altogether. All # functions passed this value will return an error instead
    # of raising an exception.
    
    # Pass this as the 'quiet' parameter to return -ENOTFOUND on NOTFOUND errors,
    # instead of raising an exception.
    QUIET_NOTFOUND = (NOTFOUND,)
    
    
    class FdtException(Exception):
        """An exception caused by an error such as one of the codes above"""
        def __init__(self, err):
            self.err = err
    
        def __str__(self):
            return 'pylibfdt error %d: %s' % (self.err, fdt_strerror(self.err))
    
    def strerror(fdt_err):
        """Get the string for an error number
    
        Args:
            fdt_err: Error number (-ve)
    
        Returns:
            String containing the associated error
        """
        return fdt_strerror(fdt_err)
    
    def check_err(val, quiet=()):
        """Raise an error if the return value is -ve
    
        This is used to check for errors returned by libfdt C functions.
    
        Args:
            val: Return value from a libfdt function
            quiet: Errors to ignore (empty to raise on all errors)
    
        Returns:
            val if val >= 0
    
        Raises
            FdtException if val < 0
        """
        if val < 0:
            if -val not in quiet:
                raise FdtException(val)
        return val
    
    def check_err_null(val, quiet=()):
        """Raise an error if the return value is NULL
    
        This is used to check for a NULL return value from certain libfdt C
        functions
    
        Args:
            val: Return value from a libfdt function
            quiet: Errors to ignore (empty to raise on all errors)
    
        Returns:
            val if val is a list, None if not
    
        Raises
            FdtException if val indicates an error was reported and the error
            is not in @quiet.
        """
        # Normally a list is returned which contains the data and its length.
        # If we get just an integer error code, it means the function failed.
        if not isinstance(val, list):
            if -val not in quiet:
                raise FdtException(val)
        return val
    
    class Fdt:
        """Device tree class, supporting all operations
    
        The Fdt object is created is created from a device tree binary file,
        e.g. with something like:
    
           fdt = Fdt(open("filename.dtb").read())
    
        Operations can then be performed using the methods in this class. Each
        method xxx(args...) corresponds to a libfdt function fdt_xxx(fdt, args...).
    
        All methods raise an FdtException if an error occurs. To avoid this
        behaviour a 'quiet' parameter is provided for some functions. This
        defaults to empty, but you can pass a list of errors that you expect.
        If one of these errors occurs, the function will return an error number
        (e.g. -NOTFOUND).
        """
        def __init__(self, data):
            self._fdt = bytearray(data)
            check_err(fdt_check_header(self._fdt));
    
    
        def subnode_offset(self, parentoffset, name, quiet=()):
            """Get the offset of a named subnode
    
            Args:
                parentoffset: Offset of the parent node to check
                name: Name of the required subnode, e.g. 'subnode@1'
                quiet: Errors to ignore (empty to raise on all errors)
    
            Returns:
                The node offset of the found node, if any
    
            Raises
                FdtException if there is no node with that name, or other error
            """
            return check_err(fdt_subnode_offset(self._fdt, parentoffset, name),
                             quiet)
    
    
    Simon Glass's avatar
    Simon Glass committed
        def path_offset(self, path, quiet=()):
            """Get the offset for a given path
    
            Args:
                path: Path to the required node, e.g. '/node@3/subnode@1'
                quiet: Errors to ignore (empty to raise on all errors)
    
            Returns:
                Node offset
    
            Raises
                FdtException if the path is not valid or not found
            """
            return check_err(fdt_path_offset(self._fdt, path), quiet)
    
        def first_property_offset(self, nodeoffset, quiet=()):
            """Get the offset of the first property in a node offset
    
            Args:
                nodeoffset: Offset to the node to check
                quiet: Errors to ignore (empty to raise on all errors)
    
            Returns:
                Offset of the first property
    
            Raises
                FdtException if the associated node has no properties, or some
                    other error occurred
            """
            return check_err(fdt_first_property_offset(self._fdt, nodeoffset),
                             quiet)
    
        def next_property_offset(self, prop_offset, quiet=()):
            """Get the next property in a node
    
            Args:
                prop_offset: Offset of the previous property
                quiet: Errors to ignore (empty to raise on all errors)
    
            Returns:
                Offset of the next property
    
            Raises:
                FdtException if the associated node has no more properties, or
                    some other error occurred
            """
            return check_err(fdt_next_property_offset(self._fdt, prop_offset),
                             quiet)
    
        def get_name(self, nodeoffset):
            """Get the name of a node
    
            Args:
                nodeoffset: Offset of node to check
    
            Returns:
                Node name
    
            Raises:
                FdtException on error (e.g. nodeoffset is invalid)
            """
            return check_err_null(fdt_get_name(self._fdt, nodeoffset))[0]
    
        def get_property_by_offset(self, prop_offset, quiet=()):
            """Obtains a property that can be examined
    
            Args:
                prop_offset: Offset of property (e.g. from first_property_offset())
                quiet: Errors to ignore (empty to raise on all errors)
    
            Returns:
                Property object, or None if not found
    
            Raises:
                FdtException on error (e.g. invalid prop_offset or device
                tree format)
            """
            pdata = check_err_null(
                    fdt_get_property_by_offset(self._fdt, prop_offset), quiet)
            if isinstance(pdata, (int)):
                return pdata
            return Property(pdata[0], pdata[1])
    
        def first_subnode(self, nodeoffset, quiet=()):
            """Find the first subnode of a parent node
    
            Args:
                nodeoffset: Node offset of parent node
                quiet: Errors to ignore (empty to raise on all errors)
    
            Returns:
                The offset of the first subnode, if any
    
            Raises:
                FdtException if no subnode found or other error occurs
            """
            return check_err(fdt_first_subnode(self._fdt, nodeoffset), quiet)
    
        def next_subnode(self, nodeoffset, quiet=()):
            """Find the next subnode
    
            Args:
                nodeoffset: Node offset of previous subnode
                quiet: Errors to ignore (empty to raise on all errors)
    
            Returns:
                The offset of the next subnode, if any
    
            Raises:
                FdtException if no more subnode found or other error occurs
            """
            return check_err(fdt_next_subnode(self._fdt, nodeoffset), quiet)
    
        def totalsize(self):
            """Return the total size of the device tree
    
            Returns:
                Total tree size in bytes
            """
            return check_err(fdt_totalsize(self._fdt))
    
        def off_dt_struct(self):
            """Return the start of the device tree struct area
    
            Returns:
                Start offset of struct area
            """
            return check_err(fdt_off_dt_struct(self._fdt))
    
        def pack(self, quiet=()):
            """Pack the device tree to remove unused space
    
            This adjusts the tree in place.
    
            Args:
                quiet: Errors to ignore (empty to raise on all errors)
    
            Raises:
                FdtException if any error occurs
            """
            return check_err(fdt_pack(self._fdt), quiet)
    
        def delprop(self, nodeoffset, prop_name):
            """Delete a property from a node
    
            Args:
                nodeoffset: Node offset containing property to delete
                prop_name: Name of property to delete
    
            Raises:
                FdtError if the property does not exist, or another error occurs
            """
            return check_err(fdt_delprop(self._fdt, nodeoffset, prop_name))
    
        def getprop(self, nodeoffset, prop_name, quiet=()):
            """Get a property from a node
    
            Args:
                nodeoffset: Node offset containing property to get
                prop_name: Name of property to get
                quiet: Errors to ignore (empty to raise on all errors)
    
            Returns:
                Value of property as a bytearray, or -ve error number
    
            Raises:
                FdtError if any error occurs (e.g. the property is not found)
            """
            pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name),
                                   quiet)
            if isinstance(pdata, (int)):
                return pdata
            return bytearray(pdata[0])
    
    
        def get_phandle(self, nodeoffset):
            """Get the phandle of a node
    
            Args:
                nodeoffset: Node offset to check
    
            Returns:
                phandle of node, or 0 if the node has no phandle or another error
                occurs
            """
            return fdt_get_phandle(self._fdt, nodeoffset)
    
        def parent_offset(self, nodeoffset, quiet=()):
            """Get the offset of a node's parent
    
            Args:
                nodeoffset: Node offset to check
                quiet: Errors to ignore (empty to raise on all errors)
    
            Returns:
                The offset of the parent node, if any
    
            Raises:
                FdtException if no parent found or other error occurs
            """
            return check_err(fdt_parent_offset(self._fdt, nodeoffset), quiet)
    
        def node_offset_by_phandle(self, phandle, quiet=()):
            """Get the offset of a node with the given phandle
    
            Args:
                phandle: Phandle to search for
                quiet: Errors to ignore (empty to raise on all errors)
    
            Returns:
                The offset of node with that phandle, if any
    
            Raises:
                FdtException if no node found or other error occurs
            """
            return check_err(fdt_node_offset_by_phandle(self._fdt, phandle), quiet)
    
    Simon Glass's avatar
    Simon Glass committed
    
    class Property:
        """Holds a device tree property name and value.
    
        This holds a copy of a property taken from the device tree. It does not
        reference the device tree, so if anything changes in the device tree,
        a Property object will remain valid.
    
        Properties:
            name: Property name
            value: Proper value as a bytearray
        """
        def __init__(self, name, value):
            self.name = name
            self.value = value
    %}
    
    %rename(fdt_property) fdt_property_func;
    
    typedef int fdt32_t;
    
    %include "libfdt/fdt.h"
    
    %include "typemaps.i"
    
    /* Most functions don't change the device tree, so use a const void * */
    %typemap(in) (const void *)(const void *fdt) {
    	if (!PyByteArray_Check($input)) {
    		SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
    			"', argument " "$argnum"" of type '" "$type""'");
    	}
    	$1 = (void *)PyByteArray_AsString($input);
            fdt = $1;
            fdt = fdt; /* avoid unused variable warning */
    }
    
    /* Some functions do change the device tree, so use void * */
    %typemap(in) (void *)(const void *fdt) {
    	if (!PyByteArray_Check($input)) {
    		SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
    			"', argument " "$argnum"" of type '" "$type""'");
    	}
    	$1 = PyByteArray_AsString($input);
            fdt = $1;
            fdt = fdt; /* avoid unused variable warning */
    }
    
    %typemap(out) (struct fdt_property *) {
    	PyObject *buff;
    
    	if ($1) {
    		resultobj = PyString_FromString(
    			fdt_string(fdt1, fdt32_to_cpu($1->nameoff)));
    		buff = PyByteArray_FromStringAndSize(
    			(const char *)($1 + 1), fdt32_to_cpu($1->len));
    		resultobj = SWIG_Python_AppendOutput(resultobj, buff);
    	}
    }
    
    %apply int *OUTPUT { int *lenp };
    
    /* typemap used for fdt_getprop() */
    %typemap(out) (const void *) {
    	if (!$1)
    		$result = Py_None;
    	else
    		$result = Py_BuildValue("s#", $1, *arg4);
    }
    
    /* We have both struct fdt_property and a function fdt_property() */
    %warnfilter(302) fdt_property;
    
    /* These are macros in the header so have to be redefined here */
    int fdt_magic(const void *fdt);
    int fdt_totalsize(const void *fdt);
    int fdt_off_dt_struct(const void *fdt);
    int fdt_off_dt_strings(const void *fdt);
    int fdt_off_mem_rsvmap(const void *fdt);
    int fdt_version(const void *fdt);
    int fdt_last_comp_version(const void *fdt);
    int fdt_boot_cpuid_phys(const void *fdt);
    int fdt_size_dt_strings(const void *fdt);
    int fdt_size_dt_struct(const void *fdt);
    
    %include <../libfdt/libfdt.h>