mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 01:10:04 +00:00
Revert "HID: wacom: generic: read the number of expected touches on a per collection basis"
This reverts commit15893fa401
. The referenced commit broke pen and touch input for a variety of devices such as the Cintiq Pro 32. Affected devices may appear to work normally for a short amount of time, but eventually loose track of actual touch state and can leave touch arbitration enabled which prevents the pen from working. The commit is not itself required for any currently-available Bluetooth device, and so we revert it to correct the behavior of broken devices. This breakage occurs due to a mismatch between the order of collections and the order of usages on some devices. This commit tries to read the contact count before processing events, but will fail if the contact count does not occur prior to the first logical finger collection. This is the case for devices like the Cintiq Pro 32 which place the contact count at the very end of the report. Without the contact count set, touches will only be partially processed. The `wacom_wac_finger_slot` function will not open any slots since the number of contacts seen is greater than the expectation of 0, but we will still end up calling `input_mt_sync_frame` for each finger anyway. This can cause problems for userspace separate from the issue currently taking place in the kernel. Only once all of the individual finger collections have been processed do we finally get to the enclosing collection which contains the contact count. The value ends up being used for the *next* report, however. This delayed use of the contact count can cause the driver to loose track of the actual touch state and believe that there are contacts down when there aren't. This leaves touch arbitration enabled and prevents the pen from working. It can also cause userspace to incorrectly treat single- finger input as gestures. Link: https://github.com/linuxwacom/input-wacom/issues/146 Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com> Reviewed-by: Aaron Armstrong Skomra <aaron.skomra@wacom.com> Fixes:15893fa401
("HID: wacom: generic: read the number of expected touches on a per collection basis") Cc: stable@vger.kernel.org # 5.3+ Signed-off-by: Jiri Kosina <jkosina@suse.cz>
This commit is contained in:
parent
185af3e775
commit
b43f977dd2
1 changed files with 16 additions and 63 deletions
|
@ -2637,9 +2637,25 @@ static void wacom_wac_finger_pre_report(struct hid_device *hdev,
|
||||||
case HID_DG_TIPSWITCH:
|
case HID_DG_TIPSWITCH:
|
||||||
hid_data->last_slot_field = equivalent_usage;
|
hid_data->last_slot_field = equivalent_usage;
|
||||||
break;
|
break;
|
||||||
|
case HID_DG_CONTACTCOUNT:
|
||||||
|
hid_data->cc_report = report->id;
|
||||||
|
hid_data->cc_index = i;
|
||||||
|
hid_data->cc_value_index = j;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hid_data->cc_report != 0 &&
|
||||||
|
hid_data->cc_index >= 0) {
|
||||||
|
struct hid_field *field = report->field[hid_data->cc_index];
|
||||||
|
int value = field->value[hid_data->cc_value_index];
|
||||||
|
if (value)
|
||||||
|
hid_data->num_expected = value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
hid_data->num_expected = wacom_wac->features.touch_max;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wacom_wac_finger_report(struct hid_device *hdev,
|
static void wacom_wac_finger_report(struct hid_device *hdev,
|
||||||
|
@ -2649,7 +2665,6 @@ static void wacom_wac_finger_report(struct hid_device *hdev,
|
||||||
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
|
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
|
||||||
struct input_dev *input = wacom_wac->touch_input;
|
struct input_dev *input = wacom_wac->touch_input;
|
||||||
unsigned touch_max = wacom_wac->features.touch_max;
|
unsigned touch_max = wacom_wac->features.touch_max;
|
||||||
struct hid_data *hid_data = &wacom_wac->hid_data;
|
|
||||||
|
|
||||||
/* If more packets of data are expected, give us a chance to
|
/* If more packets of data are expected, give us a chance to
|
||||||
* process them rather than immediately syncing a partial
|
* process them rather than immediately syncing a partial
|
||||||
|
@ -2663,7 +2678,6 @@ static void wacom_wac_finger_report(struct hid_device *hdev,
|
||||||
|
|
||||||
input_sync(input);
|
input_sync(input);
|
||||||
wacom_wac->hid_data.num_received = 0;
|
wacom_wac->hid_data.num_received = 0;
|
||||||
hid_data->num_expected = 0;
|
|
||||||
|
|
||||||
/* keep touch state for pen event */
|
/* keep touch state for pen event */
|
||||||
wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(wacom_wac);
|
wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(wacom_wac);
|
||||||
|
@ -2738,73 +2752,12 @@ static void wacom_report_events(struct hid_device *hdev,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wacom_set_num_expected(struct hid_device *hdev,
|
|
||||||
struct hid_report *report,
|
|
||||||
int collection_index,
|
|
||||||
struct hid_field *field,
|
|
||||||
int field_index)
|
|
||||||
{
|
|
||||||
struct wacom *wacom = hid_get_drvdata(hdev);
|
|
||||||
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
|
|
||||||
struct hid_data *hid_data = &wacom_wac->hid_data;
|
|
||||||
unsigned int original_collection_level =
|
|
||||||
hdev->collection[collection_index].level;
|
|
||||||
bool end_collection = false;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (hid_data->num_expected)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// find the contact count value for this segment
|
|
||||||
for (i = field_index; i < report->maxfield && !end_collection; i++) {
|
|
||||||
struct hid_field *field = report->field[i];
|
|
||||||
unsigned int field_level =
|
|
||||||
hdev->collection[field->usage[0].collection_index].level;
|
|
||||||
unsigned int j;
|
|
||||||
|
|
||||||
if (field_level != original_collection_level)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (j = 0; j < field->maxusage; j++) {
|
|
||||||
struct hid_usage *usage = &field->usage[j];
|
|
||||||
|
|
||||||
if (usage->collection_index != collection_index) {
|
|
||||||
end_collection = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (wacom_equivalent_usage(usage->hid) == HID_DG_CONTACTCOUNT) {
|
|
||||||
hid_data->cc_report = report->id;
|
|
||||||
hid_data->cc_index = i;
|
|
||||||
hid_data->cc_value_index = j;
|
|
||||||
|
|
||||||
if (hid_data->cc_report != 0 &&
|
|
||||||
hid_data->cc_index >= 0) {
|
|
||||||
|
|
||||||
struct hid_field *field =
|
|
||||||
report->field[hid_data->cc_index];
|
|
||||||
int value =
|
|
||||||
field->value[hid_data->cc_value_index];
|
|
||||||
|
|
||||||
if (value)
|
|
||||||
hid_data->num_expected = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hid_data->cc_report == 0 || hid_data->cc_index < 0)
|
|
||||||
hid_data->num_expected = wacom_wac->features.touch_max;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int wacom_wac_collection(struct hid_device *hdev, struct hid_report *report,
|
static int wacom_wac_collection(struct hid_device *hdev, struct hid_report *report,
|
||||||
int collection_index, struct hid_field *field,
|
int collection_index, struct hid_field *field,
|
||||||
int field_index)
|
int field_index)
|
||||||
{
|
{
|
||||||
struct wacom *wacom = hid_get_drvdata(hdev);
|
struct wacom *wacom = hid_get_drvdata(hdev);
|
||||||
|
|
||||||
if (WACOM_FINGER_FIELD(field))
|
|
||||||
wacom_set_num_expected(hdev, report, collection_index, field,
|
|
||||||
field_index);
|
|
||||||
wacom_report_events(hdev, report, collection_index, field_index);
|
wacom_report_events(hdev, report, collection_index, field_index);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in a new issue