Userspace PS/2 input path (keyboard + mouse)

This page describes how PS/2 keyboard and mouse data leave ring 0 for ps2d, then reach deskgui and WM v1 clients.

Warning

This page is partially stale relative to current init/service ordering. For current canonical behavior, see newdocs/boot-and-init.md, newdocs/system-architecture.md, and newdocs/settings-control-pattern.md.

Boot order

init (apps/init/src/main.rs) spawns ps2d early, then control-plane daemons (p1-netmgr, p1-timesvc, p1-powersvc, p1-dispsvc, p1-gamesvc) before deskgui (legacy userspace NIC mode inserts netd after ps2d; see newdocs/boot-and-init.md). ps2d sends SERVICE_READY (100) to PID 1 after subscribing.

Layers

IRQ 1 / IRQ 12  →  kernel PS/2 drain (`read_all_pending`)
              │
              ├─► irq_subscribe (226): raw `inb(0x60)` → IPC to **ps2d** (only when legacy poll path **off**)
              │         per-IRQ spill (512) if broker contended
              │
              └─► InputState → sys_poll_ui_events (101) → compositor (only when legacy path **on**)

ps2d:  ordered stream ring → KeyboardState + MousePacketizer
       → syscall 50: 250 (keys), 251 (mouse deltas + buttons)

deskgui:  recv 250 → forward_keyboard…(p1) → type 4 to clients
          recv 251 → merge cursor + buttons (when legacy **off**)

Syscall 226 (irq_subscribe)

  • rdi: IRQ 1 (keyboard) or 12 (PS/2 aux / mouse).

  • rsi: subscriber PID (must equal caller getpid).

  • rdx: syscall-50 message_type for each raw byte delivery.

  • Payload: p1 = byte from 0x60; p2/p3 = 0; sender_pid = 0.

IPC 250 / 251 (not syscall numbers)

Constants live in apps/deskgui/src/api/window.rs.

250 — WIRE_PS2D_KEY_EVENT

Field

Meaning

p1

Legacy WM scancode byte (make / break with 0x80).

p2

Low 32: key; high 32: modifier mask (apps/ps2d/src/keyboard.rs).

p3

1 = down, 0 = up.

251 — WIRE_PS2D_MOUSE_EVENT

Field

Meaning

p1

Low 16 bits = dx, next 16 = dy (i16 wire encoding).

p2

Bit 0 left, bit 1 right; bits 16..31 = wheel dz (i16).

p3

Reserved 0.

Kill switch: input/legacy_ps2_kernel_path

RegCube HIVE_LOCAL_MACHINE / input/legacy_ps2_kernel_path. Kernel bootstrap sets 0 (src/main.rs).

Value (trimmed, case-insensitive)

Effect

0, false, off, no, missing, empty

Userspace path: no PS/2 scancode / mouse motion in InputState queues for poll_ui_events; IRQ raw bytes go only to ps2d when it is subscribed. Alt+Tab / Alt+F4 and key_state still update.

1, true, on, yes, or any other token

Legacy path: kernel fills scancode_queue and mouse deltas as before; IRQ IPC to ps2d is not delivered (avoids duplicate input if ps2d is still running).

ps2d queuing

A 1024-slot ordered stream holds (keyboard | mouse) bytes in IRQ arrival order before decode.

Intended end state: /dev/ps2kbd / /dev/ps2mouse

See earlier roadmap: character devices with open / read / poll, compositor and gterm consuming them instead of raw IPC opcodes. Until then, 250 / 251 are the stable wire.

Client apps (gterm)

Graphical terminals use p1window try_recv_event and WmEvent::Keyboard / Mouse — compositor opcode 4 / 3 only. They do not use kernel read(0) PS/2 shortcuts.

Keyboard layout (today)

p1keyboard-layout provides PS/2 set‑1 main-cluster US QWERTY maps to ps2d and gterm. No RegCube layout key is read yet; src/sys/keyboard_layout.rs remains kernel-only / future use.

See newdocs/keyboard-input-and-layout.md for policy (Ctrl+Shift+Q, extended prefix behavior) and roadmap (locale, UTF‑8).

See also