162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Force feedback driver for USB HID PID compliant devices
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula@gmail.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/*
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci/* #define DEBUG */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/input.h>
1662306a36Sopenharmony_ci#include <linux/slab.h>
1762306a36Sopenharmony_ci#include <linux/usb.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <linux/hid.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include "usbhid.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define	PID_EFFECTS_MAX		64
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/* Report usage table used to put reports into an array */
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define PID_SET_EFFECT		0
2862306a36Sopenharmony_ci#define PID_EFFECT_OPERATION	1
2962306a36Sopenharmony_ci#define PID_DEVICE_GAIN		2
3062306a36Sopenharmony_ci#define PID_POOL		3
3162306a36Sopenharmony_ci#define PID_BLOCK_LOAD		4
3262306a36Sopenharmony_ci#define PID_BLOCK_FREE		5
3362306a36Sopenharmony_ci#define PID_DEVICE_CONTROL	6
3462306a36Sopenharmony_ci#define PID_CREATE_NEW_EFFECT	7
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define PID_REQUIRED_REPORTS	7
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define PID_SET_ENVELOPE	8
3962306a36Sopenharmony_ci#define PID_SET_CONDITION	9
4062306a36Sopenharmony_ci#define PID_SET_PERIODIC	10
4162306a36Sopenharmony_ci#define PID_SET_CONSTANT	11
4262306a36Sopenharmony_ci#define PID_SET_RAMP		12
4362306a36Sopenharmony_cistatic const u8 pidff_reports[] = {
4462306a36Sopenharmony_ci	0x21, 0x77, 0x7d, 0x7f, 0x89, 0x90, 0x96, 0xab,
4562306a36Sopenharmony_ci	0x5a, 0x5f, 0x6e, 0x73, 0x74
4662306a36Sopenharmony_ci};
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/* device_control is really 0x95, but 0x96 specified as it is the usage of
4962306a36Sopenharmony_cithe only field in that report */
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/* Value usage tables used to put fields and values into arrays */
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#define PID_EFFECT_BLOCK_INDEX	0
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#define PID_DURATION		1
5662306a36Sopenharmony_ci#define PID_GAIN		2
5762306a36Sopenharmony_ci#define PID_TRIGGER_BUTTON	3
5862306a36Sopenharmony_ci#define PID_TRIGGER_REPEAT_INT	4
5962306a36Sopenharmony_ci#define PID_DIRECTION_ENABLE	5
6062306a36Sopenharmony_ci#define PID_START_DELAY		6
6162306a36Sopenharmony_cistatic const u8 pidff_set_effect[] = {
6262306a36Sopenharmony_ci	0x22, 0x50, 0x52, 0x53, 0x54, 0x56, 0xa7
6362306a36Sopenharmony_ci};
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci#define PID_ATTACK_LEVEL	1
6662306a36Sopenharmony_ci#define PID_ATTACK_TIME		2
6762306a36Sopenharmony_ci#define PID_FADE_LEVEL		3
6862306a36Sopenharmony_ci#define PID_FADE_TIME		4
6962306a36Sopenharmony_cistatic const u8 pidff_set_envelope[] = { 0x22, 0x5b, 0x5c, 0x5d, 0x5e };
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci#define PID_PARAM_BLOCK_OFFSET	1
7262306a36Sopenharmony_ci#define PID_CP_OFFSET		2
7362306a36Sopenharmony_ci#define PID_POS_COEFFICIENT	3
7462306a36Sopenharmony_ci#define PID_NEG_COEFFICIENT	4
7562306a36Sopenharmony_ci#define PID_POS_SATURATION	5
7662306a36Sopenharmony_ci#define PID_NEG_SATURATION	6
7762306a36Sopenharmony_ci#define PID_DEAD_BAND		7
7862306a36Sopenharmony_cistatic const u8 pidff_set_condition[] = {
7962306a36Sopenharmony_ci	0x22, 0x23, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65
8062306a36Sopenharmony_ci};
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci#define PID_MAGNITUDE		1
8362306a36Sopenharmony_ci#define PID_OFFSET		2
8462306a36Sopenharmony_ci#define PID_PHASE		3
8562306a36Sopenharmony_ci#define PID_PERIOD		4
8662306a36Sopenharmony_cistatic const u8 pidff_set_periodic[] = { 0x22, 0x70, 0x6f, 0x71, 0x72 };
8762306a36Sopenharmony_cistatic const u8 pidff_set_constant[] = { 0x22, 0x70 };
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci#define PID_RAMP_START		1
9062306a36Sopenharmony_ci#define PID_RAMP_END		2
9162306a36Sopenharmony_cistatic const u8 pidff_set_ramp[] = { 0x22, 0x75, 0x76 };
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci#define PID_RAM_POOL_AVAILABLE	1
9462306a36Sopenharmony_cistatic const u8 pidff_block_load[] = { 0x22, 0xac };
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci#define PID_LOOP_COUNT		1
9762306a36Sopenharmony_cistatic const u8 pidff_effect_operation[] = { 0x22, 0x7c };
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic const u8 pidff_block_free[] = { 0x22 };
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci#define PID_DEVICE_GAIN_FIELD	0
10262306a36Sopenharmony_cistatic const u8 pidff_device_gain[] = { 0x7e };
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci#define PID_RAM_POOL_SIZE	0
10562306a36Sopenharmony_ci#define PID_SIMULTANEOUS_MAX	1
10662306a36Sopenharmony_ci#define PID_DEVICE_MANAGED_POOL	2
10762306a36Sopenharmony_cistatic const u8 pidff_pool[] = { 0x80, 0x83, 0xa9 };
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci/* Special field key tables used to put special field keys into arrays */
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci#define PID_ENABLE_ACTUATORS	0
11262306a36Sopenharmony_ci#define PID_RESET		1
11362306a36Sopenharmony_cistatic const u8 pidff_device_control[] = { 0x97, 0x9a };
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci#define PID_CONSTANT	0
11662306a36Sopenharmony_ci#define PID_RAMP	1
11762306a36Sopenharmony_ci#define PID_SQUARE	2
11862306a36Sopenharmony_ci#define PID_SINE	3
11962306a36Sopenharmony_ci#define PID_TRIANGLE	4
12062306a36Sopenharmony_ci#define PID_SAW_UP	5
12162306a36Sopenharmony_ci#define PID_SAW_DOWN	6
12262306a36Sopenharmony_ci#define PID_SPRING	7
12362306a36Sopenharmony_ci#define PID_DAMPER	8
12462306a36Sopenharmony_ci#define PID_INERTIA	9
12562306a36Sopenharmony_ci#define PID_FRICTION	10
12662306a36Sopenharmony_cistatic const u8 pidff_effect_types[] = {
12762306a36Sopenharmony_ci	0x26, 0x27, 0x30, 0x31, 0x32, 0x33, 0x34,
12862306a36Sopenharmony_ci	0x40, 0x41, 0x42, 0x43
12962306a36Sopenharmony_ci};
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci#define PID_BLOCK_LOAD_SUCCESS	0
13262306a36Sopenharmony_ci#define PID_BLOCK_LOAD_FULL	1
13362306a36Sopenharmony_cistatic const u8 pidff_block_load_status[] = { 0x8c, 0x8d };
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci#define PID_EFFECT_START	0
13662306a36Sopenharmony_ci#define PID_EFFECT_STOP		1
13762306a36Sopenharmony_cistatic const u8 pidff_effect_operation_status[] = { 0x79, 0x7b };
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistruct pidff_usage {
14062306a36Sopenharmony_ci	struct hid_field *field;
14162306a36Sopenharmony_ci	s32 *value;
14262306a36Sopenharmony_ci};
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistruct pidff_device {
14562306a36Sopenharmony_ci	struct hid_device *hid;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	struct hid_report *reports[sizeof(pidff_reports)];
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	struct pidff_usage set_effect[sizeof(pidff_set_effect)];
15062306a36Sopenharmony_ci	struct pidff_usage set_envelope[sizeof(pidff_set_envelope)];
15162306a36Sopenharmony_ci	struct pidff_usage set_condition[sizeof(pidff_set_condition)];
15262306a36Sopenharmony_ci	struct pidff_usage set_periodic[sizeof(pidff_set_periodic)];
15362306a36Sopenharmony_ci	struct pidff_usage set_constant[sizeof(pidff_set_constant)];
15462306a36Sopenharmony_ci	struct pidff_usage set_ramp[sizeof(pidff_set_ramp)];
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	struct pidff_usage device_gain[sizeof(pidff_device_gain)];
15762306a36Sopenharmony_ci	struct pidff_usage block_load[sizeof(pidff_block_load)];
15862306a36Sopenharmony_ci	struct pidff_usage pool[sizeof(pidff_pool)];
15962306a36Sopenharmony_ci	struct pidff_usage effect_operation[sizeof(pidff_effect_operation)];
16062306a36Sopenharmony_ci	struct pidff_usage block_free[sizeof(pidff_block_free)];
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	/* Special field is a field that is not composed of
16362306a36Sopenharmony_ci	   usage<->value pairs that pidff_usage values are */
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	/* Special field in create_new_effect */
16662306a36Sopenharmony_ci	struct hid_field *create_new_effect_type;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	/* Special fields in set_effect */
16962306a36Sopenharmony_ci	struct hid_field *set_effect_type;
17062306a36Sopenharmony_ci	struct hid_field *effect_direction;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	/* Special field in device_control */
17362306a36Sopenharmony_ci	struct hid_field *device_control;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	/* Special field in block_load */
17662306a36Sopenharmony_ci	struct hid_field *block_load_status;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	/* Special field in effect_operation */
17962306a36Sopenharmony_ci	struct hid_field *effect_operation_status;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	int control_id[sizeof(pidff_device_control)];
18262306a36Sopenharmony_ci	int type_id[sizeof(pidff_effect_types)];
18362306a36Sopenharmony_ci	int status_id[sizeof(pidff_block_load_status)];
18462306a36Sopenharmony_ci	int operation_id[sizeof(pidff_effect_operation_status)];
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	int pid_id[PID_EFFECTS_MAX];
18762306a36Sopenharmony_ci};
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci/*
19062306a36Sopenharmony_ci * Scale an unsigned value with range 0..max for the given field
19162306a36Sopenharmony_ci */
19262306a36Sopenharmony_cistatic int pidff_rescale(int i, int max, struct hid_field *field)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	return i * (field->logical_maximum - field->logical_minimum) / max +
19562306a36Sopenharmony_ci	    field->logical_minimum;
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci/*
19962306a36Sopenharmony_ci * Scale a signed value in range -0x8000..0x7fff for the given field
20062306a36Sopenharmony_ci */
20162306a36Sopenharmony_cistatic int pidff_rescale_signed(int i, struct hid_field *field)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	return i == 0 ? 0 : i >
20462306a36Sopenharmony_ci	    0 ? i * field->logical_maximum / 0x7fff : i *
20562306a36Sopenharmony_ci	    field->logical_minimum / -0x8000;
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic void pidff_set(struct pidff_usage *usage, u16 value)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	usage->value[0] = pidff_rescale(value, 0xffff, usage->field);
21162306a36Sopenharmony_ci	pr_debug("calculated from %d to %d\n", value, usage->value[0]);
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_cistatic void pidff_set_signed(struct pidff_usage *usage, s16 value)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	if (usage->field->logical_minimum < 0)
21762306a36Sopenharmony_ci		usage->value[0] = pidff_rescale_signed(value, usage->field);
21862306a36Sopenharmony_ci	else {
21962306a36Sopenharmony_ci		if (value < 0)
22062306a36Sopenharmony_ci			usage->value[0] =
22162306a36Sopenharmony_ci			    pidff_rescale(-value, 0x8000, usage->field);
22262306a36Sopenharmony_ci		else
22362306a36Sopenharmony_ci			usage->value[0] =
22462306a36Sopenharmony_ci			    pidff_rescale(value, 0x7fff, usage->field);
22562306a36Sopenharmony_ci	}
22662306a36Sopenharmony_ci	pr_debug("calculated from %d to %d\n", value, usage->value[0]);
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci/*
23062306a36Sopenharmony_ci * Send envelope report to the device
23162306a36Sopenharmony_ci */
23262306a36Sopenharmony_cistatic void pidff_set_envelope_report(struct pidff_device *pidff,
23362306a36Sopenharmony_ci				      struct ff_envelope *envelope)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	pidff->set_envelope[PID_EFFECT_BLOCK_INDEX].value[0] =
23662306a36Sopenharmony_ci	    pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	pidff->set_envelope[PID_ATTACK_LEVEL].value[0] =
23962306a36Sopenharmony_ci	    pidff_rescale(envelope->attack_level >
24062306a36Sopenharmony_ci			  0x7fff ? 0x7fff : envelope->attack_level, 0x7fff,
24162306a36Sopenharmony_ci			  pidff->set_envelope[PID_ATTACK_LEVEL].field);
24262306a36Sopenharmony_ci	pidff->set_envelope[PID_FADE_LEVEL].value[0] =
24362306a36Sopenharmony_ci	    pidff_rescale(envelope->fade_level >
24462306a36Sopenharmony_ci			  0x7fff ? 0x7fff : envelope->fade_level, 0x7fff,
24562306a36Sopenharmony_ci			  pidff->set_envelope[PID_FADE_LEVEL].field);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	pidff->set_envelope[PID_ATTACK_TIME].value[0] = envelope->attack_length;
24862306a36Sopenharmony_ci	pidff->set_envelope[PID_FADE_TIME].value[0] = envelope->fade_length;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	hid_dbg(pidff->hid, "attack %u => %d\n",
25162306a36Sopenharmony_ci		envelope->attack_level,
25262306a36Sopenharmony_ci		pidff->set_envelope[PID_ATTACK_LEVEL].value[0]);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	hid_hw_request(pidff->hid, pidff->reports[PID_SET_ENVELOPE],
25562306a36Sopenharmony_ci			HID_REQ_SET_REPORT);
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci/*
25962306a36Sopenharmony_ci * Test if the new envelope differs from old one
26062306a36Sopenharmony_ci */
26162306a36Sopenharmony_cistatic int pidff_needs_set_envelope(struct ff_envelope *envelope,
26262306a36Sopenharmony_ci				    struct ff_envelope *old)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	return envelope->attack_level != old->attack_level ||
26562306a36Sopenharmony_ci	       envelope->fade_level != old->fade_level ||
26662306a36Sopenharmony_ci	       envelope->attack_length != old->attack_length ||
26762306a36Sopenharmony_ci	       envelope->fade_length != old->fade_length;
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci/*
27162306a36Sopenharmony_ci * Send constant force report to the device
27262306a36Sopenharmony_ci */
27362306a36Sopenharmony_cistatic void pidff_set_constant_force_report(struct pidff_device *pidff,
27462306a36Sopenharmony_ci					    struct ff_effect *effect)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	pidff->set_constant[PID_EFFECT_BLOCK_INDEX].value[0] =
27762306a36Sopenharmony_ci		pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
27862306a36Sopenharmony_ci	pidff_set_signed(&pidff->set_constant[PID_MAGNITUDE],
27962306a36Sopenharmony_ci			 effect->u.constant.level);
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	hid_hw_request(pidff->hid, pidff->reports[PID_SET_CONSTANT],
28262306a36Sopenharmony_ci			HID_REQ_SET_REPORT);
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci/*
28662306a36Sopenharmony_ci * Test if the constant parameters have changed between effects
28762306a36Sopenharmony_ci */
28862306a36Sopenharmony_cistatic int pidff_needs_set_constant(struct ff_effect *effect,
28962306a36Sopenharmony_ci				    struct ff_effect *old)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	return effect->u.constant.level != old->u.constant.level;
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci/*
29562306a36Sopenharmony_ci * Send set effect report to the device
29662306a36Sopenharmony_ci */
29762306a36Sopenharmony_cistatic void pidff_set_effect_report(struct pidff_device *pidff,
29862306a36Sopenharmony_ci				    struct ff_effect *effect)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	pidff->set_effect[PID_EFFECT_BLOCK_INDEX].value[0] =
30162306a36Sopenharmony_ci		pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
30262306a36Sopenharmony_ci	pidff->set_effect_type->value[0] =
30362306a36Sopenharmony_ci		pidff->create_new_effect_type->value[0];
30462306a36Sopenharmony_ci	pidff->set_effect[PID_DURATION].value[0] = effect->replay.length;
30562306a36Sopenharmony_ci	pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = effect->trigger.button;
30662306a36Sopenharmony_ci	pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] =
30762306a36Sopenharmony_ci		effect->trigger.interval;
30862306a36Sopenharmony_ci	pidff->set_effect[PID_GAIN].value[0] =
30962306a36Sopenharmony_ci		pidff->set_effect[PID_GAIN].field->logical_maximum;
31062306a36Sopenharmony_ci	pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1;
31162306a36Sopenharmony_ci	pidff->effect_direction->value[0] =
31262306a36Sopenharmony_ci		pidff_rescale(effect->direction, 0xffff,
31362306a36Sopenharmony_ci				pidff->effect_direction);
31462306a36Sopenharmony_ci	pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	hid_hw_request(pidff->hid, pidff->reports[PID_SET_EFFECT],
31762306a36Sopenharmony_ci			HID_REQ_SET_REPORT);
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci/*
32162306a36Sopenharmony_ci * Test if the values used in set_effect have changed
32262306a36Sopenharmony_ci */
32362306a36Sopenharmony_cistatic int pidff_needs_set_effect(struct ff_effect *effect,
32462306a36Sopenharmony_ci				  struct ff_effect *old)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	return effect->replay.length != old->replay.length ||
32762306a36Sopenharmony_ci	       effect->trigger.interval != old->trigger.interval ||
32862306a36Sopenharmony_ci	       effect->trigger.button != old->trigger.button ||
32962306a36Sopenharmony_ci	       effect->direction != old->direction ||
33062306a36Sopenharmony_ci	       effect->replay.delay != old->replay.delay;
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci/*
33462306a36Sopenharmony_ci * Send periodic effect report to the device
33562306a36Sopenharmony_ci */
33662306a36Sopenharmony_cistatic void pidff_set_periodic_report(struct pidff_device *pidff,
33762306a36Sopenharmony_ci				      struct ff_effect *effect)
33862306a36Sopenharmony_ci{
33962306a36Sopenharmony_ci	pidff->set_periodic[PID_EFFECT_BLOCK_INDEX].value[0] =
34062306a36Sopenharmony_ci		pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
34162306a36Sopenharmony_ci	pidff_set_signed(&pidff->set_periodic[PID_MAGNITUDE],
34262306a36Sopenharmony_ci			 effect->u.periodic.magnitude);
34362306a36Sopenharmony_ci	pidff_set_signed(&pidff->set_periodic[PID_OFFSET],
34462306a36Sopenharmony_ci			 effect->u.periodic.offset);
34562306a36Sopenharmony_ci	pidff_set(&pidff->set_periodic[PID_PHASE], effect->u.periodic.phase);
34662306a36Sopenharmony_ci	pidff->set_periodic[PID_PERIOD].value[0] = effect->u.periodic.period;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	hid_hw_request(pidff->hid, pidff->reports[PID_SET_PERIODIC],
34962306a36Sopenharmony_ci			HID_REQ_SET_REPORT);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci/*
35462306a36Sopenharmony_ci * Test if periodic effect parameters have changed
35562306a36Sopenharmony_ci */
35662306a36Sopenharmony_cistatic int pidff_needs_set_periodic(struct ff_effect *effect,
35762306a36Sopenharmony_ci				    struct ff_effect *old)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	return effect->u.periodic.magnitude != old->u.periodic.magnitude ||
36062306a36Sopenharmony_ci	       effect->u.periodic.offset != old->u.periodic.offset ||
36162306a36Sopenharmony_ci	       effect->u.periodic.phase != old->u.periodic.phase ||
36262306a36Sopenharmony_ci	       effect->u.periodic.period != old->u.periodic.period;
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci/*
36662306a36Sopenharmony_ci * Send condition effect reports to the device
36762306a36Sopenharmony_ci */
36862306a36Sopenharmony_cistatic void pidff_set_condition_report(struct pidff_device *pidff,
36962306a36Sopenharmony_ci				       struct ff_effect *effect)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci	int i;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	pidff->set_condition[PID_EFFECT_BLOCK_INDEX].value[0] =
37462306a36Sopenharmony_ci		pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
37762306a36Sopenharmony_ci		pidff->set_condition[PID_PARAM_BLOCK_OFFSET].value[0] = i;
37862306a36Sopenharmony_ci		pidff_set_signed(&pidff->set_condition[PID_CP_OFFSET],
37962306a36Sopenharmony_ci				 effect->u.condition[i].center);
38062306a36Sopenharmony_ci		pidff_set_signed(&pidff->set_condition[PID_POS_COEFFICIENT],
38162306a36Sopenharmony_ci				 effect->u.condition[i].right_coeff);
38262306a36Sopenharmony_ci		pidff_set_signed(&pidff->set_condition[PID_NEG_COEFFICIENT],
38362306a36Sopenharmony_ci				 effect->u.condition[i].left_coeff);
38462306a36Sopenharmony_ci		pidff_set(&pidff->set_condition[PID_POS_SATURATION],
38562306a36Sopenharmony_ci			  effect->u.condition[i].right_saturation);
38662306a36Sopenharmony_ci		pidff_set(&pidff->set_condition[PID_NEG_SATURATION],
38762306a36Sopenharmony_ci			  effect->u.condition[i].left_saturation);
38862306a36Sopenharmony_ci		pidff_set(&pidff->set_condition[PID_DEAD_BAND],
38962306a36Sopenharmony_ci			  effect->u.condition[i].deadband);
39062306a36Sopenharmony_ci		hid_hw_request(pidff->hid, pidff->reports[PID_SET_CONDITION],
39162306a36Sopenharmony_ci				HID_REQ_SET_REPORT);
39262306a36Sopenharmony_ci	}
39362306a36Sopenharmony_ci}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci/*
39662306a36Sopenharmony_ci * Test if condition effect parameters have changed
39762306a36Sopenharmony_ci */
39862306a36Sopenharmony_cistatic int pidff_needs_set_condition(struct ff_effect *effect,
39962306a36Sopenharmony_ci				     struct ff_effect *old)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	int i;
40262306a36Sopenharmony_ci	int ret = 0;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
40562306a36Sopenharmony_ci		struct ff_condition_effect *cond = &effect->u.condition[i];
40662306a36Sopenharmony_ci		struct ff_condition_effect *old_cond = &old->u.condition[i];
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci		ret |= cond->center != old_cond->center ||
40962306a36Sopenharmony_ci		       cond->right_coeff != old_cond->right_coeff ||
41062306a36Sopenharmony_ci		       cond->left_coeff != old_cond->left_coeff ||
41162306a36Sopenharmony_ci		       cond->right_saturation != old_cond->right_saturation ||
41262306a36Sopenharmony_ci		       cond->left_saturation != old_cond->left_saturation ||
41362306a36Sopenharmony_ci		       cond->deadband != old_cond->deadband;
41462306a36Sopenharmony_ci	}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	return ret;
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci/*
42062306a36Sopenharmony_ci * Send ramp force report to the device
42162306a36Sopenharmony_ci */
42262306a36Sopenharmony_cistatic void pidff_set_ramp_force_report(struct pidff_device *pidff,
42362306a36Sopenharmony_ci					struct ff_effect *effect)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	pidff->set_ramp[PID_EFFECT_BLOCK_INDEX].value[0] =
42662306a36Sopenharmony_ci		pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
42762306a36Sopenharmony_ci	pidff_set_signed(&pidff->set_ramp[PID_RAMP_START],
42862306a36Sopenharmony_ci			 effect->u.ramp.start_level);
42962306a36Sopenharmony_ci	pidff_set_signed(&pidff->set_ramp[PID_RAMP_END],
43062306a36Sopenharmony_ci			 effect->u.ramp.end_level);
43162306a36Sopenharmony_ci	hid_hw_request(pidff->hid, pidff->reports[PID_SET_RAMP],
43262306a36Sopenharmony_ci			HID_REQ_SET_REPORT);
43362306a36Sopenharmony_ci}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci/*
43662306a36Sopenharmony_ci * Test if ramp force parameters have changed
43762306a36Sopenharmony_ci */
43862306a36Sopenharmony_cistatic int pidff_needs_set_ramp(struct ff_effect *effect, struct ff_effect *old)
43962306a36Sopenharmony_ci{
44062306a36Sopenharmony_ci	return effect->u.ramp.start_level != old->u.ramp.start_level ||
44162306a36Sopenharmony_ci	       effect->u.ramp.end_level != old->u.ramp.end_level;
44262306a36Sopenharmony_ci}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci/*
44562306a36Sopenharmony_ci * Send a request for effect upload to the device
44662306a36Sopenharmony_ci *
44762306a36Sopenharmony_ci * Returns 0 if device reported success, -ENOSPC if the device reported memory
44862306a36Sopenharmony_ci * is full. Upon unknown response the function will retry for 60 times, if
44962306a36Sopenharmony_ci * still unsuccessful -EIO is returned.
45062306a36Sopenharmony_ci */
45162306a36Sopenharmony_cistatic int pidff_request_effect_upload(struct pidff_device *pidff, int efnum)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci	int j;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	pidff->create_new_effect_type->value[0] = efnum;
45662306a36Sopenharmony_ci	hid_hw_request(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT],
45762306a36Sopenharmony_ci			HID_REQ_SET_REPORT);
45862306a36Sopenharmony_ci	hid_dbg(pidff->hid, "create_new_effect sent, type: %d\n", efnum);
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = 0;
46162306a36Sopenharmony_ci	pidff->block_load_status->value[0] = 0;
46262306a36Sopenharmony_ci	hid_hw_wait(pidff->hid);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	for (j = 0; j < 60; j++) {
46562306a36Sopenharmony_ci		hid_dbg(pidff->hid, "pid_block_load requested\n");
46662306a36Sopenharmony_ci		hid_hw_request(pidff->hid, pidff->reports[PID_BLOCK_LOAD],
46762306a36Sopenharmony_ci				HID_REQ_GET_REPORT);
46862306a36Sopenharmony_ci		hid_hw_wait(pidff->hid);
46962306a36Sopenharmony_ci		if (pidff->block_load_status->value[0] ==
47062306a36Sopenharmony_ci		    pidff->status_id[PID_BLOCK_LOAD_SUCCESS]) {
47162306a36Sopenharmony_ci			hid_dbg(pidff->hid, "device reported free memory: %d bytes\n",
47262306a36Sopenharmony_ci				 pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?
47362306a36Sopenharmony_ci				 pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1);
47462306a36Sopenharmony_ci			return 0;
47562306a36Sopenharmony_ci		}
47662306a36Sopenharmony_ci		if (pidff->block_load_status->value[0] ==
47762306a36Sopenharmony_ci		    pidff->status_id[PID_BLOCK_LOAD_FULL]) {
47862306a36Sopenharmony_ci			hid_dbg(pidff->hid, "not enough memory free: %d bytes\n",
47962306a36Sopenharmony_ci				pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?
48062306a36Sopenharmony_ci				pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1);
48162306a36Sopenharmony_ci			return -ENOSPC;
48262306a36Sopenharmony_ci		}
48362306a36Sopenharmony_ci	}
48462306a36Sopenharmony_ci	hid_err(pidff->hid, "pid_block_load failed 60 times\n");
48562306a36Sopenharmony_ci	return -EIO;
48662306a36Sopenharmony_ci}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci/*
48962306a36Sopenharmony_ci * Play the effect with PID id n times
49062306a36Sopenharmony_ci */
49162306a36Sopenharmony_cistatic void pidff_playback_pid(struct pidff_device *pidff, int pid_id, int n)
49262306a36Sopenharmony_ci{
49362306a36Sopenharmony_ci	pidff->effect_operation[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	if (n == 0) {
49662306a36Sopenharmony_ci		pidff->effect_operation_status->value[0] =
49762306a36Sopenharmony_ci			pidff->operation_id[PID_EFFECT_STOP];
49862306a36Sopenharmony_ci	} else {
49962306a36Sopenharmony_ci		pidff->effect_operation_status->value[0] =
50062306a36Sopenharmony_ci			pidff->operation_id[PID_EFFECT_START];
50162306a36Sopenharmony_ci		pidff->effect_operation[PID_LOOP_COUNT].value[0] = n;
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	hid_hw_request(pidff->hid, pidff->reports[PID_EFFECT_OPERATION],
50562306a36Sopenharmony_ci			HID_REQ_SET_REPORT);
50662306a36Sopenharmony_ci}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci/*
50962306a36Sopenharmony_ci * Play the effect with effect id @effect_id for @value times
51062306a36Sopenharmony_ci */
51162306a36Sopenharmony_cistatic int pidff_playback(struct input_dev *dev, int effect_id, int value)
51262306a36Sopenharmony_ci{
51362306a36Sopenharmony_ci	struct pidff_device *pidff = dev->ff->private;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	pidff_playback_pid(pidff, pidff->pid_id[effect_id], value);
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	return 0;
51862306a36Sopenharmony_ci}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci/*
52162306a36Sopenharmony_ci * Erase effect with PID id
52262306a36Sopenharmony_ci */
52362306a36Sopenharmony_cistatic void pidff_erase_pid(struct pidff_device *pidff, int pid_id)
52462306a36Sopenharmony_ci{
52562306a36Sopenharmony_ci	pidff->block_free[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id;
52662306a36Sopenharmony_ci	hid_hw_request(pidff->hid, pidff->reports[PID_BLOCK_FREE],
52762306a36Sopenharmony_ci			HID_REQ_SET_REPORT);
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci/*
53162306a36Sopenharmony_ci * Stop and erase effect with effect_id
53262306a36Sopenharmony_ci */
53362306a36Sopenharmony_cistatic int pidff_erase_effect(struct input_dev *dev, int effect_id)
53462306a36Sopenharmony_ci{
53562306a36Sopenharmony_ci	struct pidff_device *pidff = dev->ff->private;
53662306a36Sopenharmony_ci	int pid_id = pidff->pid_id[effect_id];
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	hid_dbg(pidff->hid, "starting to erase %d/%d\n",
53962306a36Sopenharmony_ci		effect_id, pidff->pid_id[effect_id]);
54062306a36Sopenharmony_ci	/* Wait for the queue to clear. We do not want a full fifo to
54162306a36Sopenharmony_ci	   prevent the effect removal. */
54262306a36Sopenharmony_ci	hid_hw_wait(pidff->hid);
54362306a36Sopenharmony_ci	pidff_playback_pid(pidff, pid_id, 0);
54462306a36Sopenharmony_ci	pidff_erase_pid(pidff, pid_id);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	return 0;
54762306a36Sopenharmony_ci}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci/*
55062306a36Sopenharmony_ci * Effect upload handler
55162306a36Sopenharmony_ci */
55262306a36Sopenharmony_cistatic int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
55362306a36Sopenharmony_ci			       struct ff_effect *old)
55462306a36Sopenharmony_ci{
55562306a36Sopenharmony_ci	struct pidff_device *pidff = dev->ff->private;
55662306a36Sopenharmony_ci	int type_id;
55762306a36Sopenharmony_ci	int error;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = 0;
56062306a36Sopenharmony_ci	if (old) {
56162306a36Sopenharmony_ci		pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] =
56262306a36Sopenharmony_ci			pidff->pid_id[effect->id];
56362306a36Sopenharmony_ci	}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	switch (effect->type) {
56662306a36Sopenharmony_ci	case FF_CONSTANT:
56762306a36Sopenharmony_ci		if (!old) {
56862306a36Sopenharmony_ci			error = pidff_request_effect_upload(pidff,
56962306a36Sopenharmony_ci					pidff->type_id[PID_CONSTANT]);
57062306a36Sopenharmony_ci			if (error)
57162306a36Sopenharmony_ci				return error;
57262306a36Sopenharmony_ci		}
57362306a36Sopenharmony_ci		if (!old || pidff_needs_set_effect(effect, old))
57462306a36Sopenharmony_ci			pidff_set_effect_report(pidff, effect);
57562306a36Sopenharmony_ci		if (!old || pidff_needs_set_constant(effect, old))
57662306a36Sopenharmony_ci			pidff_set_constant_force_report(pidff, effect);
57762306a36Sopenharmony_ci		if (!old ||
57862306a36Sopenharmony_ci		    pidff_needs_set_envelope(&effect->u.constant.envelope,
57962306a36Sopenharmony_ci					&old->u.constant.envelope))
58062306a36Sopenharmony_ci			pidff_set_envelope_report(pidff,
58162306a36Sopenharmony_ci					&effect->u.constant.envelope);
58262306a36Sopenharmony_ci		break;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	case FF_PERIODIC:
58562306a36Sopenharmony_ci		if (!old) {
58662306a36Sopenharmony_ci			switch (effect->u.periodic.waveform) {
58762306a36Sopenharmony_ci			case FF_SQUARE:
58862306a36Sopenharmony_ci				type_id = PID_SQUARE;
58962306a36Sopenharmony_ci				break;
59062306a36Sopenharmony_ci			case FF_TRIANGLE:
59162306a36Sopenharmony_ci				type_id = PID_TRIANGLE;
59262306a36Sopenharmony_ci				break;
59362306a36Sopenharmony_ci			case FF_SINE:
59462306a36Sopenharmony_ci				type_id = PID_SINE;
59562306a36Sopenharmony_ci				break;
59662306a36Sopenharmony_ci			case FF_SAW_UP:
59762306a36Sopenharmony_ci				type_id = PID_SAW_UP;
59862306a36Sopenharmony_ci				break;
59962306a36Sopenharmony_ci			case FF_SAW_DOWN:
60062306a36Sopenharmony_ci				type_id = PID_SAW_DOWN;
60162306a36Sopenharmony_ci				break;
60262306a36Sopenharmony_ci			default:
60362306a36Sopenharmony_ci				hid_err(pidff->hid, "invalid waveform\n");
60462306a36Sopenharmony_ci				return -EINVAL;
60562306a36Sopenharmony_ci			}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci			error = pidff_request_effect_upload(pidff,
60862306a36Sopenharmony_ci					pidff->type_id[type_id]);
60962306a36Sopenharmony_ci			if (error)
61062306a36Sopenharmony_ci				return error;
61162306a36Sopenharmony_ci		}
61262306a36Sopenharmony_ci		if (!old || pidff_needs_set_effect(effect, old))
61362306a36Sopenharmony_ci			pidff_set_effect_report(pidff, effect);
61462306a36Sopenharmony_ci		if (!old || pidff_needs_set_periodic(effect, old))
61562306a36Sopenharmony_ci			pidff_set_periodic_report(pidff, effect);
61662306a36Sopenharmony_ci		if (!old ||
61762306a36Sopenharmony_ci		    pidff_needs_set_envelope(&effect->u.periodic.envelope,
61862306a36Sopenharmony_ci					&old->u.periodic.envelope))
61962306a36Sopenharmony_ci			pidff_set_envelope_report(pidff,
62062306a36Sopenharmony_ci					&effect->u.periodic.envelope);
62162306a36Sopenharmony_ci		break;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	case FF_RAMP:
62462306a36Sopenharmony_ci		if (!old) {
62562306a36Sopenharmony_ci			error = pidff_request_effect_upload(pidff,
62662306a36Sopenharmony_ci					pidff->type_id[PID_RAMP]);
62762306a36Sopenharmony_ci			if (error)
62862306a36Sopenharmony_ci				return error;
62962306a36Sopenharmony_ci		}
63062306a36Sopenharmony_ci		if (!old || pidff_needs_set_effect(effect, old))
63162306a36Sopenharmony_ci			pidff_set_effect_report(pidff, effect);
63262306a36Sopenharmony_ci		if (!old || pidff_needs_set_ramp(effect, old))
63362306a36Sopenharmony_ci			pidff_set_ramp_force_report(pidff, effect);
63462306a36Sopenharmony_ci		if (!old ||
63562306a36Sopenharmony_ci		    pidff_needs_set_envelope(&effect->u.ramp.envelope,
63662306a36Sopenharmony_ci					&old->u.ramp.envelope))
63762306a36Sopenharmony_ci			pidff_set_envelope_report(pidff,
63862306a36Sopenharmony_ci					&effect->u.ramp.envelope);
63962306a36Sopenharmony_ci		break;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	case FF_SPRING:
64262306a36Sopenharmony_ci		if (!old) {
64362306a36Sopenharmony_ci			error = pidff_request_effect_upload(pidff,
64462306a36Sopenharmony_ci					pidff->type_id[PID_SPRING]);
64562306a36Sopenharmony_ci			if (error)
64662306a36Sopenharmony_ci				return error;
64762306a36Sopenharmony_ci		}
64862306a36Sopenharmony_ci		if (!old || pidff_needs_set_effect(effect, old))
64962306a36Sopenharmony_ci			pidff_set_effect_report(pidff, effect);
65062306a36Sopenharmony_ci		if (!old || pidff_needs_set_condition(effect, old))
65162306a36Sopenharmony_ci			pidff_set_condition_report(pidff, effect);
65262306a36Sopenharmony_ci		break;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	case FF_FRICTION:
65562306a36Sopenharmony_ci		if (!old) {
65662306a36Sopenharmony_ci			error = pidff_request_effect_upload(pidff,
65762306a36Sopenharmony_ci					pidff->type_id[PID_FRICTION]);
65862306a36Sopenharmony_ci			if (error)
65962306a36Sopenharmony_ci				return error;
66062306a36Sopenharmony_ci		}
66162306a36Sopenharmony_ci		if (!old || pidff_needs_set_effect(effect, old))
66262306a36Sopenharmony_ci			pidff_set_effect_report(pidff, effect);
66362306a36Sopenharmony_ci		if (!old || pidff_needs_set_condition(effect, old))
66462306a36Sopenharmony_ci			pidff_set_condition_report(pidff, effect);
66562306a36Sopenharmony_ci		break;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	case FF_DAMPER:
66862306a36Sopenharmony_ci		if (!old) {
66962306a36Sopenharmony_ci			error = pidff_request_effect_upload(pidff,
67062306a36Sopenharmony_ci					pidff->type_id[PID_DAMPER]);
67162306a36Sopenharmony_ci			if (error)
67262306a36Sopenharmony_ci				return error;
67362306a36Sopenharmony_ci		}
67462306a36Sopenharmony_ci		if (!old || pidff_needs_set_effect(effect, old))
67562306a36Sopenharmony_ci			pidff_set_effect_report(pidff, effect);
67662306a36Sopenharmony_ci		if (!old || pidff_needs_set_condition(effect, old))
67762306a36Sopenharmony_ci			pidff_set_condition_report(pidff, effect);
67862306a36Sopenharmony_ci		break;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	case FF_INERTIA:
68162306a36Sopenharmony_ci		if (!old) {
68262306a36Sopenharmony_ci			error = pidff_request_effect_upload(pidff,
68362306a36Sopenharmony_ci					pidff->type_id[PID_INERTIA]);
68462306a36Sopenharmony_ci			if (error)
68562306a36Sopenharmony_ci				return error;
68662306a36Sopenharmony_ci		}
68762306a36Sopenharmony_ci		if (!old || pidff_needs_set_effect(effect, old))
68862306a36Sopenharmony_ci			pidff_set_effect_report(pidff, effect);
68962306a36Sopenharmony_ci		if (!old || pidff_needs_set_condition(effect, old))
69062306a36Sopenharmony_ci			pidff_set_condition_report(pidff, effect);
69162306a36Sopenharmony_ci		break;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	default:
69462306a36Sopenharmony_ci		hid_err(pidff->hid, "invalid type\n");
69562306a36Sopenharmony_ci		return -EINVAL;
69662306a36Sopenharmony_ci	}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	if (!old)
69962306a36Sopenharmony_ci		pidff->pid_id[effect->id] =
70062306a36Sopenharmony_ci		    pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	hid_dbg(pidff->hid, "uploaded\n");
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	return 0;
70562306a36Sopenharmony_ci}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci/*
70862306a36Sopenharmony_ci * set_gain() handler
70962306a36Sopenharmony_ci */
71062306a36Sopenharmony_cistatic void pidff_set_gain(struct input_dev *dev, u16 gain)
71162306a36Sopenharmony_ci{
71262306a36Sopenharmony_ci	struct pidff_device *pidff = dev->ff->private;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], gain);
71562306a36Sopenharmony_ci	hid_hw_request(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
71662306a36Sopenharmony_ci			HID_REQ_SET_REPORT);
71762306a36Sopenharmony_ci}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_cistatic void pidff_autocenter(struct pidff_device *pidff, u16 magnitude)
72062306a36Sopenharmony_ci{
72162306a36Sopenharmony_ci	struct hid_field *field =
72262306a36Sopenharmony_ci		pidff->block_load[PID_EFFECT_BLOCK_INDEX].field;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	if (!magnitude) {
72562306a36Sopenharmony_ci		pidff_playback_pid(pidff, field->logical_minimum, 0);
72662306a36Sopenharmony_ci		return;
72762306a36Sopenharmony_ci	}
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	pidff_playback_pid(pidff, field->logical_minimum, 1);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	pidff->set_effect[PID_EFFECT_BLOCK_INDEX].value[0] =
73262306a36Sopenharmony_ci		pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum;
73362306a36Sopenharmony_ci	pidff->set_effect_type->value[0] = pidff->type_id[PID_SPRING];
73462306a36Sopenharmony_ci	pidff->set_effect[PID_DURATION].value[0] = 0;
73562306a36Sopenharmony_ci	pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = 0;
73662306a36Sopenharmony_ci	pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] = 0;
73762306a36Sopenharmony_ci	pidff_set(&pidff->set_effect[PID_GAIN], magnitude);
73862306a36Sopenharmony_ci	pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1;
73962306a36Sopenharmony_ci	pidff->set_effect[PID_START_DELAY].value[0] = 0;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	hid_hw_request(pidff->hid, pidff->reports[PID_SET_EFFECT],
74262306a36Sopenharmony_ci			HID_REQ_SET_REPORT);
74362306a36Sopenharmony_ci}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci/*
74662306a36Sopenharmony_ci * pidff_set_autocenter() handler
74762306a36Sopenharmony_ci */
74862306a36Sopenharmony_cistatic void pidff_set_autocenter(struct input_dev *dev, u16 magnitude)
74962306a36Sopenharmony_ci{
75062306a36Sopenharmony_ci	struct pidff_device *pidff = dev->ff->private;
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	pidff_autocenter(pidff, magnitude);
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci/*
75662306a36Sopenharmony_ci * Find fields from a report and fill a pidff_usage
75762306a36Sopenharmony_ci */
75862306a36Sopenharmony_cistatic int pidff_find_fields(struct pidff_usage *usage, const u8 *table,
75962306a36Sopenharmony_ci			     struct hid_report *report, int count, int strict)
76062306a36Sopenharmony_ci{
76162306a36Sopenharmony_ci	int i, j, k, found;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	for (k = 0; k < count; k++) {
76462306a36Sopenharmony_ci		found = 0;
76562306a36Sopenharmony_ci		for (i = 0; i < report->maxfield; i++) {
76662306a36Sopenharmony_ci			if (report->field[i]->maxusage !=
76762306a36Sopenharmony_ci			    report->field[i]->report_count) {
76862306a36Sopenharmony_ci				pr_debug("maxusage and report_count do not match, skipping\n");
76962306a36Sopenharmony_ci				continue;
77062306a36Sopenharmony_ci			}
77162306a36Sopenharmony_ci			for (j = 0; j < report->field[i]->maxusage; j++) {
77262306a36Sopenharmony_ci				if (report->field[i]->usage[j].hid ==
77362306a36Sopenharmony_ci				    (HID_UP_PID | table[k])) {
77462306a36Sopenharmony_ci					pr_debug("found %d at %d->%d\n",
77562306a36Sopenharmony_ci						 k, i, j);
77662306a36Sopenharmony_ci					usage[k].field = report->field[i];
77762306a36Sopenharmony_ci					usage[k].value =
77862306a36Sopenharmony_ci						&report->field[i]->value[j];
77962306a36Sopenharmony_ci					found = 1;
78062306a36Sopenharmony_ci					break;
78162306a36Sopenharmony_ci				}
78262306a36Sopenharmony_ci			}
78362306a36Sopenharmony_ci			if (found)
78462306a36Sopenharmony_ci				break;
78562306a36Sopenharmony_ci		}
78662306a36Sopenharmony_ci		if (!found && strict) {
78762306a36Sopenharmony_ci			pr_debug("failed to locate %d\n", k);
78862306a36Sopenharmony_ci			return -1;
78962306a36Sopenharmony_ci		}
79062306a36Sopenharmony_ci	}
79162306a36Sopenharmony_ci	return 0;
79262306a36Sopenharmony_ci}
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci/*
79562306a36Sopenharmony_ci * Return index into pidff_reports for the given usage
79662306a36Sopenharmony_ci */
79762306a36Sopenharmony_cistatic int pidff_check_usage(int usage)
79862306a36Sopenharmony_ci{
79962306a36Sopenharmony_ci	int i;
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	for (i = 0; i < sizeof(pidff_reports); i++)
80262306a36Sopenharmony_ci		if (usage == (HID_UP_PID | pidff_reports[i]))
80362306a36Sopenharmony_ci			return i;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	return -1;
80662306a36Sopenharmony_ci}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci/*
80962306a36Sopenharmony_ci * Find the reports and fill pidff->reports[]
81062306a36Sopenharmony_ci * report_type specifies either OUTPUT or FEATURE reports
81162306a36Sopenharmony_ci */
81262306a36Sopenharmony_cistatic void pidff_find_reports(struct hid_device *hid, int report_type,
81362306a36Sopenharmony_ci			       struct pidff_device *pidff)
81462306a36Sopenharmony_ci{
81562306a36Sopenharmony_ci	struct hid_report *report;
81662306a36Sopenharmony_ci	int i, ret;
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	list_for_each_entry(report,
81962306a36Sopenharmony_ci			    &hid->report_enum[report_type].report_list, list) {
82062306a36Sopenharmony_ci		if (report->maxfield < 1)
82162306a36Sopenharmony_ci			continue;
82262306a36Sopenharmony_ci		ret = pidff_check_usage(report->field[0]->logical);
82362306a36Sopenharmony_ci		if (ret != -1) {
82462306a36Sopenharmony_ci			hid_dbg(hid, "found usage 0x%02x from field->logical\n",
82562306a36Sopenharmony_ci				pidff_reports[ret]);
82662306a36Sopenharmony_ci			pidff->reports[ret] = report;
82762306a36Sopenharmony_ci			continue;
82862306a36Sopenharmony_ci		}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci		/*
83162306a36Sopenharmony_ci		 * Sometimes logical collections are stacked to indicate
83262306a36Sopenharmony_ci		 * different usages for the report and the field, in which
83362306a36Sopenharmony_ci		 * case we want the usage of the parent. However, Linux HID
83462306a36Sopenharmony_ci		 * implementation hides this fact, so we have to dig it up
83562306a36Sopenharmony_ci		 * ourselves
83662306a36Sopenharmony_ci		 */
83762306a36Sopenharmony_ci		i = report->field[0]->usage[0].collection_index;
83862306a36Sopenharmony_ci		if (i <= 0 ||
83962306a36Sopenharmony_ci		    hid->collection[i - 1].type != HID_COLLECTION_LOGICAL)
84062306a36Sopenharmony_ci			continue;
84162306a36Sopenharmony_ci		ret = pidff_check_usage(hid->collection[i - 1].usage);
84262306a36Sopenharmony_ci		if (ret != -1 && !pidff->reports[ret]) {
84362306a36Sopenharmony_ci			hid_dbg(hid,
84462306a36Sopenharmony_ci				"found usage 0x%02x from collection array\n",
84562306a36Sopenharmony_ci				pidff_reports[ret]);
84662306a36Sopenharmony_ci			pidff->reports[ret] = report;
84762306a36Sopenharmony_ci		}
84862306a36Sopenharmony_ci	}
84962306a36Sopenharmony_ci}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci/*
85262306a36Sopenharmony_ci * Test if the required reports have been found
85362306a36Sopenharmony_ci */
85462306a36Sopenharmony_cistatic int pidff_reports_ok(struct pidff_device *pidff)
85562306a36Sopenharmony_ci{
85662306a36Sopenharmony_ci	int i;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	for (i = 0; i <= PID_REQUIRED_REPORTS; i++) {
85962306a36Sopenharmony_ci		if (!pidff->reports[i]) {
86062306a36Sopenharmony_ci			hid_dbg(pidff->hid, "%d missing\n", i);
86162306a36Sopenharmony_ci			return 0;
86262306a36Sopenharmony_ci		}
86362306a36Sopenharmony_ci	}
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	return 1;
86662306a36Sopenharmony_ci}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci/*
86962306a36Sopenharmony_ci * Find a field with a specific usage within a report
87062306a36Sopenharmony_ci */
87162306a36Sopenharmony_cistatic struct hid_field *pidff_find_special_field(struct hid_report *report,
87262306a36Sopenharmony_ci						  int usage, int enforce_min)
87362306a36Sopenharmony_ci{
87462306a36Sopenharmony_ci	int i;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	for (i = 0; i < report->maxfield; i++) {
87762306a36Sopenharmony_ci		if (report->field[i]->logical == (HID_UP_PID | usage) &&
87862306a36Sopenharmony_ci		    report->field[i]->report_count > 0) {
87962306a36Sopenharmony_ci			if (!enforce_min ||
88062306a36Sopenharmony_ci			    report->field[i]->logical_minimum == 1)
88162306a36Sopenharmony_ci				return report->field[i];
88262306a36Sopenharmony_ci			else {
88362306a36Sopenharmony_ci				pr_err("logical_minimum is not 1 as it should be\n");
88462306a36Sopenharmony_ci				return NULL;
88562306a36Sopenharmony_ci			}
88662306a36Sopenharmony_ci		}
88762306a36Sopenharmony_ci	}
88862306a36Sopenharmony_ci	return NULL;
88962306a36Sopenharmony_ci}
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci/*
89262306a36Sopenharmony_ci * Fill a pidff->*_id struct table
89362306a36Sopenharmony_ci */
89462306a36Sopenharmony_cistatic int pidff_find_special_keys(int *keys, struct hid_field *fld,
89562306a36Sopenharmony_ci				   const u8 *usagetable, int count)
89662306a36Sopenharmony_ci{
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	int i, j;
89962306a36Sopenharmony_ci	int found = 0;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
90262306a36Sopenharmony_ci		for (j = 0; j < fld->maxusage; j++) {
90362306a36Sopenharmony_ci			if (fld->usage[j].hid == (HID_UP_PID | usagetable[i])) {
90462306a36Sopenharmony_ci				keys[i] = j + 1;
90562306a36Sopenharmony_ci				found++;
90662306a36Sopenharmony_ci				break;
90762306a36Sopenharmony_ci			}
90862306a36Sopenharmony_ci		}
90962306a36Sopenharmony_ci	}
91062306a36Sopenharmony_ci	return found;
91162306a36Sopenharmony_ci}
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci#define PIDFF_FIND_SPECIAL_KEYS(keys, field, name) \
91462306a36Sopenharmony_ci	pidff_find_special_keys(pidff->keys, pidff->field, pidff_ ## name, \
91562306a36Sopenharmony_ci		sizeof(pidff_ ## name))
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci/*
91862306a36Sopenharmony_ci * Find and check the special fields
91962306a36Sopenharmony_ci */
92062306a36Sopenharmony_cistatic int pidff_find_special_fields(struct pidff_device *pidff)
92162306a36Sopenharmony_ci{
92262306a36Sopenharmony_ci	hid_dbg(pidff->hid, "finding special fields\n");
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	pidff->create_new_effect_type =
92562306a36Sopenharmony_ci		pidff_find_special_field(pidff->reports[PID_CREATE_NEW_EFFECT],
92662306a36Sopenharmony_ci					 0x25, 1);
92762306a36Sopenharmony_ci	pidff->set_effect_type =
92862306a36Sopenharmony_ci		pidff_find_special_field(pidff->reports[PID_SET_EFFECT],
92962306a36Sopenharmony_ci					 0x25, 1);
93062306a36Sopenharmony_ci	pidff->effect_direction =
93162306a36Sopenharmony_ci		pidff_find_special_field(pidff->reports[PID_SET_EFFECT],
93262306a36Sopenharmony_ci					 0x57, 0);
93362306a36Sopenharmony_ci	pidff->device_control =
93462306a36Sopenharmony_ci		pidff_find_special_field(pidff->reports[PID_DEVICE_CONTROL],
93562306a36Sopenharmony_ci					 0x96, 1);
93662306a36Sopenharmony_ci	pidff->block_load_status =
93762306a36Sopenharmony_ci		pidff_find_special_field(pidff->reports[PID_BLOCK_LOAD],
93862306a36Sopenharmony_ci					 0x8b, 1);
93962306a36Sopenharmony_ci	pidff->effect_operation_status =
94062306a36Sopenharmony_ci		pidff_find_special_field(pidff->reports[PID_EFFECT_OPERATION],
94162306a36Sopenharmony_ci					 0x78, 1);
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	hid_dbg(pidff->hid, "search done\n");
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	if (!pidff->create_new_effect_type || !pidff->set_effect_type) {
94662306a36Sopenharmony_ci		hid_err(pidff->hid, "effect lists not found\n");
94762306a36Sopenharmony_ci		return -1;
94862306a36Sopenharmony_ci	}
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	if (!pidff->effect_direction) {
95162306a36Sopenharmony_ci		hid_err(pidff->hid, "direction field not found\n");
95262306a36Sopenharmony_ci		return -1;
95362306a36Sopenharmony_ci	}
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	if (!pidff->device_control) {
95662306a36Sopenharmony_ci		hid_err(pidff->hid, "device control field not found\n");
95762306a36Sopenharmony_ci		return -1;
95862306a36Sopenharmony_ci	}
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	if (!pidff->block_load_status) {
96162306a36Sopenharmony_ci		hid_err(pidff->hid, "block load status field not found\n");
96262306a36Sopenharmony_ci		return -1;
96362306a36Sopenharmony_ci	}
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	if (!pidff->effect_operation_status) {
96662306a36Sopenharmony_ci		hid_err(pidff->hid, "effect operation field not found\n");
96762306a36Sopenharmony_ci		return -1;
96862306a36Sopenharmony_ci	}
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	pidff_find_special_keys(pidff->control_id, pidff->device_control,
97162306a36Sopenharmony_ci				pidff_device_control,
97262306a36Sopenharmony_ci				sizeof(pidff_device_control));
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	PIDFF_FIND_SPECIAL_KEYS(control_id, device_control, device_control);
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	if (!PIDFF_FIND_SPECIAL_KEYS(type_id, create_new_effect_type,
97762306a36Sopenharmony_ci				     effect_types)) {
97862306a36Sopenharmony_ci		hid_err(pidff->hid, "no effect types found\n");
97962306a36Sopenharmony_ci		return -1;
98062306a36Sopenharmony_ci	}
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	if (PIDFF_FIND_SPECIAL_KEYS(status_id, block_load_status,
98362306a36Sopenharmony_ci				    block_load_status) !=
98462306a36Sopenharmony_ci			sizeof(pidff_block_load_status)) {
98562306a36Sopenharmony_ci		hid_err(pidff->hid,
98662306a36Sopenharmony_ci			"block load status identifiers not found\n");
98762306a36Sopenharmony_ci		return -1;
98862306a36Sopenharmony_ci	}
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	if (PIDFF_FIND_SPECIAL_KEYS(operation_id, effect_operation_status,
99162306a36Sopenharmony_ci				    effect_operation_status) !=
99262306a36Sopenharmony_ci			sizeof(pidff_effect_operation_status)) {
99362306a36Sopenharmony_ci		hid_err(pidff->hid, "effect operation identifiers not found\n");
99462306a36Sopenharmony_ci		return -1;
99562306a36Sopenharmony_ci	}
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	return 0;
99862306a36Sopenharmony_ci}
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci/*
100162306a36Sopenharmony_ci * Find the implemented effect types
100262306a36Sopenharmony_ci */
100362306a36Sopenharmony_cistatic int pidff_find_effects(struct pidff_device *pidff,
100462306a36Sopenharmony_ci			      struct input_dev *dev)
100562306a36Sopenharmony_ci{
100662306a36Sopenharmony_ci	int i;
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	for (i = 0; i < sizeof(pidff_effect_types); i++) {
100962306a36Sopenharmony_ci		int pidff_type = pidff->type_id[i];
101062306a36Sopenharmony_ci		if (pidff->set_effect_type->usage[pidff_type].hid !=
101162306a36Sopenharmony_ci		    pidff->create_new_effect_type->usage[pidff_type].hid) {
101262306a36Sopenharmony_ci			hid_err(pidff->hid,
101362306a36Sopenharmony_ci				"effect type number %d is invalid\n", i);
101462306a36Sopenharmony_ci			return -1;
101562306a36Sopenharmony_ci		}
101662306a36Sopenharmony_ci	}
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	if (pidff->type_id[PID_CONSTANT])
101962306a36Sopenharmony_ci		set_bit(FF_CONSTANT, dev->ffbit);
102062306a36Sopenharmony_ci	if (pidff->type_id[PID_RAMP])
102162306a36Sopenharmony_ci		set_bit(FF_RAMP, dev->ffbit);
102262306a36Sopenharmony_ci	if (pidff->type_id[PID_SQUARE]) {
102362306a36Sopenharmony_ci		set_bit(FF_SQUARE, dev->ffbit);
102462306a36Sopenharmony_ci		set_bit(FF_PERIODIC, dev->ffbit);
102562306a36Sopenharmony_ci	}
102662306a36Sopenharmony_ci	if (pidff->type_id[PID_SINE]) {
102762306a36Sopenharmony_ci		set_bit(FF_SINE, dev->ffbit);
102862306a36Sopenharmony_ci		set_bit(FF_PERIODIC, dev->ffbit);
102962306a36Sopenharmony_ci	}
103062306a36Sopenharmony_ci	if (pidff->type_id[PID_TRIANGLE]) {
103162306a36Sopenharmony_ci		set_bit(FF_TRIANGLE, dev->ffbit);
103262306a36Sopenharmony_ci		set_bit(FF_PERIODIC, dev->ffbit);
103362306a36Sopenharmony_ci	}
103462306a36Sopenharmony_ci	if (pidff->type_id[PID_SAW_UP]) {
103562306a36Sopenharmony_ci		set_bit(FF_SAW_UP, dev->ffbit);
103662306a36Sopenharmony_ci		set_bit(FF_PERIODIC, dev->ffbit);
103762306a36Sopenharmony_ci	}
103862306a36Sopenharmony_ci	if (pidff->type_id[PID_SAW_DOWN]) {
103962306a36Sopenharmony_ci		set_bit(FF_SAW_DOWN, dev->ffbit);
104062306a36Sopenharmony_ci		set_bit(FF_PERIODIC, dev->ffbit);
104162306a36Sopenharmony_ci	}
104262306a36Sopenharmony_ci	if (pidff->type_id[PID_SPRING])
104362306a36Sopenharmony_ci		set_bit(FF_SPRING, dev->ffbit);
104462306a36Sopenharmony_ci	if (pidff->type_id[PID_DAMPER])
104562306a36Sopenharmony_ci		set_bit(FF_DAMPER, dev->ffbit);
104662306a36Sopenharmony_ci	if (pidff->type_id[PID_INERTIA])
104762306a36Sopenharmony_ci		set_bit(FF_INERTIA, dev->ffbit);
104862306a36Sopenharmony_ci	if (pidff->type_id[PID_FRICTION])
104962306a36Sopenharmony_ci		set_bit(FF_FRICTION, dev->ffbit);
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	return 0;
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci}
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci#define PIDFF_FIND_FIELDS(name, report, strict) \
105662306a36Sopenharmony_ci	pidff_find_fields(pidff->name, pidff_ ## name, \
105762306a36Sopenharmony_ci		pidff->reports[report], \
105862306a36Sopenharmony_ci		sizeof(pidff_ ## name), strict)
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci/*
106162306a36Sopenharmony_ci * Fill and check the pidff_usages
106262306a36Sopenharmony_ci */
106362306a36Sopenharmony_cistatic int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
106462306a36Sopenharmony_ci{
106562306a36Sopenharmony_ci	int envelope_ok = 0;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	if (PIDFF_FIND_FIELDS(set_effect, PID_SET_EFFECT, 1)) {
106862306a36Sopenharmony_ci		hid_err(pidff->hid, "unknown set_effect report layout\n");
106962306a36Sopenharmony_ci		return -ENODEV;
107062306a36Sopenharmony_ci	}
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	PIDFF_FIND_FIELDS(block_load, PID_BLOCK_LOAD, 0);
107362306a36Sopenharmony_ci	if (!pidff->block_load[PID_EFFECT_BLOCK_INDEX].value) {
107462306a36Sopenharmony_ci		hid_err(pidff->hid, "unknown pid_block_load report layout\n");
107562306a36Sopenharmony_ci		return -ENODEV;
107662306a36Sopenharmony_ci	}
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	if (PIDFF_FIND_FIELDS(effect_operation, PID_EFFECT_OPERATION, 1)) {
107962306a36Sopenharmony_ci		hid_err(pidff->hid, "unknown effect_operation report layout\n");
108062306a36Sopenharmony_ci		return -ENODEV;
108162306a36Sopenharmony_ci	}
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	if (PIDFF_FIND_FIELDS(block_free, PID_BLOCK_FREE, 1)) {
108462306a36Sopenharmony_ci		hid_err(pidff->hid, "unknown pid_block_free report layout\n");
108562306a36Sopenharmony_ci		return -ENODEV;
108662306a36Sopenharmony_ci	}
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	if (!PIDFF_FIND_FIELDS(set_envelope, PID_SET_ENVELOPE, 1))
108962306a36Sopenharmony_ci		envelope_ok = 1;
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	if (pidff_find_special_fields(pidff) || pidff_find_effects(pidff, dev))
109262306a36Sopenharmony_ci		return -ENODEV;
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	if (!envelope_ok) {
109562306a36Sopenharmony_ci		if (test_and_clear_bit(FF_CONSTANT, dev->ffbit))
109662306a36Sopenharmony_ci			hid_warn(pidff->hid,
109762306a36Sopenharmony_ci				 "has constant effect but no envelope\n");
109862306a36Sopenharmony_ci		if (test_and_clear_bit(FF_RAMP, dev->ffbit))
109962306a36Sopenharmony_ci			hid_warn(pidff->hid,
110062306a36Sopenharmony_ci				 "has ramp effect but no envelope\n");
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci		if (test_and_clear_bit(FF_PERIODIC, dev->ffbit))
110362306a36Sopenharmony_ci			hid_warn(pidff->hid,
110462306a36Sopenharmony_ci				 "has periodic effect but no envelope\n");
110562306a36Sopenharmony_ci	}
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	if (test_bit(FF_CONSTANT, dev->ffbit) &&
110862306a36Sopenharmony_ci	    PIDFF_FIND_FIELDS(set_constant, PID_SET_CONSTANT, 1)) {
110962306a36Sopenharmony_ci		hid_warn(pidff->hid, "unknown constant effect layout\n");
111062306a36Sopenharmony_ci		clear_bit(FF_CONSTANT, dev->ffbit);
111162306a36Sopenharmony_ci	}
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	if (test_bit(FF_RAMP, dev->ffbit) &&
111462306a36Sopenharmony_ci	    PIDFF_FIND_FIELDS(set_ramp, PID_SET_RAMP, 1)) {
111562306a36Sopenharmony_ci		hid_warn(pidff->hid, "unknown ramp effect layout\n");
111662306a36Sopenharmony_ci		clear_bit(FF_RAMP, dev->ffbit);
111762306a36Sopenharmony_ci	}
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	if ((test_bit(FF_SPRING, dev->ffbit) ||
112062306a36Sopenharmony_ci	     test_bit(FF_DAMPER, dev->ffbit) ||
112162306a36Sopenharmony_ci	     test_bit(FF_FRICTION, dev->ffbit) ||
112262306a36Sopenharmony_ci	     test_bit(FF_INERTIA, dev->ffbit)) &&
112362306a36Sopenharmony_ci	    PIDFF_FIND_FIELDS(set_condition, PID_SET_CONDITION, 1)) {
112462306a36Sopenharmony_ci		hid_warn(pidff->hid, "unknown condition effect layout\n");
112562306a36Sopenharmony_ci		clear_bit(FF_SPRING, dev->ffbit);
112662306a36Sopenharmony_ci		clear_bit(FF_DAMPER, dev->ffbit);
112762306a36Sopenharmony_ci		clear_bit(FF_FRICTION, dev->ffbit);
112862306a36Sopenharmony_ci		clear_bit(FF_INERTIA, dev->ffbit);
112962306a36Sopenharmony_ci	}
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	if (test_bit(FF_PERIODIC, dev->ffbit) &&
113262306a36Sopenharmony_ci	    PIDFF_FIND_FIELDS(set_periodic, PID_SET_PERIODIC, 1)) {
113362306a36Sopenharmony_ci		hid_warn(pidff->hid, "unknown periodic effect layout\n");
113462306a36Sopenharmony_ci		clear_bit(FF_PERIODIC, dev->ffbit);
113562306a36Sopenharmony_ci	}
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	PIDFF_FIND_FIELDS(pool, PID_POOL, 0);
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	if (!PIDFF_FIND_FIELDS(device_gain, PID_DEVICE_GAIN, 1))
114062306a36Sopenharmony_ci		set_bit(FF_GAIN, dev->ffbit);
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	return 0;
114362306a36Sopenharmony_ci}
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci/*
114662306a36Sopenharmony_ci * Reset the device
114762306a36Sopenharmony_ci */
114862306a36Sopenharmony_cistatic void pidff_reset(struct pidff_device *pidff)
114962306a36Sopenharmony_ci{
115062306a36Sopenharmony_ci	struct hid_device *hid = pidff->hid;
115162306a36Sopenharmony_ci	int i = 0;
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	pidff->device_control->value[0] = pidff->control_id[PID_RESET];
115462306a36Sopenharmony_ci	/* We reset twice as sometimes hid_wait_io isn't waiting long enough */
115562306a36Sopenharmony_ci	hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT);
115662306a36Sopenharmony_ci	hid_hw_wait(hid);
115762306a36Sopenharmony_ci	hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT);
115862306a36Sopenharmony_ci	hid_hw_wait(hid);
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci	pidff->device_control->value[0] =
116162306a36Sopenharmony_ci		pidff->control_id[PID_ENABLE_ACTUATORS];
116262306a36Sopenharmony_ci	hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT);
116362306a36Sopenharmony_ci	hid_hw_wait(hid);
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	/* pool report is sometimes messed up, refetch it */
116662306a36Sopenharmony_ci	hid_hw_request(hid, pidff->reports[PID_POOL], HID_REQ_GET_REPORT);
116762306a36Sopenharmony_ci	hid_hw_wait(hid);
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	if (pidff->pool[PID_SIMULTANEOUS_MAX].value) {
117062306a36Sopenharmony_ci		while (pidff->pool[PID_SIMULTANEOUS_MAX].value[0] < 2) {
117162306a36Sopenharmony_ci			if (i++ > 20) {
117262306a36Sopenharmony_ci				hid_warn(pidff->hid,
117362306a36Sopenharmony_ci					 "device reports %d simultaneous effects\n",
117462306a36Sopenharmony_ci					 pidff->pool[PID_SIMULTANEOUS_MAX].value[0]);
117562306a36Sopenharmony_ci				break;
117662306a36Sopenharmony_ci			}
117762306a36Sopenharmony_ci			hid_dbg(pidff->hid, "pid_pool requested again\n");
117862306a36Sopenharmony_ci			hid_hw_request(hid, pidff->reports[PID_POOL],
117962306a36Sopenharmony_ci					  HID_REQ_GET_REPORT);
118062306a36Sopenharmony_ci			hid_hw_wait(hid);
118162306a36Sopenharmony_ci		}
118262306a36Sopenharmony_ci	}
118362306a36Sopenharmony_ci}
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci/*
118662306a36Sopenharmony_ci * Test if autocenter modification is using the supported method
118762306a36Sopenharmony_ci */
118862306a36Sopenharmony_cistatic int pidff_check_autocenter(struct pidff_device *pidff,
118962306a36Sopenharmony_ci				  struct input_dev *dev)
119062306a36Sopenharmony_ci{
119162306a36Sopenharmony_ci	int error;
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	/*
119462306a36Sopenharmony_ci	 * Let's find out if autocenter modification is supported
119562306a36Sopenharmony_ci	 * Specification doesn't specify anything, so we request an
119662306a36Sopenharmony_ci	 * effect upload and cancel it immediately. If the approved
119762306a36Sopenharmony_ci	 * effect id was one above the minimum, then we assume the first
119862306a36Sopenharmony_ci	 * effect id is a built-in spring type effect used for autocenter
119962306a36Sopenharmony_ci	 */
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	error = pidff_request_effect_upload(pidff, 1);
120262306a36Sopenharmony_ci	if (error) {
120362306a36Sopenharmony_ci		hid_err(pidff->hid, "upload request failed\n");
120462306a36Sopenharmony_ci		return error;
120562306a36Sopenharmony_ci	}
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	if (pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] ==
120862306a36Sopenharmony_ci	    pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum + 1) {
120962306a36Sopenharmony_ci		pidff_autocenter(pidff, 0xffff);
121062306a36Sopenharmony_ci		set_bit(FF_AUTOCENTER, dev->ffbit);
121162306a36Sopenharmony_ci	} else {
121262306a36Sopenharmony_ci		hid_notice(pidff->hid,
121362306a36Sopenharmony_ci			   "device has unknown autocenter control method\n");
121462306a36Sopenharmony_ci	}
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	pidff_erase_pid(pidff,
121762306a36Sopenharmony_ci			pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]);
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	return 0;
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci}
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci/*
122462306a36Sopenharmony_ci * Check if the device is PID and initialize it
122562306a36Sopenharmony_ci */
122662306a36Sopenharmony_ciint hid_pidff_init(struct hid_device *hid)
122762306a36Sopenharmony_ci{
122862306a36Sopenharmony_ci	struct pidff_device *pidff;
122962306a36Sopenharmony_ci	struct hid_input *hidinput = list_entry(hid->inputs.next,
123062306a36Sopenharmony_ci						struct hid_input, list);
123162306a36Sopenharmony_ci	struct input_dev *dev = hidinput->input;
123262306a36Sopenharmony_ci	struct ff_device *ff;
123362306a36Sopenharmony_ci	int max_effects;
123462306a36Sopenharmony_ci	int error;
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	hid_dbg(hid, "starting pid init\n");
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	if (list_empty(&hid->report_enum[HID_OUTPUT_REPORT].report_list)) {
123962306a36Sopenharmony_ci		hid_dbg(hid, "not a PID device, no output report\n");
124062306a36Sopenharmony_ci		return -ENODEV;
124162306a36Sopenharmony_ci	}
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	pidff = kzalloc(sizeof(*pidff), GFP_KERNEL);
124462306a36Sopenharmony_ci	if (!pidff)
124562306a36Sopenharmony_ci		return -ENOMEM;
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	pidff->hid = hid;
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	hid_device_io_start(hid);
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	pidff_find_reports(hid, HID_OUTPUT_REPORT, pidff);
125262306a36Sopenharmony_ci	pidff_find_reports(hid, HID_FEATURE_REPORT, pidff);
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	if (!pidff_reports_ok(pidff)) {
125562306a36Sopenharmony_ci		hid_dbg(hid, "reports not ok, aborting\n");
125662306a36Sopenharmony_ci		error = -ENODEV;
125762306a36Sopenharmony_ci		goto fail;
125862306a36Sopenharmony_ci	}
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	error = pidff_init_fields(pidff, dev);
126162306a36Sopenharmony_ci	if (error)
126262306a36Sopenharmony_ci		goto fail;
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	pidff_reset(pidff);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	if (test_bit(FF_GAIN, dev->ffbit)) {
126762306a36Sopenharmony_ci		pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], 0xffff);
126862306a36Sopenharmony_ci		hid_hw_request(hid, pidff->reports[PID_DEVICE_GAIN],
126962306a36Sopenharmony_ci				     HID_REQ_SET_REPORT);
127062306a36Sopenharmony_ci	}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	error = pidff_check_autocenter(pidff, dev);
127362306a36Sopenharmony_ci	if (error)
127462306a36Sopenharmony_ci		goto fail;
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	max_effects =
127762306a36Sopenharmony_ci	    pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_maximum -
127862306a36Sopenharmony_ci	    pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum +
127962306a36Sopenharmony_ci	    1;
128062306a36Sopenharmony_ci	hid_dbg(hid, "max effects is %d\n", max_effects);
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	if (max_effects > PID_EFFECTS_MAX)
128362306a36Sopenharmony_ci		max_effects = PID_EFFECTS_MAX;
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	if (pidff->pool[PID_SIMULTANEOUS_MAX].value)
128662306a36Sopenharmony_ci		hid_dbg(hid, "max simultaneous effects is %d\n",
128762306a36Sopenharmony_ci			pidff->pool[PID_SIMULTANEOUS_MAX].value[0]);
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	if (pidff->pool[PID_RAM_POOL_SIZE].value)
129062306a36Sopenharmony_ci		hid_dbg(hid, "device memory size is %d bytes\n",
129162306a36Sopenharmony_ci			pidff->pool[PID_RAM_POOL_SIZE].value[0]);
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	if (pidff->pool[PID_DEVICE_MANAGED_POOL].value &&
129462306a36Sopenharmony_ci	    pidff->pool[PID_DEVICE_MANAGED_POOL].value[0] == 0) {
129562306a36Sopenharmony_ci		error = -EPERM;
129662306a36Sopenharmony_ci		hid_notice(hid,
129762306a36Sopenharmony_ci			   "device does not support device managed pool\n");
129862306a36Sopenharmony_ci		goto fail;
129962306a36Sopenharmony_ci	}
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	error = input_ff_create(dev, max_effects);
130262306a36Sopenharmony_ci	if (error)
130362306a36Sopenharmony_ci		goto fail;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	ff = dev->ff;
130662306a36Sopenharmony_ci	ff->private = pidff;
130762306a36Sopenharmony_ci	ff->upload = pidff_upload_effect;
130862306a36Sopenharmony_ci	ff->erase = pidff_erase_effect;
130962306a36Sopenharmony_ci	ff->set_gain = pidff_set_gain;
131062306a36Sopenharmony_ci	ff->set_autocenter = pidff_set_autocenter;
131162306a36Sopenharmony_ci	ff->playback = pidff_playback;
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	hid_info(dev, "Force feedback for USB HID PID devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	hid_device_io_stop(hid);
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	return 0;
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci fail:
132062306a36Sopenharmony_ci	hid_device_io_stop(hid);
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	kfree(pidff);
132362306a36Sopenharmony_ci	return error;
132462306a36Sopenharmony_ci}
1325