Commit 25721aef authored by Jiri Kosina's avatar Jiri Kosina

Merge branch 'for-4.18/multitouch' into for-linus

- improvement of duplicate usage handling in hid-input from Benjamin Tissoires
- Win 8.1 precisioun touchpad spec implementation from Benjamin Tissoires
parents 72d0beb4 abb36fe6
...@@ -57,7 +57,9 @@ MODULE_PARM_DESC(ignore_special_drivers, "Ignore any special drivers and handle ...@@ -57,7 +57,9 @@ MODULE_PARM_DESC(ignore_special_drivers, "Ignore any special drivers and handle
* Register a new report for a device. * Register a new report for a device.
*/ */
struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id) struct hid_report *hid_register_report(struct hid_device *device,
unsigned int type, unsigned int id,
unsigned int application)
{ {
struct hid_report_enum *report_enum = device->report_enum + type; struct hid_report_enum *report_enum = device->report_enum + type;
struct hid_report *report; struct hid_report *report;
...@@ -78,6 +80,7 @@ struct hid_report *hid_register_report(struct hid_device *device, unsigned type, ...@@ -78,6 +80,7 @@ struct hid_report *hid_register_report(struct hid_device *device, unsigned type,
report->type = type; report->type = type;
report->size = 0; report->size = 0;
report->device = device; report->device = device;
report->application = application;
report_enum->report_id_hash[id] = report; report_enum->report_id_hash[id] = report;
list_add_tail(&report->list, &report_enum->report_list); list_add_tail(&report->list, &report_enum->report_list);
...@@ -221,11 +224,15 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign ...@@ -221,11 +224,15 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
{ {
struct hid_report *report; struct hid_report *report;
struct hid_field *field; struct hid_field *field;
unsigned usages; unsigned int usages;
unsigned offset; unsigned int offset;
unsigned i; unsigned int i;
unsigned int application;
application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION);
report = hid_register_report(parser->device, report_type, parser->global.report_id); report = hid_register_report(parser->device, report_type,
parser->global.report_id, application);
if (!report) { if (!report) {
hid_err(parser->device, "hid_register_report failed\n"); hid_err(parser->device, "hid_register_report failed\n");
return -1; return -1;
...@@ -259,7 +266,7 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign ...@@ -259,7 +266,7 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL); field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL);
field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL); field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL);
field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION); field->application = application;
for (i = 0; i < usages; i++) { for (i = 0; i < usages; i++) {
unsigned j = i; unsigned j = i;
......
...@@ -56,6 +56,20 @@ static bool hid_generic_match(struct hid_device *hdev, ...@@ -56,6 +56,20 @@ static bool hid_generic_match(struct hid_device *hdev,
return true; return true;
} }
static int hid_generic_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
int ret;
hdev->quirks |= HID_QUIRK_INPUT_PER_APP;
ret = hid_parse(hdev);
if (ret)
return ret;
return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
}
static const struct hid_device_id hid_table[] = { static const struct hid_device_id hid_table[] = {
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, HID_ANY_ID, HID_ANY_ID) }, { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, HID_ANY_ID, HID_ANY_ID) },
{ } { }
...@@ -66,6 +80,7 @@ static struct hid_driver hid_generic = { ...@@ -66,6 +80,7 @@ static struct hid_driver hid_generic = {
.name = "hid-generic", .name = "hid-generic",
.id_table = hid_table, .id_table = hid_table,
.match = hid_generic_match, .match = hid_generic_match,
.probe = hid_generic_probe,
}; };
module_hid_driver(hid_generic); module_hid_driver(hid_generic);
......
...@@ -116,7 +116,7 @@ static int gfrm_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -116,7 +116,7 @@ static int gfrm_probe(struct hid_device *hdev, const struct hid_device_id *id)
* those reports reach gfrm_raw_event() from hid_input_report(). * those reports reach gfrm_raw_event() from hid_input_report().
*/ */
if (!hid_register_report(hdev, HID_INPUT_REPORT, if (!hid_register_report(hdev, HID_INPUT_REPORT,
GFRM100_SEARCH_KEY_REPORT_ID)) { GFRM100_SEARCH_KEY_REPORT_ID, 0)) {
ret = -ENOMEM; ret = -ENOMEM;
goto done; goto done;
} }
......
...@@ -1110,8 +1110,31 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -1110,8 +1110,31 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
set_bit(usage->type, input->evbit); 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) if (usage->code > max)
goto ignore; goto ignore;
...@@ -1487,15 +1510,56 @@ static void report_features(struct hid_device *hid) ...@@ -1487,15 +1510,56 @@ static void report_features(struct hid_device *hid)
} }
} }
static struct hid_input *hidinput_allocate(struct hid_device *hid) static struct hid_input *hidinput_allocate(struct hid_device *hid,
unsigned int application)
{ {
struct hid_input *hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL); struct hid_input *hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL);
struct input_dev *input_dev = input_allocate_device(); struct input_dev *input_dev = input_allocate_device();
if (!hidinput || !input_dev) { const char *suffix = NULL;
kfree(hidinput);
input_free_device(input_dev); if (!hidinput || !input_dev)
hid_err(hid, "Out of memory during hid input probe\n"); goto fail;
return NULL;
if ((hid->quirks & HID_QUIRK_INPUT_PER_APP) &&
hid->maxapplication > 1) {
switch (application) {
case HID_GD_KEYBOARD:
suffix = "Keyboard";
break;
case HID_GD_KEYPAD:
suffix = "Keypad";
break;
case HID_GD_MOUSE:
suffix = "Mouse";
break;
case HID_DG_STYLUS:
suffix = "Pen";
break;
case HID_DG_TOUCHSCREEN:
suffix = "Touchscreen";
break;
case HID_DG_TOUCHPAD:
suffix = "Touchpad";
break;
case HID_GD_SYSTEM_CONTROL:
suffix = "System Control";
break;
case HID_CP_CONSUMER_CONTROL:
suffix = "Consumer Control";
break;
case HID_GD_WIRELESS_RADIO_CTLS:
suffix = "Wireless Radio Control";
break;
default:
break;
}
}
if (suffix) {
hidinput->name = kasprintf(GFP_KERNEL, "%s %s",
hid->name, suffix);
if (!hidinput->name)
goto fail;
} }
input_set_drvdata(input_dev, hid); input_set_drvdata(input_dev, hid);
...@@ -1505,7 +1569,7 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid) ...@@ -1505,7 +1569,7 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid)
input_dev->setkeycode = hidinput_setkeycode; input_dev->setkeycode = hidinput_setkeycode;
input_dev->getkeycode = hidinput_getkeycode; input_dev->getkeycode = hidinput_getkeycode;
input_dev->name = hid->name; input_dev->name = hidinput->name ? hidinput->name : hid->name;
input_dev->phys = hid->phys; input_dev->phys = hid->phys;
input_dev->uniq = hid->uniq; input_dev->uniq = hid->uniq;
input_dev->id.bustype = hid->bus; input_dev->id.bustype = hid->bus;
...@@ -1513,10 +1577,19 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid) ...@@ -1513,10 +1577,19 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid)
input_dev->id.product = hid->product; input_dev->id.product = hid->product;
input_dev->id.version = hid->version; input_dev->id.version = hid->version;
input_dev->dev.parent = &hid->dev; input_dev->dev.parent = &hid->dev;
hidinput->input = input_dev; hidinput->input = input_dev;
list_add_tail(&hidinput->list, &hid->inputs); list_add_tail(&hidinput->list, &hid->inputs);
INIT_LIST_HEAD(&hidinput->reports);
return hidinput; return hidinput;
fail:
kfree(hidinput);
input_free_device(input_dev);
hid_err(hid, "Out of memory during hid input probe\n");
return NULL;
} }
static bool hidinput_has_been_populated(struct hid_input *hidinput) static bool hidinput_has_been_populated(struct hid_input *hidinput)
...@@ -1562,6 +1635,7 @@ static void hidinput_cleanup_hidinput(struct hid_device *hid, ...@@ -1562,6 +1635,7 @@ static void hidinput_cleanup_hidinput(struct hid_device *hid,
list_del(&hidinput->list); list_del(&hidinput->list);
input_free_device(hidinput->input); input_free_device(hidinput->input);
kfree(hidinput->name);
for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) { for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
if (k == HID_OUTPUT_REPORT && if (k == HID_OUTPUT_REPORT &&
...@@ -1594,6 +1668,20 @@ static struct hid_input *hidinput_match(struct hid_report *report) ...@@ -1594,6 +1668,20 @@ static struct hid_input *hidinput_match(struct hid_report *report)
return NULL; return NULL;
} }
static struct hid_input *hidinput_match_application(struct hid_report *report)
{
struct hid_device *hid = report->device;
struct hid_input *hidinput;
list_for_each_entry(hidinput, &hid->inputs, list) {
if (hidinput->report &&
hidinput->report->application == report->application)
return hidinput;
}
return NULL;
}
static inline void hidinput_configure_usages(struct hid_input *hidinput, static inline void hidinput_configure_usages(struct hid_input *hidinput,
struct hid_report *report) struct hid_report *report)
{ {
...@@ -1616,11 +1704,14 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) ...@@ -1616,11 +1704,14 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
struct hid_driver *drv = hid->driver; struct hid_driver *drv = hid->driver;
struct hid_report *report; struct hid_report *report;
struct hid_input *next, *hidinput = NULL; struct hid_input *next, *hidinput = NULL;
unsigned int application;
int i, k; int i, k;
INIT_LIST_HEAD(&hid->inputs); INIT_LIST_HEAD(&hid->inputs);
INIT_WORK(&hid->led_work, hidinput_led_worker); INIT_WORK(&hid->led_work, hidinput_led_worker);
hid->status &= ~HID_STAT_DUP_DETECTED;
if (!force) { if (!force) {
for (i = 0; i < hid->maxcollection; i++) { for (i = 0; i < hid->maxcollection; i++) {
struct hid_collection *col = &hid->collection[i]; struct hid_collection *col = &hid->collection[i];
...@@ -1646,15 +1737,20 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) ...@@ -1646,15 +1737,20 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
if (!report->maxfield) if (!report->maxfield)
continue; continue;
application = report->application;
/* /*
* Find the previous hidinput report attached * Find the previous hidinput report attached
* to this report id. * to this report id.
*/ */
if (hid->quirks & HID_QUIRK_MULTI_INPUT) if (hid->quirks & HID_QUIRK_MULTI_INPUT)
hidinput = hidinput_match(report); hidinput = hidinput_match(report);
else if (hid->maxapplication > 1 &&
(hid->quirks & HID_QUIRK_INPUT_PER_APP))
hidinput = hidinput_match_application(report);
if (!hidinput) { if (!hidinput) {
hidinput = hidinput_allocate(hid); hidinput = hidinput_allocate(hid, application);
if (!hidinput) if (!hidinput)
goto out_unwind; goto out_unwind;
} }
...@@ -1663,6 +1759,9 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) ...@@ -1663,6 +1759,9 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
if (hid->quirks & HID_QUIRK_MULTI_INPUT) if (hid->quirks & HID_QUIRK_MULTI_INPUT)
hidinput->report = report; hidinput->report = report;
list_add_tail(&report->hidinput_list,
&hidinput->reports);
} }
} }
...@@ -1687,6 +1786,10 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) ...@@ -1687,6 +1786,10 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
goto out_unwind; 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; return 0;
out_unwind: out_unwind:
......
...@@ -531,12 +531,12 @@ static int magicmouse_probe(struct hid_device *hdev, ...@@ -531,12 +531,12 @@ static int magicmouse_probe(struct hid_device *hdev,
if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE) if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE)
report = hid_register_report(hdev, HID_INPUT_REPORT, report = hid_register_report(hdev, HID_INPUT_REPORT,
MOUSE_REPORT_ID); MOUSE_REPORT_ID, 0);
else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
report = hid_register_report(hdev, HID_INPUT_REPORT, report = hid_register_report(hdev, HID_INPUT_REPORT,
TRACKPAD_REPORT_ID); TRACKPAD_REPORT_ID, 0);
report = hid_register_report(hdev, HID_INPUT_REPORT, report = hid_register_report(hdev, HID_INPUT_REPORT,
DOUBLE_REPORT_ID); DOUBLE_REPORT_ID, 0);
} }
if (!report) { if (!report) {
......
This diff is collapsed.
...@@ -292,9 +292,12 @@ struct hid_item { ...@@ -292,9 +292,12 @@ struct hid_item {
#define HID_DG_CONTACTCOUNT 0x000d0054 #define HID_DG_CONTACTCOUNT 0x000d0054
#define HID_DG_CONTACTMAX 0x000d0055 #define HID_DG_CONTACTMAX 0x000d0055
#define HID_DG_SCANTIME 0x000d0056 #define HID_DG_SCANTIME 0x000d0056
#define HID_DG_SURFACESWITCH 0x000d0057
#define HID_DG_BUTTONSWITCH 0x000d0058
#define HID_DG_BUTTONTYPE 0x000d0059 #define HID_DG_BUTTONTYPE 0x000d0059
#define HID_DG_BARRELSWITCH2 0x000d005a #define HID_DG_BARRELSWITCH2 0x000d005a
#define HID_DG_TOOLSERIALNUMBER 0x000d005b #define HID_DG_TOOLSERIALNUMBER 0x000d005b
#define HID_DG_LATENCYMODE 0x000d0060
#define HID_VD_ASUS_CUSTOM_MEDIA_KEYS 0xff310076 #define HID_VD_ASUS_CUSTOM_MEDIA_KEYS 0xff310076
/* /*
...@@ -341,10 +344,12 @@ struct hid_item { ...@@ -341,10 +344,12 @@ struct hid_item {
/* BIT(8) reserved for backward compatibility, was HID_QUIRK_NO_EMPTY_INPUT */ /* BIT(8) reserved for backward compatibility, was HID_QUIRK_NO_EMPTY_INPUT */
/* BIT(9) reserved for backward compatibility, was NO_INIT_INPUT_REPORTS */ /* BIT(9) reserved for backward compatibility, was NO_INIT_INPUT_REPORTS */
#define HID_QUIRK_ALWAYS_POLL BIT(10) #define HID_QUIRK_ALWAYS_POLL BIT(10)
#define HID_QUIRK_INPUT_PER_APP BIT(11)
#define HID_QUIRK_SKIP_OUTPUT_REPORTS BIT(16) #define HID_QUIRK_SKIP_OUTPUT_REPORTS BIT(16)
#define HID_QUIRK_SKIP_OUTPUT_REPORT_ID BIT(17) #define HID_QUIRK_SKIP_OUTPUT_REPORT_ID BIT(17)
#define HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP BIT(18) #define HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP BIT(18)
#define HID_QUIRK_HAVE_SPECIAL_DRIVER BIT(19) #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_FULLSPEED_INTERVAL BIT(28)
#define HID_QUIRK_NO_INIT_REPORTS BIT(29) #define HID_QUIRK_NO_INIT_REPORTS BIT(29)
#define HID_QUIRK_NO_IGNORE BIT(30) #define HID_QUIRK_NO_IGNORE BIT(30)
...@@ -464,8 +469,10 @@ struct hid_field { ...@@ -464,8 +469,10 @@ struct hid_field {
struct hid_report { struct hid_report {
struct list_head list; struct list_head list;
unsigned id; /* id of this report */ struct list_head hidinput_list;
unsigned type; /* report type */ unsigned int id; /* id of this report */
unsigned int type; /* report type */
unsigned int application; /* application usage for this report */
struct hid_field *field[HID_MAX_FIELDS]; /* fields of the report */ struct hid_field *field[HID_MAX_FIELDS]; /* fields of the report */
unsigned maxfield; /* maximum valid field index */ unsigned maxfield; /* maximum valid field index */
unsigned size; /* size of the report (bits) */ unsigned size; /* size of the report (bits) */
...@@ -503,12 +510,15 @@ struct hid_output_fifo { ...@@ -503,12 +510,15 @@ struct hid_output_fifo {
#define HID_STAT_ADDED BIT(0) #define HID_STAT_ADDED BIT(0)
#define HID_STAT_PARSED BIT(1) #define HID_STAT_PARSED BIT(1)
#define HID_STAT_DUP_DETECTED BIT(2)
struct hid_input { struct hid_input {
struct list_head list; struct list_head list;
struct hid_report *report; struct hid_report *report;
struct input_dev *input; struct input_dev *input;
const char *name;
bool registered; bool registered;
struct list_head reports; /* the list of reports */
}; };
enum hid_type { enum hid_type {
...@@ -865,7 +875,9 @@ void hid_output_report(struct hid_report *report, __u8 *data); ...@@ -865,7 +875,9 @@ void hid_output_report(struct hid_report *report, __u8 *data);
void __hid_request(struct hid_device *hid, struct hid_report *rep, int reqtype); void __hid_request(struct hid_device *hid, struct hid_report *rep, int reqtype);
u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags); u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags);
struct hid_device *hid_allocate_device(void); struct hid_device *hid_allocate_device(void);
struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id); struct hid_report *hid_register_report(struct hid_device *device,
unsigned int type, unsigned int id,
unsigned int application);
int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size); int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size);
struct hid_report *hid_validate_values(struct hid_device *hid, struct hid_report *hid_validate_values(struct hid_device *hid,
unsigned int type, unsigned int id, unsigned int type, unsigned int id,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment