From a0bf0ea809ba0a7621e191ec4cab5775d502ef7e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 9 Sep 2010 21:57:17 -0700 Subject: Input: hid-input - switch to using new keycode interface Switch HID code to use new style of getkeycode and setkeycode methods to allow retrieving and setting keycodes not only by their scancodes but also by index. Acked-by: Jiri Kosina Signed-off-by: Dmitry Torokhov --- drivers/hid/hid-input.c | 103 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 70 insertions(+), 33 deletions(-) (limited to 'drivers/hid/hid-input.c') diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 6c03dcc5760a..b12c07e64fbd 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -68,39 +68,49 @@ static const struct { #define map_key_clear(c) hid_map_usage_clear(hidinput, usage, &bit, \ &max, EV_KEY, (c)) -static inline int match_scancode(unsigned int code, unsigned int scancode) +static bool match_scancode(struct hid_usage *usage, + unsigned int cur_idx, unsigned int scancode) { - if (scancode == 0) - return 1; - - return (code & (HID_USAGE_PAGE | HID_USAGE)) == scancode; + return (usage->hid & (HID_USAGE_PAGE | HID_USAGE)) == scancode; } -static inline int match_keycode(unsigned int code, unsigned int keycode) +static bool match_keycode(struct hid_usage *usage, + unsigned int cur_idx, unsigned int keycode) { - if (keycode == 0) - return 1; + return usage->code == keycode; +} - return code == keycode; +static bool match_index(struct hid_usage *usage, + unsigned int cur_idx, unsigned int idx) +{ + return cur_idx == idx; } +typedef bool (*hid_usage_cmp_t)(struct hid_usage *usage, + unsigned int cur_idx, unsigned int val); + static struct hid_usage *hidinput_find_key(struct hid_device *hid, - unsigned int scancode, - unsigned int keycode) + hid_usage_cmp_t match, + unsigned int value, + unsigned int *usage_idx) { - int i, j, k; + unsigned int i, j, k, cur_idx = 0; struct hid_report *report; struct hid_usage *usage; for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) { list_for_each_entry(report, &hid->report_enum[k].report_list, list) { for (i = 0; i < report->maxfield; i++) { - for ( j = 0; j < report->field[i]->maxusage; j++) { + for (j = 0; j < report->field[i]->maxusage; j++) { usage = report->field[i]->usage + j; - if (usage->type == EV_KEY && - match_scancode(usage->hid, scancode) && - match_keycode(usage->code, keycode)) - return usage; + if (usage->type == EV_KEY) { + if (match(usage, cur_idx, value)) { + if (usage_idx) + *usage_idx = cur_idx; + return usage; + } + cur_idx++; + } } } } @@ -108,39 +118,66 @@ static struct hid_usage *hidinput_find_key(struct hid_device *hid, return NULL; } +static struct hid_usage *hidinput_locate_usage(struct hid_device *hid, + const struct input_keymap_entry *ke, + unsigned int *index) +{ + struct hid_usage *usage; + unsigned int scancode; + + if (ke->flags & INPUT_KEYMAP_BY_INDEX) + usage = hidinput_find_key(hid, match_index, ke->index, index); + else if (input_scancode_to_scalar(ke, &scancode) == 0) + usage = hidinput_find_key(hid, match_scancode, scancode, index); + else + usage = NULL; + + return usage; +} + static int hidinput_getkeycode(struct input_dev *dev, - unsigned int scancode, unsigned int *keycode) + struct input_keymap_entry *ke) { struct hid_device *hid = input_get_drvdata(dev); struct hid_usage *usage; + unsigned int scancode, index; - usage = hidinput_find_key(hid, scancode, 0); + usage = hidinput_locate_usage(hid, ke, &index); if (usage) { - *keycode = usage->code; + ke->keycode = usage->code; + ke->index = index; + scancode = usage->hid & (HID_USAGE_PAGE | HID_USAGE); + ke->len = sizeof(scancode); + memcpy(ke->scancode, &scancode, sizeof(scancode)); return 0; } + return -EINVAL; } static int hidinput_setkeycode(struct input_dev *dev, - unsigned int scancode, unsigned int keycode) + const struct input_keymap_entry *ke, + unsigned int *old_keycode) { struct hid_device *hid = input_get_drvdata(dev); struct hid_usage *usage; - int old_keycode; - usage = hidinput_find_key(hid, scancode, 0); + usage = hidinput_locate_usage(hid, ke, NULL); if (usage) { - old_keycode = usage->code; - usage->code = keycode; + *old_keycode = usage->code; + usage->code = ke->keycode; - clear_bit(old_keycode, dev->keybit); + 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); - /* Set the keybit for the old keycode if the old keycode is used - * by another key */ - if (hidinput_find_key (hid, 0, old_keycode)) - set_bit(old_keycode, dev->keybit); + dbg_hid(KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", + usage->code, usage->hid); + + /* + * Set the keybit for the old keycode if the old keycode is used + * by another key + */ + if (hidinput_find_key(hid, match_keycode, *old_keycode, NULL)) + set_bit(*old_keycode, dev->keybit); return 0; } @@ -748,8 +785,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) hid->ll_driver->hidinput_input_event; input_dev->open = hidinput_open; input_dev->close = hidinput_close; - input_dev->setkeycode = hidinput_setkeycode; - input_dev->getkeycode = hidinput_getkeycode; + input_dev->setkeycode_new = hidinput_setkeycode; + input_dev->getkeycode_new = hidinput_getkeycode; input_dev->name = hid->name; input_dev->phys = hid->phys; -- cgit v1.2.3 From f5854fad395b93071292bff27c0121b6e32215e0 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 15 Sep 2010 19:36:56 -0700 Subject: Input: hid-input - allow mapping unknown usages Currently HID layer only allows to remap keycodes for known usages, and responds with -EINVAL when user tries to map new usage code. This precludes us form relying on udev/keymap for establishing correct mappings and forces us to write dummy HID drivers responsible only for setting up keymaps. Let's allow remapping not only usages that have been set up as keys (usage->type == EV_KEY) but also yet-unmapped usages (usage->type == 0). Acked-by: Jarod Wilson Acked-by: Jiri Kosina Signed-off-by: Dmitry Torokhov --- drivers/hid/hid-input.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/hid/hid-input.c') diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index b12c07e64fbd..04121beed358 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -77,7 +77,10 @@ static bool match_scancode(struct hid_usage *usage, static bool match_keycode(struct hid_usage *usage, unsigned int cur_idx, unsigned int keycode) { - return usage->code == keycode; + /* + * We should exclude unmapped usages when doing lookup by keycode. + */ + return (usage->type == EV_KEY && usage->code == keycode); } static bool match_index(struct hid_usage *usage, @@ -103,7 +106,7 @@ static struct hid_usage *hidinput_find_key(struct hid_device *hid, for (i = 0; i < report->maxfield; i++) { for (j = 0; j < report->field[i]->maxusage; j++) { usage = report->field[i]->usage + j; - if (usage->type == EV_KEY) { + if (usage->type == EV_KEY || usage->type == 0) { if (match(usage, cur_idx, value)) { if (usage_idx) *usage_idx = cur_idx; @@ -144,7 +147,8 @@ static int hidinput_getkeycode(struct input_dev *dev, usage = hidinput_locate_usage(hid, ke, &index); if (usage) { - ke->keycode = usage->code; + ke->keycode = usage->type == EV_KEY ? + usage->code : KEY_RESERVED; ke->index = index; scancode = usage->hid & (HID_USAGE_PAGE | HID_USAGE); ke->len = sizeof(scancode); @@ -164,7 +168,8 @@ static int hidinput_setkeycode(struct input_dev *dev, usage = hidinput_locate_usage(hid, ke, NULL); if (usage) { - *old_keycode = usage->code; + *old_keycode = usage->type == EV_KEY ? + usage->code : KEY_RESERVED; usage->code = ke->keycode; clear_bit(*old_keycode, dev->keybit); -- cgit v1.2.3 From 587d145200f26758940099fbbc301fdd43d3f391 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 25 Oct 2010 19:44:21 -0700 Subject: HID: Remove KERN_DEBUG from dbg_hid use Signed-off-by: Joe Perches Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/hid/hid-input.c') diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 834ef47b76d6..76e1f64e9765 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -136,7 +136,8 @@ static int hidinput_setkeycode(struct input_dev *dev, 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); + dbg_hid("Assigned keycode %d to HID usage code %x\n", + keycode, scancode); /* Set the keybit for the old keycode if the old keycode is used * by another key */ if (hidinput_find_key (hid, 0, old_keycode)) -- cgit v1.2.3 From 83ed79c561da20019cb24944f535530d73b2d615 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 2 Dec 2010 11:49:06 +0100 Subject: HID: length resolution should be reported units/mm Input ABI requires reporting resolution on main axes in units per millimeter, not units per inch, so we need to convert accordingly. Tested-by: Nikolai Kondrashov Acked-by: Nikolai Kondrashov Signed-off-by: Dmitry Torokhov Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers/hid/hid-input.c') diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 76e1f64e9765..30af8760174b 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -162,8 +162,8 @@ static int hidinput_setkeycode(struct input_dev *dev, * * as seen in the HID specification v1.11 6.2.2.7 Global Items. * - * Only exponent 1 length units are processed. Centimeters are converted to - * inches. Degrees are converted to radians. + * Only exponent 1 length units are processed. Centimeters and inches are + * converted to millimeters. Degrees are converted to radians. */ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code) { @@ -184,13 +184,16 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code) */ if (code == ABS_X || code == ABS_Y || code == ABS_Z) { if (field->unit == 0x11) { /* If centimeters */ - /* Convert to inches */ - prev = logical_extents; - logical_extents *= 254; - if (logical_extents < prev) + /* Convert to millimeters */ + unit_exponent += 1; + } else if (field->unit == 0x13) { /* If inches */ + /* Convert to millimeters */ + prev = physical_extents; + physical_extents *= 254; + if (physical_extents < prev) return 0; - unit_exponent += 2; - } else if (field->unit != 0x13) { /* If not inches */ + unit_exponent -= 1; + } else { return 0; } } else if (code == ABS_RX || code == ABS_RY || code == ABS_RZ) { -- cgit v1.2.3