Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Thrustmaster TS-PC (TS Racer) support #65

Open
solarisfire opened this issue May 7, 2023 · 36 comments
Open

Thrustmaster TS-PC (TS Racer) support #65

solarisfire opened this issue May 7, 2023 · 36 comments

Comments

@solarisfire
Copy link

Any chance this wheelbase could be supported?

Should be similar to some of the other bases.

Currently just getting:

[ 308.587876] usb 3-2.3: new full-speed USB device number 10 using xhci_hcd
[ 308.714187] usb 3-2.3: New USB device found, idVendor=044f, idProduct=b65d, bcdDevice= 7.00
[ 308.714189] usb 3-2.3: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 308.714191] usb 3-2.3: Product: Thrustmaster FFB Wheel
[ 308.714192] usb 3-2.3: Manufacturer: Thrustmaster
[ 308.814269] input: Thrustmaster Thrustmaster FFB Wheel as /devices/pci0000:00/0000:00:01.2/0000:02:00.0/0000:03:08.0/0000:07:00.3/usb3/3-2/3-2.3/3-2.3:1.0/0003:044F:B65D.0013/input/input30
[ 308.814347] hid-tminit 0003:044F:B65D.0013: input,hidraw17: USB HID v1.00 Gamepad [Thrustmaster Thrustmaster FFB Wheel] on usb-0000:07:00.3-2.3/input0
[ 308.834183] hid-tminit 0003:044F:B65D.0013: Unknown wheel's model id 0x6, unable to proceed further with wheel init

@Kimplul
Copy link
Owner

Kimplul commented May 7, 2023

Any chance this wheelbase could be supported?

Supported, probably yes, but how much work that would take is hard to say. Unfortunately thrustmaster wheels
don't seem to really follow any consistent APIs, so two seemingly similar wheels may require wildly different implementations.

Did you already read https://github.com/Kimplul/hid-tmff2/wiki#how-to-add-in-support-for-a-new-t-series-wheel?
In addition to the stuff in the wiki, it seems that the TS-PC's initialization value is unknown, so we'd need some USB packet
captures of plugging the wheel in as well. The value would have to be added to the wheel table in hid-tminit.

@solarisfire
Copy link
Author

I am going to try and get the USB traces for this... just struggling to find some free time to do it!

@Potajito
Copy link

I also have a TS-PC would love to give a hand.

@Kimplul
Copy link
Owner

Kimplul commented Oct 21, 2023

@Potajito thanks for showing interest. As far as I'm aware, no USB packet captures have been made, so the general outline in #65 (comment) still applies. Please read through https://github.com/Kimplul/hid-tmff2/wiki#how-to-add-in-support-for-a-new-t-series-wheel and if you feel up for, try doing some captured and seeing if you can find some patterns in the data.

@solarisfire
Copy link
Author

Could do with some guidance when capturing.

It just seems to be a stream of URB_INTERRUPT and URB_CONTROL packets.

It did come back with some data on unplug/replug but not sure which bits would be the initialization value.

DEVICE DESCRIPTOR
bLength: 18
bDescriptorType: 0x01 (DEVICE)
bcdUSB: 0x0100
bDeviceClass: Device (0x00)
bDeviceSubClass: 0
bDeviceProtocol: 0 (Use class code info from Interface Descriptors)
bMaxPacketSize0: 8
idVendor: ThrustMaster, Inc. (0x044f)
idProduct: Unknown (0xb65d)
bcdDevice: 0x0700
iManufacturer: 1
iProduct: 2
iSerialNumber: 0
bNumConfigurations: 1

https://drive.google.com/file/d/13odXGOEfqU_Wfi7NfChZVsW5YsEGFQTp/view?usp=share_link

Not sure where I'd start trying to work out any sort of values for force feedback values. I think I need to find a tutorial for FEdit1...

@Kimplul
Copy link
Owner

Kimplul commented Oct 23, 2023

Sure, thanks for the capture. Just to start off with, the initial wheel state is with idProduct 0xb65d, and the Windows driver then sends out a packet to restart the wheel. After the restart, the wheel reconnects with idProduct 0xb689, as can be seen at packet no. 156 in your capture. So there should be at least one URB_CONTROL out from host to 3.1.0 in the first 150 or so packets that approximately matches
https://github.com/scarburato/hid-tminit/blob/9375f6c7d83af5dd6c8b8fe30351d0f36043b20a/hid-tminit.c#L140

In this case, it seems to be packet number 151, and from this we can see that the wValue used is 0x0009. This is the switch_value in struct tm_wheel_info.

Then we need to find another packet with the wheel's IDs. The wheel sends a packet to the computer, which should contain a number of bytes, two of which we're mainly interested in: one for the base model and one for the steering wheel attachment. These correspond to model and attachment in struct tm_wheel_info. This data should be found in a packet with bRequest == 73.
There are actually multiple of these packets for some reason (I'm guessing the Windows driver queries different parameters from different parts of the codebase, and it doesn't cache these parameters anywhere so it just requests them multiple times).

Anycase, looking at the data in packet 68, we see that the response data is 49 00 03 04 01 00 09 06 f9 01 00 00 09 01 00 00. This more or less looks like the other captures (some examples can be seen in the README in hid-tminit). Bytes 6 and 7 should be the attachment and model, respectively, so in this case model = 0x06 and attachment = 0x09. Adding an element to tm_wheel_infos[] should get hid-tminit to initialize wheel properly, something like

[...]
{0x06, 0x09, 0x0009, "Thrustmaster TS-PC"},
[...]

With my T300, for some reason I also had to send out a number of other packets, see
https://github.com/scarburato/hid-tminit/blob/9375f6c7d83af5dd6c8b8fe30351d0f36043b20a/hid-tminit.c#L26,

but other wheels don't seem to require this so I would expect that the TS-PC doesn't either.

Not sure where I'd start trying to work out any sort of values for force feedback values. I think I need to find a tutorial for FEdit1...

If you find one, let me know, not aware of any. Probably the biggest individual hurdle is the fact that you have to set the direction of the effect, the default of 'straight up' effectively translates to multiplying the force's magnitude by 0, i.e. makes the effect impossible to detect. Try dragging the direction pointer all the way to the right for example, and then go from there. Maybe go for studying just one effect at a time, i.e. press the effect button and drag it to the timeline. Note that the location on the timeline effectively adds a delay, i.e. to immediately feel an effect drag it as far left as possible.

Other than that, I guess it's worth keeping in mind that wheels typically have a couple different kinds of packets, ones that upload effects to the device and ones that modify already uploaded effects. Took me a while to figure that one out, but essentially when close the effect modification window, you should see the effect get uploaded with all possible configuration values initialized. After that, if you open up the modification window again and tweak one parameter, you should see a number of packets that each modify only the parameter you've just tweaked. If the packets you capture look like ones in https://github.com/Kimplul/hid-tmff2/blob/master/docs/FFBEFFECTS.md,

then it should be fairly straightforward to just add the wheel's USB product ID to the list of supported devices for this driver. Otherwise, you'll have to try and reverse engineer the packets yourself.

I encourage playing around with FEdit, it's ultimately not a particularly complicated program, as it more or less one-to-one maps parameters in the GUI to parameters that get sent to the wheel. The interface is just a bit daunting.

Feel free to ask questions, I'll try to help as best as I can.

@svenliekens
Copy link

svenliekens commented Jan 20, 2024

Hi

I have recently switched to Fedora from Windows and have been trying to get my TS-PC RACER to work on Linux.

I started playing with FEdit and wireshark on a spare laptop with the wheel connected.
Have managed to capture the Spring effect. It looks like it uses the same parameters as listed in the FFBEFFECTS doc.
See the attached capture file (packet no. 5) spring_effect_capture2.zip

At this point I made the quick assumption that the rest of the FFB effects would be the same.
I decided to try to build the kernel module.

  • cloned this repo
  • added {0x06, 0x09, 0x0009, "Thrustmaster TS-PC"}, to hid-tmff2/deps/hid-tminit/hid-tminit.c
  • from hid-tmff2, ran make and sudo make install

