Commit f345a479 authored by Tomasz Pakuła's avatar Tomasz Pakuła Committed by Jiri Kosina
Browse files

HID: pidff: Use direction fix only for conditional effects



The already fixed bug in SDL only affected conditional effects. This
should fix FFB in Forza Horizion 4/5 on Moza Devices as Forza Horizon
flips the constant force direction instead of using negative magnitude
values.

Changing the direction in the effect directly in pidff_upload_effect()
would affect it's value in further operations like comparing to the old
effect and/or just reading the effect values in the user application.

This, in turn, would lead to constant PID_SET_EFFECT spam as the effect
direction would constantly not match the value that's set by the
application.

This way, it's still transparent to any software/API.

Only affects conditional effects now so it's better for it to explicitly
state that in the name. If any HW ever needs fixed direction for other
effects, we'll add more quirks.

Signed-off-by: default avatarTomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Reviewed-by: default avatarOleg Makarenko <oleg@makarenk.ooo>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.com>
parent b80a75cf
Loading
Loading
Loading
Loading
+10 −10
Original line number Diff line number Diff line
@@ -144,25 +144,25 @@ static int universal_pidff_input_configured(struct hid_device *hdev,

static const struct hid_device_id universal_pidff_devices[] = {
	{ HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R3),
		.driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
		.driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION },
	{ HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R3_2),
		.driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
		.driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION },
	{ HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R5),
		.driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
		.driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION },
	{ HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R5_2),
		.driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
		.driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION },
	{ HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R9),
		.driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
		.driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION },
	{ HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R9_2),
		.driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
		.driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION },
	{ HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R12),
		.driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
		.driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION },
	{ HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R12_2),
		.driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
		.driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION },
	{ HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R16_R21),
		.driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
		.driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION },
	{ HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R16_R21_2),
		.driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
		.driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION },
	{ HID_USB_DEVICE(USB_VENDOR_ID_CAMMUS, USB_DEVICE_ID_CAMMUS_C5) },
	{ HID_USB_DEVICE(USB_VENDOR_ID_CAMMUS, USB_DEVICE_ID_CAMMUS_C12) },
	{ HID_USB_DEVICE(USB_VENDOR_ID_VRS, USB_DEVICE_ID_VRS_DFP),
+23 −5
Original line number Diff line number Diff line
@@ -205,6 +205,14 @@ struct pidff_device {
	u8 effect_count;
};

static int pidff_is_effect_conditional(struct ff_effect *effect)
{
	return effect->type == FF_SPRING  ||
	       effect->type == FF_DAMPER  ||
	       effect->type == FF_INERTIA ||
	       effect->type == FF_FRICTION;
}

/*
 * Clamp value for a given field
 */
@@ -294,6 +302,20 @@ static void pidff_set_duration(struct pidff_usage *usage, u16 duration)
	pidff_set_time(usage, duration);
}

static void pidff_set_effect_direction(struct pidff_device *pidff,
				       struct ff_effect *effect)
{
	u16 direction = effect->direction;

	/* Use fixed direction if needed */
	if (pidff->quirks & HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION &&
	    pidff_is_effect_conditional(effect))
		direction = PIDFF_FIXED_WHEEL_DIRECTION;

	pidff->effect_direction->value[0] =
		pidff_rescale(direction, U16_MAX, pidff->effect_direction);
}

/*
 * Send envelope report to the device
 */
@@ -395,11 +417,7 @@ static void pidff_set_effect_report(struct pidff_device *pidff,
		pidff->set_effect[PID_GAIN].field->logical_maximum;
	pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1;

	/* Use fixed direction if needed */
	pidff->effect_direction->value[0] = pidff_rescale(
		pidff->quirks & HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION ?
		PIDFF_FIXED_WHEEL_DIRECTION : effect->direction,
		U16_MAX, pidff->effect_direction);
	pidff_set_effect_direction(pidff, effect);

	/* Omit setting delay field if it's missing */
	if (!(pidff->quirks & HID_PIDFF_QUIRK_MISSING_DELAY))
+1 −1
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@
#define HID_PIDFF_QUIRK_PERMISSIVE_CONTROL	BIT(2)

/* Use fixed 0x4000 direction during SET_EFFECT report upload */
#define HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION	BIT(3)
#define HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION	BIT(3)

/* Force all periodic effects to be uploaded as SINE */
#define HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY	BIT(4)