diff options
| -rw-r--r-- | .clangd/index/hid-tm.h.7821369EC83FE7C8.idx | bin | 1326 -> 0 bytes | |||
| -rw-r--r-- | .clangd/index/hid-tmff2.c.9B4690F7E401243F.idx | bin | 10340 -> 0 bytes | |||
| -rw-r--r-- | .clangd/index/hid-tmt300rs.c.43A658324E8CEF81.idx | bin | 10460 -> 0 bytes | |||
| -rw-r--r-- | .clangd/index/hid-tmt300rs.h.3CC3B1B35D0BBA1F.idx | bin | 2640 -> 0 bytes | |||
| -rw-r--r-- | .clangd/index/usbhid.h.D54214605C1BF4CF.idx | bin | 3044 -> 0 bytes | |||
| -rw-r--r-- | .gitingore | 3 | ||||
| -rw-r--r-- | Init.pcapng | bin | 0 -> 6992 bytes | |||
| -rw-r--r-- | Module.symvers | 0 | ||||
| -rw-r--r-- | README.md | 18 | ||||
| -rw-r--r-- | README.md.orig | 56 | ||||
| -rw-r--r-- | force-effects.txt | 166 | ||||
| -rw-r--r-- | hid-tmt300rs.c | 564 | ||||
| -rw-r--r-- | hid-tmt300rs.h | 16 | ||||
| -rw-r--r-- | t150init.pcapng | bin | 0 -> 6772 bytes |
14 files changed, 693 insertions, 130 deletions
diff --git a/.clangd/index/hid-tm.h.7821369EC83FE7C8.idx b/.clangd/index/hid-tm.h.7821369EC83FE7C8.idx Binary files differdeleted file mode 100644 index 926efd2..0000000 --- a/.clangd/index/hid-tm.h.7821369EC83FE7C8.idx +++ /dev/null diff --git a/.clangd/index/hid-tmff2.c.9B4690F7E401243F.idx b/.clangd/index/hid-tmff2.c.9B4690F7E401243F.idx Binary files differdeleted file mode 100644 index 8585493..0000000 --- a/.clangd/index/hid-tmff2.c.9B4690F7E401243F.idx +++ /dev/null diff --git a/.clangd/index/hid-tmt300rs.c.43A658324E8CEF81.idx b/.clangd/index/hid-tmt300rs.c.43A658324E8CEF81.idx Binary files differdeleted file mode 100644 index 3de5e8d..0000000 --- a/.clangd/index/hid-tmt300rs.c.43A658324E8CEF81.idx +++ /dev/null diff --git a/.clangd/index/hid-tmt300rs.h.3CC3B1B35D0BBA1F.idx b/.clangd/index/hid-tmt300rs.h.3CC3B1B35D0BBA1F.idx Binary files differdeleted file mode 100644 index 5522235..0000000 --- a/.clangd/index/hid-tmt300rs.h.3CC3B1B35D0BBA1F.idx +++ /dev/null diff --git a/.clangd/index/usbhid.h.D54214605C1BF4CF.idx b/.clangd/index/usbhid.h.D54214605C1BF4CF.idx Binary files differdeleted file mode 100644 index 6a7514a..0000000 --- a/.clangd/index/usbhid.h.D54214605C1BF4CF.idx +++ /dev/null diff --git a/.gitingore b/.gitingore deleted file mode 100644 index 64bbd39..0000000 --- a/.gitingore +++ /dev/null @@ -1,3 +0,0 @@ -*.ko -*.o -*.mod* diff --git a/Init.pcapng b/Init.pcapng Binary files differnew file mode 100644 index 0000000..3a395ef --- /dev/null +++ b/Init.pcapng diff --git a/Module.symvers b/Module.symvers new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Module.symvers @@ -1,14 +1,10 @@ # Linux kernel module for the Thrustmaster T300RS wheel ## Current state -Playable. Dynamic updating of effects isn't baked into the wheel quite as -well as I'd hoped, and so the driver in its current state doesn't really -support it. At some point in the future I'd like to add it to the feature -list, but it will need a lot more research and might take a while. - -One other issue is that if you have the T3PA pedals, the clutch doesn't seem -to be registered by most(all?) games. It is registered and works as expected -in jstest and jstest-gtk, no clue what that is about. +Playable. I've made some improvements to the dynamic updating of effects, and +while still far for perfect, the experience is slowly getting better and better. +Some drawbacks include missing dynamic updating of ramp effects and in some +games inconsistent pedal mapping. Meaning that all pedals should be detected in games, but may be mapped incorrectly. Anycase, **this version is usable in most force feedback games, supports rangesetting as well as gain and autocentering along with most force feedback effects.** @@ -22,11 +18,11 @@ With that in mind, ## Installation + Unplug wheel from computer -+ `git clone this-repo` ++ `git clone https://github.com/Kimplul/hid-tmff2.git` + `make` + `sudo make install` + Plug wheel back in -+ reboot (not strictly necessary, but recommended) ++ reboot (not strictly necessary, but definitely recommended) Done! @@ -41,7 +37,7 @@ Write a value between 0 and 1080 to Use the default evdev ways, i.e. https://www.kernel.org/doc/html/v5.1/input/ff.html -+ Currently there is support for this driver in oversteer(https://github.com/berarma/oversteer), and ffbwrap(https://github.com/berarma/ffbtools) should work. ++ Currently there is support for this driver in oversteer(https://github.com/berarma/oversteer), and ffbwrap(https://github.com/berarma/ffbtools) should work just fine. + If the wheel has a deadzone in games, you can set up a udev rule: `/etc/udev/rules.d/99-joydev.rules` diff --git a/README.md.orig b/README.md.orig deleted file mode 100644 index f1353ef..0000000 --- a/README.md.orig +++ /dev/null @@ -1,56 +0,0 @@ -# Linux kernel module for the Thrustmaster T300RS wheel - -## Current state -Playable. Dynamic updating of effects isn't baked into the wheel quite as -well as I'd hoped, and so the driver in its current state doesn't really -support it. At some point in the future I'd like to add it to the feature -list, but it will need a lot more research and might take a while. - -One other issue is that if you have the T3PA pedals, the clutch doesn't seem -to be registered by most(all?) games. It is registered and works as expected -in jstest and jstest-gtk, no clue what that is about. - -Anycase, **this version is usable in most force feedback games, supports -rangesetting as well as gain and autocentering along with most force feedback effects.** -## Small note - -While I haven't personally come across any crashes or lockups with this -version, I can't promise that they won't occur under any circumstances. - -With that in mind, - -## Installation - -+ Unplug wheel from computer -+ `git clone this-repo` -+ `make` -+ `sudo make install` -+ Plug wheel back in -+ reboot (not strictly necessary, but recommended) - -Done! - -## Additional tidbits - -+ Change range: - -Write a value between 0 and 65535 to -/sys/bus/devices/XXXX:044F:B66E.XXX/range - -+ Change autocenter and gain: - -Use the default evdev ways, i.e. https://www.kernel.org/doc/html/v5.1/input/ff.html - -<<<<<<< HEAD - + Currently there is no support for this driver in oversteer(https://github.com/berarma/oversteer), but ffbwrap(https://github.com/berarma/ffbtools) should work. - + If the wheel has a deadzone in games, you can set up a udev rule: - `/etc/udev/rules.d/99-joydev.rules`: - `SUBSYSTEM=="input", ATTRS{idVendor}=="044f", ATTRS{idProduct}=="b66e" - - RUN+="/usr/bin/evdev-joystick --evdev %E{DEVNAME} --deadzone 0"` - This should make sure that the wheel behaves like you'd want from a - wheel. -======= -+ Currently there is no support for this driver in oversteer(https://github.com/berarma/oversteer). -I opened a pull request to add support(to some degree) for this driver to ffbtools(https://github.com/berarma/ffbtools), but until it gets merged I have a repo here: https://github.com/Kimplul/ffbtools ->>>>>>> 8dcb9edbc14b9709e6b0d8b567211e4252191b1e diff --git a/force-effects.txt b/force-effects.txt index 6c205f7..bd5b8d1 100644 --- a/force-effects.txt +++ b/force-effects.txt @@ -53,15 +53,14 @@ FF_CONSTANT: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - Modifying: (It may be possible to modify the effects all at once, not sure) - (In any case, so far I only investigated the constant modifiers) + Modifying: (For dynamic updating of effects) Direction: n/a Constant force: 60 00 - standard header 01 - ID 0a - modify constant force - 05 16 - constant force + 05 16 - constant force *** 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 @@ -75,7 +74,7 @@ FF_CONSTANT: attack_length 81, fade_level 88, fade_length 84 ) - 63 04 - value attribute should be set to + 63 04 - value attribute should be set to ?***? 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 @@ -91,6 +90,9 @@ FF_CONSTANT: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + Offset: + Not supported? + FF_RAMP: (Why on earth is it this difficult to figure out how a fucking ramp works?) @@ -117,6 +119,40 @@ FF_RAMP: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + Modifying: + Sweet baby jesus + I'll figure this out later + + Envelope: + 60 00 - standard header + 01 - ID + 31 - modify envelope + 84 - ID of envelope attribute ( attack_level 82, + attack_length 81, + fade_level 88, + fade_length 84 ) + 63 04 - value attribute should be set to + 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + + Duration: + + 60 00 + 01 - ID + 4e 08 - ? + 01 00 - time in milliseconds + 05 41 - ? + 01 00 - time in milliseconds + 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + + Offset: + Not supported? + FF_SPRING: Init: 60 00 - standard header @@ -137,6 +173,9 @@ FF_SPRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + Modifying: + Same as under + FF_DAMPER + FF_FRICTION + FF_INERTIA: Init: 60 00 - standard header @@ -155,6 +194,51 @@ FF_DAMPER + FF_FRICTION + FF_INERTIA: 00 ff ff - end of init 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + + Modifying: + positive coefficient: + 60 00 + 02 - ID + 0e 41 + 64 35 - value, signed (between 00 00 and 01 80?) + 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + + negative coefficient: + 60 00 + 02 - ID + 0e 42 + 64 35 - value, signed (between 00 00 and ff 7f?) + 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + + deadband/offset: + 60 00 + 02 - ID + 0e 4c + 64 35 - deadband (right?) (deadband + offset) (fe ff means no deadband) + 00 00 - deadband (left?) (deadband + offset) + 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + + Duration: + 60 00 - standard header + 01 - ID + 49 06 41 - modify timing? + 6c 20 - length in milliseconds + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + + Offset: + Not supported? FF_PERIODIC: 60 00 - standard header @@ -182,6 +266,80 @@ FF_PERIODIC: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + Modifying: + magnitude: + 60 00 + 02 - ID + 0e 01 + 64 35 - value, signed (between 00 00 and ff 7f?) + 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + + offset of effect: + 60 00 + 02 - ID + 0e 04 + 64 35 - value, signed (between 00 00 and ff 7f?) + 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + + phase: + 60 00 + 02 - ID + 0e 02 + 64 35 - value, signed (between 80 01 and ff 7f?) + 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + + period: + 60 00 + 02 - ID + 0e 08 + 64 35 - value, signed (between 00 00 and I guess ff 7f?) (max value in + wireshark is 0d 07, but I don't know if that's a driver or program issue) + 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + + + Envelope: + 60 00 - standard header + 01 - ID + 31 - modify envelope + 84 - ID of envelope attribute ( attack_level 82, + attack_length 81, + fade_level 88, + fade_length 84 ) + 63 04 - value attribute should be set to + 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + + Duration: + + 60 00 + 01 - ID + 4e 08 - ? + 01 00 - time in milliseconds + 05 41 - ? + 01 00 - time in milliseconds + 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + + Offset: + Not supported? + + FF_AUTOCENTER: 60 08 - header plus settings? 03 - set autocenter force diff --git a/hid-tmt300rs.c b/hid-tmt300rs.c index 8287042..a8c4c0f 100644 --- a/hid-tmt300rs.c +++ b/hid-tmt300rs.c @@ -36,7 +36,7 @@ static int t300rs_send_int(struct input_dev *dev, u8 *send_buffer, int *trans){ struct usb_interface *usbif; struct usb_host_endpoint *ep; struct urb *urb = usb_alloc_urb(0, GFP_ATOMIC); - + t300rs = t300rs_get_device(hdev); if(!t300rs){ hid_err(hdev, "could not get device\n"); @@ -96,26 +96,475 @@ static int t300rs_stop_effect(struct t300rs_device_entry *t300rs, struct t300rs_ } static void t300rs_fill_envelope(u8 *send_buffer, int i, s16 level, u16 duration, struct ff_envelope *envelope){ + u16 le_attack_level, le_attack_length, le_fade_level, le_fade_length; u16 attack_length = (duration * envelope->attack_length) / 0x7fff; u16 attack_level = (level * envelope->attack_level) / 0x7fff; u16 fade_length = (duration * envelope->fade_length) / 0x7fff; u16 fade_level = (level * envelope->fade_level) / 0x7fff; - attack_length = cpu_to_le16(attack_length); - attack_level = cpu_to_le16(attack_level); - fade_length = cpu_to_le16(fade_length); - fade_level = cpu_to_le16(fade_level); + le_attack_length = cpu_to_le16(attack_length); + le_attack_level = cpu_to_le16(attack_level); + le_fade_length = cpu_to_le16(fade_length); + le_fade_level = cpu_to_le16(fade_level); + + send_buffer[i ] = le_attack_length & 0xff; + send_buffer[i + 1] = le_attack_length >> 8; + send_buffer[i + 2] = le_attack_level & 0xff; + send_buffer[i + 3] = le_attack_level >> 8; + send_buffer[i + 4] = le_fade_length & 0xff; + send_buffer[i + 5] = le_fade_length >> 8; + send_buffer[i + 6] = le_fade_level & 0xff; + send_buffer[i + 7] = le_fade_level >> 8; +} + +static int t300rs_modify_periodic_envelope(struct t300rs_device_entry *t300rs, struct t300rs_effect_state *state, u8 *send_buffer){ + struct ff_effect effect = state->effect; + struct ff_effect old = state->old; + struct ff_periodic_effect periodic = effect.u.periodic; + struct ff_periodic_effect periodic_old = old.u.periodic; + struct ff_envelope envelope = periodic.envelope; + struct ff_envelope envelope_old = periodic_old.envelope; + u16 duration, attack_length, attack_level, fade_length, fade_level; + u16 le_attack_length, le_attack_level, le_fade_length, le_fade_level; + s16 level; + int ret = 0, trans; + + level = (periodic.magnitude * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; + + if(effect.replay.length == 0){ + duration = 0xffff; + } else { + duration = effect.replay.length; + } + + attack_length = (duration * envelope.attack_length) / 0x7fff; + attack_level = (level * envelope.attack_level) / 0x7fff; + fade_length = (duration * envelope.fade_length) / 0x7fff; + fade_level = (level * envelope.fade_level) / 0x7fff; + + le_attack_length = cpu_to_le16(attack_length); + le_attack_level = cpu_to_le16(attack_level); + le_fade_length = cpu_to_le16(fade_length); + le_fade_level = cpu_to_le16(fade_level); + + send_buffer[0] = 0x60; + send_buffer[2] = effect.id + 1; + send_buffer[3] = 0x31; + + if(envelope.attack_length != envelope_old.attack_length){ + send_buffer[4] = 0x81; + + send_buffer[5] = le_attack_length & 0xff; + send_buffer[6] = le_attack_length >> 8; + + ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans); + if(ret){ + hid_err(t300rs->hdev, "failed modifying constant effect\n"); + goto error; + } + } + + if(envelope.attack_level != envelope_old.attack_level){ + send_buffer[4] = 0x82; + + send_buffer[5] = le_attack_level & 0xff; + send_buffer[6] = le_attack_level >> 8; + + ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans); + if(ret){ + hid_err(t300rs->hdev, "failed modifying constant effect\n"); + goto error; + } + } + + if(envelope.fade_length != envelope_old.fade_length){ + send_buffer[4] = 0x84; + + send_buffer[5] = le_fade_length & 0xff; + send_buffer[6] = le_fade_length >> 8; + + ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans); + if(ret){ + hid_err(t300rs->hdev, "failed modifying constant effect\n"); + goto error; + } + } + + if(envelope.fade_level != envelope_old.fade_level){ + send_buffer[4] = 0x88; + + send_buffer[5] = le_fade_level & 0xff; + send_buffer[6] = le_fade_level >> 8; + + ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans); + if(ret){ + hid_err(t300rs->hdev, "failed modifying constant effect\n"); + goto error; + } + } + +error: + memset(send_buffer, 0, T300RS_BUFFER_LENGTH); + return ret; +} +static int t300rs_modify_constant_envelope(struct t300rs_device_entry *t300rs, struct t300rs_effect_state *state, u8 *send_buffer){ + struct ff_effect effect = state->effect; + struct ff_effect old = state->old; + struct ff_constant_effect constant = effect.u.constant; + struct ff_constant_effect constant_old = old.u.constant; + struct ff_envelope envelope = constant.envelope; + struct ff_envelope envelope_old = constant_old.envelope; + u16 duration, attack_length, attack_level, fade_length, fade_level; + u16 le_attack_length, le_attack_level, le_fade_length, le_fade_level; + s16 level; + int ret = 0, trans; + + level = (constant.level * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; + + if(effect.replay.length == 0){ + duration = 0xffff; + } else { + duration = effect.replay.length; + } + + attack_length = (duration * envelope.attack_length) / 0x7fff; + attack_level = (level * envelope.attack_level) / 0x7fff; + fade_length = (duration * envelope.fade_length) / 0x7fff; + fade_level = (level * envelope.fade_level) / 0x7fff; + + le_attack_length = cpu_to_le16(attack_length); + le_attack_level = cpu_to_le16(attack_level); + le_fade_length = cpu_to_le16(fade_length); + le_fade_level = cpu_to_le16(fade_level); + + send_buffer[0] = 0x60; + send_buffer[2] = effect.id + 1; + send_buffer[3] = 0x31; + + if(envelope.attack_length != envelope_old.attack_length){ + send_buffer[4] = 0x81; + + send_buffer[5] = le_attack_length & 0xff; + send_buffer[6] = le_attack_length >> 8; + + ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans); + if(ret){ + hid_err(t300rs->hdev, "failed modifying constant effect\n"); + goto error; + } + } + + if(envelope.attack_level != envelope_old.attack_level){ + send_buffer[4] = 0x82; + + send_buffer[5] = le_attack_level & 0xff; + send_buffer[6] = le_attack_level >> 8; + + ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans); + if(ret){ + hid_err(t300rs->hdev, "failed modifying constant effect\n"); + goto error; + } + } + + if(envelope.fade_length != envelope_old.fade_length){ + send_buffer[4] = 0x84; - send_buffer[i ] = attack_length & 0xff; - send_buffer[i + 1] = attack_length >> 8; - send_buffer[i + 2] = attack_level & 0xff; - send_buffer[i + 3] = attack_level >> 8; - send_buffer[i + 4] = fade_length & 0xff; - send_buffer[i + 5] = fade_length >> 8; - send_buffer[i + 6] = fade_level & 0xff; - send_buffer[i + 7] = fade_level >> 8; + send_buffer[5] = le_fade_length & 0xff; + send_buffer[6] = le_fade_length >> 8; + + ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans); + if(ret){ + hid_err(t300rs->hdev, "failed modifying constant effect\n"); + goto error; + } + } + + if(envelope.fade_level != envelope_old.fade_level){ + send_buffer[4] = 0x88; + + send_buffer[5] = le_fade_level & 0xff; + send_buffer[6] = le_fade_level >> 8; + + ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans); + if(ret){ + hid_err(t300rs->hdev, "failed modifying constant effect\n"); + goto error; + } + } + +error: + memset(send_buffer, 0, T300RS_BUFFER_LENGTH); + return ret; } +static int t300rs_modify_duration(struct t300rs_device_entry *t300rs, struct t300rs_effect_state *state, u8 *send_buffer){ + struct ff_effect effect = state->effect; + struct ff_effect old = state->old; + u16 duration, le_duration; + int ret = 0, trans; + + if(effect.replay.length == 0){ + duration = 0xffff; + } else { + duration = effect.replay.length; + } + + le_duration = cpu_to_le16(duration); + + if(effect.replay.length != old.replay.length){ + send_buffer[0] = 0x60; + send_buffer[2] = effect.id + 1; + send_buffer[3] = 0x49; + send_buffer[5] = 0x41; + + send_buffer[6] = le_duration & 0xff; + send_buffer[7] = le_duration >> 8; + + ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans); + if(ret){ + hid_err(t300rs->hdev, "failed modifying duration\n"); + goto error; + } + } +error: + memset(send_buffer, 0, T300RS_BUFFER_LENGTH); + return ret; +} + +static int t300rs_modify_constant(struct t300rs_device_entry *t300rs, struct t300rs_effect_state *state, u8 *send_buffer){ + struct ff_effect effect = state->effect; + struct ff_effect old = state->old; + struct ff_constant_effect constant = effect.u.constant; + struct ff_constant_effect constant_old = old.u.constant; + int ret, trans; + + if(constant.level != constant_old.level){ + s16 level, le_level; + + level = (constant.level * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; + le_level = cpu_to_le16(level); + + send_buffer[0] = 0x60; + send_buffer[2] = effect.id + 1; + send_buffer[3] = 0x0a; + + send_buffer[4] = le_level & 0xff; + send_buffer[5] = le_level >> 8; + + ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans); + if(ret){ + hid_err(t300rs->hdev, "failed modifying constant effect\n"); + goto error; + } + + memset(send_buffer, 0, T300RS_BUFFER_LENGTH); + } + + ret = t300rs_modify_constant_envelope(t300rs, state, send_buffer); + if(ret){ + hid_err(t300rs->hdev, "failed modifying constant envelope\n"); + goto error; + } + + ret = t300rs_modify_duration(t300rs, state, send_buffer); + if(ret){ + hid_err(t300rs->hdev, "failed modifying constant duration\n"); + goto error; + } + +error: + kfree(send_buffer); + return ret; +} + +static int t300rs_modify_damper(struct t300rs_device_entry *t300rs, struct t300rs_effect_state *state, u8 *send_buffer){ + struct ff_effect effect = state->effect; + struct ff_effect old = state->old; + struct ff_condition_effect damper = effect.u.condition[0]; + struct ff_condition_effect damper_old = old.u.condition[0]; + int ret, trans; + + if(damper.right_coeff != damper_old.right_coeff){ + s16 le_coeff = cpu_to_le16(damper.right_coeff); + + send_buffer[0] = 0x60; + send_buffer[2] = effect.id + 1; + send_buffer[3] = 0x0e; + send_buffer[4] = 0x41; + + send_buffer[5] = le_coeff & 0xff; + send_buffer[6] = le_coeff >> 8; + + ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans); + if(ret){ + hid_err(t300rs->hdev, "failed modifying damper rc\n"); + goto error; + } + + memset(send_buffer, 0, T300RS_BUFFER_LENGTH); + } + + if(damper.left_coeff != damper_old.left_coeff){ + s16 le_coeff = cpu_to_le16(damper.left_coeff); + + send_buffer[0] = 0x60; + send_buffer[2] = effect.id + 1; + send_buffer[3] = 0x0e; + send_buffer[4] = 0x42; + + send_buffer[5] = le_coeff & 0xff; + send_buffer[6] = le_coeff >> 8; + + ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans); + if(ret){ + hid_err(t300rs->hdev, "failed modifying damper lc\n"); + } + + memset(send_buffer, 0, T300RS_BUFFER_LENGTH); + } + + if((damper.deadband != damper_old.deadband) || + (damper.center != damper_old.center)){ + u16 le_deadband_right = cpu_to_le16(0xfffe - damper.deadband - damper.center); + u16 le_deadband_left = cpu_to_le16(0xfffe - damper.deadband + damper.center); + + send_buffer[0] = 0x60; + send_buffer[2] = effect.id + 1; + send_buffer[3] = 0x0e; + send_buffer[4] = 0x4c; + + send_buffer[5] = le_deadband_right & 0xff; + send_buffer[6] = le_deadband_right >> 8; + + send_buffer[7] = le_deadband_left & 0xff; + send_buffer[8] = le_deadband_left >> 8; + + ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans); + if(ret){ + hid_err(t300rs->hdev, "failed modifying damper deadband\n"); + } + + memset(send_buffer, 0, T300RS_BUFFER_LENGTH); + } + + ret = t300rs_modify_duration(t300rs, state, send_buffer); + if(ret){ + hid_err(t300rs->hdev, "failed modifying constant duration\n"); + goto error; + } + +error: + kfree(send_buffer); + return ret; +} + + +static int t300rs_modify_periodic(struct t300rs_device_entry *t300rs, struct t300rs_effect_state *state, u8 *send_buffer){ + struct ff_effect effect = state->effect; + struct ff_effect old = state->old; + struct ff_periodic_effect periodic = effect.u.periodic; + struct ff_periodic_effect periodic_old = old.u.periodic; + int ret, trans; + + if(periodic.magnitude != periodic_old.magnitude){ + s16 level, le_level; + + level = (periodic.magnitude * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; + le_level = cpu_to_le16(level); + + send_buffer[0] = 0x60; + send_buffer[2] = effect.id + 1; + send_buffer[3] = 0x0e; + send_buffer[4] = 0x01; + + send_buffer[5] = le_level & 0xff; + send_buffer[6] = le_level >> 8; + + ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans); + if(ret){ + hid_err(t300rs->hdev, "failed modifying periodic magnitude\n"); + goto error; + } + + memset(send_buffer, 0, T300RS_BUFFER_LENGTH); + } + + if(periodic.offset != periodic_old.offset){ + s16 le_offset = cpu_to_le16(periodic.offset); + + send_buffer[0] = 0x60; + send_buffer[2] = effect.id + 1; + send_buffer[3] = 0x0e; + send_buffer[4] = 0x04; + + send_buffer[5] = le_offset & 0xff; + send_buffer[6] = le_offset >> 8; + + ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans); + if(ret){ + hid_err(t300rs->hdev, "failed modifying periodic offset\n"); + } + + memset(send_buffer, 0, T300RS_BUFFER_LENGTH); + } + + if(periodic.phase != periodic_old.phase){ + s16 le_phase = cpu_to_le16(periodic.phase); + + send_buffer[0] = 0x60; + send_buffer[2] = effect.id + 1; + send_buffer[3] = 0x0e; + send_buffer[4] = 0x02; + + send_buffer[5] = le_phase & 0xff; + send_buffer[6] = le_phase >> 8; + + ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans); + if(ret){ + hid_err(t300rs->hdev, "failed modifying periodic phase\n"); + } + + memset(send_buffer, 0, T300RS_BUFFER_LENGTH); + } + + if(periodic.period != periodic_old.period){ + s16 le_period = cpu_to_le16(periodic.period); + + send_buffer[0] = 0x60; + send_buffer[2] = effect.id + 1; + send_buffer[3] = 0x0e; + send_buffer[4] = 0x08; + + send_buffer[5] = le_period & 0xff; + send_buffer[6] = le_period >> 8; + + ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans); + if(ret){ + hid_err(t300rs->hdev, "failed modifying periodic period\n"); + } + + memset(send_buffer, 0, T300RS_BUFFER_LENGTH); + } + + ret = t300rs_modify_periodic_envelope(t300rs, state, send_buffer); + if(ret){ + hid_err(t300rs->hdev, "failed modifying constant envelope\n"); + goto error; + } + + ret = t300rs_modify_duration(t300rs, state, send_buffer); + if(ret){ + hid_err(t300rs->hdev, "failed modifying constant duration\n"); + goto error; + } + +error: + kfree(send_buffer); + return ret; +} + + static int t300rs_upload_constant(struct t300rs_device_entry *t300rs, struct t300rs_effect_state *state){ u8 *send_buffer = kzalloc(T300RS_BUFFER_LENGTH, GFP_ATOMIC); struct ff_effect effect = state->effect; @@ -124,15 +573,16 @@ static int t300rs_upload_constant(struct t300rs_device_entry *t300rs, struct t30 u16 duration, le_offset, le_duration; int ret, trans; - - /* currently this driver doesn't support dynamic effect updating quite like - * many games would assume. There's not a huge drawback to this method, the - * wheel maybe feels a bit more jittery because of this but it's not a - * massive downside. At some point in the future I'd like to improve the - * dynamic updating, but this will do for now. - * */ - if(test_bit(FF_EFFECT_PLAYING, &state->flags)){ - t300rs_stop_effect(t300rs, state); + + /* some games, such as DiRT Rally 2 have a weird feeling to them, sort of + * like the wheel pulls just a bit to the right or left and then it just + * stops. I wouldn't be surprised if it's got something to do with the + * constant envelope, but right now I don't know. */ + + if(test_bit(FF_EFFECT_PLAYING, &state->flags) && + test_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags)){ + __clear_bit(FF_EFFECT_QUEUE_UPLOAD, &state->flags); + return t300rs_modify_constant(t300rs, state, send_buffer); } level = (constant.level * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; @@ -172,10 +622,6 @@ static int t300rs_upload_constant(struct t300rs_device_entry *t300rs, struct t30 hid_err(t300rs->hdev, "failed uploading constant effect\n"); } - if(test_bit(FF_EFFECT_PLAYING, &state->flags)){ - t300rs_play_effect(t300rs, state); - } - kfree(send_buffer); return ret; } @@ -262,8 +708,10 @@ static int t300rs_upload_spring(struct t300rs_device_entry *t300rs, struct t300r u16 duration, le_right_coeff, le_left_coeff, le_deadband_right, le_deadband_left, le_duration, le_offset; - if(test_bit(FF_EFFECT_PLAYING, &state->flags)){ - t300rs_stop_effect(t300rs, state); + if(test_bit(FF_EFFECT_PLAYING, &state->flags) && + test_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags)){ + __clear_bit(FF_EFFECT_QUEUE_UPLOAD, &state->flags); + return t300rs_modify_damper(t300rs, state, send_buffer); } if(effect.replay.length == 0){ @@ -314,10 +762,6 @@ static int t300rs_upload_spring(struct t300rs_device_entry *t300rs, struct t300r hid_err(t300rs->hdev, "failed uploading spring\n"); } - if(test_bit(FF_EFFECT_PLAYING, &state->flags)){ - t300rs_play_effect(t300rs, state); - } - kfree(send_buffer); return ret; } @@ -331,8 +775,10 @@ static int t300rs_upload_damper(struct t300rs_device_entry *t300rs, struct t300r u16 duration, le_right_coeff, le_left_coeff, le_deadband_right, le_deadband_left, le_duration, le_offset; - if(test_bit(FF_EFFECT_PLAYING, &state->flags)){ - t300rs_stop_effect(t300rs, state); + if(test_bit(FF_EFFECT_PLAYING, &state->flags) && + test_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags)){ + __clear_bit(FF_EFFECT_QUEUE_UPLOAD, &state->flags); + return t300rs_modify_damper(t300rs, state, send_buffer); } if(effect.replay.length == 0){ @@ -383,10 +829,6 @@ static int t300rs_upload_damper(struct t300rs_device_entry *t300rs, struct t300r hid_err(t300rs->hdev, "failed uploading spring\n"); } - if(test_bit(FF_EFFECT_PLAYING, &state->flags)){ - t300rs_play_effect(t300rs, state); - } - kfree(send_buffer); return ret; } @@ -399,8 +841,10 @@ static int t300rs_upload_periodic(struct t300rs_device_entry *t300rs, struct t30 u16 duration, magnitude, le_magnitude, le_phase, le_period, le_offset, le_duration; s16 le_periodic_offset; - if(test_bit(FF_EFFECT_PLAYING, &state->flags)){ - t300rs_stop_effect(t300rs, state); + if(test_bit(FF_EFFECT_PLAYING, &state->flags) && + test_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags)){ + __clear_bit(FF_EFFECT_QUEUE_UPLOAD, &state->flags); + return t300rs_modify_periodic(t300rs, state, send_buffer); } if(effect.replay.length == 0){ @@ -456,10 +900,6 @@ static int t300rs_upload_periodic(struct t300rs_device_entry *t300rs, struct t30 hid_err(t300rs->hdev, "failed uploading periodic effect"); } - if(test_bit(FF_EFFECT_PLAYING, &state->flags)){ - t300rs_play_effect(t300rs, state); - } - kfree(send_buffer); return ret; } @@ -493,10 +933,13 @@ static int t300rs_timer_helper(struct t300rs_device_entry *t300rs){ state = &t300rs->states[effect_id]; - if(test_bit(FF_EFFECT_PLAYING, &state->flags)){ - if((jiffies_now - state->start_time) >= state->effect.replay.length){ + if(test_bit(FF_EFFECT_PLAYING, &state->flags) && state->effect.replay.length){ + if((jiffies_now - state->start_time) >= state->effect.replay.length){ __clear_bit(FF_EFFECT_PLAYING, &state->flags); + /* lazy bum fix? */ + __clear_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags); + if(state->count){ __set_bit(FF_EFFECT_QUEUE_START, &state->flags); } @@ -582,6 +1025,10 @@ static int t300rs_upload(struct input_dev *dev, struct ff_effect *effect, struct spin_lock_irqsave(&t300rs->lock, t300rs->lock_flags); state->effect = *effect; + if(old){ + state->old = *old; + __set_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags); + } __set_bit(FF_EFFECT_QUEUE_UPLOAD, &state->flags); spin_unlock_irqrestore(&t300rs->lock, t300rs->lock_flags); @@ -601,11 +1048,12 @@ static int t300rs_play(struct input_dev *dev, int effect_id, int value){ spin_lock_irqsave(&t300rs->lock, t300rs->lock_flags); if(value > 0){ + /* if(test_bit(FF_EFFECT_QUEUE_START, &state->flags)){ __set_bit(FF_EFFECT_QUEUE_STOP, &state->flags); } else { t300rs->effects_used++; - } + }*/ state->count = value; state->start_time = JIFFIES2MS(jiffies); @@ -631,21 +1079,28 @@ static ssize_t t300rs_range_store(struct device *dev, struct device_attribute *a struct t300rs_device_entry *t300rs; u8 *send_buffer = kzalloc(T300RS_BUFFER_LENGTH, GFP_ATOMIC); u16 range = simple_strtoul(buf, NULL, 10); + u16 le_range; int ret, trans; t300rs = t300rs_get_device(hdev); - if(range < 0x097b){ - range = 0x097b; + if(range < 40){ + range = 40; } - range = cpu_to_le16(range); + if(range > 1080){ + range = 1080; + } + + range *= 0x3c; + + le_range = cpu_to_le16(range); send_buffer[0] = 0x60; send_buffer[1] = 0x08; send_buffer[2] = 0x11; - send_buffer[3] = range & 0xff; - send_buffer[4] = range >> 8; + send_buffer[3] = le_range & 0xff; + send_buffer[4] = le_range >> 8; ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans); if(ret){ @@ -653,7 +1108,7 @@ static ssize_t t300rs_range_store(struct device *dev, struct device_attribute *a return -1; } - t300rs->range = range; + t300rs->range = range / 0x3c; kfree(send_buffer); return count; } @@ -798,7 +1253,7 @@ int t300rs_init(struct hid_device *hdev, const signed short *ff_bits){ struct usb_device *usbdev = interface_to_usbdev(usbif); struct hid_report *report; struct ff_device *ff; - char range[10] = "54000"; /* approx 900 degress */ + char range[10] = "1080"; /* max */ int i, ret; drv_data = hid_get_drvdata(hdev); @@ -829,6 +1284,7 @@ int t300rs_init(struct hid_device *hdev, const signed short *ff_bits){ } spin_lock_init(&t300rs->lock); + spin_lock_init(&data_lock); drv_data->device_props = t300rs; diff --git a/hid-tmt300rs.h b/hid-tmt300rs.h index ccdea78..e5bb58d 100644 --- a/hid-tmt300rs.h +++ b/hid-tmt300rs.h @@ -7,12 +7,19 @@ #define T300RS_MAX_EFFECTS 16 #define T300RS_BUFFER_LENGTH 64 -#define DEFAULT_TIMER_PERIOD 4 /* the wheel seems to be bad at stuff*/ +/* the wheel seems to only be capable of processing a certain number of + * interrupts per second, and if this value is too low the kernel urb buffer(or + * some buffer at least) fills up. Optimally I would figure out some way to + * space out the interrupts so that they all leave at regular intervals, but for + * now this is good enough, go slow enough that everything works. + * */ +#define DEFAULT_TIMER_PERIOD 8 #define FF_EFFECT_QUEUE_UPLOAD 0 #define FF_EFFECT_QUEUE_START 1 #define FF_EFFECT_QUEUE_STOP 2 #define FF_EFFECT_PLAYING 3 +#define FF_EFFECT_QUEUE_UPDATE 4 #define CLAMP_VALUE_U16(x) ((unsigned short)((x) > 0xffff ? 0xffff : (x))) #define SCALE_VALUE_U16(x, bits) (CLAMP_VALUE_U16(x) >> (16 - bits)) @@ -21,6 +28,9 @@ spinlock_t lock; unsigned long lock_flags; +spinlock_t data_lock; +unsigned long data_flags; + static int timer_msecs = DEFAULT_TIMER_PERIOD; static const signed short t300rs_ff_effects[] = { @@ -43,6 +53,8 @@ static const signed short t300rs_ff_effects[] = { struct t300rs_effect_state { struct ff_effect effect; + struct ff_effect old; + bool old_set; unsigned long flags; unsigned long start_time; unsigned long count; @@ -75,7 +87,7 @@ struct t300rs_data{ void *device_props; }; -static __u8 t300rs_rdesc_fixed[] = {0x05, 0x01, 0x09, 0x04, 0xa1, 0x01, 0x09, 0x01, 0xa1, 0x00, 0x85, 0x07, 0x09, 0x30, 0x15, 0x00, 0x27, 0xff, 0xff, 0x00, 0x00, 0x35, 0x00, 0x47, 0xff, 0xff, 0x00, 0x00, 0x75, 0x10, 0x95, 0x01, 0x81, 0x02, 0x09, 0x31, 0x26, 0xff, 0x03, 0x46, 0xff, 0x03, 0x81, 0x02, 0x09, 0x35, 0x81, 0x02, 0x09, 0x36, 0x81, 0x02, 0x81, 0x03, 0x05, 0x09, 0x19, 0x01, 0x29, 0x0d, 0x25, 0x01, 0x45, 0x01, 0x75, 0x01, 0x95, 0x0d, 0x81, 0x02, 0x75, 0x0b, 0x95, 0x01, 0x81, 0x03, 0x05, 0x01, 0x09, 0x39, 0x25, 0x07, 0x46, 0x3b, 0x01, 0x55, 0x00, 0x65, 0x14, 0x75, 0x04, 0x81, 0x42, 0x65, 0x00, 0x81, 0x03, 0x85, 0x0a, 0x06, 0x00, 0xff, 0x09, 0x0a, 0x75, 0x08, 0x95, 0x3f, 0x26, 0xff, 0x7f, 0x16, 0x00, 0x80, 0x46, 0xff, 0x7f, 0x36, 0x00, 0x80, 0x91, 0x02, 0x85, 0x02, 0x09, 0x02, 0x81, 0x02, 0x09, 0x14, 0x85, 0x14, 0x81, 0x02, 0xc0, 0xc0,}; +static __u8 t300rs_rdesc_fixed[] = {0x05, 0x01, 0x09, 0x04, 0xa1, 0x01, 0x09, 0x01, 0xa1, 0x00, 0x85, 0x07, 0x09, 0x30, 0x15, 0x00, 0x27, 0xff, 0xff, 0x00, 0x00, 0x35, 0x00, 0x47, 0xff, 0xff, 0x00, 0x00, 0x75, 0x10, 0x95, 0x01, 0x81, 0x02, 0x09, 0x35, 0x26, 0xff, 0x03, 0x46, 0xff, 0x03, 0x81, 0x02, 0x09, 0x32, 0x81, 0x02, 0x09, 0x31, 0x81, 0x02, 0x81, 0x03, 0x05, 0x09, 0x19, 0x01, 0x29, 0x0d, 0x25, 0x01, 0x45, 0x01, 0x75, 0x01, 0x95, 0x0d, 0x81, 0x02, 0x75, 0x0b, 0x95, 0x01, 0x81, 0x03, 0x05, 0x01, 0x09, 0x39, 0x25, 0x07, 0x46, 0x3b, 0x01, 0x55, 0x00, 0x65, 0x14, 0x75, 0x04, 0x81, 0x42, 0x65, 0x00, 0x81, 0x03, 0x85, 0x0a, 0x06, 0x00, 0xff, 0x09, 0x0a, 0x75, 0x08, 0x95, 0x3f, 0x26, 0xff, 0x7f, 0x16, 0x00, 0x80, 0x46, 0xff, 0x7f, 0x36, 0x00, 0x80, 0x91, 0x02, 0x85, 0x02, 0x09, 0x02, 0x81, 0x02, 0x09, 0x14, 0x85, 0x14, 0x81, 0x02, 0xc0, 0xc0,}; static u8 spring_values[] = { 0xa6, 0x6a, 0xa6, 0x6a, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xdf, 0x58, 0xa6, 0x6a, 0x06 diff --git a/t150init.pcapng b/t150init.pcapng Binary files differnew file mode 100644 index 0000000..bb71e52 --- /dev/null +++ b/t150init.pcapng |
