HID: uclogic: add proper support for PF1209
[profile/ivi/kernel-x86-ivi.git] / drivers / hid / hid-lg.c
1 /*
2  *  HID driver for some logitech "special" devices
3  *
4  *  Copyright (c) 1999 Andreas Gal
5  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
6  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
7  *  Copyright (c) 2006-2007 Jiri Kosina
8  *  Copyright (c) 2007 Paul Walmsley
9  *  Copyright (c) 2008 Jiri Slaby
10  */
11
12 /*
13  * This program is free software; you can redistribute it and/or modify it
14  * under the terms of the GNU General Public License as published by the Free
15  * Software Foundation; either version 2 of the License, or (at your option)
16  * any later version.
17  */
18
19 #include <linux/device.h>
20 #include <linux/hid.h>
21 #include <linux/module.h>
22
23 #include "hid-ids.h"
24 #include "hid-lg.h"
25
26 #define LG_RDESC                0x001
27 #define LG_BAD_RELATIVE_KEYS    0x002
28 #define LG_DUPLICATE_USAGES     0x004
29 #define LG_EXPANDED_KEYMAP      0x010
30 #define LG_IGNORE_DOUBLED_WHEEL 0x020
31 #define LG_WIRELESS             0x040
32 #define LG_INVERT_HWHEEL        0x080
33 #define LG_NOGET                0x100
34 #define LG_FF                   0x200
35 #define LG_FF2                  0x400
36 #define LG_RDESC_REL_ABS        0x800
37 #define LG_FF3                  0x1000
38
39 /*
40  * Certain Logitech keyboards send in report #3 keys which are far
41  * above the logical maximum described in descriptor. This extends
42  * the original value of 0x28c of logical maximum to 0x104d
43  */
44 static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
45                 unsigned int *rsize)
46 {
47         unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
48
49         if ((quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
50                         rdesc[84] == 0x8c && rdesc[85] == 0x02) {
51                 dev_info(&hdev->dev, "fixing up Logitech keyboard report "
52                                 "descriptor\n");
53                 rdesc[84] = rdesc[89] = 0x4d;
54                 rdesc[85] = rdesc[90] = 0x10;
55         }
56         if ((quirks & LG_RDESC_REL_ABS) && *rsize >= 50 &&
57                         rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
58                         rdesc[49] == 0x81 && rdesc[50] == 0x06) {
59                 dev_info(&hdev->dev, "fixing up rel/abs in Logitech "
60                                 "report descriptor\n");
61                 rdesc[33] = rdesc[50] = 0x02;
62         }
63         return rdesc;
64 }
65
66 #define lg_map_key_clear(c)     hid_map_usage_clear(hi, usage, bit, max, \
67                 EV_KEY, (c))
68
69 static int lg_ultrax_remote_mapping(struct hid_input *hi,
70                 struct hid_usage *usage, unsigned long **bit, int *max)
71 {
72         if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
73                 return 0;
74
75         set_bit(EV_REP, hi->input->evbit);
76         switch (usage->hid & HID_USAGE) {
77         /* Reported on Logitech Ultra X Media Remote */
78         case 0x004: lg_map_key_clear(KEY_AGAIN);        break;
79         case 0x00d: lg_map_key_clear(KEY_HOME);         break;
80         case 0x024: lg_map_key_clear(KEY_SHUFFLE);      break;
81         case 0x025: lg_map_key_clear(KEY_TV);           break;
82         case 0x026: lg_map_key_clear(KEY_MENU);         break;
83         case 0x031: lg_map_key_clear(KEY_AUDIO);        break;
84         case 0x032: lg_map_key_clear(KEY_TEXT);         break;
85         case 0x033: lg_map_key_clear(KEY_LAST);         break;
86         case 0x047: lg_map_key_clear(KEY_MP3);          break;
87         case 0x048: lg_map_key_clear(KEY_DVD);          break;
88         case 0x049: lg_map_key_clear(KEY_MEDIA);        break;
89         case 0x04a: lg_map_key_clear(KEY_VIDEO);        break;
90         case 0x04b: lg_map_key_clear(KEY_ANGLE);        break;
91         case 0x04c: lg_map_key_clear(KEY_LANGUAGE);     break;
92         case 0x04d: lg_map_key_clear(KEY_SUBTITLE);     break;
93         case 0x051: lg_map_key_clear(KEY_RED);          break;
94         case 0x052: lg_map_key_clear(KEY_CLOSE);        break;
95
96         default:
97                 return 0;
98         }
99         return 1;
100 }
101
102 static int lg_dinovo_mapping(struct hid_input *hi, struct hid_usage *usage,
103                 unsigned long **bit, int *max)
104 {
105         if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
106                 return 0;
107
108         switch (usage->hid & HID_USAGE) {
109
110         case 0x00d: lg_map_key_clear(KEY_MEDIA);        break;
111         default:
112                 return 0;
113
114         }
115         return 1;
116 }
117
118 static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
119                 unsigned long **bit, int *max)
120 {
121         if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
122                 return 0;
123
124         switch (usage->hid & HID_USAGE) {
125         case 0x1001: lg_map_key_clear(KEY_MESSENGER);           break;
126         case 0x1003: lg_map_key_clear(KEY_SOUND);               break;
127         case 0x1004: lg_map_key_clear(KEY_VIDEO);               break;
128         case 0x1005: lg_map_key_clear(KEY_AUDIO);               break;
129         case 0x100a: lg_map_key_clear(KEY_DOCUMENTS);           break;
130         /* The following two entries are Playlist 1 and 2 on the MX3200 */
131         case 0x100f: lg_map_key_clear(KEY_FN_1);                break;
132         case 0x1010: lg_map_key_clear(KEY_FN_2);                break;
133         case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG);        break;
134         case 0x1012: lg_map_key_clear(KEY_NEXTSONG);            break;
135         case 0x1013: lg_map_key_clear(KEY_CAMERA);              break;
136         case 0x1014: lg_map_key_clear(KEY_MESSENGER);           break;
137         case 0x1015: lg_map_key_clear(KEY_RECORD);              break;
138         case 0x1016: lg_map_key_clear(KEY_PLAYER);              break;
139         case 0x1017: lg_map_key_clear(KEY_EJECTCD);             break;
140         case 0x1018: lg_map_key_clear(KEY_MEDIA);               break;
141         case 0x1019: lg_map_key_clear(KEY_PROG1);               break;
142         case 0x101a: lg_map_key_clear(KEY_PROG2);               break;
143         case 0x101b: lg_map_key_clear(KEY_PROG3);               break;
144         case 0x101c: lg_map_key_clear(KEY_CYCLEWINDOWS);        break;
145         case 0x101f: lg_map_key_clear(KEY_ZOOMIN);              break;
146         case 0x1020: lg_map_key_clear(KEY_ZOOMOUT);             break;
147         case 0x1021: lg_map_key_clear(KEY_ZOOMRESET);           break;
148         case 0x1023: lg_map_key_clear(KEY_CLOSE);               break;
149         case 0x1027: lg_map_key_clear(KEY_MENU);                break;
150         /* this one is marked as 'Rotate' */
151         case 0x1028: lg_map_key_clear(KEY_ANGLE);               break;
152         case 0x1029: lg_map_key_clear(KEY_SHUFFLE);             break;
153         case 0x102a: lg_map_key_clear(KEY_BACK);                break;
154         case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS);        break;
155         case 0x102d: lg_map_key_clear(KEY_WWW);                 break;
156         /* The following two are 'Start/answer call' and 'End/reject call'
157            on the MX3200 */
158         case 0x1031: lg_map_key_clear(KEY_OK);                  break;
159         case 0x1032: lg_map_key_clear(KEY_CANCEL);              break;
160         case 0x1041: lg_map_key_clear(KEY_BATTERY);             break;
161         case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR);       break;
162         case 0x1043: lg_map_key_clear(KEY_SPREADSHEET);         break;
163         case 0x1044: lg_map_key_clear(KEY_PRESENTATION);        break;
164         case 0x1045: lg_map_key_clear(KEY_UNDO);                break;
165         case 0x1046: lg_map_key_clear(KEY_REDO);                break;
166         case 0x1047: lg_map_key_clear(KEY_PRINT);               break;
167         case 0x1048: lg_map_key_clear(KEY_SAVE);                break;
168         case 0x1049: lg_map_key_clear(KEY_PROG1);               break;
169         case 0x104a: lg_map_key_clear(KEY_PROG2);               break;
170         case 0x104b: lg_map_key_clear(KEY_PROG3);               break;
171         case 0x104c: lg_map_key_clear(KEY_PROG4);               break;
172
173         default:
174                 return 0;
175         }
176         return 1;
177 }
178
179 static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
180                 struct hid_field *field, struct hid_usage *usage,
181                 unsigned long **bit, int *max)
182 {
183         /* extended mapping for certain Logitech hardware (Logitech cordless
184            desktop LX500) */
185         static const u8 e_keymap[] = {
186                   0,216,  0,213,175,156,  0,  0,  0,  0,
187                 144,  0,  0,  0,  0,  0,  0,  0,  0,212,
188                 174,167,152,161,112,  0,  0,  0,154,  0,
189                   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
190                   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
191                   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
192                   0,  0,  0,  0,  0,183,184,185,186,187,
193                 188,189,190,191,192,193,194,  0,  0,  0
194         };
195         unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
196         unsigned int hid = usage->hid;
197
198         if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
199                         lg_ultrax_remote_mapping(hi, usage, bit, max))
200                 return 1;
201
202         if (hdev->product == USB_DEVICE_ID_DINOVO_MINI &&
203                         lg_dinovo_mapping(hi, usage, bit, max))
204                 return 1;
205
206         if ((quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
207                 return 1;
208
209         if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
210                 return 0;
211
212         hid &= HID_USAGE;
213
214         /* Special handling for Logitech Cordless Desktop */
215         if (field->application == HID_GD_MOUSE) {
216                 if ((quirks & LG_IGNORE_DOUBLED_WHEEL) &&
217                                 (hid == 7 || hid == 8))
218                         return -1;
219         } else {
220                 if ((quirks & LG_EXPANDED_KEYMAP) &&
221                                 hid < ARRAY_SIZE(e_keymap) &&
222                                 e_keymap[hid] != 0) {
223                         hid_map_usage(hi, usage, bit, max, EV_KEY,
224                                         e_keymap[hid]);
225                         return 1;
226                 }
227         }
228
229         return 0;
230 }
231
232 static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
233                 struct hid_field *field, struct hid_usage *usage,
234                 unsigned long **bit, int *max)
235 {
236         unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
237
238         if ((quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
239                         (field->flags & HID_MAIN_ITEM_RELATIVE))
240                 field->flags &= ~HID_MAIN_ITEM_RELATIVE;
241
242         if ((quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
243                          usage->type == EV_REL || usage->type == EV_ABS))
244                 clear_bit(usage->code, *bit);
245
246         return 0;
247 }
248
249 static int lg_event(struct hid_device *hdev, struct hid_field *field,
250                 struct hid_usage *usage, __s32 value)
251 {
252         unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
253
254         if ((quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
255                 input_event(field->hidinput->input, usage->type, usage->code,
256                                 -value);
257                 return 1;
258         }
259
260         return 0;
261 }
262
263 static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
264 {
265         unsigned long quirks = id->driver_data;
266         unsigned int connect_mask = HID_CONNECT_DEFAULT;
267         int ret;
268
269         hid_set_drvdata(hdev, (void *)quirks);
270
271         if (quirks & LG_NOGET)
272                 hdev->quirks |= HID_QUIRK_NOGET;
273
274         ret = hid_parse(hdev);
275         if (ret) {
276                 dev_err(&hdev->dev, "parse failed\n");
277                 goto err_free;
278         }
279
280         if (quirks & (LG_FF | LG_FF2 | LG_FF3))
281                 connect_mask &= ~HID_CONNECT_FF;
282
283         ret = hid_hw_start(hdev, connect_mask);
284         if (ret) {
285                 dev_err(&hdev->dev, "hw start failed\n");
286                 goto err_free;
287         }
288
289         if (quirks & LG_FF)
290                 lgff_init(hdev);
291         if (quirks & LG_FF2)
292                 lg2ff_init(hdev);
293         if (quirks & LG_FF3)
294                 lg3ff_init(hdev);
295
296         return 0;
297 err_free:
298         return ret;
299 }
300
301 static const struct hid_device_id lg_devices[] = {
302         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
303                 .driver_data = LG_RDESC | LG_WIRELESS },
304         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
305                 .driver_data = LG_RDESC | LG_WIRELESS },
306         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2),
307                 .driver_data = LG_RDESC | LG_WIRELESS },
308
309         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER),
310                 .driver_data = LG_BAD_RELATIVE_KEYS },
311
312         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP),
313                 .driver_data = LG_DUPLICATE_USAGES },
314         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE),
315                 .driver_data = LG_DUPLICATE_USAGES },
316         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI),
317                 .driver_data = LG_DUPLICATE_USAGES },
318
319         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
320                 .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
321         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500),
322                 .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
323
324         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
325                 .driver_data = LG_NOGET },
326         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
327                 .driver_data = LG_NOGET | LG_FF },
328
329         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
330                 .driver_data = LG_FF },
331         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
332                 .driver_data = LG_FF },
333         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D),
334                 .driver_data = LG_FF },
335         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
336                 .driver_data = LG_FF },
337         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
338                 .driver_data = LG_FF },
339         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
340                 .driver_data = LG_FF },
341         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
342                 .driver_data = LG_FF },
343         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ),
344                 .driver_data = LG_FF },
345         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
346                 .driver_data = LG_FF2 },
347         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940),
348                 .driver_data = LG_FF3 },
349         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR),
350                 .driver_data = LG_RDESC_REL_ABS },
351         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER),
352                 .driver_data = LG_RDESC_REL_ABS },
353         { }
354 };
355
356 MODULE_DEVICE_TABLE(hid, lg_devices);
357
358 static struct hid_driver lg_driver = {
359         .name = "logitech",
360         .id_table = lg_devices,
361         .report_fixup = lg_report_fixup,
362         .input_mapping = lg_input_mapping,
363         .input_mapped = lg_input_mapped,
364         .event = lg_event,
365         .probe = lg_probe,
366 };
367
368 static int __init lg_init(void)
369 {
370         return hid_register_driver(&lg_driver);
371 }
372
373 static void __exit lg_exit(void)
374 {
375         hid_unregister_driver(&lg_driver);
376 }
377
378 module_init(lg_init);
379 module_exit(lg_exit);
380 MODULE_LICENSE("GPL");