hid-lg.c revision 2b24a960016b8d3221a6dd2764ab97247c48dd97
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{ 1128577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev); 1135f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 1148577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý if ((drv_data->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 } 1218577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý if ((drv_data->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 } 1288577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý if ((drv_data->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 }; 2818577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý struct lg_drv_data *drv_data = (struct lg_drv_data *)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 2928577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý if ((drv_data->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) { 3028577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý if ((drv_data->quirks & LG_IGNORE_DOUBLED_WHEEL) && 3035f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby (hid == 7 || hid == 8)) 3045f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return -1; 3055f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby } else { 3068577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý if ((drv_data->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{ 3228577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev); 3235f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3248577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý if ((drv_data->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 3288577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý if ((drv_data->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{ 3388577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev); 3395f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3408577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý if ((drv_data->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 } 3452b24a960016b8d3221a6dd2764ab97247c48dd97Michal Malý if (drv_data->quirks & LG_FF4) { 3462b24a960016b8d3221a6dd2764ab97247c48dd97Michal Malý return lg4ff_adjust_input_event(hdev, field, usage, value, drv_data); 3472b24a960016b8d3221a6dd2764ab97247c48dd97Michal Malý } 3485f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3495f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 0; 3505f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby} 3515f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3525f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) 3535f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{ 354606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby unsigned int connect_mask = HID_CONNECT_DEFAULT; 3558577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý struct lg_drv_data *drv_data; 3565f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby int ret; 3575f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3588577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL); 3598577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý if (!drv_data) { 3608577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý hid_err(hdev, "Insufficient memory, cannot allocate driver data\n"); 3618577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý return -ENOMEM; 3628577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý } 3638577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý drv_data->quirks = id->driver_data; 3648577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý 3658577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý hid_set_drvdata(hdev, (void *)drv_data); 3665f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3678577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý if (drv_data->quirks & LG_NOGET) 3685f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby hdev->quirks |= HID_QUIRK_NOGET; 3695f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3705f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby ret = hid_parse(hdev); 3715f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if (ret) { 3724291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches hid_err(hdev, "parse failed\n"); 3735f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby goto err_free; 3745f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby } 3755f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3768577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý if (drv_data->quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4)) 377606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby connect_mask &= ~HID_CONNECT_FF; 378606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby 379606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby ret = hid_hw_start(hdev, connect_mask); 3805f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if (ret) { 3814291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches hid_err(hdev, "hw start failed\n"); 3825f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby goto err_free; 3835f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby } 3845f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3857362cd2286d2364cca6738b583668f64254fe04bMichal Malý /* Setup wireless link with Logitech Wii wheel */ 3867362cd2286d2364cca6738b583668f64254fe04bMichal Malý if(hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) { 38732c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood unsigned char buf[] = { 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 38832c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood 38932c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT); 39032c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood 39132c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood if (ret >= 0) { 39232c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood /* insert a little delay of 10 jiffies ~ 40ms */ 39332c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood wait_queue_head_t wait; 39432c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood init_waitqueue_head (&wait); 39532c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood wait_event_interruptible_timeout(wait, 0, 10); 39632c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood 39732c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood /* Select random Address */ 39832c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood buf[1] = 0xB2; 39932c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood get_random_bytes(&buf[2], 2); 40032c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood 40132c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT); 40232c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood } 40332c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood } 40432c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood 4058577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý if (drv_data->quirks & LG_FF) 406606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby lgff_init(hdev); 4078577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý if (drv_data->quirks & LG_FF2) 408606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby lg2ff_init(hdev); 4098577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý if (drv_data->quirks & LG_FF3) 41074f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein lg3ff_init(hdev); 4118577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý if (drv_data->quirks & LG_FF4) 41232c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood lg4ff_init(hdev); 413606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby 4145f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 0; 4155f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabyerr_free: 4168577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý kfree(drv_data); 4175f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return ret; 4185f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby} 4195f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 42030bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malýstatic void lg_remove(struct hid_device *hdev) 42130bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý{ 4228577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev); 4238577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý if (drv_data->quirks & LG_FF4) 42430bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý lg4ff_deinit(hdev); 42530bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý 42630bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý hid_hw_stop(hdev); 4278577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý kfree(drv_data); 42830bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý} 42930bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý 4305f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic const struct hid_device_id lg_devices[] = { 4315f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER), 4325f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_RDESC | LG_WIRELESS }, 4335f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER), 4345f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_RDESC | LG_WIRELESS }, 4355f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2), 4365f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_RDESC | LG_WIRELESS }, 4375f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 4385f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER), 4395f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_BAD_RELATIVE_KEYS }, 4405f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 4415f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP), 4425f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_DUPLICATE_USAGES }, 4435f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE), 4445f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_DUPLICATE_USAGES }, 4455f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI), 4465f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_DUPLICATE_USAGES }, 4475f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 4485f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD), 4495f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP }, 4505f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500), 4515f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP }, 4525f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 4535f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D), 4545f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_NOGET }, 4555f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL), 4567362cd2286d2364cca6738b583668f64254fe04bMichal Malý .driver_data = LG_NOGET | LG_FF4 }, 457606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby 4582c6118e43040034d80894daeba41960bf0035b31Hendrik Iben { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD), 4592c6118e43040034d80894daeba41960bf0035b31Hendrik Iben .driver_data = LG_FF2 }, 460606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD), 461606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby .driver_data = LG_FF }, 462606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2), 463606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby .driver_data = LG_FF }, 464606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D), 465606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby .driver_data = LG_FF }, 466606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO), 467606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby .driver_data = LG_FF }, 468606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL), 4697362cd2286d2364cca6738b583668f64254fe04bMichal Malý .driver_data = LG_FF4 }, 470606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2), 4717362cd2286d2364cca6738b583668f64254fe04bMichal Malý .driver_data = LG_FF4 }, 472243b706d8a71364ad6080328d45b73516c8af5f3Christophe Borivant { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL), 4737362cd2286d2364cca6738b583668f64254fe04bMichal Malý .driver_data = LG_FF4 }, 4747362cd2286d2364cca6738b583668f64254fe04bMichal Malý { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL), 4757362cd2286d2364cca6738b583668f64254fe04bMichal Malý .driver_data = LG_FF4 }, 476fdc6807fcd09416c5537f479e1dcd624118e234cPeter Gundermann { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL), 4777362cd2286d2364cca6738b583668f64254fe04bMichal Malý .driver_data = LG_FF4 }, 4785623a24a80814fe471e777f12b9dbbb0f77e002eJiri Kosina { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL), 4797362cd2286d2364cca6738b583668f64254fe04bMichal Malý .driver_data = LG_NOGET | LG_FF4 }, 48032c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL), 48132c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood .driver_data = LG_FF4 }, 482fd30ea8c871552ddd6a5e1c0886de8fef4df53bcJiri Kosina { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ), 483fd30ea8c871552ddd6a5e1c0886de8fef4df53bcJiri Kosina .driver_data = LG_FF }, 484606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2), 485606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby .driver_data = LG_FF2 }, 48674f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940), 48774f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein .driver_data = LG_FF3 }, 48824985cf68612a5617d396b0b188cec807641cde1Jiri Kosina { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR), 48924985cf68612a5617d396b0b188cec807641cde1Jiri Kosina .driver_data = LG_RDESC_REL_ABS }, 49024985cf68612a5617d396b0b188cec807641cde1Jiri Kosina { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER), 49124985cf68612a5617d396b0b188cec807641cde1Jiri Kosina .driver_data = LG_RDESC_REL_ABS }, 4925f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { } 4935f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}; 49424985cf68612a5617d396b0b188cec807641cde1Jiri Kosina 4955f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri SlabyMODULE_DEVICE_TABLE(hid, lg_devices); 4965f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 4975f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic struct hid_driver lg_driver = { 4985f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .name = "logitech", 4995f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .id_table = lg_devices, 5005f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .report_fixup = lg_report_fixup, 5015f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .input_mapping = lg_input_mapping, 5025f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .input_mapped = lg_input_mapped, 5035f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .event = lg_event, 5045f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .probe = lg_probe, 50530bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý .remove = lg_remove, 5065f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}; 5075f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 508a24f423bdf253ccee369adc6c5451b40a0716fbbPeter Huewestatic int __init lg_init(void) 5095f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{ 5105f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return hid_register_driver(&lg_driver); 5115f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby} 5125f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 513a24f423bdf253ccee369adc6c5451b40a0716fbbPeter Huewestatic void __exit lg_exit(void) 5145f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{ 5155f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby hid_unregister_driver(&lg_driver); 5165f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby} 5175f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 5185f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabymodule_init(lg_init); 5195f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabymodule_exit(lg_exit); 5205f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri SlabyMODULE_LICENSE("GPL"); 521