This resulted in the following output

~/hid-tmff2$ sudo make
[sudo] password for sven: 
make -C deps/hid-tminit KDIR="/lib/modules/6.6.11-200.fc39.x86_64/build" 
make[1]: Entering directory '/home/sven/hid-tmff2/deps/hid-tminit'
make -C /lib/modules/6.6.11-200.fc39.x86_64/build M=/home/sven/hid-tmff2/deps/hid-tminit modules
make[2]: Entering directory '/usr/src/kernels/6.6.11-200.fc39.x86_64'
make[2]: Leaving directory '/usr/src/kernels/6.6.11-200.fc39.x86_64'
make[1]: Leaving directory '/home/sven/hid-tmff2/deps/hid-tminit'
make -C /lib/modules/6.6.11-200.fc39.x86_64/build M=/home/sven/hid-tmff2 modules
make[1]: Entering directory '/usr/src/kernels/6.6.11-200.fc39.x86_64'
make[1]: Leaving directory '/usr/src/kernels/6.6.11-200.fc39.x86_64'
~/hid-tmff2$ sudo make install
make -C deps/hid-tminit KDIR="/lib/modules/6.6.11-200.fc39.x86_64/build" install
make[1]: Entering directory '/home/sven/hid-tmff2/deps/hid-tminit'
make -C /lib/modules/6.6.11-200.fc39.x86_64/build M=/home/sven/hid-tmff2/deps/hid-tminit modules_install
make[2]: Entering directory '/usr/src/kernels/6.6.11-200.fc39.x86_64'
  INSTALL /lib/modules/6.6.11-200.fc39.x86_64/updates/hid-tminit.ko
  SIGN    /lib/modules/6.6.11-200.fc39.x86_64/updates/hid-tminit.ko
At main.c:167:
- SSL error:FFFFFFFF80000002:system library::No such file or directory: crypto/bio/bss_file.c:67
- SSL error:10000080:BIO routines::no such file: crypto/bio/bss_file.c:75
sign-file: ./certs/signing_key.pem
  DEPMOD  /lib/modules/6.6.11-200.fc39.x86_64
make[2]: Leaving directory '/usr/src/kernels/6.6.11-200.fc39.x86_64'
make[1]: Leaving directory '/home/sven/hid-tmff2/deps/hid-tminit'
make -C /lib/modules/6.6.11-200.fc39.x86_64/build M=/home/sven/hid-tmff2 modules_install
make[1]: Entering directory '/usr/src/kernels/6.6.11-200.fc39.x86_64'
  INSTALL /lib/modules/6.6.11-200.fc39.x86_64/updates/hid-tmff-new.ko
  SIGN    /lib/modules/6.6.11-200.fc39.x86_64/updates/hid-tmff-new.ko
At main.c:167:
- SSL error:FFFFFFFF80000002:system library::No such file or directory: crypto/bio/bss_file.c:67
- SSL error:10000080:BIO routines::no such file: crypto/bio/bss_file.c:75
sign-file: ./certs/signing_key.pem
  DEPMOD  /lib/modules/6.6.11-200.fc39.x86_64
make[1]: Leaving directory '/usr/src/kernels/6.6.11-200.fc39.x86_64'
depmod -A

I think something went wrong at the SIGN step, so I'm not sure if the build succeeded or not...

~/hid-tmff2$ lsmod | grep thrust
hid_thrustmaster       16384  0

It seems like the kernel module is loaded.

When I start Assetto Corsa (via proton-ge) my wheel is not recognised.

How should I proceed? I will test some more of the FFB effects in the mean time and compare them to the FFBEFFECTS doc.

@Kimplul
Copy link
Owner

Kimplul commented Jan 20, 2024

I think something went wrong at the SIGN step, so I'm not sure if the build succeeded or not...

Signing the module is an optional step that has to be done by whoever builds the module. The error messages are pretty scary but generally don't stop the module from functioning. There's a separate kernel configuration parameter that can disable loading unsigned modules, but it tends to not be enabled on major distros. There's a short note about it in the README.

It seems like the kernel module is loaded.

The naming is a bit messy here, hid-thrustmaster is the in-kernel counterpart of hid-tminit which is a separate module just to initialize different Thrustmaster wheels. For whatever reason Thrustmaster wheels have to be reminded which model they are, and only after that is done can FFB be used, which is what this module handles. This (hid-tmff2) module would actually show up as hid-tmff-new in lsmod because of some name handling limitations in Kbuild.

Anycase, once the wheel is told which model it is, it restarts itself and reconnects under a new USB id, which you will have to add to

static const struct hid_device_id tmff2_devices[] = {

and

switch (tmff2->hdev->product) {

It's possible that the TS-PC differs in some subtle ways from other wheels supported (different wheel range, init commands, rdesc, whatever), so you might have to add a new subdir in src. Just copy one of the existing ones and tweak values found therein. Remember to point src/Kbuild to the new dir. Unfortunately I can't really help much in figuring out which bits (if any) might have to be flipped, it was a lot of trial and error when I went through it with the T300. Mostly I just tried to get the USB traffic to resemble the captures as close as possible.

Check out sudo dmesg -w when you plug the wheel in, should show the USB product ID and (typically) helpful error messages.

@svenliekens
Copy link

svenliekens commented Jan 24, 2024

The changes I have made to hid-tminit

~/hid-tmff2/deps/hid-tminit$ git diff
diff --git a/hid-tminit.c b/hid-tminit.c
index 266086e..05e35c3 100644
--- a/hid-tminit.c
+++ b/hid-tminit.c
@@ -70,11 +70,12 @@ static const struct tm_wheel_info tm_wheels_infos[] = {
        ...
        {0x02, 0x04, 0x0005, "Thrustmaster T300 Ferrari Alcantara Edition"},
        {0x02, 0x06, 0x0005, "Thrustmaster T300RS"},
        {0x02, 0x09, 0x0005, "Thrustmaster T300RS (Open Wheel Attachment)"},
-       {0x03, 0x06, 0x0006, "Thrustmaster T150RS"}
+       {0x03, 0x06, 0x0006, "Thrustmaster T150RS"},
+       {0x06, 0x09, 0x0009, "Thrustmaster TS-PC"},
        //{0x04, 0x07, 0x0001, "Thrustmaster TMX"}
 };
 
-static const uint8_t tm_wheels_infos_length = 7;
+static const uint8_t tm_wheels_infos_length = 8;

The changes I have made to hid-tmff2

~/hid-tmff2$ git diff
--- a/src/hid-tmff2.c
+++ b/src/hid-tmff2.c
@@ -616,6 +616,7 @@ static int tmff2_probe(struct hid_device *hdev, const struct hid_device_id *id)
        hid_set_drvdata(tmff2->hdev, tmff2);
 
        switch (tmff2->hdev->product) {
+               case TMTS_PC_RACER_ID: 
                case TMT300RS_PS3_NORM_ID:
                case TMT300RS_PS3_ADV_ID:
                case TMT300RS_PS4_NORM_ID:
@@ -727,7 +728,8 @@ static const struct hid_device_id tmff2_devices[] = {
        {HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, TMT248_PC_ID)},
        /* tx */
        {HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, TX_ACTIVE)},
-
+       /* TS-PC RACER */
+       {HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, TMTS_PC_RACER_ID)},
        {}
 };
 MODULE_DEVICE_TABLE(hid, tmff2_devices);
diff --git a/src/hid-tmff2.h b/src/hid-tmff2.h
index 1eb3546..822a598 100644
--- a/src/hid-tmff2.h
+++ b/src/hid-tmff2.h
@@ -111,6 +111,8 @@ int tx_populate_api(struct tmff2_device_entry *tmff2);
 
 #define TX_ACTIVE               0xb669
 
+#define TMTS_PC_RACER_ID 0xb689
+

After sudo make && sudo make install I plug in the wheel and get the following output in dmesg. I tried some things but I'm not sure how to fix this 😬

[21716.528256] usb 3-3.1: new full-speed USB device number 6 using xhci_hcd
[21716.642259] usb 3-3.1: New USB device found, idVendor=044f, idProduct=b65d, bcdDevice= 7.00
[21716.642264] usb 3-3.1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[21716.642267] usb 3-3.1: Product: Thrustmaster FFB Wheel
[21716.642269] usb 3-3.1: Manufacturer: Thrustmaster
[21716.725411] input: Thrustmaster Thrustmaster FFB Wheel as /devices/pci0000:00/0000:00:08.1/0000:09:00.3/usb3/3-3/3-3.1/3-3.1:1.0/0003:044F:B65D.000B/input/input20
[21716.725549] hid-thrustmaster 0003:044F:B65D.000B: input,hidraw9: USB HID v1.00 Gamepad [Thrustmaster Thrustmaster FFB Wheel] on usb-0000:09:00.3-3.1/input0
[21716.745230] hid-thrustmaster 0003:044F:B65D.000B: Unknown wheel's model id 0x609, unable to proceed further with wheel init
[21716.759400] Error: Driver 'hid-thrustmaster' is already registered, aborting...

Seems like the wheel connects as id 0xb65d, but it doesn't get to the part where it restarts and uses new ID 0xb689.

I'm not even sure where wheel's model id 0x609 is coming from.

I have confirmed in my USB captures that on the Windows driver it uses the above IDs (0xb65d -> 0xb689, as you already figured out in a previous comment)

@Kimplul
Copy link
Owner

Kimplul commented Jan 24, 2024

After sudo make && sudo make install I plug in the wheel and get the following output in dmesg. I tried some things but I'm not sure how to fix this 😬

Oh right, you'll have to blacklist the in-kernel module:

echo 'blacklist hid_thrustmaster' > /etc/modprobe.d/hid_thrustmaster.conf

There's some weird name clash that happens otherwise, meaning the changes you've made haven't actually been run yet.

I'm not even sure where wheel's model id 0x609 is coming from.

Here: https://elixir.bootlin.com/linux/latest/source/drivers/hid/hid-thrustmaster.c#L240 Essentially, the wheel sends a response to a init driver query, and the 'actual' wheel ID is in that response. You'd think the USB id was the main ID but nah, that would be too easy. Anyway, you've already added it to the driver as 0x6, 0x9, it just gets printed differently in the in-kernel module.

@svenliekens
Copy link

[  100.396525] usb 3-3.1: new full-speed USB device number 5 using xhci_hcd
[  100.510157] usb 3-3.1: New USB device found, idVendor=044f, idProduct=b65d, bcdDevice= 7.00
[  100.510165] usb 3-3.1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[  100.510169] usb 3-3.1: Product: Thrustmaster FFB Wheel
[  100.510171] usb 3-3.1: Manufacturer: Thrustmaster
[  100.595651] input: Thrustmaster Thrustmaster FFB Wheel as /devices/pci0000:00/0000:00:08.1/0000:09:00.3/usb3/3-3/3-3.1/3-3.1:1.0/0003:044F:B65D.000A/input/input18
[  100.595787] hid-thrustmaster 0003:044F:B65D.000A: input,hidraw9: USB HID v1.00 Gamepad [Thrustmaster Thrustmaster FFB Wheel] on usb-0000:09:00.3-3.1/input0
[  100.616128] hid-thrustmaster 0003:044F:B65D.000A: Wheel with (model, attachment) = (0x6, 0x9) is a Thrustmaster TS-PC. attachment_found=1
[  100.618320] hid-thrustmaster 0003:044F:B65D.000A: Success?! The wheel should have been initialized!
[  100.711616] usb 3-3.1: USB disconnect, device number 5
[  101.419230] usb 3-3.1: new full-speed USB device number 6 using xhci_hcd
[  101.536158] usb 3-3.1: New USB device found, idVendor=044f, idProduct=b689, bcdDevice= 7.00
[  101.536167] usb 3-3.1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[  101.536170] usb 3-3.1: Product: Thrustmaster TS-PC Racer
[  101.536173] usb 3-3.1: Manufacturer: Thrustmaster
[  101.612400] input: Thrustmaster Thrustmaster TS-PC Racer as /devices/pci0000:00/0000:00:08.1/0000:09:00.3/usb3/3-3/3-3.1/3-3.1:1.0/0003:044F:B689.000B/input/input19
[  101.612579] hid-generic 0003:044F:B689.000B: input,hidraw9: USB HID v1.11 Joystick [Thrustmaster Thrustmaster TS-PC Racer] on usb-0000:09:00.3-3.1/input0
[  101.647434] input: Thrustmaster Thrustmaster TS-PC Racer as /devices/pci0000:00/0000:00:08.1/0000:09:00.3/usb3/3-3/3-3.1/3-3.1:1.0/0003:044F:B689.000B/input/input20
[  101.647577] tmff2 0003:044F:B689.000B: input,hidraw9: USB HID v1.11 Joystick [Thrustmaster Thrustmaster TS-PC Racer] on usb-0000:09:00.3-3.1/input0
[  101.649134] tmff2 0003:044F:B689.000B: firmware version 13 is too old, please update.
[  101.649137] tmff2 0003:044F:B689.000B: note: this has to be done through Windows.
[  101.649139] tmff2 0003:044F:B689.000B: failed initializing T300RS
[  101.649140] tmff2 0003:044F:B689.000B: init failed
[  101.668285] tmff2: probe of 0003:044F:B689.000B failed with error -22

We are making progress!
Looks like the restart (init) is working and we're getting into tmff2 territory.

It is now complaining about the firmware version being too old. But I have the newest TS PC firmware...

I assume this is where I make a subdir for the TS-PC racer, as you mentioned before (start with a copy of the T300RS?)

It's possible that the TS-PC differs in some subtle ways from other wheels supported (different wheel range, init commands, rdesc, whatever), so you might have to add a new subdir in src. Just copy one of the existing ones and tweak values found therein. Remember to point src/Kbuild to the new dir. Unfortunately I can't really help much in figuring out which bits (if any) might have to be flipped, it was a lot of trial and error when I went through it with the T300. Mostly I just tried to get the USB traffic to resemble the captures as close as possible.

@Kimplul
Copy link
Owner

Kimplul commented Jan 25, 2024

We are making progress!
Looks like the restart (init) is working and we're getting into tmff2 territory.

Excellent!

I assume this is where I make a subdir for the TS-PC racer, as you mentioned before (start with a copy of the T300RS?)

Yep, looks appropriate. Try maybe copying tmt248 instead, T300 is the 'base' for the other wheels and they use functions defined in tmt300rs, and the less you have to copy the better. Eventually I might refactor things to be a bit more clear, but as this was originally a T300 driver everything sort of evolved to be built on top of that wheel.

The T248 also doesn't currently have a firmware version check, so less changes to be made.

@svenliekens
Copy link

svenliekens commented Jan 25, 2024

