blob: 9e5a80bbd16f16eb479b7b13742dea8d279ed9ea [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
76static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
77 struct hid_usage *usage)
78{
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -050079 struct input_dev *input = hidinput->input;
80 struct hid_device *device = input->private;
Vojtech Pavlik8a409b02005-09-05 00:08:08 -050081 int max = 0, code;
82 unsigned long *bit = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
84 field->hidinput = hidinput;
85
86#ifdef DEBUG
87 printk(KERN_DEBUG "Mapping: ");
88 resolv_usage(usage->hid);
89 printk(" ---> ");
90#endif
91
92 if (field->flags & HID_MAIN_ITEM_CONSTANT)
93 goto ignore;
94
95 switch (usage->hid & HID_USAGE_PAGE) {
96
97 case HID_UP_UNDEFINED:
98 goto ignore;
99
100 case HID_UP_KEYBOARD:
101
102 set_bit(EV_REP, input->evbit);
103
104 if ((usage->hid & HID_USAGE) < 256) {
105 if (!hid_keyboard[usage->hid & HID_USAGE]) goto ignore;
106 map_key_clear(hid_keyboard[usage->hid & HID_USAGE]);
107 } else
108 map_key(KEY_UNKNOWN);
109
110 break;
111
112 case HID_UP_BUTTON:
113
114 code = ((usage->hid - 1) & 0xf);
115
116 switch (field->application) {
117 case HID_GD_MOUSE:
118 case HID_GD_POINTER: code += 0x110; break;
119 case HID_GD_JOYSTICK: code += 0x120; break;
120 case HID_GD_GAMEPAD: code += 0x130; break;
121 default:
122 switch (field->physical) {
123 case HID_GD_MOUSE:
124 case HID_GD_POINTER: code += 0x110; break;
125 case HID_GD_JOYSTICK: code += 0x120; break;
126 case HID_GD_GAMEPAD: code += 0x130; break;
127 default: code += 0x100;
128 }
129 }
130
131 map_key(code);
132 break;
133
Vojtech Pavlik0aebfda2005-09-05 00:07:59 -0500134
135 case HID_UP_SIMULATION:
136
137 switch (usage->hid & 0xffff) {
138 case 0xba: map_abs(ABS_RUDDER); break;
139 case 0xbb: map_abs(ABS_THROTTLE); break;
Dmitry Torokhovff60dde2005-12-17 11:42:54 -0500140 default: goto ignore;
Vojtech Pavlik0aebfda2005-09-05 00:07:59 -0500141 }
142 break;
143
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 case HID_UP_GENDESK:
145
146 if ((usage->hid & 0xf0) == 0x80) { /* SystemControl */
147 switch (usage->hid & 0xf) {
148 case 0x1: map_key_clear(KEY_POWER); break;
149 case 0x2: map_key_clear(KEY_SLEEP); break;
150 case 0x3: map_key_clear(KEY_WAKEUP); break;
151 default: goto unknown;
152 }
153 break;
154 }
155
156 if ((usage->hid & 0xf0) == 0x90) { /* D-pad */
157 switch (usage->hid) {
158 case HID_GD_UP: usage->hat_dir = 1; break;
159 case HID_GD_DOWN: usage->hat_dir = 5; break;
160 case HID_GD_RIGHT: usage->hat_dir = 3; break;
161 case HID_GD_LEFT: usage->hat_dir = 7; break;
162 default: goto unknown;
163 }
164 if (field->dpad) {
165 map_abs(field->dpad);
166 goto ignore;
167 }
168 map_abs(ABS_HAT0X);
169 break;
170 }
171
172 switch (usage->hid) {
173
174 /* These usage IDs map directly to the usage codes. */
175 case HID_GD_X: case HID_GD_Y: case HID_GD_Z:
176 case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
177 case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500178 if (field->flags & HID_MAIN_ITEM_RELATIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 map_rel(usage->hid & 0xf);
180 else
181 map_abs(usage->hid & 0xf);
182 break;
183
184 case HID_GD_HATSWITCH:
185 usage->hat_min = field->logical_minimum;
186 usage->hat_max = field->logical_maximum;
187 map_abs(ABS_HAT0X);
188 break;
189
190 case HID_GD_START: map_key_clear(BTN_START); break;
191 case HID_GD_SELECT: map_key_clear(BTN_SELECT); break;
192
193 default: goto unknown;
194 }
195
196 break;
197
198 case HID_UP_LED:
199 if (((usage->hid - 1) & 0xffff) >= LED_MAX)
200 goto ignore;
201 map_led((usage->hid - 1) & 0xffff);
202 break;
203
204 case HID_UP_DIGITIZER:
205
206 switch (usage->hid & 0xff) {
207
208 case 0x30: /* TipPressure */
209 if (!test_bit(BTN_TOUCH, input->keybit)) {
210 device->quirks |= HID_QUIRK_NOTOUCH;
211 set_bit(EV_KEY, input->evbit);
212 set_bit(BTN_TOUCH, input->keybit);
213 }
214
215 map_abs_clear(ABS_PRESSURE);
216 break;
217
218 case 0x32: /* InRange */
219 switch (field->physical & 0xff) {
220 case 0x21: map_key(BTN_TOOL_MOUSE); break;
221 case 0x22: map_key(BTN_TOOL_FINGER); break;
222 default: map_key(BTN_TOOL_PEN); break;
223 }
224 break;
225
226 case 0x3c: /* Invert */
227 map_key_clear(BTN_TOOL_RUBBER);
228 break;
229
230 case 0x33: /* Touch */
231 case 0x42: /* TipSwitch */
232 case 0x43: /* TipSwitch2 */
233 device->quirks &= ~HID_QUIRK_NOTOUCH;
234 map_key_clear(BTN_TOUCH);
235 break;
236
237 case 0x44: /* BarrelSwitch */
238 map_key_clear(BTN_STYLUS);
239 break;
240
241 default: goto unknown;
242 }
243 break;
244
245 case HID_UP_CONSUMER: /* USB HUT v1.1, pages 56-62 */
246
247 switch (usage->hid & HID_USAGE) {
248 case 0x000: goto ignore;
249 case 0x034: map_key_clear(KEY_SLEEP); break;
250 case 0x036: map_key_clear(BTN_MISC); break;
Micah F. Galizia39fd7482005-09-05 00:12:15 -0500251 case 0x045: map_key_clear(KEY_RADIO); break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 case 0x08a: map_key_clear(KEY_WWW); break;
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500253 case 0x08d: map_key_clear(KEY_PROGRAM); break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 case 0x095: map_key_clear(KEY_HELP); break;
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500255 case 0x09c: map_key_clear(KEY_CHANNELUP); break;
256 case 0x09d: map_key_clear(KEY_CHANNELDOWN); break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 case 0x0b0: map_key_clear(KEY_PLAY); break;
258 case 0x0b1: map_key_clear(KEY_PAUSE); break;
259 case 0x0b2: map_key_clear(KEY_RECORD); break;
260 case 0x0b3: map_key_clear(KEY_FASTFORWARD); break;
261 case 0x0b4: map_key_clear(KEY_REWIND); break;
262 case 0x0b5: map_key_clear(KEY_NEXTSONG); break;
263 case 0x0b6: map_key_clear(KEY_PREVIOUSSONG); break;
264 case 0x0b7: map_key_clear(KEY_STOPCD); break;
265 case 0x0b8: map_key_clear(KEY_EJECTCD); break;
266 case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break;
267 case 0x0e0: map_abs_clear(ABS_VOLUME); break;
268 case 0x0e2: map_key_clear(KEY_MUTE); break;
269 case 0x0e5: map_key_clear(KEY_BASSBOOST); break;
270 case 0x0e9: map_key_clear(KEY_VOLUMEUP); break;
271 case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break;
272 case 0x183: map_key_clear(KEY_CONFIG); break;
273 case 0x18a: map_key_clear(KEY_MAIL); break;
274 case 0x192: map_key_clear(KEY_CALC); break;
275 case 0x194: map_key_clear(KEY_FILE); break;
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500276 case 0x1a7: map_key_clear(KEY_DOCUMENTS); break;
277 case 0x201: map_key_clear(KEY_NEW); break;
278 case 0x207: map_key_clear(KEY_SAVE); break;
279 case 0x208: map_key_clear(KEY_PRINT); break;
280 case 0x209: map_key_clear(KEY_PROPS); break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 case 0x21a: map_key_clear(KEY_UNDO); break;
282 case 0x21b: map_key_clear(KEY_COPY); break;
283 case 0x21c: map_key_clear(KEY_CUT); break;
284 case 0x21d: map_key_clear(KEY_PASTE); break;
285 case 0x221: map_key_clear(KEY_FIND); break;
286 case 0x223: map_key_clear(KEY_HOMEPAGE); break;
287 case 0x224: map_key_clear(KEY_BACK); break;
288 case 0x225: map_key_clear(KEY_FORWARD); break;
289 case 0x226: map_key_clear(KEY_STOP); break;
290 case 0x227: map_key_clear(KEY_REFRESH); break;
291 case 0x22a: map_key_clear(KEY_BOOKMARKS); break;
Vojtech Pavlik940824b2006-01-14 00:25:39 -0500292 case 0x233: map_key_clear(KEY_SCROLLUP); break;
293 case 0x234: map_key_clear(KEY_SCROLLDOWN); break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 case 0x238: map_rel(REL_HWHEEL); break;
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500295 case 0x279: map_key_clear(KEY_REDO); break;
296 case 0x289: map_key_clear(KEY_REPLY); break;
297 case 0x28b: map_key_clear(KEY_FORWARDMAIL); break;
298 case 0x28c: map_key_clear(KEY_SEND); break;
Vojtech Pavlik940824b2006-01-14 00:25:39 -0500299
300 /* Reported on a Cherry Cymotion keyboard */
301 case 0x301: map_key_clear(KEY_PROG1); break;
302 case 0x302: map_key_clear(KEY_PROG2); break;
303 case 0x303: map_key_clear(KEY_PROG3); break;
304
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500305 default: goto ignore;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 }
307 break;
308
309 case HID_UP_HPVENDOR: /* Reported on a Dutch layout HP5308 */
310
311 set_bit(EV_REP, input->evbit);
312 switch (usage->hid & HID_USAGE) {
313 case 0x021: map_key_clear(KEY_PRINT); break;
314 case 0x070: map_key_clear(KEY_HP); break;
315 case 0x071: map_key_clear(KEY_CAMERA); break;
316 case 0x072: map_key_clear(KEY_SOUND); break;
317 case 0x073: map_key_clear(KEY_QUESTION); break;
318 case 0x080: map_key_clear(KEY_EMAIL); break;
319 case 0x081: map_key_clear(KEY_CHAT); break;
320 case 0x082: map_key_clear(KEY_SEARCH); break;
321 case 0x083: map_key_clear(KEY_CONNECT); break;
322 case 0x084: map_key_clear(KEY_FINANCE); break;
323 case 0x085: map_key_clear(KEY_SPORT); break;
324 case 0x086: map_key_clear(KEY_SHOP); break;
325 default: goto ignore;
326 }
327 break;
328
329 case HID_UP_MSVENDOR:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 goto ignore;
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500331
Stelian Pope875ce32005-09-05 01:57:33 -0500332 case HID_UP_CUSTOM: /* Reported on Logitech and Powerbook USB keyboards */
333
334 set_bit(EV_REP, input->evbit);
335 switch(usage->hid & HID_USAGE) {
336 case 0x003: map_key_clear(KEY_FN); break;
337 default: goto ignore;
338 }
339 break;
340
341 case HID_UP_LOGIVENDOR: /* Reported on Logitech Ultra X Media Remote */
Micah F. Galizia39fd7482005-09-05 00:12:15 -0500342
343 set_bit(EV_REP, input->evbit);
344 switch(usage->hid & HID_USAGE) {
345 case 0x004: map_key_clear(KEY_AGAIN); break;
346 case 0x00d: map_key_clear(KEY_HOME); break;
347 case 0x024: map_key_clear(KEY_SHUFFLE); break;
348 case 0x025: map_key_clear(KEY_TV); break;
349 case 0x026: map_key_clear(KEY_MENU); break;
350 case 0x031: map_key_clear(KEY_AUDIO); break;
351 case 0x032: map_key_clear(KEY_SUBTITLE); break;
352 case 0x033: map_key_clear(KEY_LAST); break;
353 case 0x047: map_key_clear(KEY_MP3); break;
354 case 0x048: map_key_clear(KEY_DVD); break;
355 case 0x049: map_key_clear(KEY_MEDIA); break;
356 case 0x04a: map_key_clear(KEY_VIDEO); break;
357 case 0x04b: map_key_clear(KEY_ANGLE); break;
358 case 0x04c: map_key_clear(KEY_LANGUAGE); break;
359 case 0x04d: map_key_clear(KEY_SUBTITLE); break;
360 case 0x051: map_key_clear(KEY_RED); break;
361 case 0x052: map_key_clear(KEY_CLOSE); break;
362 default: goto ignore;
363 }
364 break;
365
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 case HID_UP_PID:
367
368 set_bit(EV_FF, input->evbit);
369 switch(usage->hid & HID_USAGE) {
370 case 0x26: map_ff_effect(FF_CONSTANT); goto ignore;
371 case 0x27: map_ff_effect(FF_RAMP); goto ignore;
372 case 0x28: map_ff_effect(FF_CUSTOM); goto ignore;
373 case 0x30: map_ff_effect(FF_SQUARE); map_ff_effect(FF_PERIODIC); goto ignore;
374 case 0x31: map_ff_effect(FF_SINE); map_ff_effect(FF_PERIODIC); goto ignore;
375 case 0x32: map_ff_effect(FF_TRIANGLE); map_ff_effect(FF_PERIODIC); goto ignore;
376 case 0x33: map_ff_effect(FF_SAW_UP); map_ff_effect(FF_PERIODIC); goto ignore;
377 case 0x34: map_ff_effect(FF_SAW_DOWN); map_ff_effect(FF_PERIODIC); goto ignore;
378 case 0x40: map_ff_effect(FF_SPRING); goto ignore;
379 case 0x41: map_ff_effect(FF_DAMPER); goto ignore;
380 case 0x42: map_ff_effect(FF_INERTIA); goto ignore;
381 case 0x43: map_ff_effect(FF_FRICTION); goto ignore;
382 case 0x7e: map_ff(FF_GAIN); break;
383 case 0x83: input->ff_effects_max = field->value[0]; goto ignore;
384 case 0x98: map_ff(FF_AUTOCENTER); break;
385 case 0xa4: map_key_clear(BTN_DEAD); break;
386 default: goto ignore;
387 }
388 break;
389
390 default:
391 unknown:
392 if (field->report_size == 1) {
393 if (field->report->type == HID_OUTPUT_REPORT) {
394 map_led(LED_MISC);
395 break;
396 }
397 map_key(BTN_MISC);
398 break;
399 }
400 if (field->flags & HID_MAIN_ITEM_RELATIVE) {
401 map_rel(REL_MISC);
402 break;
403 }
404 map_abs(ABS_MISC);
405 break;
406 }
407
408 set_bit(usage->type, input->evbit);
409
410 while (usage->code <= max && test_and_set_bit(usage->code, bit))
411 usage->code = find_next_zero_bit(bit, max + 1, usage->code);
412
413 if (usage->code > max)
414 goto ignore;
415
Vojtech Pavlikc58de6d2005-09-05 00:13:15 -0500416 if (((device->quirks & (HID_QUIRK_2WHEEL_POWERMOUSE)) && (usage->hid == 0x00010032)))
417 map_rel(REL_HWHEEL);
418
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) &&
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500420 (usage->type == EV_REL) && (usage->code == REL_WHEEL))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 set_bit(REL_HWHEEL, bit);
422
423 if (((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
424 || ((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007)))
425 goto ignore;
426
427 if (usage->type == EV_ABS) {
428
429 int a = field->logical_minimum;
430 int b = field->logical_maximum;
431
432 if ((device->quirks & HID_QUIRK_BADPAD) && (usage->code == ABS_X || usage->code == ABS_Y)) {
433 a = field->logical_minimum = 0;
434 b = field->logical_maximum = 255;
435 }
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500436
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 if (field->application == HID_GD_GAMEPAD || field->application == HID_GD_JOYSTICK)
438 input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4);
439 else input_set_abs_params(input, usage->code, a, b, 0, 0);
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500440
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 }
442
443 if (usage->hat_min < usage->hat_max || usage->hat_dir) {
444 int i;
445 for (i = usage->code; i < usage->code + 2 && i <= max; i++) {
446 input_set_abs_params(input, i, -1, 1, 0, 0);
447 set_bit(i, input->absbit);
448 }
449 if (usage->hat_dir && !field->dpad)
450 field->dpad = usage->code;
451 }
452
453#ifdef DEBUG
454 resolv_event(usage->type, usage->code);
455 printk("\n");
456#endif
457 return;
458
459ignore:
460#ifdef DEBUG
461 printk("IGNORED\n");
462#endif
463 return;
464}
465
466void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, struct pt_regs *regs)
467{
Pete Zaitceva9b2e912005-07-29 12:18:34 -0700468 struct input_dev *input;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 int *quirks = &hid->quirks;
470
Pete Zaitceva9b2e912005-07-29 12:18:34 -0700471 if (!field->hidinput)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 return;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500473
474 input = field->hidinput->input;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475
476 input_regs(input, regs);
477
478 if (!usage->type)
479 return;
480
481 if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
482 || ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) {
483 if (value) hid->quirks |= HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
484 else hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
485 return;
486 }
487
488 if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) {
489 input_event(input, usage->type, REL_HWHEEL, value);
490 return;
491 }
492
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500493 if (usage->hat_min < usage->hat_max || usage->hat_dir) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 int hat_dir = usage->hat_dir;
495 if (!hat_dir)
496 hat_dir = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1;
497 if (hat_dir < 0 || hat_dir > 8) hat_dir = 0;
498 input_event(input, usage->type, usage->code , hid_hat_to_axis[hat_dir].x);
499 input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[hat_dir].y);
500 return;
501 }
502
503 if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */
504 *quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT);
505 return;
506 }
507
508 if (usage->hid == (HID_UP_DIGITIZER | 0x0032)) { /* InRange */
509 if (value) {
510 input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1);
511 return;
512 }
513 input_event(input, usage->type, usage->code, 0);
514 input_event(input, usage->type, BTN_TOOL_RUBBER, 0);
515 return;
516 }
517
518 if (usage->hid == (HID_UP_DIGITIZER | 0x0030) && (*quirks & HID_QUIRK_NOTOUCH)) { /* Pressure */
519 int a = field->logical_minimum;
520 int b = field->logical_maximum;
521 input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3));
522 }
523
524 if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */
525 input->ff_effects_max = value;
526 dbg("Maximum Effects - %d",input->ff_effects_max);
527 return;
528 }
529
530 if (usage->hid == (HID_UP_PID | 0x7fUL)) {
531 dbg("PID Pool Report\n");
532 return;
533 }
534
535 if((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
536 return;
537
538 input_event(input, usage->type, usage->code, value);
539
540 if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY))
541 input_event(input, usage->type, usage->code, 0);
542}
543
544void hidinput_report_event(struct hid_device *hid, struct hid_report *report)
545{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 struct hid_input *hidinput;
547
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500548 list_for_each_entry(hidinput, &hid->inputs, list)
549 input_sync(hidinput->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550}
551
552static int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field)
553{
554 struct hid_report *report;
555 int i, j;
556
557 list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) {
558 for (i = 0; i < report->maxfield; i++) {
559 *field = report->field[i];
560 for (j = 0; j < (*field)->maxusage; j++)
561 if ((*field)->usage[j].type == type && (*field)->usage[j].code == code)
562 return j;
563 }
564 }
565 return -1;
566}
567
568static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
569{
570 struct hid_device *hid = dev->private;
571 struct hid_field *field;
572 int offset;
573
574 if (type == EV_FF)
575 return hid_ff_event(hid, dev, type, code, value);
576
577 if (type != EV_LED)
578 return -1;
579
580 if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
581 warn("event field not found");
582 return -1;
583 }
584
585 hid_set_field(field, offset, value);
586 hid_submit_report(hid, field->report, USB_DIR_OUT);
587
588 return 0;
589}
590
591static int hidinput_open(struct input_dev *dev)
592{
593 struct hid_device *hid = dev->private;
594 return hid_open(hid);
595}
596
597static void hidinput_close(struct input_dev *dev)
598{
599 struct hid_device *hid = dev->private;
600 hid_close(hid);
601}
602
603/*
604 * Register the input device; print a message.
605 * Configure the input layer interface
606 * Read all reports and initialize the absolute field values.
607 */
608
609int hidinput_connect(struct hid_device *hid)
610{
611 struct usb_device *dev = hid->dev;
612 struct hid_report *report;
613 struct hid_input *hidinput = NULL;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500614 struct input_dev *input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 int i, j, k;
616
617 INIT_LIST_HEAD(&hid->inputs);
618
619 for (i = 0; i < hid->maxcollection; i++)
620 if (hid->collection[i].type == HID_COLLECTION_APPLICATION ||
621 hid->collection[i].type == HID_COLLECTION_PHYSICAL)
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500622 if (IS_INPUT_APPLICATION(hid->collection[i].usage))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 break;
624
625 if (i == hid->maxcollection)
626 return -1;
627
628 for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++)
629 list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
630
631 if (!report->maxfield)
632 continue;
633
634 if (!hidinput) {
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500635 hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL);
636 input_dev = input_allocate_device();
637 if (!hidinput || !input_dev) {
638 kfree(hidinput);
639 input_free_device(input_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 err("Out of memory during hid input probe");
641 return -1;
642 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500644 input_dev->private = hid;
645 input_dev->event = hidinput_input_event;
646 input_dev->open = hidinput_open;
647 input_dev->close = hidinput_close;
648
649 input_dev->name = hid->name;
650 input_dev->phys = hid->phys;
651 input_dev->uniq = hid->uniq;
652 usb_to_input_id(dev, &input_dev->id);
653 input_dev->cdev.dev = &hid->intf->dev;
654
655 hidinput->input = input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 list_add_tail(&hidinput->list, &hid->inputs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 }
658
659 for (i = 0; i < report->maxfield; i++)
660 for (j = 0; j < report->field[i]->maxusage; j++)
661 hidinput_configure_usage(hidinput, report->field[i],
662 report->field[i]->usage + j);
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500663
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 if (hid->quirks & HID_QUIRK_MULTI_INPUT) {
665 /* This will leave hidinput NULL, so that it
666 * allocates another one if we have more inputs on
667 * the same interface. Some devices (e.g. Happ's
668 * UGCI) cram a lot of unrelated inputs into the
669 * same interface. */
670 hidinput->report = report;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500671 input_register_device(hidinput->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 hidinput = NULL;
673 }
674 }
675
676 /* This only gets called when we are a single-input (most of the
677 * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is
678 * only useful in this case, and not for multi-input quirks. */
679 if (hidinput) {
680 hid_ff_init(hid);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500681 input_register_device(hidinput->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 }
683
684 return 0;
685}
686
687void hidinput_disconnect(struct hid_device *hid)
688{
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500689 struct hid_input *hidinput, *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500691 list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 list_del(&hidinput->list);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500693 input_unregister_device(hidinput->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 kfree(hidinput);
695 }
696}