67 lines
1.7 KiB
Python
67 lines
1.7 KiB
Python
#!/usr/bin/env python3
|
|||
|
|
# -*- coding: utf-8 -*-
|
||
|
|
"""从设备树复算 gpio-in-N 对应的全局 GPIO 号。"""
|
||
|
|
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
from .config import DEVICETREE_BASE
|
||
|
|
|
||
|
|
|
||
|
|
def _read_be32(path: Path, offset: int = 0):
|
||
|
|
try:
|
||
|
|
data = path.read_bytes()
|
||
|
|
except OSError:
|
||
|
|
return None
|
||
|
|
if len(data) < offset + 4:
|
||
|
|
return None
|
||
|
|
return int.from_bytes(data[offset:offset + 4], "big")
|
||
|
|
|
||
|
|
|
||
|
|
def derive_gpio(n: int, base_dir: str = DEVICETREE_BASE):
|
||
|
|
"""从设备树复算 IN<n> 的全局 GPIO 号。
|
||
|
|
|
||
|
|
返回 (gpio_num, label, pin) 或 None。
|
||
|
|
"""
|
||
|
|
base = Path(base_dir)
|
||
|
|
f = base / f"gpio-in-{n}" / "control-gpios"
|
||
|
|
if not f.exists():
|
||
|
|
return None
|
||
|
|
|
||
|
|
try:
|
||
|
|
data = f.read_bytes()
|
||
|
|
except OSError:
|
||
|
|
return None
|
||
|
|
if len(data) < 8:
|
||
|
|
return None
|
||
|
|
|
||
|
|
ph = int.from_bytes(data[0:4], "big")
|
||
|
|
pin = int.from_bytes(data[4:8], "big")
|
||
|
|
|
||
|
|
# phandle -> gpio-controller 节点
|
||
|
|
ctrl = None
|
||
|
|
for c in base.glob("gpio@*/gpio-controller@*"):
|
||
|
|
cph = _read_be32(c / "phandle")
|
||
|
|
if cph == ph:
|
||
|
|
ctrl = c
|
||
|
|
break
|
||
|
|
if ctrl is None:
|
||
|
|
return None
|
||
|
|
|
||
|
|
bank = ctrl.parent.name
|
||
|
|
if bank.startswith("gpio@"):
|
||
|
|
bank = bank[len("gpio@"):]
|
||
|
|
label = f"{bank}.gpio"
|
||
|
|
|
||
|
|
# label -> gpiochip base
|
||
|
|
gpio_class = Path("/sys/class/gpio")
|
||
|
|
if not gpio_class.exists():
|
||
|
|
return None
|
||
|
|
for g in gpio_class.glob("gpiochip*"):
|
||
|
|
try:
|
||
|
|
if (g / "label").read_text().strip() == label:
|
||
|
|
chip_base = int((g / "base").read_text().strip())
|
||
|
|
return chip_base + pin, label, pin
|
||
|
|
except (OSError, ValueError):
|
||
|
|
continue
|
||
|
|
return None
|