aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKai Krakow <kai@kaishome.de>2026-08-08 12:27:06 +0200
committerKai Krakow <kai@kaishome.de>2026-08-09 00:20:08 +0200
commit465ce84d2997e5af6630b88d88b63509d5a88031 (patch)
tree9d25a8d70ddbcda28d261fd5bd20fd8756c92ada
parentf014217288927246f92ee876afbbf9de8ba707be (diff)
downloadhid-tmff2-465ce84d2997e5af6630b88d88b63509d5a88031.tar.gz
hid-tmff2-465ce84d2997e5af6630b88d88b63509d5a88031.zip
avoid signed overflow when scaling gain
+ FF_GAIN and the driver gain both use the full 16-bit range. Their product can exceed INT_MAX. Signed overflow is undefined and happens for common settings such as 75 percent times 75 percent. Use a u32 intermediate for the scaling operation. + Pass the configured gain directly when initializing or updating the hardware. This also removes two redundant multiply-divide expressions which could overflow before cancelling out.
-rw-r--r--src/hid-tmff2.c11
1 files changed, 8 insertions, 3 deletions
diff --git a/src/hid-tmff2.c b/src/hid-tmff2.c
index 9cf07b9..02e70f1 100644
--- a/src/hid-tmff2.c
+++ b/src/hid-tmff2.c
@@ -48,6 +48,11 @@ 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)
@@ -244,7 +249,7 @@ static ssize_t gain_store(struct device *dev,
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;
}
@@ -268,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");
}
@@ -644,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)