1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * HID driver for some ITE "special" devices |
4 | * Copyright (c) 2017 Hans de Goede <hdegoede@redhat.com> |
5 | */ |
6 | |
7 | #include <linux/device.h> |
8 | #include <linux/input.h> |
9 | #include <linux/hid.h> |
10 | #include <linux/module.h> |
11 | |
12 | #include "hid-ids.h" |
13 | |
14 | #define QUIRK_TOUCHPAD_ON_OFF_REPORT BIT(0) |
15 | |
16 | static __u8 *ite_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) |
17 | { |
18 | unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); |
19 | |
20 | if (quirks & QUIRK_TOUCHPAD_ON_OFF_REPORT) { |
21 | /* For Acer Aspire Switch 10 SW5-012 keyboard-dock */ |
22 | if (*rsize == 188 && rdesc[162] == 0x81 && rdesc[163] == 0x02) { |
23 | hid_info(hdev, "Fixing up Acer Sw5-012 ITE keyboard report descriptor\n" ); |
24 | rdesc[163] = HID_MAIN_ITEM_RELATIVE; |
25 | } |
26 | /* For Acer One S1002/S1003 keyboard-dock */ |
27 | if (*rsize == 188 && rdesc[185] == 0x81 && rdesc[186] == 0x02) { |
28 | hid_info(hdev, "Fixing up Acer S1002/S1003 ITE keyboard report descriptor\n" ); |
29 | rdesc[186] = HID_MAIN_ITEM_RELATIVE; |
30 | } |
31 | /* For Acer Aspire Switch 10E (SW3-016) keyboard-dock */ |
32 | if (*rsize == 210 && rdesc[184] == 0x81 && rdesc[185] == 0x02) { |
33 | hid_info(hdev, "Fixing up Acer Aspire Switch 10E (SW3-016) ITE keyboard report descriptor\n" ); |
34 | rdesc[185] = HID_MAIN_ITEM_RELATIVE; |
35 | } |
36 | } |
37 | |
38 | return rdesc; |
39 | } |
40 | |
41 | static int ite_input_mapping(struct hid_device *hdev, |
42 | struct hid_input *hi, struct hid_field *field, |
43 | struct hid_usage *usage, unsigned long **bit, |
44 | int *max) |
45 | { |
46 | |
47 | unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); |
48 | |
49 | if ((quirks & QUIRK_TOUCHPAD_ON_OFF_REPORT) && |
50 | (usage->hid & HID_USAGE_PAGE) == 0x00880000) { |
51 | if (usage->hid == 0x00880078) { |
52 | /* Touchpad on, userspace expects F22 for this */ |
53 | hid_map_usage_clear(hidinput: hi, usage, bit, max, EV_KEY, KEY_F22); |
54 | return 1; |
55 | } |
56 | if (usage->hid == 0x00880079) { |
57 | /* Touchpad off, userspace expects F23 for this */ |
58 | hid_map_usage_clear(hidinput: hi, usage, bit, max, EV_KEY, KEY_F23); |
59 | return 1; |
60 | } |
61 | return -1; |
62 | } |
63 | |
64 | return 0; |
65 | } |
66 | |
67 | static int ite_event(struct hid_device *hdev, struct hid_field *field, |
68 | struct hid_usage *usage, __s32 value) |
69 | { |
70 | struct input_dev *input; |
71 | |
72 | if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput) |
73 | return 0; |
74 | |
75 | input = field->hidinput->input; |
76 | |
77 | /* |
78 | * The ITE8595 always reports 0 as value for the rfkill button. Luckily |
79 | * it is the only button in its report, and it sends a report on |
80 | * release only, so receiving a report means the button was pressed. |
81 | */ |
82 | if (usage->hid == HID_GD_RFKILL_BTN) { |
83 | input_event(dev: input, EV_KEY, KEY_RFKILL, value: 1); |
84 | input_sync(dev: input); |
85 | input_event(dev: input, EV_KEY, KEY_RFKILL, value: 0); |
86 | input_sync(dev: input); |
87 | return 1; |
88 | } |
89 | |
90 | return 0; |
91 | } |
92 | |
93 | static int ite_probe(struct hid_device *hdev, const struct hid_device_id *id) |
94 | { |
95 | int ret; |
96 | |
97 | hid_set_drvdata(hdev, data: (void *)id->driver_data); |
98 | |
99 | ret = hid_open_report(device: hdev); |
100 | if (ret) |
101 | return ret; |
102 | |
103 | return hid_hw_start(hdev, HID_CONNECT_DEFAULT); |
104 | } |
105 | |
106 | static const struct hid_device_id ite_devices[] = { |
107 | { HID_USB_DEVICE(USB_VENDOR_ID_ITE, USB_DEVICE_ID_ITE8595) }, |
108 | { HID_USB_DEVICE(USB_VENDOR_ID_258A, USB_DEVICE_ID_258A_6A88) }, |
109 | /* ITE8595 USB kbd ctlr, with Synaptics touchpad connected to it. */ |
110 | { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, |
111 | USB_VENDOR_ID_SYNAPTICS, |
112 | USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012), |
113 | .driver_data = QUIRK_TOUCHPAD_ON_OFF_REPORT }, |
114 | /* ITE8910 USB kbd ctlr, with Synaptics touchpad connected to it. */ |
115 | { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, |
116 | USB_VENDOR_ID_SYNAPTICS, |
117 | USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1002), |
118 | .driver_data = QUIRK_TOUCHPAD_ON_OFF_REPORT }, |
119 | /* ITE8910 USB kbd ctlr, with Synaptics touchpad connected to it. */ |
120 | { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, |
121 | USB_VENDOR_ID_SYNAPTICS, |
122 | USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1003), |
123 | .driver_data = QUIRK_TOUCHPAD_ON_OFF_REPORT }, |
124 | /* ITE8910 USB kbd ctlr, with Synaptics touchpad connected to it. */ |
125 | { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, |
126 | USB_VENDOR_ID_SYNAPTICS, |
127 | USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_017), |
128 | .driver_data = QUIRK_TOUCHPAD_ON_OFF_REPORT }, |
129 | { } |
130 | }; |
131 | MODULE_DEVICE_TABLE(hid, ite_devices); |
132 | |
133 | static struct hid_driver ite_driver = { |
134 | .name = "itetech" , |
135 | .id_table = ite_devices, |
136 | .probe = ite_probe, |
137 | .report_fixup = ite_report_fixup, |
138 | .input_mapping = ite_input_mapping, |
139 | .event = ite_event, |
140 | }; |
141 | module_hid_driver(ite_driver); |
142 | |
143 | MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>" ); |
144 | MODULE_LICENSE("GPL" ); |
145 | |