From 60e90e0a96039c58968de551aadca0fab490d35d Mon Sep 17 00:00:00 2001 From: Kimplul Date: Sat, 12 Mar 2022 18:00:40 +0200 Subject: allow for wheel 'backends' --- hid-tmff2.h | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 hid-tmff2.h (limited to 'hid-tmff2.h') diff --git a/hid-tmff2.h b/hid-tmff2.h new file mode 100644 index 0000000..bdde1a7 --- /dev/null +++ b/hid-tmff2.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _HID_TMFF2 +#define _HID_TMFF2 + +#include +#include +#include + +#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 + +#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; + + /* fields relevant to each actual device (T300, T150...) */ + void *data; + 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)(void *data); + 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); + int (*switch_mode)(void *data, uint16_t mode); + int (*set_autocenter)(void *data, uint16_t autocenter); + __u8 *(*wheel_fixup)(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize); +}; + +#endif /* _HID_TMFF2 */ -- cgit v1.3 From 9b6810ba6e1bd2553e205eb6719844253d5ce051 Mon Sep 17 00:00:00 2001 From: Kimplul Date: Sat, 12 Mar 2022 20:53:39 +0200 Subject: fix crashes --- hid-tmff2.c | 24 +++++++++--------- hid-tmff2.h | 4 ++- hid-tmt300rs.c | 78 +++++++++++++++++++++++++++------------------------------- 3 files changed, 52 insertions(+), 54 deletions(-) (limited to 'hid-tmff2.h') diff --git a/hid-tmff2.c b/hid-tmff2.c index f1d1f84..6a112fa 100644 --- a/hid-tmff2.c +++ b/hid-tmff2.c @@ -52,15 +52,15 @@ static struct tmff2_device_entry *tmff2_from_hdev(struct hid_device *hdev) static struct tmff2_device_entry *tmff2_from_input(struct input_dev *input_dev) { - struct tmff2_device_entry *tmff2; + struct hid_device *hdev; spin_lock_irqsave(&lock, lock_flags); - if (!(tmff2 = input_get_drvdata(input_dev))) { + if (!(hdev = input_get_drvdata(input_dev))) { dev_err(&input_dev->dev, "input_dev private data not found\n"); return NULL; } spin_unlock_irqrestore(&lock, lock_flags); - return tmff2; + return tmff2_from_hdev(hdev); } static ssize_t spring_level_store(struct device *dev, @@ -301,7 +301,7 @@ static void tmff2_work_handler(struct work_struct *w) } if (test_bit(FF_EFFECT_QUEUE_START, &state->flags)) { - if (tmff2->play_effect(tmff2, state)) { + if (tmff2->play_effect(tmff2->data, state)) { hid_warn(tmff2->hdev, "failed starting effect\n"); } else { __clear_bit(FF_EFFECT_QUEUE_START, &state->flags); @@ -311,7 +311,7 @@ static void tmff2_work_handler(struct work_struct *w) } if (test_bit(FF_EFFECT_QUEUE_STOP, &state->flags)) { - if (tmff2->stop_effect(tmff2, state)) { + if (tmff2->stop_effect(tmff2->data, state)) { hid_warn(tmff2->hdev, "failed stopping effect\n"); } else { __clear_bit(FF_EFFECT_PLAYING, &state->flags); @@ -420,9 +420,15 @@ 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); @@ -431,10 +437,6 @@ static int tmff2_wheel_init(struct tmff2_device_entry *tmff2) goto err; } - /* is this required or should it be done in t300rs_populate_api? */ - if ((ret = tmff2->wheel_init(tmff2->data))) - 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); @@ -482,8 +484,6 @@ static int tmff2_probe(struct hid_device *hdev, const struct hid_device_id *id) tmff2->hdev = hdev; hid_set_drvdata(tmff2->hdev, tmff2); - tmff2->input_dev = list_entry(hdev->inputs.next, struct hid_input, list)->input; - input_set_drvdata(tmff2->input_dev, tmff2); switch (tmff2->hdev->product) { /* t300rs */ @@ -508,6 +508,8 @@ static int tmff2_probe(struct hid_device *hdev, const struct hid_device_id *id) 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; diff --git a/hid-tmff2.h b/hid-tmff2.h index bdde1a7..b2a46c9 100644 --- a/hid-tmff2.h +++ b/hid-tmff2.h @@ -60,7 +60,7 @@ struct tmff2_device_entry { int (*update_effect)(void *data, struct tmff2_effect_state *state); int (*stop_effect)(void *data, struct tmff2_effect_state *state); - int (*wheel_init)(void *data); + int (*wheel_init)(struct tmff2_device_entry *tmff2); int (*wheel_destroy)(void *data); /* optional callbacks */ @@ -71,6 +71,8 @@ struct tmff2_device_entry { int (*switch_mode)(void *data, uint16_t mode); 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... */ }; #endif /* _HID_TMFF2 */ diff --git a/hid-tmt300rs.c b/hid-tmt300rs.c index ee0e817..8171578 100644 --- a/hid-tmt300rs.c +++ b/hid-tmt300rs.c @@ -1329,31 +1329,31 @@ static int t300rs_close(void *data) return ret; } -static int t300rs_create_files(struct hid_device *hdev) +static int t300rs_create_files(struct t300rs_device_entry *t300rs) { int ret; - if ((ret = device_create_file(&hdev->dev, &dev_attr_alt_mode))) { - hid_err(hdev, "unable to create sysfs interface for alt_mode\n"); + if ((ret = device_create_file(&t300rs->hdev->dev, &dev_attr_alt_mode))) { + hid_err(t300rs->hdev, "unable to create sysfs interface for alt_mode\n"); goto alt_err; } - if ((ret = device_create_file(&hdev->dev, &dev_attr_range))) { - hid_warn(hdev, "unable to create sysfs interface for range\n"); + if ((ret = device_create_file(&t300rs->hdev->dev, &dev_attr_range))) { + hid_warn(t300rs->hdev, "unable to create sysfs interface for range\n"); goto range_err; } - if ((ret = device_create_file(&hdev->dev, &dev_attr_spring_level))) { - hid_warn(hdev, "unable to create sysfs interface for spring_level\n"); + if ((ret = device_create_file(&t300rs->hdev->dev, &dev_attr_spring_level))) { + hid_warn(t300rs->hdev, "unable to create sysfs interface for spring_level\n"); goto spring_err; } - if ((ret = device_create_file(&hdev->dev, &dev_attr_damper_level))) { - hid_warn(hdev, "unable to create sysfs interface for damper_level\n"); + if ((ret = device_create_file(&t300rs->hdev->dev, &dev_attr_damper_level))) { + hid_warn(t300rs->hdev, "unable to create sysfs interface for damper_level\n"); goto damper_err; } - if ((ret = device_create_file(&hdev->dev, &dev_attr_friction_level))) { - hid_warn(hdev, "unable to create sysfs interface for friction_level\n"); + if ((ret = device_create_file(&t300rs->hdev->dev, &dev_attr_friction_level))) { + hid_warn(t300rs->hdev, "unable to create sysfs interface for friction_level\n"); goto friction_err; } @@ -1362,13 +1362,13 @@ static int t300rs_create_files(struct hid_device *hdev) /* if the creation of dev_attr_friction fails, we don't need to remove it */ /* device_remove_file(&hdev->dev, &dev_attr_friction_level); */ friction_err: - device_remove_file(&hdev->dev, &dev_attr_damper_level); + device_remove_file(&t300rs->hdev->dev, &dev_attr_damper_level); damper_err: - device_remove_file(&hdev->dev, &dev_attr_spring_level); + device_remove_file(&t300rs->hdev->dev, &dev_attr_spring_level); spring_err: - device_remove_file(&hdev->dev, &dev_attr_range); + device_remove_file(&t300rs->hdev->dev, &dev_attr_range); range_err: - device_remove_file(&hdev->dev, &dev_attr_alt_mode); + device_remove_file(&t300rs->hdev->dev, &dev_attr_alt_mode); alt_err: return ret; } @@ -1397,7 +1397,7 @@ static int t300rs_check_firmware(struct t300rs_device_entry *t300rs) ); if (ret < 0) { - hid_err(t300rs->hdev, "could not fetch firmware version\n"); + hid_err(t300rs->hdev, "could not fetch firmware version: %i\n", ret); goto out; } @@ -1422,12 +1422,21 @@ out: return ret; } -static int t300rs_wheel_init(void *data) +static int t300rs_wheel_init(struct tmff2_device_entry *tmff2) { - struct t300rs_device_entry *t300rs = data; + struct t300rs_device_entry *t300rs = kzalloc(sizeof(struct t300rs_device_entry), GFP_KERNEL); struct list_head *report_list; int ret; + if (!t300rs) { + ret = -ENOMEM; + goto t300rs_err; + } + + t300rs->hdev = tmff2->hdev; + t300rs->input_dev = tmff2->input_dev; + t300rs->usbdev = to_usb_device(tmff2->hdev->dev.parent->parent); + if(t300rs->hdev->product == 0xb66d) t300rs->buffer_length = T300RS_PS4_BUFFER_LENGTH; else @@ -1451,19 +1460,21 @@ static int t300rs_wheel_init(void *data) t300rs->open = t300rs->input_dev->open; t300rs->close = t300rs->input_dev->close; - if ((ret = t300rs_create_files(t300rs->hdev))) { + if ((ret = t300rs_create_files(t300rs))) { /* probably not a massive issue, but could affect programs like * Oversteer, best play it safe */ hid_err(t300rs->hdev, "could not create sysfs files\n"); goto sysfs_err; } - t300rs_set_range(t300rs, range); - t300rs_set_gain(t300rs, 0xffff); - /* TODO: PS4 advanced mode? */ alt_mode = (t300rs->hdev->product == 0xb66f); + /* everythin went OK */ + tmff2->data = t300rs; + tmff2->max_effects = T300RS_MAX_EFFECTS; + memcpy(tmff2->supported_effects, t300rs_effects, sizeof(t300rs_effects)); + hid_info(t300rs->hdev, "force feedback for T300RS\n"); return 0; @@ -1471,8 +1482,10 @@ sysfs_err: firmware_err: kfree(t300rs->send_buffer); +t300rs_err: + kfree(t300rs); send_err: - hid_err(t300rs->hdev, "failed creating force feedback device\n"); + hid_err(tmff2->hdev, "failed creating force feedback device\n"); return ret; } @@ -1523,17 +1536,6 @@ static __u8 *t300rs_wheel_fixup(struct hid_device *hdev, __u8 *rdesc, static int t300rs_populate_api(struct tmff2_device_entry *tmff2) { - struct t300rs_device_entry *t300rs = - kzalloc(sizeof(struct t300rs_device_entry), GFP_KERNEL); - - /* we must populate wheel_destroy at the least, even if t300rs didn't - * get allocated */ - tmff2->data = t300rs; - tmff2->max_effects = T300RS_MAX_EFFECTS; - - /* copy over supported effects */ - memcpy(tmff2->supported_effects, t300rs_effects, ARRAY_SIZE(t300rs_effects)); - /* set callbacks */ tmff2->play_effect = t300rs_play_effect; tmff2->upload_effect = t300rs_upload_effect; @@ -1551,13 +1553,5 @@ static int t300rs_populate_api(struct tmff2_device_entry *tmff2) tmff2->set_autocenter = t300rs_set_autocenter; tmff2->wheel_fixup = t300rs_wheel_fixup; - if (!t300rs) - return -ENOMEM; - - /* copy over stuff we need */ - t300rs->hdev = tmff2->hdev; - t300rs->input_dev = tmff2->input_dev; - t300rs->usbdev = to_usb_device(&tmff2->hdev->dev); - return 0; } -- cgit v1.3 From 0dcf31ff3fe8eb9bc079d94242253290a30eb97e Mon Sep 17 00:00:00 2001 From: Kimplul Date: Mon, 14 Mar 2022 00:23:40 +0200 Subject: don't include .c directly Arguably more hygienic. --- Kbuild | 2 ++ Makefile | 1 - hid-tmff2.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++--------- hid-tmff2.h | 32 ++++++++++++++----- hid-tmt300rs.c | 74 +++++++------------------------------------- hid-tmt300rs.h | 9 ++++++ 6 files changed, 131 insertions(+), 85 deletions(-) create mode 100644 Kbuild create mode 100644 hid-tmt300rs.h (limited to 'hid-tmff2.h') diff --git a/Kbuild b/Kbuild new file mode 100644 index 0000000..697f3e1 --- /dev/null +++ b/Kbuild @@ -0,0 +1,2 @@ +obj-m := hid-tmff-new.o +hid-tmff-new-y := hid-tmff2.o hid-tmt300rs.o diff --git a/Makefile b/Makefile index 9a7b851..2d88264 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,3 @@ -obj-m += hid-tmff2.o KDIR ?= /lib/modules/$(shell uname -r)/build all: hid-tminit diff --git a/hid-tmff2.c b/hid-tmff2.c index 6a112fa..811d75b 100644 --- a/hid-tmff2.c +++ b/hid-tmff2.c @@ -1,38 +1,40 @@ #include #include #include +#define TMFF2_MAIN #include "hid-tmff2.h" +#include "hid-tmt300rs.h" -static int timer_msecs = DEFAULT_TIMER_PERIOD; +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? */ -static int spring_level = 30; +int spring_level = 30; module_param(spring_level, int, 0); MODULE_PARM_DESC(spring_level, "Level of spring force (0-100), as per Oversteer standards"); -static int damper_level = 30; +int damper_level = 30; module_param(damper_level, int, 0); MODULE_PARM_DESC(damper_level, "Level of damper force (0-100), as per Oversteer standards"); -static int friction_level = 30; +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 int range = 900; +int range = 900; module_param(range, int, 0); MODULE_PARM_DESC(range, "Range of wheel, depends on the wheel. Invalid values are ignored."); -static int alt_mode = 0; +int alt_mode = 0; module_param(alt_mode, int, 0); MODULE_PARM_DESC(alt_mode, - "Alternate mode, eg. T300RS F1 mode."); + "Alternate mode, eg. F1 mode."); static spinlock_t lock; static unsigned long lock_flags; @@ -217,9 +219,6 @@ static ssize_t alt_mode_show(struct device *dev, } static DEVICE_ATTR_RW(alt_mode); -/* include each wheel */ -#include "hid-tmt300rs.c" - static void tmff2_set_gain(struct input_dev *dev, uint16_t gain) { struct tmff2_device_entry *tmff2 = tmff2_from_input(dev); @@ -416,6 +415,61 @@ static void tmff2_close(struct input_dev *dev) 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 & HAS_ALT_MODE) { + if ((ret = device_create_file(dev, &dev_attr_alt_mode))) { + hid_err(tmff2->hdev, "unable to create sysfs for alt_mode\n"); + goto alt_err; + } + } + + if (tmff2->params & HAS_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 & HAS_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 & HAS_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 & HAS_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_alt_mode); +alt_err: + return ret; +} + static int tmff2_wheel_init(struct tmff2_device_entry *tmff2) { int ret, i; @@ -464,6 +518,10 @@ static int tmff2_wheel_init(struct tmff2_device_entry *tmff2) if (tmff2->set_autocenter) ff->set_autocenter = tmff2_set_autocenter; + /* create files */ + if ((ret = tmff2_create_files(tmff2))) + goto err; + return 0; err: @@ -519,13 +577,10 @@ static int tmff2_probe(struct hid_device *hdev, const struct hid_device_id *id) init_err: hid_hw_stop(hdev); - hid_err: tmff2->wheel_destroy(tmff2->data); - wheel_err: kfree(tmff2); - oom_err: return ret; } @@ -546,12 +601,27 @@ static __u8 *tmff2_report_fixup(struct hid_device *hdev, __u8 *rdesc, static void tmff2_remove(struct hid_device *hdev) { struct tmff2_device_entry *tmff2 = tmff2_from_hdev(hdev); + struct device *dev; if (!tmff2) return; + cancel_delayed_work_sync(&tmff2->work); - tmff2->wheel_destroy(tmff2->data); + dev = &tmff2->hdev->dev; + if (tmff2->params & HAS_DAMPER_LEVEL) + device_remove_file(dev, &dev_attr_damper_level); + + if (tmff2->params & HAS_SPRING_LEVEL) + device_remove_file(dev, &dev_attr_spring_level); + + if (tmff2->params & HAS_RANGE) + device_remove_file(dev, &dev_attr_range); + + if (tmff2->params & HAS_ALT_MODE) + device_remove_file(dev, &dev_attr_alt_mode); + + tmff2->wheel_destroy(tmff2->data); hid_hw_stop(hdev); kfree(tmff2->states); diff --git a/hid-tmff2.h b/hid-tmff2.h index b2a46c9..1585649 100644 --- a/hid-tmff2.h +++ b/hid-tmff2.h @@ -1,11 +1,20 @@ /* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _HID_TMFF2 -#define _HID_TMFF2 +#ifndef __HID_TMFF2_H +#define __HID_TMFF2_H #include #include #include +#ifndef TMFF2_MAIN +extern int timer_msecs; +extern int spring_level; +extern int damper_level; +extern int friction_level; +extern int range; +extern int alt_mode; +#endif + #define USB_VENDOR_ID_THRUSTMASTER 0x044f /* the wheel seems to only be capable of processing a certain number of @@ -16,11 +25,17 @@ */ #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 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 HAS_SPRING_LEVEL (1 << 0) +#define HAS_DAMPER_LEVEL (1 << 1) +#define HAS_FRICTION_LEVEL (1 << 2) +#define HAS_RANGE (1 << 3) +#define HAS_ALT_MODE (1 << 4) #undef fixp_sin16 #define fixp_sin16(v) (((v % 360) > 180) ?\ @@ -51,6 +66,7 @@ struct tmff2_device_entry { /* fields relevant to each actual device (T300, T150...) */ void *data; + unsigned long params; unsigned long max_effects; signed short supported_effects[FF_CNT]; @@ -75,4 +91,4 @@ struct tmff2_device_entry { /* void pointers are dangerous, I know, but in this case likely the best option... */ }; -#endif /* _HID_TMFF2 */ +#endif /* __HID_TMFF2_H */ diff --git a/hid-tmt300rs.c b/hid-tmt300rs.c index 8171578..b253562 100644 --- a/hid-tmt300rs.c +++ b/hid-tmt300rs.c @@ -1,10 +1,20 @@ // SPDX-License-Identifier: GPL-2.0 #include +#include +#include "hid-tmff2.h" +#include "hid-tmt300rs.h" #define T300RS_MAX_EFFECTS 16 #define T300RS_NORM_BUFFER_LENGTH 63 #define T300RS_PS4_BUFFER_LENGTH 31 +static const unsigned long t300rs_params = + HAS_SPRING_LEVEL + | HAS_DAMPER_LEVEL + | HAS_FRICTION_LEVEL + | HAS_RANGE + | HAS_ALT_MODE; + static const signed short t300rs_effects[] = { FF_CONSTANT, FF_RAMP, @@ -1329,50 +1339,6 @@ static int t300rs_close(void *data) return ret; } -static int t300rs_create_files(struct t300rs_device_entry *t300rs) -{ - int ret; - if ((ret = device_create_file(&t300rs->hdev->dev, &dev_attr_alt_mode))) { - hid_err(t300rs->hdev, "unable to create sysfs interface for alt_mode\n"); - goto alt_err; - } - - if ((ret = device_create_file(&t300rs->hdev->dev, &dev_attr_range))) { - hid_warn(t300rs->hdev, "unable to create sysfs interface for range\n"); - goto range_err; - } - - if ((ret = device_create_file(&t300rs->hdev->dev, &dev_attr_spring_level))) { - hid_warn(t300rs->hdev, "unable to create sysfs interface for spring_level\n"); - goto spring_err; - } - - if ((ret = device_create_file(&t300rs->hdev->dev, &dev_attr_damper_level))) { - hid_warn(t300rs->hdev, "unable to create sysfs interface for damper_level\n"); - goto damper_err; - } - - if ((ret = device_create_file(&t300rs->hdev->dev, &dev_attr_friction_level))) { - hid_warn(t300rs->hdev, "unable to create sysfs interface for friction_level\n"); - goto friction_err; - } - - return ret; - - /* if the creation of dev_attr_friction fails, we don't need to remove it */ - /* device_remove_file(&hdev->dev, &dev_attr_friction_level); */ -friction_err: - device_remove_file(&t300rs->hdev->dev, &dev_attr_damper_level); -damper_err: - device_remove_file(&t300rs->hdev->dev, &dev_attr_spring_level); -spring_err: - device_remove_file(&t300rs->hdev->dev, &dev_attr_range); -range_err: - device_remove_file(&t300rs->hdev->dev, &dev_attr_alt_mode); -alt_err: - return ret; -} - static int t300rs_check_firmware(struct t300rs_device_entry *t300rs) { int ret; @@ -1460,28 +1426,20 @@ static int t300rs_wheel_init(struct tmff2_device_entry *tmff2) t300rs->open = t300rs->input_dev->open; t300rs->close = t300rs->input_dev->close; - if ((ret = t300rs_create_files(t300rs))) { - /* probably not a massive issue, but could affect programs like - * Oversteer, best play it safe */ - hid_err(t300rs->hdev, "could not create sysfs files\n"); - goto sysfs_err; - } - /* TODO: PS4 advanced mode? */ alt_mode = (t300rs->hdev->product == 0xb66f); /* 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)); hid_info(t300rs->hdev, "force feedback for T300RS\n"); return 0; -sysfs_err: firmware_err: kfree(t300rs->send_buffer); - t300rs_err: kfree(t300rs); send_err: @@ -1495,14 +1453,6 @@ static int t300rs_wheel_destroy(void *data) if (!t300rs) return -ENODEV; - /* apparently should be safe to call these even without the files - * existing */ - device_remove_file(&t300rs->hdev->dev, &dev_attr_range); - device_remove_file(&t300rs->hdev->dev, &dev_attr_alt_mode); - device_remove_file(&t300rs->hdev->dev, &dev_attr_spring_level); - device_remove_file(&t300rs->hdev->dev, &dev_attr_damper_level); - device_remove_file(&t300rs->hdev->dev, &dev_attr_friction_level); - kfree(t300rs->send_buffer); kfree(t300rs); return 0; @@ -1534,7 +1484,7 @@ static __u8 *t300rs_wheel_fixup(struct hid_device *hdev, __u8 *rdesc, return rdesc; } -static int t300rs_populate_api(struct tmff2_device_entry *tmff2) +int t300rs_populate_api(struct tmff2_device_entry *tmff2) { /* set callbacks */ tmff2->play_effect = t300rs_play_effect; diff --git a/hid-tmt300rs.h b/hid-tmt300rs.h new file mode 100644 index 0000000..9357ce1 --- /dev/null +++ b/hid-tmt300rs.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __HID_TMT300RS_H +#define __HID_TMT300RS_H + +#include "hid-tmff2.h" + +int t300rs_populate_api(struct tmff2_device_entry *tmff2); + +#endif /* __HID_TM300RS_H */ -- cgit v1.3 From 28d0a3f76748a2555fc1417216ed51112dba945c Mon Sep 17 00:00:00 2001 From: Kimplul Date: Sun, 20 Mar 2022 17:48:19 +0200 Subject: merge headers into one --- hid-tmff2.c | 35 ++++++++++++++++++----------------- hid-tmff2.h | 21 +++++++++++++-------- hid-tmt300rs.c | 35 ++++++++++++++++++----------------- 3 files changed, 49 insertions(+), 42 deletions(-) (limited to 'hid-tmff2.h') diff --git a/hid-tmff2.c b/hid-tmff2.c index 811d75b..2e7221f 100644 --- a/hid-tmff2.c +++ b/hid-tmff2.c @@ -1,9 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 #include #include #include -#define TMFF2_MAIN #include "hid-tmff2.h" -#include "hid-tmt300rs.h" + int timer_msecs = DEFAULT_TIMER_PERIOD; module_param(timer_msecs, int, 0660); @@ -421,35 +421,35 @@ static int tmff2_create_files(struct tmff2_device_entry *tmff2) int ret; /* could use short circuiting but this is more explicit */ - if (tmff2->params & HAS_ALT_MODE) { + if (tmff2->params & PARAM_ALT_MODE) { if ((ret = device_create_file(dev, &dev_attr_alt_mode))) { hid_err(tmff2->hdev, "unable to create sysfs for alt_mode\n"); goto alt_err; } } - if (tmff2->params & HAS_RANGE) { + 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 & HAS_SPRING_LEVEL) { + 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 & HAS_DAMPER_LEVEL) { + 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 & HAS_FRICTION_LEVEL) { + 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; @@ -545,12 +545,13 @@ static int tmff2_probe(struct hid_device *hdev, const struct hid_device_id *id) switch (tmff2->hdev->product) { /* t300rs */ - case 0xb66e: - case 0xb66f: - case 0xb66d: + 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; + default: ret = -ENODEV; goto wheel_err; @@ -609,16 +610,16 @@ static void tmff2_remove(struct hid_device *hdev) cancel_delayed_work_sync(&tmff2->work); dev = &tmff2->hdev->dev; - if (tmff2->params & HAS_DAMPER_LEVEL) + if (tmff2->params & PARAM_DAMPER_LEVEL) device_remove_file(dev, &dev_attr_damper_level); - if (tmff2->params & HAS_SPRING_LEVEL) + if (tmff2->params & PARAM_SPRING_LEVEL) device_remove_file(dev, &dev_attr_spring_level); - if (tmff2->params & HAS_RANGE) + if (tmff2->params & PARAM_RANGE) device_remove_file(dev, &dev_attr_range); - if (tmff2->params & HAS_ALT_MODE) + if (tmff2->params & PARAM_ALT_MODE) device_remove_file(dev, &dev_attr_alt_mode); tmff2->wheel_destroy(tmff2->data); @@ -630,9 +631,9 @@ static void tmff2_remove(struct hid_device *hdev) static const struct hid_device_id tmff2_devices[] = { /* t300rs and variations */ - {HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb66e)}, - {HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb66f)}, - {HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb66d)}, + {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)}, {} }; MODULE_DEVICE_TABLE(hid, tmff2_devices); diff --git a/hid-tmff2.h b/hid-tmff2.h index 1585649..d59104a 100644 --- a/hid-tmff2.h +++ b/hid-tmff2.h @@ -6,14 +6,12 @@ #include #include -#ifndef TMFF2_MAIN extern int timer_msecs; extern int spring_level; extern int damper_level; extern int friction_level; extern int range; extern int alt_mode; -#endif #define USB_VENDOR_ID_THRUSTMASTER 0x044f @@ -23,7 +21,7 @@ extern int alt_mode; * 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 DEFAULT_TIMER_PERIOD 8 #define FF_EFFECT_QUEUE_UPLOAD 0 #define FF_EFFECT_QUEUE_START 1 @@ -31,11 +29,11 @@ extern int alt_mode; #define FF_EFFECT_QUEUE_UPDATE 3 #define FF_EFFECT_PLAYING 4 -#define HAS_SPRING_LEVEL (1 << 0) -#define HAS_DAMPER_LEVEL (1 << 1) -#define HAS_FRICTION_LEVEL (1 << 2) -#define HAS_RANGE (1 << 3) -#define HAS_ALT_MODE (1 << 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) #undef fixp_sin16 #define fixp_sin16(v) (((v % 360) > 180) ?\ @@ -91,4 +89,11 @@ struct tmff2_device_entry { /* void pointers are dangerous, I know, but in this case likely the best option... */ }; +/* external */ +int t300rs_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 + #endif /* __HID_TMFF2_H */ diff --git a/hid-tmt300rs.c b/hid-tmt300rs.c index b253562..8c4655b 100644 --- a/hid-tmt300rs.c +++ b/hid-tmt300rs.c @@ -2,18 +2,18 @@ #include #include #include "hid-tmff2.h" -#include "hid-tmt300rs.h" #define T300RS_MAX_EFFECTS 16 #define T300RS_NORM_BUFFER_LENGTH 63 #define T300RS_PS4_BUFFER_LENGTH 31 static const unsigned long t300rs_params = - HAS_SPRING_LEVEL - | HAS_DAMPER_LEVEL - | HAS_FRICTION_LEVEL - | HAS_RANGE - | HAS_ALT_MODE; + PARAM_SPRING_LEVEL + | PARAM_DAMPER_LEVEL + | PARAM_FRICTION_LEVEL + | PARAM_RANGE + | PARAM_ALT_MODE + ; static const signed short t300rs_effects[] = { FF_CONSTANT, @@ -356,7 +356,7 @@ static u8 damper_values[] = { 0x7f, 0x07 }; -static int t300rs_send_buf(struct t300rs_device_entry *t300rs, size_t len, u8 *send_buffer) +static int t300rs_send_buf(struct t300rs_device_entry *t300rs, u8 *send_buffer, size_t len) { int i; /* check that send_buffer fits into our report */ @@ -377,7 +377,7 @@ static int t300rs_send_buf(struct t300rs_device_entry *t300rs, size_t len, u8 *s static int t300rs_send_int(struct t300rs_device_entry *t300rs) { - t300rs_send_buf(t300rs, t300rs->buffer_length, t300rs->send_buffer); + t300rs_send_buf(t300rs, t300rs->send_buffer, t300rs->buffer_length); memset(t300rs->send_buffer, 0, t300rs->buffer_length); return 0; @@ -1213,6 +1213,7 @@ static int t300rs_set_autocenter(void *data, uint16_t value) if (!t300rs) return -ENODEV; + /* TODO: this should probably also use a separately allocated buffer? */ autocenter_packet = (struct t300rs_packet_autocenter *)t300rs->send_buffer; autocenter_packet->header.cmd = 0x08; @@ -1288,7 +1289,7 @@ static int t300rs_set_range(void *data, uint16_t value) send_buffer[2] = scaled_value & 0xff; send_buffer[3] = scaled_value >> 8; - if ((ret = t300rs_send_buf(t300rs, t300rs->buffer_length, send_buffer))) + if ((ret = t300rs_send_buf(t300rs, send_buffer, t300rs->buffer_length))) hid_warn(t300rs->hdev, "failed setting range\n"); /* since everythin went OK, update the current range */ @@ -1403,7 +1404,7 @@ static int t300rs_wheel_init(struct tmff2_device_entry *tmff2) t300rs->input_dev = tmff2->input_dev; t300rs->usbdev = to_usb_device(tmff2->hdev->dev.parent->parent); - if(t300rs->hdev->product == 0xb66d) + if(t300rs->hdev->product == TMT300RS_PS4_NORM_ID) t300rs->buffer_length = T300RS_PS4_BUFFER_LENGTH; else t300rs->buffer_length = T300RS_NORM_BUFFER_LENGTH; @@ -1427,7 +1428,7 @@ static int t300rs_wheel_init(struct tmff2_device_entry *tmff2) t300rs->close = t300rs->input_dev->close; /* TODO: PS4 advanced mode? */ - alt_mode = (t300rs->hdev->product == 0xb66f); + alt_mode = (t300rs->hdev->product == TMT300RS_PS3_ADV_ID); /* everythin went OK */ tmff2->data = t300rs; @@ -1440,10 +1441,10 @@ static int t300rs_wheel_init(struct tmff2_device_entry *tmff2) firmware_err: kfree(t300rs->send_buffer); -t300rs_err: - kfree(t300rs); send_err: - hid_err(tmff2->hdev, "failed creating force feedback device\n"); + kfree(t300rs); +t300rs_err: + hid_err(tmff2->hdev, "failed initializing T300RS\n"); return ret; } @@ -1462,19 +1463,19 @@ static __u8 *t300rs_wheel_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { switch (hdev->product) { - case 0xb66e: + case TMT300RS_PS3_NORM_ID: /* normal PS3 mode */ rdesc = t300rs_rdesc_nrm_fixed; *rsize = sizeof(t300rs_rdesc_nrm_fixed); break; - case 0xb66d: + case TMT300RS_PS4_NORM_ID: /* PS4 normal mode */ rdesc = t300rs_rdesc_ps4_fixed; *rsize = sizeof(t300rs_rdesc_ps4_fixed); break; - case 0xb66f: + case TMT300RS_PS3_ADV_ID: /* PS3 advanced mode */ rdesc = t300rs_rdesc_adv_fixed; *rsize = sizeof(t300rs_rdesc_adv_fixed); -- cgit v1.3 From 725e8ea20b616b8cd29865a8819112ae2c61c54f Mon Sep 17 00:00:00 2001 From: Kimplul Date: Sun, 20 Mar 2022 19:41:25 +0200 Subject: add initial t248 support --- Kbuild | 2 +- TODO | 3 + hid-tmff2.c | 7 ++ hid-tmff2.h | 38 ++++++++++- hid-tmt248.c | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hid-tmt300rs.c | 34 +++------- 6 files changed, 256 insertions(+), 29 deletions(-) create mode 100644 hid-tmt248.c (limited to 'hid-tmff2.h') diff --git a/Kbuild b/Kbuild index 697f3e1..590c69d 100644 --- a/Kbuild +++ b/Kbuild @@ -1,2 +1,2 @@ obj-m := hid-tmff-new.o -hid-tmff-new-y := hid-tmff2.o hid-tmt300rs.o +hid-tmff-new-y := hid-tmff2.o hid-tmt300rs.o hid-tmt248.o diff --git a/TODO b/TODO index 87db3d1..70d3652 100644 --- a/TODO +++ b/TODO @@ -2,3 +2,6 @@ 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 index 2e7221f..4aa6141 100644 --- a/hid-tmff2.c +++ b/hid-tmff2.c @@ -552,6 +552,11 @@ static int tmff2_probe(struct hid_device *hdev, const struct hid_device_id *id) goto wheel_err; break; + case TMT248_PC_ID: + if ((ret = t248_populate_api(tmff2))) + goto wheel_err; + break; + default: ret = -ENODEV; goto wheel_err; @@ -634,6 +639,8 @@ static const struct hid_device_id tmff2_devices[] = { {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); diff --git a/hid-tmff2.h b/hid-tmff2.h index d59104a..f474ca7 100644 --- a/hid-tmff2.h +++ b/hid-tmff2.h @@ -91,9 +91,41 @@ struct tmff2_device_entry { /* 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 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); + + 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); #endif /* __HID_TMFF2_H */ diff --git a/hid-tmt248.c b/hid-tmt248.c new file mode 100644 index 0000000..5a19bb0 --- /dev/null +++ b/hid-tmt248.c @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#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 + ; + +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 +}; + +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; + + /* TODO: send usb commands to actually open device */ + return t248->open(t248->input_dev); +} + +static int t248_close(void *data) +{ + struct t300rs_device_entry *t248 = data; + if (!t248) + return -ENODEV; + + /* TODO: send usb commands to actually close device */ + t248->close(t248->input_dev); + return 0; +} + +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->wheel_init = t248_wheel_init; + tmff2->wheel_destroy = t248_wheel_destroy; + + tmff2->open = t248_open; + tmff2->close = t248_close; + tmff2->set_gain = t300rs_set_gain; + /* T248 only has 900 degree range, instead of T300RS 1080 */ + tmff2->set_range = t248_set_range; + tmff2->set_autocenter = t300rs_set_autocenter; + + return 0; +} diff --git a/hid-tmt300rs.c b/hid-tmt300rs.c index 8c4655b..92e9acd 100644 --- a/hid-tmt300rs.c +++ b/hid-tmt300rs.c @@ -75,22 +75,6 @@ struct usb_ctrlrequest t300rs_fw_request = { .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; - - int (*open)(struct input_dev *dev); - void (*close)(struct input_dev *dev); - - u8 buffer_length; - u8 *send_buffer; -}; - - struct t300rs_data { unsigned long quirks; void *device_props; @@ -390,7 +374,7 @@ static void t300rs_fill_header(struct t300rs_packet_header *packet_header, packet_header->code = code; } -static int t300rs_play_effect(void *data, struct tmff2_effect_state *state) +int t300rs_play_effect(void *data, struct tmff2_effect_state *state) { struct t300rs_device_entry *t300rs = data; struct __packed t300rs_packet_play { @@ -411,7 +395,7 @@ static int t300rs_play_effect(void *data, struct tmff2_effect_state *state) return ret; } -static int t300rs_stop_effect(void *data, struct tmff2_effect_state *state) +int t300rs_stop_effect(void *data, struct tmff2_effect_state *state) { struct t300rs_device_entry *t300rs = data; struct __packed t300rs_packet_stop { @@ -1132,7 +1116,7 @@ static int t300rs_upload_periodic(struct t300rs_device_entry *t300rs, return ret; } -static int t300rs_update_effect(void *data, struct tmff2_effect_state *state) +int t300rs_update_effect(void *data, struct tmff2_effect_state *state) { struct t300rs_device_entry *t300rs = data; switch (state->effect.type) { @@ -1154,7 +1138,7 @@ static int t300rs_update_effect(void *data, struct tmff2_effect_state *state) } } -static int t300rs_upload_effect(void *data, struct tmff2_effect_state *state) +int t300rs_upload_effect(void *data, struct tmff2_effect_state *state) { struct t300rs_device_entry *t300rs = data; switch (state->effect.type) { @@ -1201,7 +1185,7 @@ static int t300rs_switch_mode(void *data, uint16_t mode) return 0; } -static int t300rs_set_autocenter(void *data, uint16_t value) +int t300rs_set_autocenter(void *data, uint16_t value) { struct t300rs_device_entry *t300rs = data; struct __packed t300rs_packet_autocenter { @@ -1236,7 +1220,7 @@ static int t300rs_set_autocenter(void *data, uint16_t value) return ret; } -static int t300rs_set_gain(void *data, uint16_t gain) +int t300rs_set_gain(void *data, uint16_t gain) { struct t300rs_device_entry *t300rs = data; struct __packed t300rs_packet_gain { @@ -1257,7 +1241,7 @@ static int t300rs_set_gain(void *data, uint16_t gain) return ret; } -static int t300rs_set_range(void *data, uint16_t value) +int t300rs_set_range(void *data, uint16_t value) { struct t300rs_device_entry *t300rs = data; /* it's important that we don't use t300rs->send_buffer, as range can be @@ -1299,7 +1283,7 @@ err: return ret; } -static int t300rs_open(void *data) +int t300rs_open(void *data) { struct t300rs_device_entry *t300rs = data; struct __packed t300rs_packet_open { @@ -1319,7 +1303,7 @@ static int t300rs_open(void *data) return t300rs->open(t300rs->input_dev); } -static int t300rs_close(void *data) +int t300rs_close(void *data) { struct t300rs_device_entry *t300rs = data; struct t300rs_packet_close { -- cgit v1.3 From fed8081d45d05ecf2b557515e17a5005b90a7e96 Mon Sep 17 00:00:00 2001 From: Kimplul Date: Wed, 23 Mar 2022 18:39:27 +0200 Subject: test open/close --- hid-tmff2.h | 3 +++ hid-tmt248.c | 18 ++++++++++++++++-- hid-tmt300rs.c | 4 ++-- 3 files changed, 21 insertions(+), 4 deletions(-) (limited to 'hid-tmff2.h') diff --git a/hid-tmff2.h b/hid-tmff2.h index f474ca7..b396d78 100644 --- a/hid-tmff2.h +++ b/hid-tmff2.h @@ -128,4 +128,7 @@ 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 index 2881ffc..f3d4700 100644 --- a/hid-tmt248.c +++ b/hid-tmt248.c @@ -243,7 +243,14 @@ static int t248_open(void *data) if (!t248) return -ENODEV; - /* TODO: send usb commands to actually open device */ + 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); } @@ -253,7 +260,14 @@ static int t248_close(void *data) if (!t248) return -ENODEV; - /* TODO: send usb commands to actually close device */ + 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; } diff --git a/hid-tmt300rs.c b/hid-tmt300rs.c index 92e9acd..167262c 100644 --- a/hid-tmt300rs.c +++ b/hid-tmt300rs.c @@ -340,7 +340,7 @@ static u8 damper_values[] = { 0x7f, 0x07 }; -static int t300rs_send_buf(struct t300rs_device_entry *t300rs, u8 *send_buffer, size_t len) +int t300rs_send_buf(struct t300rs_device_entry *t300rs, u8 *send_buffer, size_t len) { int i; /* check that send_buffer fits into our report */ @@ -359,7 +359,7 @@ static int t300rs_send_buf(struct t300rs_device_entry *t300rs, u8 *send_buffer, return 0; } -static int t300rs_send_int(struct t300rs_device_entry *t300rs) +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); -- cgit v1.3 From 62412528ae90b37172675264d7129663a0341ccb Mon Sep 17 00:00:00 2001 From: Kimplul Date: Wed, 23 Mar 2022 22:39:07 +0200 Subject: fixed possible kernel oops when unplugging device --- hid-tmff2.c | 2 +- hid-tmff2.h | 4 ++-- hid-tmt248.c | 16 +++++++++------- hid-tmt300rs.c | 12 +++++++----- 4 files changed, 19 insertions(+), 15 deletions(-) (limited to 'hid-tmff2.h') diff --git a/hid-tmff2.c b/hid-tmff2.c index 4aa6141..3cfd1ad 100644 --- a/hid-tmff2.c +++ b/hid-tmff2.c @@ -627,8 +627,8 @@ static void tmff2_remove(struct hid_device *hdev) if (tmff2->params & PARAM_ALT_MODE) device_remove_file(dev, &dev_attr_alt_mode); - tmff2->wheel_destroy(tmff2->data); hid_hw_stop(hdev); + tmff2->wheel_destroy(tmff2->data); kfree(tmff2->states); kfree(tmff2); diff --git a/hid-tmff2.h b/hid-tmff2.h index b396d78..4058cf7 100644 --- a/hid-tmff2.h +++ b/hid-tmff2.h @@ -79,7 +79,7 @@ struct tmff2_device_entry { /* optional callbacks */ int (*open)(void *data); - int (*close)(void *data); + int (*close)(void *data, int dev_accessible); int (*set_gain)(void *data, uint16_t gain); int (*set_range)(void *data, uint16_t range); int (*switch_mode)(void *data, uint16_t mode); @@ -123,7 +123,7 @@ 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_close(void *, int); int t300rs_set_gain(void *, uint16_t); int t300rs_set_range(void *, uint16_t); int t300rs_set_autocenter(void *, uint16_t); diff --git a/hid-tmt248.c b/hid-tmt248.c index f3d4700..839f670 100644 --- a/hid-tmt248.c +++ b/hid-tmt248.c @@ -254,19 +254,21 @@ static int t248_open(void *data) return t248->open(t248->input_dev); } -static int t248_close(void *data) +static int t248_close(void *data, int dev_accessible) { struct t300rs_device_entry *t248 = data; if (!t248) return -ENODEV; - t248->send_buffer[0] = 0x01; - t248->send_buffer[1] = 0x05; - t300rs_send_int(t248); + if (dev_accessible) { + 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->send_buffer[0] = 0x01; + t248->send_buffer[1] = 0x00; + t300rs_send_int(t248); + } t248->close(t248->input_dev); return 0; diff --git a/hid-tmt300rs.c b/hid-tmt300rs.c index 167262c..c2a6c64 100644 --- a/hid-tmt300rs.c +++ b/hid-tmt300rs.c @@ -1303,7 +1303,7 @@ int t300rs_open(void *data) return t300rs->open(t300rs->input_dev); } -int t300rs_close(void *data) +int t300rs_close(void *data, int dev_accessible) { struct t300rs_device_entry *t300rs = data; struct t300rs_packet_close { @@ -1314,11 +1314,13 @@ int t300rs_close(void *data) if (!t300rs) return -ENODEV; - close_packet = (struct t300rs_packet_close *)t300rs->send_buffer; - close_packet->header.cmd = 0x01; + if (dev_accessible) { + close_packet = (struct t300rs_packet_close *)t300rs->send_buffer; + close_packet->header.cmd = 0x01; - if ((ret = t300rs_send_int(t300rs))) - hid_warn(t300rs->hdev, "failed sending close command\n"); + if ((ret = t300rs_send_int(t300rs))) + hid_warn(t300rs->hdev, "failed sending close command\n"); + } t300rs->close(t300rs->input_dev); return ret; -- cgit v1.3 From 51623455c8136f40f47ad98a0532ea70dd1c99e4 Mon Sep 17 00:00:00 2001 From: Kimplul Date: Thu, 24 Mar 2022 13:34:49 +0200 Subject: fix work handler being run after destruction --- hid-tmff2.c | 47 +++++++++++++++++++++++++++++++++++------------ hid-tmff2.h | 6 ++++-- hid-tmt248.c | 22 +++++++++++++--------- hid-tmt300rs.c | 12 +++++------- 4 files changed, 57 insertions(+), 30 deletions(-) (limited to 'hid-tmff2.h') diff --git a/hid-tmff2.c b/hid-tmff2.c index d632b09..fe4950d 100644 --- a/hid-tmff2.c +++ b/hid-tmff2.c @@ -43,10 +43,10 @@ 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))) { + + if (!(tmff2 = hid_get_drvdata(hdev))) dev_err(&hdev->dev, "hdev private data not found\n"); - return NULL; - } + spin_unlock_irqrestore(&lock, lock_flags); return tmff2; @@ -56,10 +56,10 @@ 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))) { + + if (!(hdev = input_get_drvdata(input_dev))) dev_err(&input_dev->dev, "input_dev private data not found\n"); - return NULL; - } + spin_unlock_irqrestore(&lock, lock_flags); return tmff2_from_hdev(hdev); @@ -90,6 +90,7 @@ static ssize_t spring_level_store(struct device *dev, 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); @@ -100,6 +101,7 @@ static ssize_t damper_level_store(struct device *dev, unsigned int value; int ret; + ret = kstrtouint(buf, 0, &value); if (ret) { dev_err(dev, "kstrtouint failed at damper_level_store: %i", ret); @@ -119,6 +121,7 @@ static ssize_t damper_level_store(struct device *dev, 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); @@ -129,6 +132,7 @@ static ssize_t friction_level_store(struct device *dev, unsigned int value; int ret; + ret = kstrtouint(buf, 0, &value); if (ret) { dev_err(dev, "kstrtouint failed at friction_level_store: %i", ret); @@ -150,6 +154,7 @@ static ssize_t friction_level_show(struct device *dev, { size_t count; + count = scnprintf(buf, PAGE_SIZE, "%u\n", friction_level); return count; @@ -163,6 +168,7 @@ static ssize_t range_store(struct device *dev, unsigned int value; int ret; + if (!tmff2) return -ENODEV; @@ -182,6 +188,7 @@ static ssize_t range_store(struct device *dev, 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); @@ -193,6 +200,7 @@ static ssize_t alt_mode_store(struct device *dev, unsigned int value; int ret; + if (!tmff2) return -ENODEV; @@ -215,6 +223,7 @@ static ssize_t alt_mode_show(struct device *dev, /* TODO: could be cool to add in something like a small menu that gives * names and corresponding index to modes, or maybe parsing modes * directly? */ + return scnprintf(buf, PAGE_SIZE, "%i\n", alt_mode); } static DEVICE_ATTR_RW(alt_mode); @@ -222,6 +231,7 @@ static DEVICE_ATTR_RW(alt_mode); static void tmff2_set_gain(struct input_dev *dev, uint16_t gain) { struct tmff2_device_entry *tmff2 = tmff2_from_input(dev); + if (!tmff2) return; @@ -237,6 +247,7 @@ static void tmff2_set_gain(struct input_dev *dev, uint16_t gain) static void tmff2_set_autocenter(struct input_dev *dev, uint16_t autocenter) { struct tmff2_device_entry *tmff2 = tmff2_from_input(dev); + if (!tmff2) return; @@ -258,6 +269,7 @@ static void tmff2_work_handler(struct work_struct *w) unsigned long time_now; __u16 effect_length; + if (!tmff2) return; @@ -324,7 +336,7 @@ static void tmff2_work_handler(struct work_struct *w) spin_unlock(&tmff2->lock); } - if (max_count) + if (max_count && tmff2->allow_scheduling) schedule_delayed_work(&tmff2->work, msecs_to_jiffies(timer_msecs)); } @@ -333,6 +345,7 @@ static int tmff2_upload(struct input_dev *dev, { struct tmff2_effect_state *state; struct tmff2_device_entry *tmff2 = tmff2_from_input(dev); + if (!tmff2) return -ENODEV; @@ -362,6 +375,7 @@ 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; @@ -382,7 +396,7 @@ static int tmff2_play(struct input_dev *dev, int effect_id, int value) spin_unlock(&tmff2->lock); - if (!delayed_work_pending(&tmff2->work)) + if (!delayed_work_pending(&tmff2->work) && tmff2->allow_scheduling) schedule_delayed_work(&tmff2->work, 0); return 0; @@ -391,6 +405,7 @@ static int tmff2_play(struct input_dev *dev, int effect_id, int value) static int tmff2_open(struct input_dev *dev) { struct tmff2_device_entry *tmff2 = tmff2_from_input(dev); + if (!tmff2) return -ENODEV; @@ -404,11 +419,15 @@ static int tmff2_open(struct input_dev *dev) 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, tmff2->hdev != 0); + tmff2->close(tmff2->data); return; } @@ -420,6 +439,7 @@ 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_ALT_MODE) { if ((ret = device_create_file(dev, &dev_attr_alt_mode))) { @@ -474,6 +494,7 @@ 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); @@ -522,6 +543,7 @@ static int tmff2_wheel_init(struct tmff2_device_entry *tmff2) if ((ret = tmff2_create_files(tmff2))) goto err; + tmff2->allow_scheduling = 1; return 0; input_ff_destroy(tmff2->input_dev); @@ -536,6 +558,7 @@ static int tmff2_probe(struct hid_device *hdev, const struct hid_device_id *id) int ret; + if (!tmff2) { ret = -ENOMEM; goto oom_err; @@ -596,6 +619,7 @@ 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; @@ -609,9 +633,11 @@ 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; @@ -627,9 +653,6 @@ static void tmff2_remove(struct hid_device *hdev) if (tmff2->params & PARAM_ALT_MODE) device_remove_file(dev, &dev_attr_alt_mode); - /* indicate that the underlying usb device should not be assumed to be - * accessible */ - tmff2->hdev = 0; hid_hw_stop(hdev); tmff2->wheel_destroy(tmff2->data); diff --git a/hid-tmff2.h b/hid-tmff2.h index 4058cf7..390bd94 100644 --- a/hid-tmff2.h +++ b/hid-tmff2.h @@ -62,6 +62,8 @@ struct tmff2_device_entry { spinlock_t lock; + int allow_scheduling; + /* fields relevant to each actual device (T300, T150...) */ void *data; unsigned long params; @@ -79,7 +81,7 @@ struct tmff2_device_entry { /* optional callbacks */ int (*open)(void *data); - int (*close)(void *data, int dev_accessible); + int (*close)(void *data); int (*set_gain)(void *data, uint16_t gain); int (*set_range)(void *data, uint16_t range); int (*switch_mode)(void *data, uint16_t mode); @@ -123,7 +125,7 @@ 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); +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); diff --git a/hid-tmt248.c b/hid-tmt248.c index 839f670..aef2944 100644 --- a/hid-tmt248.c +++ b/hid-tmt248.c @@ -133,6 +133,7 @@ static int t248_interrupts(struct t300rs_device_entry *t248) 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; @@ -167,6 +168,7 @@ int t248_wheel_init(struct tmff2_device_entry *tmff2) struct list_head *report_list; int ret; + if (!t248) { ret = -ENOMEM; goto t248_err; @@ -213,6 +215,7 @@ t248_err: int t248_wheel_destroy(void *data) { struct t300rs_device_entry *t300rs = data; + if (!t300rs) return -ENODEV; @@ -224,6 +227,7 @@ int t248_wheel_destroy(void *data) 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; @@ -240,6 +244,7 @@ int t248_set_range(void *data, uint16_t value) static int t248_open(void *data) { struct t300rs_device_entry *t248 = data; + if (!t248) return -ENODEV; @@ -254,21 +259,20 @@ static int t248_open(void *data) return t248->open(t248->input_dev); } -static int t248_close(void *data, int dev_accessible) +static int t248_close(void *data) { struct t300rs_device_entry *t248 = data; + if (!t248) return -ENODEV; - if (dev_accessible) { - t248->send_buffer[0] = 0x01; - t248->send_buffer[1] = 0x05; - t300rs_send_int(t248); + 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->send_buffer[0] = 0x01; + t248->send_buffer[1] = 0x00; + t300rs_send_int(t248); t248->close(t248->input_dev); return 0; diff --git a/hid-tmt300rs.c b/hid-tmt300rs.c index c2a6c64..167262c 100644 --- a/hid-tmt300rs.c +++ b/hid-tmt300rs.c @@ -1303,7 +1303,7 @@ int t300rs_open(void *data) return t300rs->open(t300rs->input_dev); } -int t300rs_close(void *data, int dev_accessible) +int t300rs_close(void *data) { struct t300rs_device_entry *t300rs = data; struct t300rs_packet_close { @@ -1314,13 +1314,11 @@ int t300rs_close(void *data, int dev_accessible) if (!t300rs) return -ENODEV; - if (dev_accessible) { - close_packet = (struct t300rs_packet_close *)t300rs->send_buffer; - close_packet->header.cmd = 0x01; + close_packet = (struct t300rs_packet_close *)t300rs->send_buffer; + close_packet->header.cmd = 0x01; - if ((ret = t300rs_send_int(t300rs))) - hid_warn(t300rs->hdev, "failed sending close command\n"); - } + if ((ret = t300rs_send_int(t300rs))) + hid_warn(t300rs->hdev, "failed sending close command\n"); t300rs->close(t300rs->input_dev); return ret; -- cgit v1.3 From 2814c3eb42a0ed97d40a42aaefa1bfcd79781bdc Mon Sep 17 00:00:00 2001 From: Kimplul Date: Thu, 24 Mar 2022 20:43:42 +0200 Subject: add master gain --- hid-tmff2.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ hid-tmff2.h | 2 ++ hid-tmt248.c | 1 + hid-tmt300rs.c | 1 + 4 files changed, 64 insertions(+), 7 deletions(-) (limited to 'hid-tmff2.h') diff --git a/hid-tmff2.c b/hid-tmff2.c index fe4950d..f5202ae 100644 --- a/hid-tmff2.c +++ b/hid-tmff2.c @@ -29,12 +29,18 @@ MODULE_PARM_DESC(friction_level, int range = 900; module_param(range, int, 0); MODULE_PARM_DESC(range, - "Range of wheel, depends on the wheel. Invalid values are ignored."); + "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."); + "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; @@ -228,7 +234,36 @@ static ssize_t alt_mode_show(struct device *dev, } static DEVICE_ATTR_RW(alt_mode); -static void tmff2_set_gain(struct input_dev *dev, uint16_t gain) +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); @@ -240,11 +275,11 @@ static void tmff2_set_gain(struct input_dev *dev, uint16_t gain) return; } - if (tmff2->set_gain(tmff2->data, gain)) + 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 autocenter) +static void tmff2_set_autocenter(struct input_dev *dev, uint16_t value) { struct tmff2_device_entry *tmff2 = tmff2_from_input(dev); @@ -256,7 +291,7 @@ static void tmff2_set_autocenter(struct input_dev *dev, uint16_t autocenter) return; } - if (tmff2->set_autocenter(tmff2->data, autocenter)) + if (tmff2->set_autocenter(tmff2->data, value)) hid_warn(tmff2->hdev, "unable to set autocenter\n"); } @@ -441,6 +476,13 @@ static int tmff2_create_files(struct tmff2_device_entry *tmff2) /* 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_alt_mode))) { hid_err(tmff2->hdev, "unable to create sysfs for alt_mode\n"); @@ -487,6 +529,8 @@ spring_err: range_err: device_remove_file(dev, &dev_attr_alt_mode); alt_err: + device_remove_file(dev, &dev_attr_gain); +gain_err: return ret; } @@ -533,12 +577,18 @@ static int tmff2_wheel_init(struct tmff2_device_entry *tmff2) if (tmff2->close) tmff2->input_dev->close = tmff2_close; - if (tmff2->set_gain) + /* 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); + /* create files */ if ((ret = tmff2_create_files(tmff2))) goto err; @@ -653,6 +703,9 @@ static void tmff2_remove(struct hid_device *hdev) if (tmff2->params & PARAM_ALT_MODE) device_remove_file(dev, &dev_attr_alt_mode); + if (tmff2->params & PARAM_GAIN) + device_remove_file(dev, &dev_attr_gain); + hid_hw_stop(hdev); tmff2->wheel_destroy(tmff2->data); diff --git a/hid-tmff2.h b/hid-tmff2.h index 390bd94..765f071 100644 --- a/hid-tmff2.h +++ b/hid-tmff2.h @@ -11,6 +11,7 @@ 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 @@ -34,6 +35,7 @@ extern int alt_mode; #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) ?\ diff --git a/hid-tmt248.c b/hid-tmt248.c index aef2944..e241301 100644 --- a/hid-tmt248.c +++ b/hid-tmt248.c @@ -29,6 +29,7 @@ static const unsigned long t248_params = | PARAM_DAMPER_LEVEL | PARAM_FRICTION_LEVEL | PARAM_RANGE + | PARAM_GAIN ; static const signed short t248_effects[] = { diff --git a/hid-tmt300rs.c b/hid-tmt300rs.c index 167262c..5e4a848 100644 --- a/hid-tmt300rs.c +++ b/hid-tmt300rs.c @@ -11,6 +11,7 @@ static const unsigned long t300rs_params = PARAM_SPRING_LEVEL | PARAM_DAMPER_LEVEL | PARAM_FRICTION_LEVEL + | PARAM_GAIN | PARAM_RANGE | PARAM_ALT_MODE ; -- cgit v1.3 From 41c46e46415bfe9d393a5a3858f0c58f0a914c6b Mon Sep 17 00:00:00 2001 From: Kimplul Date: Fri, 25 Mar 2022 14:14:18 +0200 Subject: change alternate mode handling --- hid-tmff2.c | 45 ++++++++++++++++------------------ hid-tmff2.h | 5 ++++ hid-tmt300rs.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 100 insertions(+), 27 deletions(-) (limited to 'hid-tmff2.h') diff --git a/hid-tmff2.c b/hid-tmff2.c index f5202ae..12e8e25 100644 --- a/hid-tmff2.c +++ b/hid-tmff2.c @@ -199,40 +199,34 @@ static ssize_t range_show(struct device *dev, } static DEVICE_ATTR_RW(range); -static ssize_t alt_mode_store(struct device *dev, +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)); - unsigned int value; - int ret; - if (!tmff2) return -ENODEV; - if ((ret = kstrtouint(buf, 0, &value))) { - hid_err(tmff2->hdev, "kstrtouint failed at alt_mode_store: %i", ret); - return ret; - } - - if (tmff2->switch_mode) { - if ((ret = tmff2->switch_mode(tmff2->data, value))) - return ret; - } + if (tmff2->alt_mode_store) + return tmff2->alt_mode_store(tmff2->data, buf, count); - return count; + return 0; } -static ssize_t alt_mode_show(struct device *dev, +static ssize_t alternate_modes_show(struct device *dev, struct device_attribute *attr, char *buf) { - /* TODO: could be cool to add in something like a small menu that gives - * names and corresponding index to modes, or maybe parsing modes - * directly? */ + struct tmff2_device_entry *tmff2 = tmff2_from_hdev(to_hid_device(dev)); - return scnprintf(buf, PAGE_SIZE, "%i\n", alt_mode); + if (!tmff2) + return -ENODEV; + + if (tmff2->alt_mode_show) + return tmff2->alt_mode_show(tmff2->data, buf); + + return 0; } -static DEVICE_ATTR_RW(alt_mode); +static DEVICE_ATTR_RW(alternate_modes); static ssize_t gain_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -484,8 +478,8 @@ static int tmff2_create_files(struct tmff2_device_entry *tmff2) } if (tmff2->params & PARAM_ALT_MODE) { - if ((ret = device_create_file(dev, &dev_attr_alt_mode))) { - hid_err(tmff2->hdev, "unable to create sysfs for alt_mode\n"); + 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; } } @@ -527,7 +521,7 @@ damper_err: spring_err: device_remove_file(dev, &dev_attr_range); range_err: - device_remove_file(dev, &dev_attr_alt_mode); + device_remove_file(dev, &dev_attr_alternate_modes); alt_err: device_remove_file(dev, &dev_attr_gain); gain_err: @@ -589,6 +583,9 @@ static int tmff2_wheel_init(struct tmff2_device_entry *tmff2) 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; @@ -701,7 +698,7 @@ static void tmff2_remove(struct hid_device *hdev) device_remove_file(dev, &dev_attr_range); if (tmff2->params & PARAM_ALT_MODE) - device_remove_file(dev, &dev_attr_alt_mode); + device_remove_file(dev, &dev_attr_alternate_modes); if (tmff2->params & PARAM_GAIN) device_remove_file(dev, &dev_attr_gain); diff --git a/hid-tmff2.h b/hid-tmff2.h index 765f071..a57b434 100644 --- a/hid-tmff2.h +++ b/hid-tmff2.h @@ -86,7 +86,11 @@ struct tmff2_device_entry { 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); @@ -117,6 +121,7 @@ struct t300rs_device_entry { int (*open)(struct input_dev *dev); void (*close)(struct input_dev *dev); + int mode; u8 buffer_length; u8 *send_buffer; }; diff --git a/hid-tmt300rs.c b/hid-tmt300rs.c index 5e4a848..687832f 100644 --- a/hid-tmt300rs.c +++ b/hid-tmt300rs.c @@ -1167,25 +1167,94 @@ static int t300rs_switch_mode(void *data, uint16_t mode) if (!t300rs) return -ENODEV; - if(alt_mode == mode) /* already in specified mode */ + if(t300rs->mode == mode) /* already in specified mode */ return 0; 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 + 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); + return 0; } +static struct t300rs_alt_modes { + char *id; + char *label; + uint16_t mode; +} t300rs_modes[] = { + {"native", "T300RS base", 0}, + {"F1", "T300RS with F1 wheel attachment", 1} +}; + +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; + + 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 (count >= PAGE_SIZE - 1) + return count; + + if (t300rs_modes[i].mode == t300rs->mode) + count += scnprintf(buf + count, PAGE_SIZE - count, " *\n"); + else + count += scnprintf(buf + count, PAGE_SIZE - count, "\n"); + + if (count >= PAGE_SIZE - 1) + return count; + } + + return count; +} + +static ssize_t t300rs_alt_mode_store(void *data, const char *buf, size_t count) +{ + struct tmff2_device_entry *t300rs = data; + int i, len, mode_len; + char *lbuf; + if (!t300rs) + return -ENODEV; + + lbuf = kasprintf(GFP_KERNEL, "%s", buf); + if (!lbuf) + return -ENOMEM; + + len = strlen(buf); + for (i = 0; i < ARRAY_SIZE(t300rs_modes); ++i) { + mode_len = strlen(t300rs_modes[i].id); + if (mode_len > len) + continue; + + if (strncmp(lbuf, t300rs_modes[i].id, mode_len) == 0) { + t300rs_switch_mode(data, t300rs_modes[i].mode); + break; + } + } + + kfree(lbuf); + return count; +} + int t300rs_set_autocenter(void *data, uint16_t value) { struct t300rs_device_entry *t300rs = data; @@ -1413,7 +1482,7 @@ static int t300rs_wheel_init(struct tmff2_device_entry *tmff2) t300rs->close = t300rs->input_dev->close; /* TODO: PS4 advanced mode? */ - alt_mode = (t300rs->hdev->product == TMT300RS_PS3_ADV_ID); + t300rs->mode = (t300rs->hdev->product == TMT300RS_PS3_ADV_ID); /* everythin went OK */ tmff2->data = t300rs; @@ -1486,6 +1555,8 @@ int t300rs_populate_api(struct tmff2_device_entry *tmff2) 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; -- cgit v1.3 From bb853865fce78d062186c808dc63fcfe12ebf195 Mon Sep 17 00:00:00 2001 From: Kimplul Date: Fri, 25 Mar 2022 15:23:59 +0200 Subject: allow only specific attachments to change mode --- hid-tmff2.h | 1 + hid-tmt300rs.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 88 insertions(+), 1 deletion(-) (limited to 'hid-tmff2.h') diff --git a/hid-tmff2.h b/hid-tmff2.h index a57b434..d5de938 100644 --- a/hid-tmff2.h +++ b/hid-tmff2.h @@ -122,6 +122,7 @@ struct t300rs_device_entry { void (*close)(struct input_dev *dev); int mode; + int attachment; u8 buffer_length; u8 *send_buffer; }; diff --git a/hid-tmt300rs.c b/hid-tmt300rs.c index 687832f..c5b4655 100644 --- a/hid-tmt300rs.c +++ b/hid-tmt300rs.c @@ -7,6 +7,9 @@ #define T300RS_NORM_BUFFER_LENGTH 63 #define T300RS_PS4_BUFFER_LENGTH 31 +#define T300RS_DEFAULT_ATTACHMENT 0x06 +#define T300RS_F1_ATTACHMENT 0x03 + static const unsigned long t300rs_params = PARAM_SPRING_LEVEL | PARAM_DAMPER_LEVEL @@ -1208,6 +1211,11 @@ static ssize_t t300rs_alt_mode_show(void *data, char *buf) if (!t300rs) return -ENODEV; + if (t300rs->attachment != T300RS_F1_ATTACHMENT) + /* we only support one native mode */ + return scnprintf(buf, PAGE_SIZE, "%s: %s *\n", + t300rs_modes[0].id, t300rs_modes[0].label); + 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); @@ -1229,12 +1237,15 @@ static ssize_t t300rs_alt_mode_show(void *data, char *buf) static ssize_t t300rs_alt_mode_store(void *data, const char *buf, size_t count) { - struct tmff2_device_entry *t300rs = data; + struct t300rs_device_entry *t300rs = data; int i, len, mode_len; char *lbuf; if (!t300rs) return -ENODEV; + if (t300rs->attachment != T300RS_F1_ATTACHMENT) + return count; /* don't do anything */ + lbuf = kasprintf(GFP_KERNEL, "%s", buf); if (!lbuf) return -ENOMEM; @@ -1443,6 +1454,79 @@ out: return ret; } +static int t300rs_get_attachment(struct t300rs_device_entry *t300rs) +{ + /* taken directly from hid_tminit */ + struct __packed t300rs_attachment_response + { + uint16_t type; + + 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; + + 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 = 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; + } + + 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; + } + + kfree(response); + return attachment; + +out: + kfree(response); + return ret; +} + static int t300rs_wheel_init(struct tmff2_device_entry *tmff2) { struct t300rs_device_entry *t300rs = kzalloc(sizeof(struct t300rs_device_entry), GFP_KERNEL); @@ -1483,6 +1567,8 @@ static int t300rs_wheel_init(struct tmff2_device_entry *tmff2) /* TODO: PS4 advanced mode? */ t300rs->mode = (t300rs->hdev->product == TMT300RS_PS3_ADV_ID); + if ((t300rs->attachment = t300rs_get_attachment(t300rs)) < 0) + t300rs->attachment = T300RS_DEFAULT_ATTACHMENT; /* everythin went OK */ tmff2->data = t300rs; -- cgit v1.3