// SPDX-License-Identifier: GPL-2.0-or-later
#include <linux/workqueue.h>
#include <linux/module.h>
#include <linux/hid.h>
#include <linux/version.h>
#include "hid-tmff2.h"


int open_mode = 1;
module_param(open_mode, int, 0660);
MODULE_PARM_DESC(open_mode,
		"Whether to send mode change commands on open/close");

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

/* should these be removed and just rely on /sys? */
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");

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");

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");

int range = 900;
module_param(range, int, 0);
MODULE_PARM_DESC(range,
		"Range of wheel, depends on the wheel. Invalid values are ignored");

int alt_mode = 0;
module_param(alt_mode, int, 0);
MODULE_PARM_DESC(alt_mode,
		"Alternate mode, eg. F1 mode");

#define GAIN_MAX 65535
int gain = 40000;
module_param(gain, int, 0);
MODULE_PARM_DESC(gain,
		"Level of gain (0-65535)");

static spinlock_t lock;

static struct tmff2_device_entry *tmff2_from_hdev(struct hid_device *hdev)
{
	unsigned long lock_flags = 0;
	struct tmff2_device_entry *tmff2;
	spin_lock_irqsave(&lock, lock_flags);

	if (!(tmff2 = hid_get_drvdata(hdev)))
		dev_err(&hdev->dev, "hdev private data not found\n");

	spin_unlock_irqrestore(&lock, lock_flags);

	return tmff2;
}

static struct tmff2_device_entry *tmff2_from_input(struct input_dev *input_dev)
{
	unsigned long lock_flags = 0;
	struct hid_device *hdev;
	spin_lock_irqsave(&lock, lock_flags);

	if (!(hdev = input_get_drvdata(input_dev)))
		dev_err(&input_dev->dev, "input_dev private data not found\n");

	spin_unlock_irqrestore(&lock, lock_flags);

	return tmff2_from_hdev(hdev);
}

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

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

	if (value > 100) {
		dev_info(dev, "value %i larger than max 100, clamping to 100.\n", value);
		value = 100;
	}

	spring_level = value;

	return count;
}

static ssize_t spring_level_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	return scnprintf(buf, PAGE_SIZE, "%u\n", spring_level);
}
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)
{
	unsigned int value;
	int ret;


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

	if (value > 100) {
		dev_info(dev, "value %i larger than max 100, clamping to 100.\n", value);
		value = 100;
	}

	damper_level = value;

	return count;
}

static ssize_t damper_level_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	return scnprintf(buf, PAGE_SIZE, "%u\n", damper_level);
}
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)
{
	unsigned int value;
	int ret;


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

	if (value > 100) {
		dev_info(dev, "value %i larger than max 100, clamping to 100.\n", value);
		value = 100;
	}

	friction_level = value;

	return count;
}

static ssize_t friction_level_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	return scnprintf(buf, PAGE_SIZE, "%u\n", friction_level);
}
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 tmff2_device_entry *tmff2 = tmff2_from_hdev(to_hid_device(dev));
	unsigned int value;
	int ret;

	if (!tmff2)
		return -ENODEV;

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

	if (tmff2->set_range) {
		if ((ret = tmff2->set_range(tmff2->data, value)))
			return ret;
	}

	return count;
}

static ssize_t range_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	return scnprintf(buf, PAGE_SIZE, "%u\n", range);
}
static DEVICE_ATTR_RW(range);

static ssize_t alternate_modes_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	struct tmff2_device_entry *tmff2 = tmff2_from_hdev(to_hid_device(dev));

	if (!tmff2)
		return -ENODEV;

	if (tmff2->alt_mode_store)
		return tmff2->alt_mode_store(tmff2->data, buf, count);

	return 0;
}

static ssize_t alternate_modes_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct tmff2_device_entry *tmff2 = tmff2_from_hdev(to_hid_device(dev));

	if (!tmff2)
		return -ENODEV;

	if (tmff2->alt_mode_show)
		return tmff2->alt_mode_show(tmff2->data, buf);

	return 0;
}
static DEVICE_ATTR_RW(alternate_modes);

static ssize_t gain_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	struct tmff2_device_entry *tmff2 = tmff2_from_hdev(to_hid_device(dev));
	unsigned int value;
	int ret;

	if (!tmff2)
		return -ENODEV;

	if ((ret = kstrtouint(buf, 0, &value))) {
		dev_err(dev, "kstrtouint failed at gain_store: %i", ret);
		return ret;
	}

	gain = value;
	if (tmff2->set_gain) /* if we can, update gain immediately */
		tmff2->set_gain(tmff2->data, (GAIN_MAX * gain) / GAIN_MAX);

	return count;
}

static ssize_t gain_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	return scnprintf(buf, PAGE_SIZE, "%i\n", gain);
}
static DEVICE_ATTR_RW(gain);

static void tmff2_set_gain(struct input_dev *dev, uint16_t value)
{
	struct tmff2_device_entry *tmff2 = tmff2_from_input(dev);

	if (!tmff2)
		return;

	if (!tmff2->set_gain) {
		hid_err(tmff2->hdev, "missing set_gain\n");
		return;
	}

	if (tmff2->set_gain(tmff2->data, (value * gain) / GAIN_MAX))
		hid_warn(tmff2->hdev, "unable to set gain\n");
}

static void tmff2_set_autocenter(struct input_dev *dev, uint16_t value)
{
	struct tmff2_device_entry *tmff2 = tmff2_from_input(dev);

	if (!tmff2)
		return;

	if (!tmff2->set_autocenter) {
		hid_err(tmff2->hdev, "missing set_autocenter\n");
		return;
	}

	if (tmff2->set_autocenter(tmff2->data, value))
		hid_warn(tmff2->hdev, "unable to set autocenter\n");
}

static void tmff2_work_handler(struct work_struct *w)
{
	unsigned long lock_flags = 0;
	struct delayed_work *dw = container_of(w, struct delayed_work, work);
	struct tmff2_device_entry *tmff2 = container_of(dw, struct tmff2_device_entry, work);
	struct tmff2_effect_state *state;
	int max_count = 0, effect_id;
	unsigned long time_now;
	__u16 effect_delay, effect_length;


	if (!tmff2)
		return;

	for (effect_id = 0; effect_id < tmff2->max_effects; ++effect_id) {
		unsigned long actions = 0;
		struct tmff2_effect_state effect;

		time_now = JIFFIES2MS(jiffies);

		state = &tmff2->states[effect_id];

		/* critical section for updating state flags, keep log of what
		 * actions to take after the critical section with actions */
		spin_lock_irqsave(&tmff2->lock, lock_flags);

		effect_delay = state->effect.replay.delay;
		effect_length = state->effect.replay.length;
		if (test_bit(FF_EFFECT_PLAYING, &state->flags) && effect_length) {
			if ((time_now - state->start_time) >=
					(effect_delay + effect_length) * state->count) {
				__clear_bit(FF_EFFECT_PLAYING, &state->flags);
				__clear_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags);

				state->count = 0;
			}
		}

		if (test_bit(FF_EFFECT_QUEUE_UPLOAD, &state->flags)) {
			__set_bit(FF_EFFECT_QUEUE_UPLOAD, &actions);
			__clear_bit(FF_EFFECT_QUEUE_UPLOAD, &state->flags);
			/* if we're uploading an effect, it's bound to be up
			 * to date */
			__clear_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags);
		}

		if (test_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags)) {
			__set_bit(FF_EFFECT_QUEUE_UPDATE, &actions);
			__clear_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags);
		}

		if (test_bit(FF_EFFECT_QUEUE_START, &state->flags)) {
			__set_bit(FF_EFFECT_QUEUE_START, &actions);
			__clear_bit(FF_EFFECT_QUEUE_START, &state->flags);
			/* effect is playing since we're started it right now */
			__set_bit(FF_EFFECT_PLAYING, &state->flags);
		}

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

			/* the effect can't be playing if we're stopped, aye? */
			__clear_bit(FF_EFFECT_PLAYING, &state->flags);
		}

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

		/* copy effect state to local variable so we can pass it around
		 * after the atomic section */
		effect = *state;

		spin_unlock_irqrestore(&tmff2->lock, lock_flags);

		/* perform the identified actions */
		if (test_bit(FF_EFFECT_QUEUE_UPLOAD, &actions)
				&& tmff2->upload_effect(tmff2->data, &effect)) {
			hid_warn(tmff2->hdev, "failed uploading effect\n");
		}

		if (test_bit(FF_EFFECT_QUEUE_UPDATE, &actions)
				&& tmff2->update_effect(tmff2->data, &effect)) {
			hid_warn(tmff2->hdev, "failed updating effect\n");
		}

		if (test_bit(FF_EFFECT_QUEUE_START, &actions)
				&& tmff2->play_effect(tmff2->data, &effect)) {
			hid_warn(tmff2->hdev, "failed starting effect\n");
		}

		if (test_bit(FF_EFFECT_QUEUE_STOP, &actions)
				&& tmff2->stop_effect(tmff2->data, &effect)) {
			hid_warn(tmff2->hdev, "failed stopping effect\n");
		}


		/* wait for each effect update to actually be sent out to avoid
		 * filling up usb output queue */
		hid_hw_wait(tmff2->hdev);
	}

	if (max_count && tmff2->allow_scheduling)
		schedule_delayed_work(&tmff2->work, msecs_to_jiffies(timer_msecs));
}

static void tmff2_rewrite_rumble(struct ff_effect *effect)
{
	/* this is more or less directly copied from
	 * https://elixir.bootlin.com/linux/latest/source/drivers/input/ff-core.c#L48
	 * except we set the direction to east, to make sure the direction
	 * scaling doesn't do any funny business */
	int magnitude = 0;
	if (effect->type != FF_RUMBLE)
		return;

	magnitude = effect->u.rumble.strong_magnitude / 3
		+ effect->u.rumble.weak_magnitude / 6;

	effect->type = FF_PERIODIC;
	effect->direction = 16384;
	effect->u.periodic.waveform = FF_SINE;
	effect->u.periodic.period = 50;
	effect->u.periodic.magnitude = magnitude;
	effect->u.periodic.offset = 0;
	effect->u.periodic.phase = 0;
	effect->u.periodic.envelope.attack_length = 0;
	effect->u.periodic.envelope.attack_level = 0;
	effect->u.periodic.envelope.fade_length = 0;
	effect->u.periodic.envelope.fade_level = 0;
}

static int tmff2_upload(struct input_dev *dev,
		struct ff_effect *effect, struct ff_effect *old)
{
	unsigned long lock_flags = 0;
	struct tmff2_effect_state *state;
	struct tmff2_device_entry *tmff2 = tmff2_from_input(dev);

	if (!tmff2)
		return -ENODEV;

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

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

	spin_lock_irqsave(&tmff2->lock, lock_flags);

	state->effect = *effect;
	tmff2_rewrite_rumble(&state->effect);

	if (old) {
		if (!test_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags)) {
			state->old = *old;
			tmff2_rewrite_rumble(&state->old);
		}

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

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

static int tmff2_play(struct input_dev *dev, int effect_id, int value)
{
	unsigned long lock_flags = 0;
	struct tmff2_effect_state *state;
	struct tmff2_device_entry *tmff2 = tmff2_from_input(dev);

	if (!tmff2)
		return -ENODEV;

	state = &tmff2->states[effect_id];
	if (!state)
		return 0;

	spin_lock_irqsave(&tmff2->lock, lock_flags);
	if (value > 0) {
		state->count = value;
		state->start_time = JIFFIES2MS(jiffies);
		__set_bit(FF_EFFECT_QUEUE_START, &state->flags);
		__clear_bit(FF_EFFECT_QUEUE_STOP, &state->flags);
	} else {
		__set_bit(FF_EFFECT_QUEUE_STOP, &state->flags);
		__clear_bit(FF_EFFECT_QUEUE_START, &state->flags);
	}

	spin_unlock_irqrestore(&tmff2->lock, lock_flags);

	if (!delayed_work_pending(&tmff2->work) && tmff2->allow_scheduling)
		schedule_delayed_work(&tmff2->work, 0);

	return 0;
}

static int tmff2_open(struct input_dev *dev)
{
	struct tmff2_device_entry *tmff2 = tmff2_from_input(dev);

	if (!tmff2)
		return -ENODEV;

	if (tmff2->open)
		return tmff2->open(tmff2->data, open_mode);

	hid_err(tmff2->hdev, "no open callback set\n");
	return -EINVAL;
}

static void tmff2_close(struct input_dev *dev)
{
	struct tmff2_device_entry *tmff2 = tmff2_from_input(dev);

	if (!tmff2)
		return;

	/* since we're closing the device, no need to continue feeding it new data */
	/* TODO: check somewhere that multiple users can't open us at the same
	 * time */
	cancel_delayed_work_sync(&tmff2->work);

	if (tmff2->close) {
		tmff2->close(tmff2->data, open_mode);
		return;
	}

	hid_err(tmff2->hdev, "no close callback set\n");
}

static int tmff2_create_files(struct tmff2_device_entry *tmff2)
{
	struct device *dev = &tmff2->hdev->dev;
	int ret;


	/* could use short circuiting but this is more explicit */
	if (tmff2->params & PARAM_GAIN) {
		if ((ret = device_create_file(dev, &dev_attr_gain))) {
			hid_err(tmff2->hdev, "unable to create sysfs for gain\n");
			goto gain_err;
		}
	}

	if (tmff2->params & PARAM_ALT_MODE) {
		if ((ret = device_create_file(dev, &dev_attr_alternate_modes))) {
			hid_err(tmff2->hdev, "unable to create sysfs for alternate_modes\n");
			goto alt_err;
		}
	}

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

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

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

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

	return 0;

friction_err:
	device_remove_file(dev, &dev_attr_damper_level);
damper_err:
	device_remove_file(dev, &dev_attr_spring_level);
spring_err:
	device_remove_file(dev, &dev_attr_range);
range_err:
	device_remove_file(dev, &dev_attr_alternate_modes);
alt_err:
	device_remove_file(dev, &dev_attr_gain);
gain_err:
	return ret;
}

static int tmff2_wheel_init(struct tmff2_device_entry *tmff2)
{
	int ret, i;
	struct ff_device *ff;

	spin_lock_init(&lock);
	spin_lock_init(&tmff2->lock);
	INIT_DELAYED_WORK(&tmff2->work, tmff2_work_handler);

	/* get parameters etc from backend */
	if ((ret = tmff2->wheel_init(tmff2, open_mode)))
		goto err;


	tmff2->states = kzalloc(sizeof(struct tmff2_effect_state) * tmff2->max_effects,
			GFP_KERNEL);

	if (!tmff2->states) {
		ret = -ENOMEM;
		goto err;
	}

	/* set supported effects into input_dev->ffbit */
	for (i = 0; tmff2->supported_effects[i] >= 0; ++i)
		__set_bit(tmff2->supported_effects[i], tmff2->input_dev->ffbit);

	/* tell ffb subsystem that we want to handle our own rumble effects,
	 * this is a (maybe kind of silly) workaround to the ffb subsystem
	 * setting the direction of rumble to 0, which in our case means 0
	 * force. Instead, do exactly what the subsystem would do, but update
	 * the direction.
	 *
	 * It *might* be a good idea to change this in the subsystem proper, but
	 * I don't know if anyone relies on the rumble to be 0 degrees, consider
	 * this just a proof of concept for now */
	if (test_bit(FF_PERIODIC, tmff2->input_dev->ffbit))
		__set_bit(FF_RUMBLE, tmff2->input_dev->ffbit);

	/* create actual ff device*/
	if ((ret = input_ff_create(tmff2->input_dev, tmff2->max_effects))) {
		hid_err(tmff2->hdev, "could not create input_ff\n");
		goto ff_err;
	}

	/* set ff callbacks */
	ff = tmff2->input_dev->ff;
	ff->upload = tmff2_upload;
	ff->playback = tmff2_play;

	if (tmff2->open)
		tmff2->input_dev->open = tmff2_open;

	if (tmff2->close)
		tmff2->input_dev->close = tmff2_close;

	/* set defaults wherever possible */
	if (tmff2->set_gain) {
		ff->set_gain = tmff2_set_gain;
		tmff2->set_gain(tmff2->data, (GAIN_MAX * gain) / GAIN_MAX);
	}

	if (tmff2->set_autocenter)
		ff->set_autocenter = tmff2_set_autocenter;

	if (tmff2->set_range)
		tmff2->set_range(tmff2->data, range);

	if (tmff2->switch_mode)
		tmff2->switch_mode(tmff2->data, alt_mode);

	/* create files */
	if ((ret = tmff2_create_files(tmff2)))
		goto file_err;

	tmff2->allow_scheduling = 1;
	return 0;

file_err:
	input_ff_destroy(tmff2->input_dev);
ff_err:
	kfree(tmff2->states);
err:
	return ret;
}

static int tmff2_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
	struct tmff2_device_entry *tmff2 =
		kzalloc(sizeof(struct tmff2_device_entry), GFP_KERNEL);

	int ret;


	if (!tmff2) {
		ret = -ENOMEM;
		goto oom_err;
	}

