Merge branch 'hidraw' into for-linus
authorJiri Kosina <jkosina@suse.cz>
Sun, 14 Oct 2007 12:47:56 +0000 (14:47 +0200)
committerJiri Kosina <jkosina@suse.cz>
Sun, 14 Oct 2007 12:47:56 +0000 (14:47 +0200)
drivers/hid/hid-debug.c
drivers/hid/hid-input.c
drivers/hid/usbhid/Kconfig
drivers/hid/usbhid/hid-core.c
drivers/hid/usbhid/hid-ff.c
drivers/hid/usbhid/hid-plff.c
drivers/hid/usbhid/hid-quirks.c
drivers/hid/usbhid/hid-tmff.c
drivers/hid/usbhid/hiddev.c
include/linux/hid.h
include/linux/input.h

index a13757b7898028986f98739eecfb3649be96bdfd..5c24fe46d8eb9c423637888f163e70dedb2281c2 100644 (file)
@@ -34,7 +34,7 @@
 struct hid_usage_entry {
        unsigned  page;
        unsigned  usage;
-       char     *description;
+       const char     *description;
 };
 
 static const struct hid_usage_entry hid_usage_table[] = {
@@ -365,8 +365,8 @@ void hid_resolv_usage(unsigned usage) {
 }
 EXPORT_SYMBOL_GPL(hid_resolv_usage);
 
-__inline__ static void tab(int n) {
-       while (n--) printk(" ");
+static void tab(int n) {
+       printk(KERN_DEBUG "%*s", n, "");
 }
 
 void hid_dump_field(struct hid_field *field, int n) {
@@ -401,8 +401,8 @@ void hid_dump_field(struct hid_field *field, int n) {
                tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent);
        }
        if (field->unit) {
-               char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" };
-               char *units[5][8] = {
+               static const char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" };
+               static const char *units[5][8] = {
                        { "None", "None", "None", "None", "None", "None", "None", "None" },
                        { "None", "Centimeter", "Gram", "Seconds", "Kelvin",     "Ampere", "Candela", "None" },
                        { "None", "Radians",    "Gram", "Seconds", "Kelvin",     "Ampere", "Candela", "None" },
@@ -457,7 +457,7 @@ void hid_dump_field(struct hid_field *field, int n) {
        printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute ");
        printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : "");
        printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : "");
-       printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPrefferedState " : "");
+       printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPreferredState " : "");
        printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : "");
        printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : "");
        printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : "");
@@ -470,7 +470,7 @@ void hid_dump_device(struct hid_device *device) {
        struct hid_report *report;
        struct list_head *list;
        unsigned i,k;
-       static char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
+       static const char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
 
        if (!hid_debug)
                return;
@@ -501,13 +501,13 @@ void hid_dump_input(struct hid_usage *usage, __s32 value) {
        if (!hid_debug)
                return;
 
-       printk("hid-debug: input ");
+       printk(KERN_DEBUG "hid-debug: input ");
        hid_resolv_usage(usage->hid);
        printk(" = %d\n", value);
 }
 EXPORT_SYMBOL_GPL(hid_dump_input);
 
-static char *events[EV_MAX + 1] = {
+static const char *events[EV_MAX + 1] = {
        [EV_SYN] = "Sync",                      [EV_KEY] = "Key",
        [EV_REL] = "Relative",                  [EV_ABS] = "Absolute",
        [EV_MSC] = "Misc",                      [EV_LED] = "LED",
@@ -516,10 +516,10 @@ static char *events[EV_MAX + 1] = {
        [EV_FF_STATUS] = "ForceFeedbackStatus",
 };
 
-static char *syncs[2] = {
+static const char *syncs[2] = {
        [SYN_REPORT] = "Report",                [SYN_CONFIG] = "Config",
 };
-static char *keys[KEY_MAX + 1] = {
+static const char *keys[KEY_MAX + 1] = {
        [KEY_RESERVED] = "Reserved",            [KEY_ESC] = "Esc",
        [KEY_1] = "1",                          [KEY_2] = "2",
        [KEY_3] = "3",                          [KEY_4] = "4",
@@ -697,7 +697,8 @@ static char *keys[KEY_MAX + 1] = {
        [KEY_DEL_LINE] = "DeleteLine",
        [KEY_SEND] = "Send",                    [KEY_REPLY] = "Reply",
        [KEY_FORWARDMAIL] = "ForwardMail",      [KEY_SAVE] = "Save",
-       [KEY_DOCUMENTS] = "Documents",
+       [KEY_DOCUMENTS] = "Documents",          [KEY_SPELLCHECK] = "SpellCheck",
+       [KEY_LOGOFF] = "Logoff",
        [KEY_FN] = "Fn",                        [KEY_FN_ESC] = "Fn+ESC",
        [KEY_FN_1] = "Fn+1",                    [KEY_FN_2] = "Fn+2",
        [KEY_FN_B] = "Fn+B",                    [KEY_FN_D] = "Fn+D",
@@ -715,7 +716,7 @@ static char *keys[KEY_MAX + 1] = {
        [KEY_SWITCHVIDEOMODE] = "SwitchVideoMode",
 };
 
-static char *relatives[REL_MAX + 1] = {
+static const char *relatives[REL_MAX + 1] = {
        [REL_X] = "X",                  [REL_Y] = "Y",
        [REL_Z] = "Z",                  [REL_RX] = "Rx",
        [REL_RY] = "Ry",                [REL_RZ] = "Rz",
@@ -723,7 +724,7 @@ static char *relatives[REL_MAX + 1] = {
        [REL_WHEEL] = "Wheel",          [REL_MISC] = "Misc",
 };
 
-static char *absolutes[ABS_MAX + 1] = {
+static const char *absolutes[ABS_MAX + 1] = {
        [ABS_X] = "X",                  [ABS_Y] = "Y",
        [ABS_Z] = "Z",                  [ABS_RX] = "Rx",
        [ABS_RY] = "Ry",                [ABS_RZ] = "Rz",
@@ -739,12 +740,12 @@ static char *absolutes[ABS_MAX + 1] = {
        [ABS_VOLUME] = "Volume",        [ABS_MISC] = "Misc",
 };
 
-static char *misc[MSC_MAX + 1] = {
+static const char *misc[MSC_MAX + 1] = {
        [MSC_SERIAL] = "Serial",        [MSC_PULSELED] = "Pulseled",
        [MSC_GESTURE] = "Gesture",      [MSC_RAW] = "RawData"
 };
 
-static char *leds[LED_MAX + 1] = {
+static const char *leds[LED_MAX + 1] = {
        [LED_NUML] = "NumLock",         [LED_CAPSL] = "CapsLock",
        [LED_SCROLLL] = "ScrollLock",   [LED_COMPOSE] = "Compose",
        [LED_KANA] = "Kana",            [LED_SLEEP] = "Sleep",
@@ -752,16 +753,16 @@ static char *leds[LED_MAX + 1] = {
        [LED_MISC] = "Misc",
 };
 
-static char *repeats[REP_MAX + 1] = {
+static const char *repeats[REP_MAX + 1] = {
        [REP_DELAY] = "Delay",          [REP_PERIOD] = "Period"
 };
 
-static char *sounds[SND_MAX + 1] = {
+static const char *sounds[SND_MAX + 1] = {
        [SND_CLICK] = "Click",          [SND_BELL] = "Bell",
        [SND_TONE] = "Tone"
 };
 
-static char **names[EV_MAX + 1] = {
+static const char **names[EV_MAX + 1] = {
        [EV_SYN] = syncs,                       [EV_KEY] = keys,
        [EV_REL] = relatives,                   [EV_ABS] = absolutes,
        [EV_MSC] = misc,                        [EV_LED] = leds,
@@ -777,4 +778,3 @@ void hid_resolv_event(__u8 type, __u16 code) {
                names[type] ? (names[type][code] ? names[type][code] : "?") : "?");
 }
 EXPORT_SYMBOL_GPL(hid_resolv_event);
-
index 8edbd30cf7955bcb54e80d2ce42fe6f2f545b8e2..0c3e12c1794cf1ab5f331ecf16e97163cf761120 100644 (file)
@@ -53,7 +53,7 @@ static const unsigned char hid_keyboard[256] = {
        115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk,
        122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
        unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
-       unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
+       unk,unk,unk,unk,unk,unk,179,180,unk,unk,unk,unk,unk,unk,unk,unk,
        unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
        unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
         29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
@@ -86,6 +86,10 @@ static const struct {
 #define map_abs_clear(c)       do { map_abs(c); clear_bit(c, bit); } while (0)
 #define map_key_clear(c)       do { map_key(c); clear_bit(c, bit); } while (0)
 
+/* hardware needing special handling due to colliding MSVENDOR page usages */
+#define IS_CHICONY_TACTICAL_PAD(x) (x->vendor == 0x04f2 && device->product == 0x0418)
+#define IS_MS_KB(x) (x->vendor == 0x045e && (x->product == 0x00db || x->product == 0x00f9))
+
 #ifdef CONFIG_USB_HIDINPUT_POWERBOOK
 
 struct hidinput_key_translation {
@@ -295,7 +299,7 @@ static int hidinput_getkeycode(struct input_dev *dev, int scancode,
 {
        struct hid_device *hid = dev->private;
        struct hid_usage *usage;
-       
+
        usage = hidinput_find_key(hid, scancode, 0);
        if (usage) {
                *keycode = usage->code;
@@ -310,15 +314,15 @@ static int hidinput_setkeycode(struct input_dev *dev, int scancode,
        struct hid_device *hid = dev->private;
        struct hid_usage *usage;
        int old_keycode;
-       
+
        if (keycode < 0 || keycode > KEY_MAX)
                return -EINVAL;
-       
+
        usage = hidinput_find_key(hid, scancode, 0);
        if (usage) {
                old_keycode = usage->code;
                usage->code = keycode;
-               
+
                clear_bit(old_keycode, dev->keybit);
                set_bit(usage->code, dev->keybit);
                dbg_hid(KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", keycode, scancode);
@@ -326,10 +330,10 @@ static int hidinput_setkeycode(struct input_dev *dev, int scancode,
                 * by another key */
                if (hidinput_find_key (hid, 0, old_keycode))
                        set_bit(old_keycode, dev->keybit);
-               
+
                return 0;
        }
-       
+
        return -EINVAL;
 }
 
@@ -351,6 +355,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
        if (field->flags & HID_MAIN_ITEM_CONSTANT)
                goto ignore;
 
+       /* only LED usages are supported in output fields */
+       if (field->report_type == HID_OUTPUT_REPORT &&
+                       (usage->hid & HID_USAGE_PAGE) != HID_UP_LED) {
+               dbg_hid_line(" [non-LED output field] ");
+               goto ignore;
+       }
+
        switch (usage->hid & HID_USAGE_PAGE) {
 
                case HID_UP_UNDEFINED:
@@ -595,6 +606,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                                case 0x0f6: map_key_clear(KEY_NEXT);            break;
                                case 0x0fa: map_key_clear(KEY_BACK);            break;
 
+                               case 0x182: map_key_clear(KEY_BOOKMARKS);       break;
                                case 0x183: map_key_clear(KEY_CONFIG);          break;
                                case 0x184: map_key_clear(KEY_WORDPROCESSOR);   break;
                                case 0x185: map_key_clear(KEY_EDITOR);          break;
@@ -611,9 +623,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                                case 0x192: map_key_clear(KEY_CALC);            break;
                                case 0x194: map_key_clear(KEY_FILE);            break;
                                case 0x196: map_key_clear(KEY_WWW);             break;
+                               case 0x19c: map_key_clear(KEY_LOGOFF);          break;
                                case 0x19e: map_key_clear(KEY_COFFEE);          break;
                                case 0x1a6: map_key_clear(KEY_HELP);            break;
                                case 0x1a7: map_key_clear(KEY_DOCUMENTS);       break;
+                               case 0x1ab: map_key_clear(KEY_SPELLCHECK);      break;
+                               case 0x1b6: map_key_clear(KEY_MEDIA);           break;
+                               case 0x1b7: map_key_clear(KEY_SOUND);           break;
                                case 0x1bc: map_key_clear(KEY_MESSENGER);       break;
                                case 0x1bd: map_key_clear(KEY_INFO);            break;
                                case 0x201: map_key_clear(KEY_NEW);             break;
@@ -720,8 +736,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 
                case HID_UP_MSVENDOR:
 
-                       /* special case - Chicony Chicony KU-0418 tactical pad */
-                       if (device->vendor == 0x04f2 && device->product == 0x0418) {
+                       /* Unfortunately, there are multiple devices which
+                        * emit usages from MSVENDOR page that require different
+                        * handling. If this list grows too much in the future,
+                        * more general handling will have to be introduced here
+                        * (i.e. another blacklist).
+                        */
+
+                       /* Chicony Chicony KU-0418 tactical pad */
+                       if (IS_CHICONY_TACTICAL_PAD(device)) {
                                set_bit(EV_REP, input->evbit);
                                switch(usage->hid & HID_USAGE) {
                                        case 0xff01: map_key_clear(BTN_1);              break;
@@ -737,6 +760,26 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                                        case 0xff0b: map_key_clear(BTN_B);              break;
                                        default:    goto ignore;
                                }
+
+                       /* Microsoft Natural Ergonomic Keyboard 4000 */
+                       } else if (IS_MS_KB(device)) {
+                               switch(usage->hid & HID_USAGE) {
+                                       case 0xfd06:
+                                               map_key_clear(KEY_CHAT);
+                                               break;
+                                       case 0xfd07:
+                                               map_key_clear(KEY_PHONE);
+                                               break;
+                                       case 0xff05:
+                                               set_bit(EV_REP, input->evbit);
+                                               map_key_clear(KEY_F13);
+                                               set_bit(KEY_F14, input->keybit);
+                                               set_bit(KEY_F15, input->keybit);
+                                               set_bit(KEY_F16, input->keybit);
+                                               set_bit(KEY_F17, input->keybit);
+                                               set_bit(KEY_F18, input->keybit);
+                                       default:        goto ignore;
+                               }
                        } else {
                                goto ignore;
                        }
@@ -888,6 +931,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                set_bit(KEY_VOLUMEDOWN, input->keybit);
        }
 
+       if (usage->type == EV_KEY) {
+               set_bit(EV_MSC, input->evbit);
+               set_bit(MSC_SCAN, input->mscbit);
+       }
+
        hid_resolv_event(usage->type, usage->code);
 
        dbg_hid_line("\n");
@@ -991,6 +1039,29 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
                return;
        }
 
+       /* Handling MS keyboards special buttons */
+       if (IS_MS_KB(hid) && usage->hid == (HID_UP_MSVENDOR | 0xff05)) {
+               int key = 0;
+               static int last_key = 0;
+               switch (value) {
+                       case 0x01: key = KEY_F14; break;
+                       case 0x02: key = KEY_F15; break;
+                       case 0x04: key = KEY_F16; break;
+                       case 0x08: key = KEY_F17; break;
+                       case 0x10: key = KEY_F18; break;
+                       default: break;
+               }
+               if (key) {
+                       input_event(input, usage->type, key, 1);
+                       last_key = key;
+               } else {
+                       input_event(input, usage->type, last_key, 0);
+               }
+       }
+       /* report the usage code as scancode if the key status has changed */
+       if (usage->type == EV_KEY && !!test_bit(usage->code, input->key) != value)
+               input_event(input, EV_MSC, MSC_SCAN, usage->hid);
+
        input_event(input, usage->type, usage->code, value);
 
        if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY))
@@ -1051,6 +1122,9 @@ int hidinput_connect(struct hid_device *hid)
        int i, j, k;
        int max_report_type = HID_OUTPUT_REPORT;
 
+       if (hid->quirks & HID_QUIRK_IGNORE_HIDINPUT)
+               return -1;
+
        INIT_LIST_HEAD(&hid->inputs);
 
        for (i = 0; i < hid->maxcollection; i++)
index 1b4b572f899ba6c1f23fbb6c9685687fddfb4a99..c557d7040a69a946ea91458ef8724dab85247c2a 100644 (file)
@@ -71,19 +71,20 @@ config LOGITECH_FF
          force feedback.
 
 config PANTHERLORD_FF
-       bool "PantherLord USB/PS2 2in1 Adapter support"
+       bool "PantherLord/GreenAsia based device support"
        depends on HID_FF
        select INPUT_FF_MEMLESS if USB_HID
        help
-         Say Y here if you have a PantherLord USB/PS2 2in1 Adapter and want
-         to enable force feedback support for it.
+         Say Y here if you have a PantherLord/GreenAsia based game controller
+         or adapter and want to enable force feedback support for it.
 
 config THRUSTMASTER_FF
-       bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)"
+       bool "ThrustMaster devices support (EXPERIMENTAL)"
        depends on HID_FF && EXPERIMENTAL
        select INPUT_FF_MEMLESS if USB_HID
        help
-         Say Y here if you have a THRUSTMASTER FireStore Dual Power 2,
+         Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
+         a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel,
          and want to enable force feedback support for it.
          Note: if you say N here, this device will still be supported, but without
          force feedback.
index 3a9563195850d04f0459d2cdede688058a2d9c03..b38e559b7a46073dab466375200002828f7602ab 100644 (file)
@@ -513,7 +513,16 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
 
 int usbhid_open(struct hid_device *hid)
 {
-       ++hid->open;
+       struct usbhid_device *usbhid = hid->driver_data;
+       int res;
+
+       if (!hid->open++) {
+               res = usb_autopm_get_interface(usbhid->intf);
+               if (res < 0) {
+                       hid->open--;
+                       return -EIO;
+               }
+       }
        if (hid_start_in(hid))
                hid_io_error(hid);
        return 0;
@@ -523,8 +532,10 @@ void usbhid_close(struct hid_device *hid)
 {
        struct usbhid_device *usbhid = hid->driver_data;
 
-       if (!--hid->open)
+       if (!--hid->open) {
                usb_kill_urb(usbhid->urbin);
+               usb_autopm_put_interface(usbhid->intf);
+       }
 }
 
 /*
@@ -1082,6 +1093,7 @@ static struct usb_driver hid_driver = {
        .pre_reset =    hid_pre_reset,
        .post_reset =   hid_post_reset,
        .id_table =     hid_usb_ids,
+       .supports_autosuspend = 1,
 };
 
 static int __init hid_init(void)
index 23431fbbc3d7e7030976357721785c9f0dcb1e6d..22329feb3b5ae63d7b65a3e561f263da7935342d 100644 (file)
@@ -62,11 +62,14 @@ static struct hid_ff_initializer inits[] = {
        { 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */
 #endif
 #ifdef CONFIG_PANTHERLORD_FF
-       { 0x810, 0x0001, hid_plff_init },
+       { 0x810, 0x0001, hid_plff_init }, /* "Twin USB Joystick" */
+       { 0xe8f, 0x0003, hid_plff_init }, /* "GreenAsia Inc.    USB Joystick     " */
 #endif
 #ifdef CONFIG_THRUSTMASTER_FF
        { 0x44f, 0xb300, hid_tmff_init },
        { 0x44f, 0xb304, hid_tmff_init },
+       { 0x44f, 0xb651, hid_tmff_init }, /* FGT Rumble Force Wheel */
+       { 0x44f, 0xb654, hid_tmff_init }, /* FGT Force Feedback Wheel */
 #endif
 #ifdef CONFIG_ZEROPLUS_FF
        { 0xc12, 0x0005, hid_zpff_init },
index d6a8f2b49bd242c3b6875320cfe32f4c5ba099a8..9eb83cf9d22b98021d540b61f08be3a690f45466 100644 (file)
@@ -1,5 +1,15 @@
 /*
- *  Force feedback support for PantherLord USB/PS2 2in1 Adapter devices
+ *  Force feedback support for PantherLord/GreenAsia based devices
+ *
+ *  The devices are distributed under various names and the same USB device ID
+ *  can be used in both adapters and actual game controllers.
+ *
+ *  0810:0001 "Twin USB Joystick"
+ *   - tested with PantherLord USB/PS2 2in1 Adapter
+ *   - contains two reports, one for each port (HID_QUIRK_MULTI_INPUT)
+ *
+ *  0e8f:0003 "GreenAsia Inc.    USB Joystick     "
+ *   - tested with Köng Gaming gamepad
  *
  *  Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com>
  */
@@ -67,11 +77,11 @@ int hid_plff_init(struct hid_device *hid)
        struct input_dev *dev;
        int error;
 
-       /* The device contains 2 output reports (one for each
-          HID_QUIRK_MULTI_INPUT device), both containing 1 field, which
-          contains 4 ff00.0002 usages and 4 16bit absolute values.
+       /* The device contains one output report per physical device, all
+          containing 1 field, which contains 4 ff00.0002 usages and 4 16bit
+          absolute values.
 
-          The input reports also contain a field which contains
+          The input reports also contain a field which contains
           8 ff00.0001 usages and 8 boolean values. Their meaning is
           currently unknown. */
 
@@ -122,8 +132,8 @@ int hid_plff_init(struct hid_device *hid)
                usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
        }
 
-       printk(KERN_INFO "hid-plff: Force feedback for PantherLord USB/PS2 "
-              "2in1 Adapters by Anssi Hannula <anssi.hannula@gmail.com>\n");
+       printk(KERN_INFO "hid-plff: Force feedback for PantherLord/GreenAsia "
+              "devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
 
        return 0;
 }
index 6b21a214f419028f212f238374d92687f1e3a556..41a59a80e7edff34299d0a0d3f93225eedc9381a 100644 (file)
@@ -61,6 +61,7 @@
 #define USB_DEVICE_ID_APPLE_GEYSER4_JIS        0x021c
 #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY   0x030a
 #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY    0x030b
+#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242
 
 #define USB_VENDOR_ID_ASUS             0x0b05
 #define USB_DEVICE_ID_ASUS_LCM         0x1726
@@ -86,6 +87,9 @@
 
 #define USB_VENDOR_ID_CIDC             0x1677
 
+#define USB_VENDOR_ID_CMEDIA           0x0d8c
+#define USB_DEVICE_ID_CM109            0x000e
+
 #define USB_VENDOR_ID_CODEMERCS                0x07c0
 #define USB_DEVICE_ID_CODEMERCS_IOW_FIRST      0x1500
 #define USB_DEVICE_ID_CODEMERCS_IOW_LAST       0x15ff
 #define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
 #define USB_DEVICE_ID_DELORME_EM_LT20  0x0200
 
+#define USB_VENDOR_ID_ELO              0x04E7
+#define USB_DEVICE_ID_ELO_TS2700       0x0020
+
 #define USB_VENDOR_ID_ESSENTIAL_REALITY        0x0d7f
 #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
 
 #define USB_VENDOR_ID_GAMERON          0x0810
 #define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR 0x0001
 
+#define USB_VENDOR_ID_GENERAL_TOUCH    0x0dfc
+
 #define USB_VENDOR_ID_GLAB             0x06c2
 #define USB_DEVICE_ID_4_PHIDGETSERVO_30        0x0038
 #define USB_DEVICE_ID_1_PHIDGETSERVO_30        0x0039
@@ -373,6 +382,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES },
 
        { USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV },
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT },
        { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT },
 
        { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE },
@@ -387,11 +397,16 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM, HID_QUIRK_IGNORE},
        { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GENERAL_TOUCH, 0x0001, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GENERAL_TOUCH, 0x0002, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GENERAL_TOUCH, 0x0003, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GENERAL_TOUCH, 0x0004, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE },
@@ -507,6 +522,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
+       { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
@@ -614,6 +630,8 @@ static const struct hid_rdesc_blacklist {
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_RDESC_LOGITECH },
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_RDESC_LOGITECH },
 
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_RDESC_MACBOOK_JIS },
+
        { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_RDESC_PETALYNX },
 
        { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_RDESC_SWAPPED_MIN_MAX },
@@ -927,6 +945,18 @@ static void usbhid_fixup_cypress_descriptor(unsigned char *rdesc, int rsize)
                printk(KERN_INFO "Fixing up Cypress report descriptor\n");
 }
 
+/*
+ * MacBook JIS keyboard has wrong logical maximum
+ */
+static void usbhid_fixup_macbook_descriptor(unsigned char *rdesc, int rsize)
+{
+       if (rsize >= 60 && rdesc[53] == 0x65
+                       && rdesc[59] == 0x65) {
+               printk(KERN_INFO "Fixing up MacBook JIS keyboard report descriptor\n");
+               rdesc[53] = rdesc[59] = 0xe7;
+       }
+}
+
 
 static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize)
 {
@@ -941,6 +971,9 @@ static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned
 
        if (quirks & HID_QUIRK_RDESC_PETALYNX)
                usbhid_fixup_petalynx_descriptor(rdesc, rsize);
+
+       if (quirks & HID_QUIRK_RDESC_MACBOOK_JIS)
+               usbhid_fixup_macbook_descriptor(rdesc, rsize);
 }
 
 /**
index 555bb48b4295d0d7ea167702ea125bcb4cbd1088..69882a726e99d8cc19b6fda183e2b0f9ca8de240 100644 (file)
 #include "usbhid.h"
 
 /* Usages for thrustmaster devices I know about */
-#define THRUSTMASTER_USAGE_RUMBLE_LR   (HID_UP_GENDESK | 0xbb)
+#define THRUSTMASTER_USAGE_FF  (HID_UP_GENDESK | 0xbb)
 
+struct dev_type {
+       u16 idVendor;
+       u16 idProduct;
+       const signed short *ff;
+};
+
+static const signed short ff_rumble[] = {
+       FF_RUMBLE,
+       -1
+};
+
+static const signed short ff_joystick[] = {
+       FF_CONSTANT,
+       -1
+};
+
+static const struct dev_type devices[] = {
+       { 0x44f, 0xb300, ff_rumble },
+       { 0x44f, 0xb304, ff_rumble },
+       { 0x44f, 0xb651, ff_rumble },   /* FGT Rumble Force Wheel */
+       { 0x44f, 0xb654, ff_joystick }, /* FGT Force Feedback Wheel */
+};
 
 struct tmff_device {
        struct hid_report *report;
-       struct hid_field *rumble;
+       struct hid_field *ff_field;
 };
 
 /* Changes values from 0 to 0xffff into values from minimum to maximum */
-static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum)
+static inline int hid_tmff_scale_u16(unsigned int in,
+                               int minimum, int maximum)
 {
        int ret;
 
@@ -57,22 +80,57 @@ static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum)
        return ret;
 }
 
+/* Changes values from -0x80 to 0x7f into values from minimum to maximum */
+static inline int hid_tmff_scale_s8(int in,
+                                   int minimum, int maximum)
+{
+       int ret;
+
+       ret = (((in + 0x80) * (maximum - minimum)) / 0xff) + minimum;
+       if (ret < minimum)
+               return minimum;
+       if (ret > maximum)
+               return maximum;
+       return ret;
+}
+
 static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
 {
        struct hid_device *hid = input_get_drvdata(dev);
        struct tmff_device *tmff = data;
+       struct hid_field *ff_field = tmff->ff_field;
+       int x, y;
        int left, right;        /* Rumbling */
 
-       left = hid_tmff_scale(effect->u.rumble.weak_magnitude,
-               tmff->rumble->logical_minimum, tmff->rumble->logical_maximum);
-       right = hid_tmff_scale(effect->u.rumble.strong_magnitude,
-               tmff->rumble->logical_minimum, tmff->rumble->logical_maximum);
-
-       tmff->rumble->value[0] = left;
-       tmff->rumble->value[1] = right;
-       dbg_hid("(left,right)=(%08x, %08x)\n", left, right);
-       usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
-
+       switch (effect->type) {
+       case FF_CONSTANT:
+               x = hid_tmff_scale_s8(effect->u.ramp.start_level,
+                                       ff_field->logical_minimum,
+                                       ff_field->logical_maximum);
+               y = hid_tmff_scale_s8(effect->u.ramp.end_level,
+                                       ff_field->logical_minimum,
+                                       ff_field->logical_maximum);
+
+               dbg_hid("(x, y)=(%04x, %04x)\n", x, y);
+               ff_field->value[0] = x;
+               ff_field->value[1] = y;
+               usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
+               break;
+
+       case FF_RUMBLE:
+               left = hid_tmff_scale_u16(effect->u.rumble.weak_magnitude,
+                                       ff_field->logical_minimum,
+                                       ff_field->logical_maximum);
+               right = hid_tmff_scale_u16(effect->u.rumble.strong_magnitude,
+                                       ff_field->logical_minimum,
+                                       ff_field->logical_maximum);
+
+               dbg_hid("(left,right)=(%08x, %08x)\n", left, right);
+               ff_field->value[0] = left;
+               ff_field->value[1] = right;
+               usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
+               break;
+       }
        return 0;
 }
 
@@ -82,14 +140,16 @@ int hid_tmff_init(struct hid_device *hid)
        struct list_head *pos;
        struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
        struct input_dev *input_dev = hidinput->input;
+       const signed short *ff_bits = ff_joystick;
        int error;
+       int i;
 
        tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL);
        if (!tmff)
                return -ENOMEM;
 
        /* Find the report to use */
-       __list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) {
+       list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) {
                struct hid_report *report = (struct hid_report *)pos;
                int fieldnum;
 
@@ -100,48 +160,65 @@ int hid_tmff_init(struct hid_device *hid)
                                continue;
 
                        switch (field->usage[0].hid) {
-                               case THRUSTMASTER_USAGE_RUMBLE_LR:
-                                       if (field->report_count < 2) {
-                                               warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR with report_count < 2");
-                                               continue;
-                                       }
+                       case THRUSTMASTER_USAGE_FF:
+                               if (field->report_count < 2) {
+                                       warn("ignoring FF field with report_count < 2");
+                                       continue;
+                               }
 
-                                       if (field->logical_maximum == field->logical_minimum) {
-                                               warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR with logical_maximum == logical_minimum");
-                                               continue;
-                                       }
+                               if (field->logical_maximum == field->logical_minimum) {
+                                       warn("ignoring FF field with logical_maximum == logical_minimum");
+                                       continue;
+                               }
 
-                                       if (tmff->report && tmff->report != report) {
-                                               warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR in other report");
-                                               continue;
-                                       }
+                               if (tmff->report && tmff->report != report) {
+                                       warn("ignoring FF field in other report");
+                                       continue;
+                               }
 
-                                       if (tmff->rumble && tmff->rumble != field) {
-                                               warn("ignoring duplicate THRUSTMASTER_USAGE_RUMBLE_LR");
-                                               continue;
+                               if (tmff->ff_field && tmff->ff_field != field) {
+                                       warn("ignoring duplicate FF field");
+                                       continue;
+                               }
+
+                               tmff->report = report;
+                               tmff->ff_field = field;
+
+                               for (i = 0; i < ARRAY_SIZE(devices); i++) {
+                                       if (input_dev->id.vendor == devices[i].idVendor &&
+                                           input_dev->id.product == devices[i].idProduct) {
+                                               ff_bits = devices[i].ff;
+                                               break;
                                        }
+                               }
 
-                                       tmff->report = report;
-                                       tmff->rumble = field;
+                               for (i = 0; ff_bits[i] >= 0; i++)
+                                       set_bit(ff_bits[i], input_dev->ffbit);
 
-                                       set_bit(FF_RUMBLE, input_dev->ffbit);
-                                       break;
+                               break;
 
-                               default:
-                                       warn("ignoring unknown output usage %08x", field->usage[0].hid);
-                                       continue;
+                       default:
+                               warn("ignoring unknown output usage %08x", field->usage[0].hid);
+                               continue;
                        }
                }
        }
 
-       error = input_ff_create_memless(input_dev, tmff, hid_tmff_play);
-       if (error) {
-               kfree(tmff);
-               return error;
+       if (!tmff->report) {
+               err("cant find FF field in output reports\n");
+               error = -ENODEV;
+               goto fail;
        }
 
-       info("Force feedback for ThrustMaster rumble pad devices by Zinx Verituse <zinx@epicsol.org>");
+       error = input_ff_create_memless(input_dev, tmff, hid_tmff_play);
+       if (error)
+               goto fail;
 
+       info("Force feedback for ThrustMaster devices by Zinx Verituse <zinx@epicsol.org>");
        return 0;
+
+ fail:
+       kfree(tmff);
+       return error;
 }
 
index e793127f971eae29903298b7cb6d3ec64a156325..9837adcb17e940478568fa33e89e194508c1cad1 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/usb.h>
 #include <linux/hid.h>
 #include <linux/hiddev.h>
+#include <linux/compat.h>
 #include "usbhid.h"
 
 #ifdef CONFIG_USB_DYNAMIC_MINORS
@@ -738,6 +739,14 @@ inval:
        return -EINVAL;
 }
 
+#ifdef CONFIG_COMPAT
+static long hiddev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct inode *inode = file->f_path.dentry->d_inode;
+       return hiddev_ioctl(inode, file, cmd, compat_ptr(arg));
+}
+#endif
+
 static const struct file_operations hiddev_fops = {
        .owner =        THIS_MODULE,
        .read =         hiddev_read,
@@ -747,6 +756,9 @@ static const struct file_operations hiddev_fops = {
        .release =      hiddev_release,
        .ioctl =        hiddev_ioctl,
        .fasync =       hiddev_fasync,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = hiddev_compat_ioctl,
+#endif
 };
 
 static struct usb_class_driver hiddev_class = {
index 0ac2b5260b26eb4c9d95c9d302777d1d67b71663..55e51f9f76cb70fddf29d69fa9ad66668910a9e4 100644 (file)
@@ -276,6 +276,7 @@ struct hid_item {
 #define HID_QUIRK_HIDINPUT                     0x00200000
 #define HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL        0x00400000
 #define HID_QUIRK_LOGITECH_EXPANDED_KEYMAP     0x00800000
+#define HID_QUIRK_IGNORE_HIDINPUT              0x01000000
 
 /*
  * Separate quirks for runtime report descriptor fixup
@@ -285,6 +286,7 @@ struct hid_item {
 #define HID_QUIRK_RDESC_LOGITECH               0x00000002
 #define HID_QUIRK_RDESC_SWAPPED_MIN_MAX                0x00000004
 #define HID_QUIRK_RDESC_PETALYNX               0x00000008
+#define HID_QUIRK_RDESC_MACBOOK_JIS            0x00000010
 
 /*
  * This is the global environment of the parser. This information is
index 6eb3aead7f1d93775ba4020e9d252df5210c757a..52d1bd434a500abb69f5cc94b8225bf856080f5d 100644 (file)
@@ -523,6 +523,8 @@ struct input_absinfo {
 #define KEY_ADDRESSBOOK                0x1ad   /* AL Contacts/Address Book */
 #define KEY_MESSENGER          0x1ae   /* AL Instant Messaging */
 #define KEY_DISPLAYTOGGLE      0x1af   /* Turn display (LCD) on and off */
+#define KEY_SPELLCHECK         0x1b0   /* AL Spell Check */
+#define KEY_LOGOFF             0x1b1   /* AL Logoff */
 
 #define KEY_DEL_EOL            0x1c0
 #define KEY_DEL_EOS            0x1c1
This page took 0.040199 seconds and 5 git commands to generate.