// SPDX-License-Identifier: GPL-2.0
#include "hid-tmt300rs.h"

static int timer_msecs = DEFAULT_TIMER_PERIOD;
module_param(timer_msecs, int, 0660);
MODULE_PARM_DESC(timer_msecs, "Timer resolution in msecs");

static int spring_level = 30;
module_param(spring_level, int, 0);
MODULE_PARM_DESC(spring_level, "Level of spring force (0-100), as per Oversteer standards");

static int damper_level = 30;
module_param(damper_level, int, 0);
MODULE_PARM_DESC(damper_level, "Level of damper force (0-100), as per Oversteer standards");

static int friction_level = 30;
module_param(friction_level, int, 0);
MODULE_PARM_DESC(friction_level, "Level of friction force (0-100), as per Oversteer standards");

static struct t300rs_device_entry *t300rs_get_device(struct hid_device *hdev)
{
	struct t300rs_data *drv_data;
	struct t300rs_device_entry *t300rs;

	spin_lock_irqsave(&lock, lock_flags);
	drv_data = hid_get_drvdata(hdev);
	if (!drv_data) {
		hid_err(hdev, "private data not found\n");
		return NULL;
	}

	t300rs = drv_data->device_props;
	if (!t300rs) {
		hid_err(hdev, "device properties not found\n");
		return NULL;
	}
	spin_unlock_irqrestore(&lock, lock_flags);
	return t300rs;
}

static int t300rs_send_int(struct t300rs_device_entry *t300rs)
{
	int i;
	for (i = 0; i < T300RS_BUFFER_LENGTH; ++i)
		t300rs->ff_field->value[i] = t300rs->send_buffer[i];

	hid_hw_request(t300rs->hdev, t300rs->report, HID_REQ_SET_REPORT);

	memset(t300rs->send_buffer, 0, T300RS_BUFFER_LENGTH);

	return 0;
}

static void t300rs_fill_header(struct t300rs_packet_header *packet_header,
		uint8_t id, uint8_t code)
{
	packet_header->id = id + 1;
	packet_header->code = code;
}

static int t300rs_play_effect(struct t300rs_device_entry *t300rs,
		struct t300rs_effect_state *state)
{
	struct __packed t300rs_packet_play {
		struct t300rs_packet_header header;
		uint8_t value;
	} *play_packet = (struct t300rs_packet_play *)t300rs->send_buffer;

	int ret;


	t300rs_fill_header(&play_packet->header, state->effect.id, 0x89);
	play_packet->value = 0x01;

	ret = t300rs_send_int(t300rs);
	if (ret)
		hid_err(t300rs->hdev, "failed starting effect play\n");

	return ret;
}

static int t300rs_stop_effect(struct t300rs_device_entry *t300rs,
		struct t300rs_effect_state *state)
{
	struct __packed t300rs_packet_stop {
		struct t300rs_packet_header header;
		uint8_t value;
	} *stop_packet = (struct t300rs_packet_stop *)t300rs->send_buffer;

	int ret;


	t300rs_fill_header(&stop_packet->header, state->effect.id, 0x89);

	ret = t300rs_send_int(t300rs);
	if (ret)
		hid_err(t300rs->hdev, "failed stopping effect play\n");

	return ret;
}

static void t300rs_fill_envelope(struct t300rs_packet_envelope *packet_envelope,
		int16_t level, uint16_t duration, struct ff_envelope *envelope)
{
	uint16_t attack_length = (duration * envelope->attack_length) / 0x7fff;
	uint16_t attack_level = (level * envelope->attack_level) / 0x7fff;
	uint16_t fade_length = (duration * envelope->fade_length) / 0x7fff;
	uint16_t fade_level = (level * envelope->fade_level) / 0x7fff;

	packet_envelope->attack_length = cpu_to_le16(attack_length);
	packet_envelope->attack_level = cpu_to_le16(attack_level);
	packet_envelope->fade_length = cpu_to_le16(fade_length);
	packet_envelope->fade_level = cpu_to_le16(fade_level);
}

static void t300rs_fill_timing(struct t300rs_packet_timing *packet_timing,
		uint16_t duration, uint16_t offset){
	packet_timing->start_marker = 0x47;

	packet_timing->duration = cpu_to_le16(duration);
	packet_timing->offset = cpu_to_le16(offset);

	packet_timing->end_marker = 0xffff;
}

static int t300rs_modify_envelope(struct t300rs_device_entry *t300rs,
		struct t300rs_effect_state *state,
		int16_t level,
		uint16_t duration,
		uint8_t id,
		struct ff_envelope envelope,
		struct ff_envelope envelope_old
		)
{
	struct __packed t300rs_packet_mod_envelope {
		struct t300rs_packet_header header;
		uint8_t attribute;
		uint16_t value;
	} *packet_mod_envelope = (struct t300rs_packet_mod_envelope *)t300rs->send_buffer;

	uint16_t attack_length, attack_level, fade_length, fade_level;
	int ret = 0;

	duration = duration - 1;

	attack_length = (duration * envelope.attack_length) / 0x7fff;
	attack_level = (level * envelope.attack_level) / 0x7fff;
	fade_length = (duration * envelope.fade_length) / 0x7fff;
	fade_level = (level * envelope.fade_level) / 0x7fff;

	if (envelope.attack_length != envelope_old.attack_length) {
		t300rs_fill_header(&packet_mod_envelope->header, id, 0x31);
		packet_mod_envelope->attribute = 0x81;
		packet_mod_envelope->value = cpu_to_le16(attack_length);

		ret = t300rs_send_int(t300rs);
		if (ret) {
			hid_err(t300rs->hdev, "failed modifying effect envelope\n");
			goto error;
		}
	}

	if (envelope.attack_level != envelope_old.attack_level) {
		t300rs_fill_header(&packet_mod_envelope->header, id, 0x31);
		packet_mod_envelope->attribute = 0x82;
		packet_mod_envelope->value = cpu_to_le16(attack_level);

		ret = t300rs_send_int(t300rs);
		if (ret) {
			hid_err(t300rs->hdev, "failed modifying effect envelope\n");
			goto error;
		}
	}

	if (envelope.fade_length != envelope_old.fade_length) {
		t300rs_fill_header(&packet_mod_envelope->header, id, 0x31);
		packet_mod_envelope->attribute = 0x84;
		packet_mod_envelope->value = cpu_to_le16(fade_length);

		ret = t300rs_send_int(t300rs);
		if (ret) {
			hid_err(t300rs->hdev, "failed modifying effect envelope\n");
			goto error;
		}
	}

	if (envelope.fade_level != envelope_old.fade_level) {
		t300rs_fill_header(&packet_mod_envelope->header, id, 0x31);
		packet_mod_envelope->attribute = 0x88;
		packet_mod_envelope->value = cpu_to_le16(fade_level);

		ret = t300rs_send_int(t300rs);
		if (ret) {
			hid_err(t300rs->hdev, "failed modifying effect envelope\n");
			goto error;
		}
	}

error:
	return ret;
}

static int t300rs_modify_duration(struct t300rs_device_entry *t300rs,
		struct t300rs_effect_state *state)
{
	struct ff_effect effect = state->effect;
	struct ff_effect old = state->old;
	struct t300rs_packet_mod_duration {
		struct t300rs_packet_header header;
		padding: 8;
	 	uint8_t marker;
		uint16_t duration;
	} *packet_mod_duration = (struct t300rs_packet_mod_duration *)t300rs->send_buffer;

	uint16_t duration;
	int ret = 0;

	duration = effect.replay.length - 1;

	if (effect.replay.length != old.replay.length) {

		t300rs_fill_header(&packet_mod_duration->header, effect.id, 0x49);
		packet_mod_duration->marker = 0x41;
		packet_mod_duration->duration = cpu_to_le16(duration);

		ret = t300rs_send_int(t300rs);
		if (ret) {
			hid_err(t300rs->hdev, "failed modifying duration\n");
			goto error;
		}
	}

error:
	return ret;
}

static int t300rs_modify_constant(struct t300rs_device_entry *t300rs,
		struct t300rs_effect_state *state)
{
	struct ff_effect effect = state->effect;
	struct ff_effect old = state->old;
	struct ff_constant_effect constant = effect.u.constant;
	struct ff_constant_effect constant_old = old.u.constant;
	struct __packed t300rs_packet_mod_constant {
		struct t300rs_packet_header header;
		uint8_t level;
	} *packet_mod_constant = (struct t300rs_packet_mod_constant *)t300rs->send_buffer;
	int ret;
	int16_t level;

	level = (constant.level * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff;

	if (constant.level != constant_old.level) {

		t300rs_fill_header(&packet_mod_constant->header, effect.id, 0x0a);
		packet_mod_constant->level = level;

		ret = t300rs_send_int(t300rs);
		if (ret) {
			hid_err(t300rs->hdev, "failed modifying constant effect\n");
			goto error;
		}

	}

	ret = t300rs_modify_envelope(t300rs,
			state,
			level,
			effect.replay.length,
			effect.id,
			constant.envelope,
			constant_old.envelope
			);

	if (ret) {
		hid_err(t300rs->hdev, "failed modifying constant envelope\n");
		goto error;
	}

	ret = t300rs_modify_duration(t300rs, state);
	if (ret) {
		hid_err(t300rs->hdev, "failed modifying constant duration\n");
		goto error;
	}

error:
	return ret;
}

static int t300rs_modify_ramp(struct t300rs_device_entry *t300rs,
		struct t300rs_effect_state *state)
{
	struct ff_effect effect = state->effect;
	struct ff_effect old = state->old;
	struct ff_ramp_effect ramp = effect.u.ramp;
	struct ff_ramp_effect ramp_old = old.u.ramp;
	struct __packed t300rs_packet_mod_ramp {
		struct t300rs_packet_header header;
		uint8_t attribute;
		uint16_t difference;
		uint16_t level;
	} *packet_mod_ramp = (struct t300rs_packet_mod_ramp *)t300rs->send_buffer;

	int ret;

	uint16_t difference, top, bottom;
	int16_t level;

	top = ramp.end_level > ramp.start_level ? ramp.end_level : ramp.start_level;
	bottom = ramp.end_level > ramp.start_level ? ramp.start_level : ramp.end_level;


	difference = ((top - bottom) * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff;


	level = (top * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff;

	if (ramp.start_level != ramp_old.start_level || ramp.end_level != ramp_old.end_level) {

		t300rs_fill_header(&packet_mod_ramp->header, effect.id, 0x0e);
		packet_mod_ramp->attribute = 0x03;
		packet_mod_ramp->difference = cpu_to_le16(difference);
		packet_mod_ramp->level = cpu_to_le16(level);

		ret = t300rs_send_int(t300rs);
		if (ret) {
			hid_err(t300rs->hdev, "failed modifying ramp effect\n");
			goto error;
		}

	}

	ret = t300rs_modify_envelope(t300rs,
			state,
			level,
			effect.replay.length,
			effect.id,
			ramp.envelope,
			ramp_old.envelope
			);


	if (ret) {
		hid_err(t300rs->hdev, "failed modifying ramp envelope\n");
		goto error;
	}

	ret = t300rs_modify_duration(t300rs, state);
	if (ret) {
		hid_err(t300rs->hdev, "failed modifying ramp duration\n");
		goto error;
	}

error:
	return ret;
}
static int t300rs_modify_damper(struct t300rs_device_entry *t300rs,
		struct t300rs_effect_state *state)
{
	struct ff_effect effect = state->effect;
	struct ff_effect old = state->old;
	struct ff_condition_effect damper = effect.u.condition[0];
	struct ff_condition_effect damper_old = old.u.condition[0];
	struct __packed t300rs_packet_mod_damper {
		struct t300rs_packet_header header;
		uint8_t attribute;
		uint16_t value0;
		uint16_t value1;
	} *packet_mod_damper = (struct t300rs_packet_mod_damper *)t300rs->send_buffer;

	int ret, input_level;

	input_level = damper_level;
	if (state->effect.type == FF_FRICTION)
		input_level = friction_level;

	if (state->effect.type == FF_SPRING)
		input_level = spring_level;

	if (damper.right_coeff != damper_old.right_coeff) {
		int16_t coeff = damper.right_coeff * input_level / 100;

		t300rs_fill_header(&packet_mod_damper->header, effect.id, 0x0e);
		packet_mod_damper->attribute = 0x41;
		packet_mod_damper->value0 = cpu_to_le16(coeff);

		ret = t300rs_send_int(t300rs);
		if (ret) {
			hid_err(t300rs->hdev, "failed modifying damper rc\n");
			goto error;
		}

	}

	if (damper.left_coeff != damper_old.left_coeff) {
		int16_t coeff = damper.left_coeff * input_level / 100;

		t300rs_fill_header(&packet_mod_damper->header, effect.id, 0x0e);
		packet_mod_damper->attribute = 0x42;
		packet_mod_damper->value0 = cpu_to_le16(coeff);

		ret = t300rs_send_int(t300rs);
		if (ret) {
			hid_err(t300rs->hdev, "failed modifying damper lc\n");
			goto error;
		}

	}

	if ((damper.deadband != damper_old.deadband)
			|| (damper.center != damper_old.center)) {

		uint16_t right_deadband = 0xfffe - damper.deadband - damper.center;
		uint16_t left_deadband = 0xfffe - damper.deadband + damper.center;

		t300rs_fill_header(&packet_mod_damper->header, effect.id, 0x0e);
		packet_mod_damper->attribute = 0x4c;
		packet_mod_damper->value0 = cpu_to_le16(right_deadband);
		packet_mod_damper->value1 = cpu_to_le16(left_deadband);

		ret = t300rs_send_int(t300rs);
		if (ret) {
			hid_err(t300rs->hdev, "failed modifying damper deadband\n");
			goto error;
		}

	}

	ret = t300rs_modify_duration(t300rs, state);
	if (ret) {
		hid_err(t300rs->hdev, "failed modifying damper duration\n");
		goto error;
	}

error:
	return ret;
}


static int t300rs_modify_periodic(struct t300rs_device_entry *t300rs,
		struct t300rs_effect_state *state)
{
	struct ff_effect effect = state->effect;
	struct ff_effect old = state->old;
	struct ff_periodic_effect periodic = effect.u.periodic;
	struct ff_periodic_effect periodic_old = old.u.periodic;
	struct __packed t300rs_packet_mod_periodic {
		struct t300rs_packet_header header;
		uint8_t attribute;
		uint16_t value;
	} *packet_mod_periodic = (struct t300rs_packet_mod_periodic *)t300rs->send_buffer;

	int ret;
	int16_t level;

	level = (periodic.magnitude * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff;

	if (periodic.magnitude != periodic_old.magnitude) {

		t300rs_fill_header(&packet_mod_periodic->header, effect.id, 0x0e);
		packet_mod_periodic->attribute = 0x01;
		packet_mod_periodic->value = cpu_to_le16(level);

		ret = t300rs_send_int(t300rs);
		if (ret) {
			hid_err(t300rs->hdev, "failed modifying periodic magnitude\n");
			goto error;
		}

	}

	if (periodic.offset != periodic_old.offset) {
		int16_t offset = periodic.offset;

		t300rs_fill_header(&packet_mod_periodic->header, effect.id, 0x0e);
		packet_mod_periodic->attribute = 0x02;
		packet_mod_periodic->value = cpu_to_le16(offset);

		ret = t300rs_send_int(t300rs);
		if (ret) {
			hid_err(t300rs->hdev, "failed modifying periodic offset\n");
			goto error;
		}

	}

	if (periodic.phase != periodic_old.phase) {
		int16_t phase = periodic.phase;

		t300rs_fill_header(&packet_mod_periodic->header, effect.id, 0x0e);
		packet_mod_periodic->attribute = 0x04;
		packet_mod_periodic->value = phase;

		ret = t300rs_send_int(t300rs);
		if (ret) {
			hid_err(t300rs->hdev, "failed modifying periodic phase\n");
			goto error;
		}

	}

	if (periodic.period != periodic_old.period) {
		int16_t period = periodic.period;

		t300rs_fill_header(&packet_mod_periodic->header, effect.id, 0x0e);
		packet_mod_periodic->attribute = 0x08;
		packet_mod_periodic->value = period;

		ret = t300rs_send_int(t300rs);
		if (ret) {
			hid_err(t300rs->hdev, "failed modifying periodic period\n");
			goto error;
		}

	}

	ret = t300rs_modify_envelope(t300rs,
			state,
			level,
			effect.replay.length,
			effect.id,
			periodic.envelope,
			periodic_old.envelope
			);

	if (ret) {
		hid_err(t300rs->hdev, "failed modifying periodic envelope\n");
		goto error;
	}

	ret = t300rs_modify_duration(t300rs, state);
	if (ret) {
		hid_err(t300rs->hdev, "failed modifying periodic duration\n");
		goto error;
	}

error:
	return ret;
}

static int t300rs_upload_constant(struct t300rs_device_entry *t300rs,
		struct t300rs_effect_state *state)
{
	struct ff_effect effect = state->effect;
	struct ff_constant_effect constant = state->effect.u.constant;
	struct __packed t300rs_packet_constant {
		struct t300rs_packet_header header;
		uint16_t level;
		struct t300rs_packet_envelope envelope;
		struct t300rs_packet_timing timing;
	} *packet_constant = (struct t300rs_packet_constant *)t300rs->send_buffer;

	int16_t level;
	uint16_t duration, offset;

	int ret;

	/* some games, such as DiRT Rally 2 have a weird feeling to them, sort of
	 * like the wheel pulls just a bit to the right or left and then it just
	 * stops. I wouldn't be surprised if it's got something to do with the
	 * constant envelope, but right now I don't know.
	 */

	if (test_bit(FF_EFFECT_PLAYING, &state->flags)
		&& test_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags)) {

		__clear_bit(FF_EFFECT_QUEUE_UPLOAD, &state->flags);

		return t300rs_modify_constant(t300rs, state);
	}

	level = (constant.level * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff;
	duration = effect.replay.length - 1;

	offset = effect.replay.delay;

	t300rs_fill_header(&packet_constant->header, effect.id, 0x6a);

	packet_constant->level = cpu_to_le16(level);

	t300rs_fill_envelope(&packet_constant->envelope, level, duration,
			&constant.envelope);
	t300rs_fill_timing(&packet_constant->timing, duration, offset);

	ret = t300rs_send_int(t300rs);
	if (ret)
		hid_err(t300rs->hdev, "failed uploading constant effect\n");

	return ret;
}

static int t300rs_upload_ramp(struct t300rs_device_entry *t300rs,
		struct t300rs_effect_state *state)
{
	struct ff_effect effect = state->effect;
	struct ff_ramp_effect ramp = state->effect.u.ramp;
	struct __packed t300rs_packet_ramp {
		struct t300rs_packet_header header;
		uint16_t difference;
		uint16_t level;
		uint16_t duration;
		uint8_t marker;
		uint8_t direction;
		struct t300rs_packet_envelope envelope;
		struct t300rs_packet_timing timing;
	} *packet_ramp = (struct t300rs_packet_ramp *)t300rs->send_buffer;

	int ret;
	uint16_t difference, offset, top, bottom, duration;
	int16_t level;

	if (test_bit(FF_EFFECT_PLAYING, &state->flags)
		&& test_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags)) {

		__clear_bit(FF_EFFECT_QUEUE_UPLOAD, &state->flags);

		return t300rs_modify_ramp(t300rs, state);
	}

	duration = effect.replay.length - 1;

	top = ramp.end_level > ramp.start_level ? ramp.end_level : ramp.start_level;
	bottom = ramp.end_level > ramp.start_level ? ramp.start_level : ramp.end_level;


	difference = ((top - bottom) * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff;
	level = (top * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff;
	offset = effect.replay.delay;


	t300rs_fill_header(&packet_ramp->header, effect.id, 0x6b);

	packet_ramp->difference = cpu_to_le16(difference);
	packet_ramp->level = cpu_to_le16(level);
	packet_ramp->duration = cpu_to_le16(duration);

	packet_ramp->marker = 0x80;

	t300rs_fill_envelope(&packet_ramp->envelope, level, duration,
			&ramp.envelope);

	packet_ramp->direction = ramp.end_level > ramp.start_level ? 0x04 : 0x05;
	t300rs_fill_timing(&packet_ramp->timing, duration, offset);

	ret = t300rs_send_int(t300rs);
	if (ret)
		hid_err(t300rs->hdev, "failed uploading ramp");

	return ret;
}

static int t300rs_upload_spring(struct t300rs_device_entry *t300rs,
		struct t300rs_effect_state *state)
{
	struct ff_effect effect = state->effect;
	/* we only care about the first axis */
	struct ff_condition_effect spring = state->effect.u.condition[0];
	struct __packed t300rs_packet_spring {
		struct t300rs_packet_header header;
		uint16_t right_coeff;
		uint16_t left_coeff;
		uint16_t right_deadband;
		uint16_t left_deadband;
		uint8_t spring_start[17];
		struct t300rs_packet_envelope envelope;
		struct t300rs_packet_timing timing;
	} *packet_spring = (struct t300rs_packet_spring *)t300rs->send_buffer;

	int ret;
	uint16_t duration, right_coeff, left_coeff, right_deadband, left_deadband, offset;

	if (test_bit(FF_EFFECT_PLAYING, &state->flags)
		&& test_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags)) {

		__clear_bit(FF_EFFECT_QUEUE_UPLOAD, &state->flags);

		return t300rs_modify_damper(t300rs, state);
	}

	duration = effect.replay.length - 1;

	right_coeff = spring.right_coeff * spring_level / 100;
	left_coeff = spring.left_coeff * spring_level / 100;

	right_deadband = 0xfffe - spring.deadband - spring.center;
	left_deadband = 0xfffe - spring.deadband + spring.center;

	offset = effect.replay.delay;

	t300rs_fill_header(&packet_spring->header, effect.id, 0x64);

	packet_spring->right_coeff = right_coeff;
	packet_spring->left_coeff = left_coeff;
	packet_spring->right_deadband = right_deadband;
	packet_spring->left_deadband = left_deadband;

	memcpy(&packet_spring->spring_start, spring_values, ARRAY_SIZE(spring_values));
	t300rs_fill_timing(&packet_spring->timing, duration, offset);

	ret = t300rs_send_int(t300rs);
	if (ret)
		hid_err(t300rs->hdev, "failed uploading spring\n");

	return ret;
}

static int t300rs_upload_damper(struct t300rs_device_entry *t300rs,
		struct t300rs_effect_state *state)
{

	struct ff_effect effect = state->effect;
	/* we only care about the first axis */
	struct ff_condition_effect spring = state->effect.u.condition[0];
	struct __packed t300rs_packet_damper {
		struct t300rs_packet_header header;
		uint16_t right_coeff;
		uint16_t left_coeff;
		uint16_t right_deadband;
		uint16_t left_deadband;
		/* space for spring const */
		uint8_t damper_start[17];
		struct t300rs_packet_envelope envelope;
		struct t300rs_packet_timing timing;
	} *packet_damper = (struct t300rs_packet_damper *)t300rs->send_buffer;

	int ret, input_level;
	uint16_t duration, right_coeff, left_coeff, right_deadband, left_deadband, offset;

	if (test_bit(FF_EFFECT_PLAYING, &state->flags)	&&
			test_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags)) {

		__clear_bit(FF_EFFECT_QUEUE_UPLOAD, &state->flags);

		return t300rs_modify_damper(t300rs, state);
	}

	duration = effect.replay.length - 1;

	input_level = damper_level;
	if (state->effect.type == FF_FRICTION)
		input_level = friction_level;

	right_coeff = spring.right_coeff * input_level / 100;
	left_coeff = spring.left_coeff * input_level / 100;

	right_deadband = 0xfffe - spring.deadband - spring.center;
	left_deadband = 0xfffe - spring.deadband + spring.center;

	offset = effect.replay.delay;

	t300rs_fill_header(&packet_damper->header, effect.id, 0x64);

	packet_damper->right_coeff = right_coeff;
	packet_damper->left_coeff = left_coeff;
	packet_damper->right_deadband = right_deadband;
	packet_damper->left_deadband = left_deadband;

	memcpy(&packet_damper->damper_start, damper_values, ARRAY_SIZE(damper_values));
	t300rs_fill_timing(&packet_damper->timing, duration, offset);

	ret = t300rs_send_int(t300rs);
	if (ret)
		hid_err(t300rs->hdev, "failed uploading spring\n");

	return ret;
}

static int t300rs_upload_periodic(struct t300rs_device_entry *t300rs,
		struct t300rs_effect_state *state)
{
	struct ff_effect effect = state->effect;
	struct ff_periodic_effect periodic = state->effect.u.periodic;
	struct __packed t300rs_packet_periodic {
		struct t300rs_packet_header header;
		uint16_t magnitude;
		uint16_t periodic_offset;
		uint16_t phase;
		uint16_t period;
padding : 8;
	  	uint8_t marker;
		struct t300rs_packet_envelope envelope;
		uint8_t waveform;
		struct t300rs_packet_timing timing;
	} *packet_periodic = (struct t300rs_packet_periodic *)t300rs->send_buffer;

	int ret;
	uint16_t duration, magnitude, phase, period, offset;
	int16_t periodic_offset;

	if (test_bit(FF_EFFECT_PLAYING, &state->flags)	&&
			test_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags)) {

		__clear_bit(FF_EFFECT_QUEUE_UPLOAD, &state->flags);

		return t300rs_modify_periodic(t300rs, state);
	}

	duration = effect.replay.length - 1;

	magnitude = (periodic.magnitude * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff;

	phase = periodic.phase;
	periodic_offset = periodic.offset;
	period = periodic.period;
	offset = effect.replay.delay;

	t300rs_fill_header(&packet_periodic->header, effect.id, 0x6b);

	packet_periodic->magnitude = magnitude;
	packet_periodic->periodic_offset = periodic_offset;
	packet_periodic->phase = phase;
	packet_periodic->period = period;

	packet_periodic->marker = 0x80;

	t300rs_fill_envelope(&packet_periodic->envelope, magnitude, duration,
			&periodic.envelope);

	packet_periodic->waveform = periodic.waveform - 0x57;

	t300rs_fill_timing(&packet_periodic->timing, duration, offset);

	ret = t300rs_send_int(t300rs);
	if (ret)
		hid_err(t300rs->hdev, "failed uploading periodic effect");

	return ret;
}

static int t300rs_upload_effect(struct t300rs_device_entry *t300rs,
		struct t300rs_effect_state *state)
{
	switch (state->effect.type) {
		case FF_CONSTANT:
			return t300rs_upload_constant(t300rs, state);
		case FF_RAMP:
			return t300rs_upload_ramp(t300rs, state);
		case FF_SPRING:
			return t300rs_upload_spring(t300rs, state);
		case FF_DAMPER:
		case FF_FRICTION:
		case FF_INERTIA:
			return t300rs_upload_damper(t300rs, state);
		case FF_PERIODIC:
			return t300rs_upload_periodic(t300rs, state);
		default:
			hid_err(t300rs->hdev, "invalid effect type: %x", state->effect.type);
			return -1;
	}
}

static int t300rs_timer_helper(struct t300rs_device_entry *t300rs)
{
	struct t300rs_effect_state *state;
	unsigned long jiffies_now = JIFFIES2MS(jiffies);
	int max_count = 0, effect_id, ret;

	for (effect_id = 0; effect_id < T300RS_MAX_EFFECTS; ++effect_id) {

		state = &t300rs->states[effect_id];

		if (test_bit(FF_EFFECT_PLAYING, &state->flags) && state->effect.replay.length) {
			if ((jiffies_now - state->start_time) >= state->effect.replay.length) {
				__clear_bit(FF_EFFECT_PLAYING, &state->flags);

				/* lazy bum fix? */
				__clear_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags);

				if (state->count)
					state->count--;

				if (state->count)
					__set_bit(FF_EFFECT_QUEUE_START, &state->flags);
			}
		}

		if (test_bit(FF_EFFECT_QUEUE_UPLOAD, &state->flags)) {
			__clear_bit(FF_EFFECT_QUEUE_UPLOAD, &state->flags);

			ret = t300rs_upload_effect(t300rs, state);
			if (ret) {
				hid_err(t300rs->hdev, "failed uploading effects");
				return ret;
			}
		}

		if (test_bit(FF_EFFECT_QUEUE_START, &state->flags)) {
			__clear_bit(FF_EFFECT_QUEUE_START, &state->flags);
			__set_bit(FF_EFFECT_PLAYING, &state->flags);

			ret = t300rs_play_effect(t300rs, state);
			if (ret) {
				hid_err(t300rs->hdev, "failed starting effects\n");
				return ret;
			}

		}

		if (test_bit(FF_EFFECT_QUEUE_STOP, &state->flags)) {
			__clear_bit(FF_EFFECT_QUEUE_STOP, &state->flags);
			__clear_bit(FF_EFFECT_PLAYING, &state->flags);

			ret = t300rs_stop_effect(t300rs, state);
			if (ret) {
				hid_err(t300rs->hdev, "failed stopping effect\n");
				return ret;
			}
		}

		if (state->count > max_count)
			max_count = state->count;
	}

	return max_count;
}

static enum hrtimer_restart t300rs_timer(struct hrtimer *t)
{
	struct t300rs_device_entry *t300rs = container_of(t, struct t300rs_device_entry, hrtimer);
	int max_count;

	max_count = t300rs_timer_helper(t300rs);

	if (max_count > 0) {
		hrtimer_forward_now(&t300rs->hrtimer, ms_to_ktime(timer_msecs));
		return HRTIMER_RESTART;
	} else {
		return HRTIMER_NORESTART;
	}
}

static int t300rs_upload(struct input_dev *dev,
		struct ff_effect *effect, struct ff_effect *old)
{
	struct hid_device *hdev = input_get_drvdata(dev);
	struct t300rs_device_entry *t300rs;
	struct t300rs_effect_state *state;

	t300rs = t300rs_get_device(hdev);
	if (!t300rs) {
		hid_err(hdev, "could not get device\n");
		return -1;
	}

	if (effect->type == FF_PERIODIC && effect->u.periodic.period == 0)
		return -EINVAL;

	state = &t300rs->states[effect->id];

	spin_lock_irqsave(&t300rs->lock, t300rs->lock_flags);

	state->effect = *effect;

	if (old) {
		state->old = *old;
		__set_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags);
	} else {
		__clear_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags);
	}
	__set_bit(FF_EFFECT_QUEUE_UPLOAD, &state->flags);

	spin_unlock_irqrestore(&t300rs->lock, t300rs->lock_flags);

	return 0;
}

static int t300rs_play(struct input_dev *dev, int effect_id, int value)
{
	struct hid_device *hdev = input_get_drvdata(dev);
	struct t300rs_device_entry *t300rs;
	struct t300rs_effect_state *state;

	t300rs = t300rs_get_device(hdev);
	if (!t300rs) {
		hid_err(hdev, "could not get device\n");
		return -1;
	}

	state = &t300rs->states[effect_id];

	if (&state->effect == 0)
		return 0;

	spin_lock_irqsave(&t300rs->lock, t300rs->lock_flags);

	if (value > 0) {
		state->count = value;
		state->start_time = JIFFIES2MS(jiffies);
		__set_bit(FF_EFFECT_QUEUE_START, &state->flags);

		if (test_bit(FF_EFFECT_QUEUE_STOP, &state->flags))
			__clear_bit(FF_EFFECT_QUEUE_STOP, &state->flags);

	} else {
		__set_bit(FF_EFFECT_QUEUE_STOP, &state->flags);
	}

	if (!hrtimer_active(&t300rs->hrtimer))
		hrtimer_start(&t300rs->hrtimer, ms_to_ktime(timer_msecs), HRTIMER_MODE_REL);

	spin_unlock_irqrestore(&t300rs->lock, t300rs->lock_flags);
	return 0;
}

static ssize_t spring_level_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	struct hid_device *hdev = to_hid_device(dev);
	unsigned int value;
	int ret;

	ret = kstrtouint(buf, 0, &value);
	if (ret) {
		hid_err(hdev, "kstrtouint failed at spring_level_store: %i", ret);
		return ret;
	}

	if (value > 100)
		value = 100;

	spring_level = value;

	return count;
}
static ssize_t spring_level_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	size_t count;

	count = scnprintf(buf, PAGE_SIZE, "%u\n", spring_level);

	return count;
}

static DEVICE_ATTR_RW(spring_level);

static ssize_t damper_level_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	struct hid_device *hdev = to_hid_device(dev);
	unsigned int value;
	int ret;

	ret = kstrtouint(buf, 0, &value);
	if (ret) {
		hid_err(hdev, "kstrtouint failed at damper_level_store: %i", ret);
		return ret;
	}

	if (value > 100)
		value = 100;

	damper_level = value;

	return count;
}

static ssize_t damper_level_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	size_t count;

	count = scnprintf(buf, PAGE_SIZE, "%u\n", damper_level);

	return count;
}

static DEVICE_ATTR_RW(damper_level);

static ssize_t friction_level_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	struct hid_device *hdev = to_hid_device(dev);
	unsigned int value;
	int ret;

	ret = kstrtouint(buf, 0, &value);
	if (ret) {
		hid_err(hdev, "kstrtouint failed at friction_level_store: %i", ret);
		return ret;
	}

	if (value > 100)
		value = 100;

	friction_level = value;

	return count;
}
static ssize_t friction_level_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	size_t count;

	count = scnprintf(buf, PAGE_SIZE, "%u\n", friction_level);

	return count;
}

