From 75006183d0a379a2b0fa844fc32b3e27d229f368 Mon Sep 17 00:00:00 2001 From: RaySlash Date: Mon, 2 Oct 2023 13:08:52 +1000 Subject: src: initial refactoring --- Kbuild | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 Kbuild (limited to 'Kbuild') diff --git a/Kbuild b/Kbuild deleted file mode 100644 index 619792c..0000000 --- a/Kbuild +++ /dev/null @@ -1,2 +0,0 @@ -obj-m := hid-tmff-new.o -hid-tmff-new-y := hid-tmff2.o hid-tmt300rs.o hid-tmt248.o hid-tmtx.o -- cgit v1.3 From fc6076449bd39a17fc8210af38c941ece9cf9cc0 Mon Sep 17 00:00:00 2001 From: RaySlash Date: Wed, 4 Oct 2023 14:11:29 +1000 Subject: src, deps, docs: update - Update the effects documents - Rename `hid-tm*` to `tm*` for folders - Move `Makefile` and `Kbuild` to root - Add `deps/` and move in [hid-tminit](https://github.com/scarburato/hid-tminit/commit/9375f6c7d83af5dd6c8b8fe30351d0f36043b20a) --- .gitmodules | 4 +- Kbuild | 2 + Makefile | 16 + deps/tminit | 1 + docs/effects/FFBEFFECTS_T248.md | 7 + docs/effects/FFBEFFECTS_T300RS.md | 541 ++++++++++++ src/Kbuild | 2 - src/Makefile | 16 - src/hid-tminit | 1 - src/hid-tmt248/hid-tmt248.c | 335 -------- src/hid-tmt300rs/hid-tmt300rs.c | 1714 ------------------------------------- src/hid-tmt300rs/hid-tmt300rs.h | 9 - src/hid-tmtx/hid-tmtx.c | 323 ------- src/tmt248/hid-tmt248.c | 335 ++++++++ src/tmt300rs/hid-tmt300rs.c | 1714 +++++++++++++++++++++++++++++++++++++ src/tmt300rs/hid-tmt300rs.h | 9 + src/tmtx/hid-tmtx.c | 323 +++++++ 17 files changed, 2950 insertions(+), 2402 deletions(-) create mode 100644 Kbuild create mode 100644 Makefile create mode 160000 deps/tminit create mode 100644 docs/effects/FFBEFFECTS_T248.md create mode 100644 docs/effects/FFBEFFECTS_T300RS.md delete mode 100644 src/Kbuild delete mode 100644 src/Makefile delete mode 160000 src/hid-tminit delete mode 100644 src/hid-tmt248/hid-tmt248.c delete mode 100644 src/hid-tmt300rs/hid-tmt300rs.c delete mode 100644 src/hid-tmt300rs/hid-tmt300rs.h delete mode 100644 src/hid-tmtx/hid-tmtx.c create mode 100644 src/tmt248/hid-tmt248.c create mode 100644 src/tmt300rs/hid-tmt300rs.c create mode 100644 src/tmt300rs/hid-tmt300rs.h create mode 100644 src/tmtx/hid-tmtx.c (limited to 'Kbuild') diff --git a/.gitmodules b/.gitmodules index 6038e0c..047c0f3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "src/hid-tminit"] - path = src/hid-tminit +[submodule "deps/tminit"] + path = deps/tminit url = https://github.com/scarburato/hid-tminit diff --git a/Kbuild b/Kbuild new file mode 100644 index 0000000..e33e86f --- /dev/null +++ b/Kbuild @@ -0,0 +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 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5e2ab40 --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +KDIR ?= /lib/modules/$(shell uname -r)/build + +all: hid-tminit + $(MAKE) -C $(KDIR) M=$(shell pwd) modules + +install: hid-tminit + $(MAKE) -C $(KDIR) M=$(shell pwd) modules_install + depmod -A + +clean: hid-tminit + $(MAKE) -C $(KDIR) M=$(shell pwd) clean + + +.PHONY: hid-tminit +hid-tminit: + $(MAKE) -C hid-tminit KDIR="$(KDIR)" $(MAKECMDGOALS) diff --git a/deps/tminit b/deps/tminit new file mode 160000 index 0000000..9375f6c --- /dev/null +++ b/deps/tminit @@ -0,0 +1 @@ +Subproject commit 9375f6c7d83af5dd6c8b8fe30351d0f36043b20a diff --git a/docs/effects/FFBEFFECTS_T248.md b/docs/effects/FFBEFFECTS_T248.md new file mode 100644 index 0000000..f43fb55 --- /dev/null +++ b/docs/effects/FFBEFFECTS_T248.md @@ -0,0 +1,7 @@ +# Force Feedback Effects - Thrustmaster T248 + +## Open: +Identical to [T300RS](./FFBEFFECTST300RS) + +## Close: +Identical to [T300RS](./FFBEFFECTST300RS) diff --git a/docs/effects/FFBEFFECTS_T300RS.md b/docs/effects/FFBEFFECTS_T300RS.md new file mode 100644 index 0000000..f076ec7 --- /dev/null +++ b/docs/effects/FFBEFFECTS_T300RS.md @@ -0,0 +1,541 @@ +# Force Feedback Effects - Thrustmaster T300RS (incl. PS3/PS4 modes) +Here I will gather all info I can find out about the different force feedback effects and their USB commands. All values seem to be little-endian. Also, general note, it seems like some effects are affected by the direction of the force, denoted by `***`. As far as I can tell, `fade_level` and `attack_level` values are calculated by mapping the `u16` into `s16` and taking the absolute value, and after that multiplying by the direction. + +> **NOTE:** All values are examples of actual commands that I captured on the USB interface, not the only available ones. + + +## GENERAL +### Playing +``` + 60 00 - standard header + 01 - ID + 89 - playing options + 01 - play + 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +``` + +### Stopping/removing (why are they rolled into one?) +``` + 60 00 - standard header + 01 - ID + 89 - playing options + 00 - stop + 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +``` + +## Open: +``` + 60 01 - standard header? + 04 - ? + 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + + (this command doesn't appear every time, odd) + 60 12 - ? + bf 04 00 00 03 b7 1e - ? /* wow, this is different on different wheels? */ + 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + + 60 01 - ? + 05 - ? + 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +``` + +## Close: +``` + 60 01 - standard header? + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +``` + +## Rotation angle: +``` + 60 08 - header plus settings? + 11 - set rotation angle + 55 d5 - angle (between ff ff and 7b 09, one degree is roughly 3c) + 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +``` + +## FF_AUTOCENTER: +``` + 60 08 - header plus settings? + 03 - set autocenter force + 8f 02 - force (between ff ff and 00 00) + 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +``` + +## FF_GAIN: +``` + 60 02 - header plus gain? + bf - gain (between ff and 00) + 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +``` + +## FF_CONSTANT +### Initialization +``` + 60 00 - standard header + 01 - ID + 6a - new constant effect(?) + fe ff - strength *** + 00 00 - attack_length + 00 00 - attack_level *** + 00 00 - fade_length + 00 00 - fade_level *** + 00 4f - ? + f7 17 - time in milliseconds, unsigned + 00 00 + 07 00 - offset from start(?) + 00 ff ff - end of new effect(?) + 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 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 (For dynamic updating of effects) + +#### Direction: ``N/A`` + +#### Constant force: +``` +60 00 - standard header +01 - ID +0a - modify 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 +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 - standard header + 01 - ID + 49 00 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: `N/A` + +## FF_RAMP +(Why on earth is it this difficult to figure out how a ramp works?) +### Init: +``` + 60 00 - standard header + 01 - ID + 6b - new ramp effect + f6 7f - difference *** + fe ff - level? *** (level = (if end_level > start_level, end_level, else + start_level) - difference?) (signed) + 00 00 + f7 17 - time + 00 80 - some kind of marker + 00 00 - attack_length + f6 7f - attack_level *** + 00 00 - fade_length + f6 7f - fade_level*** + 04 - invert (going "down", 05, going "up", 04) + 4f + f7 17 - time again? + 00 00 + 00 00 - offset + 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 00 00 00 00 00 00 +``` +### Modifying: +(Sweet baby jesus. I'll figure this out later ``Ramp(?)``) +``` + 60 00 - standard header + 01 - ID + 0e - ??? + 03 - ramp? + e3 04 - difference? + 7d 75 - "level"? + 05 - ???? + 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 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: `N/A` + +## FF_SPRING: +### Init: +``` + 60 00 - standard header + 01 - ID + 64 - new conditional effect + fc 7f - positive coefficient (right?) + fc 7f - negative coefficient (left?) + fe ff - deadband (left?) (deadband + offset) (fe ff means no deadband) + fe ff - deadband (right?) (deadband + offset) + a6 6a a6 6a fe ff fe ff fe ff fe ff df 58 a6 6a 06 - some weird hard-coded + values to do with springs? + + 4f + f7 17 - duration + 00 00 + 00 00 - offset + 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: +Same as below (FF_DAMPER + FF_FRICTION + FF_INERTIA) + +## FF_DAMPER + FF_FRICTION + FF_INERTIA: +### Init: +``` + 60 00 - standard header + 02 -ID + 64 - new conditional effect + fc 7f - positive coefficient (right?) + fc 7f - negative coefficient (left?) + fe ff - deadband (left?) (deadband + offset) (fe ff means no deadband) + fe ff - deadband (right?) (deadband + offset) + fc 7f fc 7f fe ff fe ff fe ff fe ff fc 7f fc 7f 07 - some weird hard-coded + values to do with friction? + 4f + f7 17 - duration + 00 00 + 00 00 - offset + 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: `N/A` + +## FF_PERIODIC: +### Init +``` + 60 00 - standard header + 01 - ID + 6b - new periodic effect + 00 00 - magnitude *** + fe ff - offset (up/down) + 00 00 - phase (left/right) + e8 03 - period + 00 80 + 00 00 - attack_length + 00 00 - attack_level *** + 00 00 - fade_length + 00 00 - fade_level *** + 01 - type of periodic ( square 01, + sine 03, + triangle 02, + sawtooth down 05, + sawtooth up 04 ) + 4f + f7 17 - duration + 00 00 + 00 00 - offset + 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 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 02 + 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 04 + 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: +``` + Square: + 60 00 + 01 - ID + 49 - ? + 01 - Effect type + 41 - ? + 4e 0c - 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 00 00 00 + + Sine: + 60 00 + 01 - ID + 49 - ? + 03 - Effect type + 41 - ? + ec 13 - 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 00 00 00 + + Triangle: + 60 00 + 01 - ID + 49 - ? + 02 - Effect type + 41 - ? + 4e 0c - 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 00 00 00 + + Sawtooth up: + 60 00 + 01 - ID + 49 - ? + 04 - Effect type + 41 - ? + 4e 0c - 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 00 00 00 + + Sawtooth down: + 60 00 + 01 - ID + 49 - ? + 05 - Effect type + 41 - ? + ec 13 - 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 00 00 00 +``` +### Offset: `N/A ?` + +## PS4 Input +``` +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 226 /* wheel */ +ff00.0021 = 125 /* wheel */ +ff00.0021 = 255 /* gas */ +ff00.0021 = 255 /* gas */ +ff00.0021 = 255 /* brake */ +ff00.0021 = 255 /* brake */ +ff00.0021 = 255 /* clutch */ +ff00.0021 = 255 /* clutch */ +ff00.0021 = 0 +ff00.0021 = 255 +ff00.0021 = 255 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +ff00.0021 = 0 +``` diff --git a/src/Kbuild b/src/Kbuild deleted file mode 100644 index b8541e0..0000000 --- a/src/Kbuild +++ /dev/null @@ -1,2 +0,0 @@ -obj-m := hid-tmff-new.o -hid-tmff-new-y := hid-tmff2.o hid-tmt300rs/hid-tmt300rs.o hid-tmt248/hid-tmt248.o hid-tmtx/hid-tmtx.o diff --git a/src/Makefile b/src/Makefile deleted file mode 100644 index 5e2ab40..0000000 --- a/src/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -KDIR ?= /lib/modules/$(shell uname -r)/build - -all: hid-tminit - $(MAKE) -C $(KDIR) M=$(shell pwd) modules - -install: hid-tminit - $(MAKE) -C $(KDIR) M=$(shell pwd) modules_install - depmod -A - -clean: hid-tminit - $(MAKE) -C $(KDIR) M=$(shell pwd) clean - - -.PHONY: hid-tminit -hid-tminit: - $(MAKE) -C hid-tminit KDIR="$(KDIR)" $(MAKECMDGOALS) diff --git a/src/hid-tminit b/src/hid-tminit deleted file mode 160000 index 9375f6c..0000000 --- a/src/hid-tminit +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9375f6c7d83af5dd6c8b8fe30351d0f36043b20a diff --git a/src/hid-tmt248/hid-tmt248.c b/src/hid-tmt248/hid-tmt248.c deleted file mode 100644 index af3aaa9..0000000 --- a/src/hid-tmt248/hid-tmt248.c +++ /dev/null @@ -1,335 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -#include -#include -#include "../hid-tmff2.h" - -#define T248_MAX_EFFECTS 16 -#define T248_BUFFER_LENGTH 63 - -static const u8 setup_0[64] = { 0x42, 0x01 }; -static const u8 setup_1[64] = { 0x0a, 0x04, 0x90, 0x03 }; -static const u8 setup_2[64] = { 0x0a, 0x04, 0x00, 0x0c }; -static const u8 setup_3[64] = { 0x0a, 0x04, 0x12, 0x10 }; -static const u8 setup_4[64] = { 0x0a, 0x04, 0x00, 0x06 }; -static const u8 setup_5[64] = { 0x0a, 0x04, 0x00, 0x0e }; -static const u8 setup_6[64] = { 0x0a, 0x04, 0x00, 0x0e, 0x01 }; -static const u8 *const setup_arr[] = { setup_0, setup_1, setup_2, setup_3, setup_4, setup_5, setup_6 }; -static const unsigned int setup_arr_sizes[] = { - ARRAY_SIZE(setup_0), - ARRAY_SIZE(setup_1), - ARRAY_SIZE(setup_2), - ARRAY_SIZE(setup_3), - ARRAY_SIZE(setup_4), - ARRAY_SIZE(setup_5), - ARRAY_SIZE(setup_6) -}; - -static const unsigned long t248_params = - PARAM_SPRING_LEVEL - | PARAM_DAMPER_LEVEL - | PARAM_FRICTION_LEVEL - | PARAM_RANGE - | PARAM_GAIN - ; - -static const signed short t248_effects[] = { - FF_CONSTANT, - FF_RAMP, - FF_SPRING, - FF_DAMPER, - FF_FRICTION, - FF_INERTIA, - FF_PERIODIC, - FF_SINE, - FF_TRIANGLE, - FF_SQUARE, - FF_SAW_UP, - FF_SAW_DOWN, - FF_AUTOCENTER, - FF_GAIN, - -1 -}; - -/* TODO: sort through this stuff */ -static u8 t248_pc_rdesc_fixed[] = { - 0x05, 0x01, /* Usage page (Generic Desktop) */ - 0x09, 0x04, /* Usage (Joystick) */ - 0xa1, 0x01, /* Collection (Application) */ - 0x09, 0x01, /* Usage (Pointer) */ - 0xa1, 0x00, /* Collection (Physical) */ - 0x85, 0x07, /* Report ID (7) */ - 0x09, 0x30, /* Usage (X) */ - 0x15, 0x00, /* Logical minimum (0) */ - 0x27, 0xff, 0xff, 0x00, 0x00, /* Logical maximum (65535) */ - 0x35, 0x00, /* Physical minimum (0) */ - 0x47, 0xff, 0xff, 0x00, 0x00, /* Physical maximum (65535) */ - 0x75, 0x10, /* Report size (16) */ - 0x95, 0x01, /* Report count (1) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x09, 0x31, /* Usage (Y) TODO: clutch? */ - 0x26, 0xff, 0x03, /* Logical maximum (1023) */ - 0x46, 0xff, 0x03, /* Physical maximum (1023) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x09, 0x35, /* Usage (Rz) TODO: brake? */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x09, 0x36, /* Usage (Slider) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x75, 0x08, /* Report size (8) */ - 0x26, 0xff, 0x00, /* Logical maximum (255) */ - 0x46, 0xff, 0x00, /* Physical maximum (255) */ - 0x09, 0x40, /* Usage (Vx) TODO: what is this? */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x09, 0x41, /* Usage (Vy) TODO: --||-- */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x09, 0x33, /* Usage (Rx) TODO: --||-- */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x09, 0x34, /* Usage (Ry) TODO: --||-- */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x09, 0x32, /* Usage (Z) TODO: --||-- (gas?) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x09, 0x37, /* Usage (Dial) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x05, 0x09, /* Usage page (Button) */ - 0x19, 0x01, /* Usage minimum (1) */ - 0x29, 0x1a, /* Usage maximum (13) */ - 0x25, 0x01, /* Logical maximum (1) */ - 0x45, 0x01, /* Physical maximum (1) */ - 0x75, 0x01, /* Report size (1) */ - 0x95, 0x1a, /* Report count (26) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x75, 0x06, /* Report size (6) */ - 0x95, 0x01, /* Report count (1) */ - 0x81, 0x03, /* Usage (Variable, Absolute, Constant) */ - 0x05, 0x01, /* Usage page (Generic Desktop) */ - 0x09, 0x39, /* Usage (Hat Switch) */ - 0x25, 0x07, /* Logical maximum (7) */ - 0x46, 0x3b, 0x01, /* Physical maximum (315) */ - 0x55, 0x00, /* Unit exponent (0) */ - 0x65, 0x14, /* Unit (Eng rot, Angular Pos) */ - 0x75, 0x04, /* Report size (4) */ - 0x81, 0x42, /* Input (Variable, Absolute, NullState) */ - 0x65, 0x00, /* Input (None) */ - 0x81, 0x03, /* Input (Variable, Absolute, Constant) */ - 0x85, 0x60, /* Report ID (96), prev 10 */ - 0x06, 0x00, 0xff, /* Usage page (Vendor 1) */ - 0x09, 0x60, /* Usage (96), prev 10 */ - 0x75, 0x08, /* Report size (8) */ - 0x95, 0x3f, /* Report count (63) */ - 0x26, 0xff, 0x00, /* Logical maximum (256) */ - 0x46, 0xff, 0x00, /* Physical maximum (256) */ - 0x91, 0x02, /* Output (Variable, Absolute) */ - 0x85, 0x02, /* Report ID (2) */ - 0x09, 0x02, /* Usage (2) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x09, 0x14, /* Usage (20) */ - 0x85, 0x14, /* Report ID (20) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0xc0, /* End collection */ - 0xc0, /* End collection */ -}; - -static int t248_interrupts(struct t300rs_device_entry *t248) -{ - u8 *send_buf = kmalloc(256, GFP_KERNEL); - struct usb_interface *usbif = to_usb_interface(t248->hdev->dev.parent); - struct usb_host_endpoint *ep; - int ret, trans, b_ep, i; - - if (!send_buf) { - hid_err(t248->hdev, "failed allocating send buffer\n"); - return -ENOMEM; - } - - ep = &usbif->cur_altsetting->endpoint[1]; - b_ep = ep->desc.bEndpointAddress; - - for (i = 0; i < ARRAY_SIZE(setup_arr); ++i) { - memcpy(send_buf, setup_arr[i], setup_arr_sizes[i]); - - ret = usb_interrupt_msg(t248->usbdev, - usb_sndintpipe(t248->usbdev, b_ep), - send_buf, setup_arr_sizes[i], - &trans, - USB_CTRL_SET_TIMEOUT); - - if (ret) { - hid_err(t248->hdev, "setup data couldn't be sent\n"); - goto err; - } - } - -err: - kfree(send_buf); - return ret; -} - -int t248_wheel_destroy(void *data) -{ - struct t300rs_device_entry *t300rs = data; - - if (!t300rs) - return -ENODEV; - - kfree(t300rs->send_buffer); - kfree(t300rs); - return 0; -} - -int t248_set_range(void *data, uint16_t value) -{ - struct t300rs_device_entry *t248 = data; - - if (value < 140) { - hid_info(t248->hdev, "value %i too small, clamping to 140\n", value); - value = 140; - } - - if (value > 900) { - hid_info(t248->hdev, "value %i too large, clamping to 900\n", value); - value = 900; - } - - return t300rs_set_range(data, value); -} - -static int t248_send_open(struct t300rs_device_entry *t248) -{ - int r1, r2; - t248->send_buffer[0] = 0x01; - t248->send_buffer[1] = 0x04; - if ((r1 = t300rs_send_int(t248))) - return r1; - - t248->send_buffer[0] = 0x01; - t248->send_buffer[1] = 0x05; - if ((r2 = t300rs_send_int(t248))) - return r2; - - return 0; -} - -static int t248_open(void *data, int open_mode) -{ - struct t300rs_device_entry *t248 = data; - - if (!t248) - return -ENODEV; - - if (open_mode) - t248_send_open(t248); - - return t248->open(t248->input_dev); -} - -static int t248_send_close(struct t300rs_device_entry *t248) -{ - int r1, r2; - t248->send_buffer[0] = 0x01; - t248->send_buffer[1] = 0x05; - if ((r1 = t300rs_send_int(t248))) - return r1; - - t248->send_buffer[0] = 0x01; - t248->send_buffer[1] = 0x00; - if ((r2 = t300rs_send_int(t248))) - return r2; - - return 0; -} - -static int t248_close(void *data, int open_mode) -{ - struct t300rs_device_entry *t248 = data; - - if (!t248) - return -ENODEV; - - if (open_mode) - t248_send_close(t248); - - t248->close(t248->input_dev); - return 0; -} - -int t248_wheel_init(struct tmff2_device_entry *tmff2, int open_mode) -{ - struct t300rs_device_entry *t248 = kzalloc(sizeof(struct t300rs_device_entry), GFP_KERNEL); - struct list_head *report_list; - int ret; - - - if (!t248) { - ret = -ENOMEM; - goto t248_err; - } - - t248->hdev = tmff2->hdev; - t248->input_dev = tmff2->input_dev; - t248->usbdev = to_usb_device(tmff2->hdev->dev.parent->parent); - t248->buffer_length = T248_BUFFER_LENGTH; - - t248->send_buffer = kzalloc(t248->buffer_length, GFP_KERNEL); - if (!t248->send_buffer) { - ret = -ENOMEM; - goto send_err; - } - - report_list = &t248->hdev->report_enum[HID_OUTPUT_REPORT].report_list; - t248->report = list_entry(report_list->next, struct hid_report, list); - t248->ff_field = t248->report->field[0]; - - t248->open = t248->input_dev->open; - t248->close = t248->input_dev->close; - - if ((ret = t248_interrupts(t248))) - goto interrupt_err; - - /* everything went OK */ - tmff2->data = t248; - tmff2->params = t248_params; - tmff2->max_effects = T248_MAX_EFFECTS; - memcpy(tmff2->supported_effects, t248_effects, sizeof(t248_effects)); - - if (!open_mode) - t248_send_open(t248); - - hid_info(t248->hdev, "force feedback for T248\n"); - return 0; - -interrupt_err: -send_err: - kfree(t248); -t248_err: - hid_err(tmff2->hdev, "failed initializing T248\n"); - return ret; -} - -static __u8 *t248_wheel_fixup(struct hid_device *hdev, __u8 *rdesc, - unsigned int *rsize) -{ - rdesc = t248_pc_rdesc_fixed; - *rsize = sizeof(t248_pc_rdesc_fixed); - return rdesc; -} - -int t248_populate_api(struct tmff2_device_entry *tmff2) -{ - tmff2->play_effect = t300rs_play_effect; - tmff2->upload_effect = t300rs_upload_effect; - tmff2->update_effect = t300rs_update_effect; - tmff2->stop_effect = t300rs_stop_effect; - - tmff2->set_gain = t300rs_set_gain; - tmff2->set_autocenter = t300rs_set_autocenter; - /* T248 only has 900 degree range, instead of T300RS 1080 */ - tmff2->set_range = t248_set_range; - tmff2->wheel_fixup = t248_wheel_fixup; - - tmff2->open = t248_open; - tmff2->close = t248_close; - - tmff2->wheel_init = t248_wheel_init; - tmff2->wheel_destroy = t248_wheel_destroy; - - return 0; -} diff --git a/src/hid-tmt300rs/hid-tmt300rs.c b/src/hid-tmt300rs/hid-tmt300rs.c deleted file mode 100644 index 20bb239..0000000 --- a/src/hid-tmt300rs/hid-tmt300rs.c +++ /dev/null @@ -1,1714 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -#include -#include -#include "../hid-tmff2.h" - -#define T300RS_MAX_EFFECTS 16 -#define T300RS_NORM_BUFFER_LENGTH 63 -#define T300RS_PS4_BUFFER_LENGTH 31 - -#define T300RS_DEFAULT_ATTACHMENT 0x06 -#define T300RS_F1_ATTACHMENT 0x03 - -static const unsigned long t300rs_params = - PARAM_SPRING_LEVEL - | PARAM_DAMPER_LEVEL - | PARAM_FRICTION_LEVEL - | PARAM_GAIN - | PARAM_RANGE - | PARAM_ALT_MODE - ; - -static const signed short t300rs_effects[] = { - FF_CONSTANT, - FF_RAMP, - FF_SPRING, - FF_DAMPER, - FF_FRICTION, - FF_INERTIA, - FF_PERIODIC, - FF_SINE, - FF_TRIANGLE, - FF_SQUARE, - FF_SAW_UP, - FF_SAW_DOWN, - FF_AUTOCENTER, - FF_GAIN, - -1 -}; - -struct __packed t300rs_fw_response { - uint8_t unused1[2]; - uint8_t fw_version; - uint8_t unused2; -}; - - -struct __packed t300rs_packet_header { - uint8_t zero1; - uint8_t id; - uint8_t code; -}; - -struct __packed t300rs_setup_header { - uint8_t cmd; - uint8_t code; -}; - -struct __packed t300rs_packet_envelope { - uint16_t attack_length; - uint16_t attack_level; - uint16_t fade_length; - uint16_t fade_level; -}; - -struct __packed t300rs_packet_timing { - uint8_t start_marker; - uint16_t duration; - uint8_t zero1[2]; - uint16_t offset; - uint8_t zero2; - uint16_t end_marker; -}; - -struct usb_ctrlrequest t300rs_fw_request = { - .bRequestType = 0xc1, - .bRequest = 86, - .wValue = 0, - .wIndex = 0, - .wLength = 8 -}; - -struct t300rs_data { - unsigned long quirks; - void *device_props; -}; - -static u8 t300rs_rdesc_nrm_fixed[] = { - 0x05, 0x01, /* Usage page (Generic Desktop) */ - 0x09, 0x04, /* Usage (Joystick) */ - 0xa1, 0x01, /* Collection (Application) */ - 0x09, 0x01, /* Usage (Pointer) */ - 0xa1, 0x00, /* Collection (Physical) */ - 0x85, 0x07, /* Report ID (7) */ - 0x09, 0x30, /* Usage (X) */ - 0x15, 0x00, /* Logical minimum (0) */ - 0x27, 0xff, 0xff, 0x00, 0x00, /* Logical maximum (65535) */ - 0x35, 0x00, /* Physical minimum (0) */ - 0x47, 0xff, 0xff, 0x00, 0x00, /* Physical maximum (65535) */ - 0x75, 0x10, /* Report size (16) */ - 0x95, 0x01, /* Report count (1) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x09, 0x35, /* Usage (Rz) (Brake) */ - 0x26, 0xff, 0x03, /* Logical maximum (1023) */ - 0x46, 0xff, 0x03, /* Physical maximum (1023) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x09, 0x32, /* Usage (Z) (Gas) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x09, 0x31, /* Usage (Y) (Clutch) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x81, 0x03, /* Input (Variable, Absolute, Constant) */ - 0x05, 0x09, /* Usage page (Button) */ - 0x19, 0x01, /* Usage minimum (1) */ - 0x29, 0x0d, /* Usage maximum (13) */ - 0x25, 0x01, /* Logical maximum (1) */ - 0x45, 0x01, /* Physical maximum (1) */ - 0x75, 0x01, /* Report size (1) */ - 0x95, 0x0d, /* Report count (13) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x75, 0x0b, /* Report size (13) */ - 0x95, 0x01, /* Report count (1) */ - 0x81, 0x03, /* Usage (Variable, Absolute, Constant) */ - 0x05, 0x01, /* Usage page (Generic Desktop) */ - 0x09, 0x39, /* Usage (Hat Switch) */ - 0x25, 0x07, /* Logical maximum (7) */ - 0x46, 0x3b, 0x01, /* Physical maximum (315) */ - 0x55, 0x00, /* Unit exponent (0) */ - 0x65, 0x14, /* Unit (Eng Rot, Angular Pos) */ - 0x75, 0x04, /* Report size (4) */ - 0x81, 0x42, /* Input (Variable, Absolute, NullState) */ - 0x65, 0x00, /* Unit (None) */ - 0x81, 0x03, /* Input (Variable, Absolute, Constant) */ - 0x85, 0x60, /* Report ID (96), prev 10 */ - 0x06, 0x00, 0xff, /* Usage page (Vendor 1) */ - 0x09, 0x60, /* Usage (96), prev 10 */ - 0x75, 0x08, /* Report size (8) */ - 0x95, 0x3f, /* Report count (63) */ - 0x26, 0xff, 0x7f, /* Logical maximum (32767) */ - 0x15, 0x00, /* Logical minimum (0) */ - 0x46, 0xff, 0x7f, /* Physical maximum (32767) */ - 0x36, 0x00, 0x80, /* Physical minimum (-32768) */ - 0x91, 0x02, /* Output (Variable, Absolute) */ - 0x85, 0x02, /* Report ID (2) */ - 0x09, 0x02, /* Usage (2) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x09, 0x14, /* Usage (20) */ - 0x85, 0x14, /* Report ID (20) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0xc0, /* End collection */ - 0xc0, /* End collection */ -}; - -static u8 t300rs_rdesc_adv_fixed[] = { - 0x05, 0x01, /* Usage page (Generic Desktop) */ - 0x09, 0x04, /* Usage (Joystick) */ - 0xa1, 0x01, /* Collection (Application) */ - 0x09, 0x01, /* Usage (Pointer) */ - 0xa1, 0x00, /* Collection (Physical) */ - 0x85, 0x07, /* Report ID (7) */ - 0x09, 0x30, /* Usage (X) */ - 0x15, 0x00, /* Logical minimum (0) */ - 0x27, 0xff, 0xff, 0x00, 0x00, /* Logical maximum (65535) */ - 0x35, 0x00, /* Physical minimum (0) */ - 0x47, 0xff, 0xff, 0x00, 0x00, /* Physical maximum (65535) */ - 0x75, 0x10, /* Report size (16) */ - 0x95, 0x01, /* Report count (1) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x09, 0x31, /* Usage (Y) */ - 0x26, 0xff, 0x03, /* Logical maximum (1023) */ - 0x46, 0xff, 0x03, /* Physical maximum (1023) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x09, 0x35, /* Usage (Rz) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x09, 0x36, /* Usage (Slider) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x81, 0x03, /* Input (Variable, Absolute, Constant) ? */ - 0x05, 0x09, /* Usage page (Button) */ - 0x19, 0x01, /* Usage minimum (1) */ - 0x29, 0x19, /* Usage maximum (25) */ - 0x25, 0x01, /* Logical maximum (1) */ - 0x45, 0x01, /* Physical maximum (1) */ - 0x75, 0x01, /* Report size (1) */ - 0x95, 0x19, /* Report count (25) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x75, 0x03, /* Report size (3) */ - 0x95, 0x01, /* Report count (1) */ - 0x81, 0x03, /* Input (Variable, Absolute, Constant) */ - 0x05, 0x01, /* Usage page (Generic Desktop) */ - 0x09, 0x39, /* Usage (Hat Switch) */ - 0x25, 0x07, /* Logical maximum (7) */ - 0x46, 0x3b, 0x01, /* Physical maximum (315) */ - 0x55, 0x00, /* Unit exponent (0) */ - 0x65, 0x14, /* Unit (Eng Rot, Angular Pos) */ - 0x75, 0x04, /* Report size (4) */ - 0x81, 0x42, /* Input (Variable, Absolute, NullState) */ - 0x65, 0x00, /* Unit (None) */ - 0x85, 0x60, /* Report ID (96), prev 10 */ - 0x06, 0x00, 0xff, /* Usage page (Vendor 1) */ - 0x09, 0x60, /* Usage (96), prev 10 (why?) */ - 0x75, 0x08, /* Report size (8) */ - 0x95, 0x3f, /* Report count (63) */ - 0x26, 0xff, 0x00, /* Logical maximum (255) */ - 0x46, 0xff, 0x00, /* Physical maximum (255) */ - 0x91, 0x02, /* Output (Variable, Absolute) */ - 0x85, 0x02, /* Report ID (2) */ - 0x09, 0x02, /* Usage (Mouse) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x09, 0x14, /* Usage (20) */ - 0x85, 0x14, /* Report ID (20) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0xc0, /* End collection */ - 0xc0, /* End collection */ -}; - -static u8 t300rs_rdesc_ps4_fixed[] = { - 0x05, 0x01, /* Usage page (Generic Desktop) */ - 0x09, 0x05, /* Usage (GamePad) */ - 0xa1, 0x01, /* Collection (Application) */ - 0x85, 0x01, /* Report ID (1) */ - 0x09, 0x00, /* Usage (U) (was X) */ - 0x09, 0x00, /* Usage (U) (was Y) */ - 0x09, 0x00, /* Usage (U) (was Z) */ - 0x09, 0x00, /* Usage (U) (was Rz)*/ - 0x15, 0x00, /* Logical minimum (0) */ - 0x26, 0xff, 0x00, /* Logical maximum (255) */ - 0x75, 0x08, /* Report size (8) */ - 0x95, 0x04, /* Report count (4) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x09, 0x39, /* Usage (Hat Switch) */ - 0x15, 0x00, /* Logical minimum (0) */ - 0x25, 0x07, /* Logical maximum (7)*/ - 0x35, 0x00, /* Physical minimum (0) */ - 0x46, 0x3b, 0x01, /* Physical maximum (315) */ - 0x65, 0x14, /* Unit (Eng Rot, Angular Pos) */ - 0x75, 0x04, /* Report size (4) */ - 0x95, 0x01, /* Report count (1) */ - 0x81, 0x42, /* Input (Variable, Absolute, NullState) */ - 0x65, 0x00, /* Input (None) */ - 0x05, 0x09, /* Usage page (Button) */ - 0x19, 0x01, /* Usage minimum (1) */ - 0x29, 0x0e, /* Usage maximum (14) */ - 0x15, 0x00, /* Logical minimum (0) */ - 0x25, 0x01, /* Logical maximum (1) */ - 0x75, 0x01, /* Report size (1) */ - 0x95, 0x0e, /* Report size (14) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x06, 0x00, 0xff, /* Usage page (Vendor 1) */ - 0x09, 0x20, /* Usage (32) */ - 0x75, 0x06, /* Report size (6) */ - 0x95, 0x01, /* Report count (1) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x05, 0x01, /* Usage page (Generic Desktop) */ - 0x09, 0x00, /* Usage (U) (was Rx)*/ - 0x09, 0x00, /* Usage (U) (was Ry) */ - 0x15, 0x00, /* Logical minimum (0) */ - 0x26, 0xff, 0x00, /* Logical maximum (255) */ - 0x75, 0x08, /* Report size (8) */ - 0x95, 0x02, /* Report count (2) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x05, 0x01, /* Usage page (Vendor 1) */ - /* constant zero? */ - 0x09, 0x00, /* Usage (33) */ - 0x95, 0x21, /* Report count (33) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - /* wheel */ - 0x09, 0x30, /* Usage (X) */ - 0x15, 0x00, /* Logical minimum (0) */ - 0x27, 0xff, 0xff, 0x00, 0x00, /* Logical maximum (65535) */ - 0x35, 0x00, /* Physical minimum (0) */ - 0x47, 0xff, 0xff, 0x00, 0x00, /* Physical maximum (65535) */ - 0x75, 0x10, /* Report size (16) */ - 0x95, 0x01, /* Report count (1) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - /* gas */ - 0x09, 0x31, /* Usage (Y) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - /* brake */ - 0x09, 0x32, /* Usage (Z) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - /* clutch */ - 0x09, 0x35, /* Usage (Rz) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - /* stick shifter (check model no) */ - 0x05, 0x09, /* Usage page (Button) */ - 0x19, 0x0f, /* Usage minimum (15) */ - 0x29, 0x17, /* Usage maximum (23) */ - 0x15, 0x00, /* Logical minimum (1) */ - 0x25, 0x01, /* Logical maximum (1) */ - 0x75, 0x01, /* Report size (1) */ - 0x95, 0x08, /* Report count (8) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - /* no clue */ - 0x05, 0x01, /* Usage page (Generic Desktop) */ - 0x09, 0x00, /* Usage (U) */ - 0x75, 0x08, /* Report size (8) */ - 0x95, 0x0c, /* Report count (12) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - /* continue unmodified */ - 0x06, 0x00, 0xff, /* Usage page (Vendor defined 1) */ - 0x85, 0x60, /* Report ID (5) (change to 0x60?) */ - 0x09, 0x60, /* Usage (34) (change to 0x60?) */ - 0x95, 0x1f, /* Report count (31) () */ - 0x91, 0x02, /* Output (Variable, Absolute) */ - 0x85, 0x03, /* Report ID (3) */ - 0x0a, 0x21, 0x27, /* ??? */ - 0x95, 0x2f, /* Report count (47) */ - 0xb1, 0x02, /* Feature (Data, Var, Abs) */ - 0xc0, /* End collection */ - - /* From here on out no clue */ - 0x06, 0xf0, - 0xff, 0x09, - 0x40, 0xa1, - 0x01, 0x85, - 0xf0, 0x09, - 0x47, 0x95, - 0x3f, 0xb1, - 0x02, 0x85, - 0xf1, 0x09, - 0x48, 0x95, - 0x3f, 0xb1, - 0x02, 0x85, - 0xf2, 0x09, - 0x49, 0x95, - 0x0f, 0xb1, - 0x02, 0x85, - 0xf3, 0x0a, - 0x01, 0x47, - 0x95, 0x07, - 0xb1, 0x02, - 0xc0, -}; - -static u8 spring_values[] = { - 0xa6, 0x6a, 0xa6, 0x6a, 0xfe, - 0xff, 0xfe, 0xff, 0xfe, 0xff, - 0xfe, 0xff, 0xdf, 0x58, 0xa6, - 0x6a, 0x06 -}; - -static u8 damper_values[] = { - 0xfc, 0x7f, 0xfc, 0x7f, 0xfe, - 0xff, 0xfe, 0xff, 0xfe, 0xff, - 0xfe, 0xff, 0xfc, 0x7f, 0xfc, - 0x7f, 0x07 -}; - -int t300rs_send_buf(struct t300rs_device_entry *t300rs, u8 *send_buffer, size_t len) -{ - int i; - /* check that send_buffer fits into our report */ - if (len > t300rs->buffer_length) - return -EINVAL; - - /* fill with actual data */ - for (i = 0; i < len; ++i) - t300rs->ff_field->value[i] = send_buffer[i]; - - /* fill the rest with zeroes */ - for (i = len; i < t300rs->buffer_length; ++i) - t300rs->ff_field->value[i] = 0; - - hid_hw_request(t300rs->hdev, t300rs->report, HID_REQ_SET_REPORT); - return 0; -} - -int t300rs_send_int(struct t300rs_device_entry *t300rs) -{ - t300rs_send_buf(t300rs, t300rs->send_buffer, t300rs->buffer_length); - memset(t300rs->send_buffer, 0, t300rs->buffer_length); - - return 0; -} - -static void t300rs_fill_header(struct t300rs_packet_header *packet_header, - uint8_t id, uint8_t code) -{ - packet_header->id = id + 1; - packet_header->code = code; -} - -int t300rs_play_effect(void *data, struct tmff2_effect_state *state) -{ - struct t300rs_device_entry *t300rs = data; - struct __packed t300rs_packet_play { - struct t300rs_packet_header header; - uint8_t value; - } *play_packet = (struct t300rs_packet_play *)t300rs->send_buffer; - - int ret; - - - t300rs_fill_header(&play_packet->header, state->effect.id, 0x89); - play_packet->value = 0x01; - - ret = t300rs_send_int(t300rs); - if (ret) - hid_err(t300rs->hdev, "failed starting effect play\n"); - - return ret; -} - -int t300rs_stop_effect(void *data, struct tmff2_effect_state *state) -{ - struct t300rs_device_entry *t300rs = data; - struct __packed t300rs_packet_stop { - struct t300rs_packet_header header; - uint8_t value; - } *stop_packet = (struct t300rs_packet_stop *)t300rs->send_buffer; - - int ret; - - - t300rs_fill_header(&stop_packet->header, state->effect.id, 0x89); - - ret = t300rs_send_int(t300rs); - if (ret) - hid_err(t300rs->hdev, "failed stopping effect play\n"); - - return ret; -} - -static void t300rs_fill_envelope(struct t300rs_packet_envelope *packet_envelope, - int16_t level, uint16_t duration, struct ff_envelope *envelope) -{ - uint16_t attack_length = (duration * envelope->attack_length) / 0x7fff; - uint16_t attack_level = (level * envelope->attack_level) / 0x7fff; - uint16_t fade_length = (duration * envelope->fade_length) / 0x7fff; - uint16_t fade_level = (level * envelope->fade_level) / 0x7fff; - - packet_envelope->attack_length = cpu_to_le16(attack_length); - packet_envelope->attack_level = cpu_to_le16(attack_level); - packet_envelope->fade_length = cpu_to_le16(fade_length); - packet_envelope->fade_level = cpu_to_le16(fade_level); -} - -static void t300rs_fill_timing(struct t300rs_packet_timing *packet_timing, - uint16_t duration, uint16_t offset){ - packet_timing->start_marker = 0x4f; - - packet_timing->duration = cpu_to_le16(duration); - packet_timing->offset = cpu_to_le16(offset); - - packet_timing->end_marker = 0xffff; -} - -static int t300rs_update_envelope(struct t300rs_device_entry *t300rs, - struct tmff2_effect_state *state, - int16_t level, - uint16_t duration, - uint8_t id, - struct ff_envelope envelope, - struct ff_envelope envelope_old - ) -{ - struct __packed t300rs_packet_mod_envelope { - struct t300rs_packet_header header; - uint8_t attribute; - uint16_t value; - } *packet_mod_envelope = (struct t300rs_packet_mod_envelope *)t300rs->send_buffer; - - uint16_t attack_length, attack_level, fade_length, fade_level; - int ret = 0; - - duration = duration - 1; - - 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; - - if (envelope.attack_length != envelope_old.attack_length) { - t300rs_fill_header(&packet_mod_envelope->header, id, 0x31); - packet_mod_envelope->attribute = 0x81; - packet_mod_envelope->value = cpu_to_le16(attack_length); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying effect envelope\n"); - goto error; - } - } - - if (envelope.attack_level != envelope_old.attack_level) { - t300rs_fill_header(&packet_mod_envelope->header, id, 0x31); - packet_mod_envelope->attribute = 0x82; - packet_mod_envelope->value = cpu_to_le16(attack_level); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying effect envelope\n"); - goto error; - } - } - - if (envelope.fade_length != envelope_old.fade_length) { - t300rs_fill_header(&packet_mod_envelope->header, id, 0x31); - packet_mod_envelope->attribute = 0x84; - packet_mod_envelope->value = cpu_to_le16(fade_length); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying effect envelope\n"); - goto error; - } - } - - if (envelope.fade_level != envelope_old.fade_level) { - t300rs_fill_header(&packet_mod_envelope->header, id, 0x31); - packet_mod_envelope->attribute = 0x88; - packet_mod_envelope->value = cpu_to_le16(fade_level); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying effect envelope\n"); - goto error; - } - } - -error: - return ret; -} - -static int t300rs_update_simple_duration(struct t300rs_device_entry *t300rs, - struct tmff2_effect_state *state, unsigned type) -{ - struct ff_effect effect = state->effect; - struct __packed t300rs_packet_mod_duration { - struct t300rs_packet_header header; - uint16_t marker; - uint16_t duration; - } *packet_mod_duration = (struct t300rs_packet_mod_duration *)t300rs->send_buffer; - - uint16_t duration; - int ret = 0; - - duration = effect.replay.length - 1; - - t300rs_fill_header(&packet_mod_duration->header, effect.id, 0x49); - packet_mod_duration->marker = cpu_to_le16(0x4100 + type); - packet_mod_duration->duration = cpu_to_le16(duration); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying duration\n"); - goto error; - } - -error: - return ret; -} - -static int t300rs_update_periodic_duration(struct t300rs_device_entry *t300rs, - struct tmff2_effect_state *state, unsigned type) -{ - struct ff_effect effect = state->effect; - struct __packed t300rs_packet_mod_duration { - struct t300rs_packet_header header; - uint8_t type; - uint8_t marker; - uint16_t duration; - } *packet_mod_duration = (struct t300rs_packet_mod_duration *)t300rs->send_buffer; - - uint16_t duration; - int ret = 0; - - duration = effect.replay.length - 1; - - t300rs_fill_header(&packet_mod_duration->header, effect.id, 0x49); - packet_mod_duration->type = type; - packet_mod_duration->marker = 0x41; - packet_mod_duration->duration = cpu_to_le16(duration); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying duration\n"); - goto error; - } - -error: - return ret; -} - -static int t300rs_update_ramp_duration(struct t300rs_device_entry *t300rs, - struct tmff2_effect_state *state) -{ - struct ff_effect effect = state->effect; - struct __packed t300rs_packet_mod_duration { - struct t300rs_packet_header header; - uint8_t marker0; - uint16_t duration0; - uint8_t marker1; - uint8_t marker2; - uint16_t duration1; - } *packet_mod_duration = (struct t300rs_packet_mod_duration *)t300rs->send_buffer; - - uint16_t duration; - int ret = 0; - - duration = effect.replay.length - 1; - - t300rs_fill_header(&packet_mod_duration->header, effect.id, 0x4e); - packet_mod_duration->marker0 = 0x08; - packet_mod_duration->duration0 = cpu_to_le16(duration); - packet_mod_duration->marker1 = 0x05; - packet_mod_duration->marker2 = 0x41; - packet_mod_duration->duration1 = cpu_to_le16(duration); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying duration\n"); - goto error; - } - -error: - return ret; -} - -static int t300rs_update_constant(struct t300rs_device_entry *t300rs, - struct tmff2_effect_state *state) -{ - 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 __packed t300rs_packet_mod_constant { - struct t300rs_packet_header header; - uint16_t level; - } *packet_mod_constant = (struct t300rs_packet_mod_constant *)t300rs->send_buffer; - int ret; - int16_t level; - - level = (constant.level * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; - - if ((constant.level != constant_old.level) || (effect.direction != old.direction)) { - - t300rs_fill_header(&packet_mod_constant->header, effect.id, 0x0a); - packet_mod_constant->level = cpu_to_le16(level); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying constant effect\n"); - goto error; - } - - } - - ret = t300rs_update_envelope(t300rs, - state, - level, - effect.replay.length, - effect.id, - constant.envelope, - constant_old.envelope - ); - - if (ret) { - hid_err(t300rs->hdev, "failed modifying constant envelope\n"); - goto error; - } - - ret = t300rs_update_simple_duration(t300rs, state, 0x00); - if (ret) { - hid_err(t300rs->hdev, "failed modifying constant duration\n"); - goto error; - } - -error: - return ret; -} - -static int t300rs_update_ramp(struct t300rs_device_entry *t300rs, - struct tmff2_effect_state *state) -{ - struct ff_effect effect = state->effect; - struct ff_effect old = state->old; - struct ff_ramp_effect ramp = effect.u.ramp; - struct ff_ramp_effect ramp_old = old.u.ramp; - struct __packed t300rs_packet_mod_ramp { - struct t300rs_packet_header header; - uint8_t attribute; - uint16_t difference; - uint16_t level; - } *packet_mod_ramp = (struct t300rs_packet_mod_ramp *)t300rs->send_buffer; - - int ret; - - uint16_t difference, top, bottom; - int16_t level; - - top = ramp.end_level > ramp.start_level ? ramp.end_level : ramp.start_level; - bottom = ramp.end_level > ramp.start_level ? ramp.start_level : ramp.end_level; - - - difference = ((top - bottom) * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; - - - level = (top * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; - - if ((ramp.start_level != ramp_old.start_level) - || (ramp.end_level != ramp_old.end_level) - || (effect.direction != old.direction)) { - - t300rs_fill_header(&packet_mod_ramp->header, effect.id, 0x0e); - packet_mod_ramp->attribute = 0x03; - packet_mod_ramp->difference = cpu_to_le16(difference); - packet_mod_ramp->level = cpu_to_le16(level); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying ramp effect\n"); - goto error; - } - - } - - ret = t300rs_update_envelope(t300rs, - state, - level, - effect.replay.length, - effect.id, - ramp.envelope, - ramp_old.envelope - ); - - - if (ret) { - hid_err(t300rs->hdev, "failed modifying ramp envelope\n"); - goto error; - } - - ret = t300rs_update_ramp_duration(t300rs, state); - if (ret) { - hid_err(t300rs->hdev, "failed modifying ramp duration\n"); - goto error; - } - -error: - return ret; -} - -static int t300rs_update_damper(struct t300rs_device_entry *t300rs, - struct tmff2_effect_state *state) -{ - 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]; - struct __packed t300rs_packet_mod_damper { - struct t300rs_packet_header header; - uint8_t attribute; - uint16_t value0; - uint16_t value1; - } *packet_mod_damper = (struct t300rs_packet_mod_damper *)t300rs->send_buffer; - - int ret, input_level; - - input_level = damper_level; - if (state->effect.type == FF_FRICTION) - input_level = friction_level; - - if (state->effect.type == FF_SPRING) - input_level = spring_level; - - if (damper.right_coeff != damper_old.right_coeff) { - int16_t coeff = damper.right_coeff * input_level / 100; - - t300rs_fill_header(&packet_mod_damper->header, effect.id, 0x0e); - packet_mod_damper->attribute = 0x41; - packet_mod_damper->value0 = cpu_to_le16(coeff); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying damper rc\n"); - goto error; - } - - } - - if (damper.left_coeff != damper_old.left_coeff) { - int16_t coeff = damper.left_coeff * input_level / 100; - - t300rs_fill_header(&packet_mod_damper->header, effect.id, 0x0e); - packet_mod_damper->attribute = 0x42; - packet_mod_damper->value0 = cpu_to_le16(coeff); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying damper lc\n"); - goto error; - } - - } - - if ((damper.deadband != damper_old.deadband) - || (damper.center != damper_old.center)) { - - uint16_t right_deadband = 0xfffe - damper.deadband - damper.center; - uint16_t left_deadband = 0xfffe - damper.deadband + damper.center; - - t300rs_fill_header(&packet_mod_damper->header, effect.id, 0x0e); - packet_mod_damper->attribute = 0x4c; - packet_mod_damper->value0 = cpu_to_le16(right_deadband); - packet_mod_damper->value1 = cpu_to_le16(left_deadband); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying damper deadband\n"); - goto error; - } - - } - - ret = t300rs_update_simple_duration(t300rs, state, 0x06); - if (ret) { - hid_err(t300rs->hdev, "failed modifying damper duration\n"); - goto error; - } - -error: - return ret; -} - -static int t300rs_update_spring(struct t300rs_device_entry *t300rs, - struct tmff2_effect_state *state) -{ - return t300rs_update_damper(t300rs, state); -} - - -static int t300rs_update_periodic(struct t300rs_device_entry *t300rs, - struct tmff2_effect_state *state) -{ - 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 __packed t300rs_packet_mod_periodic { - struct t300rs_packet_header header; - uint8_t attribute; - uint16_t value; - } *packet_mod_periodic = (struct t300rs_packet_mod_periodic *)t300rs->send_buffer; - - int ret; - int16_t magnitude, phase; - - magnitude = (periodic.magnitude * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; - phase = periodic.phase; - - if ((periodic.magnitude != periodic_old.magnitude) - || (effect.direction != old.direction)) { - - t300rs_fill_header(&packet_mod_periodic->header, effect.id, 0x0e); - packet_mod_periodic->attribute = 0x01; - packet_mod_periodic->value = cpu_to_le16(magnitude); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying periodic magnitude\n"); - goto error; - } - - } - - if (periodic.offset != periodic_old.offset) { - uint16_t offset = periodic.offset; - - t300rs_fill_header(&packet_mod_periodic->header, effect.id, 0x0e); - packet_mod_periodic->attribute = 0x02; - packet_mod_periodic->value = cpu_to_le16(offset); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying periodic offset\n"); - goto error; - } - - } - - if (periodic.phase != periodic_old.phase) { - - t300rs_fill_header(&packet_mod_periodic->header, effect.id, 0x0e); - packet_mod_periodic->attribute = 0x04; - packet_mod_periodic->value = cpu_to_le16(phase); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying periodic phase\n"); - goto error; - } - - } - - if (periodic.period != periodic_old.period) { - int16_t period = periodic.period; - - t300rs_fill_header(&packet_mod_periodic->header, effect.id, 0x0e); - packet_mod_periodic->attribute = 0x08; - packet_mod_periodic->value = cpu_to_le16(period); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying periodic period\n"); - goto error; - } - - } - - ret = t300rs_update_envelope(t300rs, - state, - magnitude, - effect.replay.length, - effect.id, - periodic.envelope, - periodic_old.envelope - ); - - if (ret) { - hid_err(t300rs->hdev, "failed modifying periodic envelope\n"); - goto error; - } - - ret = t300rs_update_periodic_duration(t300rs, state, periodic.waveform - 0x57); - if (ret) { - hid_err(t300rs->hdev, "failed modifying periodic duration\n"); - goto error; - } - -error: - return ret; -} - -static int t300rs_upload_constant(struct t300rs_device_entry *t300rs, - struct tmff2_effect_state *state) -{ - struct ff_effect effect = state->effect; - struct ff_constant_effect constant = state->effect.u.constant; - struct __packed t300rs_packet_constant { - struct t300rs_packet_header header; - uint16_t level; - struct t300rs_packet_envelope envelope; - uint8_t zero; - struct t300rs_packet_timing timing; - } *packet_constant = (struct t300rs_packet_constant *)t300rs->send_buffer; - - int16_t level; - uint16_t duration, offset; - - int ret; - - level = (constant.level * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; - duration = effect.replay.length - 1; - - offset = effect.replay.delay; - - t300rs_fill_header(&packet_constant->header, effect.id, 0x6a); - - packet_constant->level = cpu_to_le16(level); - - t300rs_fill_envelope(&packet_constant->envelope, level, duration, - &constant.envelope); - t300rs_fill_timing(&packet_constant->timing, duration, offset); - - ret = t300rs_send_int(t300rs); - if (ret) - hid_err(t300rs->hdev, "failed uploading constant effect\n"); - - return ret; -} - -static int t300rs_upload_ramp(struct t300rs_device_entry *t300rs, - struct tmff2_effect_state *state) -{ - struct ff_effect effect = state->effect; - struct ff_ramp_effect ramp = state->effect.u.ramp; - struct __packed t300rs_packet_ramp { - struct t300rs_packet_header header; - uint16_t difference; - uint16_t level; - uint8_t zero1[2]; - uint16_t duration; - uint16_t marker; - struct t300rs_packet_envelope envelope; - uint8_t direction; - struct t300rs_packet_timing timing; - } *packet_ramp = (struct t300rs_packet_ramp *)t300rs->send_buffer; - - int ret; - uint16_t difference, offset, top, bottom, duration; - int16_t level; - - duration = effect.replay.length - 1; - - top = ramp.end_level > ramp.start_level ? ramp.end_level : ramp.start_level; - bottom = ramp.end_level > ramp.start_level ? ramp.start_level : ramp.end_level; - - - difference = ((top - bottom) * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; - level = (top * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; - offset = effect.replay.delay; - - - t300rs_fill_header(&packet_ramp->header, effect.id, 0x6b); - - packet_ramp->difference = cpu_to_le16(difference); - packet_ramp->level = cpu_to_le16(level); - packet_ramp->duration = cpu_to_le16(duration); - - packet_ramp->marker = cpu_to_le16(0x8000); - - t300rs_fill_envelope(&packet_ramp->envelope, level, duration, - &ramp.envelope); - - packet_ramp->direction = ramp.end_level > ramp.start_level ? 0x04 : 0x05; - t300rs_fill_timing(&packet_ramp->timing, duration, offset); - - ret = t300rs_send_int(t300rs); - if (ret) - hid_err(t300rs->hdev, "failed uploading ramp"); - - return ret; -} - -static int t300rs_upload_spring(struct t300rs_device_entry *t300rs, - struct tmff2_effect_state *state) -{ - struct ff_effect effect = state->effect; - /* we only care about the first axis */ - struct ff_condition_effect spring = state->effect.u.condition[0]; - struct __packed t300rs_packet_spring { - struct t300rs_packet_header header; - uint16_t right_coeff; - uint16_t left_coeff; - uint16_t right_deadband; - uint16_t left_deadband; - uint8_t spring_start[17]; - struct t300rs_packet_timing timing; - } *packet_spring = (struct t300rs_packet_spring *)t300rs->send_buffer; - - int ret; - uint16_t duration, right_coeff, left_coeff, right_deadband, left_deadband, offset; - - duration = effect.replay.length - 1; - - right_coeff = spring.right_coeff * spring_level / 100; - left_coeff = spring.left_coeff * spring_level / 100; - - right_deadband = 0xfffe - spring.deadband - spring.center; - left_deadband = 0xfffe - spring.deadband + spring.center; - - offset = effect.replay.delay; - - t300rs_fill_header(&packet_spring->header, effect.id, 0x64); - - packet_spring->right_coeff = cpu_to_le16(right_coeff); - packet_spring->left_coeff = cpu_to_le16(left_coeff); - packet_spring->right_deadband = cpu_to_le16(right_deadband); - packet_spring->left_deadband = cpu_to_le16(left_deadband); - - memcpy(&packet_spring->spring_start, spring_values, ARRAY_SIZE(spring_values)); - t300rs_fill_timing(&packet_spring->timing, duration, offset); - - ret = t300rs_send_int(t300rs); - if (ret) - hid_err(t300rs->hdev, "failed uploading spring\n"); - - return ret; -} - -static int t300rs_upload_damper(struct t300rs_device_entry *t300rs, - struct tmff2_effect_state *state) -{ - - struct ff_effect effect = state->effect; - /* we only care about the first axis */ - struct ff_condition_effect spring = state->effect.u.condition[0]; - struct __packed t300rs_packet_damper { - struct t300rs_packet_header header; - uint16_t right_coeff; - uint16_t left_coeff; - uint16_t right_deadband; - uint16_t left_deadband; - uint8_t damper_start[17]; - struct t300rs_packet_timing timing; - } *packet_damper = (struct t300rs_packet_damper *)t300rs->send_buffer; - - int ret, input_level; - uint16_t duration, right_coeff, left_coeff, right_deadband, left_deadband, offset; - - duration = effect.replay.length - 1; - - input_level = damper_level; - if (state->effect.type == FF_FRICTION) - input_level = friction_level; - - right_coeff = spring.right_coeff * input_level / 100; - left_coeff = spring.left_coeff * input_level / 100; - - right_deadband = 0xfffe - spring.deadband - spring.center; - left_deadband = 0xfffe - spring.deadband + spring.center; - - offset = effect.replay.delay; - - t300rs_fill_header(&packet_damper->header, effect.id, 0x64); - - packet_damper->right_coeff = cpu_to_le16(right_coeff); - packet_damper->left_coeff = cpu_to_le16(left_coeff); - packet_damper->right_deadband = cpu_to_le16(right_deadband); - packet_damper->left_deadband = cpu_to_le16(left_deadband); - - memcpy(&packet_damper->damper_start, damper_values, ARRAY_SIZE(damper_values)); - t300rs_fill_timing(&packet_damper->timing, duration, offset); - - ret = t300rs_send_int(t300rs); - if (ret) - hid_err(t300rs->hdev, "failed uploading spring\n"); - - return ret; -} - -static int t300rs_upload_periodic(struct t300rs_device_entry *t300rs, - struct tmff2_effect_state *state) -{ - struct ff_effect effect = state->effect; - struct ff_periodic_effect periodic = state->effect.u.periodic; - struct __packed t300rs_packet_periodic { - struct t300rs_packet_header header; - uint16_t magnitude; - uint16_t periodic_offset; - uint16_t phase; - uint16_t period; - uint16_t marker; - struct t300rs_packet_envelope envelope; - uint8_t waveform; - struct t300rs_packet_timing timing; - } *packet_periodic = (struct t300rs_packet_periodic *)t300rs->send_buffer; - - int ret; - uint16_t duration, period, offset, periodic_offset; - int16_t phase, magnitude; - - duration = effect.replay.length - 1; - magnitude = (periodic.magnitude * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; - - phase = periodic.phase; - periodic_offset = periodic.offset; - - period = periodic.period; - offset = effect.replay.delay; - - t300rs_fill_header(&packet_periodic->header, effect.id, 0x6b); - - packet_periodic->magnitude = cpu_to_le16(magnitude); - packet_periodic->periodic_offset = cpu_to_le16(periodic_offset); - packet_periodic->phase = cpu_to_le16(phase); - packet_periodic->period = cpu_to_le16(period); - - packet_periodic->marker = cpu_to_le16(0x8000); - - t300rs_fill_envelope(&packet_periodic->envelope, magnitude, duration, - &periodic.envelope); - - packet_periodic->waveform = periodic.waveform - 0x57; - - t300rs_fill_timing(&packet_periodic->timing, duration, offset); - - ret = t300rs_send_int(t300rs); - if (ret) - hid_err(t300rs->hdev, "failed uploading periodic effect"); - - return ret; -} - -int t300rs_update_effect(void *data, struct tmff2_effect_state *state) -{ - struct t300rs_device_entry *t300rs = data; - switch (state->effect.type) { - case FF_CONSTANT: - return t300rs_update_constant(t300rs, state); - case FF_RAMP: - return t300rs_update_ramp(t300rs, state); - case FF_SPRING: - return t300rs_update_spring(t300rs, state); - case FF_DAMPER: - case FF_FRICTION: - case FF_INERTIA: - return t300rs_update_damper(t300rs, state); - case FF_PERIODIC: - return t300rs_update_periodic(t300rs, state); - default: - hid_err(t300rs->hdev, "invalid effect type: %x", state->effect.type); - return -1; - } -} - -int t300rs_upload_effect(void *data, struct tmff2_effect_state *state) -{ - struct t300rs_device_entry *t300rs = data; - switch (state->effect.type) { - case FF_CONSTANT: - return t300rs_upload_constant(t300rs, state); - case FF_RAMP: - return t300rs_upload_ramp(t300rs, state); - case FF_SPRING: - return t300rs_upload_spring(t300rs, state); - case FF_DAMPER: - case FF_FRICTION: - case FF_INERTIA: - return t300rs_upload_damper(t300rs, state); - case FF_PERIODIC: - return t300rs_upload_periodic(t300rs, state); - default: - hid_err(t300rs->hdev, "invalid effect type: %x", state->effect.type); - return -1; - } -} - -static int t300rs_switch_mode(void *data, uint16_t mode) -{ - struct t300rs_device_entry *t300rs = data; - if (!t300rs) - return -ENODEV; - - if(t300rs->mode == mode) /* already in specified mode */ - return 0; - - if (mode == 0) - /* go to normal mode */ - usb_control_msg(t300rs->usbdev, - usb_sndctrlpipe(t300rs->usbdev, 0), - 83, 0x41, 5, 0, 0, 0, - USB_CTRL_SET_TIMEOUT - ); - else if (mode == 1) - /* go to advanced mode */ - usb_control_msg(t300rs->usbdev, - usb_sndctrlpipe(t300rs->usbdev, 0), - 83, 0x41, 3, 0, 0, 0, - USB_CTRL_SET_TIMEOUT - ); - else - hid_warn(t300rs->hdev, "mode %i not supported\n", mode); - - - return 0; -} - -static struct t300rs_alt_modes { - char *id; - char *label; - uint16_t mode; -} t300rs_modes[] = { - {"base", "T300RS base", 0}, - {"F1", "T300RS with F1 wheel attachment", 1} -}; - -static ssize_t t300rs_alt_mode_show(void *data, char *buf) -{ - struct t300rs_device_entry *t300rs = data; - ssize_t count = 0; - int i; - if (!t300rs) - return -ENODEV; - - if (t300rs->attachment != T300RS_F1_ATTACHMENT) - /* we only support one base mode */ - return scnprintf(buf, PAGE_SIZE, "%s: %s *\n", - t300rs_modes[0].id, t300rs_modes[0].label); - - for (i = 0; i < ARRAY_SIZE(t300rs_modes); ++i) { - count += scnprintf(buf + count, PAGE_SIZE - count, "%s: %s", - t300rs_modes[i].id, t300rs_modes[i].label); - - if (count >= PAGE_SIZE - 1) - return count; - - if (t300rs_modes[i].mode == t300rs->mode) - count += scnprintf(buf + count, PAGE_SIZE - count, " *\n"); - else - count += scnprintf(buf + count, PAGE_SIZE - count, "\n"); - - if (count >= PAGE_SIZE - 1) - return count; - } - - return count; -} - -static ssize_t t300rs_alt_mode_store(void *data, const char *buf, size_t count) -{ - struct t300rs_device_entry *t300rs = data; - int i, len, mode_len; - char *lbuf; - if (!t300rs) - return -ENODEV; - - if (t300rs->attachment != T300RS_F1_ATTACHMENT) - return count; /* don't do anything */ - - lbuf = kasprintf(GFP_KERNEL, "%s", buf); - if (!lbuf) - return -ENOMEM; - - len = strlen(buf); - for (i = 0; i < ARRAY_SIZE(t300rs_modes); ++i) { - mode_len = strlen(t300rs_modes[i].id); - if (mode_len > len) - continue; - - if (strncmp(lbuf, t300rs_modes[i].id, mode_len) == 0) { - t300rs_switch_mode(data, t300rs_modes[i].mode); - break; - } - } - - kfree(lbuf); - return count; -} - -int t300rs_set_autocenter(void *data, uint16_t value) -{ - struct t300rs_device_entry *t300rs = data; - struct __packed t300rs_packet_autocenter { - struct t300rs_setup_header header; - uint16_t value; - } *autocenter_packet; - int ret; - - if (!t300rs) - return -ENODEV; - - /* TODO: this should probably also use a separately allocated buffer? */ - autocenter_packet = (struct t300rs_packet_autocenter *)t300rs->send_buffer; - - autocenter_packet->header.cmd = 0x08; - autocenter_packet->header.code = 0x04; - autocenter_packet->value = cpu_to_le16(0x01); - - if ((ret = t300rs_send_int(t300rs))) { - hid_err(t300rs->hdev, "failed setting autocenter"); - return ret; - } - - autocenter_packet->header.cmd = 0x08; - autocenter_packet->header.code = 0x03; - - autocenter_packet->value = cpu_to_le16(value); - - if ((ret = t300rs_send_int(t300rs))) - hid_err(t300rs->hdev, "failed setting autocenter"); - - return ret; -} - -int t300rs_set_gain(void *data, uint16_t gain) -{ - struct t300rs_device_entry *t300rs = data; - struct __packed t300rs_packet_gain { - struct t300rs_setup_header header; - } *gain_packet; - int ret; - - if (!t300rs) - return -ENODEV; - - gain_packet = (struct t300rs_packet_gain *)t300rs->send_buffer; - gain_packet->header.cmd = 0x02; - gain_packet->header.code = (gain >> 8) & 0xff; - - if ((ret = t300rs_send_int(t300rs))) - hid_err(t300rs->hdev, "failed setting gain: %i\n", ret); - - return ret; -} - -int t300rs_set_range(void *data, uint16_t value) -{ - struct t300rs_device_entry *t300rs = data; - /* it's important that we don't use t300rs->send_buffer, as range can be - * set from outside of the FFB environment, and we don't want to - * accidentally overwrite any data. */ - u8 *send_buffer = kzalloc(t300rs->buffer_length, GFP_KERNEL); - uint16_t scaled_value; - int ret; - - if (value < 40) { - hid_info(t300rs->hdev, "value %i too small, clamping to 40\n", value); - value = 40; - } - - if (value > 1080) { - hid_info(t300rs->hdev, "value %i too large, clamping to 1080\n", value); - value = 1080; - } - - if (!send_buffer) { - ret = -EINVAL; - hid_err(t300rs->hdev, "could not allocate send_buffer\n"); - goto err; - } - - scaled_value = value * 0x3c; - send_buffer[0] = 0x08; - send_buffer[1] = 0x11; - send_buffer[2] = scaled_value & 0xff; - send_buffer[3] = scaled_value >> 8; - - if ((ret = t300rs_send_buf(t300rs, send_buffer, t300rs->buffer_length))) - hid_warn(t300rs->hdev, "failed setting range\n"); - - /* since everythin went OK, update the current range */ - range = value; -err: - kfree(send_buffer); - return ret; -} - -static int t300rs_send_open(struct t300rs_device_entry *t300rs) -{ - struct __packed t300rs_packet_open { - struct t300rs_setup_header header; - } *open_packet; - - open_packet = (struct t300rs_packet_open *)t300rs->send_buffer; - open_packet->header.cmd = 0x01; - open_packet->header.code = 0x05; - - return t300rs_send_int(t300rs); -} - -static int t300rs_send_close(struct t300rs_device_entry *t300rs) -{ - struct __packed t300rs_packet_open { - struct t300rs_setup_header header; - } *open_packet; - - open_packet = (struct t300rs_packet_open *)t300rs->send_buffer; - open_packet->header.cmd = 0x01; - - return t300rs_send_int(t300rs); -} - -int t300rs_open(void *data, int open_mode) -{ - struct t300rs_device_entry *t300rs = data; - if (!t300rs) - return -ENODEV; - - if (open_mode && t300rs_send_open(t300rs)) - hid_warn(t300rs->hdev, "failed sending open command\n"); - - return t300rs->open(t300rs->input_dev); -} - -int t300rs_close(void *data, int open_mode) -{ - struct t300rs_device_entry *t300rs = data; - int ret; - - if (!t300rs) - return -ENODEV; - - if (open_mode && (ret = t300rs_send_close(t300rs))) - hid_warn(t300rs->hdev, "failed sending close command\n"); - - t300rs->close(t300rs->input_dev); - return ret; -} - -static int t300rs_check_firmware(struct t300rs_device_entry *t300rs) -{ - int ret; - struct t300rs_fw_response *fw_response = - kzalloc(sizeof(struct t300rs_fw_response), GFP_KERNEL); - - if (!fw_response) { - hid_err(t300rs->hdev, "could not allocate fw_response\n"); - return -ENOMEM; - } - - /* Fetch firmware version */ - ret = usb_control_msg(t300rs->usbdev, - usb_rcvctrlpipe(t300rs->usbdev, 0), - t300rs_fw_request.bRequest, - t300rs_fw_request.bRequestType, - t300rs_fw_request.wValue, - t300rs_fw_request.wIndex, - fw_response, - t300rs_fw_request.wLength, - USB_CTRL_SET_TIMEOUT - ); - - if (ret < 0) { - hid_err(t300rs->hdev, "could not fetch firmware version: %i\n", ret); - goto out; - } - - /* Educated guess */ - if (fw_response->fw_version < 31 && ret >= 0) { - hid_err(t300rs->hdev, - "firmware version %i is too old, please update.\n", - fw_response->fw_version - ); - - hid_info(t300rs->hdev, "note: this has to be done through Windows.\n"); - - ret = -EINVAL; - goto out; - } - - /* everything OK */ - ret = 0; - -out: - kfree(fw_response); - return ret; -} - -static int t300rs_get_attachment(struct t300rs_device_entry *t300rs) -{ - /* taken directly from hid_tminit */ - struct __packed t300rs_attachment_response - { - uint16_t type; - - union { - struct __packed { - uint16_t field0; - uint16_t field1; - uint8_t attachment; - uint8_t model; - uint16_t field2; - uint16_t field3; - uint16_t field4; - uint16_t field5; - } a; - - struct __packed { - uint16_t field0; - uint16_t field1; - uint8_t attachment; - uint8_t model; - } b; - }; - } *response = kzalloc(GFP_KERNEL, sizeof(struct t300rs_attachment_response)); - struct usb_ctrlrequest t300rs_attachment_rq = { - .bRequestType = 0xc1, - .bRequest = 73, - .wValue = 0, - .wIndex = 0, - .wLength = sizeof(struct t300rs_attachment_response) - }; - int ret, attachment; - if (!response) - return -ENODEV; - - ret = usb_control_msg(t300rs->usbdev, - usb_rcvctrlpipe(t300rs->usbdev, 0), - t300rs_attachment_rq.bRequest, - t300rs_attachment_rq.bRequestType, - t300rs_attachment_rq.wValue, - t300rs_attachment_rq.wIndex, - response, - sizeof(struct t300rs_attachment_response), - USB_CTRL_SET_TIMEOUT - ); - - if (ret < 0) { - hid_err(t300rs->hdev, "could not fetch attachment: %i\n", ret); - goto out; - } - - if (response->type == cpu_to_le16(0x49)) { - attachment = response->a.attachment; - } else if (response->type == cpu_to_le16(0x47)) { - attachment = response->b.attachment; - } else { - hid_err(t300rs->hdev, "unknown packet type %hx\n, please contact a maintainer", - response->type); - ret = -EINVAL; - goto out; - } - - kfree(response); - return attachment; - -out: - kfree(response); - return ret; -} - -static int t300rs_wheel_init(struct tmff2_device_entry *tmff2, int open_mode) -{ - struct t300rs_device_entry *t300rs = kzalloc(sizeof(struct t300rs_device_entry), GFP_KERNEL); - struct list_head *report_list; - int ret; - - if (!t300rs) { - ret = -ENOMEM; - goto t300rs_err; - } - - t300rs->hdev = tmff2->hdev; - t300rs->input_dev = tmff2->input_dev; - t300rs->usbdev = to_usb_device(tmff2->hdev->dev.parent->parent); - - if(t300rs->hdev->product == TMT300RS_PS4_NORM_ID) - t300rs->buffer_length = T300RS_PS4_BUFFER_LENGTH; - else - t300rs->buffer_length = T300RS_NORM_BUFFER_LENGTH; - - t300rs->send_buffer = kzalloc(t300rs->buffer_length, GFP_KERNEL); - if (!t300rs->send_buffer) { - ret = -ENOMEM; - goto send_err; - } - - if ((ret = t300rs_check_firmware(t300rs))) - goto firmware_err; - - report_list = &t300rs->hdev->report_enum[HID_OUTPUT_REPORT].report_list; - - /* because we set the rdesc, we know exactly which report and field to use */ - t300rs->report = list_entry(report_list->next, struct hid_report, list); - t300rs->ff_field = t300rs->report->field[0]; - - t300rs->open = t300rs->input_dev->open; - t300rs->close = t300rs->input_dev->close; - - /* TODO: PS4 advanced mode? */ - alt_mode = (t300rs->mode = (t300rs->hdev->product == TMT300RS_PS3_ADV_ID)); - if ((t300rs->attachment = t300rs_get_attachment(t300rs)) < 0) - t300rs->attachment = T300RS_DEFAULT_ATTACHMENT; - - /* everythin went OK */ - tmff2->data = t300rs; - tmff2->params = t300rs_params; - tmff2->max_effects = T300RS_MAX_EFFECTS; - memcpy(tmff2->supported_effects, t300rs_effects, sizeof(t300rs_effects)); - - if (!open_mode) - t300rs_send_open(t300rs); - - hid_info(t300rs->hdev, "force feedback for T300RS\n"); - return 0; - -firmware_err: - kfree(t300rs->send_buffer); -send_err: - kfree(t300rs); -t300rs_err: - hid_err(tmff2->hdev, "failed initializing T300RS\n"); - return ret; -} - -static int t300rs_wheel_destroy(void *data) -{ - struct t300rs_device_entry *t300rs = data; - if (!t300rs) - return -ENODEV; - - kfree(t300rs->send_buffer); - kfree(t300rs); - return 0; -} - -static __u8 *t300rs_wheel_fixup(struct hid_device *hdev, __u8 *rdesc, - unsigned int *rsize) -{ - switch (hdev->product) { - case TMT300RS_PS3_NORM_ID: - /* normal PS3 mode */ - rdesc = t300rs_rdesc_nrm_fixed; - *rsize = sizeof(t300rs_rdesc_nrm_fixed); - break; - - case TMT300RS_PS4_NORM_ID: - /* PS4 normal mode */ - rdesc = t300rs_rdesc_ps4_fixed; - *rsize = sizeof(t300rs_rdesc_ps4_fixed); - break; - - case TMT300RS_PS3_ADV_ID: - /* PS3 advanced mode */ - rdesc = t300rs_rdesc_adv_fixed; - *rsize = sizeof(t300rs_rdesc_adv_fixed); - break; - } - - return rdesc; -} - -int t300rs_populate_api(struct tmff2_device_entry *tmff2) -{ - /* set callbacks */ - tmff2->play_effect = t300rs_play_effect; - tmff2->upload_effect = t300rs_upload_effect; - tmff2->update_effect = t300rs_update_effect; - tmff2->stop_effect = t300rs_stop_effect; - - tmff2->wheel_init = t300rs_wheel_init; - tmff2->wheel_destroy = t300rs_wheel_destroy; - - tmff2->open = t300rs_open; - tmff2->close = t300rs_close; - tmff2->set_gain = t300rs_set_gain; - tmff2->set_range = t300rs_set_range; - tmff2->switch_mode = t300rs_switch_mode; - tmff2->alt_mode_show = t300rs_alt_mode_show; - tmff2->alt_mode_store = t300rs_alt_mode_store; - tmff2->set_autocenter = t300rs_set_autocenter; - tmff2->wheel_fixup = t300rs_wheel_fixup; - - return 0; -} diff --git a/src/hid-tmt300rs/hid-tmt300rs.h b/src/hid-tmt300rs/hid-tmt300rs.h deleted file mode 100644 index 2305f4b..0000000 --- a/src/hid-tmt300rs/hid-tmt300rs.h +++ /dev/null @@ -1,9 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef __HID_TMT300RS_H -#define __HID_TMT300RS_H - -#include "../hid-tmff2.h" - -int t300rs_populate_api(struct tmff2_device_entry *tmff2); - -#endif diff --git a/src/hid-tmtx/hid-tmtx.c b/src/hid-tmtx/hid-tmtx.c deleted file mode 100644 index afca799..0000000 --- a/src/hid-tmtx/hid-tmtx.c +++ /dev/null @@ -1,323 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -#include -#include -#include "../hid-tmff2.h" - -#define TMTX_MAX_EFFECTS 16 -#define TMTX_BUFFER_LENGTH 63 - -static const u8 setup_0[64] = { 0x42, 0x01 }; -static const u8 setup_1[64] = { 0x0a, 0x04, 0x90, 0x03 }; -static const u8 setup_2[64] = { 0x0a, 0x04, 0x00, 0x0c }; -static const u8 setup_3[64] = { 0x0a, 0x04, 0x12, 0x10 }; -static const u8 setup_4[64] = { 0x0a, 0x04, 0x00, 0x06 }; -static const u8 setup_5[64] = { 0x0a, 0x04, 0x00, 0x0e }; -static const u8 setup_6[64] = { 0x0a, 0x04, 0x00, 0x0e, 0x01 }; -static const u8 *const setup_arr[] = { setup_0, setup_1, setup_2, setup_3, setup_4, setup_5, setup_6 }; -static const unsigned int setup_arr_sizes[] = { - ARRAY_SIZE(setup_0), - ARRAY_SIZE(setup_1), - ARRAY_SIZE(setup_2), - ARRAY_SIZE(setup_3), - ARRAY_SIZE(setup_4), - ARRAY_SIZE(setup_5), - ARRAY_SIZE(setup_6) -}; - -static const unsigned long tx_params = - PARAM_SPRING_LEVEL - | PARAM_DAMPER_LEVEL - | PARAM_FRICTION_LEVEL - | PARAM_RANGE - | PARAM_GAIN - ; - -static const signed short tx_effects[] = { - FF_CONSTANT, - FF_RAMP, - FF_SPRING, - FF_DAMPER, - FF_FRICTION, - FF_INERTIA, - FF_PERIODIC, - FF_SINE, - FF_TRIANGLE, - FF_SQUARE, - FF_SAW_UP, - FF_SAW_DOWN, - FF_AUTOCENTER, - FF_GAIN, - -1 -}; - -/* TODO: sort through this stuff */ -static u8 tx_pc_rdesc_fixed[] = { - 0x05, 0x01, /* Usage page (Generic Desktop) */ - 0x09, 0x04, /* Usage (Joystick) */ - 0xa1, 0x01, /* Collection (Application) */ - 0x09, 0x01, /* Usage (Pointer) */ - 0xa1, 0x00, /* Collection (Physical) */ - 0x85, 0x07, /* Report ID (7) */ - 0x09, 0x30, /* Usage (X) */ - 0x15, 0x00, /* Logical minimum (0) */ - 0x27, 0xff, 0xff, 0x00, 0x00, /* Logical maximum (65535) */ - 0x35, 0x00, /* Physical minimum (0) */ - 0x47, 0xff, 0xff, 0x00, 0x00, /* Physical maximum (65535) */ - 0x75, 0x10, /* Report size (16) */ - 0x95, 0x01, /* Report count (1) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x09, 0x35, /* Usage (Rz) (Brake) */ - 0x26, 0xff, 0x03, /* Logical maximum (1023) */ - 0x46, 0xff, 0x03, /* Physical maximum (1023) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x09, 0x32, /* Usage (Z) (Gas) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x09, 0x31, /* Usage (Y) (Clutch) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x81, 0x03, /* Input (Variable, Absolute, Constant) */ - 0x05, 0x09, /* Usage page (Button) */ - 0x19, 0x01, /* Usage minimum (1) */ - 0x29, 0x0d, /* Usage maximum (13) */ - 0x25, 0x01, /* Logical maximum (1) */ - 0x45, 0x01, /* Physical maximum (1) */ - 0x75, 0x01, /* Report size (1) */ - 0x95, 0x0d, /* Report count (13) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x75, 0x0b, /* Report size (13) */ - 0x95, 0x01, /* Report count (1) */ - 0x81, 0x03, /* Usage (Variable, Absolute, Constant) */ - 0x05, 0x01, /* Usage page (Generic Desktop) */ - 0x09, 0x39, /* Usage (Hat Switch) */ - 0x25, 0x07, /* Logical maximum (7) */ - 0x46, 0x3b, 0x01, /* Physical maximum (315) */ - 0x55, 0x00, /* Unit exponent (0) */ - 0x65, 0x14, /* Unit (Eng Rot, Angular Pos) */ - 0x75, 0x04, /* Report size (4) */ - 0x81, 0x42, /* Input (Variable, Absolute, NullState) */ - 0x65, 0x00, /* Unit (None) */ - 0x81, 0x03, /* Input (Variable, Absolute, Constant) */ - 0x85, 0x60, /* Report ID (96), prev 10 */ - 0x06, 0x00, 0xff, /* Usage page (Vendor 1) */ - 0x09, 0x60, /* Usage (96), prev 10 */ - 0x75, 0x08, /* Report size (8) */ - 0x95, 0x3f, /* Report count (63) */ - 0x26, 0xff, 0x7f, /* Logical maximum (32767) */ - 0x15, 0x00, /* Logical minimum (0) */ - 0x46, 0xff, 0x7f, /* Physical maximum (32767) */ - 0x36, 0x00, 0x80, /* Physical minimum (-32768) */ - 0x91, 0x02, /* Output (Variable, Absolute) */ - 0x85, 0x02, /* Report ID (2) */ - 0x09, 0x02, /* Usage (2) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0x09, 0x14, /* Usage (20) */ - 0x85, 0x14, /* Report ID (20) */ - 0x81, 0x02, /* Input (Variable, Absolute) */ - 0xc0, /* End collection */ - 0xc0, /* End collection */ -}; - -static int tx_interrupts(struct t300rs_device_entry *tx) -{ - u8 *send_buf = kmalloc(256, GFP_KERNEL); - struct usb_interface *usbif = to_usb_interface(tx->hdev->dev.parent); - struct usb_host_endpoint *ep; - int ret, trans, b_ep, i; - - if (!send_buf) { - hid_err(tx->hdev, "failed allocating send buffer\n"); - return -ENOMEM; - } - - ep = &usbif->cur_altsetting->endpoint[1]; - b_ep = ep->desc.bEndpointAddress; - - for (i = 0; i < ARRAY_SIZE(setup_arr); ++i) { - memcpy(send_buf, setup_arr[i], setup_arr_sizes[i]); - - ret = usb_interrupt_msg(tx->usbdev, - usb_sndintpipe(tx->usbdev, b_ep), - send_buf, setup_arr_sizes[i], - &trans, - USB_CTRL_SET_TIMEOUT); - - if (ret) { - hid_err(tx->hdev, "setup data couldn't be sent\n"); - goto err; - } - } - -err: - kfree(send_buf); - return ret; -} - -int tx_wheel_destroy(void *data) -{ - struct t300rs_device_entry *t300rs = data; - - if (!t300rs) - return -ENODEV; - - kfree(t300rs->send_buffer); - kfree(t300rs); - return 0; -} - -int tx_set_range(void *data, uint16_t value) -{ - struct t300rs_device_entry *tx = data; - - if (value < 140) { - hid_info(tx->hdev, "value %i too small, clamping to 140\n", value); - value = 140; - } - - if (value > 900) { - hid_info(tx->hdev, "value %i too large, clamping to 900\n", value); - value = 900; - } - - return t300rs_set_range(data, value); -} - -static int tx_send_open(struct t300rs_device_entry *tx) -{ - int r1, r2; - tx->send_buffer[0] = 0x01; - tx->send_buffer[1] = 0x04; - if ((r1 = t300rs_send_int(tx))) - return r1; - - tx->send_buffer[0] = 0x01; - tx->send_buffer[1] = 0x05; - if ((r2 = t300rs_send_int(tx))) - return r2; - - return 0; -} - -static int tx_open(void *data, int open_mode) -{ - struct t300rs_device_entry *tx = data; - - if (!tx) - return -ENODEV; - - if (open_mode) - tx_send_open(tx); - - return tx->open(tx->input_dev); -} - -static int tx_send_close(struct t300rs_device_entry *tx) -{ - int r1, r2; - tx->send_buffer[0] = 0x01; - tx->send_buffer[1] = 0x05; - if ((r1 = t300rs_send_int(tx))) - return r1; - - tx->send_buffer[0] = 0x01; - tx->send_buffer[1] = 0x00; - if ((r2 = t300rs_send_int(tx))) - return r2; - - return 0; -} - -static int tx_close(void *data, int open_mode) -{ - struct t300rs_device_entry *tx = data; - - if (!tx) - return -ENODEV; - - if (open_mode) - tx_send_close(tx); - - tx->close(tx->input_dev); - return 0; -} - -int tx_wheel_init(struct tmff2_device_entry *tmff2, int open_mode) -{ - struct t300rs_device_entry *tx = kzalloc(sizeof(struct t300rs_device_entry), GFP_KERNEL); - struct list_head *report_list; - int ret; - - - if (!tx) { - ret = -ENOMEM; - goto tx_err; - } - - tx->hdev = tmff2->hdev; - tx->input_dev = tmff2->input_dev; - tx->usbdev = to_usb_device(tmff2->hdev->dev.parent->parent); - tx->buffer_length = TMTX_BUFFER_LENGTH; - - tx->send_buffer = kzalloc(tx->buffer_length, GFP_KERNEL); - if (!tx->send_buffer) { - ret = -ENOMEM; - goto send_err; - } - - report_list = &tx->hdev->report_enum[HID_OUTPUT_REPORT].report_list; - tx->report = list_entry(report_list->next, struct hid_report, list); - tx->ff_field = tx->report->field[0]; - - tx->open = tx->input_dev->open; - tx->close = tx->input_dev->close; - - if ((ret = tx_interrupts(tx))) - goto interrupt_err; - - /* everything went OK */ - tmff2->data = tx; - tmff2->params = tx_params; - tmff2->max_effects = TMTX_MAX_EFFECTS; - memcpy(tmff2->supported_effects, tx_effects, sizeof(tx_effects)); - - if (!open_mode) - tx_send_open(tx); - - hid_info(tx->hdev, "force feedback for TX\n"); - return 0; - -interrupt_err: -send_err: - kfree(tx); -tx_err: - hid_err(tmff2->hdev, "failed initializing TX\n"); - return ret; -} - -static __u8 *tx_wheel_fixup(struct hid_device *hdev, __u8 *rdesc, - unsigned int *rsize) -{ - rdesc = tx_pc_rdesc_fixed; - *rsize = sizeof(tx_pc_rdesc_fixed); - return rdesc; -} - -int tx_populate_api(struct tmff2_device_entry *tmff2) -{ - tmff2->play_effect = t300rs_play_effect; - tmff2->upload_effect = t300rs_upload_effect; - tmff2->update_effect = t300rs_update_effect; - tmff2->stop_effect = t300rs_stop_effect; - - tmff2->set_gain = t300rs_set_gain; - tmff2->set_autocenter = t300rs_set_autocenter; - /* TX only has 900 degree range, instead of T300RS 1080 */ - tmff2->set_range = tx_set_range; - tmff2->wheel_fixup = tx_wheel_fixup; - - tmff2->open = tx_open; - tmff2->close = tx_close; - - tmff2->wheel_init = tx_wheel_init; - tmff2->wheel_destroy = tx_wheel_destroy; - - return 0; -} diff --git a/src/tmt248/hid-tmt248.c b/src/tmt248/hid-tmt248.c new file mode 100644 index 0000000..af3aaa9 --- /dev/null +++ b/src/tmt248/hid-tmt248.c @@ -0,0 +1,335 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include +#include "../hid-tmff2.h" + +#define T248_MAX_EFFECTS 16 +#define T248_BUFFER_LENGTH 63 + +static const u8 setup_0[64] = { 0x42, 0x01 }; +static const u8 setup_1[64] = { 0x0a, 0x04, 0x90, 0x03 }; +static const u8 setup_2[64] = { 0x0a, 0x04, 0x00, 0x0c }; +static const u8 setup_3[64] = { 0x0a, 0x04, 0x12, 0x10 }; +static const u8 setup_4[64] = { 0x0a, 0x04, 0x00, 0x06 }; +static const u8 setup_5[64] = { 0x0a, 0x04, 0x00, 0x0e }; +static const u8 setup_6[64] = { 0x0a, 0x04, 0x00, 0x0e, 0x01 }; +static const u8 *const setup_arr[] = { setup_0, setup_1, setup_2, setup_3, setup_4, setup_5, setup_6 }; +static const unsigned int setup_arr_sizes[] = { + ARRAY_SIZE(setup_0), + ARRAY_SIZE(setup_1), + ARRAY_SIZE(setup_2), + ARRAY_SIZE(setup_3), + ARRAY_SIZE(setup_4), + ARRAY_SIZE(setup_5), + ARRAY_SIZE(setup_6) +}; + +static const unsigned long t248_params = + PARAM_SPRING_LEVEL + | PARAM_DAMPER_LEVEL + | PARAM_FRICTION_LEVEL + | PARAM_RANGE + | PARAM_GAIN + ; + +static const signed short t248_effects[] = { + FF_CONSTANT, + FF_RAMP, + FF_SPRING, + FF_DAMPER, + FF_FRICTION, + FF_INERTIA, + FF_PERIODIC, + FF_SINE, + FF_TRIANGLE, + FF_SQUARE, + FF_SAW_UP, + FF_SAW_DOWN, + FF_AUTOCENTER, + FF_GAIN, + -1 +}; + +/* TODO: sort through this stuff */ +static u8 t248_pc_rdesc_fixed[] = { + 0x05, 0x01, /* Usage page (Generic Desktop) */ + 0x09, 0x04, /* Usage (Joystick) */ + 0xa1, 0x01, /* Collection (Application) */ + 0x09, 0x01, /* Usage (Pointer) */ + 0xa1, 0x00, /* Collection (Physical) */ + 0x85, 0x07, /* Report ID (7) */ + 0x09, 0x30, /* Usage (X) */ + 0x15, 0x00, /* Logical minimum (0) */ + 0x27, 0xff, 0xff, 0x00, 0x00, /* Logical maximum (65535) */ + 0x35, 0x00, /* Physical minimum (0) */ + 0x47, 0xff, 0xff, 0x00, 0x00, /* Physical maximum (65535) */ + 0x75, 0x10, /* Report size (16) */ + 0x95, 0x01, /* Report count (1) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x09, 0x31, /* Usage (Y) TODO: clutch? */ + 0x26, 0xff, 0x03, /* Logical maximum (1023) */ + 0x46, 0xff, 0x03, /* Physical maximum (1023) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x09, 0x35, /* Usage (Rz) TODO: brake? */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x09, 0x36, /* Usage (Slider) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x75, 0x08, /* Report size (8) */ + 0x26, 0xff, 0x00, /* Logical maximum (255) */ + 0x46, 0xff, 0x00, /* Physical maximum (255) */ + 0x09, 0x40, /* Usage (Vx) TODO: what is this? */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x09, 0x41, /* Usage (Vy) TODO: --||-- */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x09, 0x33, /* Usage (Rx) TODO: --||-- */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x09, 0x34, /* Usage (Ry) TODO: --||-- */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x09, 0x32, /* Usage (Z) TODO: --||-- (gas?) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x09, 0x37, /* Usage (Dial) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x05, 0x09, /* Usage page (Button) */ + 0x19, 0x01, /* Usage minimum (1) */ + 0x29, 0x1a, /* Usage maximum (13) */ + 0x25, 0x01, /* Logical maximum (1) */ + 0x45, 0x01, /* Physical maximum (1) */ + 0x75, 0x01, /* Report size (1) */ + 0x95, 0x1a, /* Report count (26) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x75, 0x06, /* Report size (6) */ + 0x95, 0x01, /* Report count (1) */ + 0x81, 0x03, /* Usage (Variable, Absolute, Constant) */ + 0x05, 0x01, /* Usage page (Generic Desktop) */ + 0x09, 0x39, /* Usage (Hat Switch) */ + 0x25, 0x07, /* Logical maximum (7) */ + 0x46, 0x3b, 0x01, /* Physical maximum (315) */ + 0x55, 0x00, /* Unit exponent (0) */ + 0x65, 0x14, /* Unit (Eng rot, Angular Pos) */ + 0x75, 0x04, /* Report size (4) */ + 0x81, 0x42, /* Input (Variable, Absolute, NullState) */ + 0x65, 0x00, /* Input (None) */ + 0x81, 0x03, /* Input (Variable, Absolute, Constant) */ + 0x85, 0x60, /* Report ID (96), prev 10 */ + 0x06, 0x00, 0xff, /* Usage page (Vendor 1) */ + 0x09, 0x60, /* Usage (96), prev 10 */ + 0x75, 0x08, /* Report size (8) */ + 0x95, 0x3f, /* Report count (63) */ + 0x26, 0xff, 0x00, /* Logical maximum (256) */ + 0x46, 0xff, 0x00, /* Physical maximum (256) */ + 0x91, 0x02, /* Output (Variable, Absolute) */ + 0x85, 0x02, /* Report ID (2) */ + 0x09, 0x02, /* Usage (2) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x09, 0x14, /* Usage (20) */ + 0x85, 0x14, /* Report ID (20) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0xc0, /* End collection */ + 0xc0, /* End collection */ +}; + +static int t248_interrupts(struct t300rs_device_entry *t248) +{ + u8 *send_buf = kmalloc(256, GFP_KERNEL); + struct usb_interface *usbif = to_usb_interface(t248->hdev->dev.parent); + struct usb_host_endpoint *ep; + int ret, trans, b_ep, i; + + if (!send_buf) { + hid_err(t248->hdev, "failed allocating send buffer\n"); + return -ENOMEM; + } + + ep = &usbif->cur_altsetting->endpoint[1]; + b_ep = ep->desc.bEndpointAddress; + + for (i = 0; i < ARRAY_SIZE(setup_arr); ++i) { + memcpy(send_buf, setup_arr[i], setup_arr_sizes[i]); + + ret = usb_interrupt_msg(t248->usbdev, + usb_sndintpipe(t248->usbdev, b_ep), + send_buf, setup_arr_sizes[i], + &trans, + USB_CTRL_SET_TIMEOUT); + + if (ret) { + hid_err(t248->hdev, "setup data couldn't be sent\n"); + goto err; + } + } + +err: + kfree(send_buf); + return ret; +} + +int t248_wheel_destroy(void *data) +{ + struct t300rs_device_entry *t300rs = data; + + if (!t300rs) + return -ENODEV; + + kfree(t300rs->send_buffer); + kfree(t300rs); + return 0; +} + +int t248_set_range(void *data, uint16_t value) +{ + struct t300rs_device_entry *t248 = data; + + if (value < 140) { + hid_info(t248->hdev, "value %i too small, clamping to 140\n", value); + value = 140; + } + + if (value > 900) { + hid_info(t248->hdev, "value %i too large, clamping to 900\n", value); + value = 900; + } + + return t300rs_set_range(data, value); +} + +static int t248_send_open(struct t300rs_device_entry *t248) +{ + int r1, r2; + t248->send_buffer[0] = 0x01; + t248->send_buffer[1] = 0x04; + if ((r1 = t300rs_send_int(t248))) + return r1; + + t248->send_buffer[0] = 0x01; + t248->send_buffer[1] = 0x05; + if ((r2 = t300rs_send_int(t248))) + return r2; + + return 0; +} + +static int t248_open(void *data, int open_mode) +{ + struct t300rs_device_entry *t248 = data; + + if (!t248) + return -ENODEV; + + if (open_mode) + t248_send_open(t248); + + return t248->open(t248->input_dev); +} + +static int t248_send_close(struct t300rs_device_entry *t248) +{ + int r1, r2; + t248->send_buffer[0] = 0x01; + t248->send_buffer[1] = 0x05; + if ((r1 = t300rs_send_int(t248))) + return r1; + + t248->send_buffer[0] = 0x01; + t248->send_buffer[1] = 0x00; + if ((r2 = t300rs_send_int(t248))) + return r2; + + return 0; +} + +static int t248_close(void *data, int open_mode) +{ + struct t300rs_device_entry *t248 = data; + + if (!t248) + return -ENODEV; + + if (open_mode) + t248_send_close(t248); + + t248->close(t248->input_dev); + return 0; +} + +int t248_wheel_init(struct tmff2_device_entry *tmff2, int open_mode) +{ + struct t300rs_device_entry *t248 = kzalloc(sizeof(struct t300rs_device_entry), GFP_KERNEL); + struct list_head *report_list; + int ret; + + + if (!t248) { + ret = -ENOMEM; + goto t248_err; + } + + t248->hdev = tmff2->hdev; + t248->input_dev = tmff2->input_dev; + t248->usbdev = to_usb_device(tmff2->hdev->dev.parent->parent); + t248->buffer_length = T248_BUFFER_LENGTH; + + t248->send_buffer = kzalloc(t248->buffer_length, GFP_KERNEL); + if (!t248->send_buffer) { + ret = -ENOMEM; + goto send_err; + } + + report_list = &t248->hdev->report_enum[HID_OUTPUT_REPORT].report_list; + t248->report = list_entry(report_list->next, struct hid_report, list); + t248->ff_field = t248->report->field[0]; + + t248->open = t248->input_dev->open; + t248->close = t248->input_dev->close; + + if ((ret = t248_interrupts(t248))) + goto interrupt_err; + + /* everything went OK */ + tmff2->data = t248; + tmff2->params = t248_params; + tmff2->max_effects = T248_MAX_EFFECTS; + memcpy(tmff2->supported_effects, t248_effects, sizeof(t248_effects)); + + if (!open_mode) + t248_send_open(t248); + + hid_info(t248->hdev, "force feedback for T248\n"); + return 0; + +interrupt_err: +send_err: + kfree(t248); +t248_err: + hid_err(tmff2->hdev, "failed initializing T248\n"); + return ret; +} + +static __u8 *t248_wheel_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + rdesc = t248_pc_rdesc_fixed; + *rsize = sizeof(t248_pc_rdesc_fixed); + return rdesc; +} + +int t248_populate_api(struct tmff2_device_entry *tmff2) +{ + tmff2->play_effect = t300rs_play_effect; + tmff2->upload_effect = t300rs_upload_effect; + tmff2->update_effect = t300rs_update_effect; + tmff2->stop_effect = t300rs_stop_effect; + + tmff2->set_gain = t300rs_set_gain; + tmff2->set_autocenter = t300rs_set_autocenter; + /* T248 only has 900 degree range, instead of T300RS 1080 */ + tmff2->set_range = t248_set_range; + tmff2->wheel_fixup = t248_wheel_fixup; + + tmff2->open = t248_open; + tmff2->close = t248_close; + + tmff2->wheel_init = t248_wheel_init; + tmff2->wheel_destroy = t248_wheel_destroy; + + return 0; +} diff --git a/src/tmt300rs/hid-tmt300rs.c b/src/tmt300rs/hid-tmt300rs.c new file mode 100644 index 0000000..20bb239 --- /dev/null +++ b/src/tmt300rs/hid-tmt300rs.c @@ -0,0 +1,1714 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include +#include "../hid-tmff2.h" + +#define T300RS_MAX_EFFECTS 16 +#define T300RS_NORM_BUFFER_LENGTH 63 +#define T300RS_PS4_BUFFER_LENGTH 31 + +#define T300RS_DEFAULT_ATTACHMENT 0x06 +#define T300RS_F1_ATTACHMENT 0x03 + +static const unsigned long t300rs_params = + PARAM_SPRING_LEVEL + | PARAM_DAMPER_LEVEL + | PARAM_FRICTION_LEVEL + | PARAM_GAIN + | PARAM_RANGE + | PARAM_ALT_MODE + ; + +static const signed short t300rs_effects[] = { + FF_CONSTANT, + FF_RAMP, + FF_SPRING, + FF_DAMPER, + FF_FRICTION, + FF_INERTIA, + FF_PERIODIC, + FF_SINE, + FF_TRIANGLE, + FF_SQUARE, + FF_SAW_UP, + FF_SAW_DOWN, + FF_AUTOCENTER, + FF_GAIN, + -1 +}; + +struct __packed t300rs_fw_response { + uint8_t unused1[2]; + uint8_t fw_version; + uint8_t unused2; +}; + + +struct __packed t300rs_packet_header { + uint8_t zero1; + uint8_t id; + uint8_t code; +}; + +struct __packed t300rs_setup_header { + uint8_t cmd; + uint8_t code; +}; + +struct __packed t300rs_packet_envelope { + uint16_t attack_length; + uint16_t attack_level; + uint16_t fade_length; + uint16_t fade_level; +}; + +struct __packed t300rs_packet_timing { + uint8_t start_marker; + uint16_t duration; + uint8_t zero1[2]; + uint16_t offset; + uint8_t zero2; + uint16_t end_marker; +}; + +struct usb_ctrlrequest t300rs_fw_request = { + .bRequestType = 0xc1, + .bRequest = 86, + .wValue = 0, + .wIndex = 0, + .wLength = 8 +}; + +struct t300rs_data { + unsigned long quirks; + void *device_props; +}; + +static u8 t300rs_rdesc_nrm_fixed[] = { + 0x05, 0x01, /* Usage page (Generic Desktop) */ + 0x09, 0x04, /* Usage (Joystick) */ + 0xa1, 0x01, /* Collection (Application) */ + 0x09, 0x01, /* Usage (Pointer) */ + 0xa1, 0x00, /* Collection (Physical) */ + 0x85, 0x07, /* Report ID (7) */ + 0x09, 0x30, /* Usage (X) */ + 0x15, 0x00, /* Logical minimum (0) */ + 0x27, 0xff, 0xff, 0x00, 0x00, /* Logical maximum (65535) */ + 0x35, 0x00, /* Physical minimum (0) */ + 0x47, 0xff, 0xff, 0x00, 0x00, /* Physical maximum (65535) */ + 0x75, 0x10, /* Report size (16) */ + 0x95, 0x01, /* Report count (1) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x09, 0x35, /* Usage (Rz) (Brake) */ + 0x26, 0xff, 0x03, /* Logical maximum (1023) */ + 0x46, 0xff, 0x03, /* Physical maximum (1023) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x09, 0x32, /* Usage (Z) (Gas) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x09, 0x31, /* Usage (Y) (Clutch) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x81, 0x03, /* Input (Variable, Absolute, Constant) */ + 0x05, 0x09, /* Usage page (Button) */ + 0x19, 0x01, /* Usage minimum (1) */ + 0x29, 0x0d, /* Usage maximum (13) */ + 0x25, 0x01, /* Logical maximum (1) */ + 0x45, 0x01, /* Physical maximum (1) */ + 0x75, 0x01, /* Report size (1) */ + 0x95, 0x0d, /* Report count (13) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x75, 0x0b, /* Report size (13) */ + 0x95, 0x01, /* Report count (1) */ + 0x81, 0x03, /* Usage (Variable, Absolute, Constant) */ + 0x05, 0x01, /* Usage page (Generic Desktop) */ + 0x09, 0x39, /* Usage (Hat Switch) */ + 0x25, 0x07, /* Logical maximum (7) */ + 0x46, 0x3b, 0x01, /* Physical maximum (315) */ + 0x55, 0x00, /* Unit exponent (0) */ + 0x65, 0x14, /* Unit (Eng Rot, Angular Pos) */ + 0x75, 0x04, /* Report size (4) */ + 0x81, 0x42, /* Input (Variable, Absolute, NullState) */ + 0x65, 0x00, /* Unit (None) */ + 0x81, 0x03, /* Input (Variable, Absolute, Constant) */ + 0x85, 0x60, /* Report ID (96), prev 10 */ + 0x06, 0x00, 0xff, /* Usage page (Vendor 1) */ + 0x09, 0x60, /* Usage (96), prev 10 */ + 0x75, 0x08, /* Report size (8) */ + 0x95, 0x3f, /* Report count (63) */ + 0x26, 0xff, 0x7f, /* Logical maximum (32767) */ + 0x15, 0x00, /* Logical minimum (0) */ + 0x46, 0xff, 0x7f, /* Physical maximum (32767) */ + 0x36, 0x00, 0x80, /* Physical minimum (-32768) */ + 0x91, 0x02, /* Output (Variable, Absolute) */ + 0x85, 0x02, /* Report ID (2) */ + 0x09, 0x02, /* Usage (2) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x09, 0x14, /* Usage (20) */ + 0x85, 0x14, /* Report ID (20) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0xc0, /* End collection */ + 0xc0, /* End collection */ +}; + +static u8 t300rs_rdesc_adv_fixed[] = { + 0x05, 0x01, /* Usage page (Generic Desktop) */ + 0x09, 0x04, /* Usage (Joystick) */ + 0xa1, 0x01, /* Collection (Application) */ + 0x09, 0x01, /* Usage (Pointer) */ + 0xa1, 0x00, /* Collection (Physical) */ + 0x85, 0x07, /* Report ID (7) */ + 0x09, 0x30, /* Usage (X) */ + 0x15, 0x00, /* Logical minimum (0) */ + 0x27, 0xff, 0xff, 0x00, 0x00, /* Logical maximum (65535) */ + 0x35, 0x00, /* Physical minimum (0) */ + 0x47, 0xff, 0xff, 0x00, 0x00, /* Physical maximum (65535) */ + 0x75, 0x10, /* Report size (16) */ + 0x95, 0x01, /* Report count (1) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x09, 0x31, /* Usage (Y) */ + 0x26, 0xff, 0x03, /* Logical maximum (1023) */ + 0x46, 0xff, 0x03, /* Physical maximum (1023) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x09, 0x35, /* Usage (Rz) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x09, 0x36, /* Usage (Slider) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x81, 0x03, /* Input (Variable, Absolute, Constant) ? */ + 0x05, 0x09, /* Usage page (Button) */ + 0x19, 0x01, /* Usage minimum (1) */ + 0x29, 0x19, /* Usage maximum (25) */ + 0x25, 0x01, /* Logical maximum (1) */ + 0x45, 0x01, /* Physical maximum (1) */ + 0x75, 0x01, /* Report size (1) */ + 0x95, 0x19, /* Report count (25) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x75, 0x03, /* Report size (3) */ + 0x95, 0x01, /* Report count (1) */ + 0x81, 0x03, /* Input (Variable, Absolute, Constant) */ + 0x05, 0x01, /* Usage page (Generic Desktop) */ + 0x09, 0x39, /* Usage (Hat Switch) */ + 0x25, 0x07, /* Logical maximum (7) */ + 0x46, 0x3b, 0x01, /* Physical maximum (315) */ + 0x55, 0x00, /* Unit exponent (0) */ + 0x65, 0x14, /* Unit (Eng Rot, Angular Pos) */ + 0x75, 0x04, /* Report size (4) */ + 0x81, 0x42, /* Input (Variable, Absolute, NullState) */ + 0x65, 0x00, /* Unit (None) */ + 0x85, 0x60, /* Report ID (96), prev 10 */ + 0x06, 0x00, 0xff, /* Usage page (Vendor 1) */ + 0x09, 0x60, /* Usage (96), prev 10 (why?) */ + 0x75, 0x08, /* Report size (8) */ + 0x95, 0x3f, /* Report count (63) */ + 0x26, 0xff, 0x00, /* Logical maximum (255) */ + 0x46, 0xff, 0x00, /* Physical maximum (255) */ + 0x91, 0x02, /* Output (Variable, Absolute) */ + 0x85, 0x02, /* Report ID (2) */ + 0x09, 0x02, /* Usage (Mouse) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x09, 0x14, /* Usage (20) */ + 0x85, 0x14, /* Report ID (20) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0xc0, /* End collection */ + 0xc0, /* End collection */ +}; + +static u8 t300rs_rdesc_ps4_fixed[] = { + 0x05, 0x01, /* Usage page (Generic Desktop) */ + 0x09, 0x05, /* Usage (GamePad) */ + 0xa1, 0x01, /* Collection (Application) */ + 0x85, 0x01, /* Report ID (1) */ + 0x09, 0x00, /* Usage (U) (was X) */ + 0x09, 0x00, /* Usage (U) (was Y) */ + 0x09, 0x00, /* Usage (U) (was Z) */ + 0x09, 0x00, /* Usage (U) (was Rz)*/ + 0x15, 0x00, /* Logical minimum (0) */ + 0x26, 0xff, 0x00, /* Logical maximum (255) */ + 0x75, 0x08, /* Report size (8) */ + 0x95, 0x04, /* Report count (4) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x09, 0x39, /* Usage (Hat Switch) */ + 0x15, 0x00, /* Logical minimum (0) */ + 0x25, 0x07, /* Logical maximum (7)*/ + 0x35, 0x00, /* Physical minimum (0) */ + 0x46, 0x3b, 0x01, /* Physical maximum (315) */ + 0x65, 0x14, /* Unit (Eng Rot, Angular Pos) */ + 0x75, 0x04, /* Report size (4) */ + 0x95, 0x01, /* Report count (1) */ + 0x81, 0x42, /* Input (Variable, Absolute, NullState) */ + 0x65, 0x00, /* Input (None) */ + 0x05, 0x09, /* Usage page (Button) */ + 0x19, 0x01, /* Usage minimum (1) */ + 0x29, 0x0e, /* Usage maximum (14) */ + 0x15, 0x00, /* Logical minimum (0) */ + 0x25, 0x01, /* Logical maximum (1) */ + 0x75, 0x01, /* Report size (1) */ + 0x95, 0x0e, /* Report size (14) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x06, 0x00, 0xff, /* Usage page (Vendor 1) */ + 0x09, 0x20, /* Usage (32) */ + 0x75, 0x06, /* Report size (6) */ + 0x95, 0x01, /* Report count (1) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x05, 0x01, /* Usage page (Generic Desktop) */ + 0x09, 0x00, /* Usage (U) (was Rx)*/ + 0x09, 0x00, /* Usage (U) (was Ry) */ + 0x15, 0x00, /* Logical minimum (0) */ + 0x26, 0xff, 0x00, /* Logical maximum (255) */ + 0x75, 0x08, /* Report size (8) */ + 0x95, 0x02, /* Report count (2) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x05, 0x01, /* Usage page (Vendor 1) */ + /* constant zero? */ + 0x09, 0x00, /* Usage (33) */ + 0x95, 0x21, /* Report count (33) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + /* wheel */ + 0x09, 0x30, /* Usage (X) */ + 0x15, 0x00, /* Logical minimum (0) */ + 0x27, 0xff, 0xff, 0x00, 0x00, /* Logical maximum (65535) */ + 0x35, 0x00, /* Physical minimum (0) */ + 0x47, 0xff, 0xff, 0x00, 0x00, /* Physical maximum (65535) */ + 0x75, 0x10, /* Report size (16) */ + 0x95, 0x01, /* Report count (1) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + /* gas */ + 0x09, 0x31, /* Usage (Y) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + /* brake */ + 0x09, 0x32, /* Usage (Z) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + /* clutch */ + 0x09, 0x35, /* Usage (Rz) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + /* stick shifter (check model no) */ + 0x05, 0x09, /* Usage page (Button) */ + 0x19, 0x0f, /* Usage minimum (15) */ + 0x29, 0x17, /* Usage maximum (23) */ + 0x15, 0x00, /* Logical minimum (1) */ + 0x25, 0x01, /* Logical maximum (1) */ + 0x75, 0x01, /* Report size (1) */ + 0x95, 0x08, /* Report count (8) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + /* no clue */ + 0x05, 0x01, /* Usage page (Generic Desktop) */ + 0x09, 0x00, /* Usage (U) */ + 0x75, 0x08, /* Report size (8) */ + 0x95, 0x0c, /* Report count (12) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + /* continue unmodified */ + 0x06, 0x00, 0xff, /* Usage page (Vendor defined 1) */ + 0x85, 0x60, /* Report ID (5) (change to 0x60?) */ + 0x09, 0x60, /* Usage (34) (change to 0x60?) */ + 0x95, 0x1f, /* Report count (31) () */ + 0x91, 0x02, /* Output (Variable, Absolute) */ + 0x85, 0x03, /* Report ID (3) */ + 0x0a, 0x21, 0x27, /* ??? */ + 0x95, 0x2f, /* Report count (47) */ + 0xb1, 0x02, /* Feature (Data, Var, Abs) */ + 0xc0, /* End collection */ + + /* From here on out no clue */ + 0x06, 0xf0, + 0xff, 0x09, + 0x40, 0xa1, + 0x01, 0x85, + 0xf0, 0x09, + 0x47, 0x95, + 0x3f, 0xb1, + 0x02, 0x85, + 0xf1, 0x09, + 0x48, 0x95, + 0x3f, 0xb1, + 0x02, 0x85, + 0xf2, 0x09, + 0x49, 0x95, + 0x0f, 0xb1, + 0x02, 0x85, + 0xf3, 0x0a, + 0x01, 0x47, + 0x95, 0x07, + 0xb1, 0x02, + 0xc0, +}; + +static u8 spring_values[] = { + 0xa6, 0x6a, 0xa6, 0x6a, 0xfe, + 0xff, 0xfe, 0xff, 0xfe, 0xff, + 0xfe, 0xff, 0xdf, 0x58, 0xa6, + 0x6a, 0x06 +}; + +static u8 damper_values[] = { + 0xfc, 0x7f, 0xfc, 0x7f, 0xfe, + 0xff, 0xfe, 0xff, 0xfe, 0xff, + 0xfe, 0xff, 0xfc, 0x7f, 0xfc, + 0x7f, 0x07 +}; + +int t300rs_send_buf(struct t300rs_device_entry *t300rs, u8 *send_buffer, size_t len) +{ + int i; + /* check that send_buffer fits into our report */ + if (len > t300rs->buffer_length) + return -EINVAL; + + /* fill with actual data */ + for (i = 0; i < len; ++i) + t300rs->ff_field->value[i] = send_buffer[i]; + + /* fill the rest with zeroes */ + for (i = len; i < t300rs->buffer_length; ++i) + t300rs->ff_field->value[i] = 0; + + hid_hw_request(t300rs->hdev, t300rs->report, HID_REQ_SET_REPORT); + return 0; +} + +int t300rs_send_int(struct t300rs_device_entry *t300rs) +{ + t300rs_send_buf(t300rs, t300rs->send_buffer, t300rs->buffer_length); + memset(t300rs->send_buffer, 0, t300rs->buffer_length); + + return 0; +} + +static void t300rs_fill_header(struct t300rs_packet_header *packet_header, + uint8_t id, uint8_t code) +{ + packet_header->id = id + 1; + packet_header->code = code; +} + +int t300rs_play_effect(void *data, struct tmff2_effect_state *state) +{ + struct t300rs_device_entry *t300rs = data; + struct __packed t300rs_packet_play { + struct t300rs_packet_header header; + uint8_t value; + } *play_packet = (struct t300rs_packet_play *)t300rs->send_buffer; + + int ret; + + + t300rs_fill_header(&play_packet->header, state->effect.id, 0x89); + play_packet->value = 0x01; + + ret = t300rs_send_int(t300rs); + if (ret) + hid_err(t300rs->hdev, "failed starting effect play\n"); + + return ret; +} + +int t300rs_stop_effect(void *data, struct tmff2_effect_state *state) +{ + struct t300rs_device_entry *t300rs = data; + struct __packed t300rs_packet_stop { + struct t300rs_packet_header header; + uint8_t value; + } *stop_packet = (struct t300rs_packet_stop *)t300rs->send_buffer; + + int ret; + + + t300rs_fill_header(&stop_packet->header, state->effect.id, 0x89); + + ret = t300rs_send_int(t300rs); + if (ret) + hid_err(t300rs->hdev, "failed stopping effect play\n"); + + return ret; +} + +static void t300rs_fill_envelope(struct t300rs_packet_envelope *packet_envelope, + int16_t level, uint16_t duration, struct ff_envelope *envelope) +{ + uint16_t attack_length = (duration * envelope->attack_length) / 0x7fff; + uint16_t attack_level = (level * envelope->attack_level) / 0x7fff; + uint16_t fade_length = (duration * envelope->fade_length) / 0x7fff; + uint16_t fade_level = (level * envelope->fade_level) / 0x7fff; + + packet_envelope->attack_length = cpu_to_le16(attack_length); + packet_envelope->attack_level = cpu_to_le16(attack_level); + packet_envelope->fade_length = cpu_to_le16(fade_length); + packet_envelope->fade_level = cpu_to_le16(fade_level); +} + +static void t300rs_fill_timing(struct t300rs_packet_timing *packet_timing, + uint16_t duration, uint16_t offset){ + packet_timing->start_marker = 0x4f; + + packet_timing->duration = cpu_to_le16(duration); + packet_timing->offset = cpu_to_le16(offset); + + packet_timing->end_marker = 0xffff; +} + +static int t300rs_update_envelope(struct t300rs_device_entry *t300rs, + struct tmff2_effect_state *state, + int16_t level, + uint16_t duration, + uint8_t id, + struct ff_envelope envelope, + struct ff_envelope envelope_old + ) +{ + struct __packed t300rs_packet_mod_envelope { + struct t300rs_packet_header header; + uint8_t attribute; + uint16_t value; + } *packet_mod_envelope = (struct t300rs_packet_mod_envelope *)t300rs->send_buffer; + + uint16_t attack_length, attack_level, fade_length, fade_level; + int ret = 0; + + duration = duration - 1; + + 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; + + if (envelope.attack_length != envelope_old.attack_length) { + t300rs_fill_header(&packet_mod_envelope->header, id, 0x31); + packet_mod_envelope->attribute = 0x81; + packet_mod_envelope->value = cpu_to_le16(attack_length); + + ret = t300rs_send_int(t300rs); + if (ret) { + hid_err(t300rs->hdev, "failed modifying effect envelope\n"); + goto error; + } + } + + if (envelope.attack_level != envelope_old.attack_level) { + t300rs_fill_header(&packet_mod_envelope->header, id, 0x31); + packet_mod_envelope->attribute = 0x82; + packet_mod_envelope->value = cpu_to_le16(attack_level); + + ret = t300rs_send_int(t300rs); + if (ret) { + hid_err(t300rs->hdev, "failed modifying effect envelope\n"); + goto error; + } + } + + if (envelope.fade_length != envelope_old.fade_length) { + t300rs_fill_header(&packet_mod_envelope->header, id, 0x31); + packet_mod_envelope->attribute = 0x84; + packet_mod_envelope->value = cpu_to_le16(fade_length); + + ret = t300rs_send_int(t300rs); + if (ret) { + hid_err(t300rs->hdev, "failed modifying effect envelope\n"); + goto error; + } + } + + if (envelope.fade_level != envelope_old.fade_level) { + t300rs_fill_header(&packet_mod_envelope->header, id, 0x31); + packet_mod_envelope->attribute = 0x88; + packet_mod_envelope->value = cpu_to_le16(fade_level); + + ret = t300rs_send_int(t300rs); + if (ret) { + hid_err(t300rs->hdev, "failed modifying effect envelope\n"); + goto error; + } + } + +error: + return ret; +} + +static int t300rs_update_simple_duration(struct t300rs_device_entry *t300rs, + struct tmff2_effect_state *state, unsigned type) +{ + struct ff_effect effect = state->effect; + struct __packed t300rs_packet_mod_duration { + struct t300rs_packet_header header; + uint16_t marker; + uint16_t duration; + } *packet_mod_duration = (struct t300rs_packet_mod_duration *)t300rs->send_buffer; + + uint16_t duration; + int ret = 0; + + duration = effect.replay.length - 1; + + t300rs_fill_header(&packet_mod_duration->header, effect.id, 0x49); + packet_mod_duration->marker = cpu_to_le16(0x4100 + type); + packet_mod_duration->duration = cpu_to_le16(duration); + + ret = t300rs_send_int(t300rs); + if (ret) { + hid_err(t300rs->hdev, "failed modifying duration\n"); + goto error; + } + +error: + return ret; +} + +static int t300rs_update_periodic_duration(struct t300rs_device_entry *t300rs, + struct tmff2_effect_state *state, unsigned type) +{ + struct ff_effect effect = state->effect; + struct __packed t300rs_packet_mod_duration { + struct t300rs_packet_header header; + uint8_t type; + uint8_t marker; + uint16_t duration; + } *packet_mod_duration = (struct t300rs_packet_mod_duration *)t300rs->send_buffer; + + uint16_t duration; + int ret = 0; + + duration = effect.replay.length - 1; + + t300rs_fill_header(&packet_mod_duration->header, effect.id, 0x49); + packet_mod_duration->type = type; + packet_mod_duration->marker = 0x41; + packet_mod_duration->duration = cpu_to_le16(duration); + + ret = t300rs_send_int(t300rs); + if (ret) { + hid_err(t300rs->hdev, "failed modifying duration\n"); + goto error; + } + +error: + return ret; +} + +static int t300rs_update_ramp_duration(struct t300rs_device_entry *t300rs, + struct tmff2_effect_state *state) +{ + struct ff_effect effect = state->effect; + struct __packed t300rs_packet_mod_duration { + struct t300rs_packet_header header; + uint8_t marker0; + uint16_t duration0; + uint8_t marker1; + uint8_t marker2; + uint16_t duration1; + } *packet_mod_duration = (struct t300rs_packet_mod_duration *)t300rs->send_buffer; + + uint16_t duration; + int ret = 0; + + duration = effect.replay.length - 1; + + t300rs_fill_header(&packet_mod_duration->header, effect.id, 0x4e); + packet_mod_duration->marker0 = 0x08; + packet_mod_duration->duration0 = cpu_to_le16(duration); + packet_mod_duration->marker1 = 0x05; + packet_mod_duration->marker2 = 0x41; + packet_mod_duration->duration1 = cpu_to_le16(duration); + + ret = t300rs_send_int(t300rs); + if (ret) { + hid_err(t300rs->hdev, "failed modifying duration\n"); + goto error; + } + +error: + return ret; +} + +static int t300rs_update_constant(struct t300rs_device_entry *t300rs, + struct tmff2_effect_state *state) +{ + 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 __packed t300rs_packet_mod_constant { + struct t300rs_packet_header header; + uint16_t level; + } *packet_mod_constant = (struct t300rs_packet_mod_constant *)t300rs->send_buffer; + int ret; + int16_t level; + + level = (constant.level * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; + + if ((constant.level != constant_old.level) || (effect.direction != old.direction)) { + + t300rs_fill_header(&packet_mod_constant->header, effect.id, 0x0a); + packet_mod_constant->level = cpu_to_le16(level); + + ret = t300rs_send_int(t300rs); + if (ret) { + hid_err(t300rs->hdev, "failed modifying constant effect\n"); + goto error; + } + + } + + ret = t300rs_update_envelope(t300rs, + state, + level, + effect.replay.length, + effect.id, + constant.envelope, + constant_old.envelope + ); + + if (ret) { + hid_err(t300rs->hdev, "failed modifying constant envelope\n"); + goto error; + } + + ret = t300rs_update_simple_duration(t300rs, state, 0x00); + if (ret) { + hid_err(t300rs->hdev, "failed modifying constant duration\n"); + goto error; + } + +error: + return ret; +} + +static int t300rs_update_ramp(struct t300rs_device_entry *t300rs, + struct tmff2_effect_state *state) +{ + struct ff_effect effect = state->effect; + struct ff_effect old = state->old; + struct ff_ramp_effect ramp = effect.u.ramp; + struct ff_ramp_effect ramp_old = old.u.ramp; + struct __packed t300rs_packet_mod_ramp { + struct t300rs_packet_header header; + uint8_t attribute; + uint16_t difference; + uint16_t level; + } *packet_mod_ramp = (struct t300rs_packet_mod_ramp *)t300rs->send_buffer; + + int ret; + + uint16_t difference, top, bottom; + int16_t level; + + top = ramp.end_level > ramp.start_level ? ramp.end_level : ramp.start_level; + bottom = ramp.end_level > ramp.start_level ? ramp.start_level : ramp.end_level; + + + difference = ((top - bottom) * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; + + + level = (top * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; + + if ((ramp.start_level != ramp_old.start_level) + || (ramp.end_level != ramp_old.end_level) + || (effect.direction != old.direction)) { + + t300rs_fill_header(&packet_mod_ramp->header, effect.id, 0x0e); + packet_mod_ramp->attribute = 0x03; + packet_mod_ramp->difference = cpu_to_le16(difference); + packet_mod_ramp->level = cpu_to_le16(level); + + ret = t300rs_send_int(t300rs); + if (ret) { + hid_err(t300rs->hdev, "failed modifying ramp effect\n"); + goto error; + } + + } + + ret = t300rs_update_envelope(t300rs, + state, + level, + effect.replay.length, + effect.id, + ramp.envelope, + ramp_old.envelope + ); + + + if (ret) { + hid_err(t300rs->hdev, "failed modifying ramp envelope\n"); + goto error; + } + + ret = t300rs_update_ramp_duration(t300rs, state); + if (ret) { + hid_err(t300rs->hdev, "failed modifying ramp duration\n"); + goto error; + } + +error: + return ret; +} + +static int t300rs_update_damper(struct t300rs_device_entry *t300rs, + struct tmff2_effect_state *state) +{ + 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]; + struct __packed t300rs_packet_mod_damper { + struct t300rs_packet_header header; + uint8_t attribute; + uint16_t value0; + uint16_t value1; + } *packet_mod_damper = (struct t300rs_packet_mod_damper *)t300rs->send_buffer; + + int ret, input_level; + + input_level = damper_level; + if (state->effect.type == FF_FRICTION) + input_level = friction_level; + + if (state->effect.type == FF_SPRING) + input_level = spring_level; + + if (damper.right_coeff != damper_old.right_coeff) { + int16_t coeff = damper.right_coeff * input_level / 100; + + t300rs_fill_header(&packet_mod_damper->header, effect.id, 0x0e); + packet_mod_damper->attribute = 0x41; + packet_mod_damper->value0 = cpu_to_le16(coeff); + + ret = t300rs_send_int(t300rs); + if (ret) { + hid_err(t300rs->hdev, "failed modifying damper rc\n"); + goto error; + } + + } + + if (damper.left_coeff != damper_old.left_coeff) { + int16_t coeff = damper.left_coeff * input_level / 100; + + t300rs_fill_header(&packet_mod_damper->header, effect.id, 0x0e); + packet_mod_damper->attribute = 0x42; + packet_mod_damper->value0 = cpu_to_le16(coeff); + + ret = t300rs_send_int(t300rs); + if (ret) { + hid_err(t300rs->hdev, "failed modifying damper lc\n"); + goto error; + } + + } + + if ((damper.deadband != damper_old.deadband) + || (damper.center != damper_old.center)) { + + uint16_t right_deadband = 0xfffe - damper.deadband - damper.center; + uint16_t left_deadband = 0xfffe - damper.deadband + damper.center; + + t300rs_fill_header(&packet_mod_damper->header, effect.id, 0x0e); + packet_mod_damper->attribute = 0x4c; + packet_mod_damper->value0 = cpu_to_le16(right_deadband); + packet_mod_damper->value1 = cpu_to_le16(left_deadband); + + ret = t300rs_send_int(t300rs); + if (ret) { + hid_err(t300rs->hdev, "failed modifying damper deadband\n"); + goto error; + } + + } + + ret = t300rs_update_simple_duration(t300rs, state, 0x06); + if (ret) { + hid_err(t300rs->hdev, "failed modifying damper duration\n"); + goto error; + } + +error: + return ret; +} + +static int t300rs_update_spring(struct t300rs_device_entry *t300rs, + struct tmff2_effect_state *state) +{ + return t300rs_update_damper(t300rs, state); +} + + +static int t300rs_update_periodic(struct t300rs_device_entry *t300rs, + struct tmff2_effect_state *state) +{ + 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 __packed t300rs_packet_mod_periodic { + struct t300rs_packet_header header; + uint8_t attribute; + uint16_t value; + } *packet_mod_periodic = (struct t300rs_packet_mod_periodic *)t300rs->send_buffer; + + int ret; + int16_t magnitude, phase; + + magnitude = (periodic.magnitude * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; + phase = periodic.phase; + + if ((periodic.magnitude != periodic_old.magnitude) + || (effect.direction != old.direction)) { + + t300rs_fill_header(&packet_mod_periodic->header, effect.id, 0x0e); + packet_mod_periodic->attribute = 0x01; + packet_mod_periodic->value = cpu_to_le16(magnitude); + + ret = t300rs_send_int(t300rs); + if (ret) { + hid_err(t300rs->hdev, "failed modifying periodic magnitude\n"); + goto error; + } + + } + + if (periodic.offset != periodic_old.offset) { + uint16_t offset = periodic.offset; + + t300rs_fill_header(&packet_mod_periodic->header, effect.id, 0x0e); + packet_mod_periodic->attribute = 0x02; + packet_mod_periodic->value = cpu_to_le16(offset); + + ret = t300rs_send_int(t300rs); + if (ret) { + hid_err(t300rs->hdev, "failed modifying periodic offset\n"); + goto error; + } + + } + + if (periodic.phase != periodic_old.phase) { + + t300rs_fill_header(&packet_mod_periodic->header, effect.id, 0x0e); + packet_mod_periodic->attribute = 0x04; + packet_mod_periodic->value = cpu_to_le16(phase); + + ret = t300rs_send_int(t300rs); + if (ret) { + hid_err(t300rs->hdev, "failed modifying periodic phase\n"); + goto error; + } + + } + + if (periodic.period != periodic_old.period) { + int16_t period = periodic.period; + + t300rs_fill_header(&packet_mod_periodic->header, effect.id, 0x0e); + packet_mod_periodic->attribute = 0x08; + packet_mod_periodic->value = cpu_to_le16(period); + + ret = t300rs_send_int(t300rs); + if (ret) { + hid_err(t300rs->hdev, "failed modifying periodic period\n"); + goto error; + } + + } + + ret = t300rs_update_envelope(t300rs, + state, + magnitude, + effect.replay.length, + effect.id, + periodic.envelope, + periodic_old.envelope + ); + + if (ret) { + hid_err(t300rs->hdev, "failed modifying periodic envelope\n"); + goto error; + } + + ret = t300rs_update_periodic_duration(t300rs, state, periodic.waveform - 0x57); + if (ret) { + hid_err(t300rs->hdev, "failed modifying periodic duration\n"); + goto error; + } + +error: + return ret; +} + +static int t300rs_upload_constant(struct t300rs_device_entry *t300rs, + struct tmff2_effect_state *state) +{ + struct ff_effect effect = state->effect; + struct ff_constant_effect constant = state->effect.u.constant; + struct __packed t300rs_packet_constant { + struct t300rs_packet_header header; + uint16_t level; + struct t300rs_packet_envelope envelope; + uint8_t zero; + struct t300rs_packet_timing timing; + } *packet_constant = (struct t300rs_packet_constant *)t300rs->send_buffer; + + int16_t level; + uint16_t duration, offset; + + int ret; + + level = (constant.level * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; + duration = effect.replay.length - 1; + + offset = effect.replay.delay; + + t300rs_fill_header(&packet_constant->header, effect.id, 0x6a); + + packet_constant->level = cpu_to_le16(level); + + t300rs_fill_envelope(&packet_constant->envelope, level, duration, + &constant.envelope); + t300rs_fill_timing(&packet_constant->timing, duration, offset); + + ret = t300rs_send_int(t300rs); + if (ret) + hid_err(t300rs->hdev, "failed uploading constant effect\n"); + + return ret; +} + +static int t300rs_upload_ramp(struct t300rs_device_entry *t300rs, + struct tmff2_effect_state *state) +{ + struct ff_effect effect = state->effect; + struct ff_ramp_effect ramp = state->effect.u.ramp; + struct __packed t300rs_packet_ramp { + struct t300rs_packet_header header; + uint16_t difference; + uint16_t level; + uint8_t zero1[2]; + uint16_t duration; + uint16_t marker; + struct t300rs_packet_envelope envelope; + uint8_t direction; + struct t300rs_packet_timing timing; + } *packet_ramp = (struct t300rs_packet_ramp *)t300rs->send_buffer; + + int ret; + uint16_t difference, offset, top, bottom, duration; + int16_t level; + + duration = effect.replay.length - 1; + + top = ramp.end_level > ramp.start_level ? ramp.end_level : ramp.start_level; + bottom = ramp.end_level > ramp.start_level ? ramp.start_level : ramp.end_level; + + + difference = ((top - bottom) * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; + level = (top * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; + offset = effect.replay.delay; + + + t300rs_fill_header(&packet_ramp->header, effect.id, 0x6b); + + packet_ramp->difference = cpu_to_le16(difference); + packet_ramp->level = cpu_to_le16(level); + packet_ramp->duration = cpu_to_le16(duration); + + packet_ramp->marker = cpu_to_le16(0x8000); + + t300rs_fill_envelope(&packet_ramp->envelope, level, duration, + &ramp.envelope); + + packet_ramp->direction = ramp.end_level > ramp.start_level ? 0x04 : 0x05; + t300rs_fill_timing(&packet_ramp->timing, duration, offset); + + ret = t300rs_send_int(t300rs); + if (ret) + hid_err(t300rs->hdev, "failed uploading ramp"); + + return ret; +} + +static int t300rs_upload_spring(struct t300rs_device_entry *t300rs, + struct tmff2_effect_state *state) +{ + struct ff_effect effect = state->effect; + /* we only care about the first axis */ + struct ff_condition_effect spring = state->effect.u.condition[0]; + struct __packed t300rs_packet_spring { + struct t300rs_packet_header header; + uint16_t right_coeff; + uint16_t left_coeff; + uint16_t right_deadband; + uint16_t left_deadband; + uint8_t spring_start[17]; + struct t300rs_packet_timing timing; + } *packet_spring = (struct t300rs_packet_spring *)t300rs->send_buffer; + + int ret; + uint16_t duration, right_coeff, left_coeff, right_deadband, left_deadband, offset; + + duration = effect.replay.length - 1; + + right_coeff = spring.right_coeff * spring_level / 100; + left_coeff = spring.left_coeff * spring_level / 100; + + right_deadband = 0xfffe - spring.deadband - spring.center; + left_deadband = 0xfffe - spring.deadband + spring.center; + + offset = effect.replay.delay; + + t300rs_fill_header(&packet_spring->header, effect.id, 0x64); + + packet_spring->right_coeff = cpu_to_le16(right_coeff); + packet_spring->left_coeff = cpu_to_le16(left_coeff); + packet_spring->right_deadband = cpu_to_le16(right_deadband); + packet_spring->left_deadband = cpu_to_le16(left_deadband); + + memcpy(&packet_spring->spring_start, spring_values, ARRAY_SIZE(spring_values)); + t300rs_fill_timing(&packet_spring->timing, duration, offset); + + ret = t300rs_send_int(t300rs); + if (ret) + hid_err(t300rs->hdev, "failed uploading spring\n"); + + return ret; +} + +static int t300rs_upload_damper(struct t300rs_device_entry *t300rs, + struct tmff2_effect_state *state) +{ + + struct ff_effect effect = state->effect; + /* we only care about the first axis */ + struct ff_condition_effect spring = state->effect.u.condition[0]; + struct __packed t300rs_packet_damper { + struct t300rs_packet_header header; + uint16_t right_coeff; + uint16_t left_coeff; + uint16_t right_deadband; + uint16_t left_deadband; + uint8_t damper_start[17]; + struct t300rs_packet_timing timing; + } *packet_damper = (struct t300rs_packet_damper *)t300rs->send_buffer; + + int ret, input_level; + uint16_t duration, right_coeff, left_coeff, right_deadband, left_deadband, offset; + + duration = effect.replay.length - 1; + + input_level = damper_level; + if (state->effect.type == FF_FRICTION) + input_level = friction_level; + + right_coeff = spring.right_coeff * input_level / 100; + left_coeff = spring.left_coeff * input_level / 100; + + right_deadband = 0xfffe - spring.deadband - spring.center; + left_deadband = 0xfffe - spring.deadband + spring.center; + + offset = effect.replay.delay; + + t300rs_fill_header(&packet_damper->header, effect.id, 0x64); + + packet_damper->right_coeff = cpu_to_le16(right_coeff); + packet_damper->left_coeff = cpu_to_le16(left_coeff); + packet_damper->right_deadband = cpu_to_le16(right_deadband); + packet_damper->left_deadband = cpu_to_le16(left_deadband); + + memcpy(&packet_damper->damper_start, damper_values, ARRAY_SIZE(damper_values)); + t300rs_fill_timing(&packet_damper->timing, duration, offset); + + ret = t300rs_send_int(t300rs); + if (ret) + hid_err(t300rs->hdev, "failed uploading spring\n"); + + return ret; +} + +static int t300rs_upload_periodic(struct t300rs_device_entry *t300rs, + struct tmff2_effect_state *state) +{ + struct ff_effect effect = state->effect; + struct ff_periodic_effect periodic = state->effect.u.periodic; + struct __packed t300rs_packet_periodic { + struct t300rs_packet_header header; + uint16_t magnitude; + uint16_t periodic_offset; + uint16_t phase; + uint16_t period; + uint16_t marker; + struct t300rs_packet_envelope envelope; + uint8_t waveform; + struct t300rs_packet_timing timing; + } *packet_periodic = (struct t300rs_packet_periodic *)t300rs->send_buffer; + + int ret; + uint16_t duration, period, offset, periodic_offset; + int16_t phase, magnitude; + + duration = effect.replay.length - 1; + magnitude = (periodic.magnitude * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; + + phase = periodic.phase; + periodic_offset = periodic.offset; + + period = periodic.period; + offset = effect.replay.delay; + + t300rs_fill_header(&packet_periodic->header, effect.id, 0x6b); + + packet_periodic->magnitude = cpu_to_le16(magnitude); + packet_periodic->periodic_offset = cpu_to_le16(periodic_offset); + packet_periodic->phase = cpu_to_le16(phase); + packet_periodic->period = cpu_to_le16(period); + + packet_periodic->marker = cpu_to_le16(0x8000); + + t300rs_fill_envelope(&packet_periodic->envelope, magnitude, duration, + &periodic.envelope); + + packet_periodic->waveform = periodic.waveform - 0x57; + + t300rs_fill_timing(&packet_periodic->timing, duration, offset); + + ret = t300rs_send_int(t300rs); + if (ret) + hid_err(t300rs->hdev, "failed uploading periodic effect"); + + return ret; +} + +int t300rs_update_effect(void *data, struct tmff2_effect_state *state) +{ + struct t300rs_device_entry *t300rs = data; + switch (state->effect.type) { + case FF_CONSTANT: + return t300rs_update_constant(t300rs, state); + case FF_RAMP: + return t300rs_update_ramp(t300rs, state); + case FF_SPRING: + return t300rs_update_spring(t300rs, state); + case FF_DAMPER: + case FF_FRICTION: + case FF_INERTIA: + return t300rs_update_damper(t300rs, state); + case FF_PERIODIC: + return t300rs_update_periodic(t300rs, state); + default: + hid_err(t300rs->hdev, "invalid effect type: %x", state->effect.type); + return -1; + } +} + +int t300rs_upload_effect(void *data, struct tmff2_effect_state *state) +{ + struct t300rs_device_entry *t300rs = data; + switch (state->effect.type) { + case FF_CONSTANT: + return t300rs_upload_constant(t300rs, state); + case FF_RAMP: + return t300rs_upload_ramp(t300rs, state); + case FF_SPRING: + return t300rs_upload_spring(t300rs, state); + case FF_DAMPER: + case FF_FRICTION: + case FF_INERTIA: + return t300rs_upload_damper(t300rs, state); + case FF_PERIODIC: + return t300rs_upload_periodic(t300rs, state); + default: + hid_err(t300rs->hdev, "invalid effect type: %x", state->effect.type); + return -1; + } +} + +static int t300rs_switch_mode(void *data, uint16_t mode) +{ + struct t300rs_device_entry *t300rs = data; + if (!t300rs) + return -ENODEV; + + if(t300rs->mode == mode) /* already in specified mode */ + return 0; + + if (mode == 0) + /* go to normal mode */ + usb_control_msg(t300rs->usbdev, + usb_sndctrlpipe(t300rs->usbdev, 0), + 83, 0x41, 5, 0, 0, 0, + USB_CTRL_SET_TIMEOUT + ); + else if (mode == 1) + /* go to advanced mode */ + usb_control_msg(t300rs->usbdev, + usb_sndctrlpipe(t300rs->usbdev, 0), + 83, 0x41, 3, 0, 0, 0, + USB_CTRL_SET_TIMEOUT + ); + else + hid_warn(t300rs->hdev, "mode %i not supported\n", mode); + + + return 0; +} + +static struct t300rs_alt_modes { + char *id; + char *label; + uint16_t mode; +} t300rs_modes[] = { + {"base", "T300RS base", 0}, + {"F1", "T300RS with F1 wheel attachment", 1} +}; + +static ssize_t t300rs_alt_mode_show(void *data, char *buf) +{ + struct t300rs_device_entry *t300rs = data; + ssize_t count = 0; + int i; + if (!t300rs) + return -ENODEV; + + if (t300rs->attachment != T300RS_F1_ATTACHMENT) + /* we only support one base mode */ + return scnprintf(buf, PAGE_SIZE, "%s: %s *\n", + t300rs_modes[0].id, t300rs_modes[0].label); + + for (i = 0; i < ARRAY_SIZE(t300rs_modes); ++i) { + count += scnprintf(buf + count, PAGE_SIZE - count, "%s: %s", + t300rs_modes[i].id, t300rs_modes[i].label); + + if (count >= PAGE_SIZE - 1) + return count; + + if (t300rs_modes[i].mode == t300rs->mode) + count += scnprintf(buf + count, PAGE_SIZE - count, " *\n"); + else + count += scnprintf(buf + count, PAGE_SIZE - count, "\n"); + + if (count >= PAGE_SIZE - 1) + return count; + } + + return count; +} + +static ssize_t t300rs_alt_mode_store(void *data, const char *buf, size_t count) +{ + struct t300rs_device_entry *t300rs = data; + int i, len, mode_len; + char *lbuf; + if (!t300rs) + return -ENODEV; + + if (t300rs->attachment != T300RS_F1_ATTACHMENT) + return count; /* don't do anything */ + + lbuf = kasprintf(GFP_KERNEL, "%s", buf); + if (!lbuf) + return -ENOMEM; + + len = strlen(buf); + for (i = 0; i < ARRAY_SIZE(t300rs_modes); ++i) { + mode_len = strlen(t300rs_modes[i].id); + if (mode_len > len) + continue; + + if (strncmp(lbuf, t300rs_modes[i].id, mode_len) == 0) { + t300rs_switch_mode(data, t300rs_modes[i].mode); + break; + } + } + + kfree(lbuf); + return count; +} + +int t300rs_set_autocenter(void *data, uint16_t value) +{ + struct t300rs_device_entry *t300rs = data; + struct __packed t300rs_packet_autocenter { + struct t300rs_setup_header header; + uint16_t value; + } *autocenter_packet; + int ret; + + if (!t300rs) + return -ENODEV; + + /* TODO: this should probably also use a separately allocated buffer? */ + autocenter_packet = (struct t300rs_packet_autocenter *)t300rs->send_buffer; + + autocenter_packet->header.cmd = 0x08; + autocenter_packet->header.code = 0x04; + autocenter_packet->value = cpu_to_le16(0x01); + + if ((ret = t300rs_send_int(t300rs))) { + hid_err(t300rs->hdev, "failed setting autocenter"); + return ret; + } + + autocenter_packet->header.cmd = 0x08; + autocenter_packet->header.code = 0x03; + + autocenter_packet->value = cpu_to_le16(value); + + if ((ret = t300rs_send_int(t300rs))) + hid_err(t300rs->hdev, "failed setting autocenter"); + + return ret; +} + +int t300rs_set_gain(void *data, uint16_t gain) +{ + struct t300rs_device_entry *t300rs = data; + struct __packed t300rs_packet_gain { + struct t300rs_setup_header header; + } *gain_packet; + int ret; + + if (!t300rs) + return -ENODEV; + + gain_packet = (struct t300rs_packet_gain *)t300rs->send_buffer; + gain_packet->header.cmd = 0x02; + gain_packet->header.code = (gain >> 8) & 0xff; + + if ((ret = t300rs_send_int(t300rs))) + hid_err(t300rs->hdev, "failed setting gain: %i\n", ret); + + return ret; +} + +int t300rs_set_range(void *data, uint16_t value) +{ + struct t300rs_device_entry *t300rs = data; + /* it's important that we don't use t300rs->send_buffer, as range can be + * set from outside of the FFB environment, and we don't want to + * accidentally overwrite any data. */ + u8 *send_buffer = kzalloc(t300rs->buffer_length, GFP_KERNEL); + uint16_t scaled_value; + int ret; + + if (value < 40) { + hid_info(t300rs->hdev, "value %i too small, clamping to 40\n", value); + value = 40; + } + + if (value > 1080) { + hid_info(t300rs->hdev, "value %i too large, clamping to 1080\n", value); + value = 1080; + } + + if (!send_buffer) { + ret = -EINVAL; + hid_err(t300rs->hdev, "could not allocate send_buffer\n"); + goto err; + } + + scaled_value = value * 0x3c; + send_buffer[0] = 0x08; + send_buffer[1] = 0x11; + send_buffer[2] = scaled_value & 0xff; + send_buffer[3] = scaled_value >> 8; + + if ((ret = t300rs_send_buf(t300rs, send_buffer, t300rs->buffer_length))) + hid_warn(t300rs->hdev, "failed setting range\n"); + + /* since everythin went OK, update the current range */ + range = value; +err: + kfree(send_buffer); + return ret; +} + +static int t300rs_send_open(struct t300rs_device_entry *t300rs) +{ + struct __packed t300rs_packet_open { + struct t300rs_setup_header header; + } *open_packet; + + open_packet = (struct t300rs_packet_open *)t300rs->send_buffer; + open_packet->header.cmd = 0x01; + open_packet->header.code = 0x05; + + return t300rs_send_int(t300rs); +} + +static int t300rs_send_close(struct t300rs_device_entry *t300rs) +{ + struct __packed t300rs_packet_open { + struct t300rs_setup_header header; + } *open_packet; + + open_packet = (struct t300rs_packet_open *)t300rs->send_buffer; + open_packet->header.cmd = 0x01; + + return t300rs_send_int(t300rs); +} + +int t300rs_open(void *data, int open_mode) +{ + struct t300rs_device_entry *t300rs = data; + if (!t300rs) + return -ENODEV; + + if (open_mode && t300rs_send_open(t300rs)) + hid_warn(t300rs->hdev, "failed sending open command\n"); + + return t300rs->open(t300rs->input_dev); +} + +int t300rs_close(void *data, int open_mode) +{ + struct t300rs_device_entry *t300rs = data; + int ret; + + if (!t300rs) + return -ENODEV; + + if (open_mode && (ret = t300rs_send_close(t300rs))) + hid_warn(t300rs->hdev, "failed sending close command\n"); + + t300rs->close(t300rs->input_dev); + return ret; +} + +static int t300rs_check_firmware(struct t300rs_device_entry *t300rs) +{ + int ret; + struct t300rs_fw_response *fw_response = + kzalloc(sizeof(struct t300rs_fw_response), GFP_KERNEL); + + if (!fw_response) { + hid_err(t300rs->hdev, "could not allocate fw_response\n"); + return -ENOMEM; + } + + /* Fetch firmware version */ + ret = usb_control_msg(t300rs->usbdev, + usb_rcvctrlpipe(t300rs->usbdev, 0), + t300rs_fw_request.bRequest, + t300rs_fw_request.bRequestType, + t300rs_fw_request.wValue, + t300rs_fw_request.wIndex, + fw_response, + t300rs_fw_request.wLength, + USB_CTRL_SET_TIMEOUT + ); + + if (ret < 0) { + hid_err(t300rs->hdev, "could not fetch firmware version: %i\n", ret); + goto out; + } + + /* Educated guess */ + if (fw_response->fw_version < 31 && ret >= 0) { + hid_err(t300rs->hdev, + "firmware version %i is too old, please update.\n", + fw_response->fw_version + ); + + hid_info(t300rs->hdev, "note: this has to be done through Windows.\n"); + + ret = -EINVAL; + goto out; + } + + /* everything OK */ + ret = 0; + +out: + kfree(fw_response); + return ret; +} + +static int t300rs_get_attachment(struct t300rs_device_entry *t300rs) +{ + /* taken directly from hid_tminit */ + struct __packed t300rs_attachment_response + { + uint16_t type; + + union { + struct __packed { + uint16_t field0; + uint16_t field1; + uint8_t attachment; + uint8_t model; + uint16_t field2; + uint16_t field3; + uint16_t field4; + uint16_t field5; + } a; + + struct __packed { + uint16_t field0; + uint16_t field1; + uint8_t attachment; + uint8_t model; + } b; + }; + } *response = kzalloc(GFP_KERNEL, sizeof(struct t300rs_attachment_response)); + struct usb_ctrlrequest t300rs_attachment_rq = { + .bRequestType = 0xc1, + .bRequest = 73, + .wValue = 0, + .wIndex = 0, + .wLength = sizeof(struct t300rs_attachment_response) + }; + int ret, attachment; + if (!response) + return -ENODEV; + + ret = usb_control_msg(t300rs->usbdev, + usb_rcvctrlpipe(t300rs->usbdev, 0), + t300rs_attachment_rq.bRequest, + t300rs_attachment_rq.bRequestType, + t300rs_attachment_rq.wValue, + t300rs_attachment_rq.wIndex, + response, + sizeof(struct t300rs_attachment_response), + USB_CTRL_SET_TIMEOUT + ); + + if (ret < 0) { + hid_err(t300rs->hdev, "could not fetch attachment: %i\n", ret); + goto out; + } + + if (response->type == cpu_to_le16(0x49)) { + attachment = response->a.attachment; + } else if (response->type == cpu_to_le16(0x47)) { + attachment = response->b.attachment; + } else { + hid_err(t300rs->hdev, "unknown packet type %hx\n, please contact a maintainer", + response->type); + ret = -EINVAL; + goto out; + } + + kfree(response); + return attachment; + +out: + kfree(response); + return ret; +} + +static int t300rs_wheel_init(struct tmff2_device_entry *tmff2, int open_mode) +{ + struct t300rs_device_entry *t300rs = kzalloc(sizeof(struct t300rs_device_entry), GFP_KERNEL); + struct list_head *report_list; + int ret; + + if (!t300rs) { + ret = -ENOMEM; + goto t300rs_err; + } + + t300rs->hdev = tmff2->hdev; + t300rs->input_dev = tmff2->input_dev; + t300rs->usbdev = to_usb_device(tmff2->hdev->dev.parent->parent); + + if(t300rs->hdev->product == TMT300RS_PS4_NORM_ID) + t300rs->buffer_length = T300RS_PS4_BUFFER_LENGTH; + else + t300rs->buffer_length = T300RS_NORM_BUFFER_LENGTH; + + t300rs->send_buffer = kzalloc(t300rs->buffer_length, GFP_KERNEL); + if (!t300rs->send_buffer) { + ret = -ENOMEM; + goto send_err; + } + + if ((ret = t300rs_check_firmware(t300rs))) + goto firmware_err; + + report_list = &t300rs->hdev->report_enum[HID_OUTPUT_REPORT].report_list; + + /* because we set the rdesc, we know exactly which report and field to use */ + t300rs->report = list_entry(report_list->next, struct hid_report, list); + t300rs->ff_field = t300rs->report->field[0]; + + t300rs->open = t300rs->input_dev->open; + t300rs->close = t300rs->input_dev->close; + + /* TODO: PS4 advanced mode? */ + alt_mode = (t300rs->mode = (t300rs->hdev->product == TMT300RS_PS3_ADV_ID)); + if ((t300rs->attachment = t300rs_get_attachment(t300rs)) < 0) + t300rs->attachment = T300RS_DEFAULT_ATTACHMENT; + + /* everythin went OK */ + tmff2->data = t300rs; + tmff2->params = t300rs_params; + tmff2->max_effects = T300RS_MAX_EFFECTS; + memcpy(tmff2->supported_effects, t300rs_effects, sizeof(t300rs_effects)); + + if (!open_mode) + t300rs_send_open(t300rs); + + hid_info(t300rs->hdev, "force feedback for T300RS\n"); + return 0; + +firmware_err: + kfree(t300rs->send_buffer); +send_err: + kfree(t300rs); +t300rs_err: + hid_err(tmff2->hdev, "failed initializing T300RS\n"); + return ret; +} + +static int t300rs_wheel_destroy(void *data) +{ + struct t300rs_device_entry *t300rs = data; + if (!t300rs) + return -ENODEV; + + kfree(t300rs->send_buffer); + kfree(t300rs); + return 0; +} + +static __u8 *t300rs_wheel_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + switch (hdev->product) { + case TMT300RS_PS3_NORM_ID: + /* normal PS3 mode */ + rdesc = t300rs_rdesc_nrm_fixed; + *rsize = sizeof(t300rs_rdesc_nrm_fixed); + break; + + case TMT300RS_PS4_NORM_ID: + /* PS4 normal mode */ + rdesc = t300rs_rdesc_ps4_fixed; + *rsize = sizeof(t300rs_rdesc_ps4_fixed); + break; + + case TMT300RS_PS3_ADV_ID: + /* PS3 advanced mode */ + rdesc = t300rs_rdesc_adv_fixed; + *rsize = sizeof(t300rs_rdesc_adv_fixed); + break; + } + + return rdesc; +} + +int t300rs_populate_api(struct tmff2_device_entry *tmff2) +{ + /* set callbacks */ + tmff2->play_effect = t300rs_play_effect; + tmff2->upload_effect = t300rs_upload_effect; + tmff2->update_effect = t300rs_update_effect; + tmff2->stop_effect = t300rs_stop_effect; + + tmff2->wheel_init = t300rs_wheel_init; + tmff2->wheel_destroy = t300rs_wheel_destroy; + + tmff2->open = t300rs_open; + tmff2->close = t300rs_close; + tmff2->set_gain = t300rs_set_gain; + tmff2->set_range = t300rs_set_range; + tmff2->switch_mode = t300rs_switch_mode; + tmff2->alt_mode_show = t300rs_alt_mode_show; + tmff2->alt_mode_store = t300rs_alt_mode_store; + tmff2->set_autocenter = t300rs_set_autocenter; + tmff2->wheel_fixup = t300rs_wheel_fixup; + + return 0; +} diff --git a/src/tmt300rs/hid-tmt300rs.h b/src/tmt300rs/hid-tmt300rs.h new file mode 100644 index 0000000..2305f4b --- /dev/null +++ b/src/tmt300rs/hid-tmt300rs.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef __HID_TMT300RS_H +#define __HID_TMT300RS_H + +#include "../hid-tmff2.h" + +int t300rs_populate_api(struct tmff2_device_entry *tmff2); + +#endif diff --git a/src/tmtx/hid-tmtx.c b/src/tmtx/hid-tmtx.c new file mode 100644 index 0000000..afca799 --- /dev/null +++ b/src/tmtx/hid-tmtx.c @@ -0,0 +1,323 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include +#include "../hid-tmff2.h" + +#define TMTX_MAX_EFFECTS 16 +#define TMTX_BUFFER_LENGTH 63 + +static const u8 setup_0[64] = { 0x42, 0x01 }; +static const u8 setup_1[64] = { 0x0a, 0x04, 0x90, 0x03 }; +static const u8 setup_2[64] = { 0x0a, 0x04, 0x00, 0x0c }; +static const u8 setup_3[64] = { 0x0a, 0x04, 0x12, 0x10 }; +static const u8 setup_4[64] = { 0x0a, 0x04, 0x00, 0x06 }; +static const u8 setup_5[64] = { 0x0a, 0x04, 0x00, 0x0e }; +static const u8 setup_6[64] = { 0x0a, 0x04, 0x00, 0x0e, 0x01 }; +static const u8 *const setup_arr[] = { setup_0, setup_1, setup_2, setup_3, setup_4, setup_5, setup_6 }; +static const unsigned int setup_arr_sizes[] = { + ARRAY_SIZE(setup_0), + ARRAY_SIZE(setup_1), + ARRAY_SIZE(setup_2), + ARRAY_SIZE(setup_3), + ARRAY_SIZE(setup_4), + ARRAY_SIZE(setup_5), + ARRAY_SIZE(setup_6) +}; + +static const unsigned long tx_params = + PARAM_SPRING_LEVEL + | PARAM_DAMPER_LEVEL + | PARAM_FRICTION_LEVEL + | PARAM_RANGE + | PARAM_GAIN + ; + +static const signed short tx_effects[] = { + FF_CONSTANT, + FF_RAMP, + FF_SPRING, + FF_DAMPER, + FF_FRICTION, + FF_INERTIA, + FF_PERIODIC, + FF_SINE, + FF_TRIANGLE, + FF_SQUARE, + FF_SAW_UP, + FF_SAW_DOWN, + FF_AUTOCENTER, + FF_GAIN, + -1 +}; + +/* TODO: sort through this stuff */ +static u8 tx_pc_rdesc_fixed[] = { + 0x05, 0x01, /* Usage page (Generic Desktop) */ + 0x09, 0x04, /* Usage (Joystick) */ + 0xa1, 0x01, /* Collection (Application) */ + 0x09, 0x01, /* Usage (Pointer) */ + 0xa1, 0x00, /* Collection (Physical) */ + 0x85, 0x07, /* Report ID (7) */ + 0x09, 0x30, /* Usage (X) */ + 0x15, 0x00, /* Logical minimum (0) */ + 0x27, 0xff, 0xff, 0x00, 0x00, /* Logical maximum (65535) */ + 0x35, 0x00, /* Physical minimum (0) */ + 0x47, 0xff, 0xff, 0x00, 0x00, /* Physical maximum (65535) */ + 0x75, 0x10, /* Report size (16) */ + 0x95, 0x01, /* Report count (1) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x09, 0x35, /* Usage (Rz) (Brake) */ + 0x26, 0xff, 0x03, /* Logical maximum (1023) */ + 0x46, 0xff, 0x03, /* Physical maximum (1023) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x09, 0x32, /* Usage (Z) (Gas) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x09, 0x31, /* Usage (Y) (Clutch) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x81, 0x03, /* Input (Variable, Absolute, Constant) */ + 0x05, 0x09, /* Usage page (Button) */ + 0x19, 0x01, /* Usage minimum (1) */ + 0x29, 0x0d, /* Usage maximum (13) */ + 0x25, 0x01, /* Logical maximum (1) */ + 0x45, 0x01, /* Physical maximum (1) */ + 0x75, 0x01, /* Report size (1) */ + 0x95, 0x0d, /* Report count (13) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x75, 0x0b, /* Report size (13) */ + 0x95, 0x01, /* Report count (1) */ + 0x81, 0x03, /* Usage (Variable, Absolute, Constant) */ + 0x05, 0x01, /* Usage page (Generic Desktop) */ + 0x09, 0x39, /* Usage (Hat Switch) */ + 0x25, 0x07, /* Logical maximum (7) */ + 0x46, 0x3b, 0x01, /* Physical maximum (315) */ + 0x55, 0x00, /* Unit exponent (0) */ + 0x65, 0x14, /* Unit (Eng Rot, Angular Pos) */ + 0x75, 0x04, /* Report size (4) */ + 0x81, 0x42, /* Input (Variable, Absolute, NullState) */ + 0x65, 0x00, /* Unit (None) */ + 0x81, 0x03, /* Input (Variable, Absolute, Constant) */ + 0x85, 0x60, /* Report ID (96), prev 10 */ + 0x06, 0x00, 0xff, /* Usage page (Vendor 1) */ + 0x09, 0x60, /* Usage (96), prev 10 */ + 0x75, 0x08, /* Report size (8) */ + 0x95, 0x3f, /* Report count (63) */ + 0x26, 0xff, 0x7f, /* Logical maximum (32767) */ + 0x15, 0x00, /* Logical minimum (0) */ + 0x46, 0xff, 0x7f, /* Physical maximum (32767) */ + 0x36, 0x00, 0x80, /* Physical minimum (-32768) */ + 0x91, 0x02, /* Output (Variable, Absolute) */ + 0x85, 0x02, /* Report ID (2) */ + 0x09, 0x02, /* Usage (2) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0x09, 0x14, /* Usage (20) */ + 0x85, 0x14, /* Report ID (20) */ + 0x81, 0x02, /* Input (Variable, Absolute) */ + 0xc0, /* End collection */ + 0xc0, /* End collection */ +}; + +static int tx_interrupts(struct t300rs_device_entry *tx) +{ + u8 *send_buf = kmalloc(256, GFP_KERNEL); + struct usb_interface *usbif = to_usb_interface(tx->hdev->dev.parent); + struct usb_host_endpoint *ep; + int ret, trans, b_ep, i; + + if (!send_buf) { + hid_err(tx->hdev, "failed allocating send buffer\n"); + return -ENOMEM; + } + + ep = &usbif->cur_altsetting->endpoint[1]; + b_ep = ep->desc.bEndpointAddress; + + for (i = 0; i < ARRAY_SIZE(setup_arr); ++i) { + memcpy(send_buf, setup_arr[i], setup_arr_sizes[i]); + + ret = usb_interrupt_msg(tx->usbdev, + usb_sndintpipe(tx->usbdev, b_ep), + send_buf, setup_arr_sizes[i], + &trans, + USB_CTRL_SET_TIMEOUT); + + if (ret) { + hid_err(tx->hdev, "setup data couldn't be sent\n"); + goto err; + } + } + +err: + kfree(send_buf); + return ret; +} + +int tx_wheel_destroy(void *data) +{ + struct t300rs_device_entry *t300rs = data; + + if (!t300rs) + return -ENODEV; + + kfree(t300rs->send_buffer); + kfree(t300rs); + return 0; +} + +int tx_set_range(void *data, uint16_t value) +{ + struct t300rs_device_entry *tx = data; + + if (value < 140) { + hid_info(tx->hdev, "value %i too small, clamping to 140\n", value); + value = 140; + } + + if (value > 900) { + hid_info(tx->hdev, "value %i too large, clamping to 900\n", value); + value = 900; + } + + return t300rs_set_range(data, value); +} + +static int tx_send_open(struct t300rs_device_entry *tx) +{ + int r1, r2; + tx->send_buffer[0] = 0x01; + tx->send_buffer[1] = 0x04; + if ((r1 = t300rs_send_int(tx))) + return r1; + + tx->send_buffer[0] = 0x01; + tx->send_buffer[1] = 0x05; + if ((r2 = t300rs_send_int(tx))) + return r2; + + return 0; +} + +static int tx_open(void *data, int open_mode) +{ + struct t300rs_device_entry *tx = data; + + if (!tx) + return -ENODEV; + + if (open_mode) + tx_send_open(tx); + + return tx->open(tx->input_dev); +} + +static int tx_send_close(struct t300rs_device_entry *tx) +{ + int r1, r2; + tx->send_buffer[0] = 0x01; + tx->send_buffer[1] = 0x05; + if ((r1 = t300rs_send_int(tx))) + return r1; + + tx->send_buffer[0] = 0x01; + tx->send_buffer[1] = 0x00; + if ((r2 = t300rs_send_int(tx))) + return r2; + + return 0; +} + +static int tx_close(void *data, int open_mode) +{ + struct t300rs_device_entry *tx = data; + + if (!tx) + return -ENODEV; + + if (open_mode) + tx_send_close(tx); + + tx->close(tx->input_dev); + return 0; +} + +int tx_wheel_init(struct tmff2_device_entry *tmff2, int open_mode) +{ + struct t300rs_device_entry *tx = kzalloc(sizeof(struct t300rs_device_entry), GFP_KERNEL); + struct list_head *report_list; + int ret; + + + if (!tx) { + ret = -ENOMEM; + goto tx_err; + } + + tx->hdev = tmff2->hdev; + tx->input_dev = tmff2->input_dev; + tx->usbdev = to_usb_device(tmff2->hdev->dev.parent->parent); + tx->buffer_length = TMTX_BUFFER_LENGTH; + + tx->send_buffer = kzalloc(tx->buffer_length, GFP_KERNEL); + if (!tx->send_buffer) { + ret = -ENOMEM; + goto send_err; + } + + report_list = &tx->hdev->report_enum[HID_OUTPUT_REPORT].report_list; + tx->report = list_entry(report_list->next, struct hid_report, list); + tx->ff_field = tx->report->field[0]; + + tx->open = tx->input_dev->open; + tx->close = tx->input_dev->close; + + if ((ret = tx_interrupts(tx))) + goto interrupt_err; + + /* everything went OK */ + tmff2->data = tx; + tmff2->params = tx_params; + tmff2->max_effects = TMTX_MAX_EFFECTS; + memcpy(tmff2->supported_effects, tx_effects, sizeof(tx_effects)); + + if (!open_mode) + tx_send_open(tx); + + hid_info(tx->hdev, "force feedback for TX\n"); + return 0; + +interrupt_err: +send_err: + kfree(tx); +tx_err: + hid_err(tmff2->hdev, "failed initializing TX\n"); + return ret; +} + +static __u8 *tx_wheel_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + rdesc = tx_pc_rdesc_fixed; + *rsize = sizeof(tx_pc_rdesc_fixed); + return rdesc; +} + +int tx_populate_api(struct tmff2_device_entry *tmff2) +{ + tmff2->play_effect = t300rs_play_effect; + tmff2->upload_effect = t300rs_upload_effect; + tmff2->update_effect = t300rs_update_effect; + tmff2->stop_effect = t300rs_stop_effect; + + tmff2->set_gain = t300rs_set_gain; + tmff2->set_autocenter = t300rs_set_autocenter; + /* TX only has 900 degree range, instead of T300RS 1080 */ + tmff2->set_range = tx_set_range; + tmff2->wheel_fixup = tx_wheel_fixup; + + tmff2->open = tx_open; + tmff2->close = tx_close; + + tmff2->wheel_init = tx_wheel_init; + tmff2->wheel_destroy = tx_wheel_destroy; + + return 0; +} -- cgit v1.3