m1n1/proxyclient/m1n1/hostutils.py
Martin Povišer 4a61e3d50d m1n1.hostutils: Support accesses wider than kernel granule
Signed-off-by: Martin Povišer <povik@protonmail.com>
2022-08-30 22:29:41 +09:00

96 lines
3.1 KiB
Python

# SPDX-License-Identifier: MIT
from pathlib import Path
import os
class KernelRegmapAccessor:
def __init__(self, name):
self.path = self._find_path(name)
self.read_ranges()
self.read_linelen()
@classmethod
def _find_path(cls, name):
basedir = Path("/sys/kernel/debug/regmap")
if (path := Path(name)).exists():
return path
elif (path := basedir.joinpath(name)).exists():
return path
elif name in (available := cls._list_regmaps(basedir)):
return available[name]
else:
raise ValueError(f"kernel regmap not found: {name}")
@classmethod
def _list_regmaps(cls, basedir):
return {
p.joinpath("name").open("rb").read().strip().decode(): p
for p in basedir.iterdir() if p.is_dir()
}
def open_node(self, name, mode="rb", **kwargs):
return self.path.joinpath(name).open(mode, **kwargs)
def read_ranges(self):
with self.open_node("range") as f:
self.ranges = [
range(int(a, 16), int(b, 16) + 1)
for a, b in (l.strip().split(b"-") for l in f)
]
def read_linelen(self):
with self.open_node("registers", buffering=0) as f:
l = f.read(64).split(b"\n")[0]
valstr = l.split(b":")[1].strip()
self.linelen = len(l) + 1
self.working_width = len(valstr) * 4
def _find_off(self, reg):
off = 0
for r in self.ranges:
if reg >= r.stop:
off += r.stop - r.start
else:
off += reg - r.start
break
if reg not in r:
raise ValueError(f"register {reg:04x} out of range")
return off * self.linelen
def _read(self, reg, width=None):
assert width == self.working_width
with self.open_node("registers", buffering=0) as f:
f.seek(self._find_off(reg))
l = f.read(self.linelen)
regstr, valstr = l.split(b":")
assert int(regstr, 16) == reg
return int(valstr, 16)
def read(self, reg, width=None):
assert width % self.working_width == 0
ret = 0
for off in range(0, width // 8, self.working_width // 8):
ret |= self._read(reg + off, self.working_width) << (8 * off)
return ret
def _write(self, reg, val, width=None):
assert width == self.working_width
with self.open_node("registers", mode="wb") as f:
f.write(f"{reg:x} {val:x}".encode())
def write(self, reg, val, width=None):
assert width % self.working_width == 0
for off in range(0, width // 8, self.working_width // 8):
self._write(reg + off, val >> (8 * off), self.working_width)
def require_debugfs():
if os.path.ismount("/sys/kernel/debug"):
return
os.system("mount -t debugfs none /sys/kernel/debug")
if __name__ == "__main__":
require_debugfs()
from m1n1.hw.codecs import TAS5770Regs
tas = TAS5770Regs(KernelRegmapAccessor("tas2770"), 0)
import code
code.interact(local=locals())