diff --git a/hid-moza.c b/hid-moza.c index d1ba7e7..8e6e963 100644 --- a/hid-moza.c +++ b/hid-moza.c @@ -9,6 +9,7 @@ #include #include #include "hid-moza.h" +#include "hid-pidff.h" static const struct hid_device_id moza_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R3) }, @@ -32,8 +33,8 @@ static u8 *moza_report_fixup(struct hid_device *hdev, __u8 *rdesc, } -static int moza_probe(struct hid_device *hdev, - const struct hid_device_id *id) +static int moza_probe(struct hid_device *hdev, + const struct hid_device_id *id) { int ret; ret = hid_parse(hdev); @@ -48,7 +49,12 @@ static int moza_probe(struct hid_device *hdev, goto err; } - ret = hid_pidff_init_moza(hdev); + /* set PIDFF quirks for moza wheelbases */ + unsigned quirks = 0; + quirks |= PIDFF_QUIRK_FIX_0_INFINITE_LENGTH; + quirks |= PIDFF_QUIRK_FIX_WHEEL_DIRECTION; + + ret = hid_pidff_init_with_quirks(hdev, quirks); if (ret) { hid_warn(hdev, "Force feedback not supported\n"); goto err; @@ -60,10 +66,10 @@ err: } static int moza_input_configured(struct hid_device *hdev, - struct hid_input *hidinput) + struct hid_input *hidinput) { struct input_dev *input = hidinput->input; - input_set_abs_params(input, ABS_X, + input_set_abs_params(input, ABS_X, input->absinfo[ABS_X].minimum, input->absinfo[ABS_X].maximum, 0, 0); return 0; diff --git a/hid-moza.h b/hid-moza.h index c173d5b..b3c4adb 100644 --- a/hid-moza.h +++ b/hid-moza.h @@ -10,6 +10,4 @@ #define USB_DEVICE_ID_MOZA_R16 0x0000 #define USB_DEVICE_ID_MOZA_R21 0x0000 -int hid_pidff_init_moza(struct hid_device *hdev); - #endif diff --git a/hid-pidff.c b/hid-pidff.c index 2221b68..59e1c6d 100644 --- a/hid-pidff.c +++ b/hid-pidff.c @@ -3,6 +3,8 @@ * Force feedback driver for USB HID PID compliant devices * * Copyright (c) 2005, 2006 Anssi Hannula + * Copyright (c) 2024 Oleg Makarenko + * Copyright (c) 2024 Tomasz PakuĊ‚a */ /* @@ -19,6 +21,7 @@ #include //#include "usbhid.h" +#include "hid-pidff.h" #define PID_EFFECTS_MAX 64 @@ -184,6 +187,7 @@ struct pidff_device { int operation_id[sizeof(pidff_effect_operation_status)]; int pid_id[PID_EFFECTS_MAX]; + unsigned quirks; }; /* @@ -297,21 +301,35 @@ static int pidff_needs_set_constant(struct ff_effect *effect, static void pidff_set_effect_report(struct pidff_device *pidff, struct ff_effect *effect) { + /* check for device quirks */ + unsigned short direction = effect->direction; + unsigned short length = effect->replay.length; + + if (pidff->quirks & PIDFF_QUIRK_FIX_0_INFINITE_LENGTH && length == 0) + length = 0xffff; + + if ((effect->type == FF_DAMPER || + effect->type == FF_FRICTION || + effect->type == FF_SPRING || + effect->type == FF_INERTIA) && + pidff->quirks & PIDFF_QUIRK_FIX_WHEEL_DIRECTION) + direction = 0x3FFF; + pidff->set_effect[PID_EFFECT_BLOCK_INDEX].value[0] = pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; pidff->set_effect_type->value[0] = pidff->create_new_effect_type->value[0]; - pidff->set_effect[PID_DURATION].value[0] = - effect->replay.length == 0 ? 0xffff: effect->replay.length; - pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = effect->trigger.button; + pidff->set_effect[PID_DURATION].value[0] = length; + pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = + effect->trigger.button; pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] = effect->trigger.interval; pidff->set_effect[PID_GAIN].value[0] = pidff->set_effect[PID_GAIN].field->logical_maximum; pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1; pidff->effect_direction->value[0] = - pidff_rescale(effect->direction, 0xffff, - pidff->effect_direction); + pidff_rescale(direction, 0xffff, pidff->effect_direction); + pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay; hid_hw_request(pidff->hid, pidff->reports[PID_SET_EFFECT], @@ -499,12 +517,13 @@ static void pidff_playback_pid(struct pidff_device *pidff, int pid_id, int n) } else { pidff->effect_operation_status->value[0] = pidff->operation_id[PID_EFFECT_START]; - - n = clamp(n, pidff->effect_operation[PID_LOOP_COUNT].field->logical_minimum, + + n = clamp(n, pidff->effect_operation[PID_LOOP_COUNT].field->logical_minimum, pidff->effect_operation[PID_LOOP_COUNT].field->logical_maximum); pidff->effect_operation[PID_LOOP_COUNT].value[0] = n; } + hid_dbg(pidff->hid, "Playing effect %d %d times\n", pid_id, n); hid_hw_request(pidff->hid, pidff->reports[PID_EFFECT_OPERATION], HID_REQ_SET_REPORT); } @@ -1231,7 +1250,7 @@ static int pidff_check_autocenter(struct pidff_device *pidff, /* * Check if the device is PID and initialize it */ -int hid_pidff_init_moza(struct hid_device *hid) +int hid_pidff_init(struct hid_device *hid) { struct pidff_device *pidff; struct hid_input *hidinput = list_entry(hid->inputs.next, @@ -1253,6 +1272,7 @@ int hid_pidff_init_moza(struct hid_device *hid) return -ENOMEM; pidff->hid = hid; + pidff->quirks = 0; hid_device_io_start(hid); @@ -1318,7 +1338,7 @@ int hid_pidff_init_moza(struct hid_device *hid) ff->set_autocenter = pidff_set_autocenter; ff->playback = pidff_playback; - hid_info(dev, "Force feedback for Moza wheel\n"); + hid_info(dev, "Force feedback for USB HID PID devices\n"); hid_device_io_stop(hid); @@ -1330,3 +1350,29 @@ int hid_pidff_init_moza(struct hid_device *hid) kfree(pidff); return error; } + +/* + * Check if the device is PID and initialize it + * Add quirks after initialisation + */ +int hid_pidff_init_with_quirks(struct hid_device *hid, unsigned quirks) +{ + int error = hid_pidff_init(hid); + + if (error) + return error; + + struct hid_input *hidinput = list_entry(hid->inputs.next, + struct hid_input, list); + struct input_dev *dev = hidinput->input; + struct pidff_device *pidff = dev->ff->private; + + /* set quirks on the pidff device */ + hid_device_io_start(hid); + pidff->quirks |= quirks; + hid_device_io_stop(hid); + + hid_dbg(dev, "Device quirks: %d\n", pidff->quirks); + + return 0; +} diff --git a/hid-pidff.h b/hid-pidff.h new file mode 100644 index 0000000..90eab45 --- /dev/null +++ b/hid-pidff.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __HID_PIDFF_H +#define __HID_PIDFF_H + +/* PIDFF Quirks to solve issues with certain devices */ + +/* + * Substitute 0 length with 0xffff to resolve issues with + * infinite effects coming from windows API +*/ +#define PIDFF_QUIRK_FIX_0_INFINITE_LENGTH BIT(0) + +/* + * Ignore direction for spring/damping/friction/inertia effects + * and always set 16384 +*/ +#define PIDFF_QUIRK_FIX_WHEEL_DIRECTION BIT(1) + +int hid_pidff_init(struct hid_device *hid); +int hid_pidff_init_with_quirks(struct hid_device *hid, unsigned quirks); + +#endif