diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2022-04-08 23:05:55 +0300 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2022-04-08 23:05:55 +0300 |
| commit | 8975ebace17be841b42f53222c79f0530698e2ca (patch) | |
| tree | 05ef250e985f1a7c2ebaa5f5f695636b6a2c8594 | |
| parent | 37f0f4bbeddc4a1d1b885a89f08a2921fb3e0d30 (diff) | |
| parent | 0471da28f10feb5f3ad58fe8233810cf031b90da (diff) | |
| download | hid-tmff2-8975ebace17be841b42f53222c79f0530698e2ca.tar.gz hid-tmff2-8975ebace17be841b42f53222c79f0530698e2ca.zip | |
Merge branch 't248'
| -rw-r--r-- | Kbuild | 2 | ||||
| -rw-r--r-- | Makefile | 1 | ||||
| -rw-r--r-- | TODO | 7 | ||||
| -rw-r--r-- | hid-tmff2.c | 733 | ||||
| -rw-r--r-- | hid-tmff2.h | 144 | ||||
| -rw-r--r-- | hid-tmt248.c | 310 | ||||
| -rw-r--r-- | hid-tmt300rs.c | 2084 | ||||
| -rw-r--r-- | hid-tmt300rs.h | 161 | ||||
| -rw-r--r-- | ps4-input.txt | 54 | ||||
| -rw-r--r-- | t248-effects.txt | 2 |
10 files changed, 2318 insertions, 1180 deletions
@@ -0,0 +1,2 @@ +obj-m := hid-tmff-new.o +hid-tmff-new-y := hid-tmff2.o hid-tmt300rs.o hid-tmt248.o @@ -1,4 +1,3 @@ -obj-m += hid-tmt300rs.o KDIR ?= /lib/modules/$(shell uname -r)/build all: hid-tminit @@ -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 |
