Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
79422741 JK |
2 | /* |
3 | * HID driver for Kye/Genius devices not fully compliant with HID standard | |
4 | * | |
5 | * Copyright (c) 2009 Jiri Kosina | |
6 | * Copyright (c) 2009 Tomas Hanak | |
22ca20b2 | 7 | * Copyright (c) 2012 Nikolai Kondrashov |
b8cd2d96 | 8 | * Copyright (c) 2023 David Yang |
79422741 JK |
9 | */ |
10 | ||
b8cd2d96 | 11 | #include <asm-generic/unaligned.h> |
79422741 JK |
12 | #include <linux/device.h> |
13 | #include <linux/hid.h> | |
14 | #include <linux/module.h> | |
15 | ||
16 | #include "hid-ids.h" | |
17 | ||
4782c0e0 DY |
18 | static const __u8 easypen_m610x_control_rdesc[] = { |
19 | 0x05, 0x0C, /* Usage Page (Consumer), */ | |
20 | 0x09, 0x01, /* Usage (Consumer Control), */ | |
21 | 0xA1, 0x01, /* Collection (Application), */ | |
22 | 0x85, 0x12, /* Report ID (18), */ | |
23 | 0x0A, 0x1A, 0x02, /* Usage (AC Undo), */ | |
24 | 0x0A, 0x79, 0x02, /* Usage (AC Redo Or Repeat), */ | |
25 | 0x0A, 0x2D, 0x02, /* Usage (AC Zoom In), */ | |
26 | 0x0A, 0x2E, 0x02, /* Usage (AC Zoom Out), */ | |
27 | 0x14, /* Logical Minimum (0), */ | |
28 | 0x25, 0x01, /* Logical Maximum (1), */ | |
29 | 0x75, 0x01, /* Report Size (1), */ | |
30 | 0x95, 0x04, /* Report Count (4), */ | |
31 | 0x81, 0x02, /* Input (Variable), */ | |
32 | 0x95, 0x34, /* Report Count (52), */ | |
33 | 0x81, 0x01, /* Input (Constant), */ | |
34 | 0xC0 /* End Collection */ | |
22ca20b2 NK |
35 | }; |
36 | ||
4782c0e0 DY |
37 | static const __u8 pensketch_m912_control_rdesc[] = { |
38 | 0x05, 0x0C, /* Usage Page (Consumer), */ | |
39 | 0x09, 0x01, /* Usage (Consumer Control), */ | |
40 | 0xA1, 0x01, /* Collection (Application), */ | |
41 | 0x85, 0x12, /* Report ID (18), */ | |
42 | 0x14, /* Logical Minimum (0), */ | |
43 | 0x25, 0x01, /* Logical Maximum (1), */ | |
44 | 0x75, 0x01, /* Report Size (1), */ | |
45 | 0x95, 0x08, /* Report Count (8), */ | |
46 | 0x05, 0x0C, /* Usage Page (Consumer), */ | |
47 | 0x0A, 0x6A, 0x02, /* Usage (AC Delete), */ | |
48 | 0x0A, 0x1A, 0x02, /* Usage (AC Undo), */ | |
49 | 0x0A, 0x01, 0x02, /* Usage (AC New), */ | |
50 | 0x0A, 0x2F, 0x02, /* Usage (AC Zoom), */ | |
51 | 0x0A, 0x25, 0x02, /* Usage (AC Forward), */ | |
52 | 0x0A, 0x24, 0x02, /* Usage (AC Back), */ | |
53 | 0x0A, 0x2D, 0x02, /* Usage (AC Zoom In), */ | |
54 | 0x0A, 0x2E, 0x02, /* Usage (AC Zoom Out), */ | |
55 | 0x81, 0x02, /* Input (Variable), */ | |
56 | 0x95, 0x30, /* Report Count (48), */ | |
57 | 0x81, 0x03, /* Input (Constant, Variable), */ | |
58 | 0xC0 /* End Collection */ | |
22ca20b2 NK |
59 | }; |
60 | ||
4782c0e0 DY |
61 | static const __u8 easypen_m406xe_control_rdesc[] = { |
62 | 0x05, 0x0C, /* Usage Page (Consumer), */ | |
63 | 0x09, 0x01, /* Usage (Consumer Control), */ | |
64 | 0xA1, 0x01, /* Collection (Application), */ | |
65 | 0x85, 0x12, /* Report ID (18), */ | |
66 | 0x14, /* Logical Minimum (0), */ | |
67 | 0x25, 0x01, /* Logical Maximum (1), */ | |
68 | 0x75, 0x01, /* Report Size (1), */ | |
69 | 0x95, 0x04, /* Report Count (4), */ | |
70 | 0x0A, 0x79, 0x02, /* Usage (AC Redo Or Repeat), */ | |
71 | 0x0A, 0x1A, 0x02, /* Usage (AC Undo), */ | |
72 | 0x0A, 0x2D, 0x02, /* Usage (AC Zoom In), */ | |
73 | 0x0A, 0x2E, 0x02, /* Usage (AC Zoom Out), */ | |
74 | 0x81, 0x02, /* Input (Variable), */ | |
75 | 0x95, 0x34, /* Report Count (52), */ | |
76 | 0x81, 0x03, /* Input (Constant, Variable), */ | |
77 | 0xC0 /* End Collection */ | |
515cdc19 NK |
78 | }; |
79 | ||
4782c0e0 DY |
80 | /* Fix indexes in kye_tablet_report_fixup if you change this */ |
81 | static const __u8 kye_tablet_rdesc[] = { | |
22ca20b2 NK |
82 | 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ |
83 | 0x09, 0x01, /* Usage (01h), */ | |
84 | 0xA1, 0x01, /* Collection (Application), */ | |
85 | 0x85, 0x05, /* Report ID (5), */ | |
86 | 0x09, 0x01, /* Usage (01h), */ | |
feb6faf1 MP |
87 | 0x15, 0x81, /* Logical Minimum (-127), */ |
88 | 0x25, 0x7F, /* Logical Maximum (127), */ | |
89 | 0x75, 0x08, /* Report Size (8), */ | |
90 | 0x95, 0x07, /* Report Count (7), */ | |
91 | 0xB1, 0x02, /* Feature (Variable), */ | |
92 | 0xC0, /* End Collection, */ | |
93 | 0x05, 0x0D, /* Usage Page (Digitizer), */ | |
f7d8e387 | 94 | 0x09, 0x01, /* Usage (Digitizer), */ |
feb6faf1 MP |
95 | 0xA1, 0x01, /* Collection (Application), */ |
96 | 0x85, 0x10, /* Report ID (16), */ | |
97 | 0x09, 0x20, /* Usage (Stylus), */ | |
98 | 0xA0, /* Collection (Physical), */ | |
99 | 0x09, 0x42, /* Usage (Tip Switch), */ | |
100 | 0x09, 0x44, /* Usage (Barrel Switch), */ | |
101 | 0x09, 0x46, /* Usage (Tablet Pick), */ | |
102 | 0x14, /* Logical Minimum (0), */ | |
103 | 0x25, 0x01, /* Logical Maximum (1), */ | |
104 | 0x75, 0x01, /* Report Size (1), */ | |
105 | 0x95, 0x03, /* Report Count (3), */ | |
106 | 0x81, 0x02, /* Input (Variable), */ | |
107 | 0x95, 0x04, /* Report Count (4), */ | |
4782c0e0 | 108 | 0x81, 0x01, /* Input (Constant), */ |
feb6faf1 MP |
109 | 0x09, 0x32, /* Usage (In Range), */ |
110 | 0x95, 0x01, /* Report Count (1), */ | |
111 | 0x81, 0x02, /* Input (Variable), */ | |
112 | 0x75, 0x10, /* Report Size (16), */ | |
feb6faf1 MP |
113 | 0xA4, /* Push, */ |
114 | 0x05, 0x01, /* Usage Page (Desktop), */ | |
feb6faf1 | 115 | 0x09, 0x30, /* Usage (X), */ |
4782c0e0 DY |
116 | 0x27, 0xFF, 0x7F, 0x00, 0x00, /* Logical Maximum (32767), */ |
117 | 0x34, /* Physical Minimum (0), */ | |
118 | 0x47, 0x00, 0x00, 0x00, 0x00, /* Physical Maximum (0), */ | |
119 | 0x65, 0x11, /* Unit (Centimeter), */ | |
120 | 0x55, 0x00, /* Unit Exponent (0), */ | |
121 | 0x75, 0x10, /* Report Size (16), */ | |
feb6faf1 MP |
122 | 0x81, 0x02, /* Input (Variable), */ |
123 | 0x09, 0x31, /* Usage (Y), */ | |
4782c0e0 DY |
124 | 0x27, 0xFF, 0x7F, 0x00, 0x00, /* Logical Maximum (32767), */ |
125 | 0x47, 0x00, 0x00, 0x00, 0x00, /* Physical Maximum (0), */ | |
feb6faf1 MP |
126 | 0x81, 0x02, /* Input (Variable), */ |
127 | 0xB4, /* Pop, */ | |
4782c0e0 | 128 | 0x05, 0x0D, /* Usage Page (Digitizer), */ |
feb6faf1 | 129 | 0x09, 0x30, /* Usage (Tip Pressure), */ |
4782c0e0 | 130 | 0x27, 0xFF, 0x07, 0x00, 0x00, /* Logical Maximum (2047), */ |
feb6faf1 MP |
131 | 0x81, 0x02, /* Input (Variable), */ |
132 | 0xC0, /* End Collection, */ | |
133 | 0xC0, /* End Collection, */ | |
134 | 0x05, 0x0D, /* Usage Page (Digitizer), */ | |
135 | 0x09, 0x21, /* Usage (Puck), */ | |
136 | 0xA1, 0x01, /* Collection (Application), */ | |
137 | 0x85, 0x11, /* Report ID (17), */ | |
138 | 0x09, 0x21, /* Usage (Puck), */ | |
139 | 0xA0, /* Collection (Physical), */ | |
140 | 0x05, 0x09, /* Usage Page (Button), */ | |
feb6faf1 MP |
141 | 0x19, 0x01, /* Usage Minimum (01h), */ |
142 | 0x29, 0x03, /* Usage Maximum (03h), */ | |
143 | 0x14, /* Logical Minimum (0), */ | |
144 | 0x25, 0x01, /* Logical Maximum (1), */ | |
4782c0e0 | 145 | 0x75, 0x01, /* Report Size (1), */ |
feb6faf1 MP |
146 | 0x95, 0x03, /* Report Count (3), */ |
147 | 0x81, 0x02, /* Input (Variable), */ | |
148 | 0x95, 0x04, /* Report Count (4), */ | |
149 | 0x81, 0x01, /* Input (Constant), */ | |
4782c0e0 DY |
150 | 0x05, 0x0D, /* Usage Page (Digitizer), */ |
151 | 0x09, 0x32, /* Usage (In Range), */ | |
feb6faf1 | 152 | 0x95, 0x01, /* Report Count (1), */ |
feb6faf1 | 153 | 0x81, 0x02, /* Input (Variable), */ |
feb6faf1 | 154 | 0x05, 0x01, /* Usage Page (Desktop), */ |
4782c0e0 | 155 | 0xA4, /* Push, */ |
feb6faf1 | 156 | 0x09, 0x30, /* Usage (X), */ |
4782c0e0 DY |
157 | 0x27, 0xFF, 0x7F, 0x00, 0x00, /* Logical Maximum (32767), */ |
158 | 0x34, /* Physical Minimum (0), */ | |
159 | 0x47, 0x00, 0x00, 0x00, 0x00, /* Physical Maximum (0), */ | |
160 | 0x65, 0x11, /* Unit (Centimeter), */ | |
161 | 0x55, 0x00, /* Unit Exponent (0), */ | |
162 | 0x75, 0x10, /* Report Size (16), */ | |
feb6faf1 MP |
163 | 0x81, 0x02, /* Input (Variable), */ |
164 | 0x09, 0x31, /* Usage (Y), */ | |
4782c0e0 DY |
165 | 0x27, 0xFF, 0x7F, 0x00, 0x00, /* Logical Maximum (32767), */ |
166 | 0x47, 0x00, 0x00, 0x00, 0x00, /* Physical Maximum (0), */ | |
feb6faf1 | 167 | 0x81, 0x02, /* Input (Variable), */ |
4782c0e0 | 168 | 0xB4, /* Pop, */ |
feb6faf1 | 169 | 0x09, 0x38, /* Usage (Wheel), */ |
4782c0e0 | 170 | 0x15, 0xFF, /* Logical Minimum (-1), */ |
feb6faf1 MP |
171 | 0x75, 0x08, /* Report Size (8), */ |
172 | 0x95, 0x01, /* Report Count (1), */ | |
feb6faf1 | 173 | 0x81, 0x06, /* Input (Variable, Relative), */ |
4782c0e0 | 174 | 0x81, 0x01, /* Input (Constant), */ |
feb6faf1 | 175 | 0xC0, /* End Collection, */ |
feb6faf1 MP |
176 | 0xC0 /* End Collection */ |
177 | }; | |
178 | ||
b8cd2d96 DY |
179 | static const struct kye_tablet_info { |
180 | __u32 product; | |
181 | __s32 x_logical_maximum; | |
182 | __s32 y_logical_maximum; | |
183 | __s32 pressure_logical_maximum; | |
184 | __s32 x_physical_maximum; | |
185 | __s32 y_physical_maximum; | |
186 | __s8 unit_exponent; | |
187 | __s8 unit; | |
188 | bool has_punk; | |
189 | unsigned int control_rsize; | |
190 | const __u8 *control_rdesc; | |
191 | } kye_tablets_info[] = { | |
4782c0e0 DY |
192 | {USB_DEVICE_ID_KYE_EASYPEN_I405X, /* 0x5010 */ |
193 | 14080, 10240, 1023, 55, 40, -1, 0x13, false}, | |
194 | {USB_DEVICE_ID_KYE_MOUSEPEN_I608X, /* 0x5011 */ | |
195 | 20480, 15360, 2047, 8, 6, 0, 0x13, true}, | |
196 | {USB_DEVICE_ID_KYE_EASYPEN_M610X, /* 0x5013 */ | |
197 | 40960, 25600, 1023, 1000, 625, -2, 0x13, false, | |
198 | sizeof(easypen_m610x_control_rdesc), easypen_m610x_control_rdesc}, | |
199 | {USB_DEVICE_ID_KYE_PENSKETCH_M912, /* 0x5015 */ | |
200 | 61440, 46080, 2047, 12, 9, 0, 0x13, true, | |
201 | sizeof(pensketch_m912_control_rdesc), pensketch_m912_control_rdesc}, | |
202 | {USB_DEVICE_ID_KYE_EASYPEN_M406XE, /* 0x5019 */ | |
203 | 15360, 10240, 1023, 6, 4, 0, 0x13, false, | |
204 | sizeof(easypen_m406xe_control_rdesc), easypen_m406xe_control_rdesc}, | |
205 | {USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2, /* 0x501A */ | |
206 | 40960, 30720, 2047, 8, 6, 0, 0x13, true}, | |
b8cd2d96 DY |
207 | {} |
208 | }; | |
209 | ||
0adb9c2c | 210 | static __u8 *kye_consumer_control_fixup(struct hid_device *hdev, __u8 *rdesc, |
b8cd2d96 DY |
211 | unsigned int *rsize, int offset, const char *device_name) |
212 | { | |
0adb9c2c BT |
213 | /* |
214 | * the fixup that need to be done: | |
3f8b6fb7 | 215 | * - change Usage Maximum in the Consumer Control |
0adb9c2c BT |
216 | * (report ID 3) to a reasonable value |
217 | */ | |
218 | if (*rsize >= offset + 31 && | |
219 | /* Usage Page (Consumer Devices) */ | |
220 | rdesc[offset] == 0x05 && rdesc[offset + 1] == 0x0c && | |
221 | /* Usage (Consumer Control) */ | |
222 | rdesc[offset + 2] == 0x09 && rdesc[offset + 3] == 0x01 && | |
223 | /* Usage Maximum > 12287 */ | |
224 | rdesc[offset + 10] == 0x2a && rdesc[offset + 12] > 0x2f) { | |
225 | hid_info(hdev, "fixing up %s report descriptor\n", device_name); | |
226 | rdesc[offset + 12] = 0x2f; | |
227 | } | |
228 | return rdesc; | |
229 | } | |
230 | ||
b8cd2d96 DY |
231 | /* |
232 | * Fix tablet descriptor of so-called "DataFormat 2". | |
233 | * | |
234 | * Though we may achieve a usable descriptor from original vendor-defined one, | |
235 | * some problems exist: | |
236 | * - Their Logical Maximum never exceed 32767 (7F FF), though device do report | |
237 | * values greater than that; | |
238 | * - Physical Maximums are arbitrarily filled (always equal to Logical | |
239 | * Maximum); | |
240 | * - Detail for control buttons are not provided (a vendor-defined Usage Page | |
241 | * with fixed content). | |
242 | * | |
243 | * Thus we use a pre-defined parameter table rather than digging it from | |
244 | * original descriptor. | |
245 | * | |
246 | * We may as well write a fallback routine for unrecognized kye tablet, but it's | |
247 | * clear kye are unlikely to produce new models in the foreseeable future, so we | |
248 | * simply enumerate all possible models. | |
249 | */ | |
250 | static __u8 *kye_tablet_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) | |
251 | { | |
252 | const struct kye_tablet_info *info; | |
253 | unsigned int newsize; | |
254 | ||
255 | if (*rsize < sizeof(kye_tablet_rdesc)) { | |
256 | hid_warn(hdev, | |
257 | "tablet report size too small, or kye_tablet_rdesc unexpectedly large\n"); | |
258 | return rdesc; | |
259 | } | |
260 | ||
261 | for (info = kye_tablets_info; info->product; info++) { | |
262 | if (hdev->product == info->product) | |
263 | break; | |
264 | } | |
265 | ||
266 | if (!info->product) { | |
267 | hid_err(hdev, "tablet unknown, someone forget to add kye_tablet_info entry?\n"); | |
268 | return rdesc; | |
269 | } | |
270 | ||
271 | newsize = info->has_punk ? sizeof(kye_tablet_rdesc) : 112; | |
272 | memcpy(rdesc, kye_tablet_rdesc, newsize); | |
273 | ||
274 | put_unaligned_le32(info->x_logical_maximum, rdesc + 66); | |
275 | put_unaligned_le32(info->x_physical_maximum, rdesc + 72); | |
276 | rdesc[77] = info->unit; | |
277 | rdesc[79] = info->unit_exponent; | |
278 | put_unaligned_le32(info->y_logical_maximum, rdesc + 87); | |
279 | put_unaligned_le32(info->y_physical_maximum, rdesc + 92); | |
280 | put_unaligned_le32(info->pressure_logical_maximum, rdesc + 104); | |
281 | ||
282 | if (info->has_punk) { | |
283 | put_unaligned_le32(info->x_logical_maximum, rdesc + 156); | |
284 | put_unaligned_le32(info->x_physical_maximum, rdesc + 162); | |
285 | rdesc[167] = info->unit; | |
286 | rdesc[169] = info->unit_exponent; | |
287 | put_unaligned_le32(info->y_logical_maximum, rdesc + 177); | |
288 | put_unaligned_le32(info->y_physical_maximum, rdesc + 182); | |
289 | } | |
290 | ||
291 | if (info->control_rsize) { | |
292 | if (newsize + info->control_rsize > *rsize) | |
293 | hid_err(hdev, "control rdesc unexpectedly large"); | |
294 | else { | |
295 | memcpy(rdesc + newsize, info->control_rdesc, info->control_rsize); | |
296 | newsize += info->control_rsize; | |
297 | } | |
298 | } | |
299 | ||
300 | *rsize = newsize; | |
301 | return rdesc; | |
302 | } | |
303 | ||
73e4008d NK |
304 | static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc, |
305 | unsigned int *rsize) | |
79422741 | 306 | { |
22ca20b2 NK |
307 | switch (hdev->product) { |
308 | case USB_DEVICE_ID_KYE_ERGO_525V: | |
309 | /* the fixups that need to be done: | |
310 | * - change led usage page to button for extra buttons | |
311 | * - report size 8 count 1 must be size 1 count 8 for button | |
312 | * bitfield | |
313 | * - change the button usage range to 4-7 for the extra | |
314 | * buttons | |
315 | */ | |
4ab25786 | 316 | if (*rsize >= 75 && |
22ca20b2 NK |
317 | rdesc[61] == 0x05 && rdesc[62] == 0x08 && |
318 | rdesc[63] == 0x19 && rdesc[64] == 0x08 && | |
319 | rdesc[65] == 0x29 && rdesc[66] == 0x0f && | |
320 | rdesc[71] == 0x75 && rdesc[72] == 0x08 && | |
321 | rdesc[73] == 0x95 && rdesc[74] == 0x01) { | |
322 | hid_info(hdev, | |
323 | "fixing up Kye/Genius Ergo Mouse " | |
324 | "report descriptor\n"); | |
325 | rdesc[62] = 0x09; | |
326 | rdesc[64] = 0x04; | |
327 | rdesc[66] = 0x07; | |
328 | rdesc[72] = 0x01; | |
329 | rdesc[74] = 0x08; | |
330 | } | |
331 | break; | |
3685c18e | 332 | case USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE: |
0adb9c2c BT |
333 | rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 104, |
334 | "Genius Gila Gaming Mouse"); | |
335 | break; | |
8c7b79bc DY |
336 | case USB_DEVICE_ID_GENIUS_MANTICORE: |
337 | rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 104, | |
338 | "Genius Manticore Keyboard"); | |
339 | break; | |
0adb9c2c BT |
340 | case USB_DEVICE_ID_GENIUS_GX_IMPERATOR: |
341 | rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 83, | |
342 | "Genius Gx Imperator Keyboard"); | |
0a5f99cf | 343 | break; |
8c7b79bc DY |
344 | case USB_DEVICE_ID_KYE_EASYPEN_I405X: |
345 | case USB_DEVICE_ID_KYE_MOUSEPEN_I608X: | |
346 | case USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2: | |
347 | case USB_DEVICE_ID_KYE_EASYPEN_M610X: | |
348 | case USB_DEVICE_ID_KYE_EASYPEN_M406XE: | |
349 | case USB_DEVICE_ID_KYE_PENSKETCH_M912: | |
350 | rdesc = kye_tablet_fixup(hdev, rdesc, rsize); | |
3685c18e | 351 | break; |
79422741 | 352 | } |
73e4008d | 353 | return rdesc; |
79422741 JK |
354 | } |
355 | ||
22ca20b2 NK |
356 | static int kye_tablet_enable(struct hid_device *hdev) |
357 | { | |
358 | struct list_head *list; | |
359 | struct list_head *head; | |
360 | struct hid_report *report; | |
361 | __s32 *value; | |
362 | ||
363 | list = &hdev->report_enum[HID_FEATURE_REPORT].report_list; | |
364 | list_for_each(head, list) { | |
365 | report = list_entry(head, struct hid_report, list); | |
366 | if (report->id == 5) | |
367 | break; | |
368 | } | |
369 | ||
370 | if (head == list) { | |
371 | hid_err(hdev, "tablet-enabling feature report not found\n"); | |
372 | return -ENODEV; | |
373 | } | |
374 | ||
375 | if (report->maxfield < 1 || report->field[0]->report_count < 7) { | |
376 | hid_err(hdev, "invalid tablet-enabling feature report\n"); | |
377 | return -ENODEV; | |
378 | } | |
379 | ||
380 | value = report->field[0]->value; | |
381 | ||
b8cd2d96 DY |
382 | /* |
383 | * The code is for DataFormat 2 of config xml. They have no obvious | |
384 | * meaning (at least not configurable in Windows driver) except enabling | |
385 | * fully-functional tablet mode (absolute positioning). Otherwise, the | |
386 | * tablet acts like a relative mouse. | |
387 | * | |
388 | * Though there're magic codes for DataFormat 3 and 4, no devices use | |
389 | * these DataFormats. | |
390 | */ | |
22ca20b2 NK |
391 | value[0] = 0x12; |
392 | value[1] = 0x10; | |
393 | value[2] = 0x11; | |
394 | value[3] = 0x12; | |
395 | value[4] = 0x00; | |
396 | value[5] = 0x00; | |
397 | value[6] = 0x00; | |
d8814272 | 398 | hid_hw_request(hdev, report, HID_REQ_SET_REPORT); |
22ca20b2 NK |
399 | |
400 | return 0; | |
401 | } | |
402 | ||
403 | static int kye_probe(struct hid_device *hdev, const struct hid_device_id *id) | |
404 | { | |
405 | int ret; | |
406 | ||
407 | ret = hid_parse(hdev); | |
408 | if (ret) { | |
409 | hid_err(hdev, "parse failed\n"); | |
410 | goto err; | |
411 | } | |
412 | ||
413 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); | |
414 | if (ret) { | |
415 | hid_err(hdev, "hw start failed\n"); | |
416 | goto err; | |
417 | } | |
418 | ||
419 | switch (id->product) { | |
8c7b79bc DY |
420 | case USB_DEVICE_ID_GENIUS_MANTICORE: |
421 | /* | |
422 | * The manticore keyboard needs to have all the interfaces | |
423 | * opened at least once to be fully functional. | |
424 | */ | |
425 | if (hid_hw_open(hdev)) | |
426 | hid_hw_close(hdev); | |
427 | break; | |
22ca20b2 NK |
428 | case USB_DEVICE_ID_KYE_EASYPEN_I405X: |
429 | case USB_DEVICE_ID_KYE_MOUSEPEN_I608X: | |
430 | case USB_DEVICE_ID_KYE_EASYPEN_M610X: | |
feb6faf1 | 431 | case USB_DEVICE_ID_KYE_PENSKETCH_M912: |
8c7b79bc DY |
432 | case USB_DEVICE_ID_KYE_EASYPEN_M406XE: |
433 | case USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2: | |
22ca20b2 NK |
434 | ret = kye_tablet_enable(hdev); |
435 | if (ret) { | |
436 | hid_err(hdev, "tablet enabling failed\n"); | |
437 | goto enabling_err; | |
438 | } | |
439 | break; | |
440 | } | |
441 | ||
442 | return 0; | |
443 | enabling_err: | |
444 | hid_hw_stop(hdev); | |
445 | err: | |
446 | return ret; | |
447 | } | |
448 | ||
79422741 JK |
449 | static const struct hid_device_id kye_devices[] = { |
450 | { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) }, | |
22ca20b2 | 451 | { HID_USB_DEVICE(USB_VENDOR_ID_KYE, |
8c7b79bc | 452 | USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) }, |
22ca20b2 | 453 | { HID_USB_DEVICE(USB_VENDOR_ID_KYE, |
8c7b79bc | 454 | USB_DEVICE_ID_GENIUS_MANTICORE) }, |
2bacedad | 455 | { HID_USB_DEVICE(USB_VENDOR_ID_KYE, |
8c7b79bc | 456 | USB_DEVICE_ID_GENIUS_GX_IMPERATOR) }, |
22ca20b2 | 457 | { HID_USB_DEVICE(USB_VENDOR_ID_KYE, |
8c7b79bc | 458 | USB_DEVICE_ID_KYE_EASYPEN_I405X) }, |
5e55e2aa | 459 | { HID_USB_DEVICE(USB_VENDOR_ID_KYE, |
8c7b79bc | 460 | USB_DEVICE_ID_KYE_MOUSEPEN_I608X) }, |
3685c18e | 461 | { HID_USB_DEVICE(USB_VENDOR_ID_KYE, |
8c7b79bc | 462 | USB_DEVICE_ID_KYE_EASYPEN_M610X) }, |
0adb9c2c | 463 | { HID_USB_DEVICE(USB_VENDOR_ID_KYE, |
8c7b79bc | 464 | USB_DEVICE_ID_KYE_PENSKETCH_M912) }, |
4a2c94c9 | 465 | { HID_USB_DEVICE(USB_VENDOR_ID_KYE, |
8c7b79bc | 466 | USB_DEVICE_ID_KYE_EASYPEN_M406XE) }, |
feb6faf1 | 467 | { HID_USB_DEVICE(USB_VENDOR_ID_KYE, |
8c7b79bc | 468 | USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2) }, |
79422741 JK |
469 | { } |
470 | }; | |
471 | MODULE_DEVICE_TABLE(hid, kye_devices); | |
472 | ||
473 | static struct hid_driver kye_driver = { | |
474 | .name = "kye", | |
475 | .id_table = kye_devices, | |
22ca20b2 | 476 | .probe = kye_probe, |
79422741 JK |
477 | .report_fixup = kye_report_fixup, |
478 | }; | |
f425458e | 479 | module_hid_driver(kye_driver); |
79422741 | 480 | |
79422741 | 481 | MODULE_LICENSE("GPL"); |