diff options
author | Benjamin Tissoires <benjamin.tissoires@redhat.com> | 2018-07-13 17:13:47 +0300 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2018-07-17 16:33:47 +0300 |
commit | 8dfe14b3b47ff832cb638731f9fc696a3a84f804 (patch) | |
tree | 8e4d1d1f80e006389b39a634e1939c9d6121babc /drivers/hid/hid-multitouch.c | |
parent | 3ceb3826448d1ec4650a6c2b62baa9e0994ac7d3 (diff) | |
download | linux-8dfe14b3b47ff832cb638731f9fc696a3a84f804.tar.xz |
HID: multitouch: ditch mt_report_id
Now that the driver can handle more than one multitouch collection in
a single HID device, ditch the last bit that contains us to use only
one mt collection.
Acked-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/hid-multitouch.c')
-rw-r--r-- | drivers/hid/hid-multitouch.c | 126 |
1 files changed, 94 insertions, 32 deletions
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index beaac36f61a7..a2c10fc62ef2 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -147,6 +147,13 @@ struct mt_fields { unsigned int length; }; +struct mt_report_data { + struct list_head list; + struct hid_report *report; + struct mt_application *application; + bool is_mt_collection; +}; + struct mt_device { struct mt_class mtclass; /* our mt device class */ struct timer_list release_timer; /* to release sticky fingers */ @@ -154,13 +161,13 @@ struct mt_device { struct mt_fields *fields; /* temporary placeholder for storing the multitouch fields */ unsigned long mt_io_flags; /* mt flags (MT_IO_FLAGS_*) */ - unsigned mt_report_id; /* the report ID of the multitouch device */ __u8 inputmode_value; /* InputMode HID feature value */ __u8 maxcontacts; bool is_buttonpad; /* is this device a button pad? */ bool serial_maybe; /* need to check for serial protocol */ struct list_head applications; + struct list_head reports; }; static void mt_post_parse_default_settings(struct mt_device *td, @@ -526,6 +533,60 @@ static struct mt_application *mt_find_application(struct mt_device *td, return mt_application; } +static struct mt_report_data *mt_allocate_report_data(struct mt_device *td, + struct hid_report *report) +{ + struct mt_report_data *rdata; + struct hid_field *field; + int r, n; + + rdata = devm_kzalloc(&td->hdev->dev, sizeof(*rdata), GFP_KERNEL); + if (!rdata) + return NULL; + + rdata->report = report; + rdata->application = mt_find_application(td, report->application); + + if (!rdata->application) { + devm_kfree(&td->hdev->dev, rdata); + return NULL; + } + + for (r = 0; r < report->maxfield; r++) { + field = report->field[r]; + + if (!(HID_MAIN_ITEM_VARIABLE & field->flags)) + continue; + + for (n = 0; n < field->report_count; n++) { + if (field->usage[n].hid == HID_DG_CONTACTID) + rdata->is_mt_collection = true; + } + } + + list_add_tail(&rdata->list, &td->reports); + + return rdata; +} + +static struct mt_report_data *mt_find_report_data(struct mt_device *td, + struct hid_report *report) +{ + struct mt_report_data *tmp, *rdata = NULL; + + list_for_each_entry(tmp, &td->reports, list) { + if (report == tmp->report) { + rdata = tmp; + break; + } + } + + if (!rdata) + rdata = mt_allocate_report_data(td, report); + + return rdata; +} + static void mt_store_field(struct hid_usage *usage, struct mt_device *td, struct hid_input *hi) { @@ -614,7 +675,6 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, case HID_DG_CONTACTID: mt_store_field(usage, td, hi); app->touches_by_report++; - td->mt_report_id = field->report->id; return 1; case HID_DG_WIDTH: hid_map_usage(hi, usage, bit, max, @@ -979,10 +1039,12 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, } } -static void mt_touch_report(struct hid_device *hid, struct hid_report *report) +static void mt_touch_report(struct hid_device *hid, + struct mt_report_data *rdata) { struct mt_device *td = hid_get_drvdata(hid); - struct mt_application *app; + struct hid_report *report = rdata->report; + struct mt_application *app = rdata->application; struct hid_field *field; bool first_packet; unsigned count; @@ -994,11 +1056,6 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report) if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags)) return; - app = mt_find_application(td, report->application); - - if (!app) - return; - /* * Includes multi-packet support where subsequent * packets are sent with zero contactcount. @@ -1119,8 +1176,15 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, { struct mt_device *td = hid_get_drvdata(hdev); struct mt_application *application; + struct mt_report_data *rdata; + + rdata = mt_find_report_data(td, field->report); + if (!rdata) { + hid_err(hdev, "failed to allocate data for report\n"); + return 0; + } - application = mt_find_application(td, field->application); + application = rdata->application; /* * If mtclass.export_all_inputs is not set, only map fields from @@ -1163,22 +1227,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, return 1; } - /* - * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN" - * for the stylus. - * The check for mt_report_id ensures we don't process - * HID_DG_CONTACTCOUNT from the pen report as it is outside the physical - * collection, but within the report ID. - */ - if (field->physical == HID_DG_STYLUS) - return 0; - else if ((field->physical == 0) && - (field->report->id != td->mt_report_id) && - (td->mt_report_id != -1)) - return 0; - - if (field->application == HID_DG_TOUCHSCREEN || - field->application == HID_DG_TOUCHPAD) + if (rdata->is_mt_collection && + (field->application == HID_DG_TOUCHSCREEN || + field->application == HID_DG_TOUCHPAD)) return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, application); @@ -1211,8 +1262,10 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { struct mt_device *td = hid_get_drvdata(hid); + struct mt_report_data *rdata; - if (field->report->id == td->mt_report_id) + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) return mt_touch_event(hid, field, usage, value); return 0; @@ -1222,12 +1275,14 @@ static void mt_report(struct hid_device *hid, struct hid_report *report) { struct mt_device *td = hid_get_drvdata(hid); struct hid_field *field = report->field[0]; + struct mt_report_data *rdata; if (!(hid->claimed & HID_CLAIMED_INPUT)) return; - if (report->id == td->mt_report_id) - return mt_touch_report(hid, report); + rdata = mt_find_report_data(td, report); + if (rdata && rdata->is_mt_collection) + return mt_touch_report(hid, rdata); if (field && field->hidinput && field->hidinput->input) input_sync(field->hidinput->input); @@ -1368,15 +1423,22 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) char *name; const char *suffix = NULL; unsigned int application = 0; + struct mt_report_data *rdata; struct mt_application *mt_application = NULL; struct hid_report *report; int ret; list_for_each_entry(report, &hi->reports, hidinput_list) { application = report->application; - mt_application = mt_find_application(td, application); + rdata = mt_find_report_data(td, report); + if (!rdata) { + hid_err(hdev, "failed to allocate data for report\n"); + return -ENOMEM; + } + + mt_application = rdata->application; - if (report->id == td->mt_report_id) { + if (rdata->is_mt_collection) { ret = mt_touch_input_configured(hdev, hi, mt_application); if (ret) @@ -1529,10 +1591,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) td->hdev = hdev; td->mtclass = *mtclass; td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; - td->mt_report_id = -1; hid_set_drvdata(hdev, td); INIT_LIST_HEAD(&td->applications); + INIT_LIST_HEAD(&td->reports); td->fields = devm_kzalloc(&hdev->dev, sizeof(struct mt_fields), GFP_KERNEL); |