[ 2129.709212] usb 3-3.1: new full-speed USB device number 11 using xhci_hcd
[ 2129.826621] usb 3-3.1: New USB device found, idVendor=044f, idProduct=b65d, bcdDevice= 7.00
[ 2129.826629] usb 3-3.1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 2129.826633] usb 3-3.1: Product: Thrustmaster FFB Wheel
[ 2129.826635] usb 3-3.1: Manufacturer: Thrustmaster
[ 2129.902793] input: Thrustmaster Thrustmaster FFB Wheel as /devices/pci0000:00/0000:00:08.1/0000:09:00.3/usb3/3-3/3-3.1/3-3.1:1.0/0003:044F:B65D.0010/input/input26
[ 2129.902972] hid-thrustmaster 0003:044F:B65D.0010: input,hidraw9: USB HID v1.00 Gamepad [Thrustmaster Thrustmaster FFB Wheel] on usb-0000:09:00.3-3.1/input0
[ 2129.922592] hid-thrustmaster 0003:044F:B65D.0010: Wheel with (model, attachment) = (0x6, 0x9) is a Thrustmaster TS-PC. attachment_found=1
[ 2129.924784] hid-thrustmaster 0003:044F:B65D.0010: Success?! The wheel should have been initialized!
[ 2130.026081] usb 3-3.1: USB disconnect, device number 11
[ 2130.730854] usb 3-3.1: new full-speed USB device number 12 using xhci_hcd
[ 2130.846596] usb 3-3.1: New USB device found, idVendor=044f, idProduct=b689, bcdDevice= 7.00
[ 2130.846602] usb 3-3.1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 2130.846605] usb 3-3.1: Product: Thrustmaster TS-PC Racer
[ 2130.846607] usb 3-3.1: Manufacturer: Thrustmaster
[ 2130.926887] input: Thrustmaster Thrustmaster TS-PC Racer as /devices/pci0000:00/0000:00:08.1/0000:09:00.3/usb3/3-3/3-3.1/3-3.1:1.0/0003:044F:B689.0011/input/input27
[ 2130.927082] tmff2 0003:044F:B689.0011: input,hidraw9: USB HID v1.11 Joystick [Thrustmaster Thrustmaster TS-PC Racer] on usb-0000:09:00.3-3.1/input0
[ 2130.933832] tmff2 0003:044F:B689.0011: force feedback for tspc

I now have the wheel showing up on https://hardwaretester.com/gamepad
The steering axis is working perfectly. I have played BeamNG with it. Force feedback seems to be doing nothing even though I have it enabled in the game.

So we're going in the right direction here, but I'm not sure on how to proceed... 😬

@Kimplul
Copy link
Owner

Kimplul commented Jan 25, 2024

So we're going in the right direction here, but I'm not sure on how to proceed... 😬

Right, here are a couple things to try, off the top of my head

  1. Try capturing some packets from the driver, do they match the ones you captured earlier? 0x60 0x01 ...?

If they don't, the packet format changes slightly depending on some values in the rdesc, and it might be that the TS-PC rdesc differs from the one the T248 uses. For example, I captured the T248 rdesc from the wheel and had to change these two lines:

0x09, 0x60, /* Usage (96), prev 10 */

0x85, 0x60, /* Report ID (96), prev 10 */

  1. The wheel might require some extra initialization packets. The T248, for whatever reason, needs these packets to be sent out before anything else happens:

static const u8 setup_0[64] = { 0x42, 0x01 };

The T300 didn't need them, so this might be something that changes from wheel to wheel. Maybe try checking if you can see anything similar in your Windows captures.

  1. The wheel only processes FFB after it gets sent some enable packets. The driver sends these packets when something opens the wheel:

static int t300rs_send_open(struct t300rs_device_entry *t300rs)

The T248 needs an extra packet here as well that the T300 didn't need, so the TS-PC might also differ in this regard. Check if you can see any extra packets being sent in Windows when you open a program that connects to the wheel.

Good luck, you've just stumbled on the tedious part of reverse engineering :)

@Potajito
Copy link

I gave up basically at the same point that @svenliekens did, but, shouldn't this #94 bring also compat to ts-pc, as ts-xw is basically the same wheel base? 🤔

@Kimplul
Copy link
Owner

Kimplul commented Apr 27, 2024

@Potajito certainly possible, but you'd have to try it out for yourself. I don't really know what the differences between the TS-PC and TS-XW are, the bases definitely look similar but that hasn't always been a reliable indicator of compatibility. They don't seem to share the same USB PID at least, but you could start out by doing something like

case TSPC_ACTIVE:
case TSXW_ACTIVE:
                     if ((ret = tsxw_populate_api(tmff2)))
...

adam820 added a commit to adam820/hid-tminit that referenced this issue Jun 15, 2024
adam820 added a commit to adam820/hid-tmff2 that referenced this issue Jun 15, 2024
Based on the work of svenliekens in this comment:
Kimplul#65 (comment)
adam820 added a commit to adam820/hid-tmff2 that referenced this issue Jun 28, 2024
Based on the work of svenliekens in this comment:
Kimplul#65 (comment)
adam820 added a commit to adam820/hid-tmff2 that referenced this issue Jul 4, 2024
Based on the work of svenliekens in this comment:
Kimplul#65 (comment)
@BDave95
Copy link

BDave95 commented Jul 29, 2024

Hello, first of all thank you very much for this project, if we had to wait for Thrustmaster do do anything for us ... well
After following all steps in this thread to modify all needed files my TS-PS F458 edition is detected, and FFB seems to work, tested only with ETS2 for now but installing AC now to test with it, and pedals connected to it works also.

