15f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby/* 25f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * HID driver for some logitech "special" devices 35f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * 45f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * Copyright (c) 1999 Andreas Gal 55f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> 65f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc 75f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * Copyright (c) 2006-2007 Jiri Kosina 85f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * Copyright (c) 2007 Paul Walmsley 95f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * Copyright (c) 2008 Jiri Slaby 102c6118e43040034d80894daeba41960bf0035b31Hendrik Iben * Copyright (c) 2010 Hendrik Iben 115f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby */ 125f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 135f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby/* 145f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * This program is free software; you can redistribute it and/or modify it 155f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * under the terms of the GNU General Public License as published by the Free 165f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * Software Foundation; either version 2 of the License, or (at your option) 175f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * any later version. 185f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby */ 195f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 205f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#include <linux/device.h> 215f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#include <linux/hid.h> 225f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#include <linux/module.h> 2332c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood#include <linux/random.h> 2432c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood#include <linux/sched.h> 2532c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood#include <linux/wait.h> 265f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 275f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#include "hid-ids.h" 28606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby#include "hid-lg.h" 295f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 305f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_RDESC 0x001 315f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_BAD_RELATIVE_KEYS 0x002 325f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_DUPLICATE_USAGES 0x004 335f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_EXPANDED_KEYMAP 0x010 345f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_IGNORE_DOUBLED_WHEEL 0x020 355f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_WIRELESS 0x040 365f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_INVERT_HWHEEL 0x080 375f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_NOGET 0x100 38606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby#define LG_FF 0x200 39606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby#define LG_FF2 0x400 4024985cf68612a5617d396b0b188cec807641cde1Jiri Kosina#define LG_RDESC_REL_ABS 0x800 4174f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein#define LG_FF3 0x1000 4232c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood#define LG_FF4 0x2000 435f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 44dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer/* Size of the original descriptor of the Driving Force Pro wheel */ 45dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer#define DFP_RDESC_ORIG_SIZE 97 46dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer 47dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer/* Fixed report descriptor for Logitech Driving Force Pro wheel controller 48dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer * 49dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer * The original descriptor hides the separate throttle and brake axes in 50dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer * a custom vendor usage page, providing only a combined value as 51dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer * GenericDesktop.Y. 52dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer * This descriptor removes the combined Y axis and instead reports 53dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer * separate throttle (Y) and brake (RZ). 54dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer */ 55dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauerstatic __u8 dfp_rdesc_fixed[] = { 56dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x05, 0x01, /* Usage Page (Desktop), */ 57dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x09, 0x04, /* Usage (Joystik), */ 58dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0xA1, 0x01, /* Collection (Application), */ 59dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0xA1, 0x02, /* Collection (Logical), */ 60dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x95, 0x01, /* Report Count (1), */ 61dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x75, 0x0E, /* Report Size (14), */ 62dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x14, /* Logical Minimum (0), */ 63dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x26, 0xFF, 0x3F, /* Logical Maximum (16383), */ 64dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x34, /* Physical Minimum (0), */ 65dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x46, 0xFF, 0x3F, /* Physical Maximum (16383), */ 66dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x09, 0x30, /* Usage (X), */ 67dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x81, 0x02, /* Input (Variable), */ 68dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x95, 0x0E, /* Report Count (14), */ 69dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x75, 0x01, /* Report Size (1), */ 70dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x25, 0x01, /* Logical Maximum (1), */ 71dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x45, 0x01, /* Physical Maximum (1), */ 72dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x05, 0x09, /* Usage Page (Button), */ 73dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x19, 0x01, /* Usage Minimum (01h), */ 74dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x29, 0x0E, /* Usage Maximum (0Eh), */ 75dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x81, 0x02, /* Input (Variable), */ 76dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x05, 0x01, /* Usage Page (Desktop), */ 77dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x95, 0x01, /* Report Count (1), */ 78dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x75, 0x04, /* Report Size (4), */ 79dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x25, 0x07, /* Logical Maximum (7), */ 80dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x46, 0x3B, 0x01, /* Physical Maximum (315), */ 81dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x65, 0x14, /* Unit (Degrees), */ 82dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x09, 0x39, /* Usage (Hat Switch), */ 83dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x81, 0x42, /* Input (Variable, Nullstate), */ 84dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x65, 0x00, /* Unit, */ 85dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x26, 0xFF, 0x00, /* Logical Maximum (255), */ 86dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x46, 0xFF, 0x00, /* Physical Maximum (255), */ 87dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x75, 0x08, /* Report Size (8), */ 88dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x81, 0x01, /* Input (Constant), */ 89dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x09, 0x31, /* Usage (Y), */ 90dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x81, 0x02, /* Input (Variable), */ 91dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x09, 0x35, /* Usage (Rz), */ 92dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x81, 0x02, /* Input (Variable), */ 93dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x81, 0x01, /* Input (Constant), */ 94dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0xC0, /* End Collection, */ 95dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0xA1, 0x02, /* Collection (Logical), */ 96dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x09, 0x02, /* Usage (02h), */ 97dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x95, 0x07, /* Report Count (7), */ 98dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x91, 0x02, /* Output (Variable), */ 99dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0xC0, /* End Collection, */ 100dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0xC0 /* End Collection */ 101dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer}; 102dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer 103dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer 1045f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby/* 1055f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * Certain Logitech keyboards send in report #3 keys which are far 1065f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * above the logical maximum described in descriptor. This extends 1075f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * the original value of 0x28c of logical maximum to 0x104d 1085f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby */ 10973e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashovstatic __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc, 11073e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashov unsigned int *rsize) 1115f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{ 1125f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); 1135f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 11473e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashov if ((quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 && 1155f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby rdesc[84] == 0x8c && rdesc[85] == 0x02) { 1164291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches hid_info(hdev, 1174291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches "fixing up Logitech keyboard report descriptor\n"); 1185f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby rdesc[84] = rdesc[89] = 0x4d; 1195f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby rdesc[85] = rdesc[90] = 0x10; 1205f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby } 12173e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashov if ((quirks & LG_RDESC_REL_ABS) && *rsize >= 50 && 12224985cf68612a5617d396b0b188cec807641cde1Jiri Kosina rdesc[32] == 0x81 && rdesc[33] == 0x06 && 12324985cf68612a5617d396b0b188cec807641cde1Jiri Kosina rdesc[49] == 0x81 && rdesc[50] == 0x06) { 1244291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches hid_info(hdev, 1254291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches "fixing up rel/abs in Logitech report descriptor\n"); 12624985cf68612a5617d396b0b188cec807641cde1Jiri Kosina rdesc[33] = rdesc[50] = 0x02; 12724985cf68612a5617d396b0b188cec807641cde1Jiri Kosina } 128d8692ac012104ebffb343c0bcb4a2b8642c821a6Jiri Kosina if ((quirks & LG_FF4) && *rsize >= 101 && 12932c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood rdesc[41] == 0x95 && rdesc[42] == 0x0B && 13032c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood rdesc[47] == 0x05 && rdesc[48] == 0x09) { 1314291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches hid_info(hdev, "fixing up Logitech Speed Force Wireless button descriptor\n"); 13232c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood rdesc[41] = 0x05; 13332c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood rdesc[42] = 0x09; 13432c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood rdesc[47] = 0x95; 13532c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood rdesc[48] = 0x0B; 13632c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood } 137dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer 138dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer switch (hdev->product) { 139dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: 140dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer if (*rsize == DFP_RDESC_ORIG_SIZE) { 141dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer hid_info(hdev, 142dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer "fixing up Logitech Driving Force Pro report descriptor\n"); 143dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer rdesc = dfp_rdesc_fixed; 144dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer *rsize = sizeof(dfp_rdesc_fixed); 145dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer } 146dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer break; 147dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer } 148dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer 14973e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashov return rdesc; 1505f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby} 1515f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 1525f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define lg_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \ 1535f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby EV_KEY, (c)) 1545f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 1555f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_ultrax_remote_mapping(struct hid_input *hi, 1565f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby struct hid_usage *usage, unsigned long **bit, int *max) 1575f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{ 1585f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR) 1595f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 0; 1605f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 1615f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby set_bit(EV_REP, hi->input->evbit); 1625f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby switch (usage->hid & HID_USAGE) { 1635f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby /* Reported on Logitech Ultra X Media Remote */ 1645f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x004: lg_map_key_clear(KEY_AGAIN); break; 1655f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x00d: lg_map_key_clear(KEY_HOME); break; 1665f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x024: lg_map_key_clear(KEY_SHUFFLE); break; 1675f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x025: lg_map_key_clear(KEY_TV); break; 1685f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x026: lg_map_key_clear(KEY_MENU); break; 1695f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x031: lg_map_key_clear(KEY_AUDIO); break; 1705f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x032: lg_map_key_clear(KEY_TEXT); break; 1715f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x033: lg_map_key_clear(KEY_LAST); break; 1725f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x047: lg_map_key_clear(KEY_MP3); break; 1735f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x048: lg_map_key_clear(KEY_DVD); break; 1745f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x049: lg_map_key_clear(KEY_MEDIA); break; 1755f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x04a: lg_map_key_clear(KEY_VIDEO); break; 1765f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x04b: lg_map_key_clear(KEY_ANGLE); break; 1775f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x04c: lg_map_key_clear(KEY_LANGUAGE); break; 1785f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x04d: lg_map_key_clear(KEY_SUBTITLE); break; 1795f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x051: lg_map_key_clear(KEY_RED); break; 1805f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x052: lg_map_key_clear(KEY_CLOSE); break; 1815f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 1825f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby default: 1835f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 0; 1845f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby } 1855f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 1; 1865f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby} 1875f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 18866d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosinastatic int lg_dinovo_mapping(struct hid_input *hi, struct hid_usage *usage, 18966d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina unsigned long **bit, int *max) 19066d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina{ 19166d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR) 19266d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina return 0; 19366d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina 19466d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina switch (usage->hid & HID_USAGE) { 19566d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina 19666d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina case 0x00d: lg_map_key_clear(KEY_MEDIA); break; 19766d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina default: 19866d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina return 0; 19966d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina 20066d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina } 20166d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina return 1; 20266d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina} 20366d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina 2045f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage, 2055f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby unsigned long **bit, int *max) 2065f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{ 2075f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) 2085f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 0; 2095f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 2105f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby switch (usage->hid & HID_USAGE) { 2115f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1001: lg_map_key_clear(KEY_MESSENGER); break; 2125f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1003: lg_map_key_clear(KEY_SOUND); break; 2135f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1004: lg_map_key_clear(KEY_VIDEO); break; 2145f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1005: lg_map_key_clear(KEY_AUDIO); break; 2155f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x100a: lg_map_key_clear(KEY_DOCUMENTS); break; 21618392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli /* The following two entries are Playlist 1 and 2 on the MX3200 */ 21718392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli case 0x100f: lg_map_key_clear(KEY_FN_1); break; 21818392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli case 0x1010: lg_map_key_clear(KEY_FN_2); break; 2195f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG); break; 2205f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1012: lg_map_key_clear(KEY_NEXTSONG); break; 2215f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1013: lg_map_key_clear(KEY_CAMERA); break; 2225f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1014: lg_map_key_clear(KEY_MESSENGER); break; 2235f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1015: lg_map_key_clear(KEY_RECORD); break; 2245f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1016: lg_map_key_clear(KEY_PLAYER); break; 2255f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1017: lg_map_key_clear(KEY_EJECTCD); break; 2265f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1018: lg_map_key_clear(KEY_MEDIA); break; 2275f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1019: lg_map_key_clear(KEY_PROG1); break; 2285f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x101a: lg_map_key_clear(KEY_PROG2); break; 2295f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x101b: lg_map_key_clear(KEY_PROG3); break; 23018392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli case 0x101c: lg_map_key_clear(KEY_CYCLEWINDOWS); break; 2315f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x101f: lg_map_key_clear(KEY_ZOOMIN); break; 2325f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1020: lg_map_key_clear(KEY_ZOOMOUT); break; 2335f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1021: lg_map_key_clear(KEY_ZOOMRESET); break; 2345f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1023: lg_map_key_clear(KEY_CLOSE); break; 2355f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1027: lg_map_key_clear(KEY_MENU); break; 2365f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby /* this one is marked as 'Rotate' */ 2375f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1028: lg_map_key_clear(KEY_ANGLE); break; 2385f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1029: lg_map_key_clear(KEY_SHUFFLE); break; 2395f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x102a: lg_map_key_clear(KEY_BACK); break; 2405f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS); break; 24118392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli case 0x102d: lg_map_key_clear(KEY_WWW); break; 24218392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli /* The following two are 'Start/answer call' and 'End/reject call' 24318392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli on the MX3200 */ 24418392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli case 0x1031: lg_map_key_clear(KEY_OK); break; 24518392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli case 0x1032: lg_map_key_clear(KEY_CANCEL); break; 2465f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1041: lg_map_key_clear(KEY_BATTERY); break; 2475f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR); break; 2485f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1043: lg_map_key_clear(KEY_SPREADSHEET); break; 2495f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1044: lg_map_key_clear(KEY_PRESENTATION); break; 2505f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1045: lg_map_key_clear(KEY_UNDO); break; 2515f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1046: lg_map_key_clear(KEY_REDO); break; 2525f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1047: lg_map_key_clear(KEY_PRINT); break; 2535f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1048: lg_map_key_clear(KEY_SAVE); break; 2545f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1049: lg_map_key_clear(KEY_PROG1); break; 2555f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x104a: lg_map_key_clear(KEY_PROG2); break; 2565f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x104b: lg_map_key_clear(KEY_PROG3); break; 2575f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x104c: lg_map_key_clear(KEY_PROG4); break; 2585f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 2595f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby default: 2605f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 0; 2615f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby } 2625f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 1; 2635f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby} 2645f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 2655f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi, 2665f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby struct hid_field *field, struct hid_usage *usage, 2675f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby unsigned long **bit, int *max) 2685f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{ 2695f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby /* extended mapping for certain Logitech hardware (Logitech cordless 2705f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby desktop LX500) */ 2715f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby static const u8 e_keymap[] = { 2725f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 0,216, 0,213,175,156, 0, 0, 0, 0, 2735f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 144, 0, 0, 0, 0, 0, 0, 0, 0,212, 2745f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 174,167,152,161,112, 0, 0, 0,154, 0, 2755f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2765f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2775f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2785f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 0, 0, 0, 0, 0,183,184,185,186,187, 2795f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 188,189,190,191,192,193,194, 0, 0, 0 2805f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby }; 2815f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); 2825f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby unsigned int hid = usage->hid; 2835f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 2845f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER && 2855f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby lg_ultrax_remote_mapping(hi, usage, bit, max)) 2865f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 1; 2875f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 28866d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina if (hdev->product == USB_DEVICE_ID_DINOVO_MINI && 28966d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina lg_dinovo_mapping(hi, usage, bit, max)) 29066d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina return 1; 29166d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina 2925f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if ((quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max)) 2935f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 1; 2945f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 2955f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON) 2965f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 0; 2975f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 2985f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby hid &= HID_USAGE; 2995f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3005f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby /* Special handling for Logitech Cordless Desktop */ 3015f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if (field->application == HID_GD_MOUSE) { 3025f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if ((quirks & LG_IGNORE_DOUBLED_WHEEL) && 3035f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby (hid == 7 || hid == 8)) 3045f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return -1; 3055f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby } else { 3065f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if ((quirks & LG_EXPANDED_KEYMAP) && 3075f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby hid < ARRAY_SIZE(e_keymap) && 3085f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby e_keymap[hid] != 0) { 3095f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby hid_map_usage(hi, usage, bit, max, EV_KEY, 3105f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby e_keymap[hid]); 3115f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 1; 3125f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby } 3135f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby } 3145f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3155f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 0; 3165f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby} 3175f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3185f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi, 3195f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby struct hid_field *field, struct hid_usage *usage, 3205f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby unsigned long **bit, int *max) 3215f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{ 3225f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); 3235f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3245f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if ((quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY && 3255f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby (field->flags & HID_MAIN_ITEM_RELATIVE)) 3265f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby field->flags &= ~HID_MAIN_ITEM_RELATIVE; 3275f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3285f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if ((quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY || 3295f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby usage->type == EV_REL || usage->type == EV_ABS)) 3305f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby clear_bit(usage->code, *bit); 3315f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3325f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 0; 3335f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby} 3345f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3355f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_event(struct hid_device *hdev, struct hid_field *field, 3365f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby struct hid_usage *usage, __s32 value) 3375f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{ 3385f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); 3395f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3405f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if ((quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) { 3415f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby input_event(field->hidinput->input, usage->type, usage->code, 3425f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby -value); 3435f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 1; 3445f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby } 3455f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3465f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 0; 3475f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby} 3485f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3495f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) 3505f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{ 3515f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby unsigned long quirks = id->driver_data; 352606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby unsigned int connect_mask = HID_CONNECT_DEFAULT; 3535f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby int ret; 3545f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3555f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby hid_set_drvdata(hdev, (void *)quirks); 3565f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3575f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if (quirks & LG_NOGET) 3585f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby hdev->quirks |= HID_QUIRK_NOGET; 3595f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3605f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby ret = hid_parse(hdev); 3615f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if (ret) { 3624291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches hid_err(hdev, "parse failed\n"); 3635f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby goto err_free; 3645f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby } 3655f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3667362cd2286d2364cca6738b583668f64254fe04bMichal Malý if (quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4)) 367606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby connect_mask &= ~HID_CONNECT_FF; 368606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby 369606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby ret = hid_hw_start(hdev, connect_mask); 3705f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if (ret) { 3714291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches hid_err(hdev, "hw start failed\n"); 3725f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby goto err_free; 3735f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby } 3745f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3757362cd2286d2364cca6738b583668f64254fe04bMichal Malý /* Setup wireless link with Logitech Wii wheel */ 3767362cd2286d2364cca6738b583668f64254fe04bMichal Malý if(hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) { 37732c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood unsigned char buf[] = { 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 37832c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood 37932c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT); 38032c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood 38132c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood if (ret >= 0) { 38232c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood /* insert a little delay of 10 jiffies ~ 40ms */ 38332c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood wait_queue_head_t wait; 38432c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood init_waitqueue_head (&wait); 38532c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood wait_event_interruptible_timeout(wait, 0, 10); 38632c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood 38732c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood /* Select random Address */ 38832c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood buf[1] = 0xB2; 38932c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood get_random_bytes(&buf[2], 2); 39032c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood 39132c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT); 39232c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood } 39332c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood } 39432c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood 395606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby if (quirks & LG_FF) 396606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby lgff_init(hdev); 397606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby if (quirks & LG_FF2) 398606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby lg2ff_init(hdev); 39974f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein if (quirks & LG_FF3) 40074f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein lg3ff_init(hdev); 40132c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood if (quirks & LG_FF4) 40232c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood lg4ff_init(hdev); 403606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby 4045f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 0; 4055f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabyerr_free: 4065f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return ret; 4075f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby} 4085f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 40930bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malýstatic void lg_remove(struct hid_device *hdev) 41030bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý{ 41130bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); 41230bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý if(quirks & LG_FF4) 41330bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý lg4ff_deinit(hdev); 41430bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý 41530bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý hid_hw_stop(hdev); 41630bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý} 41730bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý 4185f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic const struct hid_device_id lg_devices[] = { 4195f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER), 4205f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_RDESC | LG_WIRELESS }, 4215f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER), 4225f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_RDESC | LG_WIRELESS }, 4235f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2), 4245f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_RDESC | LG_WIRELESS }, 4255f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 4265f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER), 4275f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_BAD_RELATIVE_KEYS }, 4285f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 4295f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP), 4305f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_DUPLICATE_USAGES }, 4315f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE), 4325f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_DUPLICATE_USAGES }, 4335f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI), 4345f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_DUPLICATE_USAGES }, 4355f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 4365f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD), 4375f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP }, 4385f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500), 4395f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP }, 4405f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 4415f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D), 4425f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_NOGET }, 4435f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL), 4447362cd2286d2364cca6738b583668f64254fe04bMichal Malý .driver_data = LG_NOGET | LG_FF4 }, 445606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby 4462c6118e43040034d80894daeba41960bf0035b31Hendrik Iben { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD), 4472c6118e43040034d80894daeba41960bf0035b31Hendrik Iben .driver_data = LG_FF2 }, 448606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD), 449606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby .driver_data = LG_FF }, 450606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2), 451606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby .driver_data = LG_FF }, 452606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D), 453606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby .driver_data = LG_FF }, 454606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO), 455606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby .driver_data = LG_FF }, 456606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL), 4577362cd2286d2364cca6738b583668f64254fe04bMichal Malý .driver_data = LG_FF4 }, 458606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2), 4597362cd2286d2364cca6738b583668f64254fe04bMichal Malý .driver_data = LG_FF4 }, 460243b706d8a71364ad6080328d45b73516c8af5f3Christophe Borivant { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL), 4617362cd2286d2364cca6738b583668f64254fe04bMichal Malý .driver_data = LG_FF4 }, 4627362cd2286d2364cca6738b583668f64254fe04bMichal Malý { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL), 4637362cd2286d2364cca6738b583668f64254fe04bMichal Malý .driver_data = LG_FF4 }, 464fdc6807fcd09416c5537f479e1dcd624118e234cPeter Gundermann { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL), 4657362cd2286d2364cca6738b583668f64254fe04bMichal Malý .driver_data = LG_FF4 }, 4665623a24a80814fe471e777f12b9dbbb0f77e002eJiri Kosina { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL), 4677362cd2286d2364cca6738b583668f64254fe04bMichal Malý .driver_data = LG_NOGET | LG_FF4 }, 46832c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL), 46932c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood .driver_data = LG_FF4 }, 470fd30ea8c871552ddd6a5e1c0886de8fef4df53bcJiri Kosina { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ), 471fd30ea8c871552ddd6a5e1c0886de8fef4df53bcJiri Kosina .driver_data = LG_FF }, 472606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2), 473606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby .driver_data = LG_FF2 }, 47474f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940), 47574f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein .driver_data = LG_FF3 }, 47624985cf68612a5617d396b0b188cec807641cde1Jiri Kosina { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR), 47724985cf68612a5617d396b0b188cec807641cde1Jiri Kosina .driver_data = LG_RDESC_REL_ABS }, 47824985cf68612a5617d396b0b188cec807641cde1Jiri Kosina { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER), 47924985cf68612a5617d396b0b188cec807641cde1Jiri Kosina .driver_data = LG_RDESC_REL_ABS }, 4805f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { } 4815f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}; 48224985cf68612a5617d396b0b188cec807641cde1Jiri Kosina 4835f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri SlabyMODULE_DEVICE_TABLE(hid, lg_devices); 4845f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 4855f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic struct hid_driver lg_driver = { 4865f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .name = "logitech", 4875f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .id_table = lg_devices, 4885f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .report_fixup = lg_report_fixup, 4895f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .input_mapping = lg_input_mapping, 4905f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .input_mapped = lg_input_mapped, 4915f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .event = lg_event, 4925f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .probe = lg_probe, 49330bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý .remove = lg_remove, 4945f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}; 4955f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 496a24f423bdf253ccee369adc6c5451b40a0716fbbPeter Huewestatic int __init lg_init(void) 4975f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{ 4985f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return hid_register_driver(&lg_driver); 4995f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby} 5005f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 501a24f423bdf253ccee369adc6c5451b40a0716fbbPeter Huewestatic void __exit lg_exit(void) 5025f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{ 5035f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby hid_unregister_driver(&lg_driver); 5045f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby} 5055f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 5065f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabymodule_init(lg_init); 5075f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabymodule_exit(lg_exit); 5085f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri SlabyMODULE_LICENSE("GPL"); 509