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:
2026-04-24 20:25:00 +01:00
parent 55af4d097b
commit 08bea46575
7 changed files with 1803 additions and 138 deletions
+36 -2
View File
@@ -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]] [[files]]
path = "/usr/lib/init.d/00_base" 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]] [[files]]
path = "/usr/lib/init.d/00_drivers" path = "/usr/lib/init.d/00_drivers"
@@ -23,3 +46,14 @@ default_dependencies = false
cmd = "audiod" cmd = "audiod"
type = "oneshot_async" 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"
"""
+209 -11
View File
@@ -1,8 +1,8 @@
# Red Bear OS Boot Process Assessment & Improvement Plan # Red Bear OS Boot Process Assessment & Improvement Plan
**Generated:** 2026-04-23 **Generated:** 2026-04-23
**Updated:** 2026-04-23 **Updated:** 2026-04-24
**Status:** Phase 1 ✅, Phase 2 ✅, Phase 3 ✅, Phase 4 ✅ (docs + known gaps), Phase 5 ✅ **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 **Scope:** Comprehensive assessment of boot completeness, mistakes, robustness, resilience, and quality
## Boot Chain Overview ## Boot Chain Overview
@@ -128,12 +128,12 @@ Bare-metal testing requires physical hardware. Current validation is:
## Phase 5: Validation Matrix ✅ ## Phase 5: Validation Matrix ✅
### Build Verification ### Build Verification
| Target | Build | QEMU Boot | Notes | | Target | Build | QEMU Boot | Bare-Metal Boot | Notes |
|--------|-------|-----------|-------| |--------|-------|-----------|-----------------|-------|
| redbear-minimal | ✅ harddrive.img (2 GB) | ✅ Stage 2 (kernel loaded) | Login renders to framebuffer, not serial | | redbear-mini | ✅ harddrive.img (2 GB) | ✅ Login prompt | — | Framebuffer console login |
| redbear-full | ✅ harddrive.img (4 GB) | ✅ (prior session) | Greeter services load | | redbear-full | ✅ harddrive.img (4 GB) | ✅ Login prompt | — | Desktop packages included |
| redbear-live-mini | ✅ ISO (384 MB) | — | ISO for bare-metal boot | | redbear-live-mini | ✅ ISO (384 MB) | — | ✅ Login prompt | ISO for bare-metal boot |
| redbear-live | ✅ ISO (3.0 GB) | — | ISO for bare-metal boot | | redbear-live-full | ✅ ISO (3.0 GB) | — | — | ISO for bare-metal boot |
### Compilation Verification ### Compilation Verification
- `cargo check --workspace` in base source: **0 errors** - `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 ## 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 ### 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. `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 ### Config Include Chain
``` ```
redbear-minimal.toml → minimal.toml, redbear-legacy-base.toml, redbear-device-services.toml, redbear-netctl.toml redbear-live-full.toml redbear-live.toml
redbear-full.toml → desktop.toml, redbear-desktop.toml, redbear-greeter-services.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-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) ### 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/scripts/validate-service-files.sh` — manual service schema validation (redbear-*.toml only)
- `local/docs/BOOT-PROCESS-ASSESSMENT.md` — this document - `local/docs/BOOT-PROCESS-ASSESSMENT.md` — this document
- `recipes/core/base/source/init.initfs.d/41_acpid.service` — acpid in initfs (boot race fix) - `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/` |
+31 -27
View File
@@ -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. - `SchemeRoot` exists, but it is not a real directory yet: it does not enumerate entries.
- `lib.rs` only exposes `ProducerHandle`, `ConsumerHandle`, `DisplayHandle`, and `ControlHandle`. - `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. - `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` also opens one `ProducerHandle` and sends keyboard/mouse/button/scroll data into the same stream. - `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. - 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 ## 3. Design Principles
@@ -454,23 +454,20 @@ This keeps `DeviceConsumer` simple and avoids introducing a second handle teardo
## 13. Migration Path ## 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 `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
1. Try `NamedProducerHandle::new("ps2-keyboard")` 3. `Ps2d` struct holds `keyboard_input: InputProducer` + `mouse_input: InputProducer`
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()`
Routing: Routing:
- keyboard scancodes → `ps2-keyboard` - keyboard scancodes → `self.keyboard_input`
- mouse move / absolute move / button / scroll events → `ps2-mouse` - 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` ### 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. 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 ## 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: Another developer implementing this design should be able to proceed in this order:
1. extend `Handle` and `InputScheme` state 1. extend `Handle` and `InputScheme` state
2. teach `openat()` to parse `producer/{name}`, `events`, and dynamic device names 2. teach `openat()` to parse `producer/{name}`, `events`, and dynamic device names
3. add root `getdents()` support for `SchemeRoot` 3. add root `getdents()` support for `SchemeRoot`
4. refactor `write()` so producer type is detected before routing 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 5. fan out named-producer events to matching `DeviceConsumer` handles and the existing legacy path
6. add hotplug queue serialization helpers 6. add hotplug queue serialization helpers
7. extend `fevent()` and daemon notification loop for `DeviceConsumer` and `HotplugEvents` 7. extend `fevent()` and daemon notification loop for `DeviceConsumer` and `HotplugEvents`
8. add cleanup in `on_close()` for `NamedProducer` 8. add cleanup in `on_close()` for `NamedProducer`
9. extend `lib.rs` with the new handle types and directory lister 9. extend `lib.rs` with the new handle types and directory lister
10. migrate `ps2d` with a named-producer-first, legacy-fallback strategy 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 ## 17. Final Outcome
+417
View File
@@ -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`
+36 -14
View File
@@ -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 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` 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 **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 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: 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 - external USB keyboard fallback is not guaranteed on bare metal unless the keyboard reaches the
xHCI runtime path xHCI runtime path
- EHCI/UHCI/OHCI are not yet full runtime host-controller implementations - 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 | | 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 | | 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 | | 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 | | 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 | | 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()` | | 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/` | | 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 ## Code Quality by Daemon
@@ -183,7 +183,7 @@ Key files and their sizes:
| Daemon | Lines | Error Handling Quality | Remaining unwrap/expect | Key Gaps | | 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 | | `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 | — | | `usbscsid` | ~1800 | **Good**`ScsiError` typed errors, fallible `parse_bytes`/`parse_mut_bytes` helpers, resilient event loop, `ReadCapacity16` | 0 | — |
## Validation Infrastructure ## Validation Infrastructure
@@ -301,8 +301,19 @@ hardware; controller enumerates attached devices reliably across repeated boot c
**Remaining**: **Remaining**:
- Validate repeated attach/detach/reset behavior under stress (requires real hardware) - 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` **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. **Status**: Partially complete.
**Completed (Red Bear patch)**: **Completed (Red Bear patch)**:
- `usbhidd` error handling improved — `anyhow::Result` with context, no panics in report loop, zero `unwrap()`/`expect()` calls - `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)
- `assert_eq!` replaced with `anyhow::bail!`
- Display write failures logged as warnings instead of panicking - 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): **Remaining** (requires downstream consumer/driver migration, not inputd scheme changes):
- Migrate `usbhidd` toward named producers and per-device streams (requires inputd redesign) - Migrate `i2c-hidd` to named producers (still uses legacy `ProducerHandle`)
- Expose hotplug add/remove behavior cleanly to downstream consumers (requires inputd redesign) - Expose hotplug add/remove behavior to downstream consumers via `evdevd` migration
- Align USB HID with the `inputd` enhancement design already documented in-tree (cross-cutting)
**Where**: `recipes/core/base/source/drivers/input/usbhidd/`, `inputd/`, **Where**: `recipes/core/base/source/drivers/input/usbhidd/`, `inputd/`,
`local/docs/INPUT-SCHEME-ENHANCEMENT.md` `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):** **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 - Any remaining USB composite/device-model issues now belong to wider device-model/design cleanup
rather than one more isolated helper patch. 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 - Userspace USB API: `libusb` WIP, no coherent native story
**Hardware-dependent or design decisions:** **Hardware-dependent or design decisions:**
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"]