Skip to content

USB OHCI and XID Input

github-actions[bot] edited this page Sep 14, 2026 · 1 revision

USB, OHCI & XID Input

The Xbox controller ports are exposed to guest software through USB-compatible host-controller behavior and Xbox-specific XID devices. xemu reuses QEMU's OHCI controller model for the host controllers, then implements Xbox controller protocol/state in the XID device layer and bridges that to xemu's host input system.

Machine topology

xbox_init_common() creates two pci-ohci devices and configures each with four ports.

flowchart TD
    A[Guest USB stack] --> B[OHCI controller 0 - 4 ports]
    A --> C[OHCI controller 1 - 4 ports]
    B --> D[QEMU USB bus/devices]
    C --> D
    D --> E[Xbox XID gamepad device]
    E --> F[xemu ControllerState]
    F --> G[Host controller/input backend]
    E --> H[Rumble output]
    H --> F
Loading

The physical Xbox front connector is electrically USB-derived, but xemu does not simulate connector voltages, differential D+/D− signaling or PHY timing. Guest software interacts with an OHCI and USB-device protocol model.

Why generic OHCI is used

The original Xbox OHCI controllers are PC-compatible enough that xemu instantiates QEMU's generic pci-ohci implementation instead of maintaining an Xbox-only host-controller core.

This is an important implementation boundary:

Xbox-specific machine wiring / IRQ route
    ↓
generic QEMU OHCI controller semantics
    ↓
Xbox-specific USB device (XID)

A controller problem can therefore live in three different places: Xbox PCI/IRQ wiring, QEMU OHCI behavior, or XID device behavior.

XID input mapping

hw/xbox/xid.c maps xemu's host-neutral ControllerState into the report format expected by Xbox software.

Analog face buttons

A/B/X/Y/Black/White are represented as analog values by the Xbox controller protocol. xemu currently maps a host digital press to either 0x00 or 0xff.

Triggers

Host trigger axes are shifted into the Xbox report's 8-bit analog trigger fields.

Thumbsticks

Host stick axes are copied into the signed Xbox thumbstick fields.

Binary buttons

Back, Start, thumbstick clicks and D-pad directions are packed into wButtons.

flowchart LR
    A[Host input backend] --> B[ControllerState]
    B --> C[update_input]
    C --> D[Analog button bytes]
    C --> E[Trigger bytes]
    C --> F[Thumbstick int16 values]
    C --> G[wButtons bitmask]
    D --> H[XID input report]
    E --> H
    F --> H
    G --> H
    H --> I[Guest USB request/interrupt transfer]
Loading

The host controller's native deadzones, calibration and polling behavior are therefore separate from the guest XID report format.

Test-mode bypass

Both update_input() and update_output() return early when xemu_input_get_test_mode() is active. This prevents the running guest from receiving changes while the UI is testing a controller.

That is a host/UI policy layer, not Xbox hardware behavior. If input appears frozen only while controller-test UI is active, the XID USB model may be functioning correctly.

Rumble path

Guest rumble arrives as an XID output report. xemu copies the left/right actuator strengths into the bound ControllerState and calls xemu_input_update_rumble().

sequenceDiagram
    participant G as Guest
    participant X as XID device
    participant C as xemu ControllerState
    participant H as Host controller

    G->>X: HID SET_REPORT output
    X->>X: Validate/copy XID output state
    X->>C: left/right actuator strength
    C->>H: xemu_input_update_rumble()
Loading

Physical motor inertia/current draw is not simulated. The guest-visible command is translated into a host haptic request.

Control-request handling

usb_xid_handle_control() first gives standard requests to QEMU's descriptor helper, then handles Xbox/HID-specific cases.

Implemented requests include:

  • HID GET_REPORT for input state;
  • HID SET_REPORT for rumble/output state;
  • vendor XID descriptor 0x4200;
  • XID input/output capabilities.

Unsupported requests normally set USB_RET_STALL, which is the correct USB-level concept for many invalid requests.

Assertion boundaries

Several unsupported or malformed request paths also contain assert() calls. Examples include unexpected report/descriptor values and the default unknown-request path.

unusual guest USB request
    ↓
USB_RET_STALL set
    ↓
assert() may also fire in assertion-enabled build

That is stronger than physical hardware behavior. Real hardware would not terminate the emulator process because software sent an unsupported request. It is therefore a known robustness boundary useful for fuzzing/homebrew qualification.

One SET_REPORT path also contains a source comment saying an invalid output-length condition should be a STALL rather than relying on the current assertion expectation.

Descriptor identity

The current descriptor strings identify the device as:

Manufacturer: QEMU
Product:      Microsoft Xbox Controller
Serial:       1

Those strings are emulator-generated identity. Games normally depend more on USB/XID descriptors and report structure than on an electrical reproduction of the physical controller.

Reset behavior

usb_xid_handle_reset() currently only emits debug output. There is no complex controller-internal reset state machine in that callback.

A title that depends on undocumented controller state surviving or clearing across USB reset therefore deserves a focused test rather than assuming physical behavior is reproduced.

Timing model

Controller input is sampled when xemu updates the XID report from its host input state; the physical USB bus waveform is not simulated.

Relevant timing layers are:

flowchart LR
    A[Host OS/controller polling] --> B[xemu input state update]
    B --> C[XID report generation]
    C --> D[QEMU USB/OHCI scheduling]
    D --> E[Guest USB driver]
Loading

If an input-latency change is being measured, identify which layer changed. Lower host controller polling latency is different from OHCI scheduling, which is different from game-side input sampling.

IRQ routing

The two OHCI PCI devices are mapped through the Xbox LPC interrupt-routing model. In the current machine mapping the two controller slots route to different legacy PIC IRQs. USB device events therefore still become guest CPU work through the PCI/OHCI interrupt model; XID does not directly call a guest input handler.

Fast paths and fidelity boundaries

Area Current abstraction Consequence
USB electrical layer Not simulated No D+/D− waveform/PHY timing cost
Host controller Generic QEMU OHCI Reuses PC-compatible USB scheduling semantics
Controller protocol Xbox-specific XID Guest report/capability behavior implemented directly
Host input ControllerState abstraction Physical controller type can differ from virtual Xbox controller
Face-button pressure Digital host button → 0/255 Intermediate analog pressure absent for digital inputs
Rumble Strength → host haptic API Motor/electrical dynamics absent
Invalid requests STALL + some asserts Debug/assert builds can fail harder than hardware

Debugging flow

flowchart TD
    A[Controller bug] --> B{Guest sees OHCI device?}
    B -->|No| C[PCI/OHCI/IRQ wiring]
    B -->|Yes| D{XID enumerates?}
    D -->|No| E[USB descriptor/control requests]
    D -->|Yes| F{Input report wrong?}
    F -->|Yes| G[ControllerState → XID mapping]
    F -->|No| H{Rumble/output wrong?}
    H -->|Yes| I[SET_REPORT → host haptic path]
    H -->|No| J[Game/input timing or host backend]
Loading

Source map

Source Responsibility
hw/xbox/xbox.c Creates two four-port PCI OHCI controllers
QEMU OHCI/USB core Host-controller scheduling, transfers and USB bus behavior
hw/xbox/xid.c Xbox controller reports, requests, capabilities and rumble mapping
hw/xbox/xid.h XID structures/descriptors/state
xemu input subsystem Host controller enumeration/state/rumble backend
hw/xbox/xbox_pci.c PCI interrupt routing for OHCI devices

Related pages

Clone this wiki locally