v6.0 plan: single evdev producer architecture (inputd deprecated for desktop)
After review push-back on the dual-path (orbclient + evdev) input
architecture, the v6.0 plan is simplified to a single evdev producer
model. The user committed: 'we do not use Orbital and do not plan to
use it. we aim for wayland/kde.'
The dual-path was rejected for:
- Doubling every driver's event-write code
- Doubling per-event syscall cost
- Out-of-order risk between the two producers
- Translating back and forth loses metadata
- No desktop consumer actually needs Orbital
The corrected architecture:
Hardware
-> single /scheme/input/evdev producer (Linux struct input_event)
-> evdevd (pure scheme->/dev/input/eventN adapter)
-> /dev/input/eventN
-> libinput in-process to KWin (user session)
-> libinput in-process to redbear-compositor (greeter)
-> direct evdev fd (Qt6 apps that need raw access)
inputd is deprecated for the desktop config. It stays in the tree
only as a historical daemon.
What this changes:
1. Phase 1 effort drops from 1-2 weeks to 1 week
2. Drivers change ONCE (replace ProducerHandle with
EvdevProducerHandle) instead of dual-writing
3. evdevd refactor is now cleaner: just switch its consumer from
/scheme/input/consumer (orbclient) to /scheme/input/evdev
(Linux evdev)
4. inputd/src/lib.rs gains a new EvdevProducerHandle, EvdevEvent,
keycodes module — committed in the base fork first
Plan updates:
- Section 2 (Unified Input Architecture) rewritten to 'Single-Producer
Input Architecture'
- Critical path Phase 1 row updated to reflect 1-week effort
- Executive summary text updated
- 'Two Architecture Decisions Resolved' updated to reflect
Orbital-out decision
This commit is contained in:
@@ -80,21 +80,24 @@ was cross-referenced (see §5 and §8).
|
||||
|
||||
### Two Architecture Decisions Resolved (v6.0)
|
||||
|
||||
1. **Unified input architecture**: Red Bear has had THREE input subsystems running in parallel
|
||||
(`inputd` for Orbital, `evdevd` for Linux-compat, plus per-driver schemes). v6.0 collapses
|
||||
this to **one input path** that all consumers (Orbital, KWin, redbear-compositor, libinput)
|
||||
read from. See §3.
|
||||
1. **Single evdev producer (no Orbital on the desktop)**: Red Bear has had THREE input subsystems
|
||||
running in parallel (`inputd` for Orbital, `evdevd` as a bridge, plus per-driver schemes). The
|
||||
user explicitly committed to **"we do not use Orbital and do not plan to use it. we aim for
|
||||
wayland/kde."** So v6.0 collapses to **one input path** — drivers write Linux `struct input_event`
|
||||
records to `/scheme/input/evdev`, `evdevd` exposes them as `/dev/input/eventN`, libinput (in-process
|
||||
to KWin and to redbear-compositor) reads from there. `inputd` is deprecated for the desktop
|
||||
config; it stays in the tree only as legacy. See §2.
|
||||
|
||||
2. **Compositor decision**: KWin is the canonical Wayland compositor. `redbear-compositor`
|
||||
(788-line Rust) is **not** extended to production quality — instead it serves only the
|
||||
greeter phase. KWin takes over for the user session. See §4.
|
||||
greeter phase. KWin takes over for the user session. See §3.
|
||||
|
||||
### Critical Path Phases (v6.0)
|
||||
|
||||
| Phase | Name | Effort | Gate |
|
||||
|-------|------|--------|------|
|
||||
| 0 | Pre-flight: QML JIT + kf6-kdeclarative QML re-enable | 4-6 weeks | Qt6Quick works in QEMU |
|
||||
| 1 | Unified input architecture: inputd + evdevd merge → `/scheme/input/events` | 1-2 weeks | evdevd reads from new unified scheme |
|
||||
| 1 | Single evdev producer: drivers write `/scheme/input/evdev`, evdevd exposes `/dev/input/eventN`, libinput reads (inputd deprecated for desktop) | 1 week | evdevd reads from `/scheme/input/evdev`; libinput sees real events |
|
||||
| 2 | DRM atomic modeset + render node + PRIME real FDs + RESOURCE_MAP_BLOB | 2-3 weeks | redbear-compositor opens `renderD128` |
|
||||
| 3 | Mesa EGL Wayland fix (remove `-lorbital`, add `-lwayland-client`) | 1 week | Qt6 eglfs opens Wayland window |
|
||||
| 4 | redbear-compositor → libinput + kf6-kwayland protocol coverage | 2-3 weeks | Qt6 app runs under redbear-compositor |
|
||||
@@ -143,9 +146,9 @@ The 110 missing components include the most critical: **PipeWire**, **KWin full
|
||||
### Bottom Line
|
||||
|
||||
Red Bear OS has all the *foundations* of a desktop OS — kernel, ACPI, IRQ, low-level drivers,
|
||||
DRM scheme, Mesa, Qt6, KF6 recipes, greeter, session broker. What's missing is a *single
|
||||
coherent input stack* (inputd/evdevd are now dual), *KWin running as compositor* (the QML gate),
|
||||
and *Plasma shell apps* (plasma-desktop, dolphin, etc.).
|
||||
DRM scheme, Mesa, Qt6, KF6 recipes, greeter, session broker. What's missing is the *single
|
||||
evdev producer and consumer* (Phase 1), *KWin running as compositor* (the QML gate, Phase 0),
|
||||
and *Plasma shell apps* (plasma-desktop, dolphin, etc., Phase 7).
|
||||
|
||||
The v6.0 plan commits to:
|
||||
- One unified input path (inputd + evdevd merged via shared scheme)
|
||||
@@ -197,38 +200,46 @@ Remaining gaps:
|
||||
|
||||
---
|
||||
|
||||
## 2. Unified Input Architecture (v6.0 — replaces inputd/evdevd split)
|
||||
## 2. Single-Producer Input Architecture (v6.0)
|
||||
|
||||
### 2.1 The Problem
|
||||
|
||||
Red Bear OS has accumulated **three input subsystems** in parallel, each serving different
|
||||
downstream consumers:
|
||||
Red Bear OS has accumulated **three input subsystems** in parallel:
|
||||
|
||||
```
|
||||
ps2d/usbhidd/i2c-hidd/intel-thc-hidd/virtio-inputd
|
||||
│
|
||||
├── orbclient::Event ──→ inputd (scheme:input) ──→ Orbital compositor
|
||||
│ ──→ evdevd (converts orbclient → input_event)
|
||||
│ │
|
||||
│ └─→ /dev/input/eventN
|
||||
│
|
||||
└── evdev_format ──→ ??? (no driver writes evdev directly yet)
|
||||
└── (none, would need to write evdev)
|
||||
▲
|
||||
│
|
||||
evdevd (consumes inputd's orbclient events, re-emits as evdev)
|
||||
│
|
||||
└─→ /dev/input/eventN
|
||||
```
|
||||
|
||||
**The inputd → evdevd bridge is wrong architecture.** evdevd is a Linux-compatibility shim that
|
||||
takes Orbital's orbclient events and re-emits them as Linux evdev events. The conversion loses:
|
||||
- Timestamps (orbclient `Event` has none)
|
||||
- EV_ABS axis ranges (no absinfo)
|
||||
- EV_SYN/SYN_DROPPED flow (orbclient has no SYN)
|
||||
- Device ID/vendor/product (no metadata in orbclient)
|
||||
- Real-time behavior (inputd round-trips through a scheme)
|
||||
The v5.0 "dual-path" plan (drivers write to BOTH orbclient and evdev producers) was
|
||||
initially proposed for v6.0, then **rejected** on review. The reasons:
|
||||
|
||||
**CachyOS reference**: kernel evdev → libinput (CLIENT LIBRARY) → compositor. libinput is NOT a
|
||||
daemon. It reads `/dev/input/event*` devices directly. The CachyOS architecture has ONE input path.
|
||||
1. **Doubles every driver's event-write code** — every key press, every mouse delta,
|
||||
every button click has to be written twice
|
||||
2. **Doubles the per-event syscall cost** — 2 writes instead of 1
|
||||
3. **Out-of-order risk** — if one producer is slower than the other, events get
|
||||
misaligned between Orbital and KWin views of the same physical input
|
||||
4. **No consumer actually needs Orbital on the desktop** — KWin + redbear-compositor
|
||||
(for the greeter) are the only consumers on the desktop path. The user
|
||||
explicitly committed: **"we do not use Orbital and do not plan to use it.
|
||||
we aim for wayland/kde"**
|
||||
5. **Extra translation hop loses metadata** — timestamps, EV_ABS axis ranges,
|
||||
EV_SYN/SYN_DROPPED, vendor/product IDs, real-time ordering
|
||||
|
||||
### 2.2 The Unified Input Architecture
|
||||
### 2.2 The Decision: Single evdev Producer
|
||||
|
||||
v6.0 introduces a **single input path** that all consumers read from:
|
||||
**v6.0 commits to a single Linux evdev producer.** All input drivers write Linux
|
||||
`struct input_event` records to one scheme. `evdevd` is a thin adapter from
|
||||
that scheme to `/dev/input/eventN`. libinput (in-process to KWin and to
|
||||
redbear-compositor during the greeter phase) reads from `/dev/input/event*`.
|
||||
|
||||
```
|
||||
Hardware
|
||||
@@ -240,98 +251,98 @@ Hardware
|
||||
├── virtio-inputd (QEMU virtio-input)
|
||||
│
|
||||
▼
|
||||
ALL drivers write to ONE of two scheme producers:
|
||||
ONE producer: /scheme/input/evdev
|
||||
(Linux struct input_event, 8 bytes per event: type, code, value)
|
||||
│
|
||||
├── /scheme/input/orbclient (for Orbital compositor — ORBCLIENT format)
|
||||
│ └─→ inputd (subsumes current inputd) → Orbital display server
|
||||
▼
|
||||
evdevd (pure scheme → /dev/input/eventN adapter)
|
||||
│
|
||||
└── /scheme/input/evdev (for KWin + libinput + redbear-compositor — LINUX EVDEV format)
|
||||
└─→ /dev/input/eventN (via udev-shim)
|
||||
└─→ libinput (in-process to KWin / redbear-compositor)
|
||||
└─→ wl_seat events to Wayland clients
|
||||
|
||||
Both producers are WRITTEN by the same input drivers — they are sibling destinations.
|
||||
▼
|
||||
/dev/input/eventN (Linux native evdev)
|
||||
│
|
||||
├── libinput (in-process to KWin) → KWin wl_seat → Wayland clients
|
||||
├── libinput (in-process to redbear-compositor) → greeter wl_seat (Qt6/QML UI)
|
||||
└── Direct fd (Qt6 apps that don't use libinput) → KDE app input
|
||||
```
|
||||
|
||||
**Key changes:**
|
||||
### 2.3 What This Means for Each Component
|
||||
|
||||
1. **Each input driver writes to BOTH producers** (dual-path). The conversion to evdev format
|
||||
happens INSIDE each driver (using its own knowledge of the device: e.g. ps2d knows the scancode
|
||||
table; usbhidd knows HID usage codes; virtio-inputd knows Linux evdev semantics natively).
|
||||
| Component | Change |
|
||||
|-----------|--------|
|
||||
| `inputd` | **Deprecated for the desktop config.** Stays in the tree only as a historical Orbital daemon — never started by `redbear-full.toml` or `redbear-greeter-services.toml`. The `lib.rs` exposes the new `EvdevProducerHandle` for drivers that want to use it, and keeps the legacy `ProducerHandle` for any code that still uses Orbital. |
|
||||
| `evdevd` | **Re-scoped to a pure scheme→/dev/input/eventN adapter.** Consumes from `/scheme/input/evdev` (the new single producer). Removes the orbclient consumer path. |
|
||||
| `ps2d`, `usbhidd`, `i2c-hidd`, `intel-thc-hidd` | **Replace `ProducerHandle` with `EvdevProducerHandle`.** Convert orbclient scancodes/mouse-deltas to Linux evdev at the driver (where device knowledge lives). |
|
||||
| `virtio-inputd` (v5.1) | **Use `EvdevProducerHandle` in Phase 5.2 expansion.** The driver already has Linux keycode semantics natively — translation is trivial. |
|
||||
| `redbear-greeter` | Uses libinput or direct `/dev/input/event*` fd. Qt6 reads from these directly. No Orbital dependency. |
|
||||
| KWin | Uses libinput (in-process). Reads from `/dev/input/event*`. Same as CachyOS. |
|
||||
| `redbear-compositor` (greeter only) | Uses libinput (in-process). Same as CachyOS. |
|
||||
|
||||
2. **inputd is re-scoped** to be the Orbital-side multiplexer only. It consumes from
|
||||
`/scheme/input/orbclient` and produces to Orbital. **It no longer has an evdev-format consumer.**
|
||||
### 2.4 Driver-Side Implementation (v6.0 Phase 1)
|
||||
|
||||
3. **evdevd is re-scoped** to be a pure scheme-to-`/dev/input/eventN` adapter. It consumes from
|
||||
`/scheme/input/evdev` and produces Linux evdev events. **It no longer translates orbclient events.**
|
||||
| Driver | Current state | Required change |
|
||||
|--------|--------------|-----------------|
|
||||
| `ps2d` | Writes orbclient::Event with orbclient keycodes | Replace with `EvdevProducerHandle`. Convert orbclient `K_*` keycodes to Linux `KEY_*` keycodes (we have most of this table already). |
|
||||
| `usbhidd` | Writes orbclient::Event with orbclient keycodes | Replace with `EvdevProducerHandle`. Convert HID usage codes to Linux keycodes. |
|
||||
| `i2c-hidd` | Same as usbhidd (I2C HID is HID) | Replace with `EvdevProducerHandle`. |
|
||||
| `intel-thc-hidd` | Same as usbhidd (Intel THC is HID) | Replace with `EvdevProducerHandle`. |
|
||||
| `virtio-inputd` (v5.1) | Writes orbclient::Event | **Phase 5.2 expansion**: switch to `EvdevProducerHandle`. The driver already speaks Linux evdev natively. |
|
||||
| `redbear-keymapd` | Consumes keymaps (not events) | No change. |
|
||||
|
||||
4. **redbear-compositor and KWin** consume from `/dev/input/event*` via libinput (client library)
|
||||
or via direct evdev ioctls.
|
||||
**Effort per driver**: 1-2 days. Total: **~1 week** (much smaller than the dual-path 1-2 weeks).
|
||||
|
||||
### 2.3 Driver-Side Implementation (v6.0 Phase 1)
|
||||
### 2.5 Scheme API (v6.0)
|
||||
|
||||
| Driver | /scheme/input/orbclient writes | /scheme/input/evdev writes |
|
||||
|--------|-------------------------------|-----------------------------|
|
||||
| `ps2d` | Already does this (ProducerHandle) | **Add**: write evdev events with proper input_event struct (time/type/code/value) |
|
||||
| `usbhidd` | Already does this (ProducerHandle) | **Add**: write evdev events with HID usage → Linux keycode mapping |
|
||||
| `i2c-hidd` | Already does this | **Add**: same as usbhidd |
|
||||
| `intel-thc-hidd` | Already does this | **Add**: same as usbhidd |
|
||||
| `virtio-inputd` (v5.1) | Already does this (ProducerHandle) | **Add**: write evdev events (its native format — Phase 5.2 expansion) |
|
||||
| `redbear-keymapd` | n/a | n/a (consumes keymaps, not events) |
|
||||
|
||||
**Effort per driver**: 1-2 days each (3-5 files, ~100-200 lines). Total: 1-2 weeks for all 5 drivers.
|
||||
|
||||
### 2.4 Scheme API (v6.0)
|
||||
|
||||
**`/scheme/input/orbclient`** (replaces current `/scheme/input/producer`):
|
||||
- Producers: `ProducerHandle::new()` returns File at `/scheme/input/orbclient`
|
||||
- Consumer: inputd opens `/scheme/input/orbclient_consumer` and reads orbclient::Event (24 bytes each)
|
||||
- Inputd then forwards to Orbital's `/scheme/display` consumer
|
||||
|
||||
**`/scheme/input/evdev`** (replaces current evdevd's `input:consumer` input):
|
||||
**`/scheme/input/evdev`** (new, single producer):
|
||||
- Producers: `EvdevProducerHandle::new()` returns File at `/scheme/input/evdev`
|
||||
- Producer writes Linux `struct input_event` (24 bytes: u16 type, u16 code, s32 value, u32 time_sec,
|
||||
u32 time_usec — wait, 16 bytes actually: type, code, value) on each event
|
||||
- Consumer: evdevd opens `/scheme/input/evdev_consumer` and creates `/dev/input/eventN` files with EVIOC ioctls
|
||||
- Wire format: 8 bytes per event — `u16 type, u16 code, i32 value` (the Linux `struct input_event` with no time fields; `evdevd` adds timestamps when the device is opened, just like CachyOS)
|
||||
- Synchronization: producers MUST emit `EV_SYN / SYN_REPORT / value=0` between batches of events to mark a logical report boundary
|
||||
- Consumer: `evdevd` opens `/scheme/input/evdev_consumer` and creates `/dev/input/eventN` files with full EVIOC ioctl support
|
||||
|
||||
**`/dev/input/eventN`** (unchanged):
|
||||
- Same Linux evdev interface as today
|
||||
- libinput (in-process to KWin or compositor) opens these as fds and reads 16-byte `struct input_event`
|
||||
- Standard Linux evdev interface
|
||||
- libinput (in-process to KWin / redbear-compositor) opens these as fds and reads `struct input_event`
|
||||
- This is what CachyOS uses and what the Linux 7.1 kernel implements
|
||||
|
||||
### 2.5 Migration Plan (v6.0 Phase 1)
|
||||
**`/scheme/input/producer`** (legacy, unchanged):
|
||||
- Existing orbclient::Event producer
|
||||
- Kept in the tree for any code that still needs to feed Orbital
|
||||
- NOT used by desktop drivers or the desktop init configuration
|
||||
|
||||
### 2.6 Migration Plan (v6.0 Phase 1)
|
||||
|
||||
| Step | Files | Action |
|
||||
|------|-------|--------|
|
||||
| 1.1 | New file `local/sources/base/drivers/inputd/src/evdev_producer.rs` | Add evdev-format producer to inputd |
|
||||
| 1.2 | Modify `local/sources/base/drivers/input/ps2d/src/main.rs` | Add dual-write to `/scheme/input/evdev` |
|
||||
| 1.3 | Modify `local/sources/base/drivers/input/usbhidd/src/main.rs` | Add dual-write to `/scheme/input/evdev` |
|
||||
| 1.4 | Modify `local/sources/base/drivers/input/i2c-hidd/src/main.rs` | Add dual-write to `/scheme/input/evdev` |
|
||||
| 1.5 | Modify `local/sources/base/drivers/input/intel-thc-hidd/src/main.rs` | Add dual-write to `/scheme/input/evdev` |
|
||||
| 1.6 | Modify `local/recipes/drivers/virtio-inputd/source/src/main.rs` (Phase 5.2) | Use evdev producer (its native format) |
|
||||
| 1.7 | Modify `local/recipes/system/evdevd/source/src/main.rs` | Remove orbclient consumer; add evdev scheme consumer |
|
||||
| 1.8 | Modify `config/redbear-full.toml` | Add `input:evdev` to init (or already implied) |
|
||||
| 1.9 | Modify `local/recipes/system/udev-shim/` | Update to expose new scheme paths |
|
||||
| 1.1 | `local/sources/base/drivers/inputd/src/lib.rs` | ✅ DONE: added `EvdevProducerHandle`, `EvdevEvent`, `keycodes` module |
|
||||
| 1.2 | `local/sources/base/drivers/input/ps2d/src/main.rs` + `state.rs` | Convert orbclient keycodes to Linux keycodes, replace `ProducerHandle` with `EvdevProducerHandle` |
|
||||
| 1.3 | `local/sources/base/drivers/input/usbhidd/src/main.rs` | Same — convert HID usage to Linux keycodes |
|
||||
| 1.4 | `local/sources/base/drivers/input/i2c-hidd/src/main.rs` | Same |
|
||||
| 1.5 | `local/sources/base/drivers/input/intel-thc-hidd/src/main.rs` | Same |
|
||||
| 1.6 | `local/recipes/drivers/virtio-inputd/source/src/main.rs` (Phase 5.2) | Use evdev producer (its native format) |
|
||||
| 1.7 | `local/recipes/system/evdevd/source/src/main.rs` | Switch consumer from `/scheme/input/consumer` (orbclient) to `/scheme/input/evdev` (new single producer) |
|
||||
| 1.8 | `config/redbear-full.toml` | Add `evdevd` to init services; remove `inputd` (it was never started here anyway) |
|
||||
| 1.9 | `local/recipes/system/udev-shim/` | Update scheme mapping to expose new `/dev/input/eventN` from evdevd |
|
||||
|
||||
### 2.6 Verification (v6.0 Phase 1 Gate)
|
||||
### 2.7 Verification (v6.0 Phase 1 Gate)
|
||||
|
||||
- [ ] `ps2d` writes evdev events with valid timestamps (monotonic, not zero)
|
||||
- [ ] `usbhidd` evdev events have correct vendor/product ID (forwarded from USB descriptors)
|
||||
- [ ] `evdevd` opens `/dev/input/event*` files with correct EVIOCGVERSION
|
||||
- [ ] A test program (C) opens `/dev/input/event0` and reads events as `struct input_event`
|
||||
- [ ] `ps2d` writes evdev events with valid Linux keycodes (KEY_* from input-event-codes.h)
|
||||
- [ ] `usbhidd` evdev events have correct HID usage → Linux keycode mapping
|
||||
- [ ] `evdevd` opens `/dev/input/event*` files with correct `EVIOCGVERSION` (returns EV_VERSION)
|
||||
- [ ] A C test program opens `/dev/input/event0` and reads events as `struct input_event`
|
||||
- [ ] libinput test program opens the same device and reports "keyboard found" (or pointer)
|
||||
- [ ] QEMU: pressing a key in PS/2 → libinput sees the event
|
||||
- [ ] No regression: Orbital login still works via the orbclient path
|
||||
- [ ] QEMU: pressing a key on PS/2 → libinput sees the event
|
||||
- [ ] QEMU: keyboard arrow keys work in greeter (Qt6 reads from /dev/input/event*)
|
||||
- [ ] QEMU: virtio-input keyboard works in greeter
|
||||
|
||||
### 2.7 Why This Matters
|
||||
### 2.8 Why This Matters
|
||||
|
||||
The v6.0 unified architecture:
|
||||
- **Matches CachyOS/Linux**: One kernel-evdev path that all consumers read
|
||||
The v6.0 single-producer architecture:
|
||||
- **Matches CachyOS/Linux exactly**: One kernel-evdev path that all consumers read
|
||||
- **Enables KWin**: KWin uses libinput which reads `/dev/input/event*` — same as CachyOS
|
||||
- **Enables Wayland clients**: redbear-compositor and KWin read from libinput
|
||||
- **Preserves Orbital**: inputd continues to serve Orbital, no regression
|
||||
- **Fixes metadata loss**: vendor/product ID, axis ranges, timestamps now flow through
|
||||
- **Simplifies the code**: One consumer per input type, no bridge
|
||||
- **Eliminates dual-write overhead**: drivers write ONCE
|
||||
- **Eliminates metadata loss**: vendor/product ID, axis ranges, timestamps all flow through
|
||||
- **Simplifies the code**: One producer, one consumer (`evdevd`), one path
|
||||
- **Removes dependency on Orbital** for the desktop: inputd is dead code in redbear-full
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user