HID: kye: Sort kye devices
[linux-2.6-block.git] / drivers / hid / hid-kye.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
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
7  *  Copyright (c) 2012 Nikolai Kondrashov
8  *  Copyright (c) 2023 David Yang
9  */
10
11 #include <asm-generic/unaligned.h>
12 #include <linux/device.h>
13 #include <linux/hid.h>
14 #include <linux/module.h>
15
16 #include "hid-ids.h"
17
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               */
35 };
36
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                */
59 };
60
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                  */
78 };
79
80 /* Fix indexes in kye_tablet_report_fixup if you change this */
81 static const __u8 kye_tablet_rdesc[] = {
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),                  */
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),         */
94         0x09, 0x01,                   /*  Usage (Digitizer),              */
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),           */
108         0x81, 0x01,                   /*      Input (Constant),           */
109         0x09, 0x32,                   /*      Usage (In Range),           */
110         0x95, 0x01,                   /*      Report Count (1),           */
111         0x81, 0x02,                   /*      Input (Variable),           */
112         0x75, 0x10,                   /*      Report Size (16),           */
113         0xA4,                         /*      Push,                       */
114         0x05, 0x01,                   /*      Usage Page (Desktop),       */
115         0x09, 0x30,                   /*      Usage (X),                  */
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),           */
122         0x81, 0x02,                   /*      Input (Variable),           */
123         0x09, 0x31,                   /*      Usage (Y),                  */
124         0x27, 0xFF, 0x7F, 0x00, 0x00, /*      Logical Maximum (32767),    */
125         0x47, 0x00, 0x00, 0x00, 0x00, /*      Physical Maximum (0),       */
126         0x81, 0x02,                   /*      Input (Variable),           */
127         0xB4,                         /*      Pop,                        */
128         0x05, 0x0D,                   /*      Usage Page (Digitizer),     */
129         0x09, 0x30,                   /*      Usage (Tip Pressure),       */
130         0x27, 0xFF, 0x07, 0x00, 0x00, /*      Logical Maximum (2047),     */
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),        */
141         0x19, 0x01,                   /*      Usage Minimum (01h),        */
142         0x29, 0x03,                   /*      Usage Maximum (03h),        */
143         0x14,                         /*      Logical Minimum (0),        */
144         0x25, 0x01,                   /*      Logical Maximum (1),        */
145         0x75, 0x01,                   /*      Report Size (1),            */
146         0x95, 0x03,                   /*      Report Count (3),           */
147         0x81, 0x02,                   /*      Input (Variable),           */
148         0x95, 0x04,                   /*      Report Count (4),           */
149         0x81, 0x01,                   /*      Input (Constant),           */
150         0x05, 0x0D,                   /*      Usage Page (Digitizer),     */
151         0x09, 0x32,                   /*      Usage (In Range),           */
152         0x95, 0x01,                   /*      Report Count (1),           */
153         0x81, 0x02,                   /*      Input (Variable),           */
154         0x05, 0x01,                   /*      Usage Page (Desktop),       */
155         0xA4,                         /*      Push,                       */
156         0x09, 0x30,                   /*      Usage (X),                  */
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),           */
163         0x81, 0x02,                   /*      Input (Variable),           */
164         0x09, 0x31,                   /*      Usage (Y),                  */
165         0x27, 0xFF, 0x7F, 0x00, 0x00, /*      Logical Maximum (32767),    */
166         0x47, 0x00, 0x00, 0x00, 0x00, /*      Physical Maximum (0),       */
167         0x81, 0x02,                   /*      Input (Variable),           */
168         0xB4,                         /*      Pop,                        */
169         0x09, 0x38,                   /*      Usage (Wheel),              */
170         0x15, 0xFF,                   /*      Logical Minimum (-1),       */
171         0x75, 0x08,                   /*      Report Size (8),            */
172         0x95, 0x01,                   /*      Report Count (1),           */
173         0x81, 0x06,                   /*      Input (Variable, Relative), */
174         0x81, 0x01,                   /*      Input (Constant),           */
175         0xC0,                         /*    End Collection,               */
176         0xC0                          /*  End Collection                  */
177 };
178
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[] = {
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},
207         {}
208 };
209
210 static __u8 *kye_consumer_control_fixup(struct hid_device *hdev, __u8 *rdesc,
211                 unsigned int *rsize, int offset, const char *device_name)
212 {
213         /*
214          * the fixup that need to be done:
215          *   - change Usage Maximum in the Consumer Control
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
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
304 static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
305                 unsigned int *rsize)
306 {
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                  */
316                 if (*rsize >= 75 &&
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;
332         case USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE:
333                 rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 104,
334                                         "Genius Gila Gaming Mouse");
335                 break;
336         case USB_DEVICE_ID_GENIUS_MANTICORE:
337                 rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 104,
338                                         "Genius Manticore Keyboard");
339                 break;
340         case USB_DEVICE_ID_GENIUS_GX_IMPERATOR:
341                 rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 83,
342                                         "Genius Gx Imperator Keyboard");
343                 break;
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);
351                 break;
352         }
353         return rdesc;
354 }
355
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
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          */
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;
398         hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
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) {
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;
428         case USB_DEVICE_ID_KYE_EASYPEN_I405X:
429         case USB_DEVICE_ID_KYE_MOUSEPEN_I608X:
430         case USB_DEVICE_ID_KYE_EASYPEN_M610X:
431         case USB_DEVICE_ID_KYE_PENSKETCH_M912:
432         case USB_DEVICE_ID_KYE_EASYPEN_M406XE:
433         case USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2:
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
449 static const struct hid_device_id kye_devices[] = {
450         { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
451         { HID_USB_DEVICE(USB_VENDOR_ID_KYE,
452                                 USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) },
453         { HID_USB_DEVICE(USB_VENDOR_ID_KYE,
454                                 USB_DEVICE_ID_GENIUS_MANTICORE) },
455         { HID_USB_DEVICE(USB_VENDOR_ID_KYE,
456                                 USB_DEVICE_ID_GENIUS_GX_IMPERATOR) },
457         { HID_USB_DEVICE(USB_VENDOR_ID_KYE,
458                                 USB_DEVICE_ID_KYE_EASYPEN_I405X) },
459         { HID_USB_DEVICE(USB_VENDOR_ID_KYE,
460                                 USB_DEVICE_ID_KYE_MOUSEPEN_I608X) },
461         { HID_USB_DEVICE(USB_VENDOR_ID_KYE,
462                                 USB_DEVICE_ID_KYE_EASYPEN_M610X) },
463         { HID_USB_DEVICE(USB_VENDOR_ID_KYE,
464                                 USB_DEVICE_ID_KYE_PENSKETCH_M912) },
465         { HID_USB_DEVICE(USB_VENDOR_ID_KYE,
466                                 USB_DEVICE_ID_KYE_EASYPEN_M406XE) },
467         { HID_USB_DEVICE(USB_VENDOR_ID_KYE,
468                                 USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2) },
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,
476         .probe = kye_probe,
477         .report_fixup = kye_report_fixup,
478 };
479 module_hid_driver(kye_driver);
480
481 MODULE_LICENSE("GPL");