Conversation
This bit is the preparatory PR, and shouldn't really be included in this PR. You should be able to change the target of this PR to #220 instead of |
| `1, 2, 3, ...` assigned sequentially -> their `0x01` uploads and `0x41` | ||
| START/STOP packets carry that slot number (`41 01 41 ff` starts slot 1). | ||
|
|
||
| ### Why the wheel never stops on its own |
There was a problem hiding this comment.
This was discussed previously, packet uploads have a duration field which presumably tells the wheel how long an effect should run. This contradicts that, no?
| -1 }; | ||
|
|
||
| /* | ||
| * Resolve the hardware effect slot index for a given effect. |
There was a problem hiding this comment.
This is new, didn't we last time conclude that effect_id + 1 was the way to go?
There was a problem hiding this comment.
We did, indeed, but after the captures I got from community members, I figured that it's really true. ID 1 is reserved for constant, and the following ones for the effects
There was a problem hiding this comment.
So what happens if you try to upload two constant force effects on Windows?
| until stopped, so the driver sends `0xffff` ("infinite") and relies on its own | ||
| timer (paragraph 3). | ||
|
|
||
| ### 5.2 Envelope - `0x02` (9 bytes) |
There was a problem hiding this comment.
If you'd like, envelopes can be split off into a separate PR as well, since they're shared across several different effects. Documenting them here and then just saying "they're not used" feels a bit weird, especially since they're apparently a separate packet?
| } | ||
|
|
||
| /* Validate effect parameters based on type */ | ||
| /* Per-type range checks. We only reject values that are genuinely |
| (struct t500rs_pkt_r40_config *)buf; | ||
| config->id = 0x40; | ||
| config->subcmd = 0x11; | ||
| config->data1 = range_value & |
There was a problem hiding this comment.
cpu_to_le16() would be more clear here.
| > meaning that the wheels have to be initialized with `tmdrv`. Please see | ||
| > https://github.com/Kimplul/hid-tmff2/issues/48. | ||
|
|
||
| > **NOTE:** The T500 RS (like other modern Thrustmaster wheels) first enumerates |
There was a problem hiding this comment.
If the T500 is the same as other wheels, why add this note?
| ```shell | ||
| echo 'blacklist hid_thrustmaster' | sudo tee /etc/modprobe.d/hid_thrustmaster.conf | ||
| ``` | ||
| **Only do this if this repo's `hid-tminit` is installed** (it is built and |
There was a problem hiding this comment.
This is not strictly related to the T500, I would suggest removing. Updating docs is something I've been thinking of, that can be handled separately.
| }; | ||
|
|
||
| /* Supported effects */ | ||
| extern const signed short t500rs_effects[]; |
There was a problem hiding this comment.
I don't think this needs to be exposed in the header.
| * - b11-b12: envelope packet subtype (LE) - determines 0x02 code | ||
| * - b13-b14: reserved (0x0000) | ||
| */ | ||
| struct t500rs_pkt_r01_main { |
There was a problem hiding this comment.
Similarly, these can probably just fine be in hid-tmt500rs.c. Generally, a header should only expose what's required to use the corresponding *.c file, which should be very little in this case. hid-tmff2.c doesn't need to know the packet structure of the wheels, just that a t500rs_populate_api() function exists :)
| hid_warn(t500rs->hdev, | ||
| "Autocenter-disable (0x40 0x04) failed: %d\n", ret); | ||
|
|
||
| /* Report 0x43 - Set global gain (2 bytes). Advisory: seed the device |
| hid_warn(t500rs->hdev, | ||
| "Initial gain set (0x43) failed: %d\n", ret); | ||
|
|
||
| hid_info(t500rs->hdev, "T500RS initialized successfully (HID mode)\n"); |
| (struct t500rs_pkt_r40_config *)init_buf; | ||
| config->id = 0x40; | ||
| config->subcmd = 0x04; | ||
| // Keep explicit zeros even though memset() clears them. |
| } | ||
| ret = t500rs_send_hid(t500rs, init_buf, 4); | ||
| if (ret) | ||
| hid_warn(t500rs->hdev, |
There was a problem hiding this comment.
Actually, why doesn't this just call t500rs_set_autocenter() directly?
| hid_warn(t500rs->hdev, "Init command 0x42 0x00 failed: %d\n", | ||
| ret); | ||
|
|
||
| /* Defensive state reset: a module reload (rmmod/insmod) does not |
There was a problem hiding this comment.
Man, this comment is verbose. Just say you're stopping any effects that may be lying around or something more to the point, this is rather tedious to try and parse.
| * Windows sends these at startup: 0x42 0x04, 0x42 0x05, 0x42 0x00 | ||
| * These appear to initialize the FFB subsystem state. | ||
| * | ||
| * The opening sync (0x42 0x04) is mandatory: if the device cannot |
There was a problem hiding this comment.
Is this not the open command that another comment claims the T500 doesn't use?
| return -EINVAL; | ||
| } | ||
|
|
||
| hid_dbg(tmff2->hdev, "T500RS: Initializing HID mode\n"); |
There was a problem hiding this comment.
Not using T500RS_DBG here for whatever reason. For what it's worth, I don't really see the benefit of the macro anyway, and would maybe prefer just using hid_dbg directly, but eh.
| goto out; | ||
| } | ||
|
|
||
| /* Apply settings with Report 0x42 0x05 */ |
There was a problem hiding this comment.
Applying settings seems to be used a few times, would it make sense to have a separate function for it?
I am not sure about the stack. I tried to link them (it's linked locally on my PC using gh CLI) but when I attempt to push, I am having 422 errors: In the WebUI, If I edit the PR target, I cannot select the initial PR (with the defer), the reason being that my code resides in a fork, and this new PR cannot target the other PR itself. Either i'm doing wrong, either I just missed something. |
|
Huh, weird. I've only used the GitLab version of stacked PRs, which worked as expected, and you could select the PR from the dropdown of target branches. Anyway, no big deal if we can't figure this out right now, we can just focus on one PR at a time and when the lowest one gets merged, the commits should disappear from the others PR and the discussion hopefully stays rather more focused. |
|
Darn, read through the GitHub docs about stacked PRs and noticed
That's annoying, I guess they're currently targeting more enterprise-y situations. Sorry, didn't realize earlier, but let's keep this informatl stack going, I suspect it's still better than one huge PR. |
|
Maybe just keep a local queue branch, then push only a reviewable small commit series. Wait for feedback. Create fixup commits, fold them into the PR commits, then rebase. If the PR is ready and merged, rebase your remaining work, then create a new PR. |
The input core invokes the FF gain and autocenter callbacks from event context, which may run with IRQs disabled, and the sysfs gain store calls them from process context. Model drivers issue blocking HID output in these callbacks, which is illegal in atomic context and races the effect worker on shared transfer buffers. Route both through the existing effect workqueue instead: mark the request pending in the device entry and apply it in the worker, serialized with effect processing. Gain follows the master x game model (as lg4ff): the sysfs gain parameter acts as the master gain, the value written through the input API is the game gain, and the worker sends their product to the wheel via tmff2_scale_gain(). Both sources only mark the gain pending; the worker recomputes the product from the live values on each flush, so a sysfs change takes effect immediately without having to replay the last in-game request. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
b1b7784 to
78340e4
Compare
Add a T500RS driver on top of the core hid-tmff2 framework: - HID-mode init sequence (0x42 sync, slot STOP sweep, 0x40 autocenter teardown, 0x43 gain default); the b65d bootloader -> b65e mode switch is handled by hid-tminit. - Constant force effects only at this stage: hardware slot 0 with fixed subtypes (param 0x0e / env 0x1c), 0x03 level updates, mandatory zero-envelope 0x02, and a software expiry timer sending per-slot 0x41 STOPs (the wheel never auto-stops on its own). - Gain and range via the core parameters; autocentering routed through the core workqueue (T500RS callbacks do blocking HID I/O and must not run from atomic context). - Protocol reference: docs/T500RS_FFBEFFECTS.md (constant force sections). The shared docs/FFBEFFECTS.md is renamed to docs/T300RS_FFBEFFECTS.md since it documents the T300RS protocol. - udev rule for the SteamDeck variant.
78340e4 to
cdba043
Compare
Stacked on #220 (defer gain/autocenter to the workqueue).
Adds a T500RS driver on top of the core hid-tmff2 framework:
Follow-up stages in this stack add periodic/ramp effects and passive (condition) effects.