/* * pylibfdt - Flat Device Tree manipulation in Python * Copyright (C) 2017 Google, Inc. * Written by Simon Glass * * SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause */ %module libfdt %include %{ #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) 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) 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>