So this is a very good start but there's still some issues to fix :

  • in ETS2 i have a huge deadzone in the middle of steering axis and can't find any way to remove it
  • axis wheel + pedals are working fine (except deadzone in steering) but no buttons detected in ETS2 (that's why i'm installing AC to check if it's wheel or game related)
  • the wheel only works in standard mode and i would like to use it in advanced mode like in windows (more buttons to map)

The problem is my programming skills are limited to following tutos, and using existing files as templates to guess changes to do, so i will need help/direction to follow to investigate more.

The only thing i can think of for now is i added a directory for the tspc in /src but i have copied the T248 one as a base, maybe it would have been smarter to start from tsxw as it's almost the same wheel than the tspc

edit : just added support for TS_PC to Oversteer and it shows me a perfect steering axis without any unwanted deadzone so this one must be game related
Buttons problem however remains so this one must be driver related, maybe wrong assignation or something like that, have to investigate on this one

@Kimplul
Copy link
Owner

Kimplul commented Jul 29, 2024

@BDave95 Certainly sounds like some good process, well done!

just added support for TS_PC to Oversteer and it shows me a perfect steering axis without any unwanted deadzone so this one must be game related

It might also be possible that ETS2 uses joydev, whereas Oversteer uses evdev, but I'm not sure. Both have their own way to set deadzones. There's some previous discussion on it over in #42.

Buttons problem however remains so this one must be driver related, maybe wrong assignation or something like that, have to investigate on this one

Sounds like you might want to capture the device's rdesc and compare it to the one you're currently using, apparently t248_pc_rdesc_fixed. The wheel itself has a copy of the rdesc that gets sent over via USB when the wheel is connected to a PC, but for whatever reason they tend to not be accurate and need to be 'fixed', hence the t248_pc_rdesc_fixed etc. I would recommend doing a USB packet capture, the rdesc is among the first few USB packets sent from the wheel upon connecting. There's a short overview of what this involves over in https://github.com/Kimplul/hid-tmff2/wiki#how-to-capture-what-usb-packets-the-driver-sends-to-the-device

I don't know if the TS-PC supports attachments, but if it does, make sure it's installed properly. Apparently at least the T300 can sort of half-function with a poor connection: #89

@BDave95
Copy link

BDave95 commented Jul 30, 2024

Deadzone problem solved in all Steam games i've tested by creating a udev rule, thanks for the link, shame on me as it was mentioned on the front page

/etc/udev/rules.d/99-joydev.rules

SUBSYSTEM=="input", ATTRS{idVendor}=="044f", ATTRS{idProduct}=="b689", RUN+="/usr/bin/evdev-joystick --evdev %E{DEVNAME} --axis 0 --deadzone 0"

For the buttons problem can't be an attachment problem as it works perfectly in Windows
i tried to start from hid-tmtsxw.c instead of hid-tmt248.c and i gain access to most of my wheel buttons but not all and not with the right mapping so definitely have to do the rdesc thing but this will take more time that i have on evenings coming back from work so this will have to wait for the weekend.

Anyway for now the wheel is already usable in acceptable conditions and this is more than i hoped just a week ago so thank you again for starting this project and of course to all previous contributors to this thread.

@Potajito
Copy link

Potajito commented Aug 1, 2024

Hello, first of all thank you very much for this project, if we had to wait for Thrustmaster do do anything for us ... well After following all steps in this thread to modify all needed files my TS-PS F458 edition is detected, and FFB seems to work, tested only with ETS2 for now but installing AC now to test with it, and pedals connected to it works also.

So this is a very good start but there's still some issues to fix :

* in ETS2 i have a huge deadzone in the middle of steering axis and can't find any way to remove it

* axis wheel + pedals are working fine (except deadzone in steering) but no buttons detected in ETS2 (that's why i'm installing AC to check if it's wheel or game related)

* the wheel only works in standard mode and i would like to use it in advanced mode like in windows (more buttons to map)

The problem is my programming skills are limited to following tutos, and using existing files as templates to guess changes to do, so i will need help/direction to follow to investigate more.

The only thing i can think of for now is i added a directory for the tspc in /src but i have copied the T248 one as a base, maybe it would have been smarter to start from tsxw as it's almost the same wheel than the tspc

edit : just added support for TS_PC to Oversteer and it shows me a perfect steering axis without any unwanted deadzone so this one must be game related Buttons problem however remains so this one must be driver related, maybe wrong assignation or something like that, have to investigate on this one

Hi! Could you share what you did to get FFB working? Maybe point to a fork of this repo?
What I did was change the usb id for the tsxw to 0xb65d , blacklist hid_thrustmaster and manually install dkms module. I get the wheel to show up on gamepad testers, and I also forked Oversteer and added ts_pc support, so the wheel also shows up there, but no FFB so far. I think I'm missing something, I read about hid-tminit but I'm not really sure what to do with that.
Cheers! Feels like this is almost there!

@BDave95
Copy link

BDave95 commented Aug 2, 2024

Hi! Could you share what you did to get FFB working? Maybe point to a fork of this repo?
What I did was change the usb id for the tsxw to 0xb65d , blacklist hid_thrustmaster and manually install dkms module. I get the wheel to show up on gamepad testers, and I also forked Oversteer and added ts_pc support, so the wheel also shows up there, but no FFB so far. I think I'm missing something, I read about hid-tminit but I'm not really sure what to do with that.
Cheers! Feels like this is almost there!

The correct USB ID for the TS-PC is b689 not b65d so normal to not have FFB
If i understood correctly b65d is some sort of generic initialization ID common to all Thrustmaster wheel and the job of hid-tminit is to do the final initialization to get the right ID
The modifications i made to hid-tminit are only those indicated in svenliekens post above

Of course i will share my files, the goal is not to keep it for me but contributing to the driver for anyone, i'll see this weekend to make the diffs and publish them

@Potajito
Copy link

Potajito commented Aug 4, 2024

Thanks! I finally made it work, here is what I did, in case it can help someone else:

  • Modified hid-tmff2 files so TS-PC id uses TSXW code (check my repo at https://github.com/Potajito/hid-tmff2 for something straight forward)
  • Build and install dkms module as per instructions
  • Modified tmdrv adding TS-PC to initialize the wheel (You just need to run the script once, afaik), check my fork for the modified script: https://gitlab.com/potajito/tmdrv
    And that's it!
  • If you want your wheel to show up on oversteer, you need to add compatibility for it, check https://github.com/Potajito/oversteer
    For me, FFB works great (same as in windows I'd say) and all buttons work (I don't have any special attachments, also can't check pedals as I use a separate usb device for that).
    Thank you all for this! Hopefully this can get into the main branch so people don't have to tinker that much!

@BDave95
Copy link

BDave95 commented Aug 4, 2024

Good that you made it working too.
I investigated more about my buttons mapping problem and in fact it was obvious : this driver initialize the wheel in standard mode not in advanced mode like i use in Windows, checking in Windows the 2 modes have different PID :

  • standard mode PID_B689
  • advanced mode PID_B696
    The first is some sort of compatibility mode for PC/PS with "only" 17 functions available , the latter is PC only with full 26 functions for wheels like the F488 challenge i own.

I tried to capture packets from connecting the wheel to it's final initialization with Wireshark to figure how to initialize the wheel in advanced mod but to be honest i don't really understand anything in all this
Just figured the wheel change it's device address between it's initial start and it's final initialization, following what's published before also figure base + attachment ID are the same than those of Solarisfire, and find correct buttons mapping description but nothing about what to send to the wheel to initialize it in advanced mode, if someone more competent than me can have a look
tspc-init.zip

@BDave95
Copy link

BDave95 commented Aug 5, 2024

Here are my diffs for all files i modified

 --- org/hid-tmff2/Kbuild
+++ hid-tmff2/Kbuild
@@ -1,2 +1,2 @@
 obj-m := hid-tmff-new.o
-hid-tmff-new-y := src/hid-tmff2.o src/tmt300rs/hid-tmt300rs.o src/tmt248/hid-tmt248.o src/tmtx/hid-tmtx.o src/tmtsxw/hid-tmtsxw.o
+hid-tmff-new-y := src/hid-tmff2.o src/tmt300rs/hid-tmt300rs.o src/tmt248/hid-tmt248.o src/tmtx/hid-tmtx.o src/tmtsxw/hid-tmtsxw.o src/tmtspc/hid-tmtspc.o

--- org/hid-tmff2/deps/hid-tminit/hid-tminit.c
+++ hid-tmff2/deps/hid-tminit/hid-tminit.c
@@ -70,11 +70,12 @@
 	{0x02, 0x04, 0x0005, "Thrustmaster T300 Ferrari Alcantara Edition"},
 	{0x02, 0x06, 0x0005, "Thrustmaster T300RS"},
 	{0x02, 0x09, 0x0005, "Thrustmaster T300RS (Open Wheel Attachment)"},
-	{0x03, 0x06, 0x0006, "Thrustmaster T150RS"}
+	{0x03, 0x06, 0x0006, "Thrustmaster T150RS"},
+	{0x06, 0x09, 0x0009, "Thrustmaster TS-PC"},
 	//{0x04, 0x07, 0x0001, "Thrustmaster TMX"}
 };
 
-static const uint8_t tm_wheels_infos_length = 7;
+static const uint8_t tm_wheels_infos_length = 8;
 
 /*
  * This structs contains (in little endian) the response data

--- org/hid-tmff2/src/hid-tmff2.c
+++ hid-tmff2/src/hid-tmff2.c
@@ -678,6 +678,10 @@
 			if ((ret = tsxw_populate_api(tmff2)))
 				goto wheel_err;
 			break;
+			case TMTS_PC_RACER_ID:
+			if ((ret = tspc_populate_api(tmff2)))
+				goto wheel_err;
+			break;
 		default:
 			ret = -ENODEV;
 			goto wheel_err;
@@ -772,6 +776,8 @@
 	{HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, TMT248_PC_ID)},
 	/* tx */
 	{HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, TX_ACTIVE)},
+	/* TS-PC RACER */
+	{HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, TMTS_PC_RACER_ID)},
 	/* tsxw */
 	{HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, TSXW_ACTIVE)},
--- org/hid-tmff2/src/hid-tmff2.h
+++ hid-tmff2/src/hid-tmff2.h
@@ -103,6 +103,7 @@
 int t248_populate_api(struct tmff2_device_entry *tmff2);
 int tx_populate_api(struct tmff2_device_entry *tmff2);
 int tsxw_populate_api(struct tmff2_device_entry *tmff2);
+int tspc_populate_api(struct tmff2_device_entry *tmff2);
 
 #define TMT300RS_PS3_NORM_ID	0xb66e
 #define TMT300RS_PS3_ADV_ID	0xb66f
@@ -113,6 +114,8 @@
 #define TX_ACTIVE               0xb669
 
 #define TSXW_ACTIVE		0xb692
