From 1fe8736da695c2b14961438c73d5600538bd92d9 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Thu, 9 Aug 2007 13:24:11 +0200 Subject: [PATCH] HID: add support for Microsoft Natural Ergonomic Keyboard 4000 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 --- drivers/hid/hid-debug.c | 2 +- drivers/hid/hid-input.c | 52 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index a13757b78980..27e4cf003834 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -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", diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 8edbd30cf795..00f326012a31 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -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)) -- GitLab