Intel Wireless Series Gamepad¶
The original Intel USB base station (8086:C013) uses a custom TinyUSB
host driver in src/usb/usbh/intel/. Eight RF slots are tracked separately
for each receiver. A remembered slot does not create a player; input from
a known gamepad slot enters JoypadOS through router_submit_input().
Receiver keyboard and mouse support is not implemented. The driver owns
both USB interfaces so the boot mouse cannot collide with RF slot numbers.
Verified USB transport¶
Read using local PyUSB/libusb on macOS on 2026-09-07. The receiver has one configuration (value 1), 89 descriptor bytes and two interfaces.
| Interface / alternate | Class | Endpoint | Type | Max packet | Interval |
|---|---|---|---|---|---|
| 0 / 0 | HID boot keyboard | 81 |
Interrupt IN | 8 | 10 ms |
| 0 / 1 | 0/0/0 | 81 |
Interrupt IN | 27 | 1 ms |
| 0 / 1 | 0/0/0 | 01 |
Interrupt OUT | 25 | 1 ms |
| 0 / 1 | 0/0/0 | 02 |
Control | 8 | 0 |
| 1 / 0 | HID boot mouse | 82 |
Interrupt IN | 4 | 10 ms |
The driver claims interface 0 before generic HID, finds alternate 1's
interrupt descriptors, then asynchronously selects it with SET_INTERFACE.
Only after success does it open the interrupt endpoints and poll 27 bytes.
Endpoint 02 is not an interrupt transport and is never opened.
The protocol reference is
intel-wings 0.2,
whose intel-wings.c internally identifies itself as version 0.6.
Its 128-byte transfers, uninitialized activation padding, hardcoded
alternate-array indexing, and reversed device-type-change comparison
are not used.
Hardware capture¶
The connected gamepad successfully activated with exactly six output bytes; neither 25-byte padding nor the Linux driver's 128-byte send was necessary:
RX 7 03 01 0c 02 ff 00 00 remembered gamepad, slot 1
RX 7 03 02 0c 02 ff 00 00 remembered gamepad, slot 2
RX 7 03 03 01 02 ff 00 00 activate gamepad, slot 3
TX 6 03 01 ff 00 01 63
RX 7 06 03 00 00 ff 00 00 zero state, slot 3
RX 7 03 03 04 02 ff 00 00 gamepad ready, slot 3
RX 13 01 17 13 00 03 03 06 63 04 00 00 02 00
RX 13 01 00 00 00 03 03 06 63 04 00 00 00 00
Input has major type packet[0] & 7 == 1, RF slot packet[4] & 7,
and requires at least 13 bytes. The capture includes button presses and
releases in byte 11. All data is parsed using the actual received length.
Information messages require three bytes, or four when reading device type.
Activations are queued per slot and sent serially from a dedicated buffer;
a second activation cannot overwrite an in-flight transfer.
Mapping and lifecycle¶
The mapping follows JoypadOS's M30 driver and LAYOUT_SEGA_6BUTTON:
| Physical control | Joypad button |
|---|---|
| A, B, X, Y | B1, B2, B3, B4 |
| Z, C | L1, R1 |
| L, R shoulders | L2, R2 |
| Start | S2 |
| Mouse | S1 (Select) |
| Shift | A1 (Guide) |
Bytes 9/10 contain digital X/Y: 81 means left/up and 7f means
right/down. Other values mean neutral. These become D-pad buttons;
unused sticks remain centered at 128. Digital triggers are synthesized by
the existing profile system.
USB disconnect/deinitialization clears every submitted RF slot in the router and player manager, then clears receiver buffers and activation state. Slot replacement or reactivation also clears previous input. Major type 6 releases held inputs for a slot without forgetting its device type. No arbitrary inactivity timeout is used: the captured controller reports changes, so silence alone does not establish a disconnect. The exact RF power-off notification still needs a hardware capture.
Reproduce validation¶
/usr/bin/python3 -m venv /tmp/joypad-intel-wireless-series-venv
/tmp/joypad-intel-wireless-series-venv/bin/python -m pip install pyusb
/tmp/joypad-intel-wireless-series-venv/bin/python tools/intel-wireless-series/probe.py
sudo /tmp/joypad-intel-wireless-series-venv/bin/python tools/intel-wireless-series/probe.py --capture 45
sh tools/intel-wireless-series/test.sh
Install libusb separately if absent (Homebrew libusb on macOS).
macOS requires administrator access to detach its HID driver for capture;
the probe restores the original alternate setting and reattaches afterward.
During capture, power on the pad and press/release controls.
The C tests compile the production driver against the real TinyUSB headers,
with USB I/O/router test doubles and AddressSanitizer/UndefinedBehaviorSanitizer.
They replay the hardware sequence and test lengths, mappings, independent
slots/receivers, activation serialization/retries, and disconnect cleanup.
Firmware validation also includes an RP2040 joypad_ngc (KB2040) build.
The receiver was exercised through libusb on the Mac; the firmware has not
yet been flashed and tested on a JoypadOS adapter.