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