-
Notifications
You must be signed in to change notification settings - Fork 5
Sysfs API Reference
Every setting the hid-logitech-dd driver exposes, as sysfs attributes under:
/sys/bus/hid/devices/<DEVICE_ID>/
<DEVICE_ID> is typically 0003:046D:C276.XXXX (RS50),
0003:046D:C272.XXXX (G Pro Xbox/PC or RS50 in compat mode), or
0003:046D:C268.XXXX (G Pro PS/PC). To find your device path:
find /sys/bus/hid/devices -name "*046D*C276*" # RS50 native
find /sys/bus/hid/devices -name "*046D*C27[28]*" # G Pro / compat
# or, path-stable across models:
H=$(ls -d /sys/class/hidraw/*/device/wheel_range | head -1 | xargs dirname)Most attributes are shared between the RS50 and G Pro; per-model exceptions are called out inline. The friendly way to drive all of this is Configuring the Wheel; the wire-level encodings live in the Protocol Specification.
The operating mode. Desktop (profile 0): settings controlled by host software; sensitivity available. Onboard (profiles 1-5): settings stored in wheel profiles; brake force available.
The active profile: 0 = desktop mode, 1-5 = onboard slots.
The five onboard slots' names, queried live from the wheel:
cat wheel_profile_names
# 1: RACE
# 2: DRIFT
# 3: PROFILE 3
# ...
echo "3:RACE" > wheel_profile_names # rename slot 3The wheel persists the name to its own NVM. On an RS50 the name may be up to
9 characters, may contain spaces, and is stored uppercased. A longer
name is refused by the wheel itself and surfaces as -EIO; a bad slot or
empty name gives -EINVAL.
Steering rotation range. On the G PRO PID (compat mode included) the write
only takes effect while the wheel is in desktop mode; write 0 to
wheel_profile first.
The driver re-reads the true range from the wheel every 20 seconds (paused
while force feedback is actively playing). An external change is logged in
dmesg (rotation range changed externally), the attribute is updated to the
real value, and poll()ers are notified via sysfs_notify().
Automatic recovery from the launch-time 90° reset: some games' SDK sessions push an operating range of 90° once at session start via a TrueForce interface-2 packet, invisible to HID++ (see TrueForce Protocol). With this enabled the driver restores the pre-reset range automatically (detection to restore in under 100 ms once the poll samples the change).
Safety gates: fires only for an external silent change landing exactly on 90
(a game applying its real steering lock is respected); desktop mode only;
the wheel must be stationary; restores only ever widen the range; at most 3
restores per session; an explicit wheel_range write supersedes any pending
restore. 0 = detect-and-report only.
Overall force-feedback strength. 100% corresponds to the wheel's maximum torque (8.0 Nm on the RS50).
Wheel damping (firmware-side resistance when turning).
TrueForce haptic intensity. 0 disables.
Brake pedal force threshold (load cell sensitivity). Returns -EPERM in
desktop mode.
Shapes the steering response via feature 0x80A4: a 64-point cubic Bezier
(G HUB's Sensitivity slider). Below 50 softens the response near centre,
above 50 sharpens it, 50 reverts to the wheel's built-in curve. Reads
return the last value written (write-through cache; the wheel has no
read-back for the slider). Writes in onboard mode fail with -EPERM.
Force-feedback smoothing level. G HUB's labels: Minimum (1), Low (7), Medium (11), Maximum (15). Out-of-range values are clamped.
Automatic FFB filter adjustment. The driver splits the wire flag byte across
the two attributes: wheel_ffb_filter stamps the "user set this level" bit,
this one toggles only the "auto mode" bit.
Whether the driver inverts the sign of every FF_CONSTANT level. Wine's
DirectInput-to-evdev translation and native evdev apps disagree on sign by
one flip, and the driver cannot tell them apart at runtime:
-
1(default): invert. Correct for Wine/Proton games. If centring forces push the wheel away from centre, the toggle is at the wrong setting. -
0: pass-through. Correct for native evdev apps followingDocumentation/input/ff.rst(fftest,ffcfstress, custom tools).
Only affects FF_CONSTANT; all other effect types feel identical either
way. Note: strong FFB when reverse-driving is the sim's physics surfacing
through a direct-drive motor (verified identical on Windows), not a sign
error.
Synthetic damping applied to emulated FF_SPRING effects, as a percentage
of a FF_DAMPER running the spring's own coefficient. The driver emulates
condition effects host-side; loop latency on a low-friction direct-drive
motor makes a stiff undamped game spring ring until the wheel's over-torque
failsafe cuts power (observed live with AC EVO's map-load centring spring).
Real wheels damp the spring inside the firmware servo loop; this knob
restores that behaviour. 0 disables.
Where vibration-class effects (FF_RUMBLE and periodics at 20 Hz or faster)
are actuated:
-
tf(default): streamed on the wheel's TrueForce audio-haptic channel, the same physical path the Windows SDK uses for texture. Steering-shaping effects stay on the force channel, so rumble no longer modulates the steering axis. -
kf: legacy; everything summed into the single steering force. Kept as a fallback and for A/B comparison.
The TrueForce session is brought up lazily on the first texture-class
playback (dmesg: TrueForce texture channel ready); if init fails, texture
falls back to the steering channel (degraded feel, never lost). Texture
amplitude respects FF_GAIN and wheel_strength and is capped at half of
full scale so a synthetic full-scale rumble cannot hijack steering torque.
Low-level centre calibration primitive: writes a raw 16-bit encoder value to
adopt as the new centre (HID++ sub-device 0x05, page 0x812C). Use
wheel_calibrate_here for the common case.
One-shot "use the wheel's current physical position as the new centre"; performs the GET+SET internally, mirroring G HUB's Calibrate button. The wheel's firmware persists the new centre across power cycles.
The RS50 has 10 RGB LEDs in a strip across the faceplate, with 5 custom
slots (0-4). These attributes exist on the RS50 in both native and compat
enumeration. On a real G PRO they are hidden: that rim has level-based
rev lights with no per-LED RGB, exposed as wheel_rev_level instead.
Workflow: select a slot, set direction/colors, apply:
echo 2 > wheel_led_slot
echo 1 > wheel_led_direction
echo "FF0000 FF0000 FF0000 FF0000 FF0000 FF0000 FF0000 FF0000 FF0000 FF0000" > wheel_led_colors
echo 1 > wheel_led_apply| Attribute | Access | Values | Notes |
|---|---|---|---|
wheel_led_slot |
RW | 0-4 | selects the active custom slot and renders it (on the wire a custom slot IS effect 5 + slot) |
wheel_led_slot_name |
RW | string, max 8 chars | name of the selected slot, stored on the device |
wheel_led_slot_brightness |
RW | 0-100 | per-slot brightness |
wheel_led_direction |
RW | 0-3 | animation direction: 0 = L to R, 1 = R to L, 2 = inside out, 3 = outside in |
wheel_led_colors |
RW | 10 space-separated RRGGBB
|
LED1 is leftmost |
wheel_led_brightness |
RW | 0-100 | global brightness; changes made on the wheel's OLED are tracked and poll()able |
wheel_led_effect |
RW | 1-9 | 1-4 = built-in animations (inside-out, outside-in, R-to-L, L-to-R); 5-9 ARE the five custom slots. External effect changes are tracked |
wheel_led_apply |
W | 1 | re-applies the current slot configuration |
Rev-light level: how many LEDs are lit. Available on the real G PRO rim AND
the RS50's strip (on the RS50 the fill renders the selected custom slot's
stored colors and direction). Writes return immediately; the driver
coalesces them and flushes only the newest level at G HUB's ~160 ms cadence,
so a fast telemetry feeder always shows the latest value. The wheel reverts
an unrefreshed level after a while; feeders should refresh at ~1 Hz or
faster. Write wheel_led_effect to restore the normal idle pattern.
The pedal unit is a separate MCU (HID++ sub-device 0x02) applying a
64-point 0x80A4 response curve to each axis it reports (hardware-verified
with a two-plateau curve). Each pedal <p> in {throttle, brake,
clutch} has three attributes. They all write the single curve the axis
holds, so the last write wins; to combine a deadzone with a custom shape,
author it as one _curve upload (what the logi-dd editor does).
The raw curve: reset for the built-in linear curve, or 2-64
whitespace-separated in:out pairs (0-65535, strictly increasing in,
non-decreasing out, from 0:0 to 65535:65535; fewer than 64 pairs are
resampled). Reads back "<loaded>/<max> points loaded" from the wheel, the
honest motion-free check.
echo "0:0 19660:0 65535:65535" > wheel_throttle_curve # dead until 30%
echo reset > wheel_throttle_curveG HUB's simple slider; generates the same symmetric-Bezier curve G HUB uploads. Reads back the last written value.
Dead travel at each end. lower + upper must be at most 99; "0 0" reverts
to the built-in curve.
The steering axis's 64-point curve, same format as the pedal curves; the
store behind G HUB's Sensitivity slider. wheel_sensitivity and this
attribute write the same axis-0 curve, so the last one wins. Note the wheel
sends no reports while held still, so an upload appears to do nothing until
the wheel moves; cat reads the loaded point count back.
Same shaping for the RS Shifter & Handbrake's analog axis (base axis 4,
evdev ABS_Z). The handbrake input itself needs no configuration.
G HUB's "combined pedals": merges throttle and brake into a single centred axis for legacy games (released = centre, one pedal up, the other down); the brake's own axis goes silent.
The wheel's 12-character serial, read from HID++ DeviceInfo at init; matches
the USB iSerial.
Firmware versions read at init: the base's active main firmware and the motor unit's servo firmware. Include this in bug reports.
base: U1 65.03.B0038
motor: SC 02.01.B0042
Created for every wheel this driver binds, using the de-facto new-lg4ff attribute names and scales (raw device units, not percent) so Oversteer and similar tools work unmodified:
| Attribute | Values | Notes |
|---|---|---|
range |
90-2700 | same as wheel_range
|
gain |
0-65535 | same setting as wheel_strength, raw FF_GAIN scale; the two stay in sync |
autocenter |
0-65535 | a real driver-emulated centring spring (also reachable via evdev FF_AUTOCENTER); games that write 0 before taking over FFB correctly disable it |
spring_level / damper_level / friction_level
|
0-100, default 100 | global output scales for the emulated effect classes; damper_level scales game DAMPER effects, the wheel's own firmware damping is wheel_damping
|
Raw HID++ command shell for protocol bring-up; only present when the module
is built with CONFIG_HID_LOGITECH_HIDPP_DEBUG (make DEBUG=1). Write
feature fn [params...] in hex, read the last response.
| Error | Meaning |
|---|---|
-ENODEV |
device not found or driver not ready |
-EPERM |
operation not permitted in the current mode |
-EINVAL |
invalid value |
-ERANGE |
value out of range |
-EOPNOTSUPP |
feature not supported by this device/firmware |
-EIO |
communication error with the device (including wheel-refused values, like an over-length profile name) |
On 046d:c272 / 046d:c268 (real G PRO and RS50-in-compat), most settings
work via fallback feature paths: wheel_range, wheel_strength,
wheel_trueforce, wheel_damping, wheel_ffb_filter, wheel_profile and
wheel_calibrate. LIGHTSYNC works the same as native on an RS50 in compat.
wheel_brake_force, wheel_ffb_filter_auto and wheel_sensitivity are
unsupported by the compat firmware surface and return -EOPNOTSUPP once
their mode gating is satisfied; configure those via the wheel's OLED menu.
Remember compat mode boots in onboard mode: write 0 to wheel_profile
first for live host settings to take effect.