static DEVICE_ATTR_RW(friction_level);

static ssize_t range_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	struct hid_device *hdev = to_hid_device(dev);
	struct t300rs_device_entry *t300rs;
	struct __packed t300rs_packet_range {
		struct t300rs_setup_header header;
		uint16_t range;
	} *packet_range;

	unsigned int range;
	int ret;

	ret = kstrtouint(buf, 0, &range);
	if (ret) {
		hid_err(hdev, "kstrtouint failed at range_store: %i", ret);
		return ret;
	}

	t300rs = t300rs_get_device(hdev);
	if (!t300rs) {
		hid_err(hdev, "could not get device\n");
		return -1;
	}

	packet_range = (struct t300rs_packet_range *)t300rs->send_buffer;

	if (range < 40)
		range = 40;

	if (range > 1080)
		range = 1080;

	range *= 0x3c;


	packet_range->header.cmd = 0x08;
	packet_range->header.code = 0x11;

	packet_range->range = cpu_to_le16(range);

	ret = t300rs_send_int(t300rs);
	if (ret) {
		hid_err(hdev, "failed sending interrupts\n");
		return -1;
	}

	t300rs->range = range / 0x3c;

	return count;
}

static ssize_t range_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct hid_device *hdev = to_hid_device(dev);
	struct t300rs_device_entry *t300rs;
	size_t count = 0;

	t300rs = t300rs_get_device(hdev);
	if (!t300rs) {
		hid_err(hdev, "could not get device\n");
		return -1;
	}

	count = scnprintf(buf, PAGE_SIZE, "%u\n", t300rs->range);
	return count;
}

static DEVICE_ATTR_RW(range);

