Commit 3def0cf238e0df9736a4ce8fb54c1eb561a56ddd

Authored by Simon Glass
1 parent 5c890238c4

libfdt: Bring in proposed pylibfdt changes

This provides various patches sent to the devicetree-compiler mailing list
to enhance the Python bindings. A final version of this patch may be
created once upstreaming is complete, but if it takes too long, this can
act as a placeholder.

New pylibfdt features:
- Support for most remaining, relevant libfdt functions
- Support for sequential-write functions

Changes are applied to existing U-Boot tools as needed.

Signed-off-by: Simon Glass <sjg@chromium.org>

Showing 5 changed files with 663 additions and 71 deletions Side-by-side Diff

scripts/dtc/libfdt/libfdt.h
... ... @@ -1313,10 +1313,13 @@
1313 1313 fdt64_t tmp = cpu_to_fdt64(val);
1314 1314 return fdt_property(fdt, name, &tmp, sizeof(tmp));
1315 1315 }
  1316 +
  1317 +#ifndef SWIG /* Not available in Python */
1316 1318 static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
1317 1319 {
1318 1320 return fdt_property_u32(fdt, name, val);
1319 1321 }
  1322 +#endif
1320 1323  
1321 1324 /**
1322 1325 * fdt_property_placeholder - add a new property and return a ptr to its value
scripts/dtc/pylibfdt/libfdt.i_shipped
... ... @@ -12,6 +12,17 @@
12 12 %{
13 13 #define SWIG_FILE_WITH_INIT
14 14 #include "libfdt.h"
  15 +
  16 +/*
  17 + * We rename this function here to avoid problems with swig, since we also have
  18 + * a struct called fdt_property. That struct causes swig to create a class in
  19 + * libfdt.py called fdt_property(), which confuses things.
  20 + */
  21 +static int _fdt_property(void *fdt, const char *name, const char *val, int len)
  22 +{
  23 + return fdt_property(fdt, name, val, len);
  24 +}
  25 +
