diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2026-08-09 23:00:08 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-08-09 23:00:08 +0300 |
| commit | c5b9b79d4e61b77e0827e81dd676420b3c366743 (patch) | |
| tree | 4f61319e1e020578511c5f2e34db9cc119fd5995 | |
| parent | 9d8577ba2a2c8e3d96cfdb7be4201e4e230e210f (diff) | |
| parent | 4c142e19d14d02d0149198274b0f3f11091c71c6 (diff) | |
| download | hid-tmff2-c5b9b79d4e61b77e0827e81dd676420b3c366743.tar.gz hid-tmff2-c5b9b79d4e61b77e0827e81dd676420b3c366743.zip | |
Merge pull request #211 from kakra/t300-correctness-fixes
fix force feedback arithmetic and wheel input filtering
| -rw-r--r-- | src/hid-tmff2.c | 45 | ||||
| -rw-r--r-- | src/hid-tmff2.h | 2 | ||||
| -rw-r--r-- | src/tmt300rs/hid-tmt300rs.c | 32 |
3 files changed, 57 insertions, 22 deletions
diff --git a/src/hid-tmff2.c b/src/hid-tmff2.c index 162a30a..55e2173 100644 --- a/src/hid-tmff2.c +++ b/src/hid-tmff2.c @@ -43,11 +43,16 @@ MODULE_PARM_DESC(alt_mode, "Alternate mode, eg. F1 mode"); #define GAIN_MAX 65535 -int gain = 40000; -module_param(gain, int, 0); +u16 gain = 40000; +module_param(gain, ushort, 0); MODULE_PARM_DESC(gain, "Level of gain (0-65535)"); +static u16 tmff2_scale_gain(u16 value) +{ + return (u32)value * gain / GAIN_MAX; +} + static spinlock_t lock; static struct tmff2_device_entry *tmff2_from_hdev(struct hid_device *hdev) @@ -230,20 +235,21 @@ static ssize_t gain_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct tmff2_device_entry *tmff2 = tmff2_from_hdev(to_hid_device(dev)); - unsigned int value; + u16 value; int ret; if (!tmff2) return -ENODEV; - if ((ret = kstrtouint(buf, 0, &value))) { - dev_err(dev, "kstrtouint failed at gain_store: %i", ret); + ret = kstrtou16(buf, 0, &value); + if (ret) { + dev_err(dev, "failed to parse gain: %d\n", ret); return ret; } gain = value; if (tmff2->set_gain) /* if we can, update gain immediately */ - tmff2->set_gain(tmff2->data, (GAIN_MAX * gain) / GAIN_MAX); + tmff2->set_gain(tmff2->data, gain); return count; } @@ -251,7 +257,7 @@ static ssize_t gain_store(struct device *dev, static ssize_t gain_show(struct device *dev, struct device_attribute *attr, char *buf) { - return scnprintf(buf, PAGE_SIZE, "%i\n", gain); + return scnprintf(buf, PAGE_SIZE, "%u\n", gain); } static DEVICE_ATTR_RW(gain); @@ -267,7 +273,7 @@ static void tmff2_set_gain(struct input_dev *dev, uint16_t value) return; } - if (tmff2->set_gain(tmff2->data, (value * gain) / GAIN_MAX)) + if (tmff2->set_gain(tmff2->data, tmff2_scale_gain(value))) hid_warn(tmff2->hdev, "unable to set gain\n"); } @@ -643,7 +649,7 @@ static int tmff2_wheel_init(struct tmff2_device_entry *tmff2) /* set defaults wherever possible */ if (tmff2->set_gain) { ff->set_gain = tmff2_set_gain; - tmff2->set_gain(tmff2->data, (GAIN_MAX * gain) / GAIN_MAX); + tmff2->set_gain(tmff2->data, gain); } if (tmff2->set_autocenter) @@ -801,6 +807,26 @@ static void tmff2_remove(struct hid_device *hdev) kfree(tmff2); } +static int tmff2_input_configured(struct hid_device *hdev, + struct hid_input *hidinput) +{ + struct input_dev *input = hidinput->input; + int axis; + + if (!input->absinfo) + return 0; + + for (axis = ABS_X; axis <= ABS_BRAKE; axis++) { + if (!test_bit(axis, input->absbit)) + continue; + + input_abs_set_fuzz(input, axis, 0); + input_abs_set_flat(input, axis, 0); + } + + return 0; +} + static const struct hid_device_id tmff2_devices[] = { /* t300rs and variations */ {HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, TMT300RS_PS3_NORM_ID)}, @@ -825,6 +851,7 @@ static struct hid_driver tmff2_driver = { .probe = tmff2_probe, .remove = tmff2_remove, .report_fixup = tmff2_report_fixup, + .input_configured = tmff2_input_configured, }; module_hid_driver(tmff2_driver); diff --git a/src/hid-tmff2.h b/src/hid-tmff2.h index 6ad1d82..58ab8f3 100644 --- a/src/hid-tmff2.h +++ b/src/hid-tmff2.h @@ -11,7 +11,7 @@ extern int spring_level; extern int damper_level; extern int friction_level; extern int range; -extern int gain; +extern u16 gain; extern int alt_mode; #define USB_VENDOR_ID_THRUSTMASTER 0x044f diff --git a/src/tmt300rs/hid-tmt300rs.c b/src/tmt300rs/hid-tmt300rs.c index 00eecee..78e1939 100644 --- a/src/tmt300rs/hid-tmt300rs.c +++ b/src/tmt300rs/hid-tmt300rs.c @@ -344,30 +344,35 @@ static uint16_t t300rs_calculate_length(uint16_t length) return length; } +static s32 t300rs_scale_direction(s16 level, u16 direction) +{ + return (s32)level * fixp_sin16(direction * 360 / 0x10000) / 0x7fff; +} + static int16_t t300rs_calculate_constant_level(int16_t level, uint16_t direction) { - level = (level * fixp_sin16(direction * 360 / 0x10000)) / 0x7fff; + s32 scaled_level = t300rs_scale_direction(level, direction); /* the Windows driver uses the range [-16385;16381] */ - level = level / 2; - - return level; + return scaled_level / 2; } static void t300rs_calculate_periodic_values(struct ff_effect *effect) { struct ff_periodic_effect *periodic = &effect->u.periodic; - int16_t headroom; + s32 magnitude, headroom; - periodic->magnitude = (periodic->magnitude * fixp_sin16(effect->direction * 360 / 0x10000)) / 0x7fff; + magnitude = t300rs_scale_direction(periodic->magnitude, + effect->direction); - if (periodic->magnitude < 0){ + if (magnitude < 0) { /* the wheel handles positive magnitudes only */ - periodic->magnitude = -periodic->magnitude; + magnitude = -magnitude; /* to give the expected result 180 deg is added to the phase */ periodic->phase = (periodic->phase + (0x10000 / 2)) % 0x10000; } + periodic->magnitude = min_t(s32, magnitude, S16_MAX); /* the interval [0; 32677[ is used by the wheel for the [0; 360[ degree phase shift */ periodic->phase = periodic->phase * 32677 / 0x10000; @@ -443,13 +448,16 @@ static void t300rs_calculate_ramp_parameters(uint16_t *out_slope, { struct ff_ramp_effect *ramp = &effect->u.ramp; - int16_t start_level, end_level; + s32 start_level, end_level; - start_level = (ramp->start_level * fixp_sin16(effect->direction * 360 / 0x10000)) / 0x7fff; - end_level = (ramp->end_level * fixp_sin16(effect->direction * 360 / 0x10000)) / 0x7fff; + start_level = t300rs_scale_direction(ramp->start_level, + effect->direction); + end_level = t300rs_scale_direction(ramp->end_level, + effect->direction); *out_slope = abs(start_level - end_level) / 2; - *out_center = (start_level + end_level) / 2; + *out_center = clamp_t(s32, (start_level + end_level) / 2, + S16_MIN, S16_MAX); *out_invert = (start_level < end_level) ? 0x04 : 0x05; } |
