1 // SPDX-License-Identifier: GPL-2.0
2
3 /*
4 * HID driver for WinWing Orion 2 throttle
5 *
6 * Copyright (c) 2023 Ivan Gorinov
7 */
8
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>
15 #include <linux/workqueue.h>
16
17 #define MAX_REPORT 16
18
19 struct winwing_led {
20 struct led_classdev cdev;
21 struct hid_device *hdev;
22 int number;
23 };
24
25 struct winwing_led_info {
26 int number;
27 int max_brightness;
28 const char *led_name;
29 };
30
31 static const struct winwing_led_info led_info[3] = {
32 { 0, 255, "backlight" },
33 { 1, 1, "a-a" },
34 { 2, 1, "a-g" },
35 };
36
37 struct winwing_drv_data {
38 struct hid_device *hdev;
39 struct mutex lights_lock;
40 __u8 *report_lights;
41 __u8 *report_rumble;
42 struct work_struct rumble_work;
43 struct ff_rumble_effect rumble;
44 int rumble_left;
45 int rumble_right;
46 int has_grip15;
47 struct winwing_led leds[];
48 };
49
winwing_led_write(struct led_classdev * cdev,enum led_brightness br)50 static int winwing_led_write(struct led_classdev *cdev,
51 enum led_brightness br)
52 {
53 struct winwing_led *led = (struct winwing_led *) cdev;
54 struct winwing_drv_data *data = hid_get_drvdata(led->hdev);
55 __u8 *buf = data->report_lights;
56 int ret;
57
58 mutex_lock(&data->lights_lock);
59
60 /*
61 * Mimicking requests captured by usbmon when LEDs
62 * are controlled by the vendor's app in a VM.
63 */
64 buf[0] = 0x02;
65 buf[1] = 0x60;
66 buf[2] = 0xbe;
67 buf[3] = 0x00;
68 buf[4] = 0x00;
69 buf[5] = 0x03;
70 buf[6] = 0x49;
71 buf[7] = led->number;
72 buf[8] = br;
73 buf[9] = 0x00;
74 buf[10] = 0;
75 buf[11] = 0;
76 buf[12] = 0;
77 buf[13] = 0;
78
79 ret = hid_hw_output_report(led->hdev, buf, 14);
80
81 mutex_unlock(&data->lights_lock);
82
83 return ret;
84 }
85
winwing_init_led(struct hid_device * hdev,struct input_dev * input)86 static int winwing_init_led(struct hid_device *hdev,
87 struct input_dev *input)
88 {
89 struct winwing_drv_data *data;
90 struct winwing_led *led;
91 int ret;
92 int i;
93
94 data = hid_get_drvdata(hdev);
95
96 if (!data)
97 return -EINVAL;
98
99 data->report_lights = devm_kzalloc(&hdev->dev, MAX_REPORT, GFP_KERNEL);
100
101 if (!data->report_lights)
102 return -ENOMEM;
103
104 for (i = 0; i < 3; i += 1) {
105 const struct winwing_led_info *info = &led_info[i];
106
107 led = &data->leds[i];
108 led->hdev = hdev;
109 led->number = info->number;
110 led->cdev.max_brightness = info->max_brightness;
111 led->cdev.brightness_set_blocking = winwing_led_write;
112 led->cdev.flags = LED_HW_PLUGGABLE;
113 led->cdev.name = devm_kasprintf(&hdev->dev, GFP_KERNEL,
114 "%s::%s",
115 dev_name(&input->dev),
116 info->led_name);
117
118 if (!led->cdev.name)
119 return -ENOMEM;
120
121 ret = devm_led_classdev_register(&hdev->dev, &led->cdev);
122 if (ret)
123 return ret;
124 }
125
126 return ret;
127 }
128
winwing_map_button(int button,int has_grip15)129 static int winwing_map_button(int button, int has_grip15)
130 {
131 if (button < 1)
132 return KEY_RESERVED;
133
134 if (button > 112)
135 return KEY_RESERVED;
136
137 if (button <= 16) {
138 /*
139 * Grip buttons [1 .. 16] are mapped to
140 * key codes BTN_TRIGGER .. BTN_DEAD
141 */
142 return (button - 1) + BTN_JOYSTICK;
143 }
144
145 if (button >= 65) {
146 /*
147 * Base buttons [65 .. 112] are mapped to
148 * key codes BTN_TRIGGER_HAPPY17 .. KEY_MAX
149 */
150 return (button - 65) + BTN_TRIGGER_HAPPY17;
151 }
152
153 if (!has_grip15) {
154 /*
155 * Not mapping numbers [33 .. 64] which
156 * are not assigned to any real buttons
157 */
158 if (button >= 33)
159 return KEY_RESERVED;
160 /*
161 * Grip buttons [17 .. 32] are mapped to
162 * BTN_TRIGGER_HAPPY1 .. BTN_TRIGGER_HAPPY16
163 */
164 return (button - 17) + BTN_TRIGGER_HAPPY1;
165 }
166
167 if (button >= 49) {
168 /*
169 * Grip buttons [49 .. 64] are mapped to
170 * BTN_TRIGGER_HAPPY1 .. BTN_TRIGGER_HAPPY16
171 */
172 return (button - 49) + BTN_TRIGGER_HAPPY1;
173 }
174
175 /*
176 * Grip buttons [17 .. 44] are mapped to
177 * key codes KEY_MACRO1 .. KEY_MACRO28;
178 * also mapping numbers [45 .. 48] which
179 * are not assigned to any real buttons.
180 */
181 return (button - 17) + KEY_MACRO1;
182 }
183
winwing_input_mapping(struct hid_device * hdev,struct hid_input * hi,struct hid_field * field,struct hid_usage * usage,unsigned long ** bit,int * max)184 static int winwing_input_mapping(struct hid_device *hdev,
185 struct hid_input *hi, struct hid_field *field, struct hid_usage *usage,
186 unsigned long **bit, int *max)
187 {
188 struct winwing_drv_data *data;
189 int code = KEY_RESERVED;
190 int button = 0;
191
192 data = hid_get_drvdata(hdev);
193
194 if (!data)
195 return -EINVAL;
196
197 if ((usage->hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
198 return 0;
199
200 if (field->application != HID_GD_JOYSTICK)
201 return 0;
202
203 /* Button numbers start with 1 */
204 button = usage->hid & HID_USAGE;
205
206 code = winwing_map_button(button, data->has_grip15);
207
208 hid_map_usage(hi, usage, bit, max, EV_KEY, code);
209
210 return 1;
211 }
212
213 /*
214 * If x ≤ 0, return 0;
215 * if x is in [1 .. 65535], return a value in [1 .. 255]
216 */
convert_magnitude(int x)217 static inline int convert_magnitude(int x)
218 {
219 if (x < 1)
220 return 0;
221
222 return ((x * 255) >> 16) + 1;
223 }
224
winwing_haptic_rumble(struct winwing_drv_data * data)225 static int winwing_haptic_rumble(struct winwing_drv_data *data)
226 {
227 __u8 *buf;
228 __u8 m;
229
230 if (!data)
231 return -EINVAL;
232
233 if (!data->hdev)
234 return -EINVAL;
235
236 buf = data->report_rumble;
237
238 if (!buf)
239 return -EINVAL;
240
241 m = convert_magnitude(data->rumble.strong_magnitude);
242 if (m != data->rumble_left) {
243 int ret;
244
245 /*
246 * Mimicking requests captured by usbmon when rumble
247 * is activated by the vendor's app in a VM.
248 */
249 buf[0] = 0x02;
250 buf[1] = 0x01;
251 buf[2] = 0xbf;
252 buf[3] = 0x00;
253 buf[4] = 0x00;
254 buf[5] = 0x03;
255 buf[6] = 0x49;
256 buf[7] = 0x00;
257 buf[8] = m;
258 buf[9] = 0x00;
259 buf[10] = 0;
260 buf[11] = 0;
261 buf[12] = 0;
262 buf[13] = 0;
263
264 ret = hid_hw_output_report(data->hdev, buf, 14);
265 if (ret < 0) {
266 hid_err(data->hdev, "error %d (%*ph)\n", ret, 14, buf);
267 return ret;
268 }
269 data->rumble_left = m;
270 }
271
272 m = convert_magnitude(data->rumble.weak_magnitude);
273 if (m != data->rumble_right) {
274 int ret;
275
276 /*
277 * Mimicking requests captured by usbmon when rumble
278 * is activated by the vendor's app in a VM.
279 */
280 buf[0] = 0x02;
281 buf[1] = 0x03;
282 buf[2] = 0xbf;
283 buf[3] = 0x00;
284 buf[4] = 0x00;
285 buf[5] = 0x03;
286 buf[6] = 0x49;
287 buf[7] = 0x00;
288 buf[8] = m;
289 buf[9] = 0x00;
290 buf[10] = 0;
291 buf[11] = 0;
292 buf[12] = 0;
293 buf[13] = 0;
294
295 ret = hid_hw_output_report(data->hdev, buf, 14);
296 if (ret < 0) {
297 hid_err(data->hdev, "error %d (%*ph)\n", ret, 14, buf);
298 return ret;
299 }
300 data->rumble_right = m;
301 }
302
303 return 0;
304 }
305
306
winwing_haptic_rumble_cb(struct work_struct * work)307 static void winwing_haptic_rumble_cb(struct work_struct *work)
308 {
309 struct winwing_drv_data *data;
310
311 data = container_of(work, struct winwing_drv_data, rumble_work);
312 winwing_haptic_rumble(data);
313 }
314
winwing_play_effect(struct input_dev * dev,void * context,struct ff_effect * effect)315 static int winwing_play_effect(struct input_dev *dev, void *context,
316 struct ff_effect *effect)
317 {
318 struct hid_device *hdev = input_get_drvdata(dev);
319 struct winwing_drv_data *data = hid_get_drvdata(hdev);
320
321 if (effect->type != FF_RUMBLE)
322 return 0;
323
324 if (!data)
325 return -EINVAL;
326
327 data->rumble = effect->u.rumble;
328
329 return schedule_work(&data->rumble_work);
330 }
331
winwing_init_ff(struct hid_device * hdev,struct hid_input * hidinput)332 static int winwing_init_ff(struct hid_device *hdev, struct hid_input *hidinput)
333 {
334 struct winwing_drv_data *data;
335
336 data = (struct winwing_drv_data *) hid_get_drvdata(hdev);
337 if (!data)
338 return -EINVAL;
339
340 data->report_rumble = devm_kzalloc(&hdev->dev, MAX_REPORT, GFP_KERNEL);
341 data->rumble_left = -1;
342 data->rumble_right = -1;
343
344 input_set_capability(hidinput->input, EV_FF, FF_RUMBLE);
345
346 /*
347 * input_ff_create_memless() takes ownership of the context pointer
348 * and frees it on teardown; do not hand it the devm-managed drvdata.
349 * winwing_play_effect() fetches it from the input device instead.
350 */
351 return input_ff_create_memless(hidinput->input, NULL,
352 winwing_play_effect);
353 }
354
winwing_probe(struct hid_device * hdev,const struct hid_device_id * id)355 static int winwing_probe(struct hid_device *hdev,
356 const struct hid_device_id *id)
357 {
358 struct winwing_drv_data *data;
359 size_t data_size = struct_size(data, leds, 3);
360 int ret;
361
362 ret = hid_parse(hdev);
363 if (ret) {
364 hid_err(hdev, "parse failed\n");
365 return ret;
366 }
367
368 data = devm_kzalloc(&hdev->dev, data_size, GFP_KERNEL);
369
370 if (!data)
371 return -ENOMEM;
372
373 data->hdev = hdev;
374 data->has_grip15 = id->driver_data;
375 hid_set_drvdata(hdev, data);
376
377 INIT_WORK(&data->rumble_work, winwing_haptic_rumble_cb);
378
379 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
380 if (ret) {
381 hid_err(hdev, "hw start failed\n");
382 return ret;
383 }
384
385 return 0;
386 }
387
winwing_remove(struct hid_device * hdev)388 static void winwing_remove(struct hid_device *hdev)
389 {
390 struct winwing_drv_data *data;
391
392 data = (struct winwing_drv_data *) hid_get_drvdata(hdev);
393
394 if (data)
395 cancel_work_sync(&data->rumble_work);
396
397 hid_hw_close(hdev);
398 hid_hw_stop(hdev);
399 }
400
winwing_input_configured(struct hid_device * hdev,struct hid_input * hidinput)401 static int winwing_input_configured(struct hid_device *hdev,
402 struct hid_input *hidinput)
403 {
404 struct winwing_drv_data *data;
405 int ret;
406
407 data = (struct winwing_drv_data *) hid_get_drvdata(hdev);
408
409 ret = winwing_init_led(hdev, hidinput->input);
410
411 if (ret)
412 hid_err(hdev, "led init failed\n");
413
414 if (data->has_grip15)
415 winwing_init_ff(hdev, hidinput);
416
417 return ret;
418 }
419
420 /* Set driver_data to 1 for grips with rumble motor and more than 32 buttons */
421 static const struct hid_device_id winwing_devices[] = {
422 { HID_USB_DEVICE(0x4098, 0xbd65), .driver_data = 1 }, /* TGRIP-15E */
423 { HID_USB_DEVICE(0x4098, 0xbd64), .driver_data = 1 }, /* TGRIP-15EX */
424 { HID_USB_DEVICE(0x4098, 0xbe68), .driver_data = 0 }, /* TGRIP-16EX */
425 { HID_USB_DEVICE(0x4098, 0xbe62), .driver_data = 0 }, /* TGRIP-18 */
426 {}
427 };
428
429 MODULE_DEVICE_TABLE(hid, winwing_devices);
430
431 static struct hid_driver winwing_driver = {
432 .name = "winwing",
433 .id_table = winwing_devices,
434 .input_configured = winwing_input_configured,
435 .input_mapping = winwing_input_mapping,
436 .probe = winwing_probe,
437 .remove = winwing_remove,
438 };
439 module_hid_driver(winwing_driver);
440
441 MODULE_DESCRIPTION("HID driver for WinWing Orion 2 throttle");
442 MODULE_LICENSE("GPL");
443