Skip to content

Protocol Specification

mescon edited this page Jul 20, 2026 · 1 revision

Protocol Specification

The USB / HID++ protocol of the Logitech direct-drive wheel family, reverse-engineered from USB captures of G HUB on Windows and verified against live hardware. This page covers device identification, the USB interface layout, input reports, and the HID++ configuration protocol. The other transports have their own pages:

Most of this applies to both the RS50 and the G Pro Racing Wheel; differences are called out inline.

1. Device identification

Property RS50 G Pro Racing Wheel
Vendor ID 0x046D 0x046D
Product ID 0xC276 0xC272 (Xbox/PC), 0xC268 (PS/PC)
Device name RS50 Base for PlayStation/PC Logitech G Pro Racing Wheel
Max packet size 64 bytes 64 bytes

The RS50 can also re-enumerate as 046d:c272 ("G PRO compatibility mode", via its OLED menu) while keeping its own product string, which is how the driver tells the two apart on that PID. The G Pro exposes additional HID++ sub-devices (0x01, 0x02, 0x05 over the shared interface 1); the RS50 answers the same sub-device indices (see section 4).

2. USB interface structure

Three HID interfaces:

Interface Endpoints Report size Purpose
0 - Joystick 0x81 IN (interrupt, 1 ms) 30 bytes wheel position, pedals, buttons
1 - HID++ 0x82 IN; OUT via control SET_REPORT 64 bytes configuration, settings, feature queries
2 - Force feedback 0x83 IN / 0x03 OUT (interrupt) 64 bytes real-time force + TrueForce stream

Important: force output uses dedicated endpoint 0x03 OUT, not the HID++ protocol.

3. Joystick input reports (endpoint 0x81)

30-byte report:

Offset  Size  Type    Description
------  ----  ----    -----------
0-1     2     u16 LE  Button bitmask, buttons 0-15
2-3     2     -       Button bitmask high bytes (byte 3 bit 7 = G button)
4-5     2     u16 LE  Wheel position
6-7     2     u16 LE  Accelerator pedal
8-9     2     u16 LE  Brake pedal
10-11   2     u16 LE  Clutch pedal
12-17   6     -       Reserved (zeros)
18      1     u8      Always 0x01
19-29   11    -       Reserved (zeros)

Button bitmask, byte 0: bits 0-3 are the D-pad hat nibble, bit 4 = A, bit 5 = X, bit 6 = B, bit 7 = Y. Byte 1: bit 0 = right paddle, 1 = left paddle, 2 = LT, 3 = RT, 4 = View, 5 = Menu, 6 = LB, 7 = RB. Byte 3 bit 7 = the G (logo) button. The user-facing index table is in Button Reference.

The D-pad nibble is a standard HID hat switch (usage 0x39, logical 0-7, 45° steps clockwise from Up; 8-15 = released), decoded natively by the kernel to ABS_HAT0X/ABS_HAT0Y; the driver does no custom D-pad decoding.

Wheel position: 0x0000 full left, 0x8000 centre, 0xFFFF full right (resolution depends on the configured rotation range). Pedals: 0x0000 released to 0xFFFF fully pressed.

4. HID++ protocol (interface 1)

The wheels speak the HID++ 2.0-family protocol (protocol number 4). Commands are sent via USB control transfer (SET_REPORT) to endpoint 0; responses arrive via interrupt IN on 0x82.

Message formats

Report ID Size Layout
0x10 short 7 B id, device index, feature index, fn<<4 | sw_id, 3 params
0x11 long 20 B same header, 16 params
0x12 very long 64 B same header, 60 params

Report-ID behavior (important)

  • G Hub sends short (0x10) reports for all commands.
  • The wheel base always responds with very-long (0x12) reports, regardless of the request type. This is officially specified: the HID vendor-collection usage's capability bitmask advertises very-long support, so a driver can detect it from the report descriptor.
  • Exception: sub-device responses (device index 0x01/0x02/0x05) arrive as 0x11, not 0x12.

SW ID

The low nibble of the function byte correlates requests with responses; the firmware echoes it. SW_ID 0 is reserved for broadcasts, which is exactly how the wheel's unsolicited events arrive (settings broadcasts, profile and rotation events). The Linux driver uses SW_ID 0x0a; it must not use 0x01 because the pedal sub-device's MCU silently drops that sw-id.

Feature table (wheel base, device index 0xFF)

Feature indices are discovered at runtime (IRoot getFeatureIndex, or IFeatureSet enumeration); typical RS50-native indices shown. The real G PRO's catalog holds the same feature IDs at shifted indices, which dynamic discovery absorbs.

