e0bc4785e9
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.
105 lines
3.2 KiB
Python
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
|