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