1 // SPDX-License-Identifier: GPL-2.0
4 * HID driver for WinWing Orion 2 throttle
6 * Copyright (c) 2023 Ivan Gorinov
9 #include <linux/device.h>
10 #include <linux/hid.h>
11 #include <linux/hidraw.h>
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/mutex.h>
19 struct led_classdev cdev
;
20 struct hid_device
*hdev
;
24 struct winwing_led_info
{
30 static const struct winwing_led_info led_info
[3] = {
31 { 0, 255, "backlight" },
36 struct winwing_drv_data
{
37 struct hid_device
*hdev
;
40 unsigned int num_leds
;
41 struct winwing_led leds
[];
44 static int winwing_led_write(struct led_classdev
*cdev
,
45 enum led_brightness br
)
47 struct winwing_led
*led
= (struct winwing_led
*) cdev
;
48 struct winwing_drv_data
*data
= hid_get_drvdata(led
->hdev
);
49 __u8
*buf
= data
->report_buf
;
52 mutex_lock(&data
->lock
);
69 ret
= hid_hw_output_report(led
->hdev
, buf
, 14);
71 mutex_unlock(&data
->lock
);
76 static int winwing_init_led(struct hid_device
*hdev
,
77 struct input_dev
*input
)
79 struct winwing_drv_data
*data
;
80 struct winwing_led
*led
;
84 size_t data_size
= struct_size(data
, leds
, 3);
86 data
= devm_kzalloc(&hdev
->dev
, data_size
, GFP_KERNEL
);
91 data
->report_buf
= devm_kmalloc(&hdev
->dev
, MAX_REPORT
, GFP_KERNEL
);
93 if (!data
->report_buf
)
96 for (i
= 0; i
< 3; i
+= 1) {
97 const struct winwing_led_info
*info
= &led_info
[i
];
101 led
->number
= info
->number
;
102 led
->cdev
.max_brightness
= info
->max_brightness
;
103 led
->cdev
.brightness_set_blocking
= winwing_led_write
;
104 led
->cdev
.flags
= LED_HW_PLUGGABLE
;
105 led
->cdev
.name
= devm_kasprintf(&hdev
->dev
, GFP_KERNEL
,
107 dev_name(&input
->dev
),
110 ret
= devm_led_classdev_register(&hdev
->dev
, &led
->cdev
);
115 hid_set_drvdata(hdev
, data
);
120 static int winwing_probe(struct hid_device
*hdev
,
121 const struct hid_device_id
*id
)
125 ret
= hid_parse(hdev
);
127 hid_err(hdev
, "parse failed\n");
131 ret
= hid_hw_start(hdev
, HID_CONNECT_DEFAULT
);
133 hid_err(hdev
, "hw start failed\n");
140 static int winwing_input_configured(struct hid_device
*hdev
,
141 struct hid_input
*hidinput
)
145 ret
= winwing_init_led(hdev
, hidinput
->input
);
148 hid_err(hdev
, "led init failed\n");
153 static const __u8 original_rdesc_buttons
[] = {
154 0x05, 0x09, 0x19, 0x01, 0x29, 0x6F,
155 0x15, 0x00, 0x25, 0x01, 0x35, 0x00,
156 0x45, 0x01, 0x75, 0x01, 0x95, 0x6F,
157 0x81, 0x02, 0x75, 0x01, 0x95, 0x01,
162 * HID report descriptor shows 111 buttons, which exceeds maximum
163 * number of buttons (80) supported by Linux kernel HID subsystem.
165 * This module skips numbers 32-63, unused on some throttle grips.
168 static const __u8
*winwing_report_fixup(struct hid_device
*hdev
, __u8
*rdesc
,
171 int sig_length
= sizeof(original_rdesc_buttons
);
172 int unused_button_numbers
= 32;
177 if (memcmp(rdesc
+ 8, original_rdesc_buttons
, sig_length
) == 0) {
180 rdesc
[13] -= unused_button_numbers
;
182 /* Report Count for buttons */
183 rdesc
[25] -= unused_button_numbers
;
185 /* Report Count for padding [HID1_11, 6.2.2.9] */
186 rdesc
[31] += unused_button_numbers
;
188 hid_info(hdev
, "winwing descriptor fixed\n");
194 static int winwing_raw_event(struct hid_device
*hdev
,
195 struct hid_report
*report
, u8
*raw_data
, int size
)
198 /* Skip buttons 32 .. 63 */
199 memmove(raw_data
+ 5, raw_data
+ 9, 6);
201 /* Clear the padding */
202 memset(raw_data
+ 11, 0, 4);
208 static const struct hid_device_id winwing_devices
[] = {
209 { HID_USB_DEVICE(0x4098, 0xbe62) }, /* TGRIP-18 */
210 { HID_USB_DEVICE(0x4098, 0xbe68) }, /* TGRIP-16EX */
214 MODULE_DEVICE_TABLE(hid
, winwing_devices
);
216 static struct hid_driver winwing_driver
= {
218 .id_table
= winwing_devices
,
219 .probe
= winwing_probe
,
220 .input_configured
= winwing_input_configured
,
221 .report_fixup
= winwing_report_fixup
,
222 .raw_event
= winwing_raw_event
,
224 module_hid_driver(winwing_driver
);
226 MODULE_DESCRIPTION("HID driver for WinWing Orion 2 throttle");
227 MODULE_LICENSE("GPL");