Files

78 lines
2.7 KiB
Python
Executable File

#!/usr/bin/env python3
"""Зонд конфиг-канала GANSS ARDOR_Katana (0c45:8006) через hidraw ioctl.
HIDIOCGFEATURE(len) = _IOWR('H', 0x07, len) — размер кодируется в номере ioctl.
Для состояния клавиатуры зонд безопасен: только GET_FEATURE-запросы,
ничего не записывается.
Использование: misc/probe.py [hidrawN]
(по умолчанию — автоопределение всех hidraw-узлов клавиатуры)
"""
import array
import fcntl
import glob
import os
import struct
import sys
# размеры буфера, которые пробуем по очереди для каждого report id
PROBE_SIZES = (33, 65, 21, 17)
def hid_iocgfeature(size: int) -> int:
"""Номер ioctl _IOWR('H', 0x07, size) для чтения feature-репорта."""
return (3 << 30) | (size << 16) | (0x48 << 8) | 0x07
def find_katana_hidraws() -> list[str]:
"""Имена всех hidraw-узлов клавиатуры (0C45:8006)."""
links = glob.glob("/sys/bus/hid/devices/0003:0C45:8006.*/hidraw/hidraw*")
return sorted(os.path.basename(link) for link in links)
def read_report_id(device_path: str, report_id: int, size: int):
"""Прочитать feature-репорт; None при ошибке (нет такого rid и т.п.)."""
fd = os.open(device_path, os.O_RDWR)
try:
buf = array.array("B", bytes(1 + size)) # первый байт = report id
buf[0] = report_id
res = fcntl.ioctl(fd, hid_iocgfeature(len(buf)), buf)
n = struct.unpack("i", res[:4])[0] # ioctl возвращает [count, данные]
return bytes(res[4:4 + n])
except OSError:
return None
finally:
os.close(fd)
def hexs(data: bytes) -> str:
"""Байты в строку вида 'aa bb cc'."""
return " ".join(f"{x:02x}" for x in data)
def main():
targets = [sys.argv[1]] if len(sys.argv) > 1 else find_katana_hidraws()
if not targets:
raise SystemExit("GANSS ARDOR_Katana hidraw not found")
for name in targets:
path = f"/dev/{name}"
print(f"=== {path} ===")
for rid in range(0x01, 0x09):
found = None
for size in PROBE_SIZES:
data = read_report_id(path, rid, size)
if data:
found = (size, data)
break
if found:
size, data = found
print(f" GET_FEATURE id=0x{rid:02x} req_size={size}: "
f"{hexs(data)} ({len(data)} bytes)")
else:
print(f" GET_FEATURE id=0x{rid:02x}: empty")
if __name__ == "__main__":
sys.exit(main())