	tmff2->hdev = hdev;
	hid_set_drvdata(tmff2->hdev, tmff2);

	switch (tmff2->hdev->product) {
		case TMT300RS_PS3_NORM_ID:
		case TMT300RS_PS3_ADV_ID:
		case TMT300RS_PS4_NORM_ID:
			if ((ret = t300rs_populate_api(tmff2)))
				goto wheel_err;
			break;

		case TMT248_PC_ID:
			if ((ret = t248_populate_api(tmff2)))
				goto wheel_err;
			break;

		case TX_ACTIVE:
			if ((ret = tx_populate_api(tmff2)))
				goto wheel_err;
			break;
		case TSXW_ACTIVE:
			if ((ret = tsxw_populate_api(tmff2)))
				goto wheel_err;
			break;
			case TMTS_PC_RACER_ID:
			if ((ret = tspc_populate_api(tmff2)))
				goto wheel_err;
			break;
		default:
			ret = -ENODEV;
			goto wheel_err;
	}

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

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

	tmff2->input_dev = list_entry(hdev->inputs.next, struct hid_input, list)->input;

	if ((ret = tmff2_wheel_init(tmff2))) {
		hid_err(hdev, "init failed\n");
		goto init_err;
	}

	return 0;

init_err:
	hid_hw_stop(hdev);
hid_err:
	tmff2->wheel_destroy(tmff2->data);
wheel_err:
	kfree(tmff2);
oom_err:
	return ret;
}

#if LINUX_VERSION_CODE < KERNEL_VERSION(6,12,0)
static __u8 *tmff2_report_fixup(struct hid_device *hdev, __u8 *rdesc,
		unsigned int *rsize)
#else
static const __u8 *tmff2_report_fixup(struct hid_device *hdev, __u8 *rdesc,
		unsigned int *rsize)
#endif
{
	struct tmff2_device_entry *tmff2 = tmff2_from_hdev(hdev);

	if (!tmff2) /* not entirely sure what the best course of action would be here */
		return rdesc;

	if (tmff2->wheel_fixup)
		return tmff2->wheel_fixup(hdev, rdesc, rsize);

	return rdesc;
}

static void tmff2_remove(struct hid_device *hdev)
{
	struct tmff2_device_entry *tmff2 = tmff2_from_hdev(hdev);
	struct device *dev;

	if (!tmff2)
		return;

	tmff2->allow_scheduling = 0;
	cancel_delayed_work_sync(&tmff2->work);

	dev = &tmff2->hdev->dev;
	if (tmff2->params & PARAM_FRICTION_LEVEL)
		device_remove_file(dev, &dev_attr_friction_level);

	if (tmff2->params & PARAM_DAMPER_LEVEL)
		device_remove_file(dev, &dev_attr_damper_level);

	if (tmff2->params & PARAM_SPRING_LEVEL)
		device_remove_file(dev, &dev_attr_spring_level);

	if (tmff2->params & PARAM_RANGE)
		device_remove_file(dev, &dev_attr_range);

	if (tmff2->params & PARAM_ALT_MODE)
		device_remove_file(dev, &dev_attr_alternate_modes);

	if (tmff2->params & PARAM_GAIN)
		device_remove_file(dev, &dev_attr_gain);

	hid_hw_stop(hdev);
	tmff2->wheel_destroy(tmff2->data);

	kfree(tmff2->states);
	kfree(tmff2);
}

static const struct hid_device_id tmff2_devices[] = {
	/* t300rs and variations */
	{HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, TMT300RS_PS3_NORM_ID)},
	{HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, TMT300RS_PS3_ADV_ID)},
	{HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, TMT300RS_PS4_NORM_ID)},
	/* t248 PC*/
	{HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, TMT248_PC_ID)},
	/* tx */
	{HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, TX_ACTIVE)},
	/* TS-PC RACER */
	{HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, TMTS_PC_RACER_ID)},
	/* tsxw */
	{HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, TSXW_ACTIVE)},

	{}
};
MODULE_DEVICE_TABLE(hid, tmff2_devices);

static struct hid_driver tmff2_driver = {
	.name = "tmff2",
	.id_table = tmff2_devices,
	.probe = tmff2_probe,
	.remove = tmff2_remove,
	.report_fixup = tmff2_report_fixup,
};
module_hid_driver(tmff2_driver);

MODULE_LICENSE("GPL");
