lkml.org 
[lkml]   [2020]   [May]   [13]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.4 43/90] Revert "HID: wacom: generic: read the number of expected touches on a per collection basis"
    Date
    From: Jason Gerecke <killertofu@gmail.com>

    commit b43f977dd281945960c26b3ef67bba0fa07d39d9 upstream.

    This reverts commit 15893fa40109f5e7c67eeb8da62267d0fdf0be9d.

    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: 15893fa40109 ("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>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/hid/wacom_wac.c | 79 +++++++++---------------------------------------
    1 file changed, 16 insertions(+), 63 deletions(-)

    --- a/drivers/hid/wacom_wac.c
    +++ b/drivers/hid/wacom_wac.c
    @@ -2637,9 +2637,25 @@ static void wacom_wac_finger_pre_report(
    case HID_DG_TIPSWITCH:
    hid_data->last_slot_field = equivalent_usage;
    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,
    @@ -2649,7 +2665,6 @@ static void wacom_wac_finger_report(stru
    struct wacom_wac *wacom_wac = &wacom->wacom_wac;
    struct input_dev *input = wacom_wac->touch_input;
    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
    * process them rather than immediately syncing a partial
    @@ -2663,7 +2678,6 @@ static void wacom_wac_finger_report(stru

    input_sync(input);
    wacom_wac->hid_data.num_received = 0;
    - hid_data->num_expected = 0;

    /* keep touch state for pen event */
    wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(wacom_wac);
    @@ -2738,73 +2752,12 @@ static void wacom_report_events(struct h
    }
    }

    -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,
    int collection_index, struct hid_field *field,
    int field_index)
    {
    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);

    /*

    \
     
     \ /
      Last update: 2020-05-13 12:02    [W:4.516 / U:0.016 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site