HID: move logitech FF processing
[safe/jmp/linux-2.6] / 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_RESET_LEDS           0x008
30 #define LG_EXPANDED_KEYMAP      0x010
31 #define LG_IGNORE_DOUBLED_WHEEL 0x020
32 #define LG_WIRELESS             0x040
33 #define LG_INVERT_HWHEEL        0x080
34 #define LG_NOGET                0x100
35 #define LG_FF                   0x200
36 #define LG_FF2                  0x400
37
38 /*
39  * Certain Logitech keyboards send in report #3 keys which are far
40  * above the logical maximum described in descriptor. This extends
41  * the original value of 0x28c of logical maximum to 0x104d
42  */
43 static void lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
44                 unsigned int rsize)
45 {
46         unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
47
48         if ((quirks & LG_RDESC) && rsize >= 90 && rdesc[83] == 0x26 &&
49                         rdesc[84] == 0x8c && rdesc[85] == 0x02) {
50                 dev_info(&hdev->dev, "fixing up Logitech keyboard report "
51                                 "descriptor\n");
52                 rdesc[84] = rdesc[89] = 0x4d;
53                 rdesc[85] = rdesc[90] = 0x10;
54         }
55 }
56
57 #define lg_map_key_clear(c)     hid_map_usage_clear(hi, usage, bit, max, \
58                 EV_KEY, (c))
59
60 static int lg_ultrax_remote_mapping(struct hid_input *hi,
61                 struct hid_usage *usage, unsigned long **bit, int *max)
62 {
63         if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
64                 return 0;
65
66         set_bit(EV_REP, hi->input->evbit);
67         switch (usage->hid & HID_USAGE) {
68         /* Reported on Logitech Ultra X Media Remote */
69         case 0x004: lg_map_key_clear(KEY_AGAIN);        break;
70         case 0x00d: lg_map_key_clear(KEY_HOME);         break;
71         case 0x024: lg_map_key_clear(KEY_SHUFFLE);      break;
72         case 0x025: lg_map_key_clear(KEY_TV);           break;
73         case 0x026: lg_map_key_clear(KEY_MENU);         break;
74         case 0x031: lg_map_key_clear(KEY_AUDIO);        break;
75         case 0x032: lg_map_key_clear(KEY_TEXT);         break;
76         case 0x033: lg_map_key_clear(KEY_LAST);         break;
77         case 0x047: lg_map_key_clear(KEY_MP3);          break;
78         case 0x048: lg_map_key_clear(KEY_DVD);          break;
79         case 0x049: lg_map_key_clear(KEY_MEDIA);        break;
80         case 0x04a: lg_map_key_clear(KEY_VIDEO);        break;
81         case 0x04b: lg_map_key_clear(KEY_ANGLE);        break;
82         case 0x04c: lg_map_key_clear(KEY_LANGUAGE);     break;
83         case 0x04d: lg_map_key_clear(KEY_SUBTITLE);     break;
84         case 0x051: lg_map_key_clear(KEY_RED);          break;
85         case 0x052: lg_map_key_clear(KEY_CLOSE);        break;
86
87         default:
88                 return 0;
89         }
90         return 1;
91 }
92
93 static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
94                 unsigned long **bit, int *max)
95 {
96         if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
97                 return 0;
98
99         switch (usage->hid & HID_USAGE) {
100         case 0x1001: lg_map_key_clear(KEY_MESSENGER);           break;
101         case 0x1003: lg_map_key_clear(KEY_SOUND);               break;
102         case 0x1004: lg_map_key_clear(KEY_VIDEO);               break;
103         case 0x1005: lg_map_key_clear(KEY_AUDIO);               break;
104         case 0x100a: lg_map_key_clear(KEY_DOCUMENTS);           break;
105         case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG);        break;
106         case 0x1012: lg_map_key_clear(KEY_NEXTSONG);            break;
107         case 0x1013: lg_map_key_clear(KEY_CAMERA);              break;
108         case 0x1014: lg_map_key_clear(KEY_MESSENGER);           break;
109         case 0x1015: lg_map_key_clear(KEY_RECORD);              break;
110         case 0x1016: lg_map_key_clear(KEY_PLAYER);              break;
111         case 0x1017: lg_map_key_clear(KEY_EJECTCD);             break;
112         case 0x1018: lg_map_key_clear(KEY_MEDIA);               break;
113         case 0x1019: lg_map_key_clear(KEY_PROG1);               break;
114         case 0x101a: lg_map_key_clear(KEY_PROG2);               break;
115         case 0x101b: lg_map_key_clear(KEY_PROG3);               break;
116         case 0x101f: lg_map_key_clear(KEY_ZOOMIN);              break;
117         case 0x1020: lg_map_key_clear(KEY_ZOOMOUT);             break;
118         case 0x1021: lg_map_key_clear(KEY_ZOOMRESET);           break;
119         case 0x1023: lg_map_key_clear(KEY_CLOSE);               break;
120         case 0x1027: lg_map_key_clear(KEY_MENU);                break;
121         /* this one is marked as 'Rotate' */
122         case 0x1028: lg_map_key_clear(KEY_ANGLE);               break;
123         case 0x1029: lg_map_key_clear(KEY_SHUFFLE);             break;
124         case 0x102a: lg_map_key_clear(KEY_BACK);                break;
125         case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS);        break;
126         case 0x1041: lg_map_key_clear(KEY_BATTERY);             break;
127         case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR);       break;
128         case 0x1043: lg_map_key_clear(KEY_SPREADSHEET);         break;
129         case 0x1044: lg_map_key_clear(KEY_PRESENTATION);        break;
130         case 0x1045: lg_map_key_clear(KEY_UNDO);                break;
131         case 0x1046: lg_map_key_clear(KEY_REDO);                break;
132         case 0x1047: lg_map_key_clear(KEY_PRINT);               break;
133         case 0x1048: lg_map_key_clear(KEY_SAVE);                break;
134         case 0x1049: lg_map_key_clear(KEY_PROG1);               break;
135         case 0x104a: lg_map_key_clear(KEY_PROG2);               break;
136         case 0x104b: lg_map_key_clear(KEY_PROG3);               break;
137         case 0x104c: lg_map_key_clear(KEY_PROG4);               break;
138
139         default:
140                 return 0;
141         }
142         return 1;
143 }
144
145 static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
146                 struct hid_field *field, struct hid_usage *usage,
147                 unsigned long **bit, int *max)
148 {
149         /* extended mapping for certain Logitech hardware (Logitech cordless
150            desktop LX500) */
151         static const u8 e_keymap[] = {
152                   0,216,  0,213,175,156,  0,  0,  0,  0,
153                 144,  0,  0,  0,  0,  0,  0,  0,  0,212,
154                 174,167,152,161,112,  0,  0,  0,154,  0,
155                   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
156                   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
157                   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
158                   0,  0,  0,  0,  0,183,184,185,186,187,
159                 188,189,190,191,192,193,194,  0,  0,  0
160         };
161         unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
162         unsigned int hid = usage->hid;
163
164         if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
165                         lg_ultrax_remote_mapping(hi, usage, bit, max))
166                 return 1;
167
168         if ((quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
169                 return 1;
170
171         if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
172                 return 0;
173
174         hid &= HID_USAGE;
175
176         /* Special handling for Logitech Cordless Desktop */
177         if (field->application == HID_GD_MOUSE) {
178                 if ((quirks & LG_IGNORE_DOUBLED_WHEEL) &&
179                                 (hid == 7 || hid == 8))
180                         return -1;
181         } else {
182                 if ((quirks & LG_EXPANDED_KEYMAP) &&
183                                 hid < ARRAY_SIZE(e_keymap) &&
184                                 e_keymap[hid] != 0) {
185                         hid_map_usage(hi, usage, bit, max, EV_KEY,
186                                         e_keymap[hid]);
187                         return 1;
188                 }
189         }
190
191         return 0;
192 }
193
194 static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
195                 struct hid_field *field, struct hid_usage *usage,
196                 unsigned long **bit, int *max)
197 {
198         unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
199
200         if ((quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
201                         (field->flags & HID_MAIN_ITEM_RELATIVE))
202                 field->flags &= ~HID_MAIN_ITEM_RELATIVE;
203
204         if ((quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
205                          usage->type == EV_REL || usage->type == EV_ABS))
206                 clear_bit(usage->code, *bit);
207
208         return 0;
209 }
210
211 static int lg_event(struct hid_device *hdev, struct hid_field *field,
212                 struct hid_usage *usage, __s32 value)
213 {
214         unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
215
216         if ((quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
217                 input_event(field->hidinput->input, usage->type, usage->code,
218                                 -value);
219                 return 1;
220         }
221
222         return 0;
223 }
224
225 static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
226 {
227         unsigned long quirks = id->driver_data;
228         unsigned int connect_mask = HID_CONNECT_DEFAULT;
229         int ret;
230
231         hid_set_drvdata(hdev, (void *)quirks);
232
233         if (quirks & LG_NOGET)
234                 hdev->quirks |= HID_QUIRK_NOGET;
235
236         ret = hid_parse(hdev);
237         if (ret) {
238                 dev_err(&hdev->dev, "parse failed\n");
239                 goto err_free;
240         }
241
242         if (quirks & (LG_FF | LG_FF2))
243                 connect_mask &= ~HID_CONNECT_FF;
244
245         ret = hid_hw_start(hdev, connect_mask);
246         if (ret) {
247                 dev_err(&hdev->dev, "hw start failed\n");
248                 goto err_free;
249         }
250
251         if (quirks & LG_RESET_LEDS)
252                 usbhid_set_leds(hdev);
253
254         if (quirks & LG_FF)
255                 lgff_init(hdev);
256         if (quirks & LG_FF2)
257                 lg2ff_init(hdev);
258
259         return 0;
260 err_free:
261         return ret;
262 }
263
264 static const struct hid_device_id lg_devices[] = {
265         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
266                 .driver_data = LG_RDESC | LG_WIRELESS },
267         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
268                 .driver_data = LG_RDESC | LG_WIRELESS },
269         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2),
270                 .driver_data = LG_RDESC | LG_WIRELESS },
271
272         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER),
273                 .driver_data = LG_BAD_RELATIVE_KEYS },
274
275         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP),
276                 .driver_data = LG_DUPLICATE_USAGES },
277         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE),
278                 .driver_data = LG_DUPLICATE_USAGES },
279         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI),
280                 .driver_data = LG_DUPLICATE_USAGES },
281
282         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD),
283                 .driver_data = LG_RESET_LEDS },
284
285         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
286                 .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
287         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500),
288                 .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
289
290         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_LX3),
291                 .driver_data = LG_INVERT_HWHEEL },
292         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_V150),
293                 .driver_data = LG_INVERT_HWHEEL },
294
295         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
296                 .driver_data = LG_NOGET },
297         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
298                 .driver_data = LG_NOGET | LG_FF },
299
300         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
301                 .driver_data = LG_FF },
302         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
303                 .driver_data = LG_FF },
304         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D),
305                 .driver_data = LG_FF },
306         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
307                 .driver_data = LG_FF },
308         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
309                 .driver_data = LG_FF },
310         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
311                 .driver_data = LG_FF },
312         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
313                 .driver_data = LG_FF2 },
314         { }
315 };
316 MODULE_DEVICE_TABLE(hid, lg_devices);
317
318 static struct hid_driver lg_driver = {
319         .name = "logitech",
320         .id_table = lg_devices,
321         .report_fixup = lg_report_fixup,
322         .input_mapping = lg_input_mapping,
323         .input_mapped = lg_input_mapped,
324         .event = lg_event,
325         .probe = lg_probe,
326 };
327
328 static int lg_init(void)
329 {
330         return hid_register_driver(&lg_driver);
331 }
332
333 static void lg_exit(void)
334 {
335         hid_unregister_driver(&lg_driver);
336 }
337
338 module_init(lg_init);
339 module_exit(lg_exit);
340 MODULE_LICENSE("GPL");
341
342 HID_COMPAT_LOAD_DRIVER(logitech);