Skip to content

Comments

feat: EP0 mouse/kbd polling, CC=12 investigation (Parallels xHCI)#239

Open
ryanbreen wants to merge 1 commit intomainfrom
feat/parallels-xhci-cc12
Open

feat: EP0 mouse/kbd polling, CC=12 investigation (Parallels xHCI)#239
ryanbreen wants to merge 1 commit intomainfrom
feat/parallels-xhci-cc12

Conversation

@ryanbreen
Copy link
Owner

Summary

  • Root cause confirmed: CC=12 (Endpoint Not Enabled) on Parallels virtual xHCI interrupt endpoints is a fundamental virtual hardware limitation — not fixable through command sequencing. Parallels generates CC=12 Transfer Events proactively after ConfigureEndpoint, before any TRBs are queued, signaling that interrupt IN transfers are not implemented.
  • Working solution: EP0 GET_REPORT polling for both keyboard and mouse via boot-protocol control transfers at 4 Hz (zero errors sustained over 3+ minutes in testing).
  • Linux comparison: Exhaustive ftrace analysis matched our command sequence byte-for-byte with Linux (BSR=0, bandwidth dance, SET_CONFIGURATION ordering, SET_IDLE, HID Report Descriptor, GET_REPORT). CC=12 persists regardless. Linux keyboard/mouse works via Parallels Tools input injection, not xHCI interrupt IN.

Changes

kernel/src/drivers/usb/xhci.rs

  • Mouse EP0 GET_REPORT polling: SET_PROTOCOL(boot) during device init, then 4 Hz GET_REPORT via EP0 control pipe with ring recycling
  • EP0 ring recycling (StopEndpoint + SetTRDequeuePointer) for both keyboard and mouse — Parallels virtual xHC does not follow Link TRBs
  • Bandwidth dance (SKIP_BW_DANCE=false): matches Linux's xhci_check_bandwidth() with 3× ConfigureEndpoint + 2× StopRing per slot
  • DIAG_DOORBELL_EP_STATE, DMA buffer address logging, endpoint state diagnostics
  • Polling interval % 10 (20 Hz attempt; bottleneck is Parallels' ~250ms USB device timing, effective rate stays 4 Hz)

kernel/src/arch_impl/aarch64/timer_interrupt.rs

  • Heartbeat adds mr= mk= me= counters for mouse EP0 polling status

Test plan

  • Build: zero warnings, zero errors
  • Keyboard input: gr=N gk=N ge=0 sustained at 4 Hz with zero errors
  • Mouse input: mr=N mk=N me=0 sustained at 4 Hz with zero errors
  • BEI flag experiment: no effect (confirmed not the issue)
  • BSR=1 experiment: causes CC=19 Context State Error (reverted)
  • Bandwidth dance: all commands cc=1 but CC=12 persists on doorbell ring
  • Endpoint state after ConfigureEndpoint: state=1 (Running) — controller correctly configures endpoint; Parallels ignores interrupt IN TRBs anyway

🤖 Generated with Claude Code

Systematic investigation of CC=12 (Endpoint Not Enabled) on Parallels
ARM64 virtual xHCI interrupt endpoints, with working EP0 GET_REPORT
polling for both keyboard and mouse.

## Findings

CC=12 on interrupt IN is a fundamental Parallels virtual xHC limitation:
- Parallels proactively generates CC=12 Transfer Events after
  re-ConfigureEndpoint (before any TRBs are queued), signaling that
  interrupt IN transfers are not supported
- This persists regardless of command sequence: BSR=0/1, bandwidth
  dance enabled/disabled, BEI flag, matching Linux byte-for-byte
- EP0 control transfers work reliably; interrupt IN never completes
- Linux keyboard/mouse works via Parallels Tools injection, not xHCI
  interrupt IN (Linux ftrace shows no interrupt TRB completions in trace)

## Working solution: EP0 GET_REPORT polling

Both keyboard and mouse input work via EP0 GET_REPORT control
transfers at 4 Hz (limited by Parallels virtual USB device timing,
not our polling interval):
- gr=N gk=N mr=N mk=N with ge=me=0 (zero errors) verified in testing
- Ring recycling (StopEndpoint + SetTRDequeuePointer) for EP0 rings
  since Parallels does not follow Link TRBs on transfer rings

## Changes

xhci.rs:
- Mouse EP0 GET_REPORT polling: SET_PROTOCOL(boot) during init,
  then 4 Hz boot-protocol GET_REPORT via EP0 with ring recycling
- EP0 ring recycling for keyboard (every ~84 polls) and mouse
- Bandwidth dance (SKIP_BW_DANCE=false): matches Linux's
  xhci_check_bandwidth() sequence with 3x ConfigureEndpoint +
  2x StopRing per slot — confirmed matching Linux ftrace byte-for-byte
- BSR=0 confirmed correct (BSR=1 causes CC=19 Context State Error)
- Added EP0_MOUSE_POLL_STATE, MOUSE_CTRL_DATA_BUF, queue_ep0_mouse_get_report()
- Diagnostics: DIAG_DOORBELL_EP_STATE, DMA buffer address logging,
  endpoint state read after SET_CONFIG and at doorbell time
- Polling interval: % 10 (20 Hz attempt; bottleneck is Parallels ~4 Hz)

timer_interrupt.rs:
- Heartbeat counters: mr= mk= me= for mouse EP0 polling status

Co-Authored-By: Ryan Breen <ryan@ryanbreen.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant