python-periphery
python-periphery copied to clipboard
Add Userspace I/O class?
Can you consider to implement generic uio in your python periphery? As i see your MMIO implementation can serve the reg mapping for a /dev/uioX, only the IRQ waiting which is needed to implemented for this new class.
See this examples:
- https://github.com/ikwzm/FPGA-SoC-Linux-Example-1-ZYBO-Z7/blob/master/uio.py
- https://tuxengineering.com/blog/2020/08/15/Linux-Userspace.html
@vsergeev What do you think, is it fine?
import os
from periphery import MMIO
def get_uio_dev(uio_name):
for dev in os.listdir("/sys/class/uio"):
with open("/sys/class/uio/" + dev + "/name", "r") as f:
name = f.readline().strip()
if name == uio_name:
return "/dev/" + dev
return None
def get_uio_size(uio_dev):
size = None
with open("/sys/class/uio/" + uio_dev + "/maps/map0/size", "r") as f:
size = int(f.readline().strip(), 16)
return size
class UIO(MMIO):
def __init__(self, name):
uio_dev = get_uio_dev(name)
uio_size = get_uio_size(uio_dev)
super().__init__(0x00, uio_size, uio_dev)
# _fdesc should be opened in MMIO's __init__() instead
self._fdesc = os.open(uio_dev, os.O_RDWR | os.O_SYNC)
def enable_irq(self):
os.write(self._fdesc, bytes([1, 0, 0, 0]))
def disable_irq(self):
os.write(self._fdesc, bytes([0, 0, 0, 0]))
def wait_irq(self):
os.read(self._fdesc, 4)
def close(self):
os.close(self._fdesc)
super().close()
It's a good idea -- could use a few more getters with the UIO info. One thing to decide is whether or not to abstract away the interrupt counts -- e.g. should wait_irq()
return the raw interrupt counter or the number of interrupts that occurred since the last wait.
It's a good idea -- could use a few more getters with the UIO info. One thing to decide is whether or not to abstract away the interrupt counts -- e.g. should
wait_irq()
return the raw interrupt counter or the number of interrupts that occurred since the last wait.
What getter you think is need more?
Implementation for return missed interrupts: https://www.kernel.org/doc/html/v4.17/driver-api/uio-howto.html#how-uio-works
import os
from periphery import MMIO
def get_uio_dev(uio_name):
for dev in os.listdir("/sys/class/uio"):
with open("/sys/class/uio/" + dev + "/name", "r") as f:
name = f.readline().strip()
if name == uio_name:
return "/dev/" + dev
return None
def get_uio_size(uio_dev):
size = None
with open("/sys/class/uio/" + uio_dev + "/maps/map0/size", "r") as f:
size = int(f.readline().strip(), 16)
return size
class UIO(MMIO):
def __init__(self, name):
uio_dev = get_uio_dev(name)
uio_size = get_uio_size(uio_dev)
super().__init__(0x00, uio_size, uio_dev)
# _fdesc should be opened in MMIO's __init__() instead
self._fdesc = os.open(uio_dev, os.O_RDWR | os.O_SYNC)
self.irq_total_count = 0
self._irq_last_count = 0
def enable_irq(self):
os.write(self._fdesc, bytes([1, 0, 0, 0]))
def disable_irq(self):
os.write(self._fdesc, bytes([0, 0, 0, 0]))
def wait_irq(self):
self.irq_total_count = os.read(self._fdesc, 4)
irq_count = self.irq_total_count - self._irq_last_count
self._irq_last_count = self.irq_total_count
# return 1 or number of missed interrupts
return irq_count
def close(self):
os.close(self._fdesc)
super().close()