Index Feature ID Name Purpose
0x00 0x0000 IRoot feature discovery
0x01 0x0001 IFeatureSet list all features
0x02 0x0003 DeviceInfo serial, firmware entities
0x03 0x0005 DeviceNameType device name string
0x04 0x00C3 SecureDFU firmware update
0x09 0x1BC0 ReportHidUsages optional; the driver omits it
0x0A 0x8040 Brightness LED brightness only (the Sensitivity slider is a 0x80A4 curve upload, not this)
0x0B 0x807A LIGHTSYNC LED effects; see Protocol LIGHTSYNC
0x0C 0x807B RGBZoneConfig LED RGB data; see Protocol LIGHTSYNC
0x0D 0x80A4 AxisResponseCurve per-axis 64-point response curves
0x10 0x8123 ForceFeedback the Windows game-FFB path (unused by this driver; see Protocol Force Feedback)
0x14 0x8133 Damping damping slider
0x15 0x8134 BrakeForce brake force slider
0x16 0x8136 FFBStrength strength slider
0x17 0x8137 Profile profile / mode switching, slot names
0x18 0x8138 RotationRange rotation range
0x19 0x8139 TRUEFORCE TrueForce intensity
0x1A 0x8140 FFBFilter FFB filter + auto toggle
- 0x80D0 CombinedPedals boolean, also emits profile-change broadcasts

Setting commands

GET semantics are mostly fn=0 capabilities, fn=1 current value; the SET function varies per feature (do not assume fn=2):

Feature Page SET fn Value encoding
Rotation range 0x8138 2 degrees, u16 BE (90-2700 in 10° steps)
FFB strength 0x8136 2 Nm × 8192, u16 BE (0xFFFF = 8.0 Nm)
FFB filter 0x8140 2 flags byte (bit 0 = user set now, bit 2 = auto mode), level 1-15 in byte 6
Brake force 0x8134 2 u16 BE, 0-0xFFFF = 0-100%
Brightness 0x8040 2 0-100 in byte 5
Damping 0x8133 1 u16 BE; fn=1 is both GET and SET, disambiguated by payload length
TRUEFORCE 0x8139 3 u16 BE, 0-0xFFFF = 0-100%
Profile / mode 0x8137 2 [profile, 0, 0]; fn=1 GET returns [profile, mode], fn=3 [slot] returns the slot's name, fn=4 renames a slot
Centre calibration 0x812C (sub-device 0x05) 3 absolute encoder position u16 BE; G Hub's calibrate is fn=1 GET position then fn=3 SET

Mode differences: Sensitivity is desktop-only, Brake Force onboard-only (with capture evidence that compat firmware also accepts it in desktop), full LIGHTSYNC color control is desktop-only.

AxisResponseCurve (0x80A4)

A per-axis 64-point curve store, used on three axis groups:

  • Steering: base device 0xFF, axis 0 (wheel_response_curve, wheel_sensitivity).
  • Pedals: sub-device 0x02, axes 0/1/2 = throttle/brake/clutch.
  • Analog handbrake: base, axis 4 (HID usage 0x32, evdev ABS_Z).

An upload is fn3 [axis] (open), 22 fn4 chunks of up to 3 (in,out) u16-BE pairs (64 monotonic points from (0,0) to (0xFFFF,0xFFFF)), then fn5 commit; fn6 [axis] reverts to the built-in curve. The axis MCU applies the curve to what it reports to the PC. Note the wheel emits no HID reports while an axis is still, so read the loaded point count back with fn1 for a motion-free check.

Sub-device addressing (device index 0x01 / 0x02 / 0x05)

Besides the base at 0xFF, three sub-devices carry real HID++ traffic on both wheels, each with its own feature catalog:

  • 0x01: display / rim module (0x8091 per-key LED matrix, 0x18A2, 0x9315).
  • 0x02: pedal base (0x80A4 axis curves, 0x80D0, 0x8134 brake force, 0x8135, 0x9209/0x9215).
  • 0x05: motor / base unit: the 0x812x calibration cluster including 0x812C centre calibration.

Quirks: sub-device responses arrive as report ID 0x11; the pedal MCU silently drops sw-id 0x01.

Error packets

Errors arrive with 0xFF in the feature-index byte, then the failing feature index, the failing fn|sw byte, and a code: 1 Unknown, 2 InvalidArgument, 3 OutOfRange, 4 HWError, 5 internal, 6 InvalidFeatureIndex, 7 InvalidFunctionId, 8 Busy, 9 Unsupported.

5. Initialization

Recommended bring-up order: enumerate, claim interfaces 0/1/2, discover feature indices via IRoot/IFeatureSet, read current settings (range, strength, damping, TrueForce, filter, brightness) so sysfs reflects device state, then start the force loop (Protocol Force Feedback).

The driver also reads DeviceInfo once at init: feature 0x0003 fn2 returns the real 12-character serial; fn1 enumerates firmware entities (the base's bootloader, active main firmware and hardware entity, plus the motor unit's servo firmware on sub-device 0x05). Exposed as wheel_serial / wheel_firmware.

6. Differences from G920/G923

Feature G920/G923 RS50 / G PRO
FFB method HID++ feature 0x8123 dedicated endpoint 0x03 (plus 0x8123 as an alternative transport)
Report ID for FFB 0x11/0x12 0x01 (custom)
Sequence field 2 bytes 1 byte
Max rotation 900° 2700°
Motor belt/gear direct drive
USB interfaces unified HID++ 3 separate (joystick, HID++, FFB)

The direct-drive wheels expose two independent force transports and privilege the endpoint stream; see the architecture note in Protocol Force Feedback.

Safety when probing

Some HID++ features relate to firmware update or critical configuration. Use GET (read-only) functions when probing unknown features; never blindly send SET commands to uncharacterized features.

Clone this wiki locally