15 26 %}
16 27  
17 28 %pythoncode %{
... ... @@ -108,6 +119,7 @@
108 119 raise FdtException(val)
109 120 return val
110 121  
  122 +
111 123 class Fdt:
112 124 """Device tree class, supporting all operations
113 125  
... ... @@ -129,6 +141,163 @@
129 141 self._fdt = bytearray(data)
130 142 check_err(fdt_check_header(self._fdt));
131 143  
  144 + def as_bytearray(self):
  145 + """Get the device tree contents as a bytearray
  146 +
  147 + This can be passed directly to libfdt functions that access a
  148 + const void * for the device tree.
  149 +
  150 + Returns:
  151 + bytearray containing the device tree
  152 + """
  153 + return bytearray(self._fdt)
  154 +
  155 + def next_node(self, nodeoffset, depth, quiet=()):
  156 + """Find the next subnode
  157 +
  158 + Args:
  159 + nodeoffset: Node offset of previous node
  160 + depth: On input, the depth of the node at nodeoffset. On output, the
  161 + depth of the returned node
  162 + quiet: Errors to ignore (empty to raise on all errors)
  163 +
  164 + Returns:
  165 + The offset of the next node, if any
  166 +
  167 + Raises:
  168 + FdtException if no more nodes found or other error occurs
  169 + """
  170 + return check_err(fdt_next_node(self._fdt, nodeoffset, depth), quiet)
  171 +
  172 + def first_subnode(self, nodeoffset, quiet=()):
  173 + """Find the first subnode of a parent node
  174 +
  175 + Args:
  176 + nodeoffset: Node offset of parent node
  177 + quiet: Errors to ignore (empty to raise on all errors)
  178 +
  179 + Returns:
  180 + The offset of the first subnode, if any
  181 +
  182 + Raises:
  183 + FdtException if no subnodes found or other error occurs
  184 + """
  185 + return check_err(fdt_first_subnode(self._fdt, nodeoffset), quiet)
  186 +
  187 + def next_subnode(self, nodeoffset, quiet=()):
  188 + """Find the next subnode
  189 +
  190 + Args:
  191 + nodeoffset: Node offset of previous subnode
  192 + quiet: Errors to ignore (empty to raise on all errors)
  193 +
  194 + Returns:
  195 + The offset of the next subnode, if any
  196 +
  197 + Raises:
  198 + FdtException if no more subnodes found or other error occurs
  199 + """
  200 + return check_err(fdt_next_subnode(self._fdt, nodeoffset), quiet)
  201 +
  202 + def magic(self):
  203 + """Return the magic word from the header
  204 +
  205 + Returns:
  206 + Magic word
  207 + """
  208 + return fdt_magic(self._fdt) & 0xffffffff
  209 +
  210 + def totalsize(self):
  211 + """Return the total size of the device tree
  212 +
  213 + Returns:
  214 + Total tree size in bytes
  215 + """
  216 + return check_err(fdt_totalsize(self._fdt))
  217 +
  218 + def off_dt_struct(self):
  219 + """Return the start of the device-tree struct area
  220 +
  221 + Returns:
  222 + Start offset of struct area
  223 + """
  224 + return check_err(fdt_off_dt_struct(self._fdt))
  225 +
  226 + def off_dt_strings(self):
  227 + """Return the start of the device-tree string area
  228 +
  229 + Returns:
  230 + Start offset of string area
  231 + """
  232 + return check_err(fdt_off_dt_strings(self._fdt))
  233 +
  234 + def off_mem_rsvmap(self):
  235 + """Return the start of the memory reserve map
  236 +
  237 + Returns:
  238 + Start offset of memory reserve map
  239 + """
  240 + return check_err(fdt_off_mem_rsvmap(self._fdt))
  241 +
  242 + def version(self):
  243 + """Return the version of the device tree
  244 +
  245 + Returns:
  246 + Version number of the device tree
  247 + """
  248 + return check_err(fdt_version(self._fdt))
  249 +
  250 + def last_comp_version(self):
  251 + """Return the last compatible version of the device tree
  252 +
  253 + Returns:
  254 + Last compatible version number of the device tree
  255 + """
  256 + return check_err(fdt_last_comp_version(self._fdt))
  257 +
  258 + def boot_cpuid_phys(self):
  259 + """Return the physical boot CPU ID
  260 +
  261 + Returns:
  262 + Physical boot CPU ID
  263 + """
  264 + return check_err(fdt_boot_cpuid_phys(self._fdt))
  265 +
  266 + def size_dt_strings(self):
  267 + """Return the start of the device-tree string area
  268 +
  269 + Returns:
  270 + Start offset of string area
  271 + """
  272 + return check_err(fdt_size_dt_strings(self._fdt))
  273 +
  274 + def size_dt_struct(self):
  275 + """Return the start of the device-tree struct area
  276 +
  277 + Returns:
  278 + Start offset of struct area
  279 + """
  280 + return check_err(fdt_size_dt_struct(self._fdt))
  281 +
  282 + def num_mem_rsv(self, quiet=()):
  283 + """Return the number of memory reserve-map records
  284 +
  285 + Returns:
  286 + Number of memory reserve-map records
  287 + """
  288 + return check_err(fdt_num_mem_rsv(self._fdt), quiet)
  289 +
  290 + def get_mem_rsv(self, index, quiet=()):
  291 + """Return the indexed memory reserve-map record
  292 +
  293 + Args:
  294 + index: Record to return (0=first)
  295 +
  296 + Returns:
  297 + Number of memory reserve-map records
  298 + """
  299 + return check_err(fdt_get_mem_rsv(self._fdt, index), quiet)
  300 +
132 301 def subnode_offset(self, parentoffset, name, quiet=()):
133 302 """Get the offset of a named subnode
134 303  
... ... @@ -161,6 +330,20 @@
161 330 """
162 331 return check_err(fdt_path_offset(self._fdt, path), quiet)
163 332  
  333 + def get_name(self, nodeoffset):
  334 + """Get the name of a node
  335 +
  336 + Args:
  337 + nodeoffset: Offset of node to check
  338 +
  339 + Returns:
  340 + Node name
  341 +
  342 + Raises:
  343 + FdtException on error (e.g. nodeoffset is invalid)
  344 + """
  345 + return check_err_null(fdt_get_name(self._fdt, nodeoffset))[0]
  346 +
164 347 def first_property_offset(self, nodeoffset, quiet=()):
165 348 """Get the offset of the first property in a node offset
166 349  
... ... @@ -195,20 +378,6 @@
195 378 return check_err(fdt_next_property_offset(self._fdt, prop_offset),
196 379 quiet)
197 380  
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 381 def get_property_by_offset(self, prop_offset, quiet=()):
213 382 """Obtains a property that can be examined
214 383  
215 384  
216 385  
217 386  
218 387  
219 388  
220 389  
221 390  
222 391  
... ... @@ -229,52 +398,39 @@
229 398 return pdata
230 399 return Property(pdata[0], pdata[1])
231 400  
232   - def first_subnode(self, nodeoffset, quiet=()):
233   - """Find the first subnode of a parent node
  401 + @staticmethod
  402 + def create_empty_tree(size, quiet=()):
  403 + """Create an empty device tree ready for use
234 404  
235 405 Args:
236   - nodeoffset: Node offset of parent node
237   - quiet: Errors to ignore (empty to raise on all errors)
  406 + size: Size of device tree in bytes
238 407  
239 408 Returns:
240   - The offset of the first subnode, if any
241   -
242   - Raises:
243   - FdtException if no subnode found or other error occurs
  409 + Fdt object containing the device tree
244 410 """
245   - return check_err(fdt_first_subnode(self._fdt, nodeoffset), quiet)
  411 + data = bytearray(size)
  412 + err = check_err(fdt_create_empty_tree(data, size), quiet)
  413 + if err:
  414 + return err
  415 + return Fdt(data)
246 416  
247   - def next_subnode(self, nodeoffset, quiet=()):
248   - """Find the next subnode
  417 + def open_into(self, size, quiet=()):
  418 + """Move the device tree into a larger or smaller space
249 419  
250   - Args:
251   - nodeoffset: Node offset of previous subnode
252   - quiet: Errors to ignore (empty to raise on all errors)
  420 + This creates a new device tree of size @size and moves the existing
  421 + device tree contents over to that. It can be used to create more space
  422 + in a device tree.
253 423  
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
  424 + Args:
  425 + size: Required new size of device tree in bytes
259 426 """
260   - return check_err(fdt_next_subnode(self._fdt, nodeoffset), quiet)
  427 + fdt = bytearray(size)
  428 + fdt[:len(self._fdt)] = self._fdt
  429 + err = check_err(fdt_open_into(self._fdt, fdt, size), quiet)
  430 + if err:
  431 + return err
  432 + self._fdt = fdt
261 433  
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 434 def pack(self, quiet=()):
279 435 """Pack the device tree to remove unused space
280 436  
281 437  
282 438  
283 439  
284 440  
285 441  
... ... @@ -288,20 +444,28 @@
288 444 """
289 445 return check_err(fdt_pack(self._fdt), quiet)
290 446  
291   - def delprop(self, nodeoffset, prop_name):
292   - """Delete a property from a node
  447 + def getprop(self, nodeoffset, prop_name, quiet=()):
  448 + """Get a property from a node
293 449  
294 450 Args:
295   - nodeoffset: Node offset containing property to delete
296   - prop_name: Name of property to delete
  451 + nodeoffset: Node offset containing property to get
  452 + prop_name: Name of property to get
  453 + quiet: Errors to ignore (empty to raise on all errors)
297 454  
  455 + Returns:
  456 + Value of property as a string, or -ve error number
  457 +
298 458 Raises:
299   - FdtError if the property does not exist, or another error occurs
  459 + FdtError if any error occurs (e.g. the property is not found)
300 460 """
301   - return check_err(fdt_delprop(self._fdt, nodeoffset, prop_name))
  461 + pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name),
  462 + quiet)
  463 + if isinstance(pdata, (int)):
  464 + return pdata
  465 + return str(pdata[0])
302 466  
303   - def getprop(self, nodeoffset, prop_name, quiet=()):
304   - """Get a property from a node
  467 + def getprop_obj(self, nodeoffset, prop_name, quiet=()):
  468 + """Get a property from a node as a Property object
305 469  
306 470 Args:
307 471 nodeoffset: Node offset containing property to get
... ... @@ -309,7 +473,7 @@
309 473 quiet: Errors to ignore (empty to raise on all errors)
310 474  
311 475 Returns:
312   - Value of property as a bytearray, or -ve error number
  476 + Property object, or None if not found
313 477  
314 478 Raises:
315 479 FdtError if any error occurs (e.g. the property is not found)
... ... @@ -317,8 +481,8 @@
317 481 pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name),
318 482 quiet)
319 483 if isinstance(pdata, (int)):
320   - return pdata
321   - return bytearray(pdata[0])
  484 + return None
  485 + return Property(prop_name, bytearray(pdata[0]))
322 486  
323 487 def get_phandle(self, nodeoffset):
324 488 """Get the phandle of a node
... ... @@ -347,6 +511,108 @@
347 511 """
348 512 return check_err(fdt_parent_offset(self._fdt, nodeoffset), quiet)
349 513  
  514 + def set_name(self, nodeoffset, name, quiet=()):
  515 + """Set the name of a node
  516 +
  517 + Args:
  518 + nodeoffset: Node offset of node to update
  519 + name: New node name
  520 +
  521 + Returns:
  522 + Error code, or 0 if OK
  523 +
  524 + Raises:
  525 + FdtException if no parent found or other error occurs
  526 + """
  527 + return check_err(fdt_set_name(self._fdt, nodeoffset, name), quiet)
  528 +
  529 + def setprop(self, nodeoffset, prop_name, val, quiet=()):
  530 + """Set the value of a property
  531 +
  532 + Args:
  533 + nodeoffset: Node offset containing the property to create/update
  534 + prop_name: Name of property
  535 + val: Value to write (string or bytearray)
  536 + quiet: Errors to ignore (empty to raise on all errors)
  537 +
  538 + Returns:
  539 + Error code, or 0 if OK
  540 +
  541 + Raises:
  542 + FdtException if no parent found or other error occurs
  543 + """
  544 + return check_err(fdt_setprop(self._fdt, nodeoffset, prop_name, val,
  545 + len(val)), quiet)
  546 +
  547 + def setprop_u32(self, nodeoffset, prop_name, val, quiet=()):
  548 + """Set the value of a property
  549 +
  550 + Args:
  551 + nodeoffset: Node offset containing the property to create/update
  552 + prop_name: Name of property
  553 + val: Value to write (integer)
  554 + quiet: Errors to ignore (empty to raise on all errors)
  555 +
  556 + Returns:
  557 + Error code, or 0 if OK
  558 +
  559 + Raises:
  560 + FdtException if no parent found or other error occurs
  561 + """
  562 + return check_err(fdt_setprop_u32(self._fdt, nodeoffset, prop_name, val),
  563 + quiet)
  564 +
  565 + def setprop_u64(self, nodeoffset, prop_name, val, quiet=()):
  566 + """Set the value of a property
  567 +
  568 + Args:
  569 + nodeoffset: Node offset containing the property to create/update
  570 + prop_name: Name of property
  571 + val: Value to write (integer)
  572 + quiet: Errors to ignore (empty to raise on all errors)
  573 +
  574 + Returns:
  575 + Error code, or 0 if OK
  576 +
  577 + Raises:
  578 + FdtException if no parent found or other error occurs
  579 + """
  580 + return check_err(fdt_setprop_u64(self._fdt, nodeoffset, prop_name, val),
  581 + quiet)
  582 +
  583 + def setprop_str(self, nodeoffset, prop_name, val, quiet=()):
  584 + """Set the string value of a property
  585 +
  586 + The property is set to the string, with a nul terminator added
  587 +
  588 + Args:
  589 + nodeoffset: Node offset containing the property to create/update
  590 + prop_name: Name of property
  591 + val: Value to write (string without nul terminator)
  592 + quiet: Errors to ignore (empty to raise on all errors)
  593 +
  594 + Returns:
  595 + Error code, or 0 if OK
  596 +
  597 + Raises:
  598 + FdtException if no parent found or other error occurs
  599 + """
  600 + val += '\0'
  601 + return check_err(fdt_setprop(self._fdt, nodeoffset, prop_name,
  602 + val, len(val)), quiet)
  603 +
  604 + def delprop(self, nodeoffset, prop_name):
  605 + """Delete a property from a node
  606 +
  607 + Args:
  608 + nodeoffset: Node offset containing property to delete
  609 + prop_name: Name of property to delete
  610 +
  611 + Raises:
  612 + FdtError if the property does not exist, or another error occurs
  613 + """
  614 + return check_err(fdt_delprop(self._fdt, nodeoffset, prop_name))
  615 +
350 616 def node_offset_by_phandle(self, phandle, quiet=()):
351 617 """Get the offset of a node with the given phandle
352 618  
... ... @@ -362,7 +628,8 @@
362 628 """
363 629 return check_err(fdt_node_offset_by_phandle(self._fdt, phandle), quiet)
364 630  
365   -class Property:
  631 +
  632 +class Property(bytearray):
366 633 """Holds a device tree property name and value.
367 634  
368 635 This holds a copy of a property taken from the device tree. It does not
369 636  
370 637  
... ... @@ -371,11 +638,274 @@
371 638  
372 639 Properties:
373 640 name: Property name
374   - value: Proper value as a bytearray
  641 + value: Property value as a bytearray
375 642 """
376 643 def __init__(self, name, value):
  644 + bytearray.__init__(self, value)
377 645 self.name = name
378   - self.value = value
  646 +
  647 + def as_cell(self, fmt):
  648 + return struct.unpack('>' + fmt, self)[0]
  649 +
  650 + def as_uint32(self):
  651 + return self.as_cell('L')
  652 +
  653 + def as_int32(self):
  654 + return self.as_cell('l')
  655 +
  656 + def as_uint64(self):
  657 + return self.as_cell('Q')
  658 +
  659 + def as_int64(self):
  660 + return self.as_cell('q')
  661 +
  662 + def as_str(self):
  663 + return self[:-1]
  664 +
  665 +
  666 +class FdtSw(object):
  667 + """Software interface to create a device tree from scratch
  668 +
  669 + The methods in this class work by adding to an existing 'partial' device
  670 + tree buffer of a fixed size created by instantiating this class. When the
  671 + tree is complete, call finish() to complete the device tree so that it can
  672 + be used.
  673 +
  674 + Similarly with nodes, a new node is started with begin_node() and finished
  675 + with end_node().
  676 +
  677 + The context manager functions can be used to make this a bit easier:
  678 +
  679 + # First create the device tree with a node and property:
  680 + with FdtSw(small_size) as sw:
  681 + with sw.AddNode('node'):
  682 + sw.property_u32('reg', 2)
  683 + fdt = sw.AsFdt()
  684 +
  685 + # Now we can use it as a real device tree
  686 + fdt.setprop_u32(0, 'reg', 3)
  687 + """
  688 + def __init__(self, size, quiet=()):
  689 + fdtrw = bytearray(size)
  690 + err = check_err(fdt_create(fdtrw, size))
  691 + if err:
  692 + return err
  693 + self._fdtrw = fdtrw
  694 +
  695 + def __enter__(self):
  696 + """Contact manager to use to create a device tree via software"""
  697 + return self
  698 +
  699 + def __exit__(self, type, value, traceback):
  700 + check_err(fdt_finish(self._fdtrw))
  701 +
  702 + def AsFdt(self):
  703 + """Convert a FdtSw into an Fdt so it can be accessed as normal
  704 +
  705 + Note that finish() must be called before this function will work. If
  706 + you are using the context manager (see 'with' code in the FdtSw class
  707 + comment) then this will happen automatically.
  708 +
  709 + Returns:
  710 + Fdt object allowing access to the newly created device tree
  711 + """
  712 + return Fdt(self._fdtrw)
  713 +
  714 + def resize(self, size, quiet=()):
  715 + """Resize the buffer to accommodate a larger tree
  716 +
  717 + Args:
  718 + size: New size of tree
  719 + quiet: Errors to ignore (empty to raise on all errors)
  720 +
  721 + Raises:
  722 + FdtException if no node found or other error occurs
  723 + """
  724 + fdt = bytearray(size)
  725 + fdt[:len(self._fdtrw)] = self._fdtrw
  726 + err = check_err(fdt_resize(self._fdtrw, fdt, size), quiet)
  727 + if err:
  728 + return err
  729 + self._fdtrw = fdt
  730 +
  731 + def add_reservemap_entry(self, addr, size, quiet=()):
  732 + """Add a new memory reserve map entry
  733 +
  734 + Once finished adding, you must call finish_reservemap().
  735 +
  736 + Args:
  737 + addr: 64-bit start address
  738 + size: 64-bit size
  739 + quiet: Errors to ignore (empty to raise on all errors)
  740 +
  741 + Raises:
  742 + FdtException if no node found or other error occurs
  743 + """
  744 + return check_err(fdt_add_reservemap_entry(self._fdtrw, addr, size),
  745 + quiet)
  746 +
  747 + def finish_reservemap(self, quiet=()):
  748 + """Indicate that there are no more reserve map entries to add
  749 +
  750 + Args:
  751 + quiet: Errors to ignore (empty to raise on all errors)
  752 +
  753 + Raises:
  754 + FdtException if no node found or other error occurs
  755 + """
  756 + return check_err(fdt_finish_reservemap(self._fdtrw), quiet)
  757 +
  758 + def begin_node(self, name, quiet=()):
  759 + """Begin a new node
  760 +
  761 + Use this before adding properties to the node. Then call end_node() to
  762 + finish it. You can also use the context manager as shown in the FdtSw
  763 + class comment.
  764 +
  765 + Args:
  766 + name: Name of node to begin
  767 + quiet: Errors to ignore (empty to raise on all errors)
  768 +
  769 + Raises:
  770 + FdtException if no node found or other error occurs
  771 + """
  772 + return check_err(fdt_begin_node(self._fdtrw, name), quiet)
  773 +
  774 + def property_string(self, name, string, quiet=()):
  775 + """Add a property with a string value
  776 +
  777 + The string will be nul-terminated when written to the device tree
  778 +
  779 + Args:
  780 + name: Name of property to add
  781 + string: String value of property
  782 + quiet: Errors to ignore (empty to raise on all errors)
  783 +
  784 + Raises:
  785 + FdtException if no node found or other error occurs
  786 + """
  787 + return check_err(fdt_property_string(self._fdtrw, name, string), quiet)
  788 +
  789 + def property_u32(self, name, val, quiet=()):
  790 + """Add a property with a 32-bit value
  791 +
  792 + Write a single-cell value to the device tree
  793 +
  794 + Args:
  795 + name: Name of property to add
  796 + val: Value of property
  797 + quiet: Errors to ignore (empty to raise on all errors)
  798 +
  799 + Raises:
  800 + FdtException if no node found or other error occurs
  801 + """
  802 + return check_err(fdt_property_u32(self._fdtrw, name, val), quiet)
  803 +
  804 + def property_u64(self, name, val, quiet=()):
  805 + """Add a property with a 64-bit value
  806 +
  807 + Write a double-cell value to the device tree in big-endian format
  808 +
  809 + Args:
  810 + name: Name of property to add
  811 + val: Value of property
  812 + quiet: Errors to ignore (empty to raise on all errors)
  813 +
  814 + Raises:
  815 + FdtException if no node found or other error occurs
  816 + """
  817 + return check_err(fdt_property_u64(self._fdtrw, name, val), quiet)
  818 +
  819 + def property_cell(self, name, val, quiet=()):
  820 + """Add a property with a single-cell value
  821 +
  822 + Write a single-cell value to the device tree
  823 +
  824 + Args:
  825 + name: Name of property to add
  826 + val: Value of property
  827 + quiet: Errors to ignore (empty to raise on all errors)
  828 +
  829 + Raises:
  830 + FdtException if no node found or other error occurs
  831 + """
  832 + return check_err(fdt_property_cell(self._fdtrw, name, val), quiet)
  833 +
  834 + def property(self, name, val, quiet=()):
  835 + """Add a property
  836 +
  837 + Write a new property with the given value to the device tree. The value
  838 + is taken as is and is not nul-terminated
  839 +
  840 + Args:
  841 + name: Name of property to add
  842 + val: Value of property
  843 + quiet: Errors to ignore (empty to raise on all errors)
  844 +
  845 + Raises:
  846 + FdtException if no node found or other error occurs
  847 + """
  848 + return check_err(_fdt_property(self._fdtrw, name, val, len(val)), quiet)
  849 +
  850 + def end_node(self, quiet=()):
  851 + """End a node
  852 +
  853 + Use this after adding properties to a node to close it off. You can also
  854 + use the context manager as shown in the FdtSw class comment.
  855 +
  856 + Args:
  857 + quiet: Errors to ignore (empty to raise on all errors)
  858 +
  859 + Raises:
  860 + FdtException if no node found or other error occurs
  861 + """
  862 + return check_err(fdt_end_node(self._fdtrw), quiet)
  863 +
  864 + def finish(self, quiet=()):
  865 + """Finish writing the device tree
  866 +
  867 + This closes off the device tree ready for use
  868 +
  869 + Args:
  870 + quiet: Errors to ignore (empty to raise on all errors)
  871 +
  872 + Raises:
  873 + FdtException if no node found or other error occurs
  874 + """
  875 + return check_err(fdt_finish(self._fdtrw), quiet)
  876 +
  877 + def AddNode(self, name):
  878 + """Create a new context for adding a node
  879 +
  880 + When used in a 'with' clause this starts a new node and finishes it
  881 + afterward.
  882 +
  883 + Args:
  884 + name: Name of node to add
  885 + """
  886 + return NodeAdder(self._fdtrw, name)
  887 +
  888 +
  889 +class NodeAdder():
  890 + """Class to provide a node context
  891 +
  892 + This allows you to add nodes in a more natural way:
  893 +
  894 + with fdtsw.AddNode('name'):
  895 + fdtsw.property_string('test', 'value')
  896 +
  897 + The node is automatically completed with a call to end_node() when the
  898 + context exits.
  899 + """
  900 + def __init__(self, fdt, name):
  901 + self._fdt = fdt
  902 + self._name = name
  903 +
  904 + def __enter__(self):
  905 + check_err(fdt_begin_node(self._fdt, self._name))
  906 +
  907 + def __exit__(self, type, value, traceback):
  908 + check_err(fdt_end_node(self._fdt))
379 909 %}
380 910  
381 911 %rename(fdt_property) fdt_property_func;
... ... @@ -408,6 +938,7 @@
408 938 fdt = fdt; /* avoid unused variable warning */
409 939 }
410 940  
  941 +/* typemap used for fdt_get_property_by_offset() */
411 942 %typemap(out) (struct fdt_property *) {
412 943 PyObject *buff;
413 944  
... ... @@ -430,6 +961,44 @@
430 961 $result = Py_BuildValue("s#", $1, *arg4);
431 962 }
432 963  
  964 +/* typemap used for fdt_setprop() */
  965 +%typemap(in) (const void *val) {
  966 + $1 = PyString_AsString($input); /* char *str */
  967 +}
  968 +
  969 +/* typemap used for fdt_add_reservemap_entry() */
  970 +%typemap(in) uint64_t {
  971 + $1 = PyLong_AsUnsignedLong($input);
  972 +}
  973 +
  974 +/* typemaps used for fdt_next_node() */
  975 +%typemap(in, numinputs=1) int *depth (int depth) {
  976 + depth = (int) PyInt_AsLong($input);
  977 + $1 = &depth;
  978 +}
  979 +
  980 +%typemap(argout) int *depth {
  981 + PyObject *val = Py_BuildValue("i", *arg$argnum);
  982 + resultobj = SWIG_Python_AppendOutput(resultobj, val);
  983 +}
  984 +
  985 +%apply int *depth { int *depth };
  986 +
  987 +/* typemaps for fdt_get_mem_rsv */
  988 +%typemap(in, numinputs=0) uint64_t * (uint64_t temp) {
  989 + $1 = &temp;
  990 +}
  991 +
  992 +%typemap(argout) uint64_t * {
  993 + PyObject *val = PyLong_FromUnsignedLong(*arg$argnum);
  994 + if (!result) {
  995 + if (PyTuple_GET_SIZE(resultobj) == 0)
  996 + resultobj = val;
  997 + else
  998 + resultobj = SWIG_Python_AppendOutput(resultobj, val);
  999 + }
  1000 +}
  1001 +
433 1002 /* We have both struct fdt_property and a function fdt_property() */
434 1003 %warnfilter(302) fdt_property;
435 1004  
... ... @@ -444,6 +1013,14 @@
444 1013 int fdt_boot_cpuid_phys(const void *fdt);
445 1014 int fdt_size_dt_strings(const void *fdt);
446 1015 int fdt_size_dt_struct(const void *fdt);
  1016 +int fdt_property_string(void *fdt, const char *name, const char *val);
  1017 +int fdt_property_cell(void *fdt, const char *name, uint32_t val);
  1018 +
  1019 +/*
  1020 + * This function has a stub since the name fdt_property is used for both a
  1021 + * function and a struct, which confuses SWIG.
  1022 + */
  1023 +int _fdt_property(void *fdt, const char *name, const char *val, int len);
447 1024  
448 1025 %include <../libfdt/libfdt.h>
... ... @@ -36,14 +36,26 @@
36 36  
37 37 import dtb_platdata
38 38  
39   -def run_tests():
40   - """Run all the test we have for dtoc"""
  39 +def run_tests(args):
  40 + """Run all the test we have for dtoc
  41 +
  42 + Args:
  43 + args: List of positional args provided to binman. This can hold a test
  44 + name to execute (as in 'binman -t testSections', for example)
  45 + """
41 46 import test_dtoc
42 47  
43 48 result = unittest.TestResult()
44 49 sys.argv = [sys.argv[0]]
  50 + test_name = args and args[0] or None
45 51 for module in (test_dtoc.TestDtoc,):
46   - suite = unittest.TestLoader().loadTestsFromTestCase(module)
  52 + if test_name:
  53 + try:
  54 + suite = unittest.TestLoader().loadTestsFromName(test_name, module)
  55 + except AttributeError:
  56 + continue
  57 + else:
  58 + suite = unittest.TestLoader().loadTestsFromTestCase(module)
47 59 suite.run(result)
48 60  
49 61 print result
... ... @@ -68,7 +80,7 @@
68 80  
69 81 # Run our meagre tests
70 82 if options.test:
71   - run_tests()
  83 + run_tests(args)
72 84  
73 85 else:
74 86 dtb_platdata.run_steps(args, options.dtb_file, options.include_disabled,
... ... @@ -234,7 +234,6 @@
234 234 be updated.
235 235 """
236 236 if self._offset != my_offset:
237   - #print '%s: %d -> %d\n' % (self.path, self._offset, my_offset)
238 237 self._offset = my_offset
239 238 offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self._offset)
240 239 for subnode in self.subnodes:
... ... @@ -359,7 +358,7 @@
359 358 poffset = libfdt.fdt_first_property_offset(self._fdt, node._offset)
360 359 while poffset >= 0:
361 360 p = self._fdt_obj.get_property_by_offset(poffset)
362   - prop = Prop(node, poffset, p.name, p.value)
  361 + prop = Prop(node, poffset, p.name, p)
363 362 props_dict[prop.name] = prop
364 363  
365 364 poffset = libfdt.fdt_next_property_offset(self._fdt, poffset)
tools/dtoc/test_dtoc.py
... ... @@ -4,7 +4,8 @@
4 4  
5 5 """Tests for the dtb_platdata module
6 6  
7   -This includes unit tests for some functions and functional tests for
  7 +This includes unit tests for some functions and functional tests for the dtoc
  8 +tool.
8 9 """
9 10  
10 11 import collections