Merge tag 'linux-watchdog-5.20-rc1' of git://www.linux-watchdog.org/linux-watchdog
[linux-2.6-microblaze.git] / drivers / hid / hid-xiaomi.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * HID driver for Xiaomi Mi Dual Mode Wireless Mouse Silent Edition
4  *
5  * Copyright (c) 2021 Ilya Skriblovsky
6  */
7
8 #include <linux/init.h>
9 #include <linux/module.h>
10 #include <linux/hid.h>
11
12 #include "hid-ids.h"
13
14 /* Fixed Mi Silent Mouse report descriptor */
15 /* Button's Usage Maximum changed from 3 to 5 to make side buttons work */
16 #define MI_SILENT_MOUSE_ORIG_RDESC_LENGTH   87
17 static __u8 mi_silent_mouse_rdesc_fixed[] = {
18         0x05, 0x01,         /*  Usage Page (Desktop),               */
19         0x09, 0x02,         /*  Usage (Mouse),                      */
20         0xA1, 0x01,         /*  Collection (Application),           */
21         0x85, 0x03,         /*      Report ID (3),                  */
22         0x09, 0x01,         /*      Usage (Pointer),                */
23         0xA1, 0x00,         /*      Collection (Physical),          */
24         0x05, 0x09,         /*          Usage Page (Button),        */
25         0x19, 0x01,         /*          Usage Minimum (01h),        */
26         0x29, 0x05, /* X */ /*          Usage Maximum (05h),        */
27         0x15, 0x00,         /*          Logical Minimum (0),        */
28         0x25, 0x01,         /*          Logical Maximum (1),        */
29         0x75, 0x01,         /*          Report Size (1),            */
30         0x95, 0x05,         /*          Report Count (5),           */
31         0x81, 0x02,         /*          Input (Variable),           */
32         0x75, 0x03,         /*          Report Size (3),            */
33         0x95, 0x01,         /*          Report Count (1),           */
34         0x81, 0x01,         /*          Input (Constant),           */
35         0x05, 0x01,         /*          Usage Page (Desktop),       */
36         0x09, 0x30,         /*          Usage (X),                  */
37         0x09, 0x31,         /*          Usage (Y),                  */
38         0x15, 0x81,         /*          Logical Minimum (-127),     */
39         0x25, 0x7F,         /*          Logical Maximum (127),      */
40         0x75, 0x08,         /*          Report Size (8),            */
41         0x95, 0x02,         /*          Report Count (2),           */
42         0x81, 0x06,         /*          Input (Variable, Relative), */
43         0x09, 0x38,         /*          Usage (Wheel),              */
44         0x15, 0x81,         /*          Logical Minimum (-127),     */
45         0x25, 0x7F,         /*          Logical Maximum (127),      */
46         0x75, 0x08,         /*          Report Size (8),            */
47         0x95, 0x01,         /*          Report Count (1),           */
48         0x81, 0x06,         /*          Input (Variable, Relative), */
49         0xC0,               /*      End Collection,                 */
50         0xC0,               /*  End Collection,                     */
51         0x06, 0x01, 0xFF,   /*  Usage Page (FF01h),                 */
52         0x09, 0x01,         /*  Usage (01h),                        */
53         0xA1, 0x01,         /*  Collection (Application),           */
54         0x85, 0x05,         /*      Report ID (5),                  */
55         0x09, 0x05,         /*      Usage (05h),                    */
56         0x15, 0x00,         /*      Logical Minimum (0),            */
57         0x26, 0xFF, 0x00,   /*      Logical Maximum (255),          */
58         0x75, 0x08,         /*      Report Size (8),                */
59         0x95, 0x04,         /*      Report Count (4),               */
60         0xB1, 0x02,         /*      Feature (Variable),             */
61         0xC0                /*  End Collection                      */
62 };
63
64 static __u8 *xiaomi_report_fixup(struct hid_device *hdev, __u8 *rdesc,
65                                  unsigned int *rsize)
66 {
67         switch (hdev->product) {
68         case USB_DEVICE_ID_MI_SILENT_MOUSE:
69                 if (*rsize == MI_SILENT_MOUSE_ORIG_RDESC_LENGTH) {
70                         hid_info(hdev, "fixing up Mi Silent Mouse report descriptor\n");
71                         rdesc = mi_silent_mouse_rdesc_fixed;
72                         *rsize = sizeof(mi_silent_mouse_rdesc_fixed);
73                 }
74                 break;
75         }
76         return rdesc;
77 }
78
79 static const struct hid_device_id xiaomi_devices[] = {
80         { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_XIAOMI, USB_DEVICE_ID_MI_SILENT_MOUSE) },
81         { }
82 };
83 MODULE_DEVICE_TABLE(hid, xiaomi_devices);
84
85 static struct hid_driver xiaomi_driver = {
86         .name = "xiaomi",
87         .id_table = xiaomi_devices,
88         .report_fixup = xiaomi_report_fixup,
89 };
90 module_hid_driver(xiaomi_driver);
91
92 MODULE_LICENSE("GPL");
93 MODULE_AUTHOR("Ilya Skriblovsky <IlyaSkriblovsky@gmail.com>");
94 MODULE_DESCRIPTION("Fixing side buttons of Xiaomi Mi Silent Mouse");