aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Kbuild2
-rw-r--r--Makefile1
-rw-r--r--TODO7
-rw-r--r--hid-tmff2.c733
-rw-r--r--hid-tmff2.h144
-rw-r--r--hid-tmt248.c310
-rw-r--r--hid-tmt300rs.c2084
-rw-r--r--hid-tmt300rs.h161
-rw-r--r--ps4-input.txt54
-rw-r--r--t248-effects.txt2
10 files changed, 2318 insertions, 1180 deletions
diff --git a/Kbuild b/Kbuild
new file mode 100644
index 0000000..590c69d
--- /dev/null
+++ b/Kbuild
@@ -0,0 +1,2 @@
+obj-m := hid-tmff-new.o
+hid-tmff-new-y := hid-tmff2.o hid-tmt300rs.o hid-tmt248.o
diff --git a/Makefile b/Makefile
index 0b00472..5e2ab40 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,3 @@
-obj-m += hid-tmt300rs.o
KDIR ?= /lib/modules/$(shell uname -r)/build
all: hid-tminit
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..70d3652
--- /dev/null
+++ b/TODO
@@ -0,0 +1,7 @@
++ Make code more general to allow for stuff like T150/T248/T500 to be relatively
+easily included.
+
++ Use workqueues instead of doing everything in t300rs_timer
+
++ T248 open/close seems to crash the wheel and the kernel along with it, check how Windows handles it
++ T248 fix rdesc, 0x0a somewhere needs to be set to 0x60
diff --git a/hid-tmff2.c b/hid-tmff2.c
new file mode 100644
index 0000000..12e8e25
--- /dev/null
+++ b/hid-tmff2.c
@@ -0,0 +1,733 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/workqueue.h>
+#include <linux/module.h>
+#include <linux/hid.h>
+#include "hid-tmff2.h"
+
+
+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 unsigned long lock_flags;
+
+static struct tmff2_device_entry *tmff2_from_hdev(struct hid_device *hdev)
+{
+ 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)
+{
+ 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)
+{
+ 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 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)
+{
+ 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_length;
+
+
+ if (!tmff2)
+ return;
+
+ for (effect_id = 0; effect_id < tmff2->max_effects; ++effect_id) {
+ spin_lock(&tmff2->lock);
+
+ time_now = JIFFIES2MS(jiffies);
+ state = &tmff2->states[effect_id];
+
+ effect_length = state->effect.replay.length;
+ if (test_bit(FF_EFFECT_PLAYING, &state->flags) && effect_length) {
+ if ((time_now - state->start_time) >= effect_length) {
+ __clear_bit(FF_EFFECT_PLAYING, &state->flags);
+ __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)) {
+ if (tmff2->upload_effect(tmff2->data, state)) {
+ hid_warn(tmff2->hdev, "failed uploading effect\n");
+ } else {
+ __clear_bit(FF_EFFECT_QUEUE_UPLOAD, &state->flags);
+ /* if we're uploading an effect, it's bound to be the up
+ * to date available */
+ __clear_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags);
+ }
+ }
+
+ if (test_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags)) {
+ if (tmff2->update_effect(tmff2->data, state))
+ hid_warn(tmff2->hdev, "failed updating effect\n");
+ else
+ __clear_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags);
+ }
+
+ if (test_bit(FF_EFFECT_QUEUE_START, &state->flags)) {
+ if (tmff2->play_effect(tmff2->data, state)) {
+ hid_warn(tmff2->hdev, "failed starting effect\n");
+ } else {
+ __clear_bit(FF_EFFECT_QUEUE_START, &state->flags);
+ __set_bit(FF_EFFECT_PLAYING, &state->flags);
+ }
+
+ }
+
+ if (test_bit(FF_EFFECT_QUEUE_STOP, &state->flags)) {
+ if (tmff2->stop_effect(tmff2->data, state)) {
+ hid_warn(tmff2->hdev, "failed stopping effect\n");
+ } else {
+ __clear_bit(FF_EFFECT_PLAYING, &state->flags);
+ __clear_bit(FF_EFFECT_QUEUE_STOP, &state->flags);
+ }
+ }
+
+ if (state->count > max_count)
+ max_count = state->count;
+
+ spin_unlock(&tmff2->lock);
+ }
+
+ if (max_count && tmff2->allow_scheduling)
+ schedule_delayed_work(&tmff2->work, msecs_to_jiffies(timer_msecs));
+}
+
+static int tmff2_upload(struct input_dev *dev,
+ struct ff_effect *effect, struct ff_effect *old)
+{
+ 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(&tmff2->lock);
+
+ state->effect = *effect;
+
+ if (old) {
+ if (test_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags))
+ state->old = *old;
+
+ __set_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags);
+ } else {
+ __set_bit(FF_EFFECT_QUEUE_UPLOAD, &state->flags);
+ }
+
+ spin_unlock(&tmff2->lock);
+ return 0;
+}
+
+static int tmff2_play(struct input_dev *dev, int effect_id, int value)
+{
+ 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->effect == 0)
+ return 0;
+
+ spin_lock(&tmff2->lock);
+ 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(&tmff2->lock);
+
+ 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);
+
+ 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 */
+ cancel_delayed_work_sync(&tmff2->work);
+
+ if (tmff2->close) {
+ tmff2->close(tmff2->data);
+ 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)))
+ 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);
+
+ /* 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 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 err;
+
+ tmff2->allow_scheduling = 1;
+ return 0;
+
+ input_ff_destroy(tmff2->input_dev);
+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) {
+ /* t300rs */
+ 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;
+
+ 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;
+}
+
+static __u8 *tmff2_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
+{
+ 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_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)},
+ {}
+};
+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");
diff --git a/hid-tmff2.h b/hid-tmff2.h
new file mode 100644
index 0000000..d5de938
--- /dev/null
+++ b/hid-tmff2.h
@@ -0,0 +1,144 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __HID_TMFF2_H
+#define __HID_TMFF2_H
+
+#include <linux/fixp-arith.h>
+#include <linux/ktime.h>
+#include <linux/input.h>
+
+extern int timer_msecs;
+extern int spring_level;
+extern int damper_level;
+extern int friction_level;
+extern int range;
+extern int gain;
+extern int alt_mode;
+
+#define USB_VENDOR_ID_THRUSTMASTER 0x044f
+
+/* the wheel seems to only be capable of processing a certain number of
+ * interrupts per second, and if this value is too low the kernel urb buffer(or
+ * some buffer at least) fills up. Optimally I would figure out some way to
+ * space out the interrupts so that they all leave at regular intervals, but
+ * for now this is good enough, go slow enough that everything works.
+ */
+#define DEFAULT_TIMER_PERIOD 8
+
+#define FF_EFFECT_QUEUE_UPLOAD 0
+#define FF_EFFECT_QUEUE_START 1
+#define FF_EFFECT_QUEUE_STOP 2
+#define FF_EFFECT_QUEUE_UPDATE 3
+#define FF_EFFECT_PLAYING 4
+
+#define PARAM_SPRING_LEVEL (1 << 0)
+#define PARAM_DAMPER_LEVEL (1 << 1)
+#define PARAM_FRICTION_LEVEL (1 << 2)
+#define PARAM_RANGE (1 << 3)
+#define PARAM_ALT_MODE (1 << 4)
+#define PARAM_GAIN (1 << 5)
+
+#undef fixp_sin16
+#define fixp_sin16(v) (((v % 360) > 180) ?\
+ -(fixp_sin32((v % 360) - 180) >> 16)\
+ : fixp_sin32(v) >> 16)
+
+#define JIFFIES2MS(jiffies) ((jiffies) * 1000 / HZ)
+
+struct tmff2_effect_state {
+ struct ff_effect effect;
+ struct ff_effect old;
+
+ unsigned long flags;
+ unsigned long count;
+ unsigned long start_time;
+};
+
+struct tmff2_device_entry {
+ struct hid_device *hdev;
+ struct input_dev *input_dev;
+
+ /* pointer to array */
+ struct tmff2_effect_state *states;
+
+ struct delayed_work work;
+
+ spinlock_t lock;
+
+ int allow_scheduling;
+
+ /* fields relevant to each actual device (T300, T150...) */
+ void *data;
+ unsigned long params;
+ unsigned long max_effects;
+ signed short supported_effects[FF_CNT];
+
+ /* obligatory callbacks */
+ int (*play_effect)(void *data, struct tmff2_effect_state *state);
+ int (*upload_effect)(void *data, struct tmff2_effect_state *state);
+ int (*update_effect)(void *data, struct tmff2_effect_state *state);
+ int (*stop_effect)(void *data, struct tmff2_effect_state *state);
+
+ int (*wheel_init)(struct tmff2_device_entry *tmff2);
+ int (*wheel_destroy)(void *data);
+
+ /* optional callbacks */
+ int (*open)(void *data);
+ int (*close)(void *data);
+ int (*set_gain)(void *data, uint16_t gain);
+ int (*set_range)(void *data, uint16_t range);
+ /* switch_mode has to not do anything if we're alredy in the specified
+ * mode */
+ int (*switch_mode)(void *data, uint16_t mode);
+ ssize_t (*alt_mode_show)(void *data, char *buf);
+ ssize_t (*alt_mode_store)(void *data, const char *buf, size_t count);
+ int (*set_autocenter)(void *data, uint16_t autocenter);
+ __u8 *(*wheel_fixup)(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize);
+
+ /* void pointers are dangerous, I know, but in this case likely the best option... */
+};
+
+/* external */
+int t300rs_populate_api(struct tmff2_device_entry *tmff2);
+int t248_populate_api(struct tmff2_device_entry *tmff2);
+
+#define TMT300RS_PS3_NORM_ID 0xb66e
+#define TMT300RS_PS3_ADV_ID 0xb66f
+#define TMT300RS_PS4_NORM_ID 0xb66d
+
+#define TMT248_PC_ID 0xb696
+
+/* apis to different wheel families */
+/* T248 at least uses the T300RS api, not sure if there are other wheels but that's
+ * why these functions are given global linkage */
+
+struct t300rs_device_entry {
+ struct hid_device *hdev;
+ struct input_dev *input_dev;
+ struct hid_report *report;
+ struct hid_field *ff_field;
+ struct usb_device *usbdev;
+
+ int (*open)(struct input_dev *dev);
+ void (*close)(struct input_dev *dev);
+
+ int mode;
+ int attachment;
+ u8 buffer_length;
+ u8 *send_buffer;
+};
+
+int t300rs_play_effect(void *, struct tmff2_effect_state *);
+int t300rs_upload_effect(void *, struct tmff2_effect_state *);
+int t300rs_update_effect(void *, struct tmff2_effect_state *);
+int t300rs_stop_effect(void *, struct tmff2_effect_state *);
+
+int t300rs_open(void *);
+int t300rs_close(void *);
+int t300rs_set_gain(void *, uint16_t);
+int t300rs_set_range(void *, uint16_t);
+int t300rs_set_autocenter(void *, uint16_t);
+
+int t300rs_send_buf(struct t300rs_device_entry *t300rs, u8 *send_buffer, size_t len);
+int t300rs_send_int(struct t300rs_device_entry *t300rs);
+
+#endif /* __HID_TMFF2_H */
diff --git a/hid-tmt248.c b/hid-tmt248.c
new file mode 100644
index 0000000..e241301
--- /dev/null
+++ b/hid-tmt248.c
@@ -0,0 +1,310 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/usb.h>
+#include <linux/hid.h>
+#include "hid-tmff2.h"
+
+#define T248_MAX_EFFECTS 16
+#define T248_BUFFER_LENGTH 63
+
+static const u8 setup_0[64] = { 0x42, 0x01 };
+static const u8 setup_1[64] = { 0x0a, 0x04, 0x90, 0x03 };
+static const u8 setup_2[64] = { 0x0a, 0x04, 0x00, 0x0c };
+static const u8 setup_3[64] = { 0x0a, 0x04, 0x12, 0x10 };
+static const u8 setup_4[64] = { 0x0a, 0x04, 0x00, 0x06 };
+static const u8 setup_5[64] = { 0x0a, 0x04, 0x00, 0x0e };
+static const u8 setup_6[64] = { 0x0a, 0x04, 0x00, 0x0e, 0x01 };
+static const u8 *const setup_arr[] = { setup_0, setup_1, setup_2, setup_3, setup_4, setup_5, setup_6 };
+static const unsigned int setup_arr_sizes[] = {
+ ARRAY_SIZE(setup_0),
+ ARRAY_SIZE(setup_1),
+ ARRAY_SIZE(setup_2),
+ ARRAY_SIZE(setup_3),
+ ARRAY_SIZE(setup_4),
+ ARRAY_SIZE(setup_5),
+ ARRAY_SIZE(setup_6)
+};
+
+static const unsigned long t248_params =
+ PARAM_SPRING_LEVEL
+ | PARAM_DAMPER_LEVEL
+ | PARAM_FRICTION_LEVEL
+ | PARAM_RANGE
+ | PARAM_GAIN
+ ;
+
+static const signed short t248_effects[] = {
+ FF_CONSTANT,
+ FF_RAMP,
+ FF_SPRING,
+ FF_DAMPER,
+ FF_FRICTION,
+ FF_INERTIA,
+ FF_PERIODIC,
+ FF_SINE,
+ FF_TRIANGLE,
+ FF_SQUARE,
+ FF_SAW_UP,
+ FF_SAW_DOWN,
+ FF_AUTOCENTER,
+ FF_GAIN,
+ -1
+};
+
+/* TODO: sort through this stuff */
+static u8 t248_pc_rdesc_fixed[] = {
+ 0x05, 0x01, /* Usage page (Generic Desktop) */
+ 0x09, 0x04, /* Usage (Joystick) */
+ 0xa1, 0x01, /* Collection (Application) */
+ 0x09, 0x01, /* Usage (Pointer) */
+ 0xa1, 0x00, /* Collection (Physical) */
+ 0x85, 0x07, /* Report ID (7) */
+ 0x09, 0x30, /* Usage (X) */
+ 0x15, 0x00, /* Logical minimum (0) */
+ 0x27, 0xff, 0xff, 0x00, 0x00, /* Logical maximum (65535) */
+ 0x35, 0x00, /* Physical minimum (0) */
+ 0x47, 0xff, 0xff, 0x00, 0x00, /* Physical maximum (65535) */
+ 0x75, 0x10, /* Report size (16) */
+ 0x95, 0x01, /* Report count (1) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x09, 0x31, /* Usage (Y) TODO: clutch? */
+ 0x26, 0xff, 0x03, /* Logical maximum (1023) */
+ 0x46, 0xff, 0x03, /* Physical maximum (1023) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x09, 0x35, /* Usage (Rz) TODO: brake? */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x09, 0x36, /* Usage (Slider) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x75, 0x08, /* Report size (8) */
+ 0x26, 0xff, 0x00, /* Logical maximum (255) */
+ 0x46, 0xff, 0x00, /* Physical maximum (255) */
+ 0x09, 0x40, /* Usage (Vx) TODO: what is this? */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x09, 0x41, /* Usage (Vy) TODO: --||-- */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x09, 0x33, /* Usage (Rx) TODO: --||-- */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x09, 0x34, /* Usage (Ry) TODO: --||-- */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x09, 0x32, /* Usage (Z) TODO: --||-- (gas?) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x09, 0x37, /* Usage (Dial) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x05, 0x09, /* Usage page (Button) */
+ 0x19, 0x01, /* Usage minimum (1) */
+ 0x29, 0x1a, /* Usage maximum (13) */
+ 0x25, 0x01, /* Logical maximum (1) */
+ 0x45, 0x01, /* Physical maximum (1) */
+ 0x75, 0x01, /* Report size (1) */
+ 0x95, 0x1a, /* Report count (26) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x75, 0x06, /* Report size (6) */
+ 0x95, 0x01, /* Report count (1) */
+ 0x81, 0x03, /* Usage (Variable, Absolute, Constant) */
+ 0x05, 0x01, /* Usage page (Generic Desktop) */
+ 0x09, 0x39, /* Usage (Hat Switch) */
+ 0x25, 0x07, /* Logical maximum (7) */
+ 0x46, 0x3b, 0x01, /* Physical maximum (315) */
+ 0x55, 0x00, /* Unit exponent (0) */
+ 0x65, 0x14, /* Unit (Eng rot, Angular Pos) */
+ 0x75, 0x04, /* Report size (4) */
+ 0x81, 0x42, /* Input (Variable, Absolute, NullState) */
+ 0x65, 0x00, /* Input (None) */
+ 0x81, 0x03, /* Input (Variable, Absolute, Constant) */
+ 0x85, 0x60, /* Report ID (96), prev 10 */
+ 0x06, 0x00, 0xff, /* Usage page (Vendor 1) */
+ 0x09, 0x60, /* Usage (96), prev 10 */
+ 0x75, 0x08, /* Report size (8) */
+ 0x95, 0x3f, /* Report count (63) */
+ 0x26, 0xff, 0x00, /* Logical maximum (256) */
+ 0x46, 0xff, 0x00, /* Physical maximum (256) */
+ 0x91, 0x02, /* Output (Variable, Absolute) */
+ 0x85, 0x02, /* Report ID (2) */
+ 0x09, 0x02, /* Usage (2) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x09, 0x14, /* Usage (20) */
+ 0x85, 0x14, /* Report ID (20) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0xc0, /* End collection */
+ 0xc0, /* End collection */
+};
+
+static int t248_interrupts(struct t300rs_device_entry *t248)
+{
+ u8 *send_buf = kmalloc(256, GFP_KERNEL);
+ struct usb_interface *usbif = to_usb_interface(t248->hdev->dev.parent);
+ struct usb_host_endpoint *ep;
+ int ret, trans, b_ep, i;
+
+ if (!send_buf) {
+ hid_err(t248->hdev, "failed allocating send buffer\n");
+ return -ENOMEM;
+ }
+
+ ep = &usbif->cur_altsetting->endpoint[1];
+ b_ep = ep->desc.bEndpointAddress;
+
+ for (i = 0; i < ARRAY_SIZE(setup_arr); ++i) {
+ memcpy(send_buf, setup_arr[i], setup_arr_sizes[i]);
+
+ ret = usb_interrupt_msg(t248->usbdev,
+ usb_sndintpipe(t248->usbdev, b_ep),
+ send_buf, setup_arr_sizes[i],
+ &trans,
+ USB_CTRL_SET_TIMEOUT);
+
+ if (ret) {
+ hid_err(t248->hdev, "setup data couldn't be sent\n");
+ goto err;
+ }
+ }
+
+err:
+ kfree(send_buf);
+ return ret;
+}
+
+int t248_wheel_init(struct tmff2_device_entry *tmff2)
+{
+ struct t300rs_device_entry *t248 = kzalloc(sizeof(struct t300rs_device_entry), GFP_KERNEL);
+ struct list_head *report_list;
+ int ret;
+
+
+ if (!t248) {
+ ret = -ENOMEM;
+ goto t248_err;
+ }
+
+ t248->hdev = tmff2->hdev;
+ t248->input_dev = tmff2->input_dev;
+ t248->usbdev = to_usb_device(tmff2->hdev->dev.parent->parent);
+ t248->buffer_length = T248_BUFFER_LENGTH;
+
+ t248->send_buffer = kzalloc(t248->buffer_length, GFP_KERNEL);
+ if (!t248->send_buffer) {
+ ret = -ENOMEM;
+ goto send_err;
+ }
+
+ report_list = &t248->hdev->report_enum[HID_OUTPUT_REPORT].report_list;
+ t248->report = list_entry(report_list->next, struct hid_report, list);
+ t248->ff_field = t248->report->field[0];
+
+ t248->open = t248->input_dev->open;
+ t248->close = t248->input_dev->close;
+
+ if ((ret = t248_interrupts(t248)))
+ goto interrupt_err;
+
+ /* everything went OK */
+ tmff2->data = t248;
+ tmff2->params = t248_params;
+ tmff2->max_effects = T248_MAX_EFFECTS;
+ memcpy(tmff2->supported_effects, t248_effects, sizeof(t248_effects));
+
+ hid_info(t248->hdev, "force feedback for T248\n");
+ return 0;
+
+interrupt_err:
+send_err:
+ kfree(t248);
+t248_err:
+ hid_err(tmff2->hdev, "failed initializing T248\n");
+ return ret;
+}
+
+int t248_wheel_destroy(void *data)
+{
+ struct t300rs_device_entry *t300rs = data;
+
+ if (!t300rs)
+ return -ENODEV;
+
+ kfree(t300rs->send_buffer);
+ kfree(t300rs);
+ return 0;
+}
+
+int t248_set_range(void *data, uint16_t value)
+{
+ struct t300rs_device_entry *t248 = data;
+
+ if (value < 140) {
+ hid_info(t248->hdev, "value %i too small, clamping to 140\n", value);
+ value = 140;
+ }
+
+ if (value > 900) {
+ hid_info(t248->hdev, "value %i too large, clamping to 900\n", value);
+ value = 900;
+ }
+
+ return t300rs_set_range(data, value);
+}
+
+static int t248_open(void *data)
+{
+ struct t300rs_device_entry *t248 = data;
+
+ if (!t248)
+ return -ENODEV;
+
+ t248->send_buffer[0] = 0x01;
+ t248->send_buffer[1] = 0x04;
+ t300rs_send_int(t248);
+
+ t248->send_buffer[0] = 0x01;
+ t248->send_buffer[1] = 0x05;
+ t300rs_send_int(t248);
+
+ return t248->open(t248->input_dev);
+}
+
+static int t248_close(void *data)
+{
+ struct t300rs_device_entry *t248 = data;
+
+ if (!t248)
+ return -ENODEV;
+
+ t248->send_buffer[0] = 0x01;
+ t248->send_buffer[1] = 0x05;
+ t300rs_send_int(t248);
+
+ t248->send_buffer[0] = 0x01;
+ t248->send_buffer[1] = 0x00;
+ t300rs_send_int(t248);
+
+ t248->close(t248->input_dev);
+ return 0;
+}
+
+static __u8 *t248_wheel_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
+{
+ rdesc = t248_pc_rdesc_fixed;
+ *rsize = sizeof(t248_pc_rdesc_fixed);
+ return rdesc;
+}
+
+int t248_populate_api(struct tmff2_device_entry *tmff2)
+{
+ tmff2->play_effect = t300rs_play_effect;
+ tmff2->upload_effect = t300rs_upload_effect;
+ tmff2->update_effect = t300rs_update_effect;
+ tmff2->stop_effect = t300rs_stop_effect;
+
+ tmff2->set_gain = t300rs_set_gain;
+ tmff2->set_autocenter = t300rs_set_autocenter;
+ /* T248 only has 900 degree range, instead of T300RS 1080 */
+ tmff2->set_range = t248_set_range;
+ tmff2->wheel_fixup = t248_wheel_fixup;
+
+ tmff2->open = t248_open;
+ tmff2->close = t248_close;
+
+ tmff2->wheel_init = t248_wheel_init;
+ tmff2->wheel_destroy = t248_wheel_destroy;
+
+ return 0;
+}
diff --git a/hid-tmt300rs.c b/hid-tmt300rs.c
index 54ace09..aee30d5 100644
--- a/hid-tmt300rs.c
+++ b/hid-tmt300rs.c
@@ -1,151 +1,479 @@
// SPDX-License-Identifier: GPL-2.0
-#include "hid-tmt300rs.h"
+#include <linux/usb.h>
+#include <linux/hid.h>
+#include "hid-tmff2.h"
-static int timer_msecs = DEFAULT_TIMER_PERIOD;
-module_param(timer_msecs, int, 0660);
-MODULE_PARM_DESC(timer_msecs, "Timer resolution in msecs");
+#define T300RS_MAX_EFFECTS 16
+#define T300RS_NORM_BUFFER_LENGTH 63
+#define T300RS_PS4_BUFFER_LENGTH 31
-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");
+#define T300RS_DEFAULT_ATTACHMENT 0x06
+#define T300RS_F1_ATTACHMENT 0x03
-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 const unsigned long t300rs_params =
+ PARAM_SPRING_LEVEL
+ | PARAM_DAMPER_LEVEL
+ | PARAM_FRICTION_LEVEL
+ | PARAM_GAIN
+ | PARAM_RANGE
+ | PARAM_ALT_MODE
+ ;
-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 const signed short t300rs_effects[] = {
+ FF_CONSTANT,
+ FF_RAMP,
+ FF_SPRING,
+ FF_DAMPER,
+ FF_FRICTION,
+ FF_INERTIA,
+ FF_PERIODIC,
+ FF_SINE,
+ FF_TRIANGLE,
+ FF_SQUARE,
+ FF_SAW_UP,
+ FF_SAW_DOWN,
+ FF_AUTOCENTER,
+ FF_GAIN,
+ -1
+};
+struct __packed t300rs_fw_response {
+ uint8_t unused1[2];
+ uint8_t fw_version;
+ uint8_t unused2;
+};
-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;
- }
+struct __packed t300rs_packet_header {
+ uint8_t zero1;
+ uint8_t id;
+ uint8_t code;
+};
- 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;
-}
+struct __packed t300rs_setup_header {
+ uint8_t cmd;
+ uint8_t code;
+};
+
+struct __packed t300rs_packet_envelope {
+ uint16_t attack_length;
+ uint16_t attack_level;
+ uint16_t fade_length;
+ uint16_t fade_level;
+};
+
+struct __packed t300rs_packet_timing {
+ uint8_t start_marker;
+ uint16_t duration;
+ uint8_t zero1[2];
+ uint16_t offset;
+ uint8_t zero2;
+ uint16_t end_marker;
+};
-static int t300rs_send_int(struct input_dev *dev, u8 *send_buffer, int *trans)
+struct usb_ctrlrequest t300rs_fw_request = {
+ .bRequestType = 0xc1,
+ .bRequest = 86,
+ .wValue = 0,
+ .wIndex = 0,
+ .wLength = 8
+};
+
+struct t300rs_data {
+ unsigned long quirks;
+ void *device_props;
+};
+
+static u8 t300rs_rdesc_nrm_fixed[] = {
+ 0x05, 0x01, /* Usage page (Generic Desktop) */
+ 0x09, 0x04, /* Usage (Joystick) */
+ 0xa1, 0x01, /* Collection (Application) */
+ 0x09, 0x01, /* Usage (Pointer) */
+ 0xa1, 0x00, /* Collection (Physical) */
+ 0x85, 0x07, /* Report ID (7) */
+ 0x09, 0x30, /* Usage (X) */
+ 0x15, 0x00, /* Logical minimum (0) */
+ 0x27, 0xff, 0xff, 0x00, 0x00, /* Logical maximum (65535) */
+ 0x35, 0x00, /* Physical minimum (0) */
+ 0x47, 0xff, 0xff, 0x00, 0x00, /* Physical maximum (65535) */
+ 0x75, 0x10, /* Report size (16) */
+ 0x95, 0x01, /* Report count (1) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x09, 0x35, /* Usage (Rz) (Brake) */
+ 0x26, 0xff, 0x03, /* Logical maximum (1023) */
+ 0x46, 0xff, 0x03, /* Physical maximum (1023) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x09, 0x32, /* Usage (Z) (Gas) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x09, 0x31, /* Usage (Y) (Clutch) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x81, 0x03, /* Input (Variable, Absolute, Constant) */
+ 0x05, 0x09, /* Usage page (Button) */
+ 0x19, 0x01, /* Usage minimum (1) */
+ 0x29, 0x0d, /* Usage maximum (13) */
+ 0x25, 0x01, /* Logical maximum (1) */
+ 0x45, 0x01, /* Physical maximum (1) */
+ 0x75, 0x01, /* Report size (1) */
+ 0x95, 0x0d, /* Report count (13) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x75, 0x0b, /* Report size (13) */
+ 0x95, 0x01, /* Report count (1) */
+ 0x81, 0x03, /* Usage (Variable, Absolute, Constant) */
+ 0x05, 0x01, /* Usage page (Generic Desktop) */
+ 0x09, 0x39, /* Usage (Hat Switch) */
+ 0x25, 0x07, /* Logical maximum (7) */
+ 0x46, 0x3b, 0x01, /* Physical maximum (315) */
+ 0x55, 0x00, /* Unit exponent (0) */
+ 0x65, 0x14, /* Unit (Eng Rot, Angular Pos) */
+ 0x75, 0x04, /* Report size (4) */
+ 0x81, 0x42, /* Input (Variable, Absolute, NullState) */
+ 0x65, 0x00, /* Unit (None) */
+ 0x81, 0x03, /* Input (Variable, Absolute, Constant) */
+ 0x85, 0x60, /* Report ID (96), prev 10 */
+ 0x06, 0x00, 0xff, /* Usage page (Vendor 1) */
+ 0x09, 0x60, /* Usage (96), prev 10 */
+ 0x75, 0x08, /* Report size (8) */
+ 0x95, 0x3f, /* Report count (63) */
+ 0x26, 0xff, 0x7f, /* Logical maximum (32767) */
+ 0x15, 0x00, /* Logical minimum (0) */
+ 0x46, 0xff, 0x7f, /* Physical maximum (32767) */
+ 0x36, 0x00, 0x80, /* Physical minimum (-32768) */
+ 0x91, 0x02, /* Output (Variable, Absolute) */
+ 0x85, 0x02, /* Report ID (2) */
+ 0x09, 0x02, /* Usage (2) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x09, 0x14, /* Usage (20) */
+ 0x85, 0x14, /* Report ID (20) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0xc0, /* End collection */
+ 0xc0, /* End collection */
+};
+
+static u8 t300rs_rdesc_adv_fixed[] = {
+ 0x05, 0x01, /* Usage page (Generic Desktop) */
+ 0x09, 0x04, /* Usage (Joystick) */
+ 0xa1, 0x01, /* Collection (Application) */
+ 0x09, 0x01, /* Usage (Pointer) */
+ 0xa1, 0x00, /* Collection (Physical) */
+ 0x85, 0x07, /* Report ID (7) */
+ 0x09, 0x30, /* Usage (X) */
+ 0x15, 0x00, /* Logical minimum (0) */
+ 0x27, 0xff, 0xff, 0x00, 0x00, /* Logical maximum (65535) */
+ 0x35, 0x00, /* Physical minimum (0) */
+ 0x47, 0xff, 0xff, 0x00, 0x00, /* Physical maximum (65535) */
+ 0x75, 0x10, /* Report size (16) */
+ 0x95, 0x01, /* Report count (1) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x09, 0x31, /* Usage (Y) */
+ 0x26, 0xff, 0x03, /* Logical maximum (1023) */
+ 0x46, 0xff, 0x03, /* Physical maximum (1023) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x09, 0x35, /* Usage (Rz) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x09, 0x36, /* Usage (Slider) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x81, 0x03, /* Input (Variable, Absolute, Constant) ? */
+ 0x05, 0x09, /* Usage page (Button) */
+ 0x19, 0x01, /* Usage minimum (1) */
+ 0x29, 0x19, /* Usage maximum (25) */
+ 0x25, 0x01, /* Logical maximum (1) */
+ 0x45, 0x01, /* Physical maximum (1) */
+ 0x75, 0x01, /* Report size (1) */
+ 0x95, 0x19, /* Report count (25) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x75, 0x03, /* Report size (3) */
+ 0x95, 0x01, /* Report count (1) */
+ 0x81, 0x03, /* Input (Variable, Absolute, Constant) */
+ 0x05, 0x01, /* Usage page (Generic Desktop) */
+ 0x09, 0x39, /* Usage (Hat Switch) */
+ 0x25, 0x07, /* Logical maximum (7) */
+ 0x46, 0x3b, 0x01, /* Physical maximum (315) */
+ 0x55, 0x00, /* Unit exponent (0) */
+ 0x65, 0x14, /* Unit (Eng Rot, Angular Pos) */
+ 0x75, 0x04, /* Report size (4) */
+ 0x81, 0x42, /* Input (Variable, Absolute, NullState) */
+ 0x65, 0x00, /* Unit (None) */
+ 0x85, 0x60, /* Report ID (96), prev 10 */
+ 0x06, 0x00, 0xff, /* Usage page (Vendor 1) */
+ 0x09, 0x60, /* Usage (96), prev 10 (why?) */
+ 0x75, 0x08, /* Report size (8) */
+ 0x95, 0x3f, /* Report count (63) */
+ 0x26, 0xff, 0x00, /* Logical maximum (255) */
+ 0x46, 0xff, 0x00, /* Physical maximum (255) */
+ 0x91, 0x02, /* Output (Variable, Absolute) */
+ 0x85, 0x02, /* Report ID (2) */
+ 0x09, 0x02, /* Usage (Mouse) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x09, 0x14, /* Usage (20) */
+ 0x85, 0x14, /* Report ID (20) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0xc0, /* End collection */
+ 0xc0, /* End collection */
+};
+
+static u8 t300rs_rdesc_ps4_fixed[] = {
+ 0x05, 0x01, /* Usage page (Generic Desktop) */
+ 0x09, 0x05, /* Usage (GamePad) */
+ 0xa1, 0x01, /* Collection (Application) */
+ 0x85, 0x01, /* Report ID (1) */
+ 0x09, 0x00, /* Usage (U) (was X) */
+ 0x09, 0x00, /* Usage (U) (was Y) */
+ 0x09, 0x00, /* Usage (U) (was Z) */
+ 0x09, 0x00, /* Usage (U) (was Rz)*/
+ 0x15, 0x00, /* Logical minimum (0) */
+ 0x26, 0xff, 0x00, /* Logical maximum (255) */
+ 0x75, 0x08, /* Report size (8) */
+ 0x95, 0x04, /* Report count (4) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x09, 0x39, /* Usage (Hat Switch) */
+ 0x15, 0x00, /* Logical minimum (0) */
+ 0x25, 0x07, /* Logical maximum (7)*/
+ 0x35, 0x00, /* Physical minimum (0) */
+ 0x46, 0x3b, 0x01, /* Physical maximum (315) */
+ 0x65, 0x14, /* Unit (Eng Rot, Angular Pos) */
+ 0x75, 0x04, /* Report size (4) */
+ 0x95, 0x01, /* Report count (1) */
+ 0x81, 0x42, /* Input (Variable, Absolute, NullState) */
+ 0x65, 0x00, /* Input (None) */
+ 0x05, 0x09, /* Usage page (Button) */
+ 0x19, 0x01, /* Usage minimum (1) */
+ 0x29, 0x0e, /* Usage maximum (14) */
+ 0x15, 0x00, /* Logical minimum (0) */
+ 0x25, 0x01, /* Logical maximum (1) */
+ 0x75, 0x01, /* Report size (1) */
+ 0x95, 0x0e, /* Report size (14) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x06, 0x00, 0xff, /* Usage page (Vendor 1) */
+ 0x09, 0x20, /* Usage (32) */
+ 0x75, 0x06, /* Report size (6) */
+ 0x95, 0x01, /* Report count (1) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x05, 0x01, /* Usage page (Generic Desktop) */
+ 0x09, 0x00, /* Usage (U) (was Rx)*/
+ 0x09, 0x00, /* Usage (U) (was Ry) */
+ 0x15, 0x00, /* Logical minimum (0) */
+ 0x26, 0xff, 0x00, /* Logical maximum (255) */
+ 0x75, 0x08, /* Report size (8) */
+ 0x95, 0x02, /* Report count (2) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ 0x05, 0x01, /* Usage page (Vendor 1) */
+ /* constant zero? */
+ 0x09, 0x00, /* Usage (33) */
+ 0x95, 0x21, /* Report count (33) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ /* wheel */
+ 0x09, 0x30, /* Usage (X) */
+ 0x15, 0x00, /* Logical minimum (0) */
+ 0x27, 0xff, 0xff, 0x00, 0x00, /* Logical maximum (65535) */
+ 0x35, 0x00, /* Physical minimum (0) */
+ 0x47, 0xff, 0xff, 0x00, 0x00, /* Physical maximum (65535) */
+ 0x75, 0x10, /* Report size (16) */
+ 0x95, 0x01, /* Report count (1) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ /* gas */
+ 0x09, 0x31, /* Usage (Y) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ /* brake */
+ 0x09, 0x32, /* Usage (Z) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ /* clutch */
+ 0x09, 0x35, /* Usage (Rz) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ /* stick shifter (check model no) */
+ 0x05, 0x09, /* Usage page (Button) */
+ 0x19, 0x0f, /* Usage minimum (15) */
+ 0x29, 0x17, /* Usage maximum (23) */
+ 0x15, 0x00, /* Logical minimum (1) */
+ 0x25, 0x01, /* Logical maximum (1) */
+ 0x75, 0x01, /* Report size (1) */
+ 0x95, 0x08, /* Report count (8) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ /* no clue */
+ 0x05, 0x01, /* Usage page (Generic Desktop) */
+ 0x09, 0x00, /* Usage (U) */
+ 0x75, 0x08, /* Report size (8) */
+ 0x95, 0x0c, /* Report count (12) */
+ 0x81, 0x02, /* Input (Variable, Absolute) */
+ /* continue unmodified */
+ 0x06, 0x00, 0xff, /* Usage page (Vendor defined 1) */
+ 0x85, 0x60, /* Report ID (5) (change to 0x60?) */
+ 0x09, 0x60, /* Usage (34) (change to 0x60?) */
+ 0x95, 0x1f, /* Report count (31) () */
+ 0x91, 0x02, /* Output (Variable, Absolute) */
+ 0x85, 0x03, /* Report ID (3) */
+ 0x0a, 0x21, 0x27, /* ??? */
+ 0x95, 0x2f, /* Report count (47) */
+ 0xb1, 0x02, /* Feature (Data, Var, Abs) */
+ 0xc0, /* End collection */
+
+ /* From here on out no clue */
+ 0x06, 0xf0,
+ 0xff, 0x09,
+ 0x40, 0xa1,
+ 0x01, 0x85,
+ 0xf0, 0x09,
+ 0x47, 0x95,
+ 0x3f, 0xb1,
+ 0x02, 0x85,
+ 0xf1, 0x09,
+ 0x48, 0x95,
+ 0x3f, 0xb1,
+ 0x02, 0x85,
+ 0xf2, 0x09,
+ 0x49, 0x95,
+ 0x0f, 0xb1,
+ 0x02, 0x85,
+ 0xf3, 0x0a,
+ 0x01, 0x47,
+ 0x95, 0x07,
+ 0xb1, 0x02,
+ 0xc0,
+};
+
+static u8 spring_values[] = {
+ 0xa6, 0x6a, 0xa6, 0x6a, 0xfe,
+ 0xff, 0xfe, 0xff, 0xfe, 0xff,
+ 0xfe, 0xff, 0xdf, 0x58, 0xa6,
+ 0x6a, 0x06
+};
+
+static u8 damper_values[] = {
+ 0xfc, 0x7f, 0xfc, 0x7f, 0xfe,
+ 0xff, 0xfe, 0xff, 0xfe, 0xff,
+ 0xfe, 0xff, 0xfc, 0x7f, 0xfc,
+ 0x7f, 0x07
+};
+
+int t300rs_send_buf(struct t300rs_device_entry *t300rs, u8 *send_buffer, size_t len)
{
- struct hid_device *hdev = input_get_drvdata(dev);
- struct t300rs_device_entry *t300rs;
int i;
+ /* check that send_buffer fits into our report */
+ if (len > t300rs->buffer_length)
+ return -EINVAL;
- t300rs = t300rs_get_device(hdev);
- if (!t300rs) {
- hid_err(hdev, "could not get device\n");
- return -1;
- }
-
- for (i = 0; i < T300RS_BUFFER_LENGTH; ++i)
+ /* fill with actual data */
+ for (i = 0; i < len; ++i)
t300rs->ff_field->value[i] = send_buffer[i];
+ /* fill the rest with zeroes */
+ for (i = len; i < t300rs->buffer_length; ++i)
+ t300rs->ff_field->value[i] = 0;
+
hid_hw_request(t300rs->hdev, t300rs->report, HID_REQ_SET_REPORT);
+ return 0;
+}
- memset(send_buffer, 0, T300RS_BUFFER_LENGTH);
+int t300rs_send_int(struct t300rs_device_entry *t300rs)
+{
+ t300rs_send_buf(t300rs, t300rs->send_buffer, t300rs->buffer_length);
+ memset(t300rs->send_buffer, 0, t300rs->buffer_length);
return 0;
}
-static int t300rs_play_effect(struct t300rs_device_entry *t300rs,
- struct t300rs_effect_state *state)
+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;
+}
+
+int t300rs_play_effect(void *data, struct tmff2_effect_state *state)
{
- u8 *send_buffer = t300rs->send_buffer;
- int ret, trans;
+ struct t300rs_device_entry *t300rs = data;
+ struct __packed t300rs_packet_play {
+ struct t300rs_packet_header header;
+ uint8_t value;
+ } *play_packet = (struct t300rs_packet_play *)t300rs->send_buffer;
+
+ int ret;
- send_buffer[1] = state->effect.id + 1;
- send_buffer[2] = 0x89;
- send_buffer[3] = 0x01;
+ t300rs_fill_header(&play_packet->header, state->effect.id, 0x89);
+ play_packet->value = 0x01;
- ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ 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)
+int t300rs_stop_effect(void *data, struct tmff2_effect_state *state)
{
- u8 *send_buffer = t300rs->send_buffer;
- int ret, trans;
+ struct t300rs_device_entry *t300rs = data;
+ struct __packed t300rs_packet_stop {
+ struct t300rs_packet_header header;
+ uint8_t value;
+ } *stop_packet = (struct t300rs_packet_stop *)t300rs->send_buffer;
+
+ int ret;
- send_buffer[1] = state->effect.id + 1;
- send_buffer[2] = 0x89;
+ t300rs_fill_header(&stop_packet->header, state->effect.id, 0x89);
- ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ ret = t300rs_send_int(t300rs);
if (ret)
hid_err(t300rs->hdev, "failed stopping effect play\n");
return ret;
}
-static void t300rs_fill_envelope(u8 *send_buffer, int i, s16 level,
- u16 duration, struct ff_envelope *envelope)
+static void t300rs_fill_envelope(struct t300rs_packet_envelope *packet_envelope,
+ int16_t level, uint16_t duration, struct ff_envelope *envelope)
{
- u16 attack_length = (duration * envelope->attack_length) / 0x7fff;
- u16 attack_level = (level * envelope->attack_level) / 0x7fff;
- u16 fade_length = (duration * envelope->fade_length) / 0x7fff;
- u16 fade_level = (level * envelope->fade_level) / 0x7fff;
+ 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;
- send_buffer[i + 0] = attack_length & 0xff;
- send_buffer[i + 1] = attack_length >> 8;
- send_buffer[i + 2] = attack_level & 0xff;
- send_buffer[i + 3] = attack_level >> 8;
- send_buffer[i + 4] = fade_length & 0xff;
- send_buffer[i + 5] = fade_length >> 8;
- send_buffer[i + 6] = fade_level & 0xff;
- send_buffer[i + 7] = fade_level >> 8;
+ 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 int t300rs_modify_envelope(struct t300rs_device_entry *t300rs,
- struct t300rs_effect_state *state,
- u8 *send_buffer,
- s16 level,
- u16 duration,
- u8 id,
+static void t300rs_fill_timing(struct t300rs_packet_timing *packet_timing,
+ uint16_t duration, uint16_t offset){
+ packet_timing->start_marker = 0x4f;
+
+ packet_timing->duration = cpu_to_le16(duration);
+ packet_timing->offset = cpu_to_le16(offset);
+
+ packet_timing->end_marker = 0xffff;
+}
+
+static int t300rs_update_envelope(struct t300rs_device_entry *t300rs,
+ struct tmff2_effect_state *state,
+ int16_t level,
+ uint16_t duration,
+ uint8_t id,
struct ff_envelope envelope,
struct ff_envelope envelope_old
)
{
- u16 attack_length, attack_level, fade_length, fade_level;
- int ret = 0, trans;
+ 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;
- if (duration == 0)
- duration = 0xffff;
+ 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;
-
- send_buffer[1] = id + 1;
- send_buffer[2] = 0x31;
-
if (envelope.attack_length != envelope_old.attack_length) {
- send_buffer[3] = 0x81;
-
- send_buffer[4] = attack_length & 0xff;
- send_buffer[5] = attack_length >> 8;
+ 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->input_dev, send_buffer, &trans);
+ ret = t300rs_send_int(t300rs);
if (ret) {
hid_err(t300rs->hdev, "failed modifying effect envelope\n");
goto error;
@@ -153,12 +481,11 @@ static int t300rs_modify_envelope(struct t300rs_device_entry *t300rs,
}
if (envelope.attack_level != envelope_old.attack_level) {
- send_buffer[3] = 0x82;
-
- send_buffer[4] = attack_level & 0xff;
- send_buffer[5] = attack_level >> 8;
+ 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->input_dev, send_buffer, &trans);
+ ret = t300rs_send_int(t300rs);
if (ret) {
hid_err(t300rs->hdev, "failed modifying effect envelope\n");
goto error;
@@ -166,12 +493,11 @@ static int t300rs_modify_envelope(struct t300rs_device_entry *t300rs,
}
if (envelope.fade_length != envelope_old.fade_length) {
- send_buffer[3] = 0x84;
+ t300rs_fill_header(&packet_mod_envelope->header, id, 0x31);
+ packet_mod_envelope->attribute = 0x84;
+ packet_mod_envelope->value = cpu_to_le16(fade_length);
- send_buffer[4] = fade_length & 0xff;
- send_buffer[5] = fade_length >> 8;
-
- ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ ret = t300rs_send_int(t300rs);
if (ret) {
hid_err(t300rs->hdev, "failed modifying effect envelope\n");
goto error;
@@ -179,12 +505,11 @@ static int t300rs_modify_envelope(struct t300rs_device_entry *t300rs,
}
if (envelope.fade_level != envelope_old.fade_level) {
- send_buffer[3] = 0x88;
-
- send_buffer[4] = fade_level & 0xff;
- send_buffer[5] = fade_level >> 8;
+ 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->input_dev, send_buffer, &trans);
+ ret = t300rs_send_int(t300rs);
if (ret) {
hid_err(t300rs->hdev, "failed modifying effect envelope\n");
goto error;
@@ -195,59 +520,61 @@ error:
return ret;
}
-static int t300rs_modify_duration(struct t300rs_device_entry *t300rs,
- struct t300rs_effect_state *state, u8 *send_buffer)
+static int t300rs_update_duration(struct t300rs_device_entry *t300rs,
+ struct tmff2_effect_state *state)
{
struct ff_effect effect = state->effect;
struct ff_effect old = state->old;
- u16 duration;
- int ret = 0, trans;
+ struct t300rs_packet_mod_duration {
+ struct t300rs_packet_header header;
+ uint16_t marker;
+ uint16_t duration;
+ } *packet_mod_duration = (struct t300rs_packet_mod_duration *)t300rs->send_buffer;
- if (effect.replay.length == 0)
- duration = 0xffff;
- else
- duration = effect.replay.length;
+ uint16_t duration;
+ int ret = 0;
- if (effect.replay.length != old.replay.length) {
+ duration = effect.replay.length - 1;
- send_buffer[1] = effect.id + 1;
- send_buffer[2] = 0x49;
- send_buffer[4] = 0x41;
+ if (effect.replay.length != old.replay.length) {
- send_buffer[5] = duration & 0xff;
- send_buffer[6] = duration >> 8;
+ t300rs_fill_header(&packet_mod_duration->header, effect.id, 0x49);
+ packet_mod_duration->marker = cpu_to_le16(0x4100);
+ packet_mod_duration->duration = cpu_to_le16(duration);
- ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ 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, u8 *send_buffer)
+static int t300rs_update_constant(struct t300rs_device_entry *t300rs,
+ struct tmff2_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;
- int ret, trans;
- s16 level;
+ struct __packed t300rs_packet_mod_constant {
+ struct t300rs_packet_header header;
+ uint16_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) {
- send_buffer[1] = effect.id + 1;
- send_buffer[2] = 0x0a;
-
- send_buffer[3] = level & 0xff;
- send_buffer[4] = level >> 8;
+ t300rs_fill_header(&packet_mod_constant->header, effect.id, 0x0a);
+ packet_mod_constant->level = cpu_to_le16(level);
- ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ ret = t300rs_send_int(t300rs);
if (ret) {
hid_err(t300rs->hdev, "failed modifying constant effect\n");
goto error;
@@ -255,42 +582,48 @@ static int t300rs_modify_constant(struct t300rs_device_entry *t300rs,
}
- ret = t300rs_modify_envelope(t300rs,
+ ret = t300rs_update_envelope(t300rs,
state,
- send_buffer,
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, send_buffer);
+ ret = t300rs_update_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, u8 *send_buffer)
+static int t300rs_update_ramp(struct t300rs_device_entry *t300rs,
+ struct tmff2_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;
- int ret, trans;
+ 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;
- u16 difference, top, bottom;
- s16 level;
+ 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;
@@ -303,17 +636,12 @@ static int t300rs_modify_ramp(struct t300rs_device_entry *t300rs,
if (ramp.start_level != ramp_old.start_level || ramp.end_level != ramp_old.end_level) {
- send_buffer[1] = effect.id + 1;
- send_buffer[2] = 0x0e;
- send_buffer[3] = 0x03;
+ 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);
- send_buffer[4] = difference & 0xff;
- send_buffer[5] = difference >> 8;
-
- send_buffer[6] = level & 0xff;
- send_buffer[7] = level >> 8;
-
- ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ ret = t300rs_send_int(t300rs);
if (ret) {
hid_err(t300rs->hdev, "failed modifying ramp effect\n");
goto error;
@@ -321,9 +649,8 @@ static int t300rs_modify_ramp(struct t300rs_device_entry *t300rs,
}
- ret = t300rs_modify_envelope(t300rs,
+ ret = t300rs_update_envelope(t300rs,
state,
- send_buffer,
level,
effect.replay.length,
effect.id,
@@ -331,29 +658,37 @@ static int t300rs_modify_ramp(struct t300rs_device_entry *t300rs,
ramp_old.envelope
);
+
if (ret) {
hid_err(t300rs->hdev, "failed modifying ramp envelope\n");
goto error;
}
- ret = t300rs_modify_duration(t300rs, state, send_buffer);
+ ret = t300rs_update_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, u8 *send_buffer)
+
+static int t300rs_update_damper(struct t300rs_device_entry *t300rs,
+ struct tmff2_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];
- int ret, trans, input_level;
+ 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)
@@ -363,17 +698,13 @@ static int t300rs_modify_damper(struct t300rs_device_entry *t300rs,
input_level = spring_level;
if (damper.right_coeff != damper_old.right_coeff) {
- s16 coeff = damper.right_coeff * input_level / 100;
+ 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);
- send_buffer[1] = effect.id + 1;
- send_buffer[2] = 0x0e;
- send_buffer[3] = 0x41;
-
- send_buffer[4] = coeff & 0xff;
- send_buffer[5] = coeff >> 8;
-
- ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ ret = t300rs_send_int(t300rs);
if (ret) {
hid_err(t300rs->hdev, "failed modifying damper rc\n");
goto error;
@@ -382,17 +713,13 @@ static int t300rs_modify_damper(struct t300rs_device_entry *t300rs,
}
if (damper.left_coeff != damper_old.left_coeff) {
- s16 coeff = damper.left_coeff * input_level / 100;
-
+ int16_t coeff = damper.left_coeff * input_level / 100;
- send_buffer[1] = effect.id + 1;
- send_buffer[2] = 0x0e;
- send_buffer[3] = 0x42;
+ t300rs_fill_header(&packet_mod_damper->header, effect.id, 0x0e);
+ packet_mod_damper->attribute = 0x42;
+ packet_mod_damper->value0 = cpu_to_le16(coeff);
- send_buffer[4] = coeff & 0xff;
- send_buffer[5] = coeff >> 8;
-
- ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ ret = t300rs_send_int(t300rs);
if (ret) {
hid_err(t300rs->hdev, "failed modifying damper lc\n");
goto error;
@@ -400,23 +727,18 @@ static int t300rs_modify_damper(struct t300rs_device_entry *t300rs,
}
- if ((damper.deadband != damper_old.deadband) ||
- (damper.center != damper_old.center)) {
- u16 deadband_right = 0xfffe - damper.deadband - damper.center;
- u16 deadband_left = 0xfffe - damper.deadband + damper.center;
-
-
- send_buffer[1] = effect.id + 1;
- send_buffer[2] = 0x0e;
- send_buffer[3] = 0x4c;
+ if ((damper.deadband != damper_old.deadband)
+ || (damper.center != damper_old.center)) {
- send_buffer[4] = deadband_right & 0xff;
- send_buffer[5] = deadband_right >> 8;
+ uint16_t right_deadband = 0xfffe - damper.deadband - damper.center;
+ uint16_t left_deadband = 0xfffe - damper.deadband + damper.center;
- send_buffer[6] = deadband_left & 0xff;
- send_buffer[7] = deadband_left >> 8;
+ 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->input_dev, send_buffer, &trans);
+ ret = t300rs_send_int(t300rs);
if (ret) {
hid_err(t300rs->hdev, "failed modifying damper deadband\n");
goto error;
@@ -424,41 +746,58 @@ static int t300rs_modify_damper(struct t300rs_device_entry *t300rs,
}
- ret = t300rs_modify_duration(t300rs, state, send_buffer);
+ ret = t300rs_update_duration(t300rs, state);
if (ret) {
hid_err(t300rs->hdev, "failed modifying damper duration\n");
goto error;
}
error:
-
return ret;
}
+static int t300rs_update_spring(struct t300rs_device_entry *t300rs,
+ struct tmff2_effect_state *state)
+{
+ return t300rs_update_damper(t300rs, state);
+}
+
-static int t300rs_modify_periodic(struct t300rs_device_entry *t300rs,
- struct t300rs_effect_state *state, u8 *send_buffer)
+static int t300rs_update_periodic(struct t300rs_device_entry *t300rs,
+ struct tmff2_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;
- int ret, trans;
- s16 level;
+ 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;
- level = (periodic.magnitude * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff;
+ int ret;
+ int16_t magnitude;
+ uint16_t phase;
+ bool update_phase = false;
+ magnitude = (periodic.magnitude * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff;
+ phase = periodic.phase;
+ if(magnitude < 0){
+ phase += 0x4000;
+ phase = phase < 0 ? -phase : phase;
+ update_phase = true;
+ }
- if (periodic.magnitude != periodic_old.magnitude) {
+ magnitude = magnitude < 0 ? -magnitude : magnitude;
- send_buffer[1] = effect.id + 1;
- send_buffer[2] = 0x0e;
- send_buffer[3] = 0x01;
+ if (periodic.magnitude != periodic_old.magnitude) {
- send_buffer[4] = level & 0xff;
- send_buffer[5] = level >> 8;
+ t300rs_fill_header(&packet_mod_periodic->header, effect.id, 0x0e);
+ packet_mod_periodic->attribute = 0x01;
+ packet_mod_periodic->value = cpu_to_le16(magnitude);
- ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ ret = t300rs_send_int(t300rs);
if (ret) {
hid_err(t300rs->hdev, "failed modifying periodic magnitude\n");
goto error;
@@ -467,17 +806,13 @@ static int t300rs_modify_periodic(struct t300rs_device_entry *t300rs,
}
if (periodic.offset != periodic_old.offset) {
- s16 offset = periodic.offset;
-
-
- send_buffer[1] = effect.id + 1;
- send_buffer[2] = 0x0e;
- send_buffer[3] = 0x02;
+ int16_t offset = periodic.offset;
- send_buffer[4] = offset & 0xff;
- send_buffer[5] = offset >> 8;
+ 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->input_dev, send_buffer, &trans);
+ ret = t300rs_send_int(t300rs);
if (ret) {
hid_err(t300rs->hdev, "failed modifying periodic offset\n");
goto error;
@@ -485,18 +820,13 @@ static int t300rs_modify_periodic(struct t300rs_device_entry *t300rs,
}
- if (periodic.phase != periodic_old.phase) {
- s16 phase = periodic.phase;
+ if (periodic.phase != periodic_old.phase || update_phase) {
+ t300rs_fill_header(&packet_mod_periodic->header, effect.id, 0x0e);
+ packet_mod_periodic->attribute = 0x04;
+ packet_mod_periodic->value = cpu_to_le16(phase);
- send_buffer[1] = effect.id + 1;
- send_buffer[2] = 0x0e;
- send_buffer[3] = 0x04;
-
- send_buffer[4] = phase & 0xff;
- send_buffer[5] = phase >> 8;
-
- ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ ret = t300rs_send_int(t300rs);
if (ret) {
hid_err(t300rs->hdev, "failed modifying periodic phase\n");
goto error;
@@ -505,17 +835,13 @@ static int t300rs_modify_periodic(struct t300rs_device_entry *t300rs,
}
if (periodic.period != periodic_old.period) {
- s16 period = periodic.period;
-
+ int16_t period = periodic.period;
- send_buffer[1] = effect.id + 1;
- send_buffer[2] = 0x0e;
- send_buffer[3] = 0x08;
+ t300rs_fill_header(&packet_mod_periodic->header, effect.id, 0x0e);
+ packet_mod_periodic->attribute = 0x08;
+ packet_mod_periodic->value = cpu_to_le16(period);
- send_buffer[4] = period & 0xff;
- send_buffer[5] = period >> 8;
-
- ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ ret = t300rs_send_int(t300rs);
if (ret) {
hid_err(t300rs->hdev, "failed modifying periodic period\n");
goto error;
@@ -523,84 +849,62 @@ static int t300rs_modify_periodic(struct t300rs_device_entry *t300rs,
}
- ret = t300rs_modify_envelope(t300rs,
+ ret = t300rs_update_envelope(t300rs,
state,
- send_buffer,
- level,
+ magnitude,
effect.replay.length,
effect.id,
periodic.envelope,
- periodic_old.envelope);
+ periodic_old.envelope
+ );
+
if (ret) {
hid_err(t300rs->hdev, "failed modifying periodic envelope\n");
goto error;
}
- ret = t300rs_modify_duration(t300rs, state, send_buffer);
+ ret = t300rs_update_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 tmff2_effect_state *state)
{
- u8 *send_buffer = t300rs->send_buffer;
struct ff_effect effect = state->effect;
struct ff_constant_effect constant = state->effect.u.constant;
- s16 level;
- u16 duration, offset;
+ struct __packed t300rs_packet_constant {
+ struct t300rs_packet_header header;
+ uint16_t level;
+ struct t300rs_packet_envelope envelope;
+ uint8_t zero;
+ struct t300rs_packet_timing timing;
+ } *packet_constant = (struct t300rs_packet_constant *)t300rs->send_buffer;
- int ret, trans;
+ int16_t level;
+ uint16_t duration, offset;
- /* 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, send_buffer);
- }
+ int ret;
level = (constant.level * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff;
- if (effect.replay.length == 0)
- duration = 0xffff;
- else
- duration = effect.replay.length;
+ duration = effect.replay.length - 1;
offset = effect.replay.delay;
+ t300rs_fill_header(&packet_constant->header, effect.id, 0x6a);
- send_buffer[1] = effect.id + 1;
- send_buffer[2] = 0x6a;
-
- send_buffer[3] = level & 0xff;
- send_buffer[4] = level >> 8;
-
- t300rs_fill_envelope(send_buffer, 5, level,
- duration, &constant.envelope);
+ packet_constant->level = cpu_to_le16(level);
- send_buffer[14] = 0x4f;
+ t300rs_fill_envelope(&packet_constant->envelope, level, duration,
+ &constant.envelope);
+ t300rs_fill_timing(&packet_constant->timing, duration, offset);
- send_buffer[15] = duration & 0xff;
- send_buffer[16] = duration >> 8;
-
- send_buffer[19] = offset & 0xff;
- send_buffer[20] = offset >> 8;
-
- send_buffer[22] = 0xff;
- send_buffer[23] = 0xff;
-
- ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ ret = t300rs_send_int(t300rs);
if (ret)
hid_err(t300rs->hdev, "failed uploading constant effect\n");
@@ -608,27 +912,27 @@ static int t300rs_upload_constant(struct t300rs_device_entry *t300rs,
}
static int t300rs_upload_ramp(struct t300rs_device_entry *t300rs,
- struct t300rs_effect_state *state)
+ struct tmff2_effect_state *state)
{
- u8 *send_buffer = t300rs->send_buffer;
struct ff_effect effect = state->effect;
struct ff_ramp_effect ramp = state->effect.u.ramp;
- int ret, trans;
- u16 difference, offset, top, bottom, duration;
- s16 level;
+ struct __packed t300rs_packet_ramp {
+ struct t300rs_packet_header header;
+ uint16_t difference;
+ uint16_t level;
+ uint8_t zero1[2];
+ uint16_t duration;
+ uint16_t marker;
+ struct t300rs_packet_envelope envelope;
+ uint8_t direction;
+ struct t300rs_packet_timing timing;
+ } *packet_ramp = (struct t300rs_packet_ramp *)t300rs->send_buffer;
- 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, send_buffer);
- }
+ int ret;
+ uint16_t difference, offset, top, bottom, duration;
+ int16_t level;
- if (effect.replay.length == 0)
- duration = 0xffff;
- else
- duration = effect.replay.length;
+ 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;
@@ -639,36 +943,21 @@ static int t300rs_upload_ramp(struct t300rs_device_entry *t300rs,
offset = effect.replay.delay;
- send_buffer[1] = effect.id + 1;
- send_buffer[2] = 0x6b;
-
- send_buffer[3] = difference & 0xff;
- send_buffer[4] = difference >> 8;
-
- send_buffer[5] = level & 0xff;
- send_buffer[6] = level >> 8;
-
- send_buffer[9] = duration & 0xff;
- send_buffer[10] = duration >> 8;
-
- send_buffer[12] = 0x80;
+ t300rs_fill_header(&packet_ramp->header, effect.id, 0x6b);
- t300rs_fill_envelope(send_buffer, 13, level,
- effect.replay.length, &ramp.envelope);
+ packet_ramp->difference = cpu_to_le16(difference);
+ packet_ramp->level = cpu_to_le16(level);
+ packet_ramp->duration = cpu_to_le16(duration);
- send_buffer[22] = ramp.end_level > ramp.start_level ? 0x04 : 0x05;
- send_buffer[23] = 0x4f;
+ packet_ramp->marker = cpu_to_le16(0x8000);
- send_buffer[24] = duration & 0xff;
- send_buffer[25] = duration >> 8;
+ t300rs_fill_envelope(&packet_ramp->envelope, level, duration,
+ &ramp.envelope);
- send_buffer[28] = offset & 0xff;
- send_buffer[29] = offset >> 8;
+ packet_ramp->direction = ramp.end_level > ramp.start_level ? 0x04 : 0x05;
+ t300rs_fill_timing(&packet_ramp->timing, duration, offset);
- send_buffer[31] = 0xff;
- send_buffer[32] = 0xff;
-
- ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ ret = t300rs_send_int(t300rs);
if (ret)
hid_err(t300rs->hdev, "failed uploading ramp");
@@ -676,64 +965,45 @@ static int t300rs_upload_ramp(struct t300rs_device_entry *t300rs,
}
static int t300rs_upload_spring(struct t300rs_device_entry *t300rs,
- struct t300rs_effect_state *state)
+ struct tmff2_effect_state *state)
{
- u8 *send_buffer = t300rs->send_buffer;
struct ff_effect effect = state->effect;
/* we only care about the first axis */
struct ff_condition_effect spring = state->effect.u.condition[0];
- int ret, trans;
- u16 duration, right_coeff, left_coeff, deadband_right, deadband_left, 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);
+ 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_timing timing;
+ } *packet_spring = (struct t300rs_packet_spring *)t300rs->send_buffer;
- return t300rs_modify_damper(t300rs, state, send_buffer);
- }
-
- if (effect.replay.length == 0)
- duration = 0xffff;
- else
- duration = effect.replay.length;
+ int ret;
+ uint16_t duration, right_coeff, left_coeff, right_deadband, left_deadband, offset;
- send_buffer[1] = effect.id + 1;
- send_buffer[2] = 0x64;
+ duration = effect.replay.length - 1;
right_coeff = spring.right_coeff * spring_level / 100;
left_coeff = spring.left_coeff * spring_level / 100;
- deadband_right = 0xfffe - spring.deadband - spring.center;
- deadband_left = 0xfffe - spring.deadband + spring.center;
+ right_deadband = 0xfffe - spring.deadband - spring.center;
+ left_deadband = 0xfffe - spring.deadband + spring.center;
offset = effect.replay.delay;
- send_buffer[3] = right_coeff & 0xff;
- send_buffer[4] = right_coeff >> 8;
-
- send_buffer[5] = left_coeff & 0xff;
- send_buffer[6] = left_coeff >> 8;
-
- send_buffer[7] = deadband_right & 0xff;
- send_buffer[8] = deadband_right >> 8;
-
- send_buffer[9] = deadband_left & 0xff;
- send_buffer[10] = deadband_left >> 8;
-
- memcpy(&send_buffer[11], spring_values, ARRAY_SIZE(spring_values));
- send_buffer[28] = 0x4f;
-
- send_buffer[29] = duration & 0xff;
- send_buffer[30] = duration >> 8;
+ t300rs_fill_header(&packet_spring->header, effect.id, 0x64);
- send_buffer[33] = offset & 0xff;
- send_buffer[34] = offset >> 8;
+ packet_spring->right_coeff = cpu_to_le16(right_coeff);
+ packet_spring->left_coeff = cpu_to_le16(left_coeff);
+ packet_spring->right_deadband = cpu_to_le16(right_deadband);
+ packet_spring->left_deadband = cpu_to_le16(left_deadband);
- send_buffer[36] = 0xff;
- send_buffer[37] = 0xff;
+ memcpy(&packet_spring->spring_start, spring_values, ARRAY_SIZE(spring_values));
+ t300rs_fill_timing(&packet_spring->timing, duration, offset);
- ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ ret = t300rs_send_int(t300rs);
if (ret)
hid_err(t300rs->hdev, "failed uploading spring\n");
@@ -741,69 +1011,50 @@ static int t300rs_upload_spring(struct t300rs_device_entry *t300rs,
}
static int t300rs_upload_damper(struct t300rs_device_entry *t300rs,
- struct t300rs_effect_state *state)
+ struct tmff2_effect_state *state)
{
- u8 *send_buffer = t300rs->send_buffer;
+
struct ff_effect effect = state->effect;
/* we only care about the first axis */
struct ff_condition_effect spring = state->effect.u.condition[0];
- int ret, trans, input_level;
- u16 duration, right_coeff, left_coeff, deadband_right, deadband_left, 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);
+ 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;
+ uint8_t damper_start[17];
+ struct t300rs_packet_timing timing;
+ } *packet_damper = (struct t300rs_packet_damper *)t300rs->send_buffer;
- return t300rs_modify_damper(t300rs, state, send_buffer);
- }
+ int ret, input_level;
+ uint16_t duration, right_coeff, left_coeff, right_deadband, left_deadband, offset;
- if (effect.replay.length == 0)
- duration = 0xffff;
- else
- duration = effect.replay.length;
+ duration = effect.replay.length - 1;
input_level = damper_level;
if (state->effect.type == FF_FRICTION)
input_level = friction_level;
-
- send_buffer[1] = effect.id + 1;
- send_buffer[2] = 0x64;
-
right_coeff = spring.right_coeff * input_level / 100;
left_coeff = spring.left_coeff * input_level / 100;
- deadband_right = 0xfffe - spring.deadband - spring.center;
- deadband_left = 0xfffe - spring.deadband + spring.center;
+ right_deadband = 0xfffe - spring.deadband - spring.center;
+ left_deadband = 0xfffe - spring.deadband + spring.center;
offset = effect.replay.delay;
- send_buffer[3] = right_coeff & 0xff;
- send_buffer[4] = right_coeff >> 8;
-
- send_buffer[5] = left_coeff & 0xff;
- send_buffer[6] = left_coeff >> 8;
-
- send_buffer[7] = deadband_right & 0xff;
- send_buffer[8] = deadband_right >> 8;
-
- send_buffer[9] = deadband_left & 0xff;
- send_buffer[10] = deadband_left >> 8;
-
- memcpy(&send_buffer[11], damper_values, ARRAY_SIZE(damper_values));
- send_buffer[28] = 0x4f;
-
- send_buffer[29] = duration & 0xff;
- send_buffer[30] = duration >> 8;
+ t300rs_fill_header(&packet_damper->header, effect.id, 0x64);
- send_buffer[33] = offset & 0xff;
- send_buffer[34] = offset >> 8;
+ packet_damper->right_coeff = cpu_to_le16(right_coeff);
+ packet_damper->left_coeff = cpu_to_le16(left_coeff);
+ packet_damper->right_deadband = cpu_to_le16(right_deadband);
+ packet_damper->left_deadband = cpu_to_le16(left_deadband);
- send_buffer[36] = 0xff;
- send_buffer[37] = 0xff;
+ memcpy(&packet_damper->damper_start, damper_values, ARRAY_SIZE(damper_values));
+ t300rs_fill_timing(&packet_damper->timing, duration, offset);
- ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ ret = t300rs_send_int(t300rs);
if (ret)
hid_err(t300rs->hdev, "failed uploading spring\n");
@@ -811,804 +1062,589 @@ static int t300rs_upload_damper(struct t300rs_device_entry *t300rs,
}
static int t300rs_upload_periodic(struct t300rs_device_entry *t300rs,
- struct t300rs_effect_state *state)
+ struct tmff2_effect_state *state)
{
- u8 *send_buffer = t300rs->send_buffer;
struct ff_effect effect = state->effect;
struct ff_periodic_effect periodic = state->effect.u.periodic;
- int ret, trans;
- u16 duration, magnitude, phase, period, offset;
- s16 periodic_offset;
+ struct __packed t300rs_packet_periodic {
+ struct t300rs_packet_header header;
+ uint16_t magnitude;
+ uint16_t periodic_offset;
+ uint16_t phase;
+ uint16_t period;
+ uint16_t marker;
+ struct t300rs_packet_envelope envelope;
+ uint8_t waveform;
+ struct t300rs_packet_timing timing;
+ } *packet_periodic = (struct t300rs_packet_periodic *)t300rs->send_buffer;
- 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, send_buffer);
- }
+ int ret;
+ uint16_t duration, magnitude, period, offset;
+ int16_t periodic_offset, phase;
- if (effect.replay.length == 0)
- duration = 0xffff;
- else
- duration = effect.replay.length;
+ duration = effect.replay.length - 1;
magnitude = (periodic.magnitude * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff;
phase = periodic.phase;
+ if(magnitude < 0){
+ phase += 0x4000;
+ phase = phase < 0 ? -phase : phase;
+ }
+
+ magnitude = magnitude < 0 ? -magnitude : magnitude;
periodic_offset = periodic.offset;
period = periodic.period;
offset = effect.replay.delay;
+ t300rs_fill_header(&packet_periodic->header, effect.id, 0x6b);
- send_buffer[1] = effect.id + 1;
- send_buffer[2] = 0x6b;
-
- send_buffer[3] = magnitude & 0xff;
- send_buffer[4] = magnitude >> 8;
-
- send_buffer[7] = phase & 0xff;
- send_buffer[8] = phase >> 8;
-
- send_buffer[5] = periodic_offset & 0xff;
- send_buffer[6] = periodic_offset >> 8;
-
- send_buffer[9] = period & 0xff;
- send_buffer[10] = period >> 8;
-
- send_buffer[12] = 0x80;
+ packet_periodic->magnitude = cpu_to_le16(magnitude);
+ packet_periodic->periodic_offset = cpu_to_le16(periodic_offset);
+ packet_periodic->phase = cpu_to_le16(phase);
+ packet_periodic->period = cpu_to_le16(period);
- t300rs_fill_envelope(send_buffer, 13, magnitude,
- effect.replay.length, &periodic.envelope);
+ packet_periodic->marker = cpu_to_le16(0x8000);
- send_buffer[21] = periodic.waveform - 0x57;
- send_buffer[22] = 0x4f;
+ t300rs_fill_envelope(&packet_periodic->envelope, magnitude, duration,
+ &periodic.envelope);
- send_buffer[23] = duration & 0xff;
- send_buffer[24] = duration >> 8;
+ packet_periodic->waveform = periodic.waveform - 0x57;
- send_buffer[27] = offset & 0xff;
- send_buffer[28] = offset >> 8;
+ t300rs_fill_timing(&packet_periodic->timing, duration, offset);
- send_buffer[30] = 0xff;
- send_buffer[31] = 0xff;
-
- ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ 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)
+int t300rs_update_effect(void *data, struct tmff2_effect_state *state)
{
+ struct t300rs_device_entry *t300rs = data;
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;
+ case FF_CONSTANT:
+ return t300rs_update_constant(t300rs, state);
+ case FF_RAMP:
+ return t300rs_update_ramp(t300rs, state);
+ case FF_SPRING:
+ return t300rs_update_spring(t300rs, state);
+ case FF_DAMPER:
+ case FF_FRICTION:
+ case FF_INERTIA:
+ return t300rs_update_damper(t300rs, state);
+ case FF_PERIODIC:
+ return t300rs_update_periodic(t300rs, state);
+ default:
+ hid_err(t300rs->hdev, "invalid effect type: %x", state->effect.type);
+ return -1;
}
-
- return max_count;
}
-static enum hrtimer_restart t300rs_timer(struct hrtimer *t)
+int t300rs_upload_effect(void *data, struct tmff2_effect_state *state)
{
- 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;
+ struct t300rs_device_entry *t300rs = data;
+ 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_upload(struct input_dev *dev,
- struct ff_effect *effect, struct ff_effect *old)
+static int t300rs_switch_mode(void *data, uint16_t mode)
{
- 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;
+ struct t300rs_device_entry *t300rs = data;
+ if (!t300rs)
+ return -ENODEV;
- state = &t300rs->states[effect->id];
-
- spin_lock_irqsave(&t300rs->lock, t300rs->lock_flags);
-
- state->effect = *effect;
+ if(t300rs->mode == mode) /* already in specified mode */
+ return 0;
- 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);
+ if (mode == 0)
+ /* go to normal mode */
+ usb_control_msg(t300rs->usbdev,
+ usb_sndctrlpipe(t300rs->usbdev, 0),
+ 83, 0x41, 5, 0, 0, 0,
+ USB_CTRL_SET_TIMEOUT
+ );
+ else if (mode == 1)
+ /* go to advanced mode */
+ usb_control_msg(t300rs->usbdev,
+ usb_sndctrlpipe(t300rs->usbdev, 0),
+ 83, 0x41, 3, 0, 0, 0,
+ USB_CTRL_SET_TIMEOUT
+ );
+ else
+ hid_warn(t300rs->hdev, "mode %i not supported\n", mode);
- 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;
- }
+static struct t300rs_alt_modes {
+ char *id;
+ char *label;
+ uint16_t mode;
+} t300rs_modes[] = {
+ {"base", "T300RS base", 0},
+ {"F1", "T300RS with F1 wheel attachment", 1}
+};
- state = &t300rs->states[effect_id];
+static ssize_t t300rs_alt_mode_show(void *data, char *buf)
+{
+ struct t300rs_device_entry *t300rs = data;
+ ssize_t count = 0;
+ int i;
+ if (!t300rs)
+ return -ENODEV;
- if (&state->effect == 0)
- return 0;
+ if (t300rs->attachment != T300RS_F1_ATTACHMENT)
+ /* we only support one base mode */
+ return scnprintf(buf, PAGE_SIZE, "%s: %s *\n",
+ t300rs_modes[0].id, t300rs_modes[0].label);
- spin_lock_irqsave(&t300rs->lock, t300rs->lock_flags);
+ for (i = 0; i < ARRAY_SIZE(t300rs_modes); ++i) {
+ count += scnprintf(buf + count, PAGE_SIZE - count, "%s: %s",
+ t300rs_modes[i].id, t300rs_modes[i].label);
- if (value > 0) {
- state->count = value;
- state->start_time = JIFFIES2MS(jiffies);
- __set_bit(FF_EFFECT_QUEUE_START, &state->flags);
+ if (count >= PAGE_SIZE - 1)
+ return count;
- if (test_bit(FF_EFFECT_QUEUE_STOP, &state->flags))
- __clear_bit(FF_EFFECT_QUEUE_STOP, &state->flags);
+ if (t300rs_modes[i].mode == t300rs->mode)
+ count += scnprintf(buf + count, PAGE_SIZE - count, " *\n");
+ else
+ count += scnprintf(buf + count, PAGE_SIZE - count, "\n");
- } else {
- __set_bit(FF_EFFECT_QUEUE_STOP, &state->flags);
+ if (count >= PAGE_SIZE - 1)
+ return count;
}
- 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;
+ return count;
}
-static ssize_t spring_level_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t t300rs_alt_mode_store(void *data, 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;
- }
+ struct t300rs_device_entry *t300rs = data;
+ int i, len, mode_len;
+ char *lbuf;
+ if (!t300rs)
+ return -ENODEV;
- if (value > 100)
- value = 100;
+ if (t300rs->attachment != T300RS_F1_ATTACHMENT)
+ return count; /* don't do anything */
- spring_level = value;
+ lbuf = kasprintf(GFP_KERNEL, "%s", buf);
+ if (!lbuf)
+ return -ENOMEM;
- return count;
-}
-static ssize_t spring_level_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- size_t count;
+ len = strlen(buf);
+ for (i = 0; i < ARRAY_SIZE(t300rs_modes); ++i) {
+ mode_len = strlen(t300rs_modes[i].id);
+ if (mode_len > len)
+ continue;
- count = scnprintf(buf, PAGE_SIZE, "%u\n", spring_level);
+ if (strncmp(lbuf, t300rs_modes[i].id, mode_len) == 0) {
+ t300rs_switch_mode(data, t300rs_modes[i].mode);
+ break;
+ }
+ }
+ kfree(lbuf);
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)
+int t300rs_set_autocenter(void *data, uint16_t value)
{
- struct hid_device *hdev = to_hid_device(dev);
- unsigned int value;
- int ret;
+ struct t300rs_device_entry *t300rs = data;
+ struct __packed t300rs_packet_autocenter {
+ struct t300rs_setup_header header;
+ uint16_t value;
+ } *autocenter_packet;
+ int ret;
- ret = kstrtouint(buf, 0, &value);
- if (ret) {
- hid_err(hdev, "kstrtouint failed at damper_level_store: %i", ret);
- return ret;
- }
+ if (!t300rs)
+ return -ENODEV;
- if (value > 100)
- value = 100;
+ /* TODO: this should probably also use a separately allocated buffer? */
+ autocenter_packet = (struct t300rs_packet_autocenter *)t300rs->send_buffer;
- damper_level = value;
+ autocenter_packet->header.cmd = 0x08;
+ autocenter_packet->header.code = 0x04;
+ autocenter_packet->value = cpu_to_le16(0x01);
- return count;
-}
+ if ((ret = t300rs_send_int(t300rs))) {
+ hid_err(t300rs->hdev, "failed setting autocenter");
+ return ret;
+ }
-static ssize_t damper_level_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- size_t count;
+ autocenter_packet->header.cmd = 0x08;
+ autocenter_packet->header.code = 0x03;
- count = scnprintf(buf, PAGE_SIZE, "%u\n", damper_level);
+ autocenter_packet->value = cpu_to_le16(value);
- return count;
-}
+ if ((ret = t300rs_send_int(t300rs)))
+ hid_err(t300rs->hdev, "failed setting autocenter");
-static DEVICE_ATTR_RW(damper_level);
+ return ret;
+}
-static ssize_t friction_level_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+int t300rs_set_gain(void *data, uint16_t gain)
{
- 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;
+ struct t300rs_device_entry *t300rs = data;
+ struct __packed t300rs_packet_gain {
+ struct t300rs_setup_header header;
+ } *gain_packet;
+ int ret;
- friction_level = value;
+ if (!t300rs)
+ return -ENODEV;
- return count;
-}
-static ssize_t friction_level_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- size_t count;
+ gain_packet = (struct t300rs_packet_gain *)t300rs->send_buffer;
+ gain_packet->header.cmd = 0x02;
+ gain_packet->header.code = (gain >> 8) & 0xff;
- count = scnprintf(buf, PAGE_SIZE, "%u\n", friction_level);
+ if ((ret = t300rs_send_int(t300rs)))
+ hid_err(t300rs->hdev, "failed setting gain: %i\n", ret);
- return count;
+ return ret;
}
-static DEVICE_ATTR_RW(friction_level);
-
-static ssize_t range_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+int t300rs_set_range(void *data, uint16_t value)
{
- struct hid_device *hdev = to_hid_device(dev);
- struct t300rs_device_entry *t300rs;
- u8 *send_buffer;
- unsigned int range;
- int ret, trans;
-
- ret = kstrtouint(buf, 0, &range);
- if (ret) {
- hid_err(hdev, "kstrtouint failed at range_store: %i", ret);
- return ret;
- }
+ struct t300rs_device_entry *t300rs = data;
+ /* it's important that we don't use t300rs->send_buffer, as range can be
+ * set from outside of the FFB environment, and we don't want to
+ * accidentally overwrite any data. */
+ u8 *send_buffer = kzalloc(t300rs->buffer_length, GFP_KERNEL);
+ uint16_t scaled_value;
+ int ret;
- t300rs = t300rs_get_device(hdev);
- if (!t300rs) {
- hid_err(hdev, "could not get device\n");
- return -1;
+ if (value < 40) {
+ hid_info(t300rs->hdev, "value %i too small, clamping to 40\n", value);
+ value = 40;
}
- send_buffer = t300rs->send_buffer;
-
- if (range < 40)
- range = 40;
-
- if (range > 1080)
- range = 1080;
-
- range *= 0x3c;
+ if (value > 1080) {
+ hid_info(t300rs->hdev, "value %i too large, clamping to 1080\n", value);
+ value = 1080;
+ }
+ if (!send_buffer) {
+ ret = -EINVAL;
+ hid_err(t300rs->hdev, "could not allocate send_buffer\n");
+ goto err;
+ }
+ scaled_value = value * 0x3c;
send_buffer[0] = 0x08;
send_buffer[1] = 0x11;
- send_buffer[2] = range & 0xff;
- send_buffer[3] = range >> 8;
-
- ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
- if (ret) {
- hid_err(hdev, "failed sending interrupts\n");
- return -1;
- }
+ send_buffer[2] = scaled_value & 0xff;
+ send_buffer[3] = scaled_value >> 8;
- t300rs->range = range / 0x3c;
+ if ((ret = t300rs_send_buf(t300rs, send_buffer, t300rs->buffer_length)))
+ hid_warn(t300rs->hdev, "failed setting range\n");
- 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;
+ /* since everythin went OK, update the current range */
+ range = value;
+err:
+ kfree(send_buffer);
+ return ret;
}
-static DEVICE_ATTR_RW(range);
-
-static void t300rs_set_autocenter(struct input_dev *dev, u16 value)
+int t300rs_open(void *data)
{
- struct hid_device *hdev = input_get_drvdata(dev);
- struct t300rs_device_entry *t300rs;
- u8 *send_buffer;
- int ret, trans;
-
- t300rs = t300rs_get_device(hdev);
- if (!t300rs) {
- hid_err(hdev, "could not get device\n");
- return;
- }
-
- send_buffer = t300rs->send_buffer;
-
- send_buffer[0] = 0x08;
- send_buffer[1] = 0x04;
- send_buffer[2] = 0x01;
+ struct t300rs_device_entry *t300rs = data;
+ struct __packed t300rs_packet_open {
+ struct t300rs_setup_header header;
+ } *open_packet;
- ret = t300rs_send_int(dev, send_buffer, &trans);
- if (ret) {
- hid_err(hdev, "failed setting autocenter");
- return;
- }
+ if (!t300rs)
+ return -ENODEV;
- send_buffer[0] = 0x08;
- send_buffer[1] = 0x03;
+ open_packet = (struct t300rs_packet_open *)t300rs->send_buffer;
+ open_packet->header.cmd = 0x01;
+ open_packet->header.code = 0x05;
- send_buffer[2] = value & 0xff;
- send_buffer[3] = value >> 8;
+ if (t300rs_send_int(t300rs))
+ hid_warn(t300rs->hdev, "failed sending open command\n");
- ret = t300rs_send_int(dev, send_buffer, &trans);
- if (ret)
- hid_err(hdev, "failed setting autocenter");
+ return t300rs->open(t300rs->input_dev);
}
-static void t300rs_set_gain(struct input_dev *dev, u16 gain)
+int t300rs_close(void *data)
{
- struct hid_device *hdev = input_get_drvdata(dev);
- struct t300rs_device_entry *t300rs;
- u8 *send_buffer;
- int ret, trans;
+ struct t300rs_device_entry *t300rs = data;
+ 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;
- }
+ if (!t300rs)
+ return -ENODEV;
- send_buffer = t300rs->send_buffer;
- send_buffer[0] = 0x02;
- send_buffer[1] = SCALE_VALUE_U16(gain, 8);
+ close_packet = (struct t300rs_packet_close *)t300rs->send_buffer;
+ close_packet->header.cmd = 0x01;
- ret = t300rs_send_int(dev, send_buffer, &trans);
- if (ret)
- hid_err(hdev, "failed setting gain: %i\n", ret);
-}
+ if ((ret = t300rs_send_int(t300rs)))
+ hid_warn(t300rs->hdev, "failed sending close command\n");
-static void t300rs_destroy(struct ff_device *ff)
-{
- // maybe not necessary?
+ t300rs->close(t300rs->input_dev);
+ return ret;
}
-static int t300rs_open(struct input_dev *dev)
+static int t300rs_check_firmware(struct t300rs_device_entry *t300rs)
{
- struct t300rs_device_entry *t300rs;
- struct hid_device *hdev = input_get_drvdata(dev);
- u8 *send_buffer;
- int ret, trans;
+ int ret;
+ struct t300rs_fw_response *fw_response =
+ kzalloc(sizeof(struct t300rs_fw_response), GFP_KERNEL);
- t300rs = t300rs_get_device(hdev);
- if (!t300rs) {
- hid_err(hdev, "could not get device\n");
- return -1;
+ if (!fw_response) {
+ hid_err(t300rs->hdev, "could not allocate fw_response\n");
+ return -ENOMEM;
}
- send_buffer = t300rs->send_buffer;
-
- send_buffer[0] = 0x01;
- send_buffer[1] = 0x05;
+ /* Fetch firmware version */
+ ret = usb_control_msg(t300rs->usbdev,
+ usb_rcvctrlpipe(t300rs->usbdev, 0),
+ t300rs_fw_request.bRequest,
+ t300rs_fw_request.bRequestType,
+ t300rs_fw_request.wValue,
+ t300rs_fw_request.wIndex,
+ fw_response,
+ t300rs_fw_request.wLength,
+ USB_CTRL_SET_TIMEOUT
+ );
- ret = t300rs_send_int(dev, send_buffer, &trans);
- if (ret) {
- hid_err(hdev, "failed sending interrupts\n");
- goto err;
+ if (ret < 0) {
+ hid_err(t300rs->hdev, "could not fetch firmware version: %i\n", ret);
+ goto out;
}
-err:
- return t300rs->open(dev);
-}
+ /* Educated guess */
+ if (fw_response->fw_version < 31 && ret >= 0) {
+ hid_err(t300rs->hdev,
+ "firmware version %i is too old, please update.\n",
+ fw_response->fw_version
+ );
-static void t300rs_close(struct input_dev *dev)
-{
- int ret, trans;
- struct hid_device *hdev = input_get_drvdata(dev);
- struct t300rs_device_entry *t300rs;
- u8 *send_buffer;
+ hid_info(t300rs->hdev, "note: this has to be done through Windows.\n");
- t300rs = t300rs_get_device(hdev);
- if (!t300rs) {
- hid_err(hdev, "could not get device\n");
- return;
+ ret = -EINVAL;
+ goto out;
}
- send_buffer = t300rs->send_buffer;
-
- send_buffer[0] = 0x01;
+ /* everything OK */
+ ret = 0;
- ret = t300rs_send_int(dev, send_buffer, &trans);
- if (ret) {
- hid_err(hdev, "failed sending interrupts\n");
- goto err;
- }
-err:
- t300rs->close(dev);
+out:
+ kfree(fw_response);
+ return ret;
}
-static int t300rs_create_files(struct hid_device *hdev)
+static int t300rs_get_attachment(struct t300rs_device_entry *t300rs)
{
- int ret;
+ /* taken directly from hid_tminit */
+ struct __packed t300rs_attachment_response
+ {
+ uint16_t type;
- 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;
- }
+ union {
+ struct __packed {
+ uint16_t field0;
+ uint16_t field1;
+ uint8_t attachment;
+ uint8_t model;
+ uint16_t field2;
+ uint16_t field3;
+ uint16_t field4;
+ uint16_t field5;
+ } a;
- 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;
- }
+ struct __packed {
+ uint16_t field0;
+ uint16_t field1;
+ uint8_t attachment;
+ uint8_t model;
+ } b;
+ };
+ } *response = kzalloc(GFP_KERNEL, sizeof(struct t300rs_attachment_response));
+ struct usb_ctrlrequest t300rs_attachment_rq = {
+ .bRequestType = 0xc1,
+ .bRequest = 73,
+ .wValue = 0,
+ .wIndex = 0,
+ .wLength = sizeof(struct t300rs_attachment_response)
+ };
+ int ret, attachment;
+ if (!response)
+ return -ENODEV;
- 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 = usb_control_msg(t300rs->usbdev,
+ usb_rcvctrlpipe(t300rs->usbdev, 0),
+ t300rs_attachment_rq.bRequest,
+ t300rs_attachment_rq.bRequestType,
+ t300rs_attachment_rq.wValue,
+ t300rs_attachment_rq.wIndex,
+ response,
+ sizeof(struct t300rs_attachment_response),
+ USB_CTRL_SET_TIMEOUT
+ );
+
+ if (ret < 0) {
+ hid_err(t300rs->hdev, "could not fetch attachment: %i\n", ret);
+ goto out;
}
- 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;
+ if (response->type == cpu_to_le16(0x49)) {
+ attachment = response->a.attachment;
+ } else if (response->type == cpu_to_le16(0x47)) {
+ attachment = response->b.attachment;
+ } else {
+ hid_err(t300rs->hdev, "unknown packet type %hx\n, please contact a maintainer",
+ response->type);
+ ret = -EINVAL;
+ goto out;
}
- return ret;
+ kfree(response);
+ return attachment;
- // 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:
+out:
+ kfree(response);
return ret;
}
-static int t300rs_init(struct hid_device *hdev, const signed short *ff_bits)
+static int t300rs_wheel_init(struct tmff2_device_entry *tmff2)
{
- struct t300rs_device_entry *t300rs;
- struct t300rs_data *drv_data;
+ struct t300rs_device_entry *t300rs = kzalloc(sizeof(struct t300rs_device_entry), GFP_KERNEL);
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 err;
- }
+ int ret;
- 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);
+ t300rs->hdev = tmff2->hdev;
+ t300rs->input_dev = tmff2->input_dev;
+ t300rs->usbdev = to_usb_device(tmff2->hdev->dev.parent->parent);
- if (!t300rs->states) {
- ret = -ENOMEM;
- goto states_err;
- }
+ if(t300rs->hdev->product == TMT300RS_PS4_NORM_ID)
+ t300rs->buffer_length = T300RS_PS4_BUFFER_LENGTH;
+ else
+ t300rs->buffer_length = T300RS_NORM_BUFFER_LENGTH;
- t300rs->send_buffer = kzalloc(T300RS_BUFFER_LENGTH, GFP_KERNEL);
+ 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;
+ if ((ret = t300rs_check_firmware(t300rs)))
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 out;
- }
-
- spin_lock_init(&t300rs->lock);
-
- drv_data->device_props = t300rs;
+ report_list = &t300rs->hdev->report_enum[HID_OUTPUT_REPORT].report_list;
- report_list = &hdev->report_enum[HID_OUTPUT_REPORT].report_list;
-
- // because we set the rdesc, we know exactly which report and field to use
+ /* 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 out;
- }
-
- 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 out;
- }
+ t300rs->open = t300rs->input_dev->open;
+ t300rs->close = t300rs->input_dev->close;
+ /* TODO: PS4 advanced mode? */
+ alt_mode = (t300rs->mode = (t300rs->hdev->product == TMT300RS_PS3_ADV_ID));
+ if ((t300rs->attachment = t300rs_get_attachment(t300rs)) < 0)
+ t300rs->attachment = T300RS_DEFAULT_ATTACHMENT;
- hrtimer_init(&t300rs->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- t300rs->hrtimer.function = t300rs_timer;
+ /* everythin went OK */
+ tmff2->data = t300rs;
+ tmff2->params = t300rs_params;
+ tmff2->max_effects = T300RS_MAX_EFFECTS;
+ memcpy(tmff2->supported_effects, t300rs_effects, sizeof(t300rs_effects));
- range_store(dev, &dev_attr_range, range, 10);
- t300rs_set_gain(input_dev, 0xffff);
-
- hid_info(hdev, "force feedback for T300RS\n");
+ hid_info(t300rs->hdev, "force feedback for T300RS\n");
return 0;
-out:
- kfree(t300rs->firmware_response);
firmware_err:
kfree(t300rs->send_buffer);
send_err:
- kfree(t300rs->states);
-states_err:
kfree(t300rs);
t300rs_err:
- kfree(drv_data);
-err:
- hid_err(hdev, "failed creating force feedback device\n");
+ hid_err(tmff2->hdev, "failed initializing T300RS\n");
return ret;
-
}
-static int t300rs_probe(struct hid_device *hdev, const struct hid_device_id *id)
+static int t300rs_wheel_destroy(void *data)
{
- 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;
- }
+ struct t300rs_device_entry *t300rs = data;
+ if (!t300rs)
+ return -ENODEV;
- 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;
- }
+ kfree(t300rs->send_buffer);
+ kfree(t300rs);
return 0;
-err:
- return ret;
}
-static void t300rs_remove(struct hid_device *hdev)
+static __u8 *t300rs_wheel_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
{
- 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;
- }
+ switch (hdev->product) {
+ case TMT300RS_PS3_NORM_ID:
+ /* normal PS3 mode */
+ rdesc = t300rs_rdesc_nrm_fixed;
+ *rsize = sizeof(t300rs_rdesc_nrm_fixed);
+ break;
- hrtimer_cancel(&t300rs->hrtimer);
+ case TMT300RS_PS4_NORM_ID:
+ /* PS4 normal mode */
+ rdesc = t300rs_rdesc_ps4_fixed;
+ *rsize = sizeof(t300rs_rdesc_ps4_fixed);
+ break;
- 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);
+ case TMT300RS_PS3_ADV_ID:
+ /* PS3 advanced mode */
+ rdesc = t300rs_rdesc_adv_fixed;
+ *rsize = sizeof(t300rs_rdesc_adv_fixed);
+ break;
+ }
- hid_hw_stop(hdev);
- kfree(t300rs->states);
- kfree(t300rs->send_buffer);
- kfree(t300rs->firmware_response);
- kfree(t300rs);
- kfree(drv_data);
+ return rdesc;
}
-static __u8 *t300rs_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize)
+int t300rs_populate_api(struct tmff2_device_entry *tmff2)
{
- rdesc = t300rs_rdesc_fixed;
- *rsize = sizeof(t300rs_rdesc_fixed);
- return rdesc;
-}
+ /* set callbacks */
+ tmff2->play_effect = t300rs_play_effect;
+ tmff2->upload_effect = t300rs_upload_effect;
+ tmff2->update_effect = t300rs_update_effect;
+ tmff2->stop_effect = t300rs_stop_effect;
-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);
+ tmff2->wheel_init = t300rs_wheel_init;
+ tmff2->wheel_destroy = t300rs_wheel_destroy;
-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);
+ tmff2->open = t300rs_open;
+ tmff2->close = t300rs_close;
+ tmff2->set_gain = t300rs_set_gain;
+ tmff2->set_range = t300rs_set_range;
+ tmff2->switch_mode = t300rs_switch_mode;
+ tmff2->alt_mode_show = t300rs_alt_mode_show;
+ tmff2->alt_mode_store = t300rs_alt_mode_store;
+ tmff2->set_autocenter = t300rs_set_autocenter;
+ tmff2->wheel_fixup = t300rs_wheel_fixup;
-MODULE_LICENSE("GPL");
+ return 0;
+}
diff --git a/hid-tmt300rs.h b/hid-tmt300rs.h
index 496ba8f..9357ce1 100644
--- a/hid-tmt300rs.h
+++ b/hid-tmt300rs.h
@@ -1,158 +1,9 @@
-/* SPDX-License-Identifier: GLP-2.0 */
-#include <linux/hid.h>
-#include <linux/usb.h>
-#include <linux/input.h>
-#include <linux/module.h>
-#include <linux/hrtimer.h>
-#include <linux/slab.h>
-#include <linux/ktime.h>
-#include <linux/fixp-arith.h>
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __HID_TMT300RS_H
+#define __HID_TMT300RS_H
-//#include "hid-ids.h"
+#include "hid-tmff2.h"
-#define USB_VENDOR_ID_THRUSTMASTER 0x044f
+int t300rs_populate_api(struct tmff2_device_entry *tmff2);
-#define T300RS_MAX_EFFECTS 16
-#define T300RS_BUFFER_LENGTH 63
-
-/* the wheel seems to only be capable of processing a certain number of
- * interrupts per second, and if this value is too low the kernel urb buffer(or
- * some buffer at least) fills up. Optimally I would figure out some way to
- * space out the interrupts so that they all leave at regular intervals, but
- * for now this is good enough, go slow enough that everything works.
- */
-#define DEFAULT_TIMER_PERIOD 8
-
-#define FF_EFFECT_QUEUE_UPLOAD 0
-#define FF_EFFECT_QUEUE_START 1
-#define FF_EFFECT_QUEUE_STOP 2
-#define FF_EFFECT_PLAYING 3
-#define FF_EFFECT_QUEUE_UPDATE 4
-
-#define CLAMP_VALUE_U16(x) ((unsigned short)((x) > 0xffff ? 0xffff : (x)))
-#define SCALE_VALUE_U16(x, bits) (CLAMP_VALUE_U16(x) >> (16 - bits))
-#define JIFFIES2MS(jiffies) ((jiffies) * 1000 / HZ)
-
-spinlock_t lock;
-unsigned long lock_flags;
-
-spinlock_t data_lock;
-unsigned long data_flags;
-
-static const signed short t300rs_ff_effects[] = {
- FF_CONSTANT,
- FF_RAMP,
- FF_SPRING,
- FF_DAMPER,
- FF_FRICTION,
- FF_INERTIA,
- FF_PERIODIC,
- FF_SINE,
- FF_TRIANGLE,
- FF_SQUARE,
- FF_SAW_UP,
- FF_SAW_DOWN,
- FF_AUTOCENTER,
- FF_GAIN,
- -1
-};
-
-struct t300rs_effect_state {
- struct ff_effect effect;
- struct ff_effect old;
- bool old_set;
- unsigned long flags;
- unsigned long start_time;
- unsigned long count;
-};
-
-struct __packed t300rs_firmware_response {
- uint8_t unknown0;
- uint8_t unknown1;
- uint8_t firmware_version;
- uint8_t unknown2;
-};
-
-
-struct usb_ctrlrequest t300rs_firmware_request = {
- .bRequestType = 0xc1,
- .bRequest = 86,
- .wValue = 0,
- .wIndex = 0,
- .wLength = 8
-};
-
-
-struct t300rs_device_entry {
- struct hid_device *hdev;
- struct input_dev *input_dev;
- struct hid_report *report;
- struct hid_field *ff_field;
- struct usb_device *usbdev;
- struct usb_interface *usbif;
- struct t300rs_effect_state *states;
- struct t300rs_firmware_response *firmware_response;
- struct hrtimer hrtimer;
-
- int (*open)(struct input_dev *dev);
- void (*close)(struct input_dev *dev);
-
- spinlock_t lock;
- unsigned long lock_flags;
-
- u8 *send_buffer;
-
- u16 range;
- u8 effects_used;
-};
-
-
-struct t300rs_data {
- unsigned long quirks;
- void *device_props;
-};
-
-static __u8 t300rs_rdesc_fixed[] = {
- 0x05, 0x01, 0x09, 0x04, 0xa1,
- 0x01, 0x09, 0x01, 0xa1, 0x00,
- 0x85, 0x07, 0x09, 0x30, 0x15,
- 0x00, 0x27, 0xff, 0xff, 0x00,
- 0x00, 0x35, 0x00, 0x47, 0xff,
- 0xff, 0x00, 0x00, 0x75, 0x10,
- 0x95, 0x01, 0x81, 0x02, 0x09,
- 0x35, 0x26, 0xff, 0x03, 0x46,
- 0xff, 0x03, 0x81, 0x02, 0x09,
- 0x32, 0x81, 0x02, 0x09, 0x31,
- 0x81, 0x02, 0x81, 0x03, 0x05,
- 0x09, 0x19, 0x01, 0x29, 0x0d,
- 0x25, 0x01, 0x45, 0x01, 0x75,
- 0x01, 0x95, 0x0d, 0x81, 0x02,
- 0x75, 0x0b, 0x95, 0x01, 0x81,
- 0x03, 0x05, 0x01, 0x09, 0x39,
- 0x25, 0x07, 0x46, 0x3b, 0x01,
- 0x55, 0x00, 0x65, 0x14, 0x75,
- 0x04, 0x81, 0x42, 0x65, 0x00,
- 0x81, 0x03, 0x85, 0x60, // here 0x0a
- 0x06, 0x00, 0xff, 0x09, 0x60, // here 0x0a
- 0x75, 0x08, 0x95, 0x3f, 0x26,
- 0xff, 0x7f, 0x15, 0x00, 0x46,
- 0xff, 0x7f, 0x36, 0x00, 0x80,
- 0x91, 0x02, 0x85, 0x02, 0x09,
- 0x02, 0x81, 0x02, 0x09, 0x14,
- 0x85, 0x14, 0x81, 0x02, 0xc0,
- 0xc0,
-};
-
-static u8 spring_values[] = {
- 0xa6, 0x6a, 0xa6, 0x6a, 0xfe,
- 0xff, 0xfe, 0xff, 0xfe, 0xff,
- 0xfe, 0xff, 0xdf, 0x58, 0xa6,
- 0x6a, 0x06
-};
-
-static u8 damper_values[] = {
- 0xfc, 0x7f, 0xfc, 0x7f, 0xfe,
- 0xff, 0xfe, 0xff, 0xfe, 0xff,
- 0xfe, 0xff, 0xfc, 0x7f, 0xfc,
- 0x7f, 0x07
-};
+#endif /* __HID_TM300RS_H */
diff --git a/ps4-input.txt b/ps4-input.txt
new file mode 100644
index 0000000..9286c7e
--- /dev/null
+++ b/ps4-input.txt
@@ -0,0 +1,54 @@
+1 ff00.0021 = 0
+2 ff00.0021 = 0
+3 ff00.0021 = 0
+4 ff00.0021 = 0
+5 ff00.0021 = 0
+6 ff00.0021 = 0
+7 ff00.0021 = 0
+8 ff00.0021 = 0
+9 ff00.0021 = 0
+10 ff00.0021 = 0
+11 ff00.0021 = 0
+12 ff00.0021 = 0
+13 ff00.0021 = 0
+14 ff00.0021 = 0
+15 ff00.0021 = 0
+16 ff00.0021 = 0
+17 ff00.0021 = 0
+18 ff00.0021 = 0
+19 ff00.0021 = 0
+20 ff00.0021 = 0
+21 ff00.0021 = 0
+22 ff00.0021 = 0
+23 ff00.0021 = 0
+24 ff00.0021 = 0
+25 ff00.0021 = 0
+26 ff00.0021 = 0
+27 ff00.0021 = 0
+28 ff00.0021 = 0
+29 ff00.0021 = 0
+30 ff00.0021 = 0
+31 ff00.0021 = 0
+32 ff00.0021 = 0
+33 ff00.0021 = 0
+34 ff00.0021 = 226 /* wheel */
+35 ff00.0021 = 125 /* wheel */
+36 ff00.0021 = 255 /* gas */
+37 ff00.0021 = 255 /* gas */
+38 ff00.0021 = 255 /* brake */
+39 ff00.0021 = 255 /* brake */
+40 ff00.0021 = 255 /* clutch */
+41 ff00.0021 = 255 /* clutch */
+42 ff00.0021 = 0
+43 ff00.0021 = 255
+44 ff00.0021 = 255
+45 ff00.0021 = 0
+46 ff00.0021 = 0
+47 ff00.0021 = 0
+48 ff00.0021 = 0
+49 ff00.0021 = 0
+50 ff00.0021 = 0
+51 ff00.0021 = 0
+52 ff00.0021 = 0
+53 ff00.0021 = 0
+54 ff00.0021 = 0
diff --git a/t248-effects.txt b/t248-effects.txt
new file mode 100644
index 0000000..821fc7a
--- /dev/null
+++ b/t248-effects.txt
@@ -0,0 +1,2 @@
+Open: Identical to T300
+Close: Identical to T300