Watch
1
0
Fork
You've already forked SouveraineOS
0
SouveraineOS/USB/README.md

197 lines
12 KiB
Markdown

# USB — the Pixel 3 as a KVM device
## Current — 2026-08-07
The direction is settled: another computer sends its display **into** the
phone over GUD; the phone returns keyboard, pointer and touch as boot HID.
The same composite keeps NCM for control and carries a smoo FunctionFS
responder for host-backed storage. This is not the earlier UVC/VNC sketch.
| Piece | Current state |
|---|---|
| Display in | `souveraine-usb-kvm`: GUD FunctionFS responder, RGB565 surface on Wayland |
| Hands back | Boot keyboard + relative pointer; window keyboard, mouse and touch become HID reports |
| Storage | `smoo-gadget` FunctionFS responder; `ublk_drv` on the phone |
| Control link | NCM remains in the composite |
| Mode owner | `usb-signaller` exposes `kvm_mode`; GUD and smoo readiness gate the bind, and failure restores the prior mode |
| Human/agent surface | `sessiond` owns the audited `usb` / `set_usb_mode` verbs; held-power **Power Options** exposes HID and full KVM |
| Canonical source | receiver/session/UI/package in `~/Projects/souveraine`; device mechanism in `~/Projects/usb-signaller`; package recipes in Pixel3Arch |
| Build proof | full ARM64 release receiver and sessiond built on ArchDev; receiver tests + strict Clippy pass |
| Phone | **Not installed yet.** Live phone still has `usb-signaller 0.3.1-3`, no `smoo`, and advertises no HID/KVM mode |
TASK-62 owns the package and glass landing. The material below is the
2026-08-04 exploration ledger; it remains useful for host mode and for why the
discarded UVC/VNC routes were considered, but it is no longer the build plan.
## Baseline measured on the phone (2026-08-04, historical)
| Piece | State |
|---|---|
| Kernel gadget framework | `CONFIG_USB_GADGET=y`, `CONFIG_USB_CONFIGFS=y` — built in, no modules |
| **HID gadget** | **`CONFIG_USB_CONFIGFS_F_HID=y` — the keyboard/mouse half of KVM already ships** |
| FunctionFS | `CONFIG_USB_CONFIGFS_F_FS=y` (flexible userspace gadgets, MTP path) |
| **UVC gadget** | **`CONFIG_USB_CONFIGFS_F_UVC` not set — the video half is the one missing config line** |
| Other functions | NCM, ECM, RNDIS, EEM, ACM, serial, OBEX, mass storage; no UAC1/2, no MIDI |
| Live configfs | Two gadgets bound: `dbg` (acm.GS0, acm.GS1, ncm.usb0) and `usb-signaller-developer` (ncm.usb0) on UDC `a600000.usb` (dwc3, **super-speed capable**, currently high-speed) |
| Mode switching | `usb-signaller` 0.3.1-3 active (dev mode at boot via `usb-signaller-default-mode`); `blueline-usb-gadget` 1.0.0-2; dev mode = NCM usb0 (172.16.42.1) + ACM |
| Video hardware | Venus **encoder** `/dev/video12` + **decoder** `/dev/video13`; CAMSS sensors `/dev/video0-11`; no v4l2loopback |
| Other packages | v4l-utils, libusb, libgusb, libusbmuxd |
## Host mode — the dock question (2026-08-04, Casey: "if I plug a USB-C dock into the phone right now…")
DeX-style: the phone as the computer, a dock supplying monitors + keyboard
+ mouse. Measured against the running kernel *and* Google's own vendor DT
(`sdm845-b1c1-usb.dtsi`, LineageOS kernel lineage-22.2):
| Ask | Verdict | Evidence |
|---|---|---|
| **Multi-monitor (DP alt mode)** | **Unwired in every tree that exists.** Google's board DT wires the port as **DRP + USB-PD** (`pmi8998_pdphy`, source 5V@0.9A, sink 5V/9V@3A, try-sink) with **no DP alt-mode path** — no redriver, no typec mux, no altmode node; the only "mux" is test GPIO104 for HS enumeration. Matches Google's official spec (USB 3.1 Gen 1, no video out). The *silicon* is capable — mainline `sdm845.dtsi` fully wires `mdss_dp` → QMP USB3-DP PHY (`usb_1_qmpphy_dp_in`) — but no sdm845 board in mainline wires it end-to-end either | vendor DT (fetched), mainline dtsi (local tree) |
| **USB keyboard/mouse** | **Yes — this is what LineageOS actually gives you.** DRP port + PD = real host mode. Our tree pins `dr_mode = "peripheral"` and usb-signaller holds the port as a gadget, so *we* don't do it today — but the hardware does | vendor DT, our board DT |
| **Via a plain OTG adapter** | **Works** — classic USB-A keyboard/flash-drive case | standard OTG |
| **Via a Dell dock (WD19…)** | **Host mode: works on LineageOS, one role-switch away on ours.** Monitors over DP alt mode: no. Monitors over **DisplayLink** (software display over USB host): only with a DisplayLink driver | per-dock, plug it in |
| **Charging from the dock** | Yes (PD sink 5V/9V@3A wired in the vendor DT) | vendor DT |
**The correction (2026-08-04):** an earlier draft called the DP gap a
"connector mux on the board — hardware." That was asserted from memory and
is wrong as stated. The evidence: Google wired the port for data+PD and
never enabled DP alt mode in any tree, and the *hardware question that
remains* — whether the PCB even routes DP lanes from the QMP PHY to the
connector — is **unproven in both directions**. If LineageOS drove real
monitors over the dock, the lanes exist (via DisplayLink, not alt mode).
Decisive physical test: a USB-C→HDMI **alt-mode** adapter (not DisplayLink)
with the port in host mode; if the board routes DP, a wired-up kernel has
something to talk to.
**The daily-driver catch:** the USB-C port is the management port — tethering
and dev mode (SSH over usb0) die while it is a host. Deliberate, documented
mode switch only; cold boots stay Casey's.
## Host mode — the live test (recipe, 2026-08-04)
Confirmed on the device: the role switch is real (`/sys/class/usb_role/
a600000.usb-role-switch`, role currently `device`), passwordless sudo works,
and usb-signaller owns `com.meego.usb_moded` on the system bus (its modes are
all device-side today — Developer/Tethering/MTP — so host mode is a direct
sysfs switch, and usb-signaller's restart is the way *back*).
```
# 1. give up the gadget first — a bound gadget + host role breaks
echo "" | sudo tee /sys/kernel/config/usb_gadget/usb-signaller-developer/UDC
# 2. switch the port to host
echo host | sudo tee /sys/class/usb_role/a600000.usb-role-switch/role
# 3. plug the dock, then observe:
lsusb
dmesg | tail -30
# 4. back — WiFi SSH survives the whole trip, so this always works:
echo device | sudo tee /sys/class/usb_role/a600000.usb-role-switch/role
sudo systemctl restart usb-signaller # re-provisions the developer gadget
cat /sys/class/usb_role/a600000.usb-role-switch/role
```
Gotchas: the dock is self-powered (Dell docks carry their own PSU), so its
hub can enumerate even if the phone's VBUS sourcing is weak or absent — the
dwc3 node has **no `vbus-supply`**, so bus-powered OTG peripherals (plain
keyboards) may not power, which is itself a measurement. If the dock's hub
enumerates, its keyboard/mouse are just kernel HID input — the shell gets a
real keyboard for free. If the dock's *monitors* ever light up, the DP lanes
exist and we go hunt the mux wiring; with no typec/altmode wired, expect
nothing from them.
## Original KVM notion — superseded by TASK-62
Plug the phone into another machine's USB port. The phone controls that
machine and sees its screen — keyboard, mouse, monitor, in one cable. Two
halves, with very different states of readiness:
**Input half — HID gadget: already built.** The kernel handles the USB HID
descriptors; userspace writes 8-byte keyboard reports to `/dev/hidg0` and
4-byte mouse reports to `/dev/hidg1`. This is the half that reaches
bootloaders/BIOS (the pelya project proved it) — no video ever reaches a
BIOS, so a BIOS-stage KVM is HID plus whatever screen the machine itself has.
**Display half — two routes:**
- **Route A (works today, zero kernel change):** the live NCM link. The
controlled machine serves its display over the USB network (VNC/waypipe);
the phone shows it in a surface. Touches become HID reports. Worst part is
latency, and the link is super-speed-capable.
- **Route B (one config line away):** UVC gadget. The phone presents as a
UVC camera; the controlled machine runs a "screen-as-webcam" tool (OBS
virtual cam and friends) which is the stream source; the phone decodes
(Venus decoder ✓) and shows it. The reverse direction also exists: Venus
encoder + UVC = the PC sees the phone's *own* screen as a webcam — an
in-the-cable scrcpy.
## Prior art (verified)
- **tejado/android-usb-gadget** — USB Gadget Tool (F-Droid): configfs roles
for keyboard/mouse, FIDO CTAP, CCID, UVC camera; activates gadgets at boot.
- **Android 14 "Device as Webcam"** — `CONFIG_USB_CONFIGFS_F_UVC` + configfs
recipe (MJPEG 1080p30, `dwMaxVideoFrameBufferSize` etc.); enabled by
default in GKI since android12-5.10. The configfs UVC setup pattern is the
one to copy.
- **pelya/android-keyboard-gadget** — the classic: `/dev/hidg0` keyboard,
`/dev/hidg1` mouse, `hid-gadget-test`; works into BIOS/bootloader.
- **Kernel docs** — `usb/gadget_hid.rst` (hid_gadget_test) and
`usb/gadget_uvc.html`; the UVC reference app is
`gitlab.freedesktop.org/camera/uvc-gadget` — "queue image buffers from a
variety of sources", i.e. the phone-side userspace we would adapt to feed
viewtop/compositor frames into the gadget.
## Original questions — answered by TASK-62
1. **Directions:** KVM-into-another-machine only, or also the reverse
(phone screen out as webcam)? Both share the UVC config; the userspace
differs.
2. **Route A or B first?** A proves the whole loop today with no rebuild; B
is the "real peripheral" feel but needs a kernel rebuild + cold boot —
and that is Casey's call, on the daily driver.
3. **Touch → HID mapping:** a KVM mode turns the phone's screen into a
touchpad/screen for the target machine. The machinery is the mirror of
TASK-50's touch intent — same input-routing problem, other direction.
4. **Where does the mode live?** usb-signaller gains a "kvm" mode (profile
+ service), or sessiond owns it as a mode with a verb. The agent angle
is real: Ani gets a keyboard/mouse that reaches any host — doctrine §13
says she should have the verb, not a config file.
5. **The kernel path:** enabling F_UVC is one config line, but the kernel
package still publishes unsigned raw `.pkg.tar.zst` (TASK-25's
`repo-add --sign` is unbuilt) and installs are cold-boot events.
## Original next steps — historical
1. **Prove HID today** — provision a HID keyboard function into a scratch
gadget on the phone (configfs, no reboot), bind it, write
`hid-gadget-test` key reports, watch the laptop enumerate a second
keyboard. One session, no rebuild.
2. **Route A latency test** — laptop serves its screen (VNC/waypipe) over
the live 172.16.42.1 link; phone displays it; measure.
3. **Route B** — config one-liner + rebuild + cold boot (Casey); configfs
UVC setup per the AOSP recipe; `uvc-gadget` userspace fed by a capture
surface.
4. **usb-signaller "kvm" mode** once the pieces exist, with clean
teardown/provision against the dev mode.
## Original acceptance sketch — historical
- Phone plugged into the laptop enumerates as keyboard+mouse; typing from
the phone lands in the laptop's focused app.
- Route A: the laptop's screen renders on the phone with usable latency.
- Route B: the laptop's virtual-cam tool lists the phone as a camera; the
phone shows the stream.
- Switching modes never strands the daily driver's tethering/dev mode.
## Connects to
TASK-25 (kernel package signing — the rebuild path), TASK-50 (her hand on
the glass — the touch→HID bridge is the mirror of the touch intent),
doctrine §13 (the KVM mode as a verb), `usb-signaller` (the mode host),
souveraine-viewtop (the display surface and capture path).
## The buildable work lives here
TASK-57 (the Pi dock head — phone as gadget, Pi as display/input head over
NCM) and TASK-58 (host power — the SMB2 OTG boost, one kernel change that
unlocks host-mode power, power sharing, and phone→Pi power).