|
| 1 | +from pathlib import Path |
| 2 | +from subprocess import run |
| 3 | +from sys import argv |
| 4 | + |
| 5 | +user_group = None if len(argv) < 2 else argv[1] |
| 6 | +input_group = user_group or "input" |
| 7 | +video_group = user_group or "video" |
| 8 | + |
| 9 | +RULES = f"""\ |
| 10 | +KERNEL=="uinput", SUBSYSTEM=="misc" GROUP="{input_group}", MODE="0666" |
| 11 | +KERNEL=="event[0-9]*", SUBSYSTEM=="input" GROUP="{input_group}", MODE="0666" |
| 12 | +
|
| 13 | +KERNEL=="uleds", GROUP="input", MODE="0664" |
| 14 | +SUBSYSTEM=="leds", ACTION=="add", RUN+="/bin/chmod -R g=u,o=u /sys%p" |
| 15 | +SUBSYSTEM=="leds", ACTION=="change", ENV{{TRIGGER}}!="none", RUN+="/bin/chmod -R g=u,o=u /sys%p" |
| 16 | +
|
| 17 | +SUBSYSTEM=="video4linux" GROUP="{video_group}", MODE="0666" |
| 18 | +
|
| 19 | +KERNEL=="gpiochip[0-9]*", SUBSYSTEM=="gpio", GROUP="{input_group}", MODE="0666" |
| 20 | +""" |
| 21 | + |
| 22 | +MODULES = { |
| 23 | + "uinput": "", |
| 24 | + "uleds": "", |
| 25 | + "gpio-sim": "", |
| 26 | + "vivid": "n_devs=1 node_types=0xe1d3d vid_cap_nr=190 vid_out_nr=191 meta_cap_nr=192 meta_out_nr=193", |
| 27 | +} |
| 28 | + |
| 29 | + |
| 30 | +def loaded_modules(): |
| 31 | + return {line.split()[0] for line in Path("/proc/modules").read_text().splitlines()} |
| 32 | + |
| 33 | + |
| 34 | +LOADED_MODULES = loaded_modules() |
| 35 | + |
| 36 | + |
| 37 | +def handle_rules(): |
| 38 | + print("Checking rules") |
| 39 | + rules = Path("/etc/udev/rules.d/99-linuxpy.rules") |
| 40 | + if rules.exists() and RULES in rules.read_text(): |
| 41 | + print(" Already prepared") |
| 42 | + else: |
| 43 | + print(f" Writing rules {rules}") |
| 44 | + rules.write_text(RULES) |
| 45 | + print(" Reloading rules") |
| 46 | + run("udevadm control --reload-rules".split()) |
| 47 | + run("udevadm trigger".split()) |
| 48 | + |
| 49 | + |
| 50 | +def handle_module(mod_name): |
| 51 | + print(f"Handling {mod_name}") |
| 52 | + if mod_name in LOADED_MODULES: |
| 53 | + print(f" Unloading {mod_name}") |
| 54 | + run(f"modprobe -r {mod_name}".split()) |
| 55 | + args = MODULES[mod_name] |
| 56 | + print(f" Loading {mod_name}") |
| 57 | + run(f"modprobe {mod_name} {args}".split()) |
| 58 | + |
| 59 | + |
| 60 | +def handle_gpio_sim(): |
| 61 | + print("Preparing GPIO sim") |
| 62 | + mounts = Path("/proc/mounts") |
| 63 | + for dtype, mpath, fstype, *_ in mounts.read_text().splitlines(): |
| 64 | + if dtype == "configfs" and fstype == "configfs": |
| 65 | + CONFIGFS_PATH = Path(mpath) |
| 66 | + else: |
| 67 | + CONFIGFS_PATH = Path("/sys/kernel/config/gpio-sim") |
| 68 | + |
| 69 | + def Line(name, direction=None): |
| 70 | + result = {"name": name} |
| 71 | + if direction: |
| 72 | + result["hog"] = {"name": f"{name}-hog", "direction": direction} |
| 73 | + return result |
| 74 | + |
| 75 | + cfg = { |
| 76 | + "name": "chip99", |
| 77 | + "banks": [ |
| 78 | + { |
| 79 | + "lines": [ |
| 80 | + Line("L-I0"), |
| 81 | + Line("L-I1"), |
| 82 | + Line("L-I2", "input"), |
| 83 | + Line("L-O0", "output-high"), |
| 84 | + Line("L-O1", "output-low"), |
| 85 | + Line("L-O2"), |
| 86 | + ] |
| 87 | + }, |
| 88 | + ], |
| 89 | + } |
| 90 | + |
| 91 | + def mkdir(path): |
| 92 | + print(f" Creating {path}") |
| 93 | + path.mkdir() |
| 94 | + |
| 95 | + path = CONFIGFS_PATH / cfg["name"] |
| 96 | + live = path / "live" |
| 97 | + |
| 98 | + # clean up first |
| 99 | + if path.exists(): |
| 100 | + live.write_text("0") |
| 101 | + for directory, _, _ in path.walk(top_down=False): |
| 102 | + directory.rmdir() |
| 103 | + |
| 104 | + mkdir(path) |
| 105 | + for bank_id, bank in enumerate(cfg["banks"]): |
| 106 | + lines = bank["lines"] |
| 107 | + |
| 108 | + bpath = path / f"gpio-bank{bank_id}" |
| 109 | + mkdir(bpath) |
| 110 | + blabel = bank.get("name", f"gpio-sim-bank{bank_id}") |
| 111 | + |
| 112 | + (bpath / "num_lines").write_text("16") |
| 113 | + (bpath / "label").write_text(blabel) |
| 114 | + for line_id, line in enumerate(lines): |
| 115 | + lpath = bpath / f"line{line_id}" |
| 116 | + mkdir(lpath) |
| 117 | + (lpath / "name").write_text(line.get("name", f"L-{line_id}")) |
| 118 | + if hog := line.get("hog"): |
| 119 | + hpath = lpath / "hog" |
| 120 | + mkdir(hpath) |
| 121 | + (hpath / "name").write_text(hog["name"]) |
| 122 | + (hpath / "direction").write_text(hog["direction"]) |
| 123 | + |
| 124 | + live.write_text("1") |
| 125 | + |
| 126 | + |
| 127 | +handle_rules() |
| 128 | + |
| 129 | +for mod_name in MODULES: |
| 130 | + handle_module(mod_name) |
| 131 | + |
| 132 | +handle_gpio_sim() |
0 commit comments