aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/drivers/hid/hid-glorious.c
diff options
context:
space:
mode:
authorSamuel Čavoj <sammko@sammserver.com>2020-03-13 03:12:38 +0100
committerJiri Kosina <jkosina@suse.cz>2020-03-18 13:36:21 +0100
commit77a36a3ab4ff17fad23831192e3694a3c5a1750d (patch)
tree5f181a064cac936f529ef976b67573de2fd173ba /drivers/hid/hid-glorious.c
parentMerge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid (diff)
downloadwireguard-linux-77a36a3ab4ff17fad23831192e3694a3c5a1750d.tar.xz
wireguard-linux-77a36a3ab4ff17fad23831192e3694a3c5a1750d.zip
HID: Add driver fixing Glorious PC Gaming Race mouse report descriptor
The Glorious Model O mice (and also at least the Model O-, which is driver-wise the same mouse) have a bug in the descriptor of HID Report with ID 2. This report is used for Consumer Control buttons, which can be mapped using the provided Windows only software. Here is an excerpt from the original descriptor: INPUT(2)[INPUT] Field(0) Flags( Constant Variable Absolute ) Field(1) Flags( Constant Variable Absolute ) Field(2) Flags( Constant Variable Absolute ) The issue is the Constant flag specified on all 3 fields, which causes the hid driver to ignore changes in these fields and essentialy causes the buttons to not work at all. The submitted driver patches the descriptor to end up with the following: INPUT(2)[INPUT] Field(0) Flags( Variable Relative ) Field(1) Flags( Variable Relative ) Field(2) Flags( Variable Relative ) The Constant bit is reset and the Relative bit has been set in order to prevent repeat events when holding down the button. Additionally, the device name is changed from the hardware-reported "SINOWEALTH Wired Gaming Mouse" to "Glorious Model O" or "Glorious Model D". Signed-off-by: Samuel Čavoj <sammko@sammserver.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/hid-glorious.c')
-rw-r--r--drivers/hid/hid-glorious.c86
1 files changed, 86 insertions, 0 deletions
diff --git a/drivers/hid/hid-glorious.c b/drivers/hid/hid-glorious.c
new file mode 100644
index 000000000000..558eb08c19ef
--- /dev/null
+++ b/drivers/hid/hid-glorious.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * USB HID driver for Glorious PC Gaming Race
+ * Glorious Model O, O- and D mice.
+ *
+ * Copyright (c) 2020 Samuel Čavoj <sammko@sammserver.com>
+ */
+
+/*
+ */
+
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+MODULE_AUTHOR("Samuel Čavoj <sammko@sammserver.com>");
+MODULE_DESCRIPTION("HID driver for Glorious PC Gaming Race mice");
+
+/*
+ * Glorious Model O and O- specify the const flag in the consumer input
+ * report descriptor, which leads to inputs being ignored. Fix this
+ * by patching the descriptor.
+ */
+static __u8 *glorious_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
+{
+ if (*rsize == 213 &&
+ rdesc[84] == 129 && rdesc[112] == 129 && rdesc[140] == 129 &&
+ rdesc[85] == 3 && rdesc[113] == 3 && rdesc[141] == 3) {
+ hid_info(hdev, "patching Glorious Model O consumer control report descriptor\n");
+ rdesc[85] = rdesc[113] = rdesc[141] = \
+ HID_MAIN_ITEM_VARIABLE | HID_MAIN_ITEM_RELATIVE;
+ }
+ return rdesc;
+}
+
+static void glorious_update_name(struct hid_device *hdev)
+{
+ const char *model = "Device";
+
+ switch (hdev->product) {
+ case USB_DEVICE_ID_GLORIOUS_MODEL_O:
+ model = "Model O"; break;
+ case USB_DEVICE_ID_GLORIOUS_MODEL_D:
+ model = "Model D"; break;
+ }
+
+ snprintf(hdev->name, sizeof(hdev->name), "%s %s", "Glorious", model);
+}
+
+static int glorious_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ int ret;
+
+ hdev->quirks |= HID_QUIRK_INPUT_PER_APP;
+
+ ret = hid_parse(hdev);
+ if (ret)
+ return ret;
+
+ glorious_update_name(hdev);
+
+ return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+}
+
+static const struct hid_device_id glorious_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_GLORIOUS,
+ USB_DEVICE_ID_GLORIOUS_MODEL_O) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GLORIOUS,
+ USB_DEVICE_ID_GLORIOUS_MODEL_D) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, glorious_devices);
+
+static struct hid_driver glorious_driver = {
+ .name = "glorious",
+ .id_table = glorious_devices,
+ .probe = glorious_probe,
+ .report_fixup = glorious_report_fixup
+};
+
+module_hid_driver(glorious_driver);
+
+MODULE_LICENSE("GPL");