Files
diskos/diskos_installer/platform_probe.py
T
b0hemia e0bc4785e9 diskOS installer: initial public beta
Flashes the diskOS custom UI onto the FiiO Snowsky Disc over Ingenic mask-ROM USB,
building the image from your own stock firmware. Runs from source via install.sh.
2026-08-26 15:26:14 +10:00

105 lines
3.2 KiB
Python

"""Host OS/arch detection and Snowsky-Disc device presence checks.
Device USB identities we care about:
- Ingenic X2000 mask-ROM (flashing mode): VID:PID 0a108:eaef (a108:eaef)
- normal running device (not used for flashing) is a different id.
We enumerate USB via pyusb (bundled) so we don't depend on `lsusb` being present.
"""
import platform
import sys
MASKROM_VID = 0x0a108 & 0xFFFF # printed as a108 by lsusb; VID field is 0xa108
MASKROM_PID = 0xeaef
# lsusb shows "a108:eaef"; libusb reports idVendor=0xa108 idProduct=0xeaef
MASKROM_VID = 0xa108
def host():
"""Return (os_key, arch_key) e.g. ('linux','x86_64') / ('macos','arm64')."""
sysname = platform.system().lower()
if sysname == "darwin":
os_key = "macos"
elif sysname == "linux":
os_key = "linux"
else:
os_key = sysname # 'windows' etc. - unsupported for now
machine = platform.machine().lower()
arch = {
"x86_64": "x86_64", "amd64": "x86_64",
"arm64": "arm64", "aarch64": "arm64",
}.get(machine, machine)
return os_key, arch
def host_tag():
o, a = host()
return f"{o}-{a}"
def is_supported():
o, _ = host()
return o in ("linux", "macos")
def _bundled_libusb_backend():
"""A pyusb libusb1 backend pointed at OUR bundled libusb, so USB enumeration
works in the frozen app even when the system has no libusb. Returns a backend
or None (caller falls back to pyusb's default search)."""
try:
import glob
import os
import usb.backend.libusb1 as libusb1
from . import bundle
libdir = os.path.join(bundle.vendor_dir(), "lib")
# macOS dylib or Linux .so, whatever we bundled
for pat in ("libusb-1.0*.dylib", "libusb-1.0.so*", "libusb-1.0*"):
hits = sorted(glob.glob(os.path.join(libdir, pat)))
if hits:
return libusb1.get_backend(find_library=lambda _n, _p=hits[0]: _p)
except Exception:
pass
return None
def _maskrom_count_pyusb():
"""Count devices in Ingenic mask-ROM mode via pyusb. Returns int or None if
pyusb/backend is unavailable."""
try:
import usb.core # pyusb (bundled)
except Exception:
return None
try:
backend = _bundled_libusb_backend() # prefer our bundled libusb
devs = list(usb.core.find(find_all=True, idVendor=MASKROM_VID,
idProduct=MASKROM_PID, backend=backend))
return len(devs)
except Exception:
return None
def _maskrom_count_lsusb():
"""Fallback: parse `lsusb` if present (Linux)."""
import shutil
import subprocess
if not shutil.which("lsusb"):
return None
try:
out = subprocess.run(["lsusb"], capture_output=True, text=True, timeout=10).stdout
except Exception:
return None
return sum(1 for ln in out.splitlines() if "a108:eaef" in ln.lower())
def maskrom_count():
"""How many devices are currently in mask-ROM mode. Prefers pyusb, falls back
to lsusb, returns -1 if neither is available (caller should warn)."""
n = _maskrom_count_pyusb()
if n is not None:
return n
n = _maskrom_count_lsusb()
if n is not None:
return n
return -1