xref: /openbmc/linux/drivers/hid/hid-glorious.c (revision c38f7b0f)
177a36a3aSSamuel Čavoj // SPDX-License-Identifier: GPL-2.0-or-later
277a36a3aSSamuel Čavoj /*
377a36a3aSSamuel Čavoj  *  USB HID driver for Glorious PC Gaming Race
477a36a3aSSamuel Čavoj  *  Glorious Model O, O- and D mice.
577a36a3aSSamuel Čavoj  *
677a36a3aSSamuel Čavoj  *  Copyright (c) 2020 Samuel Čavoj <sammko@sammserver.com>
777a36a3aSSamuel Čavoj  */
877a36a3aSSamuel Čavoj 
977a36a3aSSamuel Čavoj /*
1077a36a3aSSamuel Čavoj  */
1177a36a3aSSamuel Čavoj 
1277a36a3aSSamuel Čavoj #include <linux/hid.h>
1377a36a3aSSamuel Čavoj #include <linux/module.h>
1477a36a3aSSamuel Čavoj 
1577a36a3aSSamuel Čavoj #include "hid-ids.h"
1677a36a3aSSamuel Čavoj 
1777a36a3aSSamuel Čavoj MODULE_AUTHOR("Samuel Čavoj <sammko@sammserver.com>");
1877a36a3aSSamuel Čavoj MODULE_DESCRIPTION("HID driver for Glorious PC Gaming Race mice");
1977a36a3aSSamuel Čavoj 
2077a36a3aSSamuel Čavoj /*
2177a36a3aSSamuel Čavoj  * Glorious Model O and O- specify the const flag in the consumer input
2277a36a3aSSamuel Čavoj  * report descriptor, which leads to inputs being ignored. Fix this
2377a36a3aSSamuel Čavoj  * by patching the descriptor.
24*c38f7b0fSBrett Raye  *
25*c38f7b0fSBrett Raye  * Glorious Model I incorrectly specifes the Usage Minimum for its
26*c38f7b0fSBrett Raye  * keyboard HID report, causing keycodes to be misinterpreted.
27*c38f7b0fSBrett Raye  * Fix this by setting Usage Minimum to 0 in that report.
2877a36a3aSSamuel Čavoj  */
glorious_report_fixup(struct hid_device * hdev,__u8 * rdesc,unsigned int * rsize)2977a36a3aSSamuel Čavoj static __u8 *glorious_report_fixup(struct hid_device *hdev, __u8 *rdesc,
3077a36a3aSSamuel Čavoj 		unsigned int *rsize)
3177a36a3aSSamuel Čavoj {
3277a36a3aSSamuel Čavoj 	if (*rsize == 213 &&
3377a36a3aSSamuel Čavoj 		rdesc[84] == 129 && rdesc[112] == 129 && rdesc[140] == 129 &&
3477a36a3aSSamuel Čavoj 		rdesc[85] == 3   && rdesc[113] == 3   && rdesc[141] == 3) {
3577a36a3aSSamuel Čavoj 		hid_info(hdev, "patching Glorious Model O consumer control report descriptor\n");
3677a36a3aSSamuel Čavoj 		rdesc[85] = rdesc[113] = rdesc[141] = \
3777a36a3aSSamuel Čavoj 			HID_MAIN_ITEM_VARIABLE | HID_MAIN_ITEM_RELATIVE;
3877a36a3aSSamuel Čavoj 	}
39*c38f7b0fSBrett Raye 	if (*rsize == 156 && rdesc[41] == 1) {
40*c38f7b0fSBrett Raye 		hid_info(hdev, "patching Glorious Model I keyboard report descriptor\n");
41*c38f7b0fSBrett Raye 		rdesc[41] = 0;
42*c38f7b0fSBrett Raye 	}
4377a36a3aSSamuel Čavoj 	return rdesc;
4477a36a3aSSamuel Čavoj }
4577a36a3aSSamuel Čavoj 
glorious_update_name(struct hid_device * hdev)4677a36a3aSSamuel Čavoj static void glorious_update_name(struct hid_device *hdev)
4777a36a3aSSamuel Čavoj {
4877a36a3aSSamuel Čavoj 	const char *model = "Device";
4977a36a3aSSamuel Čavoj 
5077a36a3aSSamuel Čavoj 	switch (hdev->product) {
5177a36a3aSSamuel Čavoj 	case USB_DEVICE_ID_GLORIOUS_MODEL_O:
5277a36a3aSSamuel Čavoj 		model = "Model O"; break;
5377a36a3aSSamuel Čavoj 	case USB_DEVICE_ID_GLORIOUS_MODEL_D:
5477a36a3aSSamuel Čavoj 		model = "Model D"; break;
55*c38f7b0fSBrett Raye 	case USB_DEVICE_ID_GLORIOUS_MODEL_I:
56*c38f7b0fSBrett Raye 		model = "Model I"; break;
5777a36a3aSSamuel Čavoj 	}
5877a36a3aSSamuel Čavoj 
5977a36a3aSSamuel Čavoj 	snprintf(hdev->name, sizeof(hdev->name), "%s %s", "Glorious", model);
6077a36a3aSSamuel Čavoj }
6177a36a3aSSamuel Čavoj 
glorious_probe(struct hid_device * hdev,const struct hid_device_id * id)6277a36a3aSSamuel Čavoj static int glorious_probe(struct hid_device *hdev,
6377a36a3aSSamuel Čavoj 		const struct hid_device_id *id)
6477a36a3aSSamuel Čavoj {
6577a36a3aSSamuel Čavoj 	int ret;
6677a36a3aSSamuel Čavoj 
6777a36a3aSSamuel Čavoj 	hdev->quirks |= HID_QUIRK_INPUT_PER_APP;
6877a36a3aSSamuel Čavoj 
6977a36a3aSSamuel Čavoj 	ret = hid_parse(hdev);
7077a36a3aSSamuel Čavoj 	if (ret)
7177a36a3aSSamuel Čavoj 		return ret;
7277a36a3aSSamuel Čavoj 
7377a36a3aSSamuel Čavoj 	glorious_update_name(hdev);
7477a36a3aSSamuel Čavoj 
7577a36a3aSSamuel Čavoj 	return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
7677a36a3aSSamuel Čavoj }
7777a36a3aSSamuel Čavoj 
7877a36a3aSSamuel Čavoj static const struct hid_device_id glorious_devices[] = {
79*c38f7b0fSBrett Raye 	{ HID_USB_DEVICE(USB_VENDOR_ID_SINOWEALTH,
8077a36a3aSSamuel Čavoj 		USB_DEVICE_ID_GLORIOUS_MODEL_O) },
81*c38f7b0fSBrett Raye 	{ HID_USB_DEVICE(USB_VENDOR_ID_SINOWEALTH,
8277a36a3aSSamuel Čavoj 		USB_DEVICE_ID_GLORIOUS_MODEL_D) },
83*c38f7b0fSBrett Raye 	{ HID_USB_DEVICE(USB_VENDOR_ID_LAVIEW,
84*c38f7b0fSBrett Raye 		USB_DEVICE_ID_GLORIOUS_MODEL_I) },
8577a36a3aSSamuel Čavoj 	{ }
8677a36a3aSSamuel Čavoj };
8777a36a3aSSamuel Čavoj MODULE_DEVICE_TABLE(hid, glorious_devices);
8877a36a3aSSamuel Čavoj 
8977a36a3aSSamuel Čavoj static struct hid_driver glorious_driver = {
9077a36a3aSSamuel Čavoj 	.name = "glorious",
9177a36a3aSSamuel Čavoj 	.id_table = glorious_devices,
9277a36a3aSSamuel Čavoj 	.probe = glorious_probe,
9377a36a3aSSamuel Čavoj 	.report_fixup = glorious_report_fixup
9477a36a3aSSamuel Čavoj };
9577a36a3aSSamuel Čavoj 
9677a36a3aSSamuel Čavoj module_hid_driver(glorious_driver);
9777a36a3aSSamuel Čavoj 
9877a36a3aSSamuel Čavoj MODULE_LICENSE("GPL");
99