static void t300rs_set_autocenter(struct input_dev *dev, uint16_t value)
{
	struct hid_device *hdev = input_get_drvdata(dev);
	struct t300rs_device_entry *t300rs;
	struct __packed t300rs_packet_autocenter {
		struct t300rs_setup_header header;
		uint16_t value;
	} *autocenter_packet;

	int ret;

	t300rs = t300rs_get_device(hdev);
	if (!t300rs) {
		hid_err(hdev, "could not get device\n");
		return;
	}

	autocenter_packet = (struct t300rs_packet_autocenter *)t300rs->send_buffer;

	autocenter_packet->header.cmd = 0x08;
	autocenter_packet->header.code = 0x04;
	autocenter_packet->value = cpu_to_le16(0x01);

	ret = t300rs_send_int(t300rs);
	if (ret) {
		hid_err(hdev, "failed setting autocenter");
		return;
	}

	autocenter_packet->header.cmd = 0x08;
	autocenter_packet->header.code = 0x03;

	autocenter_packet->value = cpu_to_le16(value);

	ret = t300rs_send_int(t300rs);
	if (ret)
		hid_err(hdev, "failed setting autocenter");
}

static void t300rs_set_gain(struct input_dev *dev, uint16_t gain)
{
	struct hid_device *hdev = input_get_drvdata(dev);
	struct t300rs_device_entry *t300rs;
	struct __packed t300rs_packet_gain {
		struct t300rs_setup_header header;
	} *gain_packet;

	int ret;

	t300rs = t300rs_get_device(hdev);
	if (!t300rs) {
		hid_err(hdev, "could not get device\n");
		return;
	}

	gain_packet = (struct t300rs_packet_gain *)t300rs->send_buffer;

	gain_packet->header.cmd = 0x02;
	gain_packet->header.code = (gain >> 8) & 0xff;

	ret = t300rs_send_int(t300rs);
	if (ret)
		hid_err(hdev, "failed setting gain: %i\n", ret);
}

static void t300rs_destroy(struct ff_device *ff)
{
	// maybe not necessary?
}

static int t300rs_open(struct input_dev *dev)
{
	struct t300rs_device_entry *t300rs;
	struct hid_device *hdev = input_get_drvdata(dev);
	struct __packed t300rs_packet_open {
		struct t300rs_setup_header header;
	} *open_packet;

	int ret;

	t300rs = t300rs_get_device(hdev);
	if (!t300rs) {
		hid_err(hdev, "could not get device\n");
		return -1;
	}

	open_packet = (struct t300rs_packet_open *)t300rs->send_buffer;

	open_packet->header.cmd = 0x01;
	open_packet->header.code = 0x05;

	ret = t300rs_send_int(t300rs);
	if (ret) {
		hid_err(hdev, "failed sending interrupts\n");
		goto err;
	}

err:
	return t300rs->open(dev);
}

static void t300rs_close(struct input_dev *dev)
{
	struct t300rs_device_entry *t300rs;
	struct hid_device *hdev = input_get_drvdata(dev);
	struct t300rs_packet_close {
		struct t300rs_setup_header header;
	} *close_packet;

	int ret;

	t300rs = t300rs_get_device(hdev);
	if (!t300rs) {
		hid_err(hdev, "could not get device\n");
		return;
	}

	close_packet = (struct t300rs_packet_close *)t300rs->send_buffer;

	close_packet->header.cmd = 0x01;

	ret = t300rs_send_int(t300rs);
	if (ret) {
		hid_err(hdev, "failed sending interrupts\n");
		goto err;
	}
err:
	t300rs->close(dev);
}

static int t300rs_create_files(struct hid_device *hdev)
{
	int ret;

	ret = device_create_file(&hdev->dev, &dev_attr_range);
	if (ret) {
		hid_warn(hdev, "unable to create sysfs interface for range\n");
		goto attr_range_err;
	}

	ret = device_create_file(&hdev->dev, &dev_attr_spring_level);
	if (ret) {
		hid_warn(hdev, "unable to create sysfs interface for spring_level\n");
		goto attr_spring_err;
	}

	ret = device_create_file(&hdev->dev, &dev_attr_damper_level);
	if (ret) {
		hid_warn(hdev, "unable to create sysfs interface for damper_level\n");
		goto attr_damper_err;
	}

	ret = device_create_file(&hdev->dev, &dev_attr_friction_level);
	if (ret) {
		hid_warn(hdev, "unable to create sysfs interface for friction_level\n");
		goto attr_friction_err;
	}

	return ret;

	// if the creation of dev_attr_friction fails, we don't need to remove it
	// device_remove_file(&hdev->dev, &dev_attr_friction_level);
attr_friction_err:
	device_remove_file(&hdev->dev, &dev_attr_damper_level);
attr_damper_err:
	device_remove_file(&hdev->dev, &dev_attr_spring_level);
attr_spring_err:
	device_remove_file(&hdev->dev, &dev_attr_range);
attr_range_err:
	return ret;
}

