diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2022-03-20 19:41:25 +0200 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2022-03-20 19:41:25 +0200 |
| commit | 725e8ea20b616b8cd29865a8819112ae2c61c54f (patch) | |
| tree | ad3873b3755e235fe95d3385271b4f883b6248b4 | |
| parent | 28d0a3f76748a2555fc1417216ed51112dba945c (diff) | |
| download | hid-tmff2-725e8ea20b616b8cd29865a8819112ae2c61c54f.tar.gz hid-tmff2-725e8ea20b616b8cd29865a8819112ae2c61c54f.zip | |
add initial t248 support
| -rw-r--r-- | Kbuild | 2 | ||||
| -rw-r--r-- | TODO | 3 | ||||
| -rw-r--r-- | hid-tmff2.c | 7 | ||||
| -rw-r--r-- | hid-tmff2.h | 38 | ||||
| -rw-r--r-- | hid-tmt248.c | 201 | ||||
| -rw-r--r-- | hid-tmt300rs.c | 34 |
6 files changed, 256 insertions, 29 deletions
@@ -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 @@ -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 <linux/usb.h> +#include <linux/hid.h> +#include "hid-tmff2.h" + +#define T248_MAX_EFFECTS 16 +#define T248_BUFFER_LENGTH 63 + +static const u8 setup_0[64] = { 0x42, 0x01 }; +static const u8 setup_1[64] = { 0x0a, 0x04, 0x90, 0x03 }; +static const u8 setup_2[64] = { 0x0a, 0x04, 0x00, 0x0c }; +static const u8 setup_3[64] = { 0x0a, 0x04, 0x12, 0x10 }; +static const u8 setup_4[64] = { 0x0a, 0x04, 0x00, 0x06 }; +static const u8 setup_5[64] = { 0x0a, 0x04, 0x00, 0x0e }; +static const u8 setup_6[64] = { 0x0a, 0x04, 0x00, 0x0e, 0x01 }; +static const u8 *const setup_arr[] = { setup_0, setup_1, setup_2, setup_3, setup_4, setup_5, setup_6 }; +static const unsigned int setup_arr_sizes[] = { + ARRAY_SIZE(setup_0), + ARRAY_SIZE(setup_1), + ARRAY_SIZE(setup_2), + ARRAY_SIZE(setup_3), + ARRAY_SIZE(setup_4), + ARRAY_SIZE(setup_5), + ARRAY_SIZE(setup_6) +}; + +static const unsigned long t248_params = + PARAM_SPRING_LEVEL + | PARAM_DAMPER_LEVEL + | PARAM_FRICTION_LEVEL + | PARAM_RANGE + ; + +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 { |
