> For the complete documentation index, see [llms.txt](https://docs.kouch.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.kouch.dev/docs/adr/0002-dsu-primary-output.md).

# ADR 0002: DSU/Cemuhook as the primary controller output

## Status

Amended by ADR 0026 (2026-09-30): 8 players at most, every one with motion, on two DSU servers (26760–26761).

Accepted (2026-09-17 — see `docs/ARCHITECTURE.md` "Why DSU instead of virtual gamepads").

## Context

Kouch reads controllers through the platform's input service so that gyro/motion is available for every controller type it claims (Steam Controllers, the Deck's own controls, and any pad Steam claims exclusively expose motion through that path). The emulator Kouch launches is a separate process that cannot see that input service directly, and the platform's own gamepad emulation only hands a child process up to 4 XInput-class pads — nowhere near the 16 players Kouch targets. There are two ways to get input into an arbitrary number of player slots in a separate process: virtual gamepad devices, or a UDP-based protocol that emulators poll directly.

Virtual gamepads have real constraints: Linux `uinput` needs no driver and works well, but on Windows the only practical bus driver (an archived open-source project) is unmaintained, and its actively maintained successor is commercial and B2B-only. Requiring a driver install would violate the project's goal of never requiring one to run at all. The DSU (Cemuhook) UDP protocol, by contrast, carries buttons, sticks, and motion, needs no driver on either OS, and is already supported natively by several well-known emulators as a configurable `ip:port` input source.

## Decision

DSU/Cemuhook is the **primary** output path for Phase 1–2, on both Windows and Linux. Kouch runs four DSU servers (`127.0.0.1:26760`–`26763` by default, configurable), 4 slots each, for up to 16 players; motion data rides along on whichever up to 8 slots currently hold a motion-capable assignment. All 16 slots always exist in the routing table, so an emulator's DSU client configuration never has to change when a controller connects, disconnects, or is reordered — only which physical controller feeds which slot changes, on Kouch's side. Virtual gamepads (`crates/kouch-vpad`) exist as a secondary, per-profile path for rumble and for emulators that have no DSU client, not as the default.

## Consequences

* Kouch can honestly claim it never requires a driver to run: DSU needs none on either OS. Virtual pads are opt-in extras behind the `VirtualPad` trait, documented as such.
* Emulator profiles default player-to-slot mapping deterministically (`player p → server p/4, slot p%4`), which the "Slot policy table" in `docs/ARCHITECTURE.md` depends on for its always-connected, hold-neutral disconnect behavior.
* Rumble over DSU alone is a coarser, unofficial protocol extension (`0x110001`/`0x110002`); finer haptics and full driver-backed rumble parity are pushed to the virtual-pad paths (Linux `uinput` with force feedback, and an opt-in Windows backend), tracked as separate rumble work rather than blocking the primary output path.
* Windows virtual-pad rumble depends on an archived third-party driver project; if its last signed build stops working on a future Windows release, Kouch's fallback is documented as "Windows virtual pads become unavailable, DSU-only continues to work" rather than a hard failure, since DSU never depended on that driver in the first place.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.kouch.dev/docs/adr/0002-dsu-primary-output.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