static int t300rs_init(struct hid_device *hdev, const signed short *ff_bits)
{
	struct t300rs_device_entry *t300rs;
	struct t300rs_data *drv_data;
	struct list_head *report_list;
	struct hid_input *hidinput = list_entry(hdev->inputs.next,
			struct hid_input, list);
	struct input_dev *input_dev = hidinput->input;
	struct device *dev = &hdev->dev;
	struct usb_interface *usbif = to_usb_interface(dev->parent);
	struct usb_device *usbdev = interface_to_usbdev(usbif);
	struct ff_device *ff;
	char range[10] = "900"; // max
	int i, ret;

	drv_data = hid_get_drvdata(hdev);
	if (!drv_data) {
		hid_err(hdev, "private driver data not allocated\n");
		ret = -ENOMEM;
		goto drvdata_err;
	}

	t300rs = kzalloc(sizeof(struct t300rs_device_entry), GFP_KERNEL);
	if (!t300rs) {
		ret = -ENOMEM;
		goto t300rs_err;
	}

	t300rs->input_dev = input_dev;
	t300rs->hdev = hdev;
	t300rs->usbdev = usbdev;
	t300rs->usbif = usbif;

	t300rs->states = kzalloc(
			sizeof(struct t300rs_effect_state) * T300RS_MAX_EFFECTS, GFP_KERNEL);

	if (!t300rs->states) {
		ret = -ENOMEM;
		goto states_err;
	}

	t300rs->send_buffer = kzalloc(T300RS_BUFFER_LENGTH, GFP_KERNEL);
	if (!t300rs->send_buffer) {
		ret = -ENOMEM;
		goto send_err;
	}

	t300rs->firmware_response = kzalloc(sizeof(struct t300rs_firmware_response), GFP_KERNEL);
	if (!t300rs->firmware_response) {
		ret = -ENOMEM;
		goto firmware_err;
	}

	// Check firmware version
	ret = usb_control_msg(t300rs->usbdev,
			usb_rcvctrlpipe(t300rs->usbdev, 0),
			t300rs_firmware_request.bRequest,
			t300rs_firmware_request.bRequestType,
			t300rs_firmware_request.wValue,
			t300rs_firmware_request.wIndex,
			t300rs->firmware_response,
			t300rs_firmware_request.wLength,
			USB_CTRL_SET_TIMEOUT
			);

	// Educated guess
	if (t300rs->firmware_response->firmware_version < 31 && ret >= 0) {
		hid_err(t300rs->hdev,
				"firmware version %i is too old, please update.",
				t300rs->firmware_response->firmware_version
		       );

		hid_info(t300rs->hdev, "note: this has to be done through Windows.");

		ret = -EINVAL;
		goto version_err;
	}

	spin_lock_init(&t300rs->lock);

	drv_data->device_props = t300rs;

	report_list = &hdev->report_enum[HID_OUTPUT_REPORT].report_list;

	// because we set the rdesc, we know exactly which report and field to use
	t300rs->report = list_entry(report_list->next, struct hid_report, list);
	t300rs->ff_field = t300rs->report->field[0];

	// set ff capabilities
	for (i = 0; ff_bits[i] >= 0; ++i)
		__set_bit(ff_bits[i], input_dev->ffbit);

	ret = input_ff_create(input_dev, T300RS_MAX_EFFECTS);
	if (ret) {
		hid_err(hdev, "could not create input_ff\n");
		goto input_ff_err;
	}

	ff = input_dev->ff;
	ff->upload = t300rs_upload;
	ff->playback = t300rs_play;
	ff->set_gain = t300rs_set_gain;
	ff->set_autocenter = t300rs_set_autocenter;
	ff->destroy = t300rs_destroy;

	t300rs->open = input_dev->open;
	t300rs->close = input_dev->close;

	input_dev->open = t300rs_open;
	input_dev->close = t300rs_close;

	ret = t300rs_create_files(hdev);
	if (ret) {
		// this might not be a catastrophic issue, but it could affect
		// programs such as oversteer, best play it safe
		hid_err(hdev, "could not create sysfs files\n");
		goto sysfs_err;
	}


	hrtimer_init(&t300rs->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
	t300rs->hrtimer.function = t300rs_timer;

	range_store(dev, &dev_attr_range, range, 10);
	t300rs_set_gain(input_dev, 0xffff);

	hid_info(hdev, "force feedback for T300RS\n");
	return 0;

sysfs_err:
	kfree(t300rs->firmware_response);

input_ff_err:
version_err:
firmware_err:
	kfree(t300rs->send_buffer);

send_err:
	kfree(t300rs->states);

states_err:
	kfree(t300rs);

t300rs_err:
	kfree(drv_data);

drvdata_err:
	hid_err(hdev, "failed creating force feedback device\n");

	return ret;

}

static int t300rs_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
	int ret;
	struct t300rs_data *drv_data;

	spin_lock_init(&lock);

	drv_data = kzalloc(sizeof(struct t300rs_data), GFP_KERNEL);
	if (!drv_data) {
		ret = -ENOMEM;
		goto err;
	}

	drv_data->quirks = id->driver_data;
	hid_set_drvdata(hdev, (void *)drv_data);

	ret = hid_parse(hdev);
	if (ret) {
		hid_err(hdev, "parse failed\n");
		goto err;
	}

	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
	if (ret) {
		hid_err(hdev, "hw start failed\n");
		goto err;
	}

	ret = t300rs_init(hdev, (void *)id->driver_data);
	if (ret) {
		hid_err(hdev, "t300rs_init failed\n");
		goto err;
	}

err:
	return ret;
}

static void t300rs_remove(struct hid_device *hdev)
{
	struct t300rs_device_entry *t300rs;
	struct t300rs_data *drv_data;

	drv_data = hid_get_drvdata(hdev);
	t300rs = t300rs_get_device(hdev);
	if (!t300rs) {
		hid_err(hdev, "could not get device\n");
		return;
	}

	hrtimer_cancel(&t300rs->hrtimer);

	device_remove_file(&hdev->dev, &dev_attr_range);
	device_remove_file(&hdev->dev, &dev_attr_spring_level);
	device_remove_file(&hdev->dev, &dev_attr_damper_level);
	device_remove_file(&hdev->dev, &dev_attr_friction_level);

	hid_hw_stop(hdev);
	kfree(t300rs->states);
	kfree(t300rs->send_buffer);
	kfree(t300rs->firmware_response);
	kfree(t300rs);
	kfree(drv_data);
}

static __u8 *t300rs_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize)
{
	rdesc = t300rs_rdesc_fixed;
	*rsize = sizeof(t300rs_rdesc_fixed);
	return rdesc;
}

static const struct hid_device_id t300rs_devices[] = {
	{HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb66e),
		.driver_data = (unsigned long)t300rs_ff_effects},
	{}
};
MODULE_DEVICE_TABLE(hid, t300rs_devices);

static struct hid_driver t300rs_driver = {
	.name = "t300rs",
	.id_table = t300rs_devices,
	.probe = t300rs_probe,
	.remove = t300rs_remove,
	.report_fixup = t300rs_report_fixup,
};
module_hid_driver(t300rs_driver);

MODULE_LICENSE("GPL");