+
+#define TMTS_PC_RACER_ID 	0xb689
 
 /* APIs to different wheel families */
 /* T248 and TX at least uses the T300RS api, not sure if there are other wheels

This one is just a draft and need will need further modifis

--- org/hid-tmff2/src/tmtsxw/hid-tmtsxw.c
+++ hid-tmff2/src/tmtspc/hid-tmtspc.c
@@ -3,8 +3,8 @@
 #include <linux/hid.h>
 #include "../hid-tmff2.h"
 
-#define TMTSXW_MAX_EFFECTS 16
-#define TMTSXW_BUFFER_LENGTH 63
+#define TMTSPC_MAX_EFFECTS 16
+#define TMTSPC_BUFFER_LENGTH 63
 
 static const u8 setup_0[64] = { 0x42, 0x01 };
 static const u8 setup_1[64] = { 0x0a, 0x04, 0x90, 0x03 };
@@ -24,7 +24,7 @@
 	ARRAY_SIZE(setup_6)
 };
 
-static const unsigned long tsxw_params =
+static const unsigned long tspc_params =
 	PARAM_SPRING_LEVEL
 	| PARAM_DAMPER_LEVEL
 	| PARAM_FRICTION_LEVEL
@@ -32,7 +32,7 @@
 	| PARAM_GAIN
 	;
 
-static const signed short tsxw_effects[] = {
+static const signed short tspc_effects[] = {
 	FF_CONSTANT,
 	FF_RAMP,
 	FF_SPRING,
@@ -51,7 +51,7 @@
 };
 
 /* TODO: sort through this stuff */
