Commit | Line | Data |
---|---|---|
10bd065f JK |
1 | /* |
2 | * HID-input usage mapping quirks | |
3 | * | |
4 | * This is used to handle HID-input mappings for devices violating | |
5 | * HUT 1.12 specification. | |
6 | * | |
85c985f4 | 7 | * Copyright (c) 2007-2008 Jiri Kosina |
10bd065f JK |
8 | */ |
9 | ||
10 | /* | |
11 | * This program is free software; you can redistribute it and/or modify it | |
12 | * under the terms of the GNU General Public License as published by the Free | |
13 | * Software Foundation; either version 2 of the License | |
14 | */ | |
15 | ||
16 | #include <linux/input.h> | |
17 | #include <linux/hid.h> | |
18 | ||
022e8c4d JS |
19 | #define map_rel(c) hid_map_usage(hidinput, usage, bit, max, EV_REL, (c)) |
20 | #define map_key(c) hid_map_usage(hidinput, usage, bit, max, EV_KEY, (c)) | |
10bd065f | 21 | |
022e8c4d JS |
22 | #define map_key_clear(c) hid_map_usage_clear(hidinput, usage, bit, \ |
23 | max, EV_KEY, (c)) | |
10bd065f | 24 | |
022e8c4d JS |
25 | static int quirk_belkin_wkbd(struct hid_usage *usage, |
26 | struct hid_input *hidinput, unsigned long **bit, int *max) | |
10bd065f JK |
27 | { |
28 | if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) | |
29 | return 0; | |
30 | ||
31 | switch (usage->hid & HID_USAGE) { | |
32 | case 0x03a: map_key_clear(KEY_SOUND); break; | |
33 | case 0x03b: map_key_clear(KEY_CAMERA); break; | |
34 | case 0x03c: map_key_clear(KEY_DOCUMENTS); break; | |
35 | default: | |
36 | return 0; | |
37 | } | |
38 | return 1; | |
39 | } | |
40 | ||
022e8c4d JS |
41 | static int quirk_cherry_cymotion(struct hid_usage *usage, |
42 | struct hid_input *hidinput, unsigned long **bit, int *max) | |
10bd065f JK |
43 | { |
44 | if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) | |
45 | return 0; | |
46 | ||
47 | switch (usage->hid & HID_USAGE) { | |
48 | case 0x301: map_key_clear(KEY_PROG1); break; | |
49 | case 0x302: map_key_clear(KEY_PROG2); break; | |
50 | case 0x303: map_key_clear(KEY_PROG3); break; | |
51 | default: | |
52 | return 0; | |
53 | } | |
54 | return 1; | |
55 | } | |
56 | ||
022e8c4d JS |
57 | static int quirk_gyration_remote(struct hid_usage *usage, |
58 | struct hid_input *hidinput, unsigned long **bit, int *max) | |
a7f32697 DW |
59 | { |
60 | if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR) | |
61 | return 0; | |
62 | ||
022e8c4d | 63 | set_bit(EV_REP, hidinput->input->evbit); |
a7f32697 DW |
64 | switch(usage->hid & HID_USAGE) { |
65 | /* Reported on Gyration MCE Remote */ | |
66 | case 0x00d: map_key_clear(KEY_HOME); break; | |
67 | case 0x024: map_key_clear(KEY_DVD); break; | |
68 | case 0x025: map_key_clear(KEY_PVR); break; | |
69 | case 0x046: map_key_clear(KEY_MEDIA); break; | |
70 | case 0x047: map_key_clear(KEY_MP3); break; | |
71 | case 0x049: map_key_clear(KEY_CAMERA); break; | |
72 | case 0x04a: map_key_clear(KEY_VIDEO); break; | |
73 | ||
74 | default: | |
75 | return 0; | |
76 | } | |
77 | return 1; | |
78 | } | |
79 | ||
022e8c4d JS |
80 | static int quirk_chicony_tactical_pad(struct hid_usage *usage, |
81 | struct hid_input *hidinput, unsigned long **bit, int *max) | |
10bd065f JK |
82 | { |
83 | if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR) | |
84 | return 0; | |
85 | ||
022e8c4d | 86 | set_bit(EV_REP, hidinput->input->evbit); |
10bd065f JK |
87 | switch (usage->hid & HID_USAGE) { |
88 | case 0xff01: map_key_clear(BTN_1); break; | |
89 | case 0xff02: map_key_clear(BTN_2); break; | |
90 | case 0xff03: map_key_clear(BTN_3); break; | |
91 | case 0xff04: map_key_clear(BTN_4); break; | |
92 | case 0xff05: map_key_clear(BTN_5); break; | |
93 | case 0xff06: map_key_clear(BTN_6); break; | |
94 | case 0xff07: map_key_clear(BTN_7); break; | |
95 | case 0xff08: map_key_clear(BTN_8); break; | |
96 | case 0xff09: map_key_clear(BTN_9); break; | |
97 | case 0xff0a: map_key_clear(BTN_A); break; | |
98 | case 0xff0b: map_key_clear(BTN_B); break; | |
99 | default: | |
100 | return 0; | |
101 | } | |
102 | return 1; | |
103 | } | |
104 | ||
022e8c4d JS |
105 | static int quirk_petalynx_remote(struct hid_usage *usage, |
106 | struct hid_input *hidinput, unsigned long **bit, int *max) | |
10bd065f JK |
107 | { |
108 | if (((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR) && | |
109 | ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)) | |
110 | return 0; | |
111 | ||
112 | if ((usage->hid & HID_USAGE_PAGE) == HID_UP_LOGIVENDOR) | |
113 | switch(usage->hid & HID_USAGE) { | |
114 | case 0x05a: map_key_clear(KEY_TEXT); break; | |
115 | case 0x05b: map_key_clear(KEY_RED); break; | |
116 | case 0x05c: map_key_clear(KEY_GREEN); break; | |
117 | case 0x05d: map_key_clear(KEY_YELLOW); break; | |
118 | case 0x05e: map_key_clear(KEY_BLUE); break; | |
119 | default: | |
120 | return 0; | |
121 | } | |
122 | ||
123 | if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER) | |
124 | switch(usage->hid & HID_USAGE) { | |
125 | case 0x0f6: map_key_clear(KEY_NEXT); break; | |
126 | case 0x0fa: map_key_clear(KEY_BACK); break; | |
127 | default: | |
128 | return 0; | |
129 | } | |
130 | return 1; | |
131 | } | |
132 | ||
022e8c4d JS |
133 | static int quirk_cherry_genius_29e(struct hid_usage *usage, |
134 | struct hid_input *hidinput, unsigned long **bit, int *max) | |
10bd065f JK |
135 | { |
136 | if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) | |
137 | return 0; | |
138 | ||
139 | switch (usage->hid & HID_USAGE) { | |
140 | case 0x156: map_key_clear(KEY_WORDPROCESSOR); break; | |
141 | case 0x157: map_key_clear(KEY_SPREADSHEET); break; | |
142 | case 0x158: map_key_clear(KEY_PRESENTATION); break; | |
143 | case 0x15c: map_key_clear(KEY_STOP); break; | |
144 | ||
145 | default: | |
146 | return 0; | |
147 | } | |
148 | return 1; | |
149 | } | |
150 | ||
022e8c4d | 151 | static int quirk_btc_8193(struct hid_usage *usage, struct hid_input *hidinput, |
70d215c4 | 152 | unsigned long **bit, int *max) |
36ccaad6 JK |
153 | { |
154 | if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) | |
155 | return 0; | |
156 | ||
157 | switch (usage->hid & HID_USAGE) { | |
158 | case 0x230: map_key(BTN_MOUSE); break; | |
159 | case 0x231: map_rel(REL_WHEEL); break; | |
160 | /* | |
161 | * this keyboard has a scrollwheel implemented in | |
162 | * totally broken way. We map this usage temporarily | |
163 | * to HWHEEL and handle it in the event quirk handler | |
164 | */ | |
165 | case 0x232: map_rel(REL_HWHEEL); break; | |
166 | ||
167 | default: | |
168 | return 0; | |
169 | } | |
170 | return 1; | |
171 | } | |
10bd065f JK |
172 | |
173 | #define VENDOR_ID_BELKIN 0x1020 | |
174 | #define DEVICE_ID_BELKIN_WIRELESS_KEYBOARD 0x0006 | |
175 | ||
176 | #define VENDOR_ID_CHERRY 0x046a | |
177 | #define DEVICE_ID_CHERRY_CYMOTION 0x0023 | |
178 | ||
179 | #define VENDOR_ID_CHICONY 0x04f2 | |
180 | #define DEVICE_ID_CHICONY_TACTICAL_PAD 0x0418 | |
181 | ||
36ccaad6 JK |
182 | #define VENDOR_ID_EZKEY 0x0518 |
183 | #define DEVICE_ID_BTC_8193 0x0002 | |
184 | ||
a7f32697 DW |
185 | #define VENDOR_ID_GYRATION 0x0c16 |
186 | #define DEVICE_ID_GYRATION_REMOTE 0x0002 | |
187 | ||
10bd065f JK |
188 | #define VENDOR_ID_MONTEREY 0x0566 |
189 | #define DEVICE_ID_GENIUS_KB29E 0x3004 | |
190 | ||
191 | #define VENDOR_ID_PETALYNX 0x18b1 | |
192 | #define DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037 | |
193 | ||
194 | static const struct hid_input_blacklist { | |
195 | __u16 idVendor; | |
196 | __u16 idProduct; | |
022e8c4d JS |
197 | int (*quirk)(struct hid_usage *, struct hid_input *, unsigned long **, |
198 | int *); | |
10bd065f JK |
199 | } hid_input_blacklist[] = { |
200 | { VENDOR_ID_BELKIN, DEVICE_ID_BELKIN_WIRELESS_KEYBOARD, quirk_belkin_wkbd }, | |
201 | ||
202 | { VENDOR_ID_CHERRY, DEVICE_ID_CHERRY_CYMOTION, quirk_cherry_cymotion }, | |
203 | ||
204 | { VENDOR_ID_CHICONY, DEVICE_ID_CHICONY_TACTICAL_PAD, quirk_chicony_tactical_pad }, | |
205 | ||
36ccaad6 JK |
206 | { VENDOR_ID_EZKEY, DEVICE_ID_BTC_8193, quirk_btc_8193 }, |
207 | ||
a7f32697 DW |
208 | { VENDOR_ID_GYRATION, DEVICE_ID_GYRATION_REMOTE, quirk_gyration_remote }, |
209 | ||
10bd065f JK |
210 | { VENDOR_ID_MONTEREY, DEVICE_ID_GENIUS_KB29E, quirk_cherry_genius_29e }, |
211 | ||
212 | { VENDOR_ID_PETALYNX, DEVICE_ID_PETALYNX_MAXTER_REMOTE, quirk_petalynx_remote }, | |
5f1ab74f | 213 | |
282bfd4c | 214 | { 0, 0, NULL } |
10bd065f JK |
215 | }; |
216 | ||
217 | int hidinput_mapping_quirks(struct hid_usage *usage, | |
022e8c4d | 218 | struct hid_input *hi, unsigned long **bit, int *max) |
10bd065f | 219 | { |
022e8c4d | 220 | struct hid_device *device = input_get_drvdata(hi->input); |
10bd065f JK |
221 | int i = 0; |
222 | ||
223 | while (hid_input_blacklist[i].quirk) { | |
224 | if (hid_input_blacklist[i].idVendor == device->vendor && | |
225 | hid_input_blacklist[i].idProduct == device->product) | |
022e8c4d JS |
226 | return hid_input_blacklist[i].quirk(usage, hi, bit, |
227 | max); | |
10bd065f JK |
228 | i++; |
229 | } | |
230 | return 0; | |
231 | } | |
87bc2aa9 | 232 | |
68a1f2cc | 233 | int hidinput_event_quirks(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) |
87bc2aa9 JK |
234 | { |
235 | struct input_dev *input; | |
87bc2aa9 JK |
236 | |
237 | input = field->hidinput->input; | |
238 | ||
0f221320 JS |
239 | if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && |
240 | (usage->hid == 0x00090007)) { | |
87bc2aa9 JK |
241 | if (value) hid->quirks |= HID_QUIRK_2WHEEL_MOUSE_HACK_ON; |
242 | else hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON; | |
68a1f2cc | 243 | return 1; |
87bc2aa9 JK |
244 | } |
245 | ||
246 | if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_B8) && | |
247 | (usage->type == EV_REL) && | |
248 | (usage->code == REL_WHEEL)) { | |
249 | hid->delayed_value = value; | |
68a1f2cc | 250 | return 1; |
87bc2aa9 JK |
251 | } |
252 | ||
253 | if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_B8) && | |
254 | (usage->hid == 0x000100b8)) { | |
255 | input_event(input, EV_REL, value ? REL_HWHEEL : REL_WHEEL, hid->delayed_value); | |
68a1f2cc | 256 | return 1; |
87bc2aa9 JK |
257 | } |
258 | ||
87bc2aa9 JK |
259 | if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) { |
260 | input_event(input, usage->type, REL_HWHEEL, value); | |
68a1f2cc | 261 | return 1; |
87bc2aa9 JK |
262 | } |
263 | ||
36ccaad6 JK |
264 | /* handle the temporary quirky mapping to HWHEEL */ |
265 | if (hid->quirks & HID_QUIRK_HWHEEL_WHEEL_INVERT && | |
266 | usage->type == EV_REL && usage->code == REL_HWHEEL) { | |
267 | input_event(input, usage->type, REL_WHEEL, -value); | |
68a1f2cc | 268 | return 1; |
36ccaad6 | 269 | } |
32146dc9 JK |
270 | |
271 | /* Gyration MCE remote "Sleep" key */ | |
272 | if (hid->vendor == VENDOR_ID_GYRATION && | |
273 | hid->product == DEVICE_ID_GYRATION_REMOTE && | |
274 | (usage->hid & HID_USAGE_PAGE) == HID_UP_GENDESK && | |
275 | (usage->hid & 0xff) == 0x82) { | |
276 | input_event(input, usage->type, usage->code, 1); | |
277 | input_sync(input); | |
278 | input_event(input, usage->type, usage->code, 0); | |
279 | input_sync(input); | |
280 | return 1; | |
281 | } | |
68a1f2cc | 282 | return 0; |
87bc2aa9 JK |
283 | } |
284 | ||
10bd065f | 285 |