Commit | Line | Data |
---|---|---|
931830aa BT |
1 | /* |
2 | * HID driver for Gembird Joypad, "PC Game Controller" | |
3 | * | |
4 | * Copyright (c) 2015 Red Hat, Inc | |
5 | * Copyright (c) 2015 Benjamin Tissoires | |
6 | */ | |
7 | ||
8 | /* | |
9 | * This program is free software; you can redistribute it and/or modify it | |
10 | * under the terms of the GNU General Public License as published by the Free | |
11 | * Software Foundation; either version 2 of the License, or (at your option) | |
12 | * any later version. | |
13 | */ | |
14 | ||
15 | #include <linux/device.h> | |
16 | #include <linux/hid.h> | |
17 | #include <linux/module.h> | |
18 | ||
19 | #include "hid-ids.h" | |
20 | ||
21 | #define GEMBIRD_START_FAULTY_RDESC 8 | |
22 | ||
23 | static const __u8 gembird_jpd_faulty_rdesc[] = { | |
24 | 0x75, 0x08, /* Report Size (8) */ | |
25 | 0x95, 0x05, /* Report Count (5) */ | |
26 | 0x15, 0x00, /* Logical Minimum (0) */ | |
27 | 0x26, 0xff, 0x00, /* Logical Maximum (255) */ | |
28 | 0x35, 0x00, /* Physical Minimum (0) */ | |
29 | 0x46, 0xff, 0x00, /* Physical Maximum (255) */ | |
30 | 0x09, 0x30, /* Usage (X) */ | |
31 | 0x09, 0x31, /* Usage (Y) */ | |
32 | 0x09, 0x32, /* Usage (Z) */ | |
33 | 0x09, 0x32, /* Usage (Z) */ | |
34 | 0x09, 0x35, /* Usage (Rz) */ | |
35 | 0x81, 0x02, /* Input (Data,Var,Abs) */ | |
36 | }; | |
37 | ||
38 | /* | |
39 | * we fix the report descriptor by: | |
40 | * - marking the first Z axis as constant (so it is ignored by HID) | |
41 | * - assign the original second Z to Rx | |
42 | * - assign the original Rz to Ry | |
43 | */ | |
44 | static const __u8 gembird_jpd_fixed_rdesc[] = { | |
45 | 0x75, 0x08, /* Report Size (8) */ | |
46 | 0x95, 0x02, /* Report Count (2) */ | |
47 | 0x15, 0x00, /* Logical Minimum (0) */ | |
48 | 0x26, 0xff, 0x00, /* Logical Maximum (255) */ | |
49 | 0x35, 0x00, /* Physical Minimum (0) */ | |
50 | 0x46, 0xff, 0x00, /* Physical Maximum (255) */ | |
51 | 0x09, 0x30, /* Usage (X) */ | |
52 | 0x09, 0x31, /* Usage (Y) */ | |
53 | 0x81, 0x02, /* Input (Data,Var,Abs) */ | |
54 | 0x95, 0x01, /* Report Count (1) */ | |
55 | 0x09, 0x32, /* Usage (Z) */ | |
56 | 0x81, 0x01, /* Input (Cnst,Arr,Abs) */ | |
57 | 0x95, 0x02, /* Report Count (2) */ | |
58 | 0x09, 0x33, /* Usage (Rx) */ | |
59 | 0x09, 0x34, /* Usage (Ry) */ | |
60 | 0x81, 0x02, /* Input (Data,Var,Abs) */ | |
61 | }; | |
62 | ||
63 | static __u8 *gembird_report_fixup(struct hid_device *hdev, __u8 *rdesc, | |
64 | unsigned int *rsize) | |
65 | { | |
66 | __u8 *new_rdesc; | |
67 | /* delta_size is > 0 */ | |
68 | size_t delta_size = sizeof(gembird_jpd_fixed_rdesc) - | |
69 | sizeof(gembird_jpd_faulty_rdesc); | |
70 | size_t new_size = *rsize + delta_size; | |
71 | ||
72 | if (*rsize >= 31 && !memcmp(&rdesc[GEMBIRD_START_FAULTY_RDESC], | |
73 | gembird_jpd_faulty_rdesc, | |
74 | sizeof(gembird_jpd_faulty_rdesc))) { | |
75 | new_rdesc = devm_kzalloc(&hdev->dev, new_size, GFP_KERNEL); | |
76 | if (new_rdesc == NULL) | |
77 | return rdesc; | |
78 | ||
79 | dev_info(&hdev->dev, | |
80 | "fixing Gembird JPD-DualForce 2 report descriptor.\n"); | |
81 | ||
82 | /* start by copying the end of the rdesc */ | |
83 | memcpy(new_rdesc + delta_size, rdesc, *rsize); | |
84 | ||
85 | /* add the correct beginning */ | |
86 | memcpy(new_rdesc, rdesc, GEMBIRD_START_FAULTY_RDESC); | |
87 | ||
88 | /* replace the faulty part with the fixed one */ | |
89 | memcpy(new_rdesc + GEMBIRD_START_FAULTY_RDESC, | |
90 | gembird_jpd_fixed_rdesc, | |
91 | sizeof(gembird_jpd_fixed_rdesc)); | |
92 | ||
93 | *rsize = new_size; | |
94 | rdesc = new_rdesc; | |
95 | } | |
96 | ||
97 | return rdesc; | |
98 | } | |
99 | ||
100 | static const struct hid_device_id gembird_devices[] = { | |
101 | { HID_USB_DEVICE(USB_VENDOR_ID_GEMBIRD, | |
102 | USB_DEVICE_ID_GEMBIRD_JPD_DUALFORCE2) }, | |
103 | { } | |
104 | }; | |
105 | MODULE_DEVICE_TABLE(hid, gembird_devices); | |
106 | ||
107 | static struct hid_driver gembird_driver = { | |
108 | .name = "gembird", | |
109 | .id_table = gembird_devices, | |
110 | .report_fixup = gembird_report_fixup, | |
111 | }; | |
112 | module_hid_driver(gembird_driver); | |
113 | ||
114 | MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>"); | |
115 | MODULE_DESCRIPTION("HID Gembird joypad driver"); | |
116 | MODULE_LICENSE("GPL"); |