"""USB-Geräte-Erkennung über VID:PID. Erkennt die wichtigsten Hersteller-Modi und ordnet sie einem semantischen Status zu, damit Workflows wissen, in welchem Modus das Gerät gerade ist. """ from __future__ import annotations from dataclasses import dataclass import usb.core import usb.util @dataclass(frozen=True) class DeviceMode: label: str vendor: str notes: str = "" # (vid, pid) -> Modus KNOWN: dict[tuple[int, int], DeviceMode] = { # Huawei / Kirin (0x12D1, 0x1100): DeviceMode("kirin-dload", "Huawei", "Kirin Download-Mode, wartet auf xloader via hisi-idt"), (0x12D1, 0x1052): DeviceMode("huawei-fastboot-d", "Huawei", "Erweiterter Fastboot-Mode (nach xloader)"), (0x12D1, 0x3609): DeviceMode("kirin-dload-alt", "Huawei", "Kirin DLOAD alternative PID"), (0x12D1, 0x107E): DeviceMode("huawei-hisuite", "Huawei", "HiSuite/MTP-Modus, kein Recovery-Zugriff"), # Google / Android Standard (0x18D1, 0x4EE0): DeviceMode("fastboot", "Google", "Standard-Fastboot"), (0x18D1, 0x4EE7): DeviceMode("adb", "Google", "ADB"), # MediaTek (0x0E8D, 0x0003): DeviceMode("mtk-preloader", "MediaTek", "Preloader (DA-Mode möglich)"), (0x0E8D, 0x2000): DeviceMode("mtk-brom", "MediaTek", "BROM — Ziel für mtkclient/kamakiri"), # Qualcomm EDL (0x05C6, 0x9008): DeviceMode("qc-edl", "Qualcomm", "Emergency Download (Firehose-fähig)"), } @dataclass class FoundDevice: vid: int pid: int mode: DeviceMode bus: int address: int def __str__(self) -> str: return (f"[{self.bus:03d}:{self.address:03d}] " f"{self.vid:04x}:{self.pid:04x} {self.mode.vendor} " f"{self.mode.label}") def scan() -> list[FoundDevice]: """Alle bekannten Hersteller-Modi auflisten, die gerade angeschlossen sind.""" found: list[FoundDevice] = [] for dev in usb.core.find(find_all=True): key = (dev.idVendor, dev.idProduct) mode = KNOWN.get(key) if mode is None: continue found.append(FoundDevice( vid=dev.idVendor, pid=dev.idProduct, mode=mode, bus=dev.bus, address=dev.address, )) return found def find_first(label: str) -> FoundDevice | None: for d in scan(): if d.mode.label == label: return d return None