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(-) 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