HID: multitouch: Fix stale MT slots when contact count drops to zero

The INGENIC 17EF:6161 touchscreen (Lenovo Yoga Book 9 14IAH10) reports
HID_DG_CONTACTCOUNT=0 in the frame immediately following the last finger
lift rather than omitting the frame entirely.  In mt_touch_report() the
existing code only updates num_expected when contact_count is non-zero,
so a zero contact count on the first packet of a new frame leaves
num_expected at its previous value (e.g. 2 for a two-finger gesture).
The sync check "num_received >= num_expected" then evaluates "0 >= 2"
and never fires, preventing INPUT_MT_DROP_UNUSED from releasing the
stale slots.  Those slots remain active in the kernel MT layer until the
next touch, at which point they are released in a batch alongside the
new contact — causing the userspace event consumer to miss the
intervening finger-up sequence and corrupt its gesture session state.

Fix by resetting num_expected to 0 when contact_count is zero and
num_received is still 0 (i.e., this is the first and only packet of the
frame, not a continuation packet in a multi-packet sequence).  With
num_expected=0 the sync check "0 >= 0" fires immediately, calling
input_mt_sync_frame() which drops the stale slots via
INPUT_MT_DROP_UNUSED.

The num_received==0 guard is critical: continuation packets in a
multi-packet frame arrive after at least one contact has already been
processed (num_received>0), so they are correctly excluded from this
path and the existing multi-packet logic is unaffected.

Signed-off-by: Dave Carey <carvsdriver@gmail.com>
Tested-by: Dave Carey <carvsdriver@gmail.com>
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
This commit is contained in:
Dave Carey 2026-07-30 08:43:36 -04:00 committed by Benjamin Tissoires
parent 1c942462c3
commit e8e60b6439

View File

@ -1321,21 +1321,18 @@ static void mt_touch_report(struct hid_device *hid,
* Includes multi-packet support where subsequent
* packets are sent with zero contactcount.
*/
if (contact_count >= 0) {
if (contact_count > 0)
app->num_expected = contact_count;
else if (app->num_received == 0 && app->prev_scantime != scantime) {
/*
* New multi-report frame:
*
* For Win8 PTPs the first packet (td->num_received == 0) may
* have a contactcount of 0 if there only is a button event.
* We double check that this is not a continuation packet
* of a possible multi-packet frame be checking that the
* timestamp has changed.
*
* Some other devices use a sentinel frame with 0 to release all contacts
*/
if ((app->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
app->num_received == 0 &&
app->prev_scantime != scantime)
app->num_expected = contact_count;
/* A non 0 contact count always indicates a first packet */
else if (contact_count)
app->num_expected = contact_count;
app->num_expected = 0;
}
app->prev_scantime = scantime;