Skip to content

Commit bd43bb9

Browse files
committed
hid: tmff2: add Thrustmaster T500RS wheel base driver
Add support for the Thrustmaster T500RS wheel base in the hid-tmff2 driver. This driver has been built from scratch based the previous dirty driver (see #175) on captures from ffbsdl tool ran in windows for all possible effects (through SDL2 library).
1 parent c4b70d4 commit bd43bb9

File tree

9 files changed

+3096
-8
lines changed

9 files changed

+3096
-8
lines changed

Kbuild

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,8 @@ hid-tmff-new-y := \
44
src/tmt300rs/hid-tmt300rs.o \
55
src/tmt248/hid-tmt248.o \
66
src/tmtx/hid-tmtx.o \
7-
src/tmtsxw/hid-tmtsxw.o
7+
src/tmtsxw/hid-tmtsxw.o \
8+
src/tmt500rs/hid-tmt500rs.o
9+
10+
# Pass through the global TMFF2 version define from Makefile
11+
ccflags-y += $(TMFF2_VERSION_DEF)

Makefile

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,30 @@
11
KDIR ?= /lib/modules/$(shell uname -r)/build
22

3+
# Auto-generated global build-time version for TMFF2
4+
TMFF2_BASE_VERSION ?= 0.1
5+
6+
# Allow packagers / CI to provide a fixed hash or full version:
7+
# make GIT_HASH=deadbee
8+
# make TMFF2_VERSION=0.1-1
9+
#
10+
# Only derive GIT_HASH from git if none was provided and this is a git checkout.
11+
ifeq ($(origin GIT_HASH), undefined)
12+
GIT_HASH := $(shell if command -v git >/dev/null 2>&1 && [ -d .git ]; then \
13+
git rev-parse --short=7 HEAD 2>/dev/null; \
14+
else \
15+
echo local; \
16+
fi)
17+
endif
18+
19+
BUILD_HASH := $(shell date +%s | sha1sum | cut -c1-7)
20+
21+
TMFF2_VERSION ?= $(TMFF2_BASE_VERSION)-$(GIT_HASH)+b$(BUILD_HASH)
22+
export TMFF2_VERSION_DEF := -DTMFF2_DRIVER_VERSION=\"$(TMFF2_VERSION)\"
23+
24+
325
all: deps/hid-tminit
26+
@echo "TMFF2 build version: $(TMFF2_VERSION)"
27+
@echo " - base: $(TMFF2_BASE_VERSION), commit: $(GIT_HASH), build: $(BUILD_HASH)"
428
$(MAKE) -C $(KDIR) M=$(shell pwd) modules
529

630
install: deps/hid-tminit

docs/T500RS_USB_Protocol_Analysis.md

Lines changed: 663 additions & 0 deletions
Large diffs are not rendered by default.

src/hid-tmff2.c

Lines changed: 92 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,31 @@ static ssize_t gain_store(struct device *dev,
242242
}
243243

244244
gain = value;
245-
if (tmff2->set_gain) /* if we can, update gain immediately */
246-
tmff2->set_gain(tmff2->data, (GAIN_MAX * gain) / GAIN_MAX);
245+
246+
/* Rationale: two-level gain model
247+
* - The input API's set_gain (pg) is the in-game gain (0..GAIN_MAX).
248+
* - This driver also exposes a device/system gain via sysfs param `gain`.
249+
* - The device callback receives the product: (pg * gain) / GAIN_MAX.
250+
* See worker at tmff2->set_gain(... (pg * gain) / GAIN_MAX ).
251+
* When the sysfs `gain` changes, we trigger a recompute by pushing
252+
* pending_gain_value = GAIN_MAX here so the effective device gain becomes
253+
* exactly the sysfs value (GAIN_MAX * gain / GAIN_MAX == gain) and future
254+
* in-game set_gain calls continue to multiply in.
255+
*
256+
* References:
257+
* - docs/FFBEFFECTS.md: section "FF_GAIN" shows a dedicated device gain path.
258+
* - docs/FFB_T500RS.md: Report glossary mentions 0x43 (gain), i.e., device-side
259+
* gain separate from per-effect magnitudes; drivers should expose both levels.
260+
*/
261+
if (tmff2->set_gain) {
262+
unsigned long flags;
263+
spin_lock_irqsave(&tmff2->lock, flags);
264+
tmff2->pending_gain_value = GAIN_MAX;
265+
tmff2->gain_pending = 1;
266+
spin_unlock_irqrestore(&tmff2->lock, flags);
267+
if (!delayed_work_pending(&tmff2->work) && tmff2->allow_scheduling)
268+
schedule_delayed_work(&tmff2->work, 0);
269+
}
247270

248271
return count;
249272
}
@@ -258,6 +281,7 @@ static DEVICE_ATTR_RW(gain);
258281
static void tmff2_set_gain(struct input_dev *dev, uint16_t value)
259282
{
260283
struct tmff2_device_entry *tmff2 = tmff2_from_input(dev);
284+
unsigned long flags;
261285

262286
if (!tmff2)
263287
return;
@@ -267,13 +291,20 @@ static void tmff2_set_gain(struct input_dev *dev, uint16_t value)
267291
return;
268292
}
269293

270-
if (tmff2->set_gain(tmff2->data, (value * gain) / GAIN_MAX))
271-
hid_warn(tmff2->hdev, "unable to set gain\n");
294+
/* Defer to workqueue: store pending gain and schedule */
295+
spin_lock_irqsave(&tmff2->lock, flags);
296+
tmff2->pending_gain_value = value;
297+
tmff2->gain_pending = 1;
298+
spin_unlock_irqrestore(&tmff2->lock, flags);
299+
300+
if (!delayed_work_pending(&tmff2->work) && tmff2->allow_scheduling)
301+
schedule_delayed_work(&tmff2->work, 0);
272302
}
273303

274304
static void tmff2_set_autocenter(struct input_dev *dev, uint16_t value)
275305
{
276306
struct tmff2_device_entry *tmff2 = tmff2_from_input(dev);
307+
unsigned long flags;
277308

278309
if (!tmff2)
279310
return;
@@ -283,8 +314,14 @@ static void tmff2_set_autocenter(struct input_dev *dev, uint16_t value)
283314
return;
284315
}
285316

286-
if (tmff2->set_autocenter(tmff2->data, value))
287-
hid_warn(tmff2->hdev, "unable to set autocenter\n");
317+
/* Defer to workqueue: store pending autocenter and schedule */
318+
spin_lock_irqsave(&tmff2->lock, flags);
319+
tmff2->pending_autocenter_value = value;
320+
tmff2->autocenter_pending = 1;
321+
spin_unlock_irqrestore(&tmff2->lock, flags);
322+
323+
if (!delayed_work_pending(&tmff2->work) && tmff2->allow_scheduling)
324+
schedule_delayed_work(&tmff2->work, 0);
288325
}
289326

290327
static void tmff2_work_handler(struct work_struct *w)
@@ -301,6 +338,30 @@ static void tmff2_work_handler(struct work_struct *w)
301338
if (!tmff2)
302339
return;
303340

341+
/* Apply pending control changes (gain/autocenter) in process context */
342+
{
343+
unsigned long f2;
344+
uint16_t pg = 0, pac = 0;
345+
int do_gain = 0, do_ac = 0;
346+
spin_lock_irqsave(&tmff2->lock, f2);
347+
if (tmff2->gain_pending) {
348+
pg = tmff2->pending_gain_value;
349+
tmff2->gain_pending = 0;
350+
do_gain = 1;
351+
}
352+
if (tmff2->autocenter_pending) {
353+
pac = tmff2->pending_autocenter_value;
354+
tmff2->autocenter_pending = 0;
355+
do_ac = 1;
356+
}
357+
spin_unlock_irqrestore(&tmff2->lock, f2);
358+
359+
if (do_gain && tmff2->set_gain)
360+
tmff2->set_gain(tmff2->data, (pg * gain) / GAIN_MAX);
361+
if (do_ac && tmff2->set_autocenter)
362+
tmff2->set_autocenter(tmff2->data, pac);
363+
}
364+
304365
for (effect_id = 0; effect_id < tmff2->max_effects; ++effect_id) {
305366
unsigned long actions = 0;
306367
struct tmff2_effect_state effect;
@@ -315,15 +376,26 @@ static void tmff2_work_handler(struct work_struct *w)
315376

316377
effect_delay = state->effect.replay.delay;
317378
effect_length = state->effect.replay.length;
379+
/* If playing with a finite length, stop when (delay + length) elapses */
318380
if (test_bit(FF_EFFECT_PLAYING, &state->flags) && effect_length) {
319381
if ((time_now - state->start_time) >=
320382
(effect_delay + effect_length) * state->count) {
321383
__clear_bit(FF_EFFECT_PLAYING, &state->flags);
322384
__clear_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags);
323-
385+
/* Request a STOP in process context */
386+
__set_bit(FF_EFFECT_QUEUE_STOP, &actions);
324387
state->count = 0;
325388
}
326389
}
390+
/* Delay handling for start: only trigger START after replay.delay */
391+
if (test_bit(FF_EFFECT_QUEUE_START, &state->flags)) {
392+
if ((time_now - state->start_time) >= effect_delay) {
393+
__set_bit(FF_EFFECT_QUEUE_START, &actions);
394+
__clear_bit(FF_EFFECT_QUEUE_START, &state->flags);
395+
/* effect is playing since we're starting it now */
396+
__set_bit(FF_EFFECT_PLAYING, &state->flags);
397+
} /* else: keep START pending until delay elapsed */
398+
}
327399

328400
if (test_bit(FF_EFFECT_QUEUE_UPLOAD, &state->flags)) {
329401
__set_bit(FF_EFFECT_QUEUE_UPLOAD, &actions);
@@ -694,6 +766,11 @@ static int tmff2_probe(struct hid_device *hdev, const struct hid_device_id *id)
694766
goto wheel_err;
695767
break;
696768

769+
case TMT500RS_PC_ID:
770+
if ((ret = t500rs_populate_api(tmff2)))
771+
goto wheel_err;
772+
break;
773+
697774
case TMT248_PC_ID:
698775
if ((ret = t248_populate_api(tmff2)))
699776
goto wheel_err;
@@ -802,6 +879,8 @@ static const struct hid_device_id tmff2_devices[] = {
802879
{HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, TMT300RS_PS3_NORM_ID)},
803880
{HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, TMT300RS_PS3_ADV_ID)},
804881
{HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, TMT300RS_PS4_NORM_ID)},
882+
/* t500rs */
883+
{HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, TMT500RS_PC_ID)},
805884
/* t248 PC*/
806885
{HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, TMT248_PC_ID)},
807886
/* tx */
@@ -822,4 +901,10 @@ static struct hid_driver tmff2_driver = {
822901
};
823902
module_hid_driver(tmff2_driver);
824903

904+
905+
#ifndef TMFF2_DRIVER_VERSION
906+
#define TMFF2_DRIVER_VERSION "dev"
907+
#endif
908+
MODULE_VERSION(TMFF2_DRIVER_VERSION);
909+
825910
MODULE_LICENSE("GPL");

src/hid-tmff2.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ struct tmff2_device_entry {
6464

6565
spinlock_t lock;
6666

67+
/* Pending control changes to be applied from workqueue context */
68+
uint16_t pending_gain_value;
69+
uint16_t pending_autocenter_value;
70+
int gain_pending;
71+
int autocenter_pending;
72+
6773
int allow_scheduling;
6874

6975
/* fields relevant to each actual device (T300, T248...) */
@@ -92,6 +98,7 @@ struct tmff2_device_entry {
9298
ssize_t (*alt_mode_show)(void *data, char *buf);
9399
ssize_t (*alt_mode_store)(void *data, const char *buf, size_t count);
94100
int (*set_autocenter)(void *data, uint16_t autocenter);
101+
95102
__u8 *(*wheel_fixup)(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize);
96103

97104
/* void pointers are dangerous, I know, but in this case likely the
@@ -100,6 +107,7 @@ struct tmff2_device_entry {
100107

101108
/* external */
102109
int t300rs_populate_api(struct tmff2_device_entry *tmff2);
110+
int t500rs_populate_api(struct tmff2_device_entry *tmff2);
103111
int t248_populate_api(struct tmff2_device_entry *tmff2);
104112
int tx_populate_api(struct tmff2_device_entry *tmff2);
105113
int tsxw_populate_api(struct tmff2_device_entry *tmff2);
@@ -108,6 +116,8 @@ int tsxw_populate_api(struct tmff2_device_entry *tmff2);
108116
#define TMT300RS_PS3_ADV_ID 0xb66f
109117
#define TMT300RS_PS4_NORM_ID 0xb66d
110118

119+
#define TMT500RS_PC_ID 0xb65e
120+
111121
#define TMT248_PC_ID 0xb696
112122

113123
#define TX_ACTIVE 0xb669

0 commit comments

Comments
 (0)