-static u8 tsxw_pc_rdesc_fixed[] = {
+static u8 tspc_pc_rdesc_fixed[] = {
 	0x05, 0x01, /* Usage page (Generic Desktop) */
 	0x09, 0x04, /* Usage (Joystick) */
 	0xa1, 0x01, /* Collection (Application) */
@@ -116,15 +116,15 @@
 	0xc0, /* End collection */
 };
 
-static int tsxw_interrupts(struct t300rs_device_entry *tsxw)
+static int tspc_interrupts(struct t300rs_device_entry *tspc)
 {
 	u8 *send_buf = kmalloc(256, GFP_KERNEL);
-	struct usb_interface *usbif = to_usb_interface(tsxw->hdev->dev.parent);
+	struct usb_interface *usbif = to_usb_interface(tspc->hdev->dev.parent);
 	struct usb_host_endpoint *ep;
 	int ret, trans, b_ep, i;
 
 	if (!send_buf) {
-		hid_err(tsxw->hdev, "failed allocating send buffer\n");
+		hid_err(tspc->hdev, "failed allocating send buffer\n");
 		return -ENOMEM;
 	}
 
@@ -134,14 +134,14 @@
 	for (i = 0; i < ARRAY_SIZE(setup_arr); ++i) {
 		memcpy(send_buf, setup_arr[i], setup_arr_sizes[i]);
 
-		ret = usb_interrupt_msg(tsxw->usbdev,
-				usb_sndintpipe(tsxw->usbdev, b_ep),
+		ret = usb_interrupt_msg(tspc->usbdev,
+				usb_sndintpipe(tspc->usbdev, b_ep),
 				send_buf, setup_arr_sizes[i],
 				&trans,
 				USB_CTRL_SET_TIMEOUT);
 
 		if (ret) {
-			hid_err(tsxw->hdev, "setup data couldn't be sent\n");
+			hid_err(tspc->hdev, "setup data couldn't be sent\n");
 			goto err;
 		}
 	}
@@ -151,7 +151,7 @@
 	return ret;
 }
 
-int tsxw_wheel_destroy(void *data)
+int tspc_wheel_destroy(void *data)
 {
 	struct t300rs_device_entry *t300rs = data;
 
@@ -163,144 +163,144 @@
 	return 0;
 }
 
-int tsxw_set_range(void *data, uint16_t value)
-{
-	struct t300rs_device_entry *tsxw = data;
+int tspc_set_range(void *data, uint16_t value)
+{
+	struct t300rs_device_entry *tspc = data;
 
 	if (value < 140) {
-		hid_info(tsxw->hdev, "value %i too small, clamping to 140\n", value);
+		hid_info(tspc->hdev, "value %i too small, clamping to 140\n", value);
 		value = 140;
 	}
 
 	if (value > 1080) {
-		hid_info(tsxw->hdev, "value %i too large, clamping to 1080\n", value);
+		hid_info(tspc->hdev, "value %i too large, clamping to 1080\n", value);
 		value = 1080;
 	}
 
 	return t300rs_set_range(data, value);
 }
 
-static int tsxw_send_open(struct t300rs_device_entry *tsxw)
+static int tspc_send_open(struct t300rs_device_entry *tspc)
 {
 	int r1, r2;
-	tsxw->send_buffer[0] = 0x01;
-	tsxw->send_buffer[1] = 0x04;
-	if ((r1 = t300rs_send_int(tsxw)))
+	tspc->send_buffer[0] = 0x01;
+	tspc->send_buffer[1] = 0x04;
+	if ((r1 = t300rs_send_int(tspc)))
 		return r1;
 
-	tsxw->send_buffer[0] = 0x01;
-	tsxw->send_buffer[1] = 0x05;
-	if ((r2 = t300rs_send_int(tsxw)))
+	tspc->send_buffer[0] = 0x01;
+	tspc->send_buffer[1] = 0x05;
+	if ((r2 = t300rs_send_int(tspc)))
 		return r2;
 
 	return 0;
 }
 
-static int tsxw_open(void *data, int open_mode)
-{
-	struct t300rs_device_entry *tsxw = data;
-
-	if (!tsxw)
+static int tspc_open(void *data, int open_mode)
+{
+	struct t300rs_device_entry *tspc = data;
+
+	if (!tspc)
 		return -ENODEV;
 
 	if (open_mode)
-		tsxw_send_open(tsxw);
-
-	return tsxw->open(tsxw->input_dev);
-}
-
-static int tsxw_send_close(struct t300rs_device_entry *tsxw)
+		tspc_send_open(tspc);
+
+	return tspc->open(tspc->input_dev);
+}
+
+static int tspc_send_close(struct t300rs_device_entry *tspc)
 {
 	int r1, r2;
-	tsxw->send_buffer[0] = 0x01;
-	tsxw->send_buffer[1] = 0x05;
-	if ((r1 = t300rs_send_int(tsxw)))
+	tspc->send_buffer[0] = 0x01;
+	tspc->send_buffer[1] = 0x05;
+	if ((r1 = t300rs_send_int(tspc)))
 		return r1;
 
-	tsxw->send_buffer[0] = 0x01;
-	tsxw->send_buffer[1] = 0x00;
-	if ((r2 = t300rs_send_int(tsxw)))
+	tspc->send_buffer[0] = 0x01;
+	tspc->send_buffer[1] = 0x00;
+	if ((r2 = t300rs_send_int(tspc)))
 		return r2;
 
 	return 0;
 }
 
-static int tsxw_close(void *data, int open_mode)
-{
-	struct t300rs_device_entry *tsxw = data;
-
-	if (!tsxw)
+static int tspc_close(void *data, int open_mode)
+{
+	struct t300rs_device_entry *tspc = data;
+
+	if (!tspc)
 		return -ENODEV;
 
 	if (open_mode)
-		tsxw_send_close(tsxw);
-
-	tsxw->close(tsxw->input_dev);
-	return 0;
-}
-
-int tsxw_wheel_init(struct tmff2_device_entry *tmff2, int open_mode)
-{
-	struct t300rs_device_entry *tsxw = kzalloc(sizeof(struct t300rs_device_entry), GFP_KERNEL);
+		tspc_send_close(tspc);
+
+	tspc->close(tspc->input_dev);
+	return 0;
+}
+
+int tspc_wheel_init(struct tmff2_device_entry *tmff2, int open_mode)
+{
+	struct t300rs_device_entry *tspc = kzalloc(sizeof(struct t300rs_device_entry), GFP_KERNEL);
 	struct list_head *report_list;
 	int ret;
 
 
-	if (!tsxw) {
+	if (!tspc) {
 		ret = -ENOMEM;
-		goto tsxw_err;
-	}
-
-	tsxw->hdev = tmff2->hdev;
-	tsxw->input_dev = tmff2->input_dev;
-	tsxw->usbdev = to_usb_device(tmff2->hdev->dev.parent->parent);
-	tsxw->buffer_length = TMTSXW_BUFFER_LENGTH;
-
-	tsxw->send_buffer = kzalloc(tsxw->buffer_length, GFP_KERNEL);
-	if (!tsxw->send_buffer) {
+		goto tspc_err;
+	}
+
+	tspc->hdev = tmff2->hdev;
+	tspc->input_dev = tmff2->input_dev;
+	tspc->usbdev = to_usb_device(tmff2->hdev->dev.parent->parent);
+	tspc->buffer_length = TMTSPC_BUFFER_LENGTH;
+
+	tspc->send_buffer = kzalloc(tspc->buffer_length, GFP_KERNEL);
+	if (!tspc->send_buffer) {
 		ret = -ENOMEM;
 		goto send_err;
 	}
 
-	report_list = &tsxw->hdev->report_enum[HID_OUTPUT_REPORT].report_list;
-	tsxw->report = list_entry(report_list->next, struct hid_report, list);
-	tsxw->ff_field = tsxw->report->field[0];
-
-	tsxw->open = tsxw->input_dev->open;
-	tsxw->close = tsxw->input_dev->close;
-
-	if ((ret = tsxw_interrupts(tsxw)))
+	report_list = &tspc->hdev->report_enum[HID_OUTPUT_REPORT].report_list;
+	tspc->report = list_entry(report_list->next, struct hid_report, list);
+	tspc->ff_field = tspc->report->field[0];
+
+	tspc->open = tspc->input_dev->open;
+	tspc->close = tspc->input_dev->close;
+
+	if ((ret = tspc_interrupts(tspc)))
 		goto interrupt_err;
 
 	/* everything went OK */
-	tmff2->data = tsxw;
-	tmff2->params = tsxw_params;
-	tmff2->max_effects = TMTSXW_MAX_EFFECTS;
-	memcpy(tmff2->supported_effects, tsxw_effects, sizeof(tsxw_effects));
+	tmff2->data = tspc;
+	tmff2->params = tspc_params;
+	tmff2->max_effects = TMTSPC_MAX_EFFECTS;
+	memcpy(tmff2->supported_effects, tspc_effects, sizeof(tspc_effects));
 
 	if (!open_mode)
-		tsxw_send_open(tsxw);
-
-	hid_info(tsxw->hdev, "force feedback for TS-XW\n");
+		tspc_send_open(tspc);
+
+	hid_info(tspc->hdev, "force feedback for TS-PC\n");
 	return 0;
 
 interrupt_err:
 send_err:
-	kfree(tsxw);
-tsxw_err:
-	hid_err(tmff2->hdev, "failed initializing TS-XW\n");
+	kfree(tspc);
+tspc_err:
+	hid_err(tmff2->hdev, "failed initializing TS-PC\n");
 	return ret;
 }
 
-static __u8 *tsxw_wheel_fixup(struct hid_device *hdev, __u8 *rdesc,
+static __u8 *tspc_wheel_fixup(struct hid_device *hdev, __u8 *rdesc,
 		unsigned int *rsize)
 {
-	rdesc = tsxw_pc_rdesc_fixed;
-	*rsize = sizeof(tsxw_pc_rdesc_fixed);
+	rdesc = tspc_pc_rdesc_fixed;
+	*rsize = sizeof(tspc_pc_rdesc_fixed);
 	return rdesc;
 }
 
-int tsxw_populate_api(struct tmff2_device_entry *tmff2)
+int tspc_populate_api(struct tmff2_device_entry *tmff2)
 {
 	tmff2->play_effect = t300rs_play_effect;
 	tmff2->upload_effect = t300rs_upload_effect;
@@ -309,15 +309,15 @@
 
 	tmff2->set_gain = t300rs_set_gain;
 	tmff2->set_autocenter = t300rs_set_autocenter;
-	/* TS-XW has 1080 degree range, just like T300RS 1080 */
-	tmff2->set_range = tsxw_set_range;
-	tmff2->wheel_fixup = tsxw_wheel_fixup;
-
-	tmff2->open = tsxw_open;
-	tmff2->close = tsxw_close;
-
-	tmff2->wheel_init = tsxw_wheel_init;
-	tmff2->wheel_destroy = tsxw_wheel_destroy;
-
-	return 0;
-}
+	/* TS-PC has 900 degree range, like T300RS 1080 */
+	tmff2->set_range = tspc_set_range;
+	tmff2->wheel_fixup = tspc_wheel_fixup;
+
+	tmff2->open = tspc_open;
+	tmff2->close = tspc_close;
+
+	tmff2->wheel_init = tspc_wheel_init;
+	tmff2->wheel_destroy = tspc_wheel_destroy;
+
+	return 0;
+}


@Kimplul
Copy link
Owner

Kimplul commented Aug 7, 2024

@n1njak3bab Nothing's been merged into the repository yet, I'm planning on taking a look at this over the weekend. Please do feel free to try and get things running on your end, always good to have more eyes.

@WithHammerandI
Copy link

I am so glad to see this wheel being worked on. It's the last thing I have been waiting for in order to make the transition to Linux full time.

Is it working well yet ?

Also fantastic work guys. Reading through the thread makes me realise I really should of taken up the offer to study Computers and do the Systems Analyst Course when I was offered 40 years ago.
I decided to go work for my Dad, as a Furniture Polisher. That did not work out so well. Sigh :(

@Kimplul
Copy link
Owner

Kimplul commented Sep 29, 2024

Hello again, I must admit I kind of forgot about this for a while, just got a bit buried under other things on my TODO list. I gave the provided patches a quick lookover, seems mostly fine but I did notice that in one comment the wheel's range is indicated to be 900 degrees, but the range() function allowed up to 1080. I switched 1080 to be 900 and pushed the changes to a separate tspc branch.

I also had a look at the provided USB captures, and I spotted packet number 123, seems very similar to packets that are used by the T300RS to switch modes so I added initial mode switching functionality for testing. Don't have a wheel myself so no real idea if this works or not, and I would appreciate it if somebody could check out the branch and let me know. Please be careful, preferably run this driver in a virtual machine or something as a kernel crash could (theoretically) corrupt hard drives etc. I'm not expecting anything to happen, but best to be safe.

Mode switching happens by writing something to the alternate_modes file, you should be able to find it by something like cd /sys ; find . -iname alternate_modes as root. The exact path might vary. Currently there's only switching from normal mode to advanced mode IF it works at all.

EDIT: Just as an example, echo 1 > /sys/WHATEVER/PATH/FIND/RETURNS/alternate_modes should trigger a mode switch.

@WithHammerandI
Copy link

Well that was quick.
He says replying after 3 mins. lol

Not my field but I am always willing to try, so will make a VM and have a go later.

Fingers crossed. (someone will beat me to it) Ha ha

Thanks very much for all you are doing.

@Potajito
Copy link

Hello again, I must admit I kind of forgot about this for a while, just got a bit buried under other things on my TODO list. I gave the provided patches a quick lookover, seems mostly fine but I did notice that in one comment the wheel's range is indicated to be 900 degrees, but the range() function allowed up to 1080. I switched 1080 to be 900 and pushed the changes to a separate tspc branch.

I also had a look at the provided USB captures, and I spotted packet number 123, seems very similar to packets that are used by the T300RS to switch modes so I added initial mode switching functionality for testing. Don't have a wheel myself so no real idea if this works or not, and I would appreciate it if somebody could check out the branch and let me know. Please be careful, preferably run this driver in a virtual machine or something as a kernel crash could (theoretically) corrupt hard drives etc. I'm not expecting anything to happen, but best to be safe.

Mode switching happens by writing something to the alternate_modes file, you should be able to find it by something like cd /sys ; find . -iname alternate_modes as root. The exact path might vary. Currently there's only switching from normal mode to advanced mode IF it works at all.

EDIT: Just as an example, echo 1 > /sys/WHATEVER/PATH/FIND/RETURNS/alternate_modes should trigger a mode switch.

Nice, probably it was me as I misremembered the max angle.
About the mode switch, I guess it's the attachment thing that @BDave95 mentioned? I don't remember seeing anything about that in the win driver or in the manual 🤔.
Anyway, I'm going to try the new branch and report. Personally I'll just try it as usual, not in an VM, if something breaks, it was time for a reinstall.
Btw, the tmdrv part to init the wheel should still be needed, right? I'd love to get rid of it, specially for new users it's a bit of an extra hassle that it's not very user-friendly.
Thanks again, on to testing!

@Kimplul
Copy link
Owner

Kimplul commented Sep 30, 2024

About the mode switch, I guess it's the attachment thing that @BDave95 mentioned? I don't remember seeing anything about that in the win driver or in the manual 🤔.

Yep, in tspc-init.zip earlier in the thread.

Btw, the tmdrv part to init the wheel should still be needed, right? I'd love to get rid of it, specially for new users it's a bit of an extra hassle that it's not very user-friendly.

The attached patches include code in hid-tminit, which I interpreted to mean that tmdrv shouldn't be needed anymore. But please do correct me if I'm wrong.

@BDave95
Copy link

BDave95 commented Oct 6, 2024

Cool to see it's still moving out there, had no time lastly to follow but i'll try to find some to test last advances, especially mode switching.
Thanks to everyone involved.

Nice, probably it was me as I misremembered the max angle. About the mode switch, I guess it's the attachment thing that @BDave95 mentioned? I don't remember seeing anything about that in the win driver or in the manual 🤔. Anyway, I'm going to try the new branch and report. Personally I'll just try it as usual, not in an VM, if something breaks, it was time for a reinstall. Btw, the tmdrv part to init the wheel should still be needed, right? I'd love to get rid of it, specially for new users it's a bit of an extra hassle that it's not very user-friendly. Thanks again, on to testing!

For the mode switch if i understood correctly what it written on Thrustmaster's site it's presence depend on wheel installed,
On my Pc it shows like this
thr-pan

As you can see the option appear on the lower end of the windows.
It might no show with "basic" wheels cause it would be useless as they haven't much buttons but with more advanced wheel like my F488 Challenge or the Ferrari F1 Wheel it makes sense to run only in advanced mode to take advantage of all the added buttons and dials.

Speaking of buttons and dials attributions Thrustmaster give the mapping on it's website for most common wheels, if one need to correct mapping/attribution for a particular wheel it might be a useful help
https://support.thrustmaster.com/en/product/tspcracer-en/

@BDave95
Copy link

BDave95 commented Oct 7, 2024

Took time to quick test TS-PC branch last evening.
As i had no time to test ingame i only tested the wheel with oversteer

Firstly good news my system haven't been screwed ;-)
Mode switch works, even if it's not particularly user friendly. should not be too difficult to write a script to simplify the thing and maybe it would be possible to save and restore last state like the Windows driver does

To be noted during the wheel startup "dmesg" shows a message

URB to change wheel mode seems to have failed, error code -2

and the wheel starts in standard mode

On standard mode "dmesg" TS-PC as product name, with B689 ID, but shows TS-XW for force feedback, maybe just a typo somewhere.
Oversteer shows correct buttons attribution and 1080° range but accel/brakes pedals shows as combined pedal on accel axis and clutch move the brake axis, surely just mapping problem as it was ok with the version i had before
FFB seems to respond well to Oversteer tests

Once switched to advanced mode the ID logically change to B696 so works well but this time "dmesg" shows T248 for force feedback line

In Oversteer the range shows 900 instead of 1080, all buttons and dials works perfectly, with correct assignation and more important independently and that's exactly what i was looking for
This time pedals axis works correctly with correct assignation, confirming the mappng problem in standard mode.
FFB test seems to work, at least with Oversteer tests.

Maybe i will have time this evening to dig in the source and try to find remaining problems but this is promising, thanks Kimplul

@Kimplul
Copy link
Owner

Kimplul commented Oct 7, 2024

Mode switch works, even if it's not particularly user friendly. should not be too difficult to write a script to simplify the thing and maybe it would be possible to save and restore last state like the Windows driver does

Glad to hear my guess was correct. Mode switching is primarily intended to be used via Oversteer, there's a 'Compatibility mode' dropdown. At the moment the driver isn't advertising the advanced mode so I believe the dropdown should be empty. That should be added at some point, see t300rs_alt_mode_show for reference.

To be noted during the wheel startup "dmesg" shows a message [...]

That's 'normal', Thrustmaster wheels have a very agressive initialization that breaks the USB protocol, so the USB packet that causes the initialization can sometimes be returned with an error code. The returned error seems to sometimes vary a bit, see https://github.com/Kimplul/hid-tminit/blob/17d6cad0b508417193ebf4d23f67c845487e9932/tminit.c#L144.

[...] but shows TS-XW for force feedback, maybe just a typo somewhere.

That one's on me, your patches didn't apply cleanly so I went through and applied the chunks semi-manually, I must've missed that one. Pushed a commit fixing it, thanks for pointing it out.

Once switched to advanced mode the ID logically change to B696 so works well but this time "dmesg" shows T248 for force feedback line

0xb696 seems to be shared by a few different Thrustmaster wheels, just search for it in the issue tracker and you'll see a few different hits. The T248 was the first wheel that I added support for with that USB ID, and as a result this driver correlates that ID with a T248. A refactor might be useful in the future, as we should probably ask the wheel directly what base + rim it is and presumably apply some slightly different settings based on the response. On a rant-ish sidenote, I don't think reusing the same USB product ID for multiple different products is particularly 'polite' USB behaviour, not sure if its necessarily forbidden by the USB spec but it does makes separating devices from each other quite a bit more difficult.

@BDave95
Copy link

BDave95 commented Oct 7, 2024

Just tested the last commit ingame and it's working fine in advanced mode (not tested in standard mode but there's no reason it won't work fine also)
I could complete a quick mission in ETS2 without any issue (just forgot to add the new ID in my evdev rule to fix the deadzone issue but it was quick to fix)

The combined axles thing must be related to Oversteer as it's working fine ingame with all 3 pedals separated, maybe a bug in the custom build i use, have to check that also but it's not my main priority for now

In advanced mode it's still showing as 900° wheel, maybe the driver takes the value given for the T300RS alternate mode by default cause it can't find a specific section for the TSPC.
I need to check and try to understand what you have done for the T300RS and adapt that to the TSPC, same for the compatibility mode drop down in Oversteer which is greyed

As for the duplicate ID between many wheels and bases it's far beyond my skills so i'm afraid i won't be of any help with that.
Thustmaster proprietary drivers recognize flawlessly all bases and wheels so might be others control words hidden somewhere in the USB messages, it's a pity they don't give any support nor information about that

@adam820
Copy link

adam820 commented Nov 14, 2024

Hi, thanks for keeping this moving along. I tried to do some work on this earlier this year and ran into issues with the buttons at the time and it fell off my radar. I tested this latest commit in a series of games tonight and am delighted to say that all of the buttons and axes seemed to work fine. I was able to add the wheel to Oversteer @Potajito 's branch, and control the FFB and other settings. I only have the base rim and the 599XX Evo rim, which don't use the Advanced buttons, so I was not able to test beyond the standard 13 or so buttons.

Games tested: Assetto Corsa via Content Manager, Assetto Corsa Competizione, Le Mans Ultimate (game itself crashes on loading into a circuit, but the calibration and settings recognized the wheel fine), and Automobilista 2.

I can't recall from Windows, but I generally did have to re-map which axis was the throttle, brake, and clutch - but they remapped fine and I was off to the races, so to speak. Just wanted to give my testing feedback. Thanks for the work on this! 🐎

asseto_corsa
20241113212423_1

@WithHammerandI
Copy link

This is great news, thanks to ALL for getting this working.
Just need a new HD to set things up and make the switch now.

Thanks again guys.

If I have any problems I will come here to pick your brains

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants