diff options
-rw-r--r-- | drivers/hid/hid-input.c | 33 | ||||
-rw-r--r-- | include/linux/hid.h | 2 |
2 files changed, 33 insertions, 2 deletions
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 6836a856c243..04056773102e 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1100,8 +1100,31 @@ mapped: set_bit(usage->type, input->evbit); - while (usage->code <= max && test_and_set_bit(usage->code, bit)) - usage->code = find_next_zero_bit(bit, max + 1, usage->code); + /* + * This part is *really* controversial: + * - HID aims at being generic so we should do our best to export + * all incoming events + * - HID describes what events are, so there is no reason for ABS_X + * to be mapped to ABS_Y + * - HID is using *_MISC+N as a default value, but nothing prevents + * *_MISC+N to overwrite a legitimate even, which confuses userspace + * (for instance ABS_MISC + 7 is ABS_MT_SLOT, which has a different + * processing) + * + * If devices still want to use this (at their own risk), they will + * have to use the quirk HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE, but + * the default should be a reliable mapping. + */ + while (usage->code <= max && test_and_set_bit(usage->code, bit)) { + if (device->quirks & HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE) { + usage->code = find_next_zero_bit(bit, + max + 1, + usage->code); + } else { + device->status |= HID_STAT_DUP_DETECTED; + goto ignore; + } + } if (usage->code > max) goto ignore; @@ -1611,6 +1634,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) INIT_LIST_HEAD(&hid->inputs); INIT_WORK(&hid->led_work, hidinput_led_worker); + hid->status &= ~HID_STAT_DUP_DETECTED; + if (!force) { for (i = 0; i < hid->maxcollection; i++) { struct hid_collection *col = &hid->collection[i]; @@ -1677,6 +1702,10 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) goto out_unwind; } + if (hid->status & HID_STAT_DUP_DETECTED) + hid_dbg(hid, + "Some usages could not be mapped, please use HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE if this is legitimate.\n"); + return 0; out_unwind: diff --git a/include/linux/hid.h b/include/linux/hid.h index 8da3e1f48195..0267aa5c1ea3 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -345,6 +345,7 @@ struct hid_item { #define HID_QUIRK_SKIP_OUTPUT_REPORT_ID BIT(17) #define HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP BIT(18) #define HID_QUIRK_HAVE_SPECIAL_DRIVER BIT(19) +#define HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE BIT(20) #define HID_QUIRK_FULLSPEED_INTERVAL BIT(28) #define HID_QUIRK_NO_INIT_REPORTS BIT(29) #define HID_QUIRK_NO_IGNORE BIT(30) @@ -502,6 +503,7 @@ struct hid_output_fifo { #define HID_STAT_ADDED BIT(0) #define HID_STAT_PARSED BIT(1) +#define HID_STAT_DUP_DETECTED BIT(2) struct hid_input { struct list_head list; |