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 --- hid-tmt248.c | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 hid-tmt248.c (limited to 'hid-tmt248.c') 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; +} -- cgit v1.3 From d12951deac141dcd026bc59ed9c0550f6630f345 Mon Sep 17 00:00:00 2001 From: Kimplul Date: Sun, 20 Mar 2022 19:45:51 +0200 Subject: dump default rdesc --- hid-tmt248.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'hid-tmt248.c') diff --git a/hid-tmt248.c b/hid-tmt248.c index 5a19bb0..1c51ba8 100644 --- a/hid-tmt248.c +++ b/hid-tmt248.c @@ -49,6 +49,11 @@ static const signed short t248_effects[] = { -1 }; +/* TODO: sort through this stuff */ +static u8 t248_pc_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, 0x31, 0x26, 0xff, 0x03, 0x46, 0xff, 0x03, 0x81, 0x02, 0x09, 0x35, 0x81, 0x02, 0x09, 0x36, 0x81, 0x02, 0x75, 0x08, 0x26, 0xff, 0x00, 0x46, 0xff, 0x00, 0x09, 0x40, 0x81, 0x02, 0x09, 0x41, 0x81, 0x02, 0x09, 0x33, 0x81, 0x02, 0x09, 0x34, 0x81, 0x02, 0x09, 0x32, 0x81, 0x02, 0x09, 0x37, 0x81, 0x02, 0x05, 0x09, 0x19, 0x01, 0x29, 0x1a, 0x25, 0x01, 0x45, 0x01, 0x75, 0x01, 0x95, 0x1a, 0x81, 0x02, 0x75, 0x06, 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, 0x0a, 0x06, 0x00, 0xff, 0x09, 0x0a, 0x75, 0x08, 0x95, 0x3f, 0x26, 0xff, 0x00, 0x46, 0xff, 0x00, 0x91, 0x02, 0x85, 0x02, 0x09, 0x02, 0x81, 0x02, 0x09, 0x14, 0x85, 0x14 0x81, 0x02, 0xc0, 0xc0 +}; + static int t248_interrupts(struct t300rs_device_entry *t248) { u8 *send_buf = kmalloc(256, GFP_KERNEL); -- cgit v1.3 From 3eba47f56dcb539b3dd475b9906ed9af7bd8db7f Mon Sep 17 00:00:00 2001 From: Kimplul Date: Mon, 21 Mar 2022 21:47:10 +0200 Subject: annotate t248 rdesc --- hid-tmt248.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- t248-effects.txt | 2 ++ 2 files changed, 92 insertions(+), 7 deletions(-) create mode 100644 t248-effects.txt (limited to 'hid-tmt248.c') diff --git a/hid-tmt248.c b/hid-tmt248.c index 1c51ba8..2881ffc 100644 --- a/hid-tmt248.c +++ b/hid-tmt248.c @@ -51,7 +51,80 @@ static const signed short t248_effects[] = { /* TODO: sort through this stuff */ static u8 t248_pc_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, 0x31, 0x26, 0xff, 0x03, 0x46, 0xff, 0x03, 0x81, 0x02, 0x09, 0x35, 0x81, 0x02, 0x09, 0x36, 0x81, 0x02, 0x75, 0x08, 0x26, 0xff, 0x00, 0x46, 0xff, 0x00, 0x09, 0x40, 0x81, 0x02, 0x09, 0x41, 0x81, 0x02, 0x09, 0x33, 0x81, 0x02, 0x09, 0x34, 0x81, 0x02, 0x09, 0x32, 0x81, 0x02, 0x09, 0x37, 0x81, 0x02, 0x05, 0x09, 0x19, 0x01, 0x29, 0x1a, 0x25, 0x01, 0x45, 0x01, 0x75, 0x01, 0x95, 0x1a, 0x81, 0x02, 0x75, 0x06, 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, 0x0a, 0x06, 0x00, 0xff, 0x09, 0x0a, 0x75, 0x08, 0x95, 0x3f, 0x26, 0xff, 0x00, 0x46, 0xff, 0x00, 0x91, 0x02, 0x85, 0x02, 0x09, 0x02, 0x81, 0x02, 0x09, 0x14, 0x85, 0x14 0x81, 0x02, 0xc0, 0xc0 + 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) @@ -185,6 +258,14 @@ static int t248_close(void *data) 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; @@ -192,15 +273,17 @@ int t248_populate_api(struct tmff2_device_entry *tmff2) 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; + tmff2->set_autocenter = t300rs_set_autocenter; /* T248 only has 900 degree range, instead of T300RS 1080 */ tmff2->set_range = t248_set_range; - tmff2->set_autocenter = t300rs_set_autocenter; + 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/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 -- 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-tmt248.c') 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-tmt248.c') 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-tmt248.c') 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-tmt248.c') 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