hid-lg.c revision 73e4008ddddc84d5f2499c17012b340a0dae153e
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 105f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby */ 115f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 125f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby/* 135f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * This program is free software; you can redistribute it and/or modify it 145f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * under the terms of the GNU General Public License as published by the Free 155f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * Software Foundation; either version 2 of the License, or (at your option) 165f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * any later version. 175f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby */ 185f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 195f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#include <linux/device.h> 205f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#include <linux/hid.h> 215f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#include <linux/module.h> 225f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 235f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#include "hid-ids.h" 24606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby#include "hid-lg.h" 255f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 265f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_RDESC 0x001 275f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_BAD_RELATIVE_KEYS 0x002 285f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_DUPLICATE_USAGES 0x004 295f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_EXPANDED_KEYMAP 0x010 305f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_IGNORE_DOUBLED_WHEEL 0x020 315f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_WIRELESS 0x040 325f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_INVERT_HWHEEL 0x080 335f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_NOGET 0x100 34606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby#define LG_FF 0x200 35606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby#define LG_FF2 0x400 3624985cf68612a5617d396b0b188cec807641cde1Jiri Kosina#define LG_RDESC_REL_ABS 0x800 3774f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein#define LG_FF3 0x1000 385f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 395f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby/* 405f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * Certain Logitech keyboards send in report #3 keys which are far 415f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * above the logical maximum described in descriptor. This extends 425f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * the original value of 0x28c of logical maximum to 0x104d 435f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby */ 4473e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashovstatic __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc, 4573e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashov unsigned int *rsize) 465f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{ 475f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); 485f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 4973e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashov if ((quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 && 505f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby rdesc[84] == 0x8c && rdesc[85] == 0x02) { 515f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby dev_info(&hdev->dev, "fixing up Logitech keyboard report " 525f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby "descriptor\n"); 535f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby rdesc[84] = rdesc[89] = 0x4d; 545f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby rdesc[85] = rdesc[90] = 0x10; 555f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby } 5673e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashov if ((quirks & LG_RDESC_REL_ABS) && *rsize >= 50 && 5724985cf68612a5617d396b0b188cec807641cde1Jiri Kosina rdesc[32] == 0x81 && rdesc[33] == 0x06 && 5824985cf68612a5617d396b0b188cec807641cde1Jiri Kosina rdesc[49] == 0x81 && rdesc[50] == 0x06) { 5924985cf68612a5617d396b0b188cec807641cde1Jiri Kosina dev_info(&hdev->dev, "fixing up rel/abs in Logitech " 6024985cf68612a5617d396b0b188cec807641cde1Jiri Kosina "report descriptor\n"); 6124985cf68612a5617d396b0b188cec807641cde1Jiri Kosina rdesc[33] = rdesc[50] = 0x02; 6224985cf68612a5617d396b0b188cec807641cde1Jiri Kosina } 6373e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashov return rdesc; 645f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby} 655f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 665f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define lg_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \ 675f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby EV_KEY, (c)) 685f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 695f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_ultrax_remote_mapping(struct hid_input *hi, 705f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby struct hid_usage *usage, unsigned long **bit, int *max) 715f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{ 725f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR) 735f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 0; 745f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 755f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby set_bit(EV_REP, hi->input->evbit); 765f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby switch (usage->hid & HID_USAGE) { 775f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby /* Reported on Logitech Ultra X Media Remote */ 785f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x004: lg_map_key_clear(KEY_AGAIN); break; 795f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x00d: lg_map_key_clear(KEY_HOME); break; 805f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x024: lg_map_key_clear(KEY_SHUFFLE); break; 815f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x025: lg_map_key_clear(KEY_TV); break; 825f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x026: lg_map_key_clear(KEY_MENU); break; 835f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x031: lg_map_key_clear(KEY_AUDIO); break; 845f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x032: lg_map_key_clear(KEY_TEXT); break; 855f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x033: lg_map_key_clear(KEY_LAST); break; 865f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x047: lg_map_key_clear(KEY_MP3); break; 875f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x048: lg_map_key_clear(KEY_DVD); break; 885f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x049: lg_map_key_clear(KEY_MEDIA); break; 895f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x04a: lg_map_key_clear(KEY_VIDEO); break; 905f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x04b: lg_map_key_clear(KEY_ANGLE); break; 915f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x04c: lg_map_key_clear(KEY_LANGUAGE); break; 925f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x04d: lg_map_key_clear(KEY_SUBTITLE); break; 935f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x051: lg_map_key_clear(KEY_RED); break; 945f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x052: lg_map_key_clear(KEY_CLOSE); break; 955f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 965f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby default: 975f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 0; 985f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby } 995f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 1; 1005f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby} 1015f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 10266d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosinastatic int lg_dinovo_mapping(struct hid_input *hi, struct hid_usage *usage, 10366d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina unsigned long **bit, int *max) 10466d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina{ 10566d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR) 10666d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina return 0; 10766d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina 10866d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina switch (usage->hid & HID_USAGE) { 10966d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina 11066d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina case 0x00d: lg_map_key_clear(KEY_MEDIA); break; 11166d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina default: 11266d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina return 0; 11366d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina 11466d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina } 11566d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina return 1; 11666d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina} 11766d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina 1185f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage, 1195f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby unsigned long **bit, int *max) 1205f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{ 1215f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) 1225f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 0; 1235f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 1245f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby switch (usage->hid & HID_USAGE) { 1255f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1001: lg_map_key_clear(KEY_MESSENGER); break; 1265f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1003: lg_map_key_clear(KEY_SOUND); break; 1275f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1004: lg_map_key_clear(KEY_VIDEO); break; 1285f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1005: lg_map_key_clear(KEY_AUDIO); break; 1295f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x100a: lg_map_key_clear(KEY_DOCUMENTS); break; 13018392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli /* The following two entries are Playlist 1 and 2 on the MX3200 */ 13118392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli case 0x100f: lg_map_key_clear(KEY_FN_1); break; 13218392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli case 0x1010: lg_map_key_clear(KEY_FN_2); break; 1335f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG); break; 1345f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1012: lg_map_key_clear(KEY_NEXTSONG); break; 1355f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1013: lg_map_key_clear(KEY_CAMERA); break; 1365f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1014: lg_map_key_clear(KEY_MESSENGER); break; 1375f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1015: lg_map_key_clear(KEY_RECORD); break; 1385f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1016: lg_map_key_clear(KEY_PLAYER); break; 1395f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1017: lg_map_key_clear(KEY_EJECTCD); break; 1405f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1018: lg_map_key_clear(KEY_MEDIA); break; 1415f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1019: lg_map_key_clear(KEY_PROG1); break; 1425f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x101a: lg_map_key_clear(KEY_PROG2); break; 1435f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x101b: lg_map_key_clear(KEY_PROG3); break; 14418392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli case 0x101c: lg_map_key_clear(KEY_CYCLEWINDOWS); break; 1455f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x101f: lg_map_key_clear(KEY_ZOOMIN); break; 1465f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1020: lg_map_key_clear(KEY_ZOOMOUT); break; 1475f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1021: lg_map_key_clear(KEY_ZOOMRESET); break; 1485f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1023: lg_map_key_clear(KEY_CLOSE); break; 1495f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1027: lg_map_key_clear(KEY_MENU); break; 1505f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby /* this one is marked as 'Rotate' */ 1515f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1028: lg_map_key_clear(KEY_ANGLE); break; 1525f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1029: lg_map_key_clear(KEY_SHUFFLE); break; 1535f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x102a: lg_map_key_clear(KEY_BACK); break; 1545f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS); break; 15518392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli case 0x102d: lg_map_key_clear(KEY_WWW); break; 15618392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli /* The following two are 'Start/answer call' and 'End/reject call' 15718392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli on the MX3200 */ 15818392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli case 0x1031: lg_map_key_clear(KEY_OK); break; 15918392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli case 0x1032: lg_map_key_clear(KEY_CANCEL); break; 1605f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1041: lg_map_key_clear(KEY_BATTERY); break; 1615f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR); break; 1625f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1043: lg_map_key_clear(KEY_SPREADSHEET); break; 1635f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1044: lg_map_key_clear(KEY_PRESENTATION); break; 1645f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1045: lg_map_key_clear(KEY_UNDO); break; 1655f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1046: lg_map_key_clear(KEY_REDO); break; 1665f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1047: lg_map_key_clear(KEY_PRINT); break; 1675f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1048: lg_map_key_clear(KEY_SAVE); break; 1685f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x1049: lg_map_key_clear(KEY_PROG1); break; 1695f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x104a: lg_map_key_clear(KEY_PROG2); break; 1705f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x104b: lg_map_key_clear(KEY_PROG3); break; 1715f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby case 0x104c: lg_map_key_clear(KEY_PROG4); break; 1725f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 1735f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby default: 1745f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 0; 1755f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby } 1765f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 1; 1775f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby} 1785f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 1795f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi, 1805f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby struct hid_field *field, struct hid_usage *usage, 1815f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby unsigned long **bit, int *max) 1825f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{ 1835f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby /* extended mapping for certain Logitech hardware (Logitech cordless 1845f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby desktop LX500) */ 1855f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby static const u8 e_keymap[] = { 1865f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 0,216, 0,213,175,156, 0, 0, 0, 0, 1875f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 144, 0, 0, 0, 0, 0, 0, 0, 0,212, 1885f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 174,167,152,161,112, 0, 0, 0,154, 0, 1895f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1905f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1915f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1925f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 0, 0, 0, 0, 0,183,184,185,186,187, 1935f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 188,189,190,191,192,193,194, 0, 0, 0 1945f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby }; 1955f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); 1965f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby unsigned int hid = usage->hid; 1975f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 1985f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER && 1995f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby lg_ultrax_remote_mapping(hi, usage, bit, max)) 2005f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 1; 2015f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 20266d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina if (hdev->product == USB_DEVICE_ID_DINOVO_MINI && 20366d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina lg_dinovo_mapping(hi, usage, bit, max)) 20466d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina return 1; 20566d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina 2065f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if ((quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max)) 2075f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 1; 2085f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 2095f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON) 2105f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 0; 2115f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 2125f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby hid &= HID_USAGE; 2135f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 2145f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby /* Special handling for Logitech Cordless Desktop */ 2155f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if (field->application == HID_GD_MOUSE) { 2165f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if ((quirks & LG_IGNORE_DOUBLED_WHEEL) && 2175f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby (hid == 7 || hid == 8)) 2185f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return -1; 2195f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby } else { 2205f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if ((quirks & LG_EXPANDED_KEYMAP) && 2215f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby hid < ARRAY_SIZE(e_keymap) && 2225f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby e_keymap[hid] != 0) { 2235f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby hid_map_usage(hi, usage, bit, max, EV_KEY, 2245f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby e_keymap[hid]); 2255f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 1; 2265f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby } 2275f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby } 2285f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 2295f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 0; 2305f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby} 2315f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 2325f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi, 2335f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby struct hid_field *field, struct hid_usage *usage, 2345f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby unsigned long **bit, int *max) 2355f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{ 2365f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); 2375f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 2385f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if ((quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY && 2395f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby (field->flags & HID_MAIN_ITEM_RELATIVE)) 2405f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby field->flags &= ~HID_MAIN_ITEM_RELATIVE; 2415f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 2425f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if ((quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY || 2435f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby usage->type == EV_REL || usage->type == EV_ABS)) 2445f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby clear_bit(usage->code, *bit); 2455f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 2465f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 0; 2475f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby} 2485f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 2495f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_event(struct hid_device *hdev, struct hid_field *field, 2505f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby struct hid_usage *usage, __s32 value) 2515f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{ 2525f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); 2535f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 2545f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if ((quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) { 2555f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby input_event(field->hidinput->input, usage->type, usage->code, 2565f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby -value); 2575f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 1; 2585f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby } 2595f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 2605f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 0; 2615f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby} 2625f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 2635f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) 2645f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{ 2655f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby unsigned long quirks = id->driver_data; 266606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby unsigned int connect_mask = HID_CONNECT_DEFAULT; 2675f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby int ret; 2685f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 2695f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby hid_set_drvdata(hdev, (void *)quirks); 2705f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 2715f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if (quirks & LG_NOGET) 2725f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby hdev->quirks |= HID_QUIRK_NOGET; 2735f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 2745f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby ret = hid_parse(hdev); 2755f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if (ret) { 2765f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby dev_err(&hdev->dev, "parse failed\n"); 2775f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby goto err_free; 2785f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby } 2795f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 28074f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein if (quirks & (LG_FF | LG_FF2 | LG_FF3)) 281606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby connect_mask &= ~HID_CONNECT_FF; 282606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby 283606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby ret = hid_hw_start(hdev, connect_mask); 2845f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby if (ret) { 2855f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby dev_err(&hdev->dev, "hw start failed\n"); 2865f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby goto err_free; 2875f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby } 2885f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 289606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby if (quirks & LG_FF) 290606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby lgff_init(hdev); 291606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby if (quirks & LG_FF2) 292606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby lg2ff_init(hdev); 29374f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein if (quirks & LG_FF3) 29474f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein lg3ff_init(hdev); 295606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby 2965f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return 0; 2975f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabyerr_free: 2985f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return ret; 2995f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby} 3005f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3015f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic const struct hid_device_id lg_devices[] = { 3025f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER), 3035f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_RDESC | LG_WIRELESS }, 3045f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER), 3055f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_RDESC | LG_WIRELESS }, 3065f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2), 3075f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_RDESC | LG_WIRELESS }, 3085f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3095f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER), 3105f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_BAD_RELATIVE_KEYS }, 3115f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3125f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP), 3135f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_DUPLICATE_USAGES }, 3145f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE), 3155f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_DUPLICATE_USAGES }, 3165f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI), 3175f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_DUPLICATE_USAGES }, 3185f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3195f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD), 3205f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP }, 3215f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500), 3225f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP }, 3235f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3245f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D), 3255f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .driver_data = LG_NOGET }, 3265f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL), 327606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby .driver_data = LG_NOGET | LG_FF }, 328606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby 329606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD), 330606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby .driver_data = LG_FF }, 331606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2), 332606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby .driver_data = LG_FF }, 333606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D), 334606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby .driver_data = LG_FF }, 335606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO), 336606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby .driver_data = LG_FF }, 337606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL), 338606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby .driver_data = LG_FF }, 339606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2), 340606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby .driver_data = LG_FF }, 341243b706d8a71364ad6080328d45b73516c8af5f3Christophe Borivant { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL), 342243b706d8a71364ad6080328d45b73516c8af5f3Christophe Borivant .driver_data = LG_FF }, 343fd30ea8c871552ddd6a5e1c0886de8fef4df53bcJiri Kosina { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ), 344fd30ea8c871552ddd6a5e1c0886de8fef4df53bcJiri Kosina .driver_data = LG_FF }, 345606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2), 346606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby .driver_data = LG_FF2 }, 34774f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940), 34874f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein .driver_data = LG_FF3 }, 34924985cf68612a5617d396b0b188cec807641cde1Jiri Kosina { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR), 35024985cf68612a5617d396b0b188cec807641cde1Jiri Kosina .driver_data = LG_RDESC_REL_ABS }, 35124985cf68612a5617d396b0b188cec807641cde1Jiri Kosina { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER), 35224985cf68612a5617d396b0b188cec807641cde1Jiri Kosina .driver_data = LG_RDESC_REL_ABS }, 3535f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby { } 3545f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}; 35524985cf68612a5617d396b0b188cec807641cde1Jiri Kosina 3565f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri SlabyMODULE_DEVICE_TABLE(hid, lg_devices); 3575f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3585f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic struct hid_driver lg_driver = { 3595f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .name = "logitech", 3605f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .id_table = lg_devices, 3615f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .report_fixup = lg_report_fixup, 3625f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .input_mapping = lg_input_mapping, 3635f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .input_mapped = lg_input_mapped, 3645f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .event = lg_event, 3655f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby .probe = lg_probe, 3665f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}; 3675f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 368a24f423bdf253ccee369adc6c5451b40a0716fbbPeter Huewestatic int __init lg_init(void) 3695f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{ 3705f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby return hid_register_driver(&lg_driver); 3715f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby} 3725f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 373a24f423bdf253ccee369adc6c5451b40a0716fbbPeter Huewestatic void __exit lg_exit(void) 3745f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{ 3755f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby hid_unregister_driver(&lg_driver); 3765f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby} 3775f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby 3785f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabymodule_init(lg_init); 3795f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabymodule_exit(lg_exit); 3805f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri SlabyMODULE_LICENSE("GPL"); 381