Skip to content

Commit 8713107

Browse files
LawstorantJiri Kosina
authored andcommitted
HID: pidff: Rescale time values to match field units
PID devices can use different exponents for time fields, while Linux Force Feedback API only supports miliseconds. Read the exponent of a given time field and scale its value accordingly. Changes in v7: - Rescale all time fields, not only period changes in v9: - Properly assign fade_lenght, not attack_length to PID_FADE_TIME Co-developed-by: Makarenko Oleg <oleg@makarenk.ooo> Signed-off-by: Makarenko Oleg <oleg@makarenk.ooo> Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com> Reviewed-by: Michał Kopeć <michal@nozomi.space> Reviewed-by: Paul Dino Jones <paul@spacefreak18.xyz> Tested-by: Paul Dino Jones <paul@spacefreak18.xyz> Tested-by: Cristóferson Bueno <cbueno81@gmail.com> Tested-by: Pablo Cisneros <patchkez@protonmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.com>
1 parent 1c12f13 commit 8713107

File tree

1 file changed

+54
-15
lines changed

1 file changed

+54
-15
lines changed

drivers/hid/usbhid/hid-pidff.c

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
#define PID_EFFECTS_MAX 64
2323
#define PID_INFINITE 0xffff
2424

25+
/* Linux Force Feedback API uses miliseconds as time unit */
26+
#define FF_TIME_EXPONENT -3
27+
2528
/* Report usage table used to put reports into an array */
2629

2730
#define PID_SET_EFFECT 0
@@ -231,6 +234,24 @@ static int pidff_rescale_signed(int i, struct hid_field *field)
231234
field->logical_minimum / -0x8000;
232235
}
233236

237+
/*
238+
* Scale time value from Linux default (ms) to field units
239+
*/
240+
static u32 pidff_rescale_time(u16 time, struct hid_field *field)
241+
{
242+
u32 scaled_time = time;
243+
int exponent = field->unit_exponent;
244+
pr_debug("time field exponent: %d\n", exponent);
245+
246+
for (;exponent < FF_TIME_EXPONENT; exponent++)
247+
scaled_time *= 10;
248+
for (;exponent > FF_TIME_EXPONENT; exponent--)
249+
scaled_time /= 10;
250+
251+
pr_debug("time calculated from %d to %d\n", time, scaled_time);
252+
return scaled_time;
253+
}
254+
234255
static void pidff_set(struct pidff_usage *usage, u16 value)
235256
{
236257
usage->value[0] = pidff_rescale(value, 0xffff, usage->field);
@@ -252,6 +273,27 @@ static void pidff_set_signed(struct pidff_usage *usage, s16 value)
252273
pr_debug("calculated from %d to %d\n", value, usage->value[0]);
253274
}
254275

276+
static void pidff_set_time(struct pidff_usage *usage, u16 time)
277+
{
278+
u32 modified_time = pidff_rescale_time(time, usage->field);
279+
usage->value[0] = pidff_clamp(modified_time, usage->field);
280+
}
281+
282+
static void pidff_set_duration(struct pidff_usage *usage, u16 duration)
283+
{
284+
/* Convert infinite length from Linux API (0)
285+
to PID standard (NULL) if needed */
286+
if (duration == 0)
287+
duration = PID_INFINITE;
288+
289+
if (duration == PID_INFINITE) {
290+
usage->value[0] = PID_INFINITE;
291+
return;
292+
}
293+
294+
pidff_set_time(usage, duration);
295+
}
296+
255297
/*
256298
* Send envelope report to the device
257299
*/
@@ -270,8 +312,10 @@ static void pidff_set_envelope_report(struct pidff_device *pidff,
270312
0x7fff ? 0x7fff : envelope->fade_level, 0x7fff,
271313
pidff->set_envelope[PID_FADE_LEVEL].field);
272314

273-
pidff->set_envelope[PID_ATTACK_TIME].value[0] = envelope->attack_length;
274-
pidff->set_envelope[PID_FADE_TIME].value[0] = envelope->fade_length;
315+
pidff_set_time(&pidff->set_envelope[PID_ATTACK_TIME],
316+
envelope->attack_length);
317+
pidff_set_time(&pidff->set_envelope[PID_FADE_TIME],
318+
envelope->fade_length);
275319

276320
hid_dbg(pidff->hid, "attack %u => %d\n",
277321
envelope->attack_level,
@@ -340,14 +384,12 @@ static void pidff_set_effect_report(struct pidff_device *pidff,
340384
pidff->set_effect_type->value[0] =
341385
pidff->create_new_effect_type->value[0];
342386

343-
/* Convert infinite length from Linux API (0)
344-
to PID standard (NULL) if needed */
345-
pidff->set_effect[PID_DURATION].value[0] =
346-
effect->replay.length == 0 ? PID_INFINITE : effect->replay.length;
387+
pidff_set_duration(&pidff->set_effect[PID_DURATION],
388+
effect->replay.length);
347389

348390
pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = effect->trigger.button;
349-
pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] =
350-
effect->trigger.interval;
391+
pidff_set_time(&pidff->set_effect[PID_TRIGGER_REPEAT_INT],
392+
effect->trigger.interval);
351393
pidff->set_effect[PID_GAIN].value[0] =
352394
pidff->set_effect[PID_GAIN].field->logical_maximum;
353395
pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1;
@@ -360,7 +402,8 @@ static void pidff_set_effect_report(struct pidff_device *pidff,
360402

361403
/* Omit setting delay field if it's missing */
362404
if (!(pidff->quirks & HID_PIDFF_QUIRK_MISSING_DELAY))
363-
pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay;
405+
pidff_set_time(&pidff->set_effect[PID_START_DELAY],
406+
effect->replay.delay);
364407

365408
hid_hw_request(pidff->hid, pidff->reports[PID_SET_EFFECT],
366409
HID_REQ_SET_REPORT);
@@ -392,15 +435,11 @@ static void pidff_set_periodic_report(struct pidff_device *pidff,
392435
pidff_set_signed(&pidff->set_periodic[PID_OFFSET],
393436
effect->u.periodic.offset);
394437
pidff_set(&pidff->set_periodic[PID_PHASE], effect->u.periodic.phase);
395-
396-
/* Clamp period to ensure the device can play the effect */
397-
pidff->set_periodic[PID_PERIOD].value[0] =
398-
pidff_clamp(effect->u.periodic.period,
399-
pidff->set_periodic[PID_PERIOD].field);
438+
pidff_set_time(&pidff->set_periodic[PID_PERIOD],
439+
effect->u.periodic.period);
400440

401441
hid_hw_request(pidff->hid, pidff->reports[PID_SET_PERIODIC],
402442
HID_REQ_SET_REPORT);
403-
404443
}
405444

406445
/*

0 commit comments

Comments
 (0)