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) 2008 Jiri Slaby
9 *  Copyright (c) 2010 Hendrik Iben
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#include <linux/random.h>
23#include <linux/sched.h>
24#include <linux/usb.h>
25#include <linux/wait.h>
26
27#include "usbhid/usbhid.h"
28#include "hid-ids.h"
29#include "hid-lg.h"
30
31#define LG_RDESC		0x001
32#define LG_BAD_RELATIVE_KEYS	0x002
33#define LG_DUPLICATE_USAGES	0x004
34#define LG_EXPANDED_KEYMAP	0x010
35#define LG_IGNORE_DOUBLED_WHEEL	0x020
36#define LG_WIRELESS		0x040
37#define LG_INVERT_HWHEEL	0x080
38#define LG_NOGET		0x100
39#define LG_FF			0x200
40#define LG_FF2			0x400
41#define LG_RDESC_REL_ABS	0x800
42#define LG_FF3			0x1000
43#define LG_FF4			0x2000
44
45/* Size of the original descriptors of the Driving Force (and Pro) wheels */
46#define DF_RDESC_ORIG_SIZE	130
47#define DFP_RDESC_ORIG_SIZE	97
48#define FV_RDESC_ORIG_SIZE	130
49#define MOMO_RDESC_ORIG_SIZE	87
50#define MOMO2_RDESC_ORIG_SIZE	87
51
52/* Fixed report descriptors for Logitech Driving Force (and Pro)
53 * wheel controllers
54 *
55 * The original descriptors hide the separate throttle and brake axes in
56 * a custom vendor usage page, providing only a combined value as
57 * GenericDesktop.Y.
58 * These descriptors remove the combined Y axis and instead report
59 * separate throttle (Y) and brake (RZ).
60 */
61static __u8 df_rdesc_fixed[] = {
620x05, 0x01,         /*  Usage Page (Desktop),                   */
630x09, 0x04,         /*  Usage (Joystik),                        */
640xA1, 0x01,         /*  Collection (Application),               */
650xA1, 0x02,         /*      Collection (Logical),               */
660x95, 0x01,         /*          Report Count (1),               */
670x75, 0x0A,         /*          Report Size (10),               */
680x14,               /*          Logical Minimum (0),            */
690x26, 0xFF, 0x03,   /*          Logical Maximum (1023),         */
700x34,               /*          Physical Minimum (0),           */
710x46, 0xFF, 0x03,   /*          Physical Maximum (1023),        */
720x09, 0x30,         /*          Usage (X),                      */
730x81, 0x02,         /*          Input (Variable),               */
740x95, 0x0C,         /*          Report Count (12),              */
750x75, 0x01,         /*          Report Size (1),                */
760x25, 0x01,         /*          Logical Maximum (1),            */
770x45, 0x01,         /*          Physical Maximum (1),           */
780x05, 0x09,         /*          Usage (Buttons),                */
790x19, 0x01,         /*          Usage Minimum (1),              */
800x29, 0x0c,         /*          Usage Maximum (12),             */
810x81, 0x02,         /*          Input (Variable),               */
820x95, 0x02,         /*          Report Count (2),               */
830x06, 0x00, 0xFF,   /*          Usage Page (Vendor: 65280),     */
840x09, 0x01,         /*          Usage (?: 1),                   */
850x81, 0x02,         /*          Input (Variable),               */
860x05, 0x01,         /*          Usage Page (Desktop),           */
870x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
880x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
890x95, 0x01,         /*          Report Count (1),               */
900x75, 0x08,         /*          Report Size (8),                */
910x81, 0x02,         /*          Input (Variable),               */
920x25, 0x07,         /*          Logical Maximum (7),            */
930x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
940x75, 0x04,         /*          Report Size (4),                */
950x65, 0x14,         /*          Unit (Degrees),                 */
960x09, 0x39,         /*          Usage (Hat Switch),             */
970x81, 0x42,         /*          Input (Variable, Null State),   */
980x75, 0x01,         /*          Report Size (1),                */
990x95, 0x04,         /*          Report Count (4),               */
1000x65, 0x00,         /*          Unit (none),                    */
1010x06, 0x00, 0xFF,   /*          Usage Page (Vendor: 65280),     */
1020x09, 0x01,         /*          Usage (?: 1),                   */
1030x25, 0x01,         /*          Logical Maximum (1),            */
1040x45, 0x01,         /*          Physical Maximum (1),           */
1050x81, 0x02,         /*          Input (Variable),               */
1060x05, 0x01,         /*          Usage Page (Desktop),           */
1070x95, 0x01,         /*          Report Count (1),               */
1080x75, 0x08,         /*          Report Size (8),                */
1090x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
1100x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
1110x09, 0x31,         /*          Usage (Y),                      */
1120x81, 0x02,         /*          Input (Variable),               */
1130x09, 0x35,         /*          Usage (Rz),                     */
1140x81, 0x02,         /*          Input (Variable),               */
1150xC0,               /*      End Collection,                     */
1160xA1, 0x02,         /*      Collection (Logical),               */
1170x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
1180x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
1190x95, 0x07,         /*          Report Count (7),               */
1200x75, 0x08,         /*          Report Size (8),                */
1210x09, 0x03,         /*          Usage (?: 3),                   */
1220x91, 0x02,         /*          Output (Variable),              */
1230xC0,               /*      End Collection,                     */
1240xC0                /*  End Collection                          */
125};
126
127static __u8 dfp_rdesc_fixed[] = {
1280x05, 0x01,         /*  Usage Page (Desktop),                   */
1290x09, 0x04,         /*  Usage (Joystik),                        */
1300xA1, 0x01,         /*  Collection (Application),               */
1310xA1, 0x02,         /*      Collection (Logical),               */
1320x95, 0x01,         /*          Report Count (1),               */
1330x75, 0x0E,         /*          Report Size (14),               */
1340x14,               /*          Logical Minimum (0),            */
1350x26, 0xFF, 0x3F,   /*          Logical Maximum (16383),        */
1360x34,               /*          Physical Minimum (0),           */
1370x46, 0xFF, 0x3F,   /*          Physical Maximum (16383),       */
1380x09, 0x30,         /*          Usage (X),                      */
1390x81, 0x02,         /*          Input (Variable),               */
1400x95, 0x0E,         /*          Report Count (14),              */
1410x75, 0x01,         /*          Report Size (1),                */
1420x25, 0x01,         /*          Logical Maximum (1),            */
1430x45, 0x01,         /*          Physical Maximum (1),           */
1440x05, 0x09,         /*          Usage Page (Button),            */
1450x19, 0x01,         /*          Usage Minimum (01h),            */
1460x29, 0x0E,         /*          Usage Maximum (0Eh),            */
1470x81, 0x02,         /*          Input (Variable),               */
1480x05, 0x01,         /*          Usage Page (Desktop),           */
1490x95, 0x01,         /*          Report Count (1),               */
1500x75, 0x04,         /*          Report Size (4),                */
1510x25, 0x07,         /*          Logical Maximum (7),            */
1520x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
1530x65, 0x14,         /*          Unit (Degrees),                 */
1540x09, 0x39,         /*          Usage (Hat Switch),             */
1550x81, 0x42,         /*          Input (Variable, Nullstate),    */
1560x65, 0x00,         /*          Unit,                           */
1570x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
1580x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
1590x75, 0x08,         /*          Report Size (8),                */
1600x81, 0x01,         /*          Input (Constant),               */
1610x09, 0x31,         /*          Usage (Y),                      */
1620x81, 0x02,         /*          Input (Variable),               */
1630x09, 0x35,         /*          Usage (Rz),                     */
1640x81, 0x02,         /*          Input (Variable),               */
1650x81, 0x01,         /*          Input (Constant),               */
1660xC0,               /*      End Collection,                     */
1670xA1, 0x02,         /*      Collection (Logical),               */
1680x09, 0x02,         /*          Usage (02h),                    */
1690x95, 0x07,         /*          Report Count (7),               */
1700x91, 0x02,         /*          Output (Variable),              */
1710xC0,               /*      End Collection,                     */
1720xC0                /*  End Collection                          */
173};
174
175static __u8 fv_rdesc_fixed[] = {
1760x05, 0x01,         /*  Usage Page (Desktop),                   */
1770x09, 0x04,         /*  Usage (Joystik),                        */
1780xA1, 0x01,         /*  Collection (Application),               */
1790xA1, 0x02,         /*      Collection (Logical),               */
1800x95, 0x01,         /*          Report Count (1),               */
1810x75, 0x0A,         /*          Report Size (10),               */
1820x15, 0x00,         /*          Logical Minimum (0),            */
1830x26, 0xFF, 0x03,   /*          Logical Maximum (1023),         */
1840x35, 0x00,         /*          Physical Minimum (0),           */
1850x46, 0xFF, 0x03,   /*          Physical Maximum (1023),        */
1860x09, 0x30,         /*          Usage (X),                      */
1870x81, 0x02,         /*          Input (Variable),               */
1880x95, 0x0C,         /*          Report Count (12),              */
1890x75, 0x01,         /*          Report Size (1),                */
1900x25, 0x01,         /*          Logical Maximum (1),            */
1910x45, 0x01,         /*          Physical Maximum (1),           */
1920x05, 0x09,         /*          Usage Page (Button),            */
1930x19, 0x01,         /*          Usage Minimum (01h),            */
1940x29, 0x0C,         /*          Usage Maximum (0Ch),            */
1950x81, 0x02,         /*          Input (Variable),               */
1960x95, 0x02,         /*          Report Count (2),               */
1970x06, 0x00, 0xFF,   /*          Usage Page (FF00h),             */
1980x09, 0x01,         /*          Usage (01h),                    */
1990x81, 0x02,         /*          Input (Variable),               */
2000x09, 0x02,         /*          Usage (02h),                    */
2010x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
2020x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
2030x95, 0x01,         /*          Report Count (1),               */
2040x75, 0x08,         /*          Report Size (8),                */
2050x81, 0x02,         /*          Input (Variable),               */
2060x05, 0x01,         /*          Usage Page (Desktop),           */
2070x25, 0x07,         /*          Logical Maximum (7),            */
2080x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
2090x75, 0x04,         /*          Report Size (4),                */
2100x65, 0x14,         /*          Unit (Degrees),                 */
2110x09, 0x39,         /*          Usage (Hat Switch),             */
2120x81, 0x42,         /*          Input (Variable, Null State),   */
2130x75, 0x01,         /*          Report Size (1),                */
2140x95, 0x04,         /*          Report Count (4),               */
2150x65, 0x00,         /*          Unit,                           */
2160x06, 0x00, 0xFF,   /*          Usage Page (FF00h),             */
2170x09, 0x01,         /*          Usage (01h),                    */
2180x25, 0x01,         /*          Logical Maximum (1),            */
2190x45, 0x01,         /*          Physical Maximum (1),           */
2200x81, 0x02,         /*          Input (Variable),               */
2210x05, 0x01,         /*          Usage Page (Desktop),           */
2220x95, 0x01,         /*          Report Count (1),               */
2230x75, 0x08,         /*          Report Size (8),                */
2240x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
2250x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
2260x09, 0x31,         /*          Usage (Y),                      */
2270x81, 0x02,         /*          Input (Variable),               */
2280x09, 0x32,         /*          Usage (Z),                      */
2290x81, 0x02,         /*          Input (Variable),               */
2300xC0,               /*      End Collection,                     */
2310xA1, 0x02,         /*      Collection (Logical),               */
2320x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
2330x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
2340x95, 0x07,         /*          Report Count (7),               */
2350x75, 0x08,         /*          Report Size (8),                */
2360x09, 0x03,         /*          Usage (03h),                    */
2370x91, 0x02,         /*          Output (Variable),              */
2380xC0,               /*      End Collection,                     */
2390xC0                /*  End Collection                          */
240};
241
242static __u8 momo_rdesc_fixed[] = {
2430x05, 0x01,         /*  Usage Page (Desktop),               */
2440x09, 0x04,         /*  Usage (Joystik),                    */
2450xA1, 0x01,         /*  Collection (Application),           */
2460xA1, 0x02,         /*      Collection (Logical),           */
2470x95, 0x01,         /*          Report Count (1),           */
2480x75, 0x0A,         /*          Report Size (10),           */
2490x15, 0x00,         /*          Logical Minimum (0),        */
2500x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
2510x35, 0x00,         /*          Physical Minimum (0),       */
2520x46, 0xFF, 0x03,   /*          Physical Maximum (1023),    */
2530x09, 0x30,         /*          Usage (X),                  */
2540x81, 0x02,         /*          Input (Variable),           */
2550x95, 0x08,         /*          Report Count (8),           */
2560x75, 0x01,         /*          Report Size (1),            */
2570x25, 0x01,         /*          Logical Maximum (1),        */
2580x45, 0x01,         /*          Physical Maximum (1),       */
2590x05, 0x09,         /*          Usage Page (Button),        */
2600x19, 0x01,         /*          Usage Minimum (01h),        */
2610x29, 0x08,         /*          Usage Maximum (08h),        */
2620x81, 0x02,         /*          Input (Variable),           */
2630x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
2640x75, 0x0E,         /*          Report Size (14),           */
2650x95, 0x01,         /*          Report Count (1),           */
2660x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
2670x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
2680x09, 0x00,         /*          Usage (00h),                */
2690x81, 0x02,         /*          Input (Variable),           */
2700x05, 0x01,         /*          Usage Page (Desktop),       */
2710x75, 0x08,         /*          Report Size (8),            */
2720x09, 0x31,         /*          Usage (Y),                  */
2730x81, 0x02,         /*          Input (Variable),           */
2740x09, 0x32,         /*          Usage (Z),                  */
2750x81, 0x02,         /*          Input (Variable),           */
2760x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
2770x09, 0x01,         /*          Usage (01h),                */
2780x81, 0x02,         /*          Input (Variable),           */
2790xC0,               /*      End Collection,                 */
2800xA1, 0x02,         /*      Collection (Logical),           */
2810x09, 0x02,         /*          Usage (02h),                */
2820x95, 0x07,         /*          Report Count (7),           */
2830x91, 0x02,         /*          Output (Variable),          */
2840xC0,               /*      End Collection,                 */
2850xC0                /*  End Collection                      */
286};
287
288static __u8 momo2_rdesc_fixed[] = {
2890x05, 0x01,         /*  Usage Page (Desktop),               */
2900x09, 0x04,         /*  Usage (Joystik),                    */
2910xA1, 0x01,         /*  Collection (Application),           */
2920xA1, 0x02,         /*      Collection (Logical),           */
2930x95, 0x01,         /*          Report Count (1),           */
2940x75, 0x0A,         /*          Report Size (10),           */
2950x15, 0x00,         /*          Logical Minimum (0),        */
2960x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
2970x35, 0x00,         /*          Physical Minimum (0),       */
2980x46, 0xFF, 0x03,   /*          Physical Maximum (1023),    */
2990x09, 0x30,         /*          Usage (X),                  */
3000x81, 0x02,         /*          Input (Variable),           */
3010x95, 0x0A,         /*          Report Count (10),          */
3020x75, 0x01,         /*          Report Size (1),            */
3030x25, 0x01,         /*          Logical Maximum (1),        */
3040x45, 0x01,         /*          Physical Maximum (1),       */
3050x05, 0x09,         /*          Usage Page (Button),        */
3060x19, 0x01,         /*          Usage Minimum (01h),        */
3070x29, 0x0A,         /*          Usage Maximum (0Ah),        */
3080x81, 0x02,         /*          Input (Variable),           */
3090x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
3100x09, 0x00,         /*          Usage (00h),                */
3110x95, 0x04,         /*          Report Count (4),           */
3120x81, 0x02,         /*          Input (Variable),           */
3130x95, 0x01,         /*          Report Count (1),           */
3140x75, 0x08,         /*          Report Size (8),            */
3150x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
3160x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
3170x09, 0x01,         /*          Usage (01h),                */
3180x81, 0x02,         /*          Input (Variable),           */
3190x05, 0x01,         /*          Usage Page (Desktop),       */
3200x09, 0x31,         /*          Usage (Y),                  */
3210x81, 0x02,         /*          Input (Variable),           */
3220x09, 0x32,         /*          Usage (Z),                  */
3230x81, 0x02,         /*          Input (Variable),           */
3240x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
3250x09, 0x00,         /*          Usage (00h),                */
3260x81, 0x02,         /*          Input (Variable),           */
3270xC0,               /*      End Collection,                 */
3280xA1, 0x02,         /*      Collection (Logical),           */
3290x09, 0x02,         /*          Usage (02h),                */
3300x95, 0x07,         /*          Report Count (7),           */
3310x91, 0x02,         /*          Output (Variable),          */
3320xC0,               /*      End Collection,                 */
3330xC0                /*  End Collection                      */
334};
335
336/*
337 * Certain Logitech keyboards send in report #3 keys which are far
338 * above the logical maximum described in descriptor. This extends
339 * the original value of 0x28c of logical maximum to 0x104d
340 */
341static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
342		unsigned int *rsize)
343{
344	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
345	struct usb_device_descriptor *udesc;
346	__u16 bcdDevice, rev_maj, rev_min;
347
348	if ((drv_data->quirks & LG_RDESC) && *rsize >= 91 && rdesc[83] == 0x26 &&
349			rdesc[84] == 0x8c && rdesc[85] == 0x02) {
350		hid_info(hdev,
351			 "fixing up Logitech keyboard report descriptor\n");
352		rdesc[84] = rdesc[89] = 0x4d;
353		rdesc[85] = rdesc[90] = 0x10;
354	}
355	if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 51 &&
356			rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
357			rdesc[49] == 0x81 && rdesc[50] == 0x06) {
358		hid_info(hdev,
359			 "fixing up rel/abs in Logitech report descriptor\n");
360		rdesc[33] = rdesc[50] = 0x02;
361	}
362
363	switch (hdev->product) {
364
365	/* Several wheels report as this id when operating in emulation mode. */
366	case USB_DEVICE_ID_LOGITECH_WHEEL:
367		udesc = &(hid_to_usb_dev(hdev)->descriptor);
368		if (!udesc) {
369			hid_err(hdev, "NULL USB device descriptor\n");
370			break;
371		}
372		bcdDevice = le16_to_cpu(udesc->bcdDevice);
373		rev_maj = bcdDevice >> 8;
374		rev_min = bcdDevice & 0xff;
375
376		/* Update the report descriptor for only the Driving Force wheel */
377		if (rev_maj == 1 && rev_min == 2 &&
378				*rsize == DF_RDESC_ORIG_SIZE) {
379			hid_info(hdev,
380				"fixing up Logitech Driving Force report descriptor\n");
381			rdesc = df_rdesc_fixed;
382			*rsize = sizeof(df_rdesc_fixed);
383		}
384		break;
385
386	case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
387		if (*rsize == MOMO_RDESC_ORIG_SIZE) {
388			hid_info(hdev,
389				"fixing up Logitech Momo Force (Red) report descriptor\n");
390			rdesc = momo_rdesc_fixed;
391			*rsize = sizeof(momo_rdesc_fixed);
392		}
393		break;
394
395	case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
396		if (*rsize == MOMO2_RDESC_ORIG_SIZE) {
397			hid_info(hdev,
398				"fixing up Logitech Momo Racing Force (Black) report descriptor\n");
399			rdesc = momo2_rdesc_fixed;
400			*rsize = sizeof(momo2_rdesc_fixed);
401		}
402		break;
403
404	case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
405		if (*rsize == FV_RDESC_ORIG_SIZE) {
406			hid_info(hdev,
407				"fixing up Logitech Formula Vibration report descriptor\n");
408			rdesc = fv_rdesc_fixed;
409			*rsize = sizeof(fv_rdesc_fixed);
410		}
411		break;
412
413	case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
414		if (*rsize == DFP_RDESC_ORIG_SIZE) {
415			hid_info(hdev,
416				"fixing up Logitech Driving Force Pro report descriptor\n");
417			rdesc = dfp_rdesc_fixed;
418			*rsize = sizeof(dfp_rdesc_fixed);
419		}
420		break;
421
422	case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
423		if (*rsize >= 101 && rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
424				rdesc[47] == 0x05 && rdesc[48] == 0x09) {
425			hid_info(hdev, "fixing up Logitech Speed Force Wireless report descriptor\n");
426			rdesc[41] = 0x05;
427			rdesc[42] = 0x09;
428			rdesc[47] = 0x95;
429			rdesc[48] = 0x0B;
430		}
431		break;
432	}
433
434	return rdesc;
435}
436
437#define lg_map_key_clear(c)	hid_map_usage_clear(hi, usage, bit, max, \
438		EV_KEY, (c))
439
440static int lg_ultrax_remote_mapping(struct hid_input *hi,
441		struct hid_usage *usage, unsigned long **bit, int *max)
442{
443	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
444		return 0;
445
446	set_bit(EV_REP, hi->input->evbit);
447	switch (usage->hid & HID_USAGE) {
448	/* Reported on Logitech Ultra X Media Remote */
449	case 0x004: lg_map_key_clear(KEY_AGAIN);	break;
450	case 0x00d: lg_map_key_clear(KEY_HOME);		break;
451	case 0x024: lg_map_key_clear(KEY_SHUFFLE);	break;
452	case 0x025: lg_map_key_clear(KEY_TV);		break;
453	case 0x026: lg_map_key_clear(KEY_MENU);		break;
454	case 0x031: lg_map_key_clear(KEY_AUDIO);	break;
455	case 0x032: lg_map_key_clear(KEY_TEXT);		break;
456	case 0x033: lg_map_key_clear(KEY_LAST);		break;
457	case 0x047: lg_map_key_clear(KEY_MP3);		break;
458	case 0x048: lg_map_key_clear(KEY_DVD);		break;
459	case 0x049: lg_map_key_clear(KEY_MEDIA);	break;
460	case 0x04a: lg_map_key_clear(KEY_VIDEO);	break;
461	case 0x04b: lg_map_key_clear(KEY_ANGLE);	break;
462	case 0x04c: lg_map_key_clear(KEY_LANGUAGE);	break;
463	case 0x04d: lg_map_key_clear(KEY_SUBTITLE);	break;
464	case 0x051: lg_map_key_clear(KEY_RED);		break;
465	case 0x052: lg_map_key_clear(KEY_CLOSE);	break;
466
467	default:
468		return 0;
469	}
470	return 1;
471}
472
473static int lg_dinovo_mapping(struct hid_input *hi, struct hid_usage *usage,
474		unsigned long **bit, int *max)
475{
476	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
477		return 0;
478
479	switch (usage->hid & HID_USAGE) {
480
481	case 0x00d: lg_map_key_clear(KEY_MEDIA);	break;
482	default:
483		return 0;
484
485	}
486	return 1;
487}
488
489static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
490		unsigned long **bit, int *max)
491{
492	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
493		return 0;
494
495	switch (usage->hid & HID_USAGE) {
496	case 0x1001: lg_map_key_clear(KEY_MESSENGER);		break;
497	case 0x1003: lg_map_key_clear(KEY_SOUND);		break;
498	case 0x1004: lg_map_key_clear(KEY_VIDEO);		break;
499	case 0x1005: lg_map_key_clear(KEY_AUDIO);		break;
500	case 0x100a: lg_map_key_clear(KEY_DOCUMENTS);		break;
501	/* The following two entries are Playlist 1 and 2 on the MX3200 */
502	case 0x100f: lg_map_key_clear(KEY_FN_1);		break;
503	case 0x1010: lg_map_key_clear(KEY_FN_2);		break;
504	case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG);	break;
505	case 0x1012: lg_map_key_clear(KEY_NEXTSONG);		break;
506	case 0x1013: lg_map_key_clear(KEY_CAMERA);		break;
507	case 0x1014: lg_map_key_clear(KEY_MESSENGER);		break;
508	case 0x1015: lg_map_key_clear(KEY_RECORD);		break;
509	case 0x1016: lg_map_key_clear(KEY_PLAYER);		break;
510	case 0x1017: lg_map_key_clear(KEY_EJECTCD);		break;
511	case 0x1018: lg_map_key_clear(KEY_MEDIA);		break;
512	case 0x1019: lg_map_key_clear(KEY_PROG1);		break;
513	case 0x101a: lg_map_key_clear(KEY_PROG2);		break;
514	case 0x101b: lg_map_key_clear(KEY_PROG3);		break;
515	case 0x101c: lg_map_key_clear(KEY_CYCLEWINDOWS);	break;
516	case 0x101f: lg_map_key_clear(KEY_ZOOMIN);		break;
517	case 0x1020: lg_map_key_clear(KEY_ZOOMOUT);		break;
518	case 0x1021: lg_map_key_clear(KEY_ZOOMRESET);		break;
519	case 0x1023: lg_map_key_clear(KEY_CLOSE);		break;
520	case 0x1027: lg_map_key_clear(KEY_MENU);		break;
521	/* this one is marked as 'Rotate' */
522	case 0x1028: lg_map_key_clear(KEY_ANGLE);		break;
523	case 0x1029: lg_map_key_clear(KEY_SHUFFLE);		break;
524	case 0x102a: lg_map_key_clear(KEY_BACK);		break;
525	case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS);	break;
526	case 0x102d: lg_map_key_clear(KEY_WWW);			break;
527	/* The following two are 'Start/answer call' and 'End/reject call'
528	   on the MX3200 */
529	case 0x1031: lg_map_key_clear(KEY_OK);			break;
530	case 0x1032: lg_map_key_clear(KEY_CANCEL);		break;
531	case 0x1041: lg_map_key_clear(KEY_BATTERY);		break;
532	case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR);	break;
533	case 0x1043: lg_map_key_clear(KEY_SPREADSHEET);		break;
534	case 0x1044: lg_map_key_clear(KEY_PRESENTATION);	break;
535	case 0x1045: lg_map_key_clear(KEY_UNDO);		break;
536	case 0x1046: lg_map_key_clear(KEY_REDO);		break;
537	case 0x1047: lg_map_key_clear(KEY_PRINT);		break;
538	case 0x1048: lg_map_key_clear(KEY_SAVE);		break;
539	case 0x1049: lg_map_key_clear(KEY_PROG1);		break;
540	case 0x104a: lg_map_key_clear(KEY_PROG2);		break;
541	case 0x104b: lg_map_key_clear(KEY_PROG3);		break;
542	case 0x104c: lg_map_key_clear(KEY_PROG4);		break;
543
544	default:
545		return 0;
546	}
547	return 1;
548}
549
550static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
551		struct hid_field *field, struct hid_usage *usage,
552		unsigned long **bit, int *max)
553{
554	/* extended mapping for certain Logitech hardware (Logitech cordless
555	   desktop LX500) */
556	static const u8 e_keymap[] = {
557		  0,216,  0,213,175,156,  0,  0,  0,  0,
558		144,  0,  0,  0,  0,  0,  0,  0,  0,212,
559		174,167,152,161,112,  0,  0,  0,154,  0,
560		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
561		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
562		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
563		  0,  0,  0,  0,  0,183,184,185,186,187,
564		188,189,190,191,192,193,194,  0,  0,  0
565	};
566	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
567	unsigned int hid = usage->hid;
568
569	if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
570			lg_ultrax_remote_mapping(hi, usage, bit, max))
571		return 1;
572
573	if (hdev->product == USB_DEVICE_ID_DINOVO_MINI &&
574			lg_dinovo_mapping(hi, usage, bit, max))
575		return 1;
576
577	if ((drv_data->quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
578		return 1;
579
580	if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
581		return 0;
582
583	hid &= HID_USAGE;
584
585	/* Special handling for Logitech Cordless Desktop */
586	if (field->application == HID_GD_MOUSE) {
587		if ((drv_data->quirks & LG_IGNORE_DOUBLED_WHEEL) &&
588				(hid == 7 || hid == 8))
589			return -1;
590	} else {
591		if ((drv_data->quirks & LG_EXPANDED_KEYMAP) &&
592				hid < ARRAY_SIZE(e_keymap) &&
593				e_keymap[hid] != 0) {
594			hid_map_usage(hi, usage, bit, max, EV_KEY,
595					e_keymap[hid]);
596			return 1;
597		}
598	}
599
600	return 0;
601}
602
603static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
604		struct hid_field *field, struct hid_usage *usage,
605		unsigned long **bit, int *max)
606{
607	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
608
609	if ((drv_data->quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
610			(field->flags & HID_MAIN_ITEM_RELATIVE))
611		field->flags &= ~HID_MAIN_ITEM_RELATIVE;
612
613	if ((drv_data->quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
614			 usage->type == EV_REL || usage->type == EV_ABS))
615		clear_bit(usage->code, *bit);
616
617	/* Ensure that Logitech wheels are not given a default fuzz/flat value */
618	if (usage->type == EV_ABS && (usage->code == ABS_X ||
619			usage->code == ABS_Y || usage->code == ABS_Z ||
620			usage->code == ABS_RZ)) {
621		switch (hdev->product) {
622		case USB_DEVICE_ID_LOGITECH_WHEEL:
623		case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
624		case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
625		case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
626		case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
627		case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
628		case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
629		case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
630		case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
631			field->application = HID_GD_MULTIAXIS;
632			break;
633		default:
634			break;
635		}
636	}
637
638	return 0;
639}
640
641static int lg_event(struct hid_device *hdev, struct hid_field *field,
642		struct hid_usage *usage, __s32 value)
643{
644	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
645
646	if ((drv_data->quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
647		input_event(field->hidinput->input, usage->type, usage->code,
648				-value);
649		return 1;
650	}
651	if (drv_data->quirks & LG_FF4) {
652		return lg4ff_adjust_input_event(hdev, field, usage, value, drv_data);
653	}
654
655	return 0;
656}
657
658static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
659{
660	unsigned int connect_mask = HID_CONNECT_DEFAULT;
661	struct lg_drv_data *drv_data;
662	int ret;
663
664	drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL);
665	if (!drv_data) {
666		hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
667		return -ENOMEM;
668	}
669	drv_data->quirks = id->driver_data;
670
671	hid_set_drvdata(hdev, (void *)drv_data);
672
673	if (drv_data->quirks & LG_NOGET)
674		hdev->quirks |= HID_QUIRK_NOGET;
675
676	ret = hid_parse(hdev);
677	if (ret) {
678		hid_err(hdev, "parse failed\n");
679		goto err_free;
680	}
681
682	if (drv_data->quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
683		connect_mask &= ~HID_CONNECT_FF;
684
685	ret = hid_hw_start(hdev, connect_mask);
686	if (ret) {
687		hid_err(hdev, "hw start failed\n");
688		goto err_free;
689	}
690
691	/* Setup wireless link with Logitech Wii wheel */
692	if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
693		unsigned char buf[] = { 0x00, 0xAF,  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
694
695		ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
696					HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
697
698		if (ret >= 0) {
699			/* insert a little delay of 10 jiffies ~ 40ms */
700			wait_queue_head_t wait;
701			init_waitqueue_head (&wait);
702			wait_event_interruptible_timeout(wait, 0, 10);
703
704			/* Select random Address */
705			buf[1] = 0xB2;
706			get_random_bytes(&buf[2], 2);
707
708			ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
709					HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
710		}
711	}
712
713	if (drv_data->quirks & LG_FF)
714		lgff_init(hdev);
715	if (drv_data->quirks & LG_FF2)
716		lg2ff_init(hdev);
717	if (drv_data->quirks & LG_FF3)
718		lg3ff_init(hdev);
719	if (drv_data->quirks & LG_FF4)
720		lg4ff_init(hdev);
721
722	return 0;
723err_free:
724	kfree(drv_data);
725	return ret;
726}
727
728static void lg_remove(struct hid_device *hdev)
729{
730	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
731	if (drv_data->quirks & LG_FF4)
732		lg4ff_deinit(hdev);
733
734	hid_hw_stop(hdev);
735	kfree(drv_data);
736}
737
738static const struct hid_device_id lg_devices[] = {
739	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
740		.driver_data = LG_RDESC | LG_WIRELESS },
741	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
742		.driver_data = LG_RDESC | LG_WIRELESS },
743	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2),
744		.driver_data = LG_RDESC | LG_WIRELESS },
745
746	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER),
747		.driver_data = LG_BAD_RELATIVE_KEYS },
748
749	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP),
750		.driver_data = LG_DUPLICATE_USAGES },
751	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE),
752		.driver_data = LG_DUPLICATE_USAGES },
753	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI),
754		.driver_data = LG_DUPLICATE_USAGES },
755
756	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
757		.driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
758	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500),
759		.driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
760
761	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
762		.driver_data = LG_NOGET },
763	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DUAL_ACTION),
764		.driver_data = LG_NOGET },
765	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
766		.driver_data = LG_NOGET | LG_FF4 },
767
768	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD),
769		.driver_data = LG_FF2 },
770	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
771		.driver_data = LG_FF },
772	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
773		.driver_data = LG_FF },
774	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D),
775		.driver_data = LG_FF },
776	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
777		.driver_data = LG_FF },
778	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
779		.driver_data = LG_NOGET | LG_FF4 },
780	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
781		.driver_data = LG_FF4 },
782	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL),
783		.driver_data = LG_FF2 },
784	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
785		.driver_data = LG_FF4 },
786	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL),
787		.driver_data = LG_FF4 },
788	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL),
789		.driver_data = LG_FF4 },
790	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
791		.driver_data = LG_NOGET | LG_FF4 },
792	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
793		.driver_data = LG_FF4 },
794	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG),
795		.driver_data = LG_FF },
796	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
797		.driver_data = LG_FF2 },
798	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940),
799		.driver_data = LG_FF3 },
800	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR),
801		.driver_data = LG_RDESC_REL_ABS },
802	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER),
803		.driver_data = LG_RDESC_REL_ABS },
804	{ }
805};
806
807MODULE_DEVICE_TABLE(hid, lg_devices);
808
809static struct hid_driver lg_driver = {
810	.name = "logitech",
811	.id_table = lg_devices,
812	.report_fixup = lg_report_fixup,
813	.input_mapping = lg_input_mapping,
814	.input_mapped = lg_input_mapped,
815	.event = lg_event,
816	.probe = lg_probe,
817	.remove = lg_remove,
818};
819module_hid_driver(lg_driver);
820
821MODULE_LICENSE("GPL");
822