1/* 2 * pylibfdt - Flat Device Tree manipulation in Python 3 * Copyright (C) 2017 Google, Inc. 4 * Written by Simon Glass <sjg@chromium.org> 5 * 6 * SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause 7 */ 8 9%module libfdt 10 11%include <stdint.i> 12 13%{ 14#define SWIG_FILE_WITH_INIT 15#include "libfdt.h" 16%} 17 18%pythoncode %{ 19 20import struct 21 22# Error codes, corresponding to FDT_ERR_... in libfdt.h 23(NOTFOUND, 24 EXISTS, 25 NOSPACE, 26 BADOFFSET, 27 BADPATH, 28 BADPHANDLE, 29 BADSTATE, 30 TRUNCATED, 31 BADMAGIC, 32 BADVERSION, 33 BADSTRUCTURE, 34 BADLAYOUT, 35 INTERNAL, 36 BADNCELLS, 37 BADVALUE, 38 BADOVERLAY, 39 NOPHANDLES) = QUIET_ALL = range(1, 18) 40# QUIET_ALL can be passed as the 'quiet' parameter to avoid exceptions 41# altogether. All # functions passed this value will return an error instead 42# of raising an exception. 43 44# Pass this as the 'quiet' parameter to return -ENOTFOUND on NOTFOUND errors, 45# instead of raising an exception. 46QUIET_NOTFOUND = (NOTFOUND,) 47 48 49class FdtException(Exception): 50 """An exception caused by an error such as one of the codes above""" 51 def __init__(self, err): 52 self.err = err 53 54 def __str__(self): 55 return 'pylibfdt error %d: %s' % (self.err, fdt_strerror(self.err)) 56 57def strerror(fdt_err): 58 """Get the string for an error number 59 60 Args: 61 fdt_err: Error number (-ve) 62 63 Returns: 64 String containing the associated error 65 """ 66 return fdt_strerror(fdt_err) 67 68def check_err(val, quiet=()): 69 """Raise an error if the return value is -ve 70 71 This is used to check for errors returned by libfdt C functions. 72 73 Args: 74 val: Return value from a libfdt function 75 quiet: Errors to ignore (empty to raise on all errors) 76 77 Returns: 78 val if val >= 0 79 80 Raises 81 FdtException if val < 0 82 """ 83 if val < 0: 84 if -val not in quiet: 85 raise FdtException(val) 86 return val 87 88def check_err_null(val, quiet=()): 89 """Raise an error if the return value is NULL 90 91 This is used to check for a NULL return value from certain libfdt C 92 functions 93 94 Args: 95 val: Return value from a libfdt function 96 quiet: Errors to ignore (empty to raise on all errors) 97 98 Returns: 99 val if val is a list, None if not 100 101 Raises 102 FdtException if val indicates an error was reported and the error 103 is not in @quiet. 104 """ 105 # Normally a list is returned which contains the data and its length. 106 # If we get just an integer error code, it means the function failed. 107 if not isinstance(val, list): 108 if -val not in quiet: 109 raise FdtException(val) 110 return val 111 112class Fdt: 113 """Device tree class, supporting all operations 114 115 The Fdt object is created is created from a device tree binary file, 116 e.g. with something like: 117 118 fdt = Fdt(open("filename.dtb").read()) 119 120 Operations can then be performed using the methods in this class. Each 121 method xxx(args...) corresponds to a libfdt function fdt_xxx(fdt, args...). 122 123 All methods raise an FdtException if an error occurs. To avoid this 124 behaviour a 'quiet' parameter is provided for some functions. This 125 defaults to empty, but you can pass a list of errors that you expect. 126 If one of these errors occurs, the function will return an error number 127 (e.g. -NOTFOUND). 128 """ 129 def __init__(self, data): 130 self._fdt = bytearray(data) 131 check_err(fdt_check_header(self._fdt)); 132 133 def subnode_offset(self, parentoffset, name, quiet=()): 134 """Get the offset of a named subnode 135 136 Args: 137 parentoffset: Offset of the parent node to check 138 name: Name of the required subnode, e.g. 'subnode@1' 139 quiet: Errors to ignore (empty to raise on all errors) 140 141 Returns: 142 The node offset of the found node, if any 143 144 Raises 145 FdtException if there is no node with that name, or other error 146 """ 147 return check_err(fdt_subnode_offset(self._fdt, parentoffset, name), 148 quiet) 149 150 def path_offset(self, path, quiet=()): 151 """Get the offset for a given path 152 153 Args: 154 path: Path to the required node, e.g. '/node@3/subnode@1' 155 quiet: Errors to ignore (empty to raise on all errors) 156 157 Returns: 158 Node offset 159 160 Raises 161 FdtException if the path is not valid or not found 162 """ 163 return check_err(fdt_path_offset(self._fdt, path), quiet) 164 165 def first_property_offset(self, nodeoffset, quiet=()): 166 """Get the offset of the first property in a node offset 167 168 Args: 169 nodeoffset: Offset to the node to check 170 quiet: Errors to ignore (empty to raise on all errors) 171 172 Returns: 173 Offset of the first property 174 175 Raises 176 FdtException if the associated node has no properties, or some 177 other error occurred 178 """ 179 return check_err(fdt_first_property_offset(self._fdt, nodeoffset), 180 quiet) 181 182 def next_property_offset(self, prop_offset, quiet=()): 183 """Get the next property in a node 184 185 Args: 186 prop_offset: Offset of the previous property 187 quiet: Errors to ignore (empty to raise on all errors) 188 189 Returns: 190 Offset of the next property 191 192 Raises: 193 FdtException if the associated node has no more properties, or 194 some other error occurred 195 """ 196 return check_err(fdt_next_property_offset(self._fdt, prop_offset), 197 quiet) 198 199 def get_name(self, nodeoffset): 200 """Get the name of a node 201 202 Args: 203 nodeoffset: Offset of node to check 204 205 Returns: 206 Node name 207 208 Raises: 209 FdtException on error (e.g. nodeoffset is invalid) 210 """ 211 return check_err_null(fdt_get_name(self._fdt, nodeoffset))[0] 212 213 def get_property_by_offset(self, prop_offset, quiet=()): 214 """Obtains a property that can be examined 215 216 Args: 217 prop_offset: Offset of property (e.g. from first_property_offset()) 218 quiet: Errors to ignore (empty to raise on all errors) 219 220 Returns: 221 Property object, or None if not found 222 223 Raises: 224 FdtException on error (e.g. invalid prop_offset or device 225 tree format) 226 """ 227 pdata = check_err_null( 228 fdt_get_property_by_offset(self._fdt, prop_offset), quiet) 229 if isinstance(pdata, (int)): 230 return pdata 231 return Property(pdata[0], pdata[1]) 232 233 def first_subnode(self, nodeoffset, quiet=()): 234 """Find the first subnode of a parent node 235 236 Args: 237 nodeoffset: Node offset of parent node 238 quiet: Errors to ignore (empty to raise on all errors) 239 240 Returns: 241 The offset of the first subnode, if any 242 243 Raises: 244 FdtException if no subnode found or other error occurs 245 """ 246 return check_err(fdt_first_subnode(self._fdt, nodeoffset), quiet) 247 248 def next_subnode(self, nodeoffset, quiet=()): 249 """Find the next subnode 250 251 Args: 252 nodeoffset: Node offset of previous subnode 253 quiet: Errors to ignore (empty to raise on all errors) 254 255 Returns: 256 The offset of the next subnode, if any 257 258 Raises: 259 FdtException if no more subnode found or other error occurs 260 """ 261 return check_err(fdt_next_subnode(self._fdt, nodeoffset), quiet) 262 263 def totalsize(self): 264 """Return the total size of the device tree 265 266 Returns: 267 Total tree size in bytes 268 """ 269 return check_err(fdt_totalsize(self._fdt)) 270 271 def off_dt_struct(self): 272 """Return the start of the device tree struct area 273 274 Returns: 275 Start offset of struct area 276 """ 277 return check_err(fdt_off_dt_struct(self._fdt)) 278 279 def pack(self, quiet=()): 280 """Pack the device tree to remove unused space 281 282 This adjusts the tree in place. 283 284 Args: 285 quiet: Errors to ignore (empty to raise on all errors) 286 287 Raises: 288 FdtException if any error occurs 289 """ 290 return check_err(fdt_pack(self._fdt), quiet) 291 292 def delprop(self, nodeoffset, prop_name): 293 """Delete a property from a node 294 295 Args: 296 nodeoffset: Node offset containing property to delete 297 prop_name: Name of property to delete 298 299 Raises: 300 FdtError if the property does not exist, or another error occurs 301 """ 302 return check_err(fdt_delprop(self._fdt, nodeoffset, prop_name)) 303 304 def getprop(self, nodeoffset, prop_name, quiet=()): 305 """Get a property from a node 306 307 Args: 308 nodeoffset: Node offset containing property to get 309 prop_name: Name of property to get 310 quiet: Errors to ignore (empty to raise on all errors) 311 312 Returns: 313 Value of property as a bytearray, or -ve error number 314 315 Raises: 316 FdtError if any error occurs (e.g. the property is not found) 317 """ 318 pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name), 319 quiet) 320 if isinstance(pdata, (int)): 321 return pdata 322 return bytearray(pdata[0]) 323 324 def get_phandle(self, nodeoffset): 325 """Get the phandle of a node 326 327 Args: 328 nodeoffset: Node offset to check 329 330 Returns: 331 phandle of node, or 0 if the node has no phandle or another error 332 occurs 333 """ 334 return fdt_get_phandle(self._fdt, nodeoffset) 335 336 def parent_offset(self, nodeoffset, quiet=()): 337 """Get the offset of a node's parent 338 339 Args: 340 nodeoffset: Node offset to check 341 quiet: Errors to ignore (empty to raise on all errors) 342 343 Returns: 344 The offset of the parent node, if any 345 346 Raises: 347 FdtException if no parent found or other error occurs 348 """ 349 return check_err(fdt_parent_offset(self._fdt, nodeoffset), quiet) 350 351 def node_offset_by_phandle(self, phandle, quiet=()): 352 """Get the offset of a node with the given phandle 353 354 Args: 355 phandle: Phandle to search for 356 quiet: Errors to ignore (empty to raise on all errors) 357 358 Returns: 359 The offset of node with that phandle, if any 360 361 Raises: 362 FdtException if no node found or other error occurs 363 """ 364 return check_err(fdt_node_offset_by_phandle(self._fdt, phandle), quiet) 365 366class Property: 367 """Holds a device tree property name and value. 368 369 This holds a copy of a property taken from the device tree. It does not 370 reference the device tree, so if anything changes in the device tree, 371 a Property object will remain valid. 372 373 Properties: 374 name: Property name 375 value: Proper value as a bytearray 376 """ 377 def __init__(self, name, value): 378 self.name = name 379 self.value = value 380%} 381 382%rename(fdt_property) fdt_property_func; 383 384typedef int fdt32_t; 385 386%include "libfdt/fdt.h" 387 388%include "typemaps.i" 389 390/* Most functions don't change the device tree, so use a const void * */ 391%typemap(in) (const void *)(const void *fdt) { 392 if (!PyByteArray_Check($input)) { 393 SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname" 394 "', argument " "$argnum"" of type '" "$type""'"); 395 } 396 $1 = (void *)PyByteArray_AsString($input); 397 fdt = $1; 398 fdt = fdt; /* avoid unused variable warning */ 399} 400 401/* Some functions do change the device tree, so use void * */ 402%typemap(in) (void *)(const void *fdt) { 403 if (!PyByteArray_Check($input)) { 404 SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname" 405 "', argument " "$argnum"" of type '" "$type""'"); 406 } 407 $1 = PyByteArray_AsString($input); 408 fdt = $1; 409 fdt = fdt; /* avoid unused variable warning */ 410} 411 412%typemap(out) (struct fdt_property *) { 413 PyObject *buff; 414 415 if ($1) { 416 resultobj = PyString_FromString( 417 fdt_string(fdt1, fdt32_to_cpu($1->nameoff))); 418 buff = PyByteArray_FromStringAndSize( 419 (const char *)($1 + 1), fdt32_to_cpu($1->len)); 420 resultobj = SWIG_Python_AppendOutput(resultobj, buff); 421 } 422} 423 424%apply int *OUTPUT { int *lenp }; 425 426/* typemap used for fdt_getprop() */ 427%typemap(out) (const void *) { 428 if (!$1) 429 $result = Py_None; 430 else 431 $result = Py_BuildValue("s#", $1, *arg4); 432} 433 434/* We have both struct fdt_property and a function fdt_property() */ 435%warnfilter(302) fdt_property; 436 437/* These are macros in the header so have to be redefined here */ 438int fdt_magic(const void *fdt); 439int fdt_totalsize(const void *fdt); 440int fdt_off_dt_struct(const void *fdt); 441int fdt_off_dt_strings(const void *fdt); 442int fdt_off_mem_rsvmap(const void *fdt); 443int fdt_version(const void *fdt); 444int fdt_last_comp_version(const void *fdt); 445int fdt_boot_cpuid_phys(const void *fdt); 446int fdt_size_dt_strings(const void *fdt); 447int fdt_size_dt_struct(const void *fdt); 448 449%include <../libfdt/libfdt.h> 450