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_G29_WHEEL:
624		case USB_DEVICE_ID_LOGITECH_WHEEL:
625		case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
626		case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
627		case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
628		case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
629		case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
630		case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
631		case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
632		case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
633			field->application = HID_GD_MULTIAXIS;
634			break;
635		default:
636			break;
637		}
638	}
639
640	return 0;
641}
642
643static int lg_event(struct hid_device *hdev, struct hid_field *field,
644		struct hid_usage *usage, __s32 value)
645{
646	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
647
648	if ((drv_data->quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
649		input_event(field->hidinput->input, usage->type, usage->code,
650				-value);
651		return 1;
652	}
653	if (drv_data->quirks & LG_FF4) {
654		return lg4ff_adjust_input_event(hdev, field, usage, value, drv_data);
655	}
656
657	return 0;
658}
659
660static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
661{
662	struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
663	__u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
664	unsigned int connect_mask = HID_CONNECT_DEFAULT;
665	struct lg_drv_data *drv_data;
666	int ret;
667
668	/* G29 only work with the 1st interface */
669	if ((hdev->product == USB_DEVICE_ID_LOGITECH_G29_WHEEL) &&
670	    (iface_num != 0)) {
671		dbg_hid("%s: ignoring ifnum %d\n", __func__, iface_num);
672		return -ENODEV;
673	}
674
675	drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL);
676	if (!drv_data) {
677		hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
678		return -ENOMEM;
679	}
680	drv_data->quirks = id->driver_data;
681
682	hid_set_drvdata(hdev, (void *)drv_data);
683
684	if (drv_data->quirks & LG_NOGET)
685		hdev->quirks |= HID_QUIRK_NOGET;
686
687	ret = hid_parse(hdev);
688	if (ret) {
689		hid_err(hdev, "parse failed\n");
690		goto err_free;
691	}
692
693	if (drv_data->quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
694		connect_mask &= ~HID_CONNECT_FF;
695
696	ret = hid_hw_start(hdev, connect_mask);
697	if (ret) {
698		hid_err(hdev, "hw start failed\n");
699		goto err_free;
700	}
701
702	/* Setup wireless link with Logitech Wii wheel */
703	if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
704		unsigned char buf[] = { 0x00, 0xAF,  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
705
706		ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
707					HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
708
709		if (ret >= 0) {
710			/* insert a little delay of 10 jiffies ~ 40ms */
711			wait_queue_head_t wait;
712			init_waitqueue_head (&wait);
713			wait_event_interruptible_timeout(wait, 0,
714							 msecs_to_jiffies(40));
715
716			/* Select random Address */
717			buf[1] = 0xB2;
718			get_random_bytes(&buf[2], 2);
719
720			ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
721					HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
722		}
723	}
724
725	if (drv_data->quirks & LG_FF)
726		ret = lgff_init(hdev);
727	else if (drv_data->quirks & LG_FF2)
728		ret = lg2ff_init(hdev);
729	else if (drv_data->quirks & LG_FF3)
730		ret = lg3ff_init(hdev);
731	else if (drv_data->quirks & LG_FF4)
732		ret = lg4ff_init(hdev);
733
734	if (ret)
735		goto err_free;
736
737	return 0;
738err_free:
739	kfree(drv_data);
740	return ret;
741}
742
743static void lg_remove(struct hid_device *hdev)
744{
745	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
746	if (drv_data->quirks & LG_FF4)
747		lg4ff_deinit(hdev);
748	else
749		hid_hw_stop(hdev);
750	kfree(drv_data);
751}
752
753static const struct hid_device_id lg_devices[] = {
754	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
755		.driver_data = LG_RDESC | LG_WIRELESS },
756	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
757		.driver_data = LG_RDESC | LG_WIRELESS },
758	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2),
759		.driver_data = LG_RDESC | LG_WIRELESS },
760
761	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER),
762		.driver_data = LG_BAD_RELATIVE_KEYS },
763
764	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP),
765		.driver_data = LG_DUPLICATE_USAGES },
766	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE),
767		.driver_data = LG_DUPLICATE_USAGES },
768	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI),
769		.driver_data = LG_DUPLICATE_USAGES },
770
771	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
772		.driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
773	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500),
774		.driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
775
776	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
777		.driver_data = LG_NOGET },
778	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DUAL_ACTION),
779		.driver_data = LG_NOGET },
780	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
781		.driver_data = LG_NOGET | LG_FF4 },
782
783	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD),
784		.driver_data = LG_FF2 },
785	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
786		.driver_data = LG_FF },
787	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
788		.driver_data = LG_FF },
789	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G29_WHEEL),
790		.driver_data = LG_FF4 },
791	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D),
792		.driver_data = LG_FF },
793	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
794		.driver_data = LG_FF },
795	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
796		.driver_data = LG_NOGET | LG_FF4 },
797	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
798		.driver_data = LG_FF4 },
799	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL),
800		.driver_data = LG_FF2 },
801	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
802		.driver_data = LG_FF4 },
803	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL),
804		.driver_data = LG_FF4 },
805	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL),
806		.driver_data = LG_FF4 },
807	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
808		.driver_data = LG_NOGET | LG_FF4 },
809	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
810		.driver_data = LG_FF4 },
811	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG),
812		.driver_data = LG_FF },
813	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
814		.driver_data = LG_FF2 },
815	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940),
816		.driver_data = LG_FF3 },
817	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR),
818		.driver_data = LG_RDESC_REL_ABS },
819	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER),
820		.driver_data = LG_RDESC_REL_ABS },
821	{ }
822};
823
824MODULE_DEVICE_TABLE(hid, lg_devices);
825
826static struct hid_driver lg_driver = {
827	.name = "logitech",
828	.id_table = lg_devices,
829	.report_fixup = lg_report_fixup,
830	.input_mapping = lg_input_mapping,
831	.input_mapped = lg_input_mapped,
832	.event = lg_event,
833	.probe = lg_probe,
834	.remove = lg_remove,
835};
836module_hid_driver(lg_driver);
837
838#ifdef CONFIG_LOGIWHEELS_FF
839int lg4ff_no_autoswitch = 0;
840module_param_named(lg4ff_no_autoswitch, lg4ff_no_autoswitch, int, S_IRUGO);
841MODULE_PARM_DESC(lg4ff_no_autoswitch, "Do not switch multimode wheels to their native mode automatically");
842#endif
843
844MODULE_LICENSE("GPL");
845