1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#include <linux/device.h>
17#include <linux/hid.h>
18#include <linux/module.h>
19
20#include "hid-ids.h"
21
22
23
24
25
26
27
28#define EASYPEN_I405X_RDESC_ORIG_SIZE 476
29
30
31static __u8 easypen_i405x_rdesc_fixed[] = {
32 0x06, 0x00, 0xFF,
33 0x09, 0x01,
34 0xA1, 0x01,
35 0x85, 0x05,
36 0x09, 0x01,
37 0x15, 0x80,
38 0x25, 0x7F,
39 0x75, 0x08,
40 0x95, 0x07,
41 0xB1, 0x02,
42 0xC0,
43 0x05, 0x0D,
44 0x09, 0x02,
45 0xA1, 0x01,
46 0x85, 0x10,
47 0x09, 0x20,
48 0xA0,
49 0x14,
50 0x25, 0x01,
51 0x75, 0x01,
52 0x09, 0x42,
53 0x09, 0x44,
54 0x09, 0x46,
55 0x95, 0x03,
56 0x81, 0x02,
57 0x95, 0x04,
58 0x81, 0x03,
59 0x09, 0x32,
60 0x95, 0x01,
61 0x81, 0x02,
62 0x75, 0x10,
63 0x95, 0x01,
64 0xA4,
65 0x05, 0x01,
66 0x55, 0xFD,
67 0x65, 0x13,
68 0x34,
69 0x09, 0x30,
70 0x46, 0x7C, 0x15,
71 0x26, 0x00, 0x37,
72 0x81, 0x02,
73 0x09, 0x31,
74 0x46, 0xA0, 0x0F,
75 0x26, 0x00, 0x28,
76 0x81, 0x02,
77 0xB4,
78 0x09, 0x30,
79 0x26, 0xFF, 0x03,
80 0x81, 0x02,
81 0xC0,
82 0xC0
83};
84
85
86
87
88
89
90
91#define MOUSEPEN_I608X_RDESC_ORIG_SIZE 476
92
93
94static __u8 mousepen_i608x_rdesc_fixed[] = {
95 0x06, 0x00, 0xFF,
96 0x09, 0x01,
97 0xA1, 0x01,
98 0x85, 0x05,
99 0x09, 0x01,
100 0x15, 0x80,
101 0x25, 0x7F,
102 0x75, 0x08,
103 0x95, 0x07,
104 0xB1, 0x02,
105 0xC0,
106 0x05, 0x0D,
107 0x09, 0x02,
108 0xA1, 0x01,
109 0x85, 0x10,
110 0x09, 0x20,
111 0xA0,
112 0x14,
113 0x25, 0x01,
114 0x75, 0x01,
115 0x09, 0x42,
116 0x09, 0x44,
117 0x09, 0x46,
118 0x95, 0x03,
119 0x81, 0x02,
120 0x95, 0x04,
121 0x81, 0x03,
122 0x09, 0x32,
123 0x95, 0x01,
124 0x81, 0x02,
125 0x75, 0x10,
126 0x95, 0x01,
127 0xA4,
128 0x05, 0x01,
129 0x55, 0xFD,
130 0x65, 0x13,
131 0x34,
132 0x09, 0x30,
133 0x46, 0x40, 0x1F,
134 0x26, 0x00, 0x50,
135 0x81, 0x02,
136 0x09, 0x31,
137 0x46, 0x70, 0x17,
138 0x26, 0x00, 0x3C,
139 0x81, 0x02,
140 0xB4,
141 0x09, 0x30,
142 0x26, 0xFF, 0x03,
143 0x81, 0x02,
144 0xC0,
145 0xC0,
146 0x05, 0x01,
147 0x09, 0x02,
148 0xA1, 0x01,
149 0x85, 0x11,
150 0x09, 0x01,
151 0xA0,
152 0x14,
153 0xA4,
154 0x05, 0x09,
155 0x75, 0x01,
156 0x19, 0x01,
157 0x29, 0x03,
158 0x25, 0x01,
159 0x95, 0x03,
160 0x81, 0x02,
161 0x95, 0x05,
162 0x81, 0x01,
163 0xB4,
164 0x95, 0x01,
165 0xA4,
166 0x55, 0xFD,
167 0x65, 0x13,
168 0x34,
169 0x75, 0x10,
170 0x09, 0x30,
171 0x46, 0x40, 0x1F,
172 0x26, 0x00, 0x50,
173 0x81, 0x02,
174 0x09, 0x31,
175 0x46, 0x70, 0x17,
176 0x26, 0x00, 0x3C,
177 0x81, 0x02,
178 0xB4,
179 0x75, 0x08,
180 0x09, 0x38,
181 0x15, 0xFF,
182 0x25, 0x01,
183 0x81, 0x06,
184 0x81, 0x01,
185 0xC0,
186 0xC0
187};
188
189
190
191
192
193
194
195#define EASYPEN_M610X_RDESC_ORIG_SIZE 476
196
197
198static __u8 easypen_m610x_rdesc_fixed[] = {
199 0x06, 0x00, 0xFF,
200 0x09, 0x01,
201 0xA1, 0x01,
202 0x85, 0x05,
203 0x09, 0x01,
204 0x15, 0x80,
205 0x25, 0x7F,
206 0x75, 0x08,
207 0x95, 0x07,
208 0xB1, 0x02,
209 0xC0,
210 0x05, 0x0D,
211 0x09, 0x02,
212 0xA1, 0x01,
213 0x85, 0x10,
214 0x09, 0x20,
215 0xA0,
216 0x14,
217 0x25, 0x01,
218 0x75, 0x01,
219 0x09, 0x42,
220 0x09, 0x44,
221 0x09, 0x46,
222 0x95, 0x03,
223 0x81, 0x02,
224 0x95, 0x04,
225 0x81, 0x03,
226 0x09, 0x32,
227 0x95, 0x01,
228 0x81, 0x02,
229 0x75, 0x10,
230 0x95, 0x01,
231 0xA4,
232 0x05, 0x01,
233 0x55, 0xFD,
234 0x65, 0x13,
235 0x34,
236 0x09, 0x30,
237 0x46, 0x10, 0x27,
238 0x27, 0x00, 0xA0, 0x00, 0x00,
239 0x81, 0x02,
240 0x09, 0x31,
241 0x46, 0x6A, 0x18,
242 0x26, 0x00, 0x64,
243 0x81, 0x02,
244 0xB4,
245 0x09, 0x30,
246 0x26, 0xFF, 0x03,
247 0x81, 0x02,
248 0xC0,
249 0xC0,
250 0x05, 0x0C,
251 0x09, 0x01,
252 0xA1, 0x01,
253 0x85, 0x12,
254 0x14,
255 0x25, 0x01,
256 0x75, 0x01,
257 0x95, 0x04,
258 0x0A, 0x1A, 0x02,
259 0x0A, 0x79, 0x02,
260 0x0A, 0x2D, 0x02,
261 0x0A, 0x2E, 0x02,
262 0x81, 0x02,
263 0x95, 0x01,
264 0x75, 0x14,
265 0x81, 0x03,
266 0x75, 0x20,
267 0x81, 0x03,
268 0xC0
269};
270
271static __u8 *kye_consumer_control_fixup(struct hid_device *hdev, __u8 *rdesc,
272 unsigned int *rsize, int offset, const char *device_name) {
273
274
275
276
277
278 if (*rsize >= offset + 31 &&
279
280 rdesc[offset] == 0x05 && rdesc[offset + 1] == 0x0c &&
281
282 rdesc[offset + 2] == 0x09 && rdesc[offset + 3] == 0x01 &&
283
284 rdesc[offset + 10] == 0x2a && rdesc[offset + 12] > 0x2f) {
285 hid_info(hdev, "fixing up %s report descriptor\n", device_name);
286 rdesc[offset + 12] = 0x2f;
287 }
288 return rdesc;
289}
290
291static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
292 unsigned int *rsize)
293{
294 switch (hdev->product) {
295 case USB_DEVICE_ID_KYE_ERGO_525V:
296
297
298
299
300
301
302
303 if (*rsize >= 74 &&
304 rdesc[61] == 0x05 && rdesc[62] == 0x08 &&
305 rdesc[63] == 0x19 && rdesc[64] == 0x08 &&
306 rdesc[65] == 0x29 && rdesc[66] == 0x0f &&
307 rdesc[71] == 0x75 && rdesc[72] == 0x08 &&
308 rdesc[73] == 0x95 && rdesc[74] == 0x01) {
309 hid_info(hdev,
310 "fixing up Kye/Genius Ergo Mouse "
311 "report descriptor\n");
312 rdesc[62] = 0x09;
313 rdesc[64] = 0x04;
314 rdesc[66] = 0x07;
315 rdesc[72] = 0x01;
316 rdesc[74] = 0x08;
317 }
318 break;
319 case USB_DEVICE_ID_KYE_EASYPEN_I405X:
320 if (*rsize == EASYPEN_I405X_RDESC_ORIG_SIZE) {
321 rdesc = easypen_i405x_rdesc_fixed;
322 *rsize = sizeof(easypen_i405x_rdesc_fixed);
323 }
324 break;
325 case USB_DEVICE_ID_KYE_MOUSEPEN_I608X:
326 if (*rsize == MOUSEPEN_I608X_RDESC_ORIG_SIZE) {
327 rdesc = mousepen_i608x_rdesc_fixed;
328 *rsize = sizeof(mousepen_i608x_rdesc_fixed);
329 }
330 break;
331 case USB_DEVICE_ID_KYE_EASYPEN_M610X:
332 if (*rsize == EASYPEN_M610X_RDESC_ORIG_SIZE) {
333 rdesc = easypen_m610x_rdesc_fixed;
334 *rsize = sizeof(easypen_m610x_rdesc_fixed);
335 }
336 break;
337 case USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE:
338 rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 104,
339 "Genius Gila Gaming Mouse");
340 break;
341 case USB_DEVICE_ID_GENIUS_GX_IMPERATOR:
342 rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 83,
343 "Genius Gx Imperator Keyboard");
344 break;
345 }
346 return rdesc;
347}
348
349
350
351
352
353
354
355
356
357static int kye_tablet_enable(struct hid_device *hdev)
358{
359 struct list_head *list;
360 struct list_head *head;
361 struct hid_report *report;
362 __s32 *value;
363
364 list = &hdev->report_enum[HID_FEATURE_REPORT].report_list;
365 list_for_each(head, list) {
366 report = list_entry(head, struct hid_report, list);
367 if (report->id == 5)
368 break;
369 }
370
371 if (head == list) {
372 hid_err(hdev, "tablet-enabling feature report not found\n");
373 return -ENODEV;
374 }
375
376 if (report->maxfield < 1 || report->field[0]->report_count < 7) {
377 hid_err(hdev, "invalid tablet-enabling feature report\n");
378 return -ENODEV;
379 }
380
381 value = report->field[0]->value;
382
383 value[0] = 0x12;
384 value[1] = 0x10;
385 value[2] = 0x11;
386 value[3] = 0x12;
387 value[4] = 0x00;
388 value[5] = 0x00;
389 value[6] = 0x00;
390 hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
391
392 return 0;
393}
394
395static int kye_probe(struct hid_device *hdev, const struct hid_device_id *id)
396{
397 int ret;
398
399 ret = hid_parse(hdev);
400 if (ret) {
401 hid_err(hdev, "parse failed\n");
402 goto err;
403 }
404
405 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
406 if (ret) {
407 hid_err(hdev, "hw start failed\n");
408 goto err;
409 }
410
411 switch (id->product) {
412 case USB_DEVICE_ID_KYE_EASYPEN_I405X:
413 case USB_DEVICE_ID_KYE_MOUSEPEN_I608X:
414 case USB_DEVICE_ID_KYE_EASYPEN_M610X:
415 ret = kye_tablet_enable(hdev);
416 if (ret) {
417 hid_err(hdev, "tablet enabling failed\n");
418 goto enabling_err;
419 }
420 break;
421 }
422
423 return 0;
424enabling_err:
425 hid_hw_stop(hdev);
426err:
427 return ret;
428}
429
430static const struct hid_device_id kye_devices[] = {
431 { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
432 { HID_USB_DEVICE(USB_VENDOR_ID_KYE,
433 USB_DEVICE_ID_KYE_EASYPEN_I405X) },
434 { HID_USB_DEVICE(USB_VENDOR_ID_KYE,
435 USB_DEVICE_ID_KYE_MOUSEPEN_I608X) },
436 { HID_USB_DEVICE(USB_VENDOR_ID_KYE,
437 USB_DEVICE_ID_KYE_EASYPEN_M610X) },
438 { HID_USB_DEVICE(USB_VENDOR_ID_KYE,
439 USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) },
440 { HID_USB_DEVICE(USB_VENDOR_ID_KYE,
441 USB_DEVICE_ID_GENIUS_GX_IMPERATOR) },
442 { }
443};
444MODULE_DEVICE_TABLE(hid, kye_devices);
445
446static struct hid_driver kye_driver = {
447 .name = "kye",
448 .id_table = kye_devices,
449 .probe = kye_probe,
450 .report_fixup = kye_report_fixup,
451};
452module_hid_driver(kye_driver);
453
454MODULE_LICENSE("GPL");
455