Fix boot-to-login: override pcid-spawner to oneshot_async, add U3 input producers, Intel HDA phases A-D
- Override 00_pcid-spawner.service to oneshot_async in redbear-legacy-base.toml: rootfs phase no longer blocks on PCI driver init; getty/login starts immediately. Confirmed working on both QEMU and bare metal (redbear-live-mini). - Clean up 00_base legacy script: remove dead notify ipcd/ptyd calls, keep sudo --daemon. - Add U3 named input producers: inputd supports per-device named producers with fan-out to both device-specific consumers and legacy VT consumers. Migrate ps2d and usbhidd to InputProducer trait. RESERVED_DEVICE_NAMES deduplicated. - Add Intel HDA audio driver phases A-D: ihdad error handling (37 fixes), audio quirks, codec path enumeration, mixer/volume control. - Add init service start/readiness logging (always visible, not debug-gated). - Update BOOT-PROCESS-ASSESSMENT.md: Phase 6 complete, boot procedure documented, validation matrix updated with confirmed boot status. - Update USB-IMPLEMENTATION-PLAN.md and INPUT-SCHEME-ENHANCEMENT.md for U2/U3 status.
This commit is contained in:
@@ -1,8 +1,31 @@
|
||||
# Red Bear OS overrides for broken legacy base init scripts.
|
||||
# Red Bear OS overrides for legacy base init scripts.
|
||||
#
|
||||
# 00_base: tmpdir setup + sudo --daemon. ipcd and ptyd are started by the
|
||||
# systemd-style services in base recipe's init.d/ (00_ipcd.service,
|
||||
# 00_ptyd.service). The old "notify" calls have been removed because
|
||||
# the "notify" binary does not exist — they always failed silently.
|
||||
# sudo --daemon is kept here because 00_sudo.service exists in the base
|
||||
# recipe but is not wired into any target that gets scheduled.
|
||||
# 00_drivers: removed — pcid-spawner is started by 00_pcid-spawner.service from
|
||||
# the base recipe. The legacy script was redundant.
|
||||
# 10_net: blanked — replaced by per-config network services (e.g. redbear-live-mini's
|
||||
# 10_smolnetd.service + 10_dhcpd.service).
|
||||
# 00_pcid-spawner.service: overridden to oneshot_async. The base recipe uses
|
||||
# type="oneshot" which blocks init until pcid-spawner exits. On real
|
||||
# hardware (and QEMU), pcid-spawner can hang waiting for a PCI device
|
||||
# driver that never responds, blocking the entire rootfs phase including
|
||||
# getty/login. Using oneshot_async lets init proceed to start console
|
||||
# services while drivers spawn in the background.
|
||||
|
||||
[[files]]
|
||||
path = "/usr/lib/init.d/00_base"
|
||||
data = ""
|
||||
data = """
|
||||
# clear and recreate tmpdir with 0o1777 permission
|
||||
rm -rf /tmp
|
||||
mkdir -m a=rwxt /tmp
|
||||
|
||||
nowait sudo --daemon
|
||||
"""
|
||||
|
||||
[[files]]
|
||||
path = "/usr/lib/init.d/00_drivers"
|
||||
@@ -23,3 +46,14 @@ default_dependencies = false
|
||||
cmd = "audiod"
|
||||
type = "oneshot_async"
|
||||
"""
|
||||
|
||||
[[files]]
|
||||
path = "/etc/init.d/00_pcid-spawner.service"
|
||||
data = """
|
||||
[unit]
|
||||
description = "PCI driver spawner (non-blocking)"
|
||||
|
||||
[service]
|
||||
cmd = "pcid-spawner"
|
||||
type = "oneshot_async"
|
||||
"""
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Red Bear OS Boot Process Assessment & Improvement Plan
|
||||
|
||||
**Generated:** 2026-04-23
|
||||
**Updated:** 2026-04-23
|
||||
**Status:** Phase 1 ✅, Phase 2 ✅, Phase 3 ✅, Phase 4 ✅ (docs + known gaps), Phase 5 ✅
|
||||
**Updated:** 2026-04-24
|
||||
**Status:** Phase 1 ✅, Phase 2 ✅, Phase 3 ✅, Phase 4 ✅ (docs + known gaps), Phase 5 ✅, Phase 6 ✅ (boot to login confirmed)
|
||||
**Scope:** Comprehensive assessment of boot completeness, mistakes, robustness, resilience, and quality
|
||||
|
||||
## Boot Chain Overview
|
||||
@@ -128,12 +128,12 @@ Bare-metal testing requires physical hardware. Current validation is:
|
||||
## Phase 5: Validation Matrix ✅
|
||||
|
||||
### Build Verification
|
||||
| Target | Build | QEMU Boot | Notes |
|
||||
|--------|-------|-----------|-------|
|
||||
| redbear-minimal | ✅ harddrive.img (2 GB) | ✅ Stage 2 (kernel loaded) | Login renders to framebuffer, not serial |
|
||||
| redbear-full | ✅ harddrive.img (4 GB) | ✅ (prior session) | Greeter services load |
|
||||
| redbear-live-mini | ✅ ISO (384 MB) | — | ISO for bare-metal boot |
|
||||
| redbear-live | ✅ ISO (3.0 GB) | — | ISO for bare-metal boot |
|
||||
| Target | Build | QEMU Boot | Bare-Metal Boot | Notes |
|
||||
|--------|-------|-----------|-----------------|-------|
|
||||
| redbear-mini | ✅ harddrive.img (2 GB) | ✅ Login prompt | — | Framebuffer console login |
|
||||
| redbear-full | ✅ harddrive.img (4 GB) | ✅ Login prompt | — | Desktop packages included |
|
||||
| redbear-live-mini | ✅ ISO (384 MB) | — | ✅ Login prompt | ISO for bare-metal boot |
|
||||
| redbear-live-full | ✅ ISO (3.0 GB) | — | — | ISO for bare-metal boot |
|
||||
|
||||
### Compilation Verification
|
||||
- `cargo check --workspace` in base source: **0 errors**
|
||||
@@ -179,6 +179,82 @@ CI=1 make all CONFIG_NAME=redbear-minimal ARCH=x86_64
|
||||
|
||||
## Key Technical Findings
|
||||
|
||||
### Bare-Metal Boot Log Analysis (2026-04-24)
|
||||
|
||||
AMD machine boot log shows initfs phase starts but never completes:
|
||||
- Kernel boots: ACPI, IOAPIC, timer, memory all OK
|
||||
- vesad initializes: 1280x1024 at 0xA0000000 (FRAMEBUFFER_* from UEFI bootloader)
|
||||
- fbbootlogd maps display
|
||||
- ps2d: keyboard works, mouse BAT fails (no PS/2 mouse port — expected on modern hardware)
|
||||
- pcid begins PCI enumeration
|
||||
- acpid starts, AML interpreter initializes
|
||||
- **MISSING**: "init: initfs drivers target step() complete" — scheduler.step() never returns
|
||||
- **MISSING**: "init: phase 2 — switchroot to /usr" — rootfs phase never starts
|
||||
- **MISSING**: any getty or login output
|
||||
|
||||
Root cause hypothesis (unproven): a service with `type = "notify"`, `type = { scheme = "..." }`,
|
||||
or `type = "oneshot"` in the initfs phase does not signal readiness or does not exit,
|
||||
causing init's scheduler.step() to block forever. All three service types wait synchronously
|
||||
in `service.rs`. Possible blockers include:
|
||||
- A `notify` service that hangs before calling `daemon::Daemon::ready()`
|
||||
- A `scheme` service that hangs before calling `daemon::SchemeDaemon::ready_*()`
|
||||
- An `oneshot` service like `pcid-spawner --initfs` that hangs during PCI enumeration
|
||||
With the new per-service logging (Phase 6A + 6C), the next boot will show exactly which
|
||||
service blocks — the last `init: starting ...` line before the hang identifies the blocker.
|
||||
|
||||
### Bare-Metal/QEMU Boot Log Analysis (2026-04-24, second test with Phase 6 logging)
|
||||
|
||||
The enhanced logging proved the initfs phase completes successfully. The actual blocker is
|
||||
in the rootfs phase:
|
||||
|
||||
- Initfs phase: ✅ all services start and signal readiness/exit correctly
|
||||
- `init: phase 2 - switchroot to /usr` ✅
|
||||
- `init: scheduling 22 rootfs units` ✅
|
||||
- `init: starting PCI driver spawner (pcid-spawner)` ← **BLOCKS HERE**
|
||||
- pcid-spawner (rootfs, `type = "oneshot"`) spawns e1000d (ok), ihdad (fails with RIRB timeout)
|
||||
- Then hangs — no further output for 30+ seconds while system is alive (keyboard works)
|
||||
- Init never reaches `30_console` → getty → login
|
||||
|
||||
Root cause (confirmed): rootfs `00_pcid-spawner.service` uses `type = "oneshot"`, which
|
||||
causes init to block until pcid-spawner exits. On real hardware and QEMU, pcid-spawner
|
||||
can hang waiting for a PCI device driver that never responds, blocking the entire rootfs
|
||||
phase including getty/login.
|
||||
|
||||
Fix: override `00_pcid-spawner.service` to `type = "oneshot_async"` in
|
||||
`config/redbear-legacy-base.toml`. Drivers spawn in the background while init proceeds
|
||||
to start console services. Network services that depend on specific drivers handle their
|
||||
own timing (they connect to driver schemes when ready).
|
||||
|
||||
**Confirmed working**: Both QEMU and bare-metal boot to login prompt after this fix.
|
||||
|
||||
### Phase 6: Boot Visibility & Service Cleanup ✅
|
||||
|
||||
**Status: Confirmed working — system boots to login prompt on both QEMU and bare metal.**
|
||||
|
||||
**6A: Init service start logging (always visible)**
|
||||
`init/src/scheduler.rs`: Service and target start messages promoted from DEBUG to always-visible.
|
||||
Every service now logs `init: starting <description> (<cmd>)` before spawning and
|
||||
`init: started <description> (pid <N>)` after a respawnable process is created.
|
||||
|
||||
**6B: Legacy init script cleanup**
|
||||
`config/redbear-legacy-base.toml`:
|
||||
- `00_base`: Removed dead `notify ipcd` / `notify ptyd` calls.
|
||||
The `notify` binary does not exist anywhere in the build tree — these calls always failed
|
||||
silently. ipcd and ptyd are started by the base recipe's systemd-style services
|
||||
(`00_ipcd.service`, `00_ptyd.service`). sudo --daemon is kept because `00_sudo.service`
|
||||
exists in the base recipe but is not wired into any target that gets scheduled.
|
||||
The script now does tmpdir setup + sudo --daemon.
|
||||
- `00_drivers`: Blanked (was redundant — pcid-spawner starts via `00_pcid-spawner.service`).
|
||||
|
||||
**6C: Service readiness completion logging**
|
||||
`init/src/service.rs`: Added success log after each blocking wait completes:
|
||||
- `notify` services: `init: <cmd> ready (notify)` after readiness byte received
|
||||
- `scheme` services: `init: <cmd> ready (scheme <name>)` after scheme registered
|
||||
- `oneshot` services: `init: <cmd> done (oneshot)` after process exits successfully
|
||||
Combined with 6A's `init: starting ...` before spawn, the boot log now shows the full
|
||||
lifecycle of every blocking service — any gap between "starting" and "ready/done" pinpoints
|
||||
the blocker.
|
||||
|
||||
### Serde `deny_unknown_fields` Behavior
|
||||
`UnitInfo` and `Service` structs use `#[serde(deny_unknown_fields)]`. Any unrecognized field in `[unit]` or `[service]` sections causes the ENTIRE service file to fail deserialization. The init system logs the error and skips the service — it never starts.
|
||||
|
||||
@@ -192,10 +268,18 @@ Services with `type = "oneshot_async"` are fire-and-forget by default. Init spaw
|
||||
|
||||
### Config Include Chain
|
||||
```
|
||||
redbear-minimal.toml → minimal.toml, redbear-legacy-base.toml, redbear-device-services.toml, redbear-netctl.toml
|
||||
redbear-full.toml → desktop.toml, redbear-desktop.toml, redbear-greeter-services.toml, ...
|
||||
redbear-live-full.toml → redbear-live.toml
|
||||
redbear-live.toml → redbear-full.toml
|
||||
redbear-full.toml → desktop.toml, redbear-legacy-base.toml, redbear-legacy-desktop.toml,
|
||||
redbear-device-services.toml, redbear-netctl.toml, redbear-greeter-services.toml
|
||||
desktop.toml → desktop-minimal.toml, server.toml
|
||||
desktop-minimal.toml → minimal.toml
|
||||
server.toml → minimal.toml
|
||||
minimal.toml → base.toml
|
||||
|
||||
redbear-live-mini.toml → minimal.toml, redbear-legacy-base.toml, redbear-netctl.toml
|
||||
redbear-live.toml → redbear-full.toml, ...
|
||||
redbear-mini → redbear-minimal.toml → minimal.toml, redbear-legacy-base.toml,
|
||||
redbear-device-services.toml, redbear-netctl.toml
|
||||
```
|
||||
|
||||
### Upstream Targets (not Red Bear defined)
|
||||
@@ -266,3 +350,117 @@ redbear-live.toml → redbear-full.toml, ...
|
||||
- `local/scripts/validate-service-files.sh` — manual service schema validation (redbear-*.toml only)
|
||||
- `local/docs/BOOT-PROCESS-ASSESSMENT.md` — this document
|
||||
- `recipes/core/base/source/init.initfs.d/41_acpid.service` — acpid in initfs (boot race fix)
|
||||
|
||||
## Boot Procedure
|
||||
|
||||
### Supported compile targets
|
||||
|
||||
| Target | Purpose | Output |
|
||||
|--------|---------|--------|
|
||||
| `redbear-mini` | Minimal non-desktop (QEMU + bare metal) | `build/x86_64/harddrive.img` |
|
||||
| `redbear-live-mini` | Minimal live ISO (bare metal only) | `build/x86_64/redbear-live-mini.iso` |
|
||||
| `redbear-full` | Desktop/graphics (QEMU + bare metal) | `build/x86_64/harddrive.img` |
|
||||
| `redbear-live-full` / `redbear-live` | Desktop/graphics live ISO (bare metal only) | `build/x86_64/redbear-live-full.iso` |
|
||||
|
||||
### Build commands
|
||||
|
||||
```bash
|
||||
# Minimal target (QEMU testing)
|
||||
CI=1 make all CONFIG_NAME=redbear-mini ARCH=x86_64
|
||||
|
||||
# Minimal live ISO (bare-metal boot)
|
||||
CI=1 make live CONFIG_NAME=redbear-live-mini ARCH=x86_64
|
||||
|
||||
# Desktop/graphics target (QEMU testing)
|
||||
CI=1 make all CONFIG_NAME=redbear-full ARCH=x86_64
|
||||
|
||||
# Desktop/graphics live ISO (bare-metal boot)
|
||||
CI=1 make live CONFIG_NAME=redbear-live-full ARCH=x86_64
|
||||
```
|
||||
|
||||
### QEMU boot (harddrive.img)
|
||||
|
||||
```bash
|
||||
# Boot the minimal target in QEMU
|
||||
make qemu CONFIG_NAME=redbear-mini
|
||||
|
||||
# Boot with more RAM
|
||||
make qemu CONFIG_NAME=redbear-mini QEMUFLAGS="-m 4G"
|
||||
|
||||
# Boot desktop target
|
||||
make qemu CONFIG_NAME=redbear-full
|
||||
```
|
||||
|
||||
QEMU boots from `harddrive.img` (not the live ISO). The `-serial mon:stdio` flag provides
|
||||
the serial console, but Red Bear uses the framebuffer console for login — type at the
|
||||
graphical console, not serial.
|
||||
|
||||
### Bare-metal boot (live ISO)
|
||||
|
||||
1. **Build the ISO:**
|
||||
```bash
|
||||
CI=1 make live CONFIG_NAME=redbear-live-mini ARCH=x86_64
|
||||
```
|
||||
|
||||
2. **Write ISO to USB drive:**
|
||||
```bash
|
||||
sudo dd if=build/x86_64/redbear-live-mini.iso of=/dev/sdX bs=4M status=progress && sync
|
||||
```
|
||||
Replace `/dev/sdX` with your USB device. Use `lsblk` to identify it.
|
||||
|
||||
3. **Boot from USB:**
|
||||
- Insert USB into target machine
|
||||
- Power on, enter UEFI boot menu (typically F12, F8, or Esc)
|
||||
- Select the USB device as boot target
|
||||
- Red Bear OS boots from UEFI → bootloader → kernel → init → login prompt
|
||||
|
||||
4. **Login:**
|
||||
- Default user: `root`, no password
|
||||
- The framebuffer console displays the login prompt after boot completes
|
||||
|
||||
### What happens during boot
|
||||
|
||||
```
|
||||
UEFI firmware
|
||||
→ Red Bear bootloader (loaded from EFI system partition)
|
||||
→ Kernel (kstart → start → kmain)
|
||||
→ userspace_init → bootstrap (forks initfs/procmgr/initnsmgr)
|
||||
→ Initfs phase:
|
||||
logd, inputd, vesad (framebuffer), fbcond, fbbootlogd,
|
||||
ps2d (keyboard), acpid, pcid-spawner-initfs (initfs PCI drivers), lived, redoxfs
|
||||
→ switchroot /usr
|
||||
→ Rootfs phase:
|
||||
00_base (tmpdir + sudo --daemon)
|
||||
00_ipcd.service, 00_ptyd.service
|
||||
00_pcid-spawner.service (async — spawns PCI drivers in background)
|
||||
30_console (getty with respawn)
|
||||
→ Login prompt on framebuffer console
|
||||
```
|
||||
|
||||
### Boot log markers
|
||||
|
||||
The init system logs the following always-visible markers. If boot hangs, the last visible
|
||||
marker identifies the blocker:
|
||||
|
||||
```
|
||||
init: phase 1 — initfs boot
|
||||
init: starting <description> (<cmd>) # before each service spawn
|
||||
init: <cmd> ready (notify) # notify-type service ready
|
||||
init: <cmd> ready (scheme <name>) # scheme-type service ready
|
||||
init: <cmd> done (oneshot) # oneshot service exited
|
||||
init: phase 2 — switchroot to /usr
|
||||
init: scheduling N rootfs units
|
||||
init: reached target <description>
|
||||
init: phase 3 — rootfs services started
|
||||
init: boot complete — entering waitpid loop
|
||||
```
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
| Symptom | Likely cause | Fix |
|
||||
|---------|-------------|-----|
|
||||
| No display output | UEFI framebuffer not provided | Try different USB port or disable CSM in UEFI settings |
|
||||
| Boot hangs after "scheduling N rootfs units" | A blocking service hangs | Check last "starting" line; `pcid-spawner` was previously the blocker |
|
||||
| Keyboard not working | PS/2 unavailable, USB not ready | Modern hardware uses USB — ensure xHCI controller is functional |
|
||||
| No login prompt | Getty not starting | Check `30_console` service in config; verify getty respawn is set |
|
||||
| "missing field `unit`" parse error | Invalid service TOML | Run `./local/scripts/validate-service-files.sh config/` |
|
||||
|
||||
@@ -26,11 +26,11 @@ The current `inputd` implementation in `recipes/core/base/source/drivers/inputd/
|
||||
- `SchemeRoot` exists, but it is not a real directory yet: it does not enumerate entries.
|
||||
- `lib.rs` only exposes `ProducerHandle`, `ConsumerHandle`, `DisplayHandle`, and `ControlHandle`.
|
||||
|
||||
Current callers confirm the limitation:
|
||||
Current callers after migration:
|
||||
|
||||
- `ps2d` opens one `ProducerHandle` and sends both keyboard and mouse events into the same stream.
|
||||
- `usbhidd` also opens one `ProducerHandle` and sends keyboard/mouse/button/scroll data into the same stream.
|
||||
- local `evdevd` reads `/scheme/input/consumer`, receives anonymous mixed `orbclient::Event` values, and manually translates them.
|
||||
- `ps2d` opens two `InputProducer` instances (`ps2-keyboard`, `ps2-mouse`) with legacy fallback, routing keyboard scancodes to the keyboard producer and mouse events to the mouse producer.
|
||||
- `usbhidd` opens one `InputProducer` per interface instance (`usb-{port}-if{n}`) with legacy fallback.
|
||||
- local `evdevd` reads `/scheme/input/consumer`, receives anonymous mixed `orbclient::Event` values, and manually translates them (not yet migrated to per-device streams).
|
||||
|
||||
## 3. Design Principles
|
||||
|
||||
@@ -454,23 +454,20 @@ This keeps `DeviceConsumer` simple and avoids introducing a second handle teardo
|
||||
|
||||
## 13. Migration Path
|
||||
|
||||
### 13.1 `ps2d`
|
||||
### 13.1 `ps2d` — MIGRATED
|
||||
|
||||
`ps2d` is the first caller that should adopt the new API because it already has a clean split between keyboard and mouse sources.
|
||||
`ps2d` now uses two `InputProducer` instances with named-first, legacy-fallback strategy:
|
||||
|
||||
Recommended startup logic:
|
||||
|
||||
1. Try `NamedProducerHandle::new("ps2-keyboard")`
|
||||
2. Try `NamedProducerHandle::new("ps2-mouse")`
|
||||
3. If both succeed, run in named mode
|
||||
4. If either fails, close any partially opened named handle and fall back to one legacy `ProducerHandle::new()`
|
||||
1. Try `InputProducer::new_named_or_fallback("ps2-keyboard")` → falls back to legacy on error
|
||||
2. Try `InputProducer::new_named_or_fallback("ps2-mouse")` → falls back to legacy on error
|
||||
3. `Ps2d` struct holds `keyboard_input: InputProducer` + `mouse_input: InputProducer`
|
||||
|
||||
Routing:
|
||||
|
||||
- keyboard scancodes → `ps2-keyboard`
|
||||
- mouse move / absolute move / button / scroll events → `ps2-mouse`
|
||||
- keyboard scancodes → `self.keyboard_input`
|
||||
- mouse move / absolute move / button / scroll events → `self.mouse_input`
|
||||
|
||||
This preserves compatibility with old `inputd` while immediately enabling per-device consumers on new `inputd`.
|
||||
This preserves compatibility with old `inputd` while enabling per-device consumers on new `inputd`.
|
||||
|
||||
### 13.2 `evdevd`
|
||||
|
||||
@@ -482,9 +479,15 @@ Once the scheme exists, local `evdevd` can move from `/scheme/input/consumer` to
|
||||
|
||||
It can keep the legacy consumer path as a fallback for older systems.
|
||||
|
||||
### 13.3 `usbhidd`
|
||||
### 13.3 `usbhidd` — MIGRATED
|
||||
|
||||
`usbhidd` can remain legacy initially, then later migrate to named producers such as `usb-hid0`, `usb-hid1`, or more specific per-interface names.
|
||||
`usbhidd` now uses one `InputProducer` per interface instance with named-first, legacy-fallback strategy:
|
||||
|
||||
1. Opens `InputProducer::new_named_or_fallback(&format!("usb-{}-if{}", port, interface_num))`
|
||||
2. Falls back to legacy on error
|
||||
3. All event writes go through the same `write_event()` method
|
||||
|
||||
Producer names: `usb-{port}-if{interface_num}` (e.g., `usb-1-if0`, `usb-1-if1`).
|
||||
|
||||
## 14. Backward Compatibility Requirements
|
||||
|
||||
@@ -520,16 +523,17 @@ This design does **not** include:
|
||||
|
||||
Another developer implementing this design should be able to proceed in this order:
|
||||
|
||||
1. extend `Handle` and `InputScheme` state
|
||||
2. teach `openat()` to parse `producer/{name}`, `events`, and dynamic device names
|
||||
3. add root `getdents()` support for `SchemeRoot`
|
||||
4. refactor `write()` so producer type is detected before routing
|
||||
5. fan out named-producer events to matching `DeviceConsumer` handles and the existing legacy path
|
||||
6. add hotplug queue serialization helpers
|
||||
7. extend `fevent()` and daemon notification loop for `DeviceConsumer` and `HotplugEvents`
|
||||
8. add cleanup in `on_close()` for `NamedProducer`
|
||||
9. extend `lib.rs` with the new handle types and directory lister
|
||||
10. migrate `ps2d` with a named-producer-first, legacy-fallback strategy
|
||||
1. extend `Handle` and `InputScheme` state ✅
|
||||
2. teach `openat()` to parse `producer/{name}`, `events`, and dynamic device names ✅
|
||||
3. add root `getdents()` support for `SchemeRoot` ✅
|
||||
4. refactor `write()` so producer type is detected before routing ✅
|
||||
5. fan out named-producer events to matching `DeviceConsumer` handles and the existing legacy path ✅
|
||||
6. add hotplug queue serialization helpers ✅
|
||||
7. extend `fevent()` and daemon notification loop for `DeviceConsumer` and `HotplugEvents` ✅
|
||||
8. add cleanup in `on_close()` for `NamedProducer` ✅
|
||||
9. extend `lib.rs` with the new handle types and directory lister ✅
|
||||
10. migrate `ps2d` with a named-producer-first, legacy-fallback strategy ✅
|
||||
11. migrate `usbhidd` with a named-producer-first, legacy-fallback strategy ✅
|
||||
|
||||
## 17. Final Outcome
|
||||
|
||||
|
||||
@@ -0,0 +1,417 @@
|
||||
# Intel HDA Implementation Plan
|
||||
|
||||
**Version:** 1.0 (2026-04-24)
|
||||
**Status:** Draft execution plan
|
||||
**Scope owner:** Audio subsystem (legacy HDA + Intel DSP decision path)
|
||||
|
||||
## Purpose
|
||||
|
||||
This document defines the concrete execution plan for implementing full Intel audio support in Red Bear OS, using Linux 7.0 source code in-tree as donor reference material.
|
||||
|
||||
"Full Intel support" is split into three tracks:
|
||||
|
||||
1. Legacy PCI HDA controller + analog codecs (current `ihdad` path)
|
||||
2. HDMI/DP digital audio over HDA links
|
||||
3. Modern Intel DSP-class platforms (SOF/AVS-class routing, not legacy-only HDA)
|
||||
|
||||
## Why This Plan Is Needed
|
||||
|
||||
Current in-tree evidence shows `ihdad` is an early implementation, not a complete Intel audio stack:
|
||||
|
||||
- Single-codec assumption in enumeration logic (`device.rs`)
|
||||
- Unimplemented controller interrupt handler (`handle_controller_interrupt`)
|
||||
- Fixed-format playback setup (44.1kHz / 16-bit / stereo)
|
||||
- Incomplete scheme surface (`Handle::Todo`-centric behavior)
|
||||
- No complete capture path integration in `audiod` (`TODO: audio input`)
|
||||
- Historical hardware report: "No audio, HDA driver cannot find output pins"
|
||||
|
||||
## Current Stack Snapshot
|
||||
|
||||
### Driver and daemon surface
|
||||
|
||||
- `ihdad` registers `audiohw`
|
||||
- `audiod` opens `/scheme/audiohw` and exposes `/scheme/audio`
|
||||
- SDL backends use `/scheme/audio`
|
||||
|
||||
### Known contract constraints
|
||||
|
||||
- `audiod` mixes fixed-size buffers (`HW_BUFFER_SIZE = 512`)
|
||||
- `ihdad` stream writes currently assume strict block sizing
|
||||
- `ihdad` currently hardcodes one primary output format on setup
|
||||
|
||||
## Canonical Donor Sources (Linux 7.0 in-tree)
|
||||
|
||||
- Controller policy and quirks:
|
||||
- `build/linux-kernel-cache/linux-7.0/sound/hda/controllers/intel.c`
|
||||
- Generic parser and fixup engine:
|
||||
- `build/linux-kernel-cache/linux-7.0/sound/hda/common/auto_parser.c`
|
||||
- Core codec/controller plumbing:
|
||||
- `build/linux-kernel-cache/linux-7.0/sound/hda/common/`
|
||||
- Vendor codec implementations:
|
||||
- `build/linux-kernel-cache/linux-7.0/sound/hda/codecs/`
|
||||
- Intel DSP route-selection policy:
|
||||
- `build/linux-kernel-cache/linux-7.0/sound/hda/core/intel-dsp-config.c`
|
||||
- Modern Intel DSP implementations:
|
||||
- `build/linux-kernel-cache/linux-7.0/sound/soc/sof/intel/`
|
||||
- `build/linux-kernel-cache/linux-7.0/sound/soc/intel/avs/`
|
||||
|
||||
## Execution Model
|
||||
|
||||
The plan is organized as issue-sized work packages (`HDA-001`..`HDA-012`).
|
||||
|
||||
### Phase A: Legacy HDA correctness (must complete first)
|
||||
|
||||
#### HDA-001 — Multi-codec and function-group support
|
||||
|
||||
**Goal:** Remove single-codec assumptions and support real codec topology.
|
||||
|
||||
**Files:**
|
||||
- `recipes/core/base/source/drivers/audio/ihdad/src/hda/device.rs`
|
||||
- `recipes/core/base/source/drivers/audio/ihdad/src/hda/node.rs`
|
||||
|
||||
**Acceptance criteria:**
|
||||
- Codec enumeration includes all detected codecs
|
||||
- Bring-up does not assume first codec is the audio path
|
||||
- `audiohw:codec` dump reflects multi-codec topology
|
||||
|
||||
#### HDA-002 — Controller interrupts and unsolicited events
|
||||
|
||||
**Goal:** Implement real controller interrupt handling and unsol event dispatch.
|
||||
|
||||
**Files:**
|
||||
- `recipes/core/base/source/drivers/audio/ihdad/src/hda/device.rs`
|
||||
- `recipes/core/base/source/drivers/audio/ihdad/src/hda/cmdbuff.rs`
|
||||
|
||||
**Acceptance criteria:**
|
||||
- `handle_controller_interrupt()` is non-stub
|
||||
- Jack-related unsol events are observable and processed
|
||||
- No interrupt-ack regressions under continuous playback
|
||||
|
||||
#### HDA-003 — Format/rate/channel negotiation
|
||||
|
||||
**Goal:** Replace fixed-format startup with negotiated stream format.
|
||||
|
||||
**Files:**
|
||||
- `recipes/core/base/source/drivers/audio/ihdad/src/hda/device.rs`
|
||||
- `recipes/core/base/source/drivers/audio/ihdad/src/hda/stream.rs`
|
||||
|
||||
**Acceptance criteria:**
|
||||
- Driver selects supported stream format from capabilities
|
||||
- Unsupported format requests fail deterministically
|
||||
- Startup no longer assumes 44.1kHz/16-bit/stereo only
|
||||
|
||||
#### HDA-004 — Real scheme endpoint model (`pcmout`/`pcmin`)
|
||||
|
||||
**Goal:** Replace `Handle::Todo` behavior with structured stream handles.
|
||||
|
||||
**Files:**
|
||||
- `recipes/core/base/source/drivers/audio/ihdad/src/hda/device.rs`
|
||||
- `recipes/core/base/source/audiod/src/scheme.rs`
|
||||
|
||||
**Acceptance criteria:**
|
||||
- Distinct playback and capture endpoints exist
|
||||
- Handle lifecycle and permissions are explicit
|
||||
- Multiple clients can be supported without implicit index-0 fallback
|
||||
|
||||
#### HDA-005 — Capture and duplex path
|
||||
|
||||
**Goal:** Implement and validate simultaneous input/output.
|
||||
|
||||
**Files:**
|
||||
- `recipes/core/base/source/drivers/audio/ihdad/src/hda/device.rs`
|
||||
- `recipes/core/base/source/drivers/audio/ihdad/src/hda/stream.rs`
|
||||
- `recipes/core/base/source/audiod/src/main.rs`
|
||||
- `recipes/core/base/source/audiod/src/scheme.rs`
|
||||
|
||||
**Acceptance criteria:**
|
||||
- Capture endpoint is functional
|
||||
- Duplex playback/capture runs stably for bounded runtime tests
|
||||
- `audiod` input TODO is removed
|
||||
|
||||
### Phase B: Parser, fixups, and quirk-driven stability
|
||||
|
||||
#### HDA-006 — Generic parser + fixup framework
|
||||
|
||||
**Goal:** Add parser/fixup framework equivalent to Linux generic HDA model.
|
||||
|
||||
**Files:**
|
||||
- New parser/fixup module(s) under `ihdad/src/hda/`
|
||||
- Integration in `device.rs`
|
||||
|
||||
**Acceptance criteria:**
|
||||
- Pin/path selection is parser-driven, not heuristic-only
|
||||
- Fixups can be applied by device identity and pin/config criteria
|
||||
- Targeted fixup can resolve known "no output pins" class failures
|
||||
|
||||
#### HDA-007 — Audio quirk data pipeline
|
||||
|
||||
**Goal:** Add audio quirk extraction and runtime loading pattern aligned with current quirks system.
|
||||
|
||||
**Files:**
|
||||
- `local/scripts/extract-linux-quirks.py` (extend for HDA tables)
|
||||
- `local/recipes/drivers/redox-driver-sys/source/src/quirks/mod.rs` (add audio quirk model)
|
||||
- `local/recipes/system/redbear-quirks/source/quirks.d/` (add audio quirk TOML)
|
||||
|
||||
**Acceptance criteria:**
|
||||
- Audio quirk entries load from `/etc/quirks.d`
|
||||
- Driver behavior can be changed by data without code edits
|
||||
- At least MSI/probe/position/power policy classes represented
|
||||
|
||||
#### HDA-008 — Controller policy parity slice
|
||||
|
||||
**Goal:** Add minimum policy knobs parity with Linux HDA controller behavior.
|
||||
|
||||
**Files:**
|
||||
- `recipes/core/base/source/drivers/audio/ihdad/src/hda/device.rs`
|
||||
- `recipes/core/base/source/drivers/audio/ihdad/src/main.rs`
|
||||
|
||||
**Initial parity targets:**
|
||||
- MSI policy
|
||||
- single-command fallback policy
|
||||
- codec probe mask
|
||||
- DMA position-fix policy
|
||||
- jack poll fallback policy
|
||||
|
||||
**Acceptance criteria:**
|
||||
- Policies are configurable and observable
|
||||
- Policy defaults can be influenced by quirk data
|
||||
|
||||
### Phase C: Digital audio completeness
|
||||
|
||||
#### HDA-009 — HDMI/DP audio path
|
||||
|
||||
**Goal:** Implement digital codec path handling including ELD and sink constraints.
|
||||
|
||||
**Files:**
|
||||
- New digital-audio module(s) in `ihdad/src/hda/`
|
||||
- Integration points in `device.rs`
|
||||
|
||||
**Acceptance criteria:**
|
||||
- HDMI/DP codec path is detected and usable on supported hardware/VMs
|
||||
- ELD-informed format/channel limitations are honored
|
||||
|
||||
### Phase D: Modern Intel audio (DSP-class)
|
||||
|
||||
#### HDA-010 — Intel audio route dispatcher
|
||||
|
||||
**Goal:** Add driver-selection logic equivalent to Linux `intel-dsp-config` principles.
|
||||
|
||||
**Files:**
|
||||
- New dispatcher logic in audio/pcid integration path
|
||||
- `recipes/core/base/source/drivers/audio/ihdad/config.toml` and related registration surfaces
|
||||
|
||||
**Acceptance criteria:**
|
||||
- cAVS/SOF-class devices are not incorrectly routed to legacy-only behavior
|
||||
- Route decision uses bounded platform traits (PCI class/prog-if + board traits)
|
||||
|
||||
#### HDA-011 — SOF/AVS-class implementation track
|
||||
|
||||
**Goal:** Provide a modern Intel DSP-capable driver path separate from legacy `ihdad`.
|
||||
|
||||
**Donor roots:**
|
||||
- `sound/soc/sof/intel`
|
||||
- `sound/soc/intel/avs`
|
||||
|
||||
**Acceptance criteria:**
|
||||
- At least one Intel cAVS/SOF-class machine can produce bounded playback
|
||||
- Legacy HDA path remains intact on legacy devices
|
||||
|
||||
### Phase E: Desktop ecosystem compatibility
|
||||
|
||||
#### HDA-012 — PipeWire/PulseAudio compatibility bridge
|
||||
|
||||
**Goal:** Bridge Redox native audio to desktop software expecting PipeWire/PulseAudio APIs.
|
||||
|
||||
**Acceptance criteria:**
|
||||
- KDE desktop audio consumers can produce sound through compatibility layer
|
||||
- Scope and claim language remains bounded (no overclaim)
|
||||
|
||||
## Validation Gates
|
||||
|
||||
### G1 — Legacy HDA playback stability
|
||||
|
||||
- Environment: QEMU HDA and at least one bare-metal Intel HDA device
|
||||
- Criteria:
|
||||
- Sustained playback duration threshold met
|
||||
- No IRQ storm, no driver lockup
|
||||
- No repeated timeout errors from CORB/RIRB paths
|
||||
|
||||
### G2 — Jack event behavior
|
||||
|
||||
- Environment: bare metal with physical jack
|
||||
- Criteria:
|
||||
- Plug/unplug detected
|
||||
- Route switches correctly
|
||||
- Speaker mute policy behaves as expected
|
||||
|
||||
### G3 — Duplex stability
|
||||
|
||||
- Environment: bare metal preferred; QEMU for baseline
|
||||
- Criteria:
|
||||
- Capture + playback concurrently
|
||||
- No starvation/deadlock in scheme processing
|
||||
|
||||
### G4 — Quirk efficacy
|
||||
|
||||
- Criteria:
|
||||
- At least 3 hardware-specific issues fixed by data-driven quirks
|
||||
- Fixes do not require permanent ad hoc branches in main flow
|
||||
|
||||
### G5 — Modern Intel path
|
||||
|
||||
- Environment: Intel cAVS/SOF-class system
|
||||
- Criteria:
|
||||
- Route dispatcher selects modern path
|
||||
- Bounded playback success via DSP-capable path
|
||||
|
||||
## Risk and Dependency Notes
|
||||
|
||||
1. **Main risk:** Treating SOF/AVS systems as legacy HDA-only.
|
||||
2. **Main technical debt risk:** Hardcoded policy instead of quirk-backed data.
|
||||
3. **Integration dependency:** `audiod` contract must evolve in lockstep with `ihdad` stream model.
|
||||
4. **Desktop dependency:** KDE audio integration remains blocked without compatibility bridge even if kernel/driver path works.
|
||||
|
||||
## Initial Prioritization (strict order)
|
||||
|
||||
1. HDA-001 through HDA-005
|
||||
2. HDA-006 through HDA-008
|
||||
3. HDA-009
|
||||
4. HDA-010 and HDA-011
|
||||
5. HDA-012
|
||||
|
||||
## HDA-001 Implementation Blueprint
|
||||
|
||||
This section defines the concrete first code slice for `HDA-001` (multi-codec + function-group support).
|
||||
|
||||
### Objective
|
||||
|
||||
Remove hardcoded codec `0` traversal and make codec/AFG/widget discovery data-driven from `STATESTS`.
|
||||
|
||||
### Current hotspots
|
||||
|
||||
- `ihdad` codec discovery currently hardcodes `let codec: u8 = 0` during enumeration.
|
||||
- Widget addressing and lists (`outputs`, `inputs`, pins) are global vectors not grouped by codec/function group.
|
||||
- The scheme dump path (`audiohw:codec`) assumes a single codec payload.
|
||||
|
||||
### Files to edit
|
||||
|
||||
- `recipes/core/base/source/drivers/audio/ihdad/src/hda/device.rs`
|
||||
- `recipes/core/base/source/drivers/audio/ihdad/src/hda/node.rs` (only if helper fields/methods are needed)
|
||||
|
||||
### Step-by-step patch plan
|
||||
|
||||
1. Introduce per-codec topology container in `device.rs`.
|
||||
|
||||
Add internal structures:
|
||||
|
||||
- `CodecTopology`
|
||||
- `codec_addr: CodecAddr`
|
||||
- `afgs: Vec<NodeAddr>`
|
||||
- `widget_map: HashMap<WidgetAddr, HDANode>`
|
||||
- `outputs: Vec<WidgetAddr>`
|
||||
- `inputs: Vec<WidgetAddr>`
|
||||
- `output_pins: Vec<WidgetAddr>`
|
||||
- `input_pins: Vec<WidgetAddr>`
|
||||
- `beep_addr: Option<WidgetAddr>`
|
||||
|
||||
- `IntelHDA` field:
|
||||
- `codecs_topology: HashMap<CodecAddr, CodecTopology>`
|
||||
|
||||
2. Replace global widget collections with codec-scoped accessors.
|
||||
|
||||
Keep existing fields temporarily for migration safety, but make enumeration write to `codecs_topology` first.
|
||||
After compile + smoke pass, remove stale globals (`outputs`, `inputs`, `widget_map`, pin vectors, `beep_addr`).
|
||||
|
||||
3. Refactor `enumerate()` to iterate all detected codecs.
|
||||
|
||||
- Use `self.codecs` as source (populated in `reset_controller()` from `STATESTS`).
|
||||
- For each codec:
|
||||
- Read root node `(codec, 0)`.
|
||||
- Iterate all function groups in root range.
|
||||
- Filter audio function groups (`function_group_type` audio class).
|
||||
- Enumerate widgets and classify into per-codec topology lists.
|
||||
|
||||
4. Add safe codec selection helper for playback bring-up.
|
||||
|
||||
Add helper:
|
||||
- `fn pick_primary_codec_for_output(&self) -> Option<CodecAddr>`
|
||||
|
||||
Selection policy v1:
|
||||
- First codec with at least one `output_pin` and one `AudioOutput` widget.
|
||||
- Stable tie-breaker: lowest codec address.
|
||||
|
||||
5. Make `find_best_output_pin()` codec-aware.
|
||||
|
||||
Change signature from global behavior to:
|
||||
- `fn find_best_output_pin(&mut self, codec: CodecAddr) -> Result<WidgetAddr>`
|
||||
|
||||
Ensure all widget lookups use the selected codec topology map.
|
||||
|
||||
6. Update path walk helpers to consume codec-scoped maps.
|
||||
|
||||
- `find_path_to_dac()` should use the selected codec topology `widget_map`.
|
||||
- Avoid `.unwrap()` on map lookups in traversal; return `None`/`Err(ENODEV)` on missing nodes.
|
||||
|
||||
7. Update `configure()` to use selected codec.
|
||||
|
||||
- Choose codec via `pick_primary_codec_for_output()`.
|
||||
- Call `find_best_output_pin(codec)`.
|
||||
- Resolve DAC path only within that codec.
|
||||
|
||||
8. Update codec dump endpoint to expose all codecs.
|
||||
|
||||
- Keep `openat("codec")` behavior, but include per-codec sections in output.
|
||||
- Optional follow-up: add `codec/<n>` path support; not required for first slice.
|
||||
|
||||
9. Guard rails for no-audio cases.
|
||||
|
||||
- If codecs are present but no valid output topology found, return structured `ENODEV`.
|
||||
- Do not panic on `No output pins`.
|
||||
|
||||
### Non-goals for HDA-001
|
||||
|
||||
- Jack unsolicited handling (`HDA-002`)
|
||||
- Capture stream enablement (`HDA-005`)
|
||||
- Policy quirks (`HDA-008`)
|
||||
- HDMI/DP ELD path (`HDA-009`)
|
||||
|
||||
### Compile + runtime checks for this slice
|
||||
|
||||
1. Build driver package:
|
||||
|
||||
- `./target/release/repo cook recipes/core/base`
|
||||
- or full base target flow already used by this tree
|
||||
|
||||
2. Boot in QEMU with HDA enabled:
|
||||
|
||||
- validate `ihdad` starts without panic
|
||||
- read codec dump from `audiohw:codec`
|
||||
|
||||
3. Verify acceptance:
|
||||
|
||||
- Multiple codec entries are shown when available
|
||||
- Single-codec machines still work
|
||||
- No regression in existing playback path on QEMU ICH9 HDA
|
||||
|
||||
### Exit criteria for closing HDA-001
|
||||
|
||||
- Enumeration is no longer hardcoded to codec 0.
|
||||
- Playback path can choose a valid codec deterministically.
|
||||
- Codec dump includes all detected codecs.
|
||||
- `ihdad` no longer panics when output pins are missing on codec 0 but present on another codec.
|
||||
|
||||
## Claim Language Policy
|
||||
|
||||
Until G1-G5 gates are met, support claims must remain bounded:
|
||||
|
||||
- Use: "builds", "enumerates", "bounded playback proof"
|
||||
- Avoid: "full Intel audio support" or broad compatibility claims
|
||||
|
||||
## Related Documents
|
||||
|
||||
- `local/docs/LINUX-BORROWING-RUST-IMPLEMENTATION-PLAN.md`
|
||||
- `local/docs/QUIRKS-SYSTEM.md`
|
||||
- `local/docs/QUIRKS-IMPROVEMENT-PLAN.md`
|
||||
- `local/docs/CONSOLE-TO-KDE-DESKTOP-PLAN.md`
|
||||
- `docs/05-KDE-PLASMA-ON-REDOX.md`
|
||||
- `recipes/core/base/source/drivers/COMMUNITY-HW.md`
|
||||
@@ -27,7 +27,7 @@ This repo should not treat **builds** or **enumerates** as equivalent to **valid
|
||||
|
||||
USB driver code lives in `recipes/core/base/source/drivers/usb/`, which is an upstream-managed git
|
||||
working copy. Red Bear carries all USB modifications through `local/patches/base/redox.patch`
|
||||
(currently 5029 lines, 23 diff sections, 16 USB/HID/storage-related).
|
||||
(currently ~17000 lines across ~100 diff sections).
|
||||
|
||||
**Upstream state** — the unpatched source snapshot that `make fetch` produces — has significant
|
||||
error handling gaps and several correctness bugs. Red Bear's patch layer fixes these, but the fixes
|
||||
@@ -124,7 +124,7 @@ source:
|
||||
|
||||
Even with the Red Bear patch applied:
|
||||
|
||||
- HID is still wired through the legacy mixed-stream `inputd` path
|
||||
- HID is now wired through named producers (`ps2-keyboard`, `ps2-mouse`, `usb-{port}-if{n}`); named producers always fan out to both per-device consumers and the legacy VT consumer path; the `InputProducer` wrapper falls back to an anonymous legacy `ProducerHandle` if the named path is unavailable (e.g., older `inputd` build)
|
||||
- external USB keyboard fallback is not guaranteed on bare metal unless the keyboard reaches the
|
||||
xHCI runtime path
|
||||
- EHCI/UHCI/OHCI are not yet full runtime host-controller implementations
|
||||
@@ -151,11 +151,11 @@ Even with the Red Bear patch applied:
|
||||
| xHCI controller | **builds / QEMU-validated** | Red Bear patch: 88 error handling fixes, ERDP split, endp_direction fix, cfg_idx fix, real grow_event_ring, mutex poison recovery on all hot-path locks; no real hardware validation yet |
|
||||
| EHCI/UHCI/OHCI | **builds / enumerates** | Ownership, port handling, and logging exist, but they are not yet full runtime enumeration paths |
|
||||
| Hub handling | **builds / good quality** | `usbhubd`: all `expect()` eliminated, interrupt-driven change detection with polling fallback, graceful per-port error handling |
|
||||
| HID | **builds / QEMU-validated in narrow path** | `usbhidd` handles keyboard/mouse/button/scroll via legacy input path, no panics in report loop; keyboard LED sync exists as a bounded per-device best-effort path |
|
||||
| HID | **builds / QEMU-validated in narrow path** | `usbhidd` handles keyboard/mouse/button/scroll via named producer path (`usb-{port}-if{n}`) with legacy fallback, no panics in report loop; keyboard LED sync exists as a bounded per-device best-effort path |
|
||||
| Mass storage | **builds / good quality** | `usbscsid`: typed `ScsiError`, fallible parsing, `ReadCapacity16` for >2TB, stall recovery, resilient event loop |
|
||||
| Native tooling | **builds / enumerates** | `lsusb`, `usbctl`, `redbear-info`, `redbear-usb-check` provide observability |
|
||||
| Low-level userspace API | **builds** | `xhcid_interface` with `UsbSpeed` enum, `attach_with_speed()` |
|
||||
| Validation | **builds / QEMU-only** | 3 harness scripts + in-guest checker; no real hardware validation scripts |
|
||||
| Validation | **builds / QEMU-only** | 4 harness scripts + in-guest checker; no real hardware validation scripts |
|
||||
| Hardware quirks | **builds** | `redox-driver-sys` quirk tables with 146 compiled-in USB quirk entries (mined from Linux 7.0) + 22 USB quirk flags; runtime TOML loading for `/etc/quirks.d/` |
|
||||
|
||||
## Code Quality by Daemon
|
||||
@@ -183,7 +183,7 @@ Key files and their sizes:
|
||||
| Daemon | Lines | Error Handling Quality | Remaining unwrap/expect | Key Gaps |
|
||||
|---|---|---|---|---|
|
||||
| `usbhubd` | ~430 | **Good** — `Result<(), Box<dyn Error>>`, all `expect()` eliminated, interrupt-driven change detection | 0 | 1-second polling fallback if interrupt EP unavailable |
|
||||
| `usbhidd` | 576 | **Good** — `anyhow::Result` with context, zero `unwrap()`/`expect()` | 0 | Hardcoded 1ms poll rate; mouse ×2 multiplier workaround; X scroll missing |
|
||||
| `usbhidd` | 576 | **Good** — `anyhow::Result` with context, no panics in report loop; `expect()` remains in arg parsing and descriptor setup (pre-existing) | 7 `expect()` + 1 `assert_eq!` (pre-existing, arg parsing/descriptor setup) | Hardcoded 1ms poll rate; mouse ×2 multiplier workaround; X scroll missing |
|
||||
| `usbscsid` | ~1800 | **Good** — `ScsiError` typed errors, fallible `parse_bytes`/`parse_mut_bytes` helpers, resilient event loop, `ReadCapacity16` | 0 | — |
|
||||
|
||||
## Validation Infrastructure
|
||||
@@ -301,8 +301,19 @@ hardware; controller enumerates attached devices reliably across repeated boot c
|
||||
|
||||
**Remaining**:
|
||||
- Validate repeated attach/detach/reset behavior under stress (requires real hardware)
|
||||
- Support non-default configurations and alternate settings (requires xHCI config logic in scheme.rs)
|
||||
- Improve composite-device handling and endpoint selection across interfaces (requires xHCI config logic in scheme.rs)
|
||||
|
||||
**Completed (Red Bear patch, this session)**:
|
||||
- `configure_endpoints_once()` now filters endpoints by specific interface+alternate when
|
||||
`req.interface_desc` is set, enabling composite-device drivers to claim individual interfaces
|
||||
without programming endpoints from other interfaces
|
||||
- When `interface_desc` is `None` (initial device setup), endpoints are collected from all
|
||||
default-alternate (alt 0) interfaces, preserving backward compatibility
|
||||
- `PortState.active_ifaces: BTreeMap<u8, u8>` tracks which interface numbers are active and
|
||||
which alternate setting each is using
|
||||
- `set_interface()` now updates `active_ifaces` after a successful SET_INTERFACE control request
|
||||
- `spawn_drivers()` logs non-default alternates at debug level instead of warning, documenting
|
||||
that non-default alternates are selected by drivers via SET_INTERFACE rather than auto-spawn
|
||||
- Initial configuration populates `active_ifaces` with all default-alternate interfaces
|
||||
|
||||
**Where**: `recipes/core/base/source/drivers/usb/usbhubd/`, `xhcid/src/xhci/scheme.rs`
|
||||
|
||||
@@ -316,14 +327,25 @@ least one composite device configures correctly beyond the simplest path.
|
||||
**Status**: Partially complete.
|
||||
|
||||
**Completed (Red Bear patch)**:
|
||||
- `usbhidd` error handling improved — `anyhow::Result` with context, no panics in report loop, zero `unwrap()`/`expect()` calls
|
||||
- `assert_eq!` replaced with `anyhow::bail!`
|
||||
- `usbhidd` error handling improved — `anyhow::Result` with context, no panics in report loop; `expect()`/`assert_eq!` remain in arg parsing and descriptor setup (pre-existing)
|
||||
- Display write failures logged as warnings instead of panicking
|
||||
- `inputd` scheme enhancement: named producers (`/scheme/input/producer/{name}`), per-device
|
||||
consumer streams (`/scheme/input/{device_name}`), hotplug event stream (`/scheme/input/events`),
|
||||
root directory enumeration (static entries + dynamic device names)
|
||||
- Named producer events fan out to both matching DeviceConsumers and the legacy VT consumer path
|
||||
- Hotplug binary format: 16-byte header (kind, device_id, name_len, reserved) + UTF-8 name
|
||||
- Device IDs allocated monotonically, never reused
|
||||
- Public API: `NamedProducerHandle`, `DeviceConsumerHandle`, `HotplugHandle`, `InputDeviceLister`,
|
||||
`InputProducer` (named-first, legacy-fallback convenience wrapper)
|
||||
- All legacy paths, event payloads, VT behavior, and display/control behavior preserved unchanged
|
||||
- `ps2d` migrated: two `InputProducer` instances (`ps2-keyboard`, `ps2-mouse`), keyboard events
|
||||
route to `keyboard_input`, mouse events to `mouse_input`, named-first with legacy fallback
|
||||
- `usbhidd` migrated: one `InputProducer` per interface instance (`usb-{port}-if{n}`), named-first
|
||||
with legacy fallback
|
||||
|
||||
**Remaining** (all require architectural changes to `inputd`, not USB-internal code):
|
||||
- Migrate `usbhidd` toward named producers and per-device streams (requires inputd redesign)
|
||||
- Expose hotplug add/remove behavior cleanly to downstream consumers (requires inputd redesign)
|
||||
- Align USB HID with the `inputd` enhancement design already documented in-tree (cross-cutting)
|
||||
**Remaining** (requires downstream consumer/driver migration, not inputd scheme changes):
|
||||
- Migrate `i2c-hidd` to named producers (still uses legacy `ProducerHandle`)
|
||||
- Expose hotplug add/remove behavior to downstream consumers via `evdevd` migration
|
||||
|
||||
**Where**: `recipes/core/base/source/drivers/input/usbhidd/`, `inputd/`,
|
||||
`local/docs/INPUT-SCHEME-ENHANCEMENT.md`
|
||||
@@ -685,7 +707,7 @@ The remaining gaps now fall into two categories:
|
||||
**Broader architectural work (cross-cutting, not a small bounded USB-only fix):**
|
||||
- Any remaining USB composite/device-model issues now belong to wider device-model/design cleanup
|
||||
rather than one more isolated helper patch.
|
||||
- HID producer modernization: per-device streams, hotplug add/remove (requires inputd redesign)
|
||||
- HID producer modernization: per-device streams via named producers, hotplug add/remove (inputd redesign complete, ps2d and usbhidd migrated)
|
||||
- Userspace USB API: `libusb` WIP, no coherent native story
|
||||
|
||||
**Hardware-dependent or design decisions:**
|
||||
|
||||
+1030
-84
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,44 @@
|
||||
# Audio controller and codec quirks.
|
||||
# These apply to HDA controllers and codec devices.
|
||||
|
||||
# Intel ICH8 HDA — force EAPD on outputs
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x284b
|
||||
flags = ["audio_force_eapd"]
|
||||
|
||||
# Intel ICH9 HDA (QEMU) — use immediate command interface
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x293e
|
||||
flags = ["audio_single_cmd"]
|
||||
|
||||
# Intel 6-series PCH HDA — position fix LPIB
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x1c20
|
||||
flags = ["audio_position_fix_lpib"]
|
||||
|
||||
# Intel 7-series PCH HDA — position fix LPIB
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x1e20
|
||||
flags = ["audio_position_fix_lpib"]
|
||||
|
||||
# Intel Sunrise Point HDA — position fix LPIB
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0xa170
|
||||
flags = ["audio_position_fix_lpib"]
|
||||
|
||||
# Intel Cannon Point HDA — position fix LPIB
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x9dc8
|
||||
flags = ["audio_position_fix_lpib"]
|
||||
|
||||
# AMD FCH HDA — single command fallback
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1022
|
||||
device = 0x1457
|
||||
flags = ["audio_single_cmd"]
|
||||
Reference in New Issue
Block a user