# Copyright (c) 2016, Xilinx, Inc.
# SPDX-License-Identifier: BSD-3-Clause
import os
SYSTEM_DEVICE_TREE_PATH = '/sys/kernel/config/device-tree/overlays'
[docs]def get_dtbo_path(bitfile_name):
"""This method returns the path of the dtbo file.
For example, the input "/home/xilinx/pynq/overlays/base/base.bit" will
lead to the result "/home/xilinx/pynq/overlays/base/base.dtbo".
Parameters
----------
bitfile_name : str
The absolute path of the bit file.
Returns
-------
str
The absolute path of the dtbo file.
"""
return os.path.splitext(bitfile_name)[0] + '.dtbo'
[docs]def get_dtbo_base_name(dtbo_path):
"""This method returns the base name of the dtbo file.
For example, the input "/home/xilinx/pynq/overlays/name1/name2.dtbo" will
lead to the result "name2".
Parameters
----------
dtbo_path : str
The absolute path of the dtbo file.
Returns
-------
str
The base name of the dtbo file.
"""
return dtbo_path.split('/')[-1].split('.')[0]
[docs]class DeviceTreeSegment:
"""This class instantiates the device tree segment object.
Attributes
----------
dtbo_name : str
The base name of the dtbo file as a string.
dtbo_path : str
The absolute path to the dtbo file as a string.
"""
def __init__(self, dtbo_path):
"""Return a new DeviceTreeSegment object.
Parameters
----------
dtbo_path : str
The absolute path to the dtbo file as a string.
"""
if not os.path.isfile(dtbo_path):
raise IOError('The dtbo file {} does not exist.'.format(dtbo_path))
self.dtbo_path = dtbo_path
self.dtbo_name = get_dtbo_base_name(dtbo_path)
self.sysfs_dir = os.path.join(SYSTEM_DEVICE_TREE_PATH, self.dtbo_name)
[docs] def is_dtbo_applied(self):
"""Show if the device tree segment has been applied.
Returns
-------
bool
True if the device tree status shows `applied`.
"""
if not os.path.exists(self.sysfs_dir):
return False
with open(os.path.join(self.sysfs_dir, 'status'), 'r') as f:
return f.read() == 'applied\n'
[docs] def insert(self):
"""Insert the dtbo file into the device tree.
The method will raise an exception if the insertion has failed.
"""
os.makedirs(self.sysfs_dir, exist_ok=True)
with open(self.dtbo_path, 'rb') as f:
dtbo_data = f.read()
with open(os.path.join(self.sysfs_dir, 'dtbo'),
'wb', buffering=0) as f:
f.write(dtbo_data)
# The only way to detect a DTBO insert failure is to try and
# read back the contents of the dtbo attribute and see if
# it is non-empty
with open(os.path.join(self.sysfs_dir, 'dtbo'),
'rb', buffering=0) as f:
# The entire DTBO file has to be read in a single syscall
# otherwise and IO error will occur
read_back = f.read(1024*1024)
if read_back != dtbo_data:
raise RuntimeError('Device tree {} cannot be applied'.format(
self.dtbo_name))
if not self.is_dtbo_applied():
raise RuntimeError('Device tree {} cannot be applied.'.format(
self.dtbo_name))
[docs] def remove(self):
"""Remove the dtbo file from the device tree.
"""
if os.path.exists(self.sysfs_dir):
os.rmdir(self.sysfs_dir)