An output interface translates the common input_event_t format into a console-specific or USB protocol. Output drivers read from the router and send data to the connected console or host device.
Console outputs use RP2040 PIO state machines for cycle-accurate protocol timing. They run on Core 1, isolated from USB and Bluetooth processing on Core 0. USB and UART outputs run on Core 0 since they are not timing-critical.
| Output | Protocol | Location | Max Players | PIO Programs | Notes |
|---|---|---|---|---|---|
| GameCube / Wii | Joybus | src/native/device/gamecube/ |
4 | joybus.pio |
Requires 130MHz overclock. Rumble feedback. Keyboard mode. |
| PCEngine / TurboGrafx-16 | Multiplexed | src/native/device/pcengine/ |
5 | plex.pio, clock.pio, select.pio |
Multitap emulation. 2/3/6-button and mouse modes. |
| Dreamcast | Maple bus | src/native/device/dreamcast/ |
4 | maple.pio |
Rumble feedback. Analog triggers. |
| Nuon | Polyface | src/native/device/nuon/ |
8 | polyface_read.pio, polyface_send.pio |
Tempest 3000 spinner support. In-game reset (IGR). |
| 3DO | Parallel bus (PBUS) | src/native/device/3do/ |
8 | sampling.pio, output.pio |
Mouse support. Extension passthrough. |
| N64 | Joybus | src/native/device/n64/ |
1 | joybus.pio |
Rumble feedback. Experimental. |
| Casio Loopy | Loopy protocol | src/native/device/loopy/ |
4 | loopy.pio |
Experimental. |
| Neo Geo / SuperGun | GPIO | src/native/device/gpio/ |
1 | None | Active-low button output via GPIO pins. |
| NES | Shift register | src/native/device/nes/ |
1 | PIO | NES controller emulation. |
| USB Device | USB 2.0 HID | src/usb/usbd/ |
1 | None | 13 output modes (see below). Native USB controller. |
| BLE Peripheral | BLE HID | src/usb/usbd/ |
1 | None | BLE gamepad emulation. Experimental. |
| UART | Serial TX | src/native/device/uart/ |
1 | None | Serial bridge to external microcontrollers. |
Each output interface implements the OutputInterface struct:
typedef struct {
const char* name;
output_target_t target;
void (*init)(void);
void (*task)(void);
void (*core1_task)(void);
uint8_t (*get_rumble)(void);
uint8_t (*get_player_led)(void);
} OutputInterface;init()configures PIO programs, GPIO pins, or USB descriptors during startup.core1_task()runs on Core 1 in a tight loop -- the timing-critical PIO interaction for console protocols. Only one output can claim Core 1.task()runs on Core 0 each main loop iteration for non-timing-critical work (USB device polling, status updates).get_rumble()andget_player_led()return feedback state that the player manager routes back to input controllers.
The USB device output supports 13 emulation modes, selectable at runtime via web config or button combo:
| Mode | Emulates | Console Auth |
|---|---|---|
| SInput | Joypad HID Gamepad | -- |
| XInput | Xbox 360 Controller | XSM3 |
| DirectInput | Generic HID Gamepad | -- |
| PS3 | DualShock 3 | -- |
| PS4 | DualShock 4 | Passthrough |
| PS Classic | PS Classic Controller | -- |
| Switch | Nintendo Switch Pro Controller | -- |
| Xbox Original | Controller S | -- |
| Xbox One | Xbox One Controller | -- |
| XAC | Xbox Adaptive Controller | -- |
| GC Adapter | Wii U GameCube Adapter | -- |
| Keyboard + Mouse | HID Keyboard and Mouse | -- |
| MIDI | MIDI Controller | -- |
Mode switching triggers USB re-enumeration. The selected mode persists to flash.
- GBA Link Cable — production GameCube→GBA controller mode (gc2usb autoboots an embedded payload onto a real GBA over the DOL-011 link cable; GBA reads back as a HID gamepad). Also covers the experimental USB-vendor bridge mode for a forked Dolphin (default-off, see doc for status).
Console outputs can send feedback back to the input controllers:
- Rumble: GameCube, Dreamcast, and N64 outputs forward motor commands. The player manager routes these to the correct physical controller (USB SET_REPORT, BT HID output report, N64 rumble pak).
- Player LEDs: Some outputs report player numbers, which the player manager forwards to controllers that support player LEDs (Xbox, DualShock 4, DualSense).
- Architecture -- Where outputs fit in the system
- Data Flow -- How data reaches outputs from inputs
- Input Interfaces -- The other side of the pipeline
- Apps -- How apps select which output to use