# utilities to access Device Tree properties import pathlib import os class DtNode( pathlib.PosixPath ): __slots__ = () @property def phandle( node ): return node.u32( 'phandle' ) def bytes( node, prop ): return (node/prop).read_bytes() def u32( node, prop ): return unpack( '>I', node.bytes( prop ) )[0] def strs( node, prop ): s = node.bytes( prop ).split( b'\x00' ) if s.pop() != b'': raise RuntimeError("Malformed string(-array) property") return s def str( node, prop ): return node.strs( prop )[0] def path( node, prop ): node = node.str( prop ) if node[:1] != b'/': raise RuntimeError( "Malformed device tree node: %s" % node ) return dt_root / os.fsdecode( node[1:] ) dt_root = DtNode( '/proc/device-tree' ) dt_symbol = (dt_root/'__symbols__').path dt_alias = (dt_root/'aliases').path def dt( s ): if type( s ) == DtNode: return s if isinstance( s, pathlib.Path ): return DtNode( s ) if '/' in s: ( s, p ) = s.split( '/', 1 ) return dt( s )/p if s == '': return dt_root if s[0] == '&': return dt_symbol( s[1:] ) return dt_alias( s ) # utilities to fix some annoying ctypes behaviour function = type( lambda: () ) from ctypes import c_uint8 as ubyte import ctypes class cached_getter: __slots__ = ('__name__', 'desc',) def __init__( self, desc, name=None ): if name is None: name = desc.__name__ self.__name__ = name self.desc = desc def __get__( self, instance, owner ): if not isinstance( self.desc, function ): value = self.desc.__get__( instance, owner ) if instance is not None: instance.__dict__[ self.__name__ ] = value return value elif instance is not None: value = self.desc( instance ) instance.__dict__[ self.__name__ ] = value return value else: return self def fix_ctypes_struct( cls ): instance = cls() const_fields = [] if hasattr( cls, '_const_' ): const_fields = cls._const_ for name, ctype, *args in cls._fields_: if name == "": continue desc = cls.__dict__[ name ] if name not in const_fields: if len(args) > 0: continue if not isinstance( desc.__get__( instance, cls ), ctype ): continue setattr( cls, name, cached_getter( desc, name ) ) return cls def struct_field( offset, ctype, name='field' ): @fix_ctypes_struct class Struct( ctypes.Structure ): _fields_ = [ ("", ubyte * offset), (name, ctype) ] return getattr( Struct, name )