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