HID: add support for Microsoft Natural Ergonomic Keyboard 4000
authorJiri Kosina <jkosina@suse.cz>
Thu, 9 Aug 2007 11:24:11 +0000 (13:24 +0200)
committerJiri Kosina <jkosina@suse.cz>
Sun, 14 Oct 2007 11:40:00 +0000 (13:40 +0200)
This keyboard emits a few usages that are not handled properly by
hid-input.

The usages from MSVENDOR page are colliding with Chicony Tactical
Pad device, so we have to distinguish in runtime. Ugly ...

Also, the buttons 1-5 have to be handled in a non-standard way,
as they are emitted by the keyboard in a bitfield-like fashion, but
the field is not presented as bit-field by the keyboard. The keys can't
be pressed simultaneously, so the handling we have is correct.

This patch also extends hid_keyboard[] with KPLeftParenthesis and
KPRightParenthesis as defined by Keyboard page in HUT 1.12. The
corresponding usages are also emitted by this keyboard.

Signed-off-by: Jiri Kosina <jkosina@suse.cz>
drivers/hid/hid-debug.c
drivers/hid/hid-input.c

index a13757b..27e4cf0 100644 (file)
@@ -697,7 +697,7 @@ 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_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",
index 8edbd30..00f3260 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_NEK4K(x) (x->vendor == 0x045e && x->product == 0x00db)
+
 #ifdef CONFIG_USB_HIDINPUT_POWERBOOK
 
 struct hidinput_key_translation {
@@ -614,6 +618,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                                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 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 +725,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 +749,20 @@ 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_NEK4K(device)) {
+                               switch(usage->hid & HID_USAGE) {
+                                       case 0xff05:
+                                               set_bit(EV_REP, input->evbit);
+                                               map_key_clear(BTN_0);
+                                               set_bit(BTN_1, input->keybit);
+                                               set_bit(BTN_2, input->keybit);
+                                               set_bit(BTN_3, input->keybit);
+                                               set_bit(BTN_4, input->keybit);
+                                               set_bit(BTN_5, input->keybit);
+                                       default:        goto ignore;
+                               }
                        } else {
                                goto ignore;
                        }
@@ -991,6 +1017,26 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
                return;
        }
 
+       /* Handling MS NEK4K special buttons */
+       if (IS_MS_NEK4K(hid) && usage->hid == (HID_UP_MSVENDOR | 0xff05)) {
+               int key = 0;
+               static int last_key = 0;
+               switch (value) {
+                       case 0x01: key = BTN_1; break;
+                       case 0x02: key = BTN_2; break;
+                       case 0x04: key = BTN_3; break;
+                       case 0x08: key = BTN_4; break;
+                       case 0x10: key = BTN_5; break;
+                       default: break;
+               }
+               if (key) {
+                       input_event(input, usage->type, key, 1);
+                       last_key = key;
+               } else {
+                       input_event(input, usage->type, last_key, 0);
+               }
+       }
+
        input_event(input, usage->type, usage->code, value);
 
        if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY))