blob: cb0d80f492520eeb42e5592cccd203ac81032a6a [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * $Id: hid-input.c,v 1.2 2002/04/23 00:59:25 rdamazio Exp $
3 *
4 * Copyright (c) 2000-2001 Vojtech Pavlik
5 *
6 * USB HID to Linux Input mapping
7 */
8
9/*
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 * Should you need to contact me, the author, you can do so either by
25 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
26 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
27 */
28
29#include <linux/module.h>
30#include <linux/slab.h>
31#include <linux/kernel.h>
32#include <linux/input.h>
33#include <linux/usb.h>
Dmitry Torokhov16a334c2005-06-30 00:49:08 -050034#include <linux/usb_input.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
36#undef DEBUG
37
38#include "hid.h"
39
40#define unk KEY_UNKNOWN
41
Arjan van de Ven4c4c9432005-11-29 09:43:42 +010042static const unsigned char hid_keyboard[256] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
44 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3,
45 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26,
46 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
47 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
48 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
49 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
50 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
51 115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk,
52 122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
53 unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
54 unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
55 unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
56 unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
57 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
58 150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk
59};
60
Arjan van de Ven4c4c9432005-11-29 09:43:42 +010061static const struct {
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 __s32 x;
63 __s32 y;
64} hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
65
66#define map_abs(c) do { usage->code = c; usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; } while (0)
67#define map_rel(c) do { usage->code = c; usage->type = EV_REL; bit = input->relbit; max = REL_MAX; } while (0)
68#define map_key(c) do { usage->code = c; usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; } while (0)
69#define map_led(c) do { usage->code = c; usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; } while (0)
70#define map_ff(c) do { usage->code = c; usage->type = EV_FF; bit = input->ffbit; max = FF_MAX; } while (0)
71
72#define map_abs_clear(c) do { map_abs(c); clear_bit(c, bit); } while (0)
73#define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0)
74#define map_ff_effect(c) do { set_bit(c, input->ffbit); } while (0)
75
Michael Hanselmanneab9edd2006-01-14 10:08:06 -050076#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
77
78struct hidinput_key_translation {
79 u16 from;
80 u16 to;
81 u8 flags;
82};
83
84#define POWERBOOK_FLAG_FKEY 0x01
85
86static struct hidinput_key_translation powerbook_fn_keys[] = {
87 { KEY_BACKSPACE, KEY_DELETE },
88 { KEY_F1, KEY_BRIGHTNESSDOWN, POWERBOOK_FLAG_FKEY },
89 { KEY_F2, KEY_BRIGHTNESSUP, POWERBOOK_FLAG_FKEY },
90 { KEY_F3, KEY_MUTE, POWERBOOK_FLAG_FKEY },
91 { KEY_F4, KEY_VOLUMEDOWN, POWERBOOK_FLAG_FKEY },
92 { KEY_F5, KEY_VOLUMEUP, POWERBOOK_FLAG_FKEY },
93 { KEY_F6, KEY_NUMLOCK, POWERBOOK_FLAG_FKEY },
94 { KEY_F7, KEY_SWITCHVIDEOMODE, POWERBOOK_FLAG_FKEY },
95 { KEY_F8, KEY_KBDILLUMTOGGLE, POWERBOOK_FLAG_FKEY },
96 { KEY_F9, KEY_KBDILLUMDOWN, POWERBOOK_FLAG_FKEY },
97 { KEY_F10, KEY_KBDILLUMUP, POWERBOOK_FLAG_FKEY },
98 { KEY_UP, KEY_PAGEUP },
99 { KEY_DOWN, KEY_PAGEDOWN },
100 { KEY_LEFT, KEY_HOME },
101 { KEY_RIGHT, KEY_END },
102 { }
103};
104
105static struct hidinput_key_translation powerbook_numlock_keys[] = {
106 { KEY_J, KEY_KP1 },
107 { KEY_K, KEY_KP2 },
108 { KEY_L, KEY_KP3 },
109 { KEY_U, KEY_KP4 },
110 { KEY_I, KEY_KP5 },
111 { KEY_O, KEY_KP6 },
112 { KEY_7, KEY_KP7 },
113 { KEY_8, KEY_KP8 },
114 { KEY_9, KEY_KP9 },
115 { KEY_M, KEY_KP0 },
116 { KEY_DOT, KEY_KPDOT },
117 { KEY_SLASH, KEY_KPPLUS },
118 { KEY_SEMICOLON, KEY_KPMINUS },
119 { KEY_P, KEY_KPASTERISK },
120 { KEY_MINUS, KEY_KPEQUAL },
121 { KEY_0, KEY_KPSLASH },
122 { KEY_F6, KEY_NUMLOCK },
123 { KEY_KPENTER, KEY_KPENTER },
124 { KEY_BACKSPACE, KEY_BACKSPACE },
125 { }
126};
127
128static int usbhid_pb_fnmode = 1;
129module_param_named(pb_fnmode, usbhid_pb_fnmode, int, 0644);
130MODULE_PARM_DESC(pb_fnmode,
131 "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)");
132
133static struct hidinput_key_translation *find_translation(struct hidinput_key_translation *table, u16 from)
134{
135 struct hidinput_key_translation *trans;
136
137 /* Look for the translation */
138 for (trans = table; trans->from; trans++)
139 if (trans->from == from)
140 return trans;
141
142 return NULL;
143}
144
145static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
146 struct hid_usage *usage, __s32 value)
147{
148 struct hidinput_key_translation *trans;
149
150 if (usage->code == KEY_FN) {
151 if (value) hid->quirks |= HID_QUIRK_POWERBOOK_FN_ON;
152 else hid->quirks &= ~HID_QUIRK_POWERBOOK_FN_ON;
153
154 input_event(input, usage->type, usage->code, value);
155
156 return 1;
157 }
158
159 if (usbhid_pb_fnmode) {
160 int do_translate;
161
162 trans = find_translation(powerbook_fn_keys, usage->code);
163 if (trans) {
164 if (test_bit(usage->code, hid->pb_pressed_fn))
165 do_translate = 1;
166 else if (trans->flags & POWERBOOK_FLAG_FKEY)
167 do_translate =
168 (usbhid_pb_fnmode == 2 && (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)) ||
169 (usbhid_pb_fnmode == 1 && !(hid->quirks & HID_QUIRK_POWERBOOK_FN_ON));
170 else
171 do_translate = (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON);
172
173 if (do_translate) {
174 if (value)
175 set_bit(usage->code, hid->pb_pressed_fn);
176 else
177 clear_bit(usage->code, hid->pb_pressed_fn);
178
179 input_event(input, usage->type, trans->to, value);
180
181 return 1;
182 }
183 }
184
185 if (test_bit(usage->code, hid->pb_pressed_numlock) ||
186 test_bit(LED_NUML, input->led)) {
187 trans = find_translation(powerbook_numlock_keys, usage->code);
188
189 if (trans) {
190 if (value)
191 set_bit(usage->code, hid->pb_pressed_numlock);
192 else
193 clear_bit(usage->code, hid->pb_pressed_numlock);
194
195 input_event(input, usage->type, trans->to, value);
196 }
197
198 return 1;
199 }
200 }
201
202 return 0;
203}
204
205static void hidinput_pb_setup(struct input_dev *input)
206{
207 struct hidinput_key_translation *trans;
208
209 set_bit(KEY_NUMLOCK, input->keybit);
210
211 /* Enable all needed keys */
212 for (trans = powerbook_fn_keys; trans->from; trans++)
213 set_bit(trans->to, input->keybit);
214
215 for (trans = powerbook_numlock_keys; trans->from; trans++)
216 set_bit(trans->to, input->keybit);
217}
218#else
219static inline int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
220 struct hid_usage *usage, __s32 value)
221{
222 return 0;
223}
224
225static inline void hidinput_pb_setup(struct input_dev *input)
226{
227}
228#endif
229
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
231 struct hid_usage *usage)
232{
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500233 struct input_dev *input = hidinput->input;
234 struct hid_device *device = input->private;
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500235 int max = 0, code;
236 unsigned long *bit = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
238 field->hidinput = hidinput;
239
240#ifdef DEBUG
241 printk(KERN_DEBUG "Mapping: ");
242 resolv_usage(usage->hid);
243 printk(" ---> ");
244#endif
245
246 if (field->flags & HID_MAIN_ITEM_CONSTANT)
247 goto ignore;
248
249 switch (usage->hid & HID_USAGE_PAGE) {
250
251 case HID_UP_UNDEFINED:
252 goto ignore;
253
254 case HID_UP_KEYBOARD:
255
256 set_bit(EV_REP, input->evbit);
257
258 if ((usage->hid & HID_USAGE) < 256) {
259 if (!hid_keyboard[usage->hid & HID_USAGE]) goto ignore;
260 map_key_clear(hid_keyboard[usage->hid & HID_USAGE]);
261 } else
262 map_key(KEY_UNKNOWN);
263
264 break;
265
266 case HID_UP_BUTTON:
267
268 code = ((usage->hid - 1) & 0xf);
269
270 switch (field->application) {
271 case HID_GD_MOUSE:
272 case HID_GD_POINTER: code += 0x110; break;
273 case HID_GD_JOYSTICK: code += 0x120; break;
274 case HID_GD_GAMEPAD: code += 0x130; break;
275 default:
276 switch (field->physical) {
277 case HID_GD_MOUSE:
278 case HID_GD_POINTER: code += 0x110; break;
279 case HID_GD_JOYSTICK: code += 0x120; break;
280 case HID_GD_GAMEPAD: code += 0x130; break;
281 default: code += 0x100;
282 }
283 }
284
285 map_key(code);
286 break;
287
Vojtech Pavlik0aebfda2005-09-05 00:07:59 -0500288
289 case HID_UP_SIMULATION:
290
291 switch (usage->hid & 0xffff) {
Dmitry Torokhov5fce9d7b2006-01-14 00:27:51 -0500292 case 0xba: map_abs(ABS_RUDDER); break;
Vojtech Pavlik0aebfda2005-09-05 00:07:59 -0500293 case 0xbb: map_abs(ABS_THROTTLE); break;
Dmitry Torokhov5fce9d7b2006-01-14 00:27:51 -0500294 case 0xc4: map_abs(ABS_GAS); break;
295 case 0xc5: map_abs(ABS_BRAKE); break;
296 case 0xc8: map_abs(ABS_WHEEL); break;
Dmitry Torokhovff60dde2005-12-17 11:42:54 -0500297 default: goto ignore;
Vojtech Pavlik0aebfda2005-09-05 00:07:59 -0500298 }
299 break;
300
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 case HID_UP_GENDESK:
302
303 if ((usage->hid & 0xf0) == 0x80) { /* SystemControl */
304 switch (usage->hid & 0xf) {
305 case 0x1: map_key_clear(KEY_POWER); break;
306 case 0x2: map_key_clear(KEY_SLEEP); break;
307 case 0x3: map_key_clear(KEY_WAKEUP); break;
308 default: goto unknown;
309 }
310 break;
311 }
312
313 if ((usage->hid & 0xf0) == 0x90) { /* D-pad */
314 switch (usage->hid) {
315 case HID_GD_UP: usage->hat_dir = 1; break;
316 case HID_GD_DOWN: usage->hat_dir = 5; break;
317 case HID_GD_RIGHT: usage->hat_dir = 3; break;
318 case HID_GD_LEFT: usage->hat_dir = 7; break;
319 default: goto unknown;
320 }
321 if (field->dpad) {
322 map_abs(field->dpad);
323 goto ignore;
324 }
325 map_abs(ABS_HAT0X);
326 break;
327 }
328
329 switch (usage->hid) {
330
331 /* These usage IDs map directly to the usage codes. */
332 case HID_GD_X: case HID_GD_Y: case HID_GD_Z:
333 case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
334 case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500335 if (field->flags & HID_MAIN_ITEM_RELATIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 map_rel(usage->hid & 0xf);
337 else
338 map_abs(usage->hid & 0xf);
339 break;
340
341 case HID_GD_HATSWITCH:
342 usage->hat_min = field->logical_minimum;
343 usage->hat_max = field->logical_maximum;
344 map_abs(ABS_HAT0X);
345 break;
346
347 case HID_GD_START: map_key_clear(BTN_START); break;
348 case HID_GD_SELECT: map_key_clear(BTN_SELECT); break;
349
350 default: goto unknown;
351 }
352
353 break;
354
355 case HID_UP_LED:
356 if (((usage->hid - 1) & 0xffff) >= LED_MAX)
357 goto ignore;
358 map_led((usage->hid - 1) & 0xffff);
359 break;
360
361 case HID_UP_DIGITIZER:
362
363 switch (usage->hid & 0xff) {
364
365 case 0x30: /* TipPressure */
366 if (!test_bit(BTN_TOUCH, input->keybit)) {
367 device->quirks |= HID_QUIRK_NOTOUCH;
368 set_bit(EV_KEY, input->evbit);
369 set_bit(BTN_TOUCH, input->keybit);
370 }
371
372 map_abs_clear(ABS_PRESSURE);
373 break;
374
375 case 0x32: /* InRange */
376 switch (field->physical & 0xff) {
377 case 0x21: map_key(BTN_TOOL_MOUSE); break;
378 case 0x22: map_key(BTN_TOOL_FINGER); break;
379 default: map_key(BTN_TOOL_PEN); break;
380 }
381 break;
382
383 case 0x3c: /* Invert */
384 map_key_clear(BTN_TOOL_RUBBER);
385 break;
386
387 case 0x33: /* Touch */
388 case 0x42: /* TipSwitch */
389 case 0x43: /* TipSwitch2 */
390 device->quirks &= ~HID_QUIRK_NOTOUCH;
391 map_key_clear(BTN_TOUCH);
392 break;
393
394 case 0x44: /* BarrelSwitch */
395 map_key_clear(BTN_STYLUS);
396 break;
397
398 default: goto unknown;
399 }
400 break;
401
402 case HID_UP_CONSUMER: /* USB HUT v1.1, pages 56-62 */
403
404 switch (usage->hid & HID_USAGE) {
405 case 0x000: goto ignore;
406 case 0x034: map_key_clear(KEY_SLEEP); break;
407 case 0x036: map_key_clear(BTN_MISC); break;
Micah F. Galizia39fd7482005-09-05 00:12:15 -0500408 case 0x045: map_key_clear(KEY_RADIO); break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 case 0x08a: map_key_clear(KEY_WWW); break;
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500410 case 0x08d: map_key_clear(KEY_PROGRAM); break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 case 0x095: map_key_clear(KEY_HELP); break;
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500412 case 0x09c: map_key_clear(KEY_CHANNELUP); break;
413 case 0x09d: map_key_clear(KEY_CHANNELDOWN); break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 case 0x0b0: map_key_clear(KEY_PLAY); break;
415 case 0x0b1: map_key_clear(KEY_PAUSE); break;
416 case 0x0b2: map_key_clear(KEY_RECORD); break;
417 case 0x0b3: map_key_clear(KEY_FASTFORWARD); break;
418 case 0x0b4: map_key_clear(KEY_REWIND); break;
419 case 0x0b5: map_key_clear(KEY_NEXTSONG); break;
420 case 0x0b6: map_key_clear(KEY_PREVIOUSSONG); break;
421 case 0x0b7: map_key_clear(KEY_STOPCD); break;
422 case 0x0b8: map_key_clear(KEY_EJECTCD); break;
423 case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break;
424 case 0x0e0: map_abs_clear(ABS_VOLUME); break;
425 case 0x0e2: map_key_clear(KEY_MUTE); break;
426 case 0x0e5: map_key_clear(KEY_BASSBOOST); break;
427 case 0x0e9: map_key_clear(KEY_VOLUMEUP); break;
428 case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break;
429 case 0x183: map_key_clear(KEY_CONFIG); break;
430 case 0x18a: map_key_clear(KEY_MAIL); break;
431 case 0x192: map_key_clear(KEY_CALC); break;
432 case 0x194: map_key_clear(KEY_FILE); break;
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500433 case 0x1a7: map_key_clear(KEY_DOCUMENTS); break;
434 case 0x201: map_key_clear(KEY_NEW); break;
435 case 0x207: map_key_clear(KEY_SAVE); break;
436 case 0x208: map_key_clear(KEY_PRINT); break;
437 case 0x209: map_key_clear(KEY_PROPS); break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 case 0x21a: map_key_clear(KEY_UNDO); break;
439 case 0x21b: map_key_clear(KEY_COPY); break;
440 case 0x21c: map_key_clear(KEY_CUT); break;
441 case 0x21d: map_key_clear(KEY_PASTE); break;
442 case 0x221: map_key_clear(KEY_FIND); break;
443 case 0x223: map_key_clear(KEY_HOMEPAGE); break;
444 case 0x224: map_key_clear(KEY_BACK); break;
445 case 0x225: map_key_clear(KEY_FORWARD); break;
446 case 0x226: map_key_clear(KEY_STOP); break;
447 case 0x227: map_key_clear(KEY_REFRESH); break;
448 case 0x22a: map_key_clear(KEY_BOOKMARKS); break;
Vojtech Pavlik940824b2006-01-14 00:25:39 -0500449 case 0x233: map_key_clear(KEY_SCROLLUP); break;
450 case 0x234: map_key_clear(KEY_SCROLLDOWN); break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 case 0x238: map_rel(REL_HWHEEL); break;
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500452 case 0x279: map_key_clear(KEY_REDO); break;
453 case 0x289: map_key_clear(KEY_REPLY); break;
454 case 0x28b: map_key_clear(KEY_FORWARDMAIL); break;
455 case 0x28c: map_key_clear(KEY_SEND); break;
Vojtech Pavlik940824b2006-01-14 00:25:39 -0500456
457 /* Reported on a Cherry Cymotion keyboard */
458 case 0x301: map_key_clear(KEY_PROG1); break;
459 case 0x302: map_key_clear(KEY_PROG2); break;
460 case 0x303: map_key_clear(KEY_PROG3); break;
461
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500462 default: goto ignore;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 }
464 break;
465
466 case HID_UP_HPVENDOR: /* Reported on a Dutch layout HP5308 */
467
468 set_bit(EV_REP, input->evbit);
469 switch (usage->hid & HID_USAGE) {
470 case 0x021: map_key_clear(KEY_PRINT); break;
471 case 0x070: map_key_clear(KEY_HP); break;
472 case 0x071: map_key_clear(KEY_CAMERA); break;
473 case 0x072: map_key_clear(KEY_SOUND); break;
474 case 0x073: map_key_clear(KEY_QUESTION); break;
475 case 0x080: map_key_clear(KEY_EMAIL); break;
476 case 0x081: map_key_clear(KEY_CHAT); break;
477 case 0x082: map_key_clear(KEY_SEARCH); break;
478 case 0x083: map_key_clear(KEY_CONNECT); break;
479 case 0x084: map_key_clear(KEY_FINANCE); break;
480 case 0x085: map_key_clear(KEY_SPORT); break;
481 case 0x086: map_key_clear(KEY_SHOP); break;
482 default: goto ignore;
483 }
484 break;
485
486 case HID_UP_MSVENDOR:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 goto ignore;
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500488
Stelian Pope875ce32005-09-05 01:57:33 -0500489 case HID_UP_CUSTOM: /* Reported on Logitech and Powerbook USB keyboards */
490
491 set_bit(EV_REP, input->evbit);
492 switch(usage->hid & HID_USAGE) {
Michael Hanselmanneab9edd2006-01-14 10:08:06 -0500493 case 0x003:
494 /* The fn key on Apple PowerBooks */
495 map_key_clear(KEY_FN);
496 hidinput_pb_setup(input);
497 break;
498
Stelian Pope875ce32005-09-05 01:57:33 -0500499 default: goto ignore;
500 }
501 break;
502
503 case HID_UP_LOGIVENDOR: /* Reported on Logitech Ultra X Media Remote */
Micah F. Galizia39fd7482005-09-05 00:12:15 -0500504
505 set_bit(EV_REP, input->evbit);
506 switch(usage->hid & HID_USAGE) {
507 case 0x004: map_key_clear(KEY_AGAIN); break;
508 case 0x00d: map_key_clear(KEY_HOME); break;
509 case 0x024: map_key_clear(KEY_SHUFFLE); break;
510 case 0x025: map_key_clear(KEY_TV); break;
511 case 0x026: map_key_clear(KEY_MENU); break;
512 case 0x031: map_key_clear(KEY_AUDIO); break;
513 case 0x032: map_key_clear(KEY_SUBTITLE); break;
514 case 0x033: map_key_clear(KEY_LAST); break;
515 case 0x047: map_key_clear(KEY_MP3); break;
516 case 0x048: map_key_clear(KEY_DVD); break;
517 case 0x049: map_key_clear(KEY_MEDIA); break;
518 case 0x04a: map_key_clear(KEY_VIDEO); break;
519 case 0x04b: map_key_clear(KEY_ANGLE); break;
520 case 0x04c: map_key_clear(KEY_LANGUAGE); break;
521 case 0x04d: map_key_clear(KEY_SUBTITLE); break;
522 case 0x051: map_key_clear(KEY_RED); break;
523 case 0x052: map_key_clear(KEY_CLOSE); break;
524 default: goto ignore;
525 }
526 break;
527
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 case HID_UP_PID:
529
530 set_bit(EV_FF, input->evbit);
531 switch(usage->hid & HID_USAGE) {
532 case 0x26: map_ff_effect(FF_CONSTANT); goto ignore;
533 case 0x27: map_ff_effect(FF_RAMP); goto ignore;
534 case 0x28: map_ff_effect(FF_CUSTOM); goto ignore;
535 case 0x30: map_ff_effect(FF_SQUARE); map_ff_effect(FF_PERIODIC); goto ignore;
536 case 0x31: map_ff_effect(FF_SINE); map_ff_effect(FF_PERIODIC); goto ignore;
537 case 0x32: map_ff_effect(FF_TRIANGLE); map_ff_effect(FF_PERIODIC); goto ignore;
538 case 0x33: map_ff_effect(FF_SAW_UP); map_ff_effect(FF_PERIODIC); goto ignore;
539 case 0x34: map_ff_effect(FF_SAW_DOWN); map_ff_effect(FF_PERIODIC); goto ignore;
540 case 0x40: map_ff_effect(FF_SPRING); goto ignore;
541 case 0x41: map_ff_effect(FF_DAMPER); goto ignore;
542 case 0x42: map_ff_effect(FF_INERTIA); goto ignore;
543 case 0x43: map_ff_effect(FF_FRICTION); goto ignore;
544 case 0x7e: map_ff(FF_GAIN); break;
545 case 0x83: input->ff_effects_max = field->value[0]; goto ignore;
546 case 0x98: map_ff(FF_AUTOCENTER); break;
547 case 0xa4: map_key_clear(BTN_DEAD); break;
548 default: goto ignore;
549 }
550 break;
551
552 default:
553 unknown:
554 if (field->report_size == 1) {
555 if (field->report->type == HID_OUTPUT_REPORT) {
556 map_led(LED_MISC);
557 break;
558 }
559 map_key(BTN_MISC);
560 break;
561 }
562 if (field->flags & HID_MAIN_ITEM_RELATIVE) {
563 map_rel(REL_MISC);
564 break;
565 }
566 map_abs(ABS_MISC);
567 break;
568 }
569
570 set_bit(usage->type, input->evbit);
571
572 while (usage->code <= max && test_and_set_bit(usage->code, bit))
573 usage->code = find_next_zero_bit(bit, max + 1, usage->code);
574
575 if (usage->code > max)
576 goto ignore;
577
Vojtech Pavlikc58de6d2005-09-05 00:13:15 -0500578 if (((device->quirks & (HID_QUIRK_2WHEEL_POWERMOUSE)) && (usage->hid == 0x00010032)))
579 map_rel(REL_HWHEEL);
580
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) &&
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500582 (usage->type == EV_REL) && (usage->code == REL_WHEEL))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 set_bit(REL_HWHEEL, bit);
584
585 if (((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
586 || ((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007)))
587 goto ignore;
588
589 if (usage->type == EV_ABS) {
590
591 int a = field->logical_minimum;
592 int b = field->logical_maximum;
593
594 if ((device->quirks & HID_QUIRK_BADPAD) && (usage->code == ABS_X || usage->code == ABS_Y)) {
595 a = field->logical_minimum = 0;
596 b = field->logical_maximum = 255;
597 }
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500598
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 if (field->application == HID_GD_GAMEPAD || field->application == HID_GD_JOYSTICK)
600 input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4);
601 else input_set_abs_params(input, usage->code, a, b, 0, 0);
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500602
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 }
604
605 if (usage->hat_min < usage->hat_max || usage->hat_dir) {
606 int i;
607 for (i = usage->code; i < usage->code + 2 && i <= max; i++) {
608 input_set_abs_params(input, i, -1, 1, 0, 0);
609 set_bit(i, input->absbit);
610 }
611 if (usage->hat_dir && !field->dpad)
612 field->dpad = usage->code;
613 }
614
615#ifdef DEBUG
616 resolv_event(usage->type, usage->code);
617 printk("\n");
618#endif
619 return;
620
621ignore:
622#ifdef DEBUG
623 printk("IGNORED\n");
624#endif
625 return;
626}
627
628void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, struct pt_regs *regs)
629{
Pete Zaitceva9b2e912005-07-29 12:18:34 -0700630 struct input_dev *input;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 int *quirks = &hid->quirks;
632
Pete Zaitceva9b2e912005-07-29 12:18:34 -0700633 if (!field->hidinput)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 return;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500635
636 input = field->hidinput->input;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
638 input_regs(input, regs);
639
640 if (!usage->type)
641 return;
642
643 if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
644 || ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) {
645 if (value) hid->quirks |= HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
646 else hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
647 return;
648 }
649
650 if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) {
651 input_event(input, usage->type, REL_HWHEEL, value);
652 return;
653 }
654
Michael Hanselmanneab9edd2006-01-14 10:08:06 -0500655 if ((hid->quirks & HID_QUIRK_POWERBOOK_HAS_FN) && hidinput_pb_event(hid, input, usage, value))
656 return;
657
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500658 if (usage->hat_min < usage->hat_max || usage->hat_dir) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 int hat_dir = usage->hat_dir;
660 if (!hat_dir)
661 hat_dir = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1;
662 if (hat_dir < 0 || hat_dir > 8) hat_dir = 0;
663 input_event(input, usage->type, usage->code , hid_hat_to_axis[hat_dir].x);
664 input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[hat_dir].y);
665 return;
666 }
667
668 if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */
669 *quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT);
670 return;
671 }
672
673 if (usage->hid == (HID_UP_DIGITIZER | 0x0032)) { /* InRange */
674 if (value) {
675 input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1);
676 return;
677 }
678 input_event(input, usage->type, usage->code, 0);
679 input_event(input, usage->type, BTN_TOOL_RUBBER, 0);
680 return;
681 }
682
683 if (usage->hid == (HID_UP_DIGITIZER | 0x0030) && (*quirks & HID_QUIRK_NOTOUCH)) { /* Pressure */
684 int a = field->logical_minimum;
685 int b = field->logical_maximum;
686 input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3));
687 }
688
689 if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */
690 input->ff_effects_max = value;
691 dbg("Maximum Effects - %d",input->ff_effects_max);
692 return;
693 }
694
695 if (usage->hid == (HID_UP_PID | 0x7fUL)) {
696 dbg("PID Pool Report\n");
697 return;
698 }
699
Michael Hanselmanneab9edd2006-01-14 10:08:06 -0500700 if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 return;
702
703 input_event(input, usage->type, usage->code, value);
704
705 if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY))
706 input_event(input, usage->type, usage->code, 0);
707}
708
709void hidinput_report_event(struct hid_device *hid, struct hid_report *report)
710{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 struct hid_input *hidinput;
712
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500713 list_for_each_entry(hidinput, &hid->inputs, list)
714 input_sync(hidinput->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715}
716
717static int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field)
718{
719 struct hid_report *report;
720 int i, j;
721
722 list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) {
723 for (i = 0; i < report->maxfield; i++) {
724 *field = report->field[i];
725 for (j = 0; j < (*field)->maxusage; j++)
726 if ((*field)->usage[j].type == type && (*field)->usage[j].code == code)
727 return j;
728 }
729 }
730 return -1;
731}
732
733static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
734{
735 struct hid_device *hid = dev->private;
736 struct hid_field *field;
737 int offset;
738
739 if (type == EV_FF)
740 return hid_ff_event(hid, dev, type, code, value);
741
742 if (type != EV_LED)
743 return -1;
744
745 if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
746 warn("event field not found");
747 return -1;
748 }
749
750 hid_set_field(field, offset, value);
751 hid_submit_report(hid, field->report, USB_DIR_OUT);
752
753 return 0;
754}
755
756static int hidinput_open(struct input_dev *dev)
757{
758 struct hid_device *hid = dev->private;
759 return hid_open(hid);
760}
761
762static void hidinput_close(struct input_dev *dev)
763{
764 struct hid_device *hid = dev->private;
765 hid_close(hid);
766}
767
768/*
769 * Register the input device; print a message.
770 * Configure the input layer interface
771 * Read all reports and initialize the absolute field values.
772 */
773
774int hidinput_connect(struct hid_device *hid)
775{
776 struct usb_device *dev = hid->dev;
777 struct hid_report *report;
778 struct hid_input *hidinput = NULL;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500779 struct input_dev *input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 int i, j, k;
781
782 INIT_LIST_HEAD(&hid->inputs);
783
784 for (i = 0; i < hid->maxcollection; i++)
785 if (hid->collection[i].type == HID_COLLECTION_APPLICATION ||
786 hid->collection[i].type == HID_COLLECTION_PHYSICAL)
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500787 if (IS_INPUT_APPLICATION(hid->collection[i].usage))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 break;
789
790 if (i == hid->maxcollection)
791 return -1;
792
793 for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++)
794 list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
795
796 if (!report->maxfield)
797 continue;
798
799 if (!hidinput) {
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500800 hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL);
801 input_dev = input_allocate_device();
802 if (!hidinput || !input_dev) {
803 kfree(hidinput);
804 input_free_device(input_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 err("Out of memory during hid input probe");
806 return -1;
807 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500809 input_dev->private = hid;
810 input_dev->event = hidinput_input_event;
811 input_dev->open = hidinput_open;
812 input_dev->close = hidinput_close;
813
814 input_dev->name = hid->name;
815 input_dev->phys = hid->phys;
816 input_dev->uniq = hid->uniq;
817 usb_to_input_id(dev, &input_dev->id);
818 input_dev->cdev.dev = &hid->intf->dev;
819
820 hidinput->input = input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 list_add_tail(&hidinput->list, &hid->inputs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 }
823
824 for (i = 0; i < report->maxfield; i++)
825 for (j = 0; j < report->field[i]->maxusage; j++)
826 hidinput_configure_usage(hidinput, report->field[i],
827 report->field[i]->usage + j);
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500828
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 if (hid->quirks & HID_QUIRK_MULTI_INPUT) {
830 /* This will leave hidinput NULL, so that it
831 * allocates another one if we have more inputs on
832 * the same interface. Some devices (e.g. Happ's
833 * UGCI) cram a lot of unrelated inputs into the
834 * same interface. */
835 hidinput->report = report;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500836 input_register_device(hidinput->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 hidinput = NULL;
838 }
839 }
840
841 /* This only gets called when we are a single-input (most of the
842 * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is
843 * only useful in this case, and not for multi-input quirks. */
844 if (hidinput) {
845 hid_ff_init(hid);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500846 input_register_device(hidinput->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 }
848
849 return 0;
850}
851
852void hidinput_disconnect(struct hid_device *hid)
853{
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500854 struct hid_input *hidinput, *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500856 list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 list_del(&hidinput->list);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500858 input_unregister_device(hidinput->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 kfree(hidinput);
860 }
861}