[ 0.000000] Booting Linux on physical CPU 0x0000000000 [0x410fd034] [ 0.000000] Linux version 6.7.0-rc4-msm8916 (gcc 12.2.0) [ 0.000000] Machine model: Handsome OpenStick MF800B-E LCD [ 0.000000] Memory: 381MB available [ 0.034521] SPMI bus probe: pm8916@0 [ 0.112003] msm8916-pinctrl 1000000.pinctrl: initialized [ 0.298112] sdhci-msm 7824900.mmc: eMMC 3.6GB detected [ 0.415090] wcn36xx: WCN3620 initialized (WiFi ready) [ 1.203445] pm8916-lbc 200f000.spmi:pmic@0:charger@1000: probe successful [ 1.204112] extcon: USB=1 (phandle swap worked!) [ 1.305667] pm8916-bms-vm 200f000.spmi:pmic@0:battery@4000: probe successful [ 1.512001] USB gadget: RNDIS + ECM configured [ 2.001337] IPv4: wlan0 → 192.168.100.1 (AP mode) [ 2.002001] IPv4: usb0 → 192.168.200.1 (RNDIS) [ 6.112445] qcom-q6v5-mss 4080000.remoteproc: MBA loaded, MPSS active [ 30.445123] qcom-q6v5-mss: THIS IS INTENTIONAL RESET (╯°□°)╯︵ ┻━┻ [ 33.102334] remoteproc0: remote processor recovered █
Wie aus einem 8-Dollar-4G-Modem-Stick ein Linux-Server wurde
Eine Geschichte über IRQ-Konflikte, Soft-Bricks und fragwürdige Lebensentscheidungen
ssh user@192.168.200.1 (USB)192.168.100.1 (WiFi)mmcli -m 0 --simple-connect="apn=<your_apn>"internet • T-Mobile: internet.telekom • Vodafone: web.vodafone.de____________________ / \ | MF800B-E LCD | | ================== | | | 128x128 LCD | | | | GC9107 | | | |______________| | | | | [SIM] | | | | MSM8916 PM8916 | | Cortex-A53 PMIC | | 381MB RAM | | 3.6GB eMMC | | | | [USB-C connector] | \____________________/
„Es kommt nicht auf die Specs an, die du hast. Sondern auf die Specs, um die du herumhackst." — Jeder Embedded-Entwickler, vermutlich
Das OpenStick-Projekt — gestartet von Handsome Yingyang — macht aus billigen 4G-USB-Modems mit Qualcomm-MSM8916-SoC vollwertige Linux-Single-Board-Computer. Quad-Core ARM Cortex-A53 @ 1.2 GHz mit integriertem LTE-Modem, für ein Taschengeld.
| Modell | Typ | MSM8916 | Boot | LTE | Display | Akku | Notizen |
|---|---|---|---|---|---|---|---|
| MF800B-E LCD | MiFi-Hotspot | ✅ | ✅ | ✅ | ✅ | ✅ | Star dieser Seite. FuYi-MF800-Familie, 512 MB RAM |
| UFI001B/C | USB-Stick | ✅ | ✅ | ✅ | — | — | Ursprüngliches OpenStick-Ziel. Hersteller THWC |
| UZ801 (v3) | USB-Stick | ✅ | ✅ | ✅ | — | — | Am besten dokumentiert. Zhihe-Serie, 384 MB RAM |
| UF896 | USB-Router | ✅ | ✅ | ✅ | — | — | Kompakter 4G-Router, 384 MB RAM |
| SP970 | Pocket-WiFi | ✅ | ✅ | ✅ | — | ✅ | Mehrere HW-Revisionen (V3, V10) |
| 🚫 NICHT kompatibel — oft mit MSM8916-Geräten verwechselt | |||||||
| Alcatel IK41VE | USB-Modem | ❌ | — | Nutzt MDM9207 (Qualcomm-IoT-Modem). Kein MSM8916! | |||
| ZTE MF927U | MiFi-Hotspot | ❌ | — | Nutzt ZTE ZX297520V3 (proprietäres SoC). Kein Qualcomm! | |||
| ZTE MF823 | USB-Modem | ❌ | — | Nutzt MDM9215 (reines Qualcomm-Modem). Kein MSM8916! | |||
| Huawei E3372 | USB-Modem | ❌ | — | Nutzt HiSilicon Balong (Hi6921/Hi6930). Kein Qualcomm! | |||
| Vodafone K5160 | USB-Modem | ❌ | — | Umgelabeltes Huawei E3372. HiSilicon Balong, kein MSM8916! | |||
Such nach diesen Keywords auf AliExpress oder Amazon. Preise liegen je nach Verkäufer und Modell bei 8–15 $. Achte darauf, dass im Angebot MSM8916 oder einer der Modellnamen unten steht.
Angebote ändern sich ständig — mit dieser Checkliste findest du das richtige Gerät. Es ist „hit or miss", also vor der Bestellung immer prüfen!
Kein SoC angegeben? Verkäufer weicht aus? → Finger weg. Viele ähnlich benannte Geräte nutzen völlig andere Chipsätze!
8 Monate. 7 Versionen. 1 Soft-Brick. Unendlich viele dmesg | grep-Befehle.
Es begann, wie alle großen Engineering-Projekte, mit der Frage: „Was, wenn ich Debian auf diesen 8-Dollar-Modem-Stick packe?"
$ ssh user@192.168.200.1Welcome to Debian GNU/Linuxopenstick:~$ _
Der Stick, der Internet liefern sollte, braucht jetzt selbst Internet. Ironisch.
Mit einem laufenden Linux-System bewaffnet begann die Erkundung. Display? Akku? Mehrere Distros? Warum nicht alles auf einmal!
128×128 Pixel pures Potenzial. Ein GC9107-SPI-Display, angebunden über BLSP1 QUP3 mit 24 MHz. Der Vendor-Kernel nutzte das uralte Framebuffer-Subsystem. Der Mainline-Kernel nutzt DRM.
„Das Display machen wir später" — berühmte letzte Worte, September 2025
Erzähler: Es war sehr schwer.
Das PM8916-PMIC hat ein integriertes Battery-Management-System (BMS) und einen Linear-Charger. Zwei Kernel-Module existieren. Die Device-Tree-Nodes existieren. Sie sind nur... deaktiviert.
$ cat /proc/device-tree/.../charger@1000/statusdisabled$ cat /proc/device-tree/.../battery@4000/statusdisabled$ # Cool. Cool cool cool.
Nebenbei zeigte die Modem-Firmware-Analyse: Das Debian-Image kam mit 36 Firmware-Dateien. Android hatte 56. Die Rechnung ging nicht auf.
Aber jede Wolke hat einen Silberstreif. Bei der Recovery-Analyse kam endlich DER Bug ans Licht, der den Akku-Support die ganze Zeit blockiert hatte:
genirq: Flags mismatch irq 30 00002003 (pm8916_lbc) vs. 00002003 (usb-detect@1300) pm8916-lbc: probe failed with error -16
Übersetzung: Laderegler und USB-Detektor wollen beide dieselbe Interrupt-Leitung. Der Kernel sagt „es kann nur einen geben". Keiner hat IRQF_SHARED gesetzt. Klassiker.
„Beschrifte deine Backup-Images. Oder lass es. YOLO." — Lektion #47 aus dem Embedded-Development-Handbuch
Nach Monaten des Kämpfens kam der Durchbruch durchs Verstehen des Bootloaders. Das originale Android-aboot landete immer im Fastboot-Modus, statt wirklich zu booten. Lösung? Den Bootloader von OpenWRT ausleihen.
Der Modem-Stick kann jetzt... ein Modem sein. Unter Linux. Revolutionär.
Erinnerst du dich an den IRQ-Konflikt aus v4.0? Vier Monate später entpuppte sich die Lösung als elegante Device-Tree-Operation.
Indem der Laderegler den phandle des USB-Detektors bekommt (0x8b), zeigt jede Referenz im USB-Subsystem (extcon = <0x8b>) jetzt auf den Laderegler. Der Laderegler liefert sowohl USB-Erkennung ALS AUCH Akku-Laden. Ein Treiber, ein IRQ, null Konflikte.
$ ls /sys/class/power_supply/ pm8916-bms-vm pm8916-lbc-chgr $ cat /sys/class/power_supply/pm8916-lbc-chgr/uevent POWER_SUPPLY_TYPE=USB POWER_SUPPLY_ONLINE=1 POWER_SUPPLY_CONSTANT_CHARGE_CURRENT=990000 $ cat /sys/class/extcon/*/state USB=1
Beide Power-Supplies aktiv. Extcon liefert USB-Erkennung. USB-Gadget läuft. Keine IRQ-Konflikte. Chef's kiss.
Der Qualcomm-Modem-Prozessor hat offenbar bei jedem Boot eine Identitätskrise:
qcom-q6v5-mss: fatal error received: THIS IS INTENTIONAL RESET, NO RAMDUMP EXPECTED
Es stürzt 30 Sekunden nach dem Boot absichtlich selbst ab. ModemManager verliert den Überblick. Lösung: ein systemd-Service, der die Sinnkrise abwartet und ModemManager dann sanft daran erinnert, dass das Modem noch existiert.
$ systemctl status modem-fix Active: active (exited) # "I checked. The modem is fine. It just needed a moment."
Nach 6 Monaten „das Display machen wir später" lebt der 128×128-GC9107-SPI-Screen. Und er hat eine voll interaktive UI. Und einen VNC-Desktop. Denn warum bei einem Display aufhören?
Ein modularer Python-Daemon treibt das 128×128-Display mit vollem Status-Screen und interaktivem Menüsystem. Ein Knopf, sie zu knechten — kurzer Druck zum Durchschalten, langer Druck zum Auswählen.
Der Daemon entstand als einzelner 2.568-Zeilen-Monolith und wurde dann in 8 saubere Module mit DAG-Abhängigkeitskette refaktoriert. Null zirkuläre Imports. Software-Engineering auf einem Gerät von der Größe eines USB-Sticks.
constants.py ─── hardware.py (FrameBuffer, Backlight, Input)
│ ├── graphics.py (text, shapes, 17 icons)
│ │ ├── tiles.py (menu tiles)
│ │ └── status.py (LTE, WiFi, battery, throughput)
│ └── homeassistant.py (HA REST API)
│ └── renderer.py (12 screen draw methods)
│ └── daemon.py (state machine, entry point)
TigerVNC + Openbox laufen nativ auf dem Stick. 800×600, 24-Bit-Farbe, von jedem Gerät erreichbar. Der Display-Daemon kann den VNC-Framebuffer in Echtzeit auf den winzigen SPI-Screen spiegeln.
Ein voller grafischer Desktop auf einem 8-Dollar-Modem-Stick. Was für eine Zeit, am Leben zu sein.
Der Hotspot starb bei jedem Daemon-Neustart. Ursache? Der Backlight-Treiber mappte per /dev/mem 48 MB physisches MMIO — den gesamten Low-Address-SoC-Registerbereich inklusive Clocks, GPIOs und SPMI-Bus.
# Before (broken): maps 12,288 pages of MMIO mmap(fd, 0x3000000, offset=0) # 48 MB from address 0 # After (working): maps 1 page, just the MPP4 channel mmap(fd, 0x1000, offset=0x26F0000) # 4 KB at the exact register
Eine 12.000-fache Reduktion des gemappten Speichers. Das WLAN überlebte.
Was in einem Gerät steckt, das kleiner ist als dein Daumen.
HOST PC MF800B-E LCD OpenStick
------- ----------------------
USB
[Terminal] ----[RNDIS/gadget]---- [Debian Linux]
ssh user@ Kernel 6.7.0-rc4-msm8916
192.168.200.1 |
+-- [WiFi AP] --- 192.168.100.1
| wlan0 (WCN3620)
|
+-- [LTE Modem] --- internet
| wwan0 (Q6 remoteproc)
| ModemManager + NetworkManager
|
+-- [PMIC PM8916] --- SPMI Bus
| +- charger@1000 (pm8916-lbc)
| | extcon USB + charging
| +- battery@4000 (pm8916-bms-vm)
| | voltage, SOC, health
| +- adc@3100 (VADC)
| +- gpio, rtc, temp-alarm
|
+-- [Display UI] --- SPI (/dev/fb0)
| 128x128 GC9107 (XRGB8888)
| openstick-ui.service (8 modules)
| Status, menus, HA control
|
+-- [VNC Desktop] --- port 5901
| TigerVNC + Openbox (800x600)
| ~96 MB RAM footprint
|
+-- [LEDs]
Red/Green/Blue status
Von Power-On bis ping google.com — eine Reise über tausend Interrupts.
3,6 GB Flash-Speicher. 22 Partitionen. Jedes Byte verbucht.
# Partitionstabelle ausgeben (der Moment der Wahrheit) $ edl printgpt --memory=emmc Parsing Qualcomm Sahara / Firehose protocol... Name Offset Size Flags ───────────────────────────────────────────────── sbl1 0x00000000 128.0 KB bootable tz 0x00020000 256.0 KB hyp 0x00060000 128.0 KB rpm 0x00080000 128.0 KB aboot 0x000A0000 1.0 MB bootable boot 0x001A0000 32.0 MB bootable modem 0x021A0000 64.0 MB system 0x061A0000 1.6 GB userdata 0x261A0000 1.2 GB cache 0x6E1A0000 128.0 MB recovery 0x761A0000 32.0 MB ───────────────────────────────────────────────── 22 Partitionen gefunden. Keine Rückgabe.
„3,6 GB schienen genug Platz. Dann sagte Debian ‚halt mal mein dpkg'." — Die traurige Geschichte von apt autoremove
Wenn etwas schiefgeht (und das wird es), ist EDL dein Freund.
# Ganzes eMMC lesen (der „oh nein"-Knopf) edl rf backup.bin --memory=emmc # Einzelne Partitionen lesen (der „chirurgische" Ansatz) edl rl partitions/ --memory=emmc --genxml # Alles zurückschreiben (der „Rückgängig"-Knopf) edl wf backup.bin --memory=emmc # Partitionstabelle ausgeben (der „was sehe ich da"-Knopf) edl printgpt --memory=emmc
Befehle getippt. Verstand verloren. Eine Hommage an das Handwerkszeug.
Diese Website verwendet keine Tracker, keine Cookies und keine Analyse-Tools. Es werden nur technisch notwendige Server-Logs erfasst (IP-Adresse, Zeitstempel, User-Agent). Diese Daten werden nach 14 Tagen automatisch gelöscht, nicht an Dritte weitergegeben und dienen ausschließlich dem technischen Betrieb der Seite.