xref: /openbmc/linux/drivers/hid/hid-lg.c (revision 8fa5723aa7e053d498336b48448b292fc2e0458b)
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_EXTREME_3D),
291 		.driver_data = LG_NOGET },
292 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
293 		.driver_data = LG_NOGET | LG_FF },
294 
295 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
296 		.driver_data = LG_FF },
297 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
298 		.driver_data = LG_FF },
299 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D),
300 		.driver_data = LG_FF },
301 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
302 		.driver_data = LG_FF },
303 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
304 		.driver_data = LG_FF },
305 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
306 		.driver_data = LG_FF },
307 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
308 		.driver_data = LG_FF2 },
309 	{ }
310 };
311 MODULE_DEVICE_TABLE(hid, lg_devices);
312 
313 static struct hid_driver lg_driver = {
314 	.name = "logitech",
315 	.id_table = lg_devices,
316 	.report_fixup = lg_report_fixup,
317 	.input_mapping = lg_input_mapping,
318 	.input_mapped = lg_input_mapped,
319 	.event = lg_event,
320 	.probe = lg_probe,
321 };
322 
323 static int lg_init(void)
324 {
325 	return hid_register_driver(&lg_driver);
326 }
327 
328 static void lg_exit(void)
329 {
330 	hid_unregister_driver(&lg_driver);
331 }
332 
333 module_init(lg_init);
334 module_exit(lg_exit);
335 MODULE_LICENSE("GPL");
336 
337 HID_COMPAT_LOAD_DRIVER(logitech);
338