Patch "Input: zinitix - do not report shadow fingers" has been added to the 5.16-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    Input: zinitix - do not report shadow fingers

to the 5.16-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     input-zinitix-do-not-report-shadow-fingers.patch
and it can be found in the queue-5.16 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit d1bef47c5f55ac616e67132f09af76e0e85c7859
Author: Linus Walleij <linus.walleij@xxxxxxxxxx>
Date:   Fri Mar 4 13:17:33 2022 -0800

    Input: zinitix - do not report shadow fingers
    
    [ Upstream commit e941dc13fd3717122207d74539ab95da07ef797f ]
    
    I observed the following problem with the BT404 touch pad
    running the Phosh UI:
    
    When e.g. typing on the virtual keyboard pressing "g" would
    produce "ggg".
    
    After some analysis it turns out the firmware reports that three
    fingers hit that coordinate at the same time, finger 0, 2 and
    4 (of the five available 0,1,2,3,4).
    
    DOWN
      Zinitix-TS 3-0020: finger 0 down (246, 395)
      Zinitix-TS 3-0020: finger 1 up (0, 0)
      Zinitix-TS 3-0020: finger 2 down (246, 395)
      Zinitix-TS 3-0020: finger 3 up (0, 0)
      Zinitix-TS 3-0020: finger 4 down (246, 395)
    UP
      Zinitix-TS 3-0020: finger 0 up (246, 395)
      Zinitix-TS 3-0020: finger 2 up (246, 395)
      Zinitix-TS 3-0020: finger 4 up (246, 395)
    
    This is one touch and release: i.e. this is all reported on
    touch (down) and release.
    
    There is a field in the struct touch_event called finger_cnt
    which is actually a bitmask of the fingers active in the
    event.
    
    Rename this field finger_mask as this matches the use contents
    better, then use for_each_set_bit() to iterate over just the
    fingers that are actally active.
    
    Factor out a finger reporting function zinitix_report_fingers()
    to handle all fingers.
    
    Also be more careful in reporting finger down/up: we were
    reporting every event with input_mt_report_slot_state(..., true);
    but this should only be reported on finger down or move,
    not on finger up, so also add code to check p->sub_status
    to see what is happening and report correctly.
    
    After this my Zinitix BT404 touchscreen report fingers
    flawlessly.
    
    The vendor drive I have notably does not use the "finger_cnt"
    and contains obviously incorrect code like this:
    
      if (touch_dev->touch_info.finger_cnt > MAX_SUPPORTED_FINGER_NUM)
          touch_dev->touch_info.finger_cnt = MAX_SUPPORTED_FINGER_NUM;
    
    As MAX_SUPPORTED_FINGER_NUM is an ordinal and the field is
    a bitmask this seems quite confused.
    
    Signed-off-by: Linus Walleij <linus.walleij@xxxxxxxxxx>
    Link: https://lore.kernel.org/r/20220228233017.2270599-1-linus.walleij@xxxxxxxxxx
    Signed-off-by: Dmitry Torokhov <dmitry.torokhov@xxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c
index 1e70b8d2a8d7..400957f4c8c9 100644
--- a/drivers/input/touchscreen/zinitix.c
+++ b/drivers/input/touchscreen/zinitix.c
@@ -135,7 +135,7 @@ struct point_coord {
 
 struct touch_event {
 	__le16	status;
-	u8	finger_cnt;
+	u8	finger_mask;
 	u8	time_stamp;
 	struct point_coord point_coord[MAX_SUPPORTED_FINGER_NUM];
 };
@@ -311,11 +311,32 @@ static int zinitix_send_power_on_sequence(struct bt541_ts_data *bt541)
 static void zinitix_report_finger(struct bt541_ts_data *bt541, int slot,
 				  const struct point_coord *p)
 {
+	u16 x, y;
+
+	if (unlikely(!(p->sub_status &
+		       (SUB_BIT_UP | SUB_BIT_DOWN | SUB_BIT_MOVE)))) {
+		dev_dbg(&bt541->client->dev, "unknown finger event %#02x\n",
+			p->sub_status);
+		return;
+	}
+
+	x = le16_to_cpu(p->x);
+	y = le16_to_cpu(p->y);
+
 	input_mt_slot(bt541->input_dev, slot);
-	input_mt_report_slot_state(bt541->input_dev, MT_TOOL_FINGER, true);
-	touchscreen_report_pos(bt541->input_dev, &bt541->prop,
-			       le16_to_cpu(p->x), le16_to_cpu(p->y), true);
-	input_report_abs(bt541->input_dev, ABS_MT_TOUCH_MAJOR, p->width);
+	if (input_mt_report_slot_state(bt541->input_dev, MT_TOOL_FINGER,
+				       !(p->sub_status & SUB_BIT_UP))) {
+		touchscreen_report_pos(bt541->input_dev,
+				       &bt541->prop, x, y, true);
+		input_report_abs(bt541->input_dev,
+				 ABS_MT_TOUCH_MAJOR, p->width);
+		dev_dbg(&bt541->client->dev, "finger %d %s (%u, %u)\n",
+			slot, p->sub_status & SUB_BIT_DOWN ? "down" : "move",
+			x, y);
+	} else {
+		dev_dbg(&bt541->client->dev, "finger %d up (%u, %u)\n",
+			slot, x, y);
+	}
 }
 
 static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
@@ -323,6 +344,7 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
 	struct bt541_ts_data *bt541 = bt541_handler;
 	struct i2c_client *client = bt541->client;
 	struct touch_event touch_event;
+	unsigned long finger_mask;
 	int error;
 	int i;
 
@@ -335,10 +357,14 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
 		goto out;
 	}
 
-	for (i = 0; i < MAX_SUPPORTED_FINGER_NUM; i++)
-		if (touch_event.point_coord[i].sub_status & SUB_BIT_EXIST)
-			zinitix_report_finger(bt541, i,
-					      &touch_event.point_coord[i]);
+	finger_mask = touch_event.finger_mask;
+	for_each_set_bit(i, &finger_mask, MAX_SUPPORTED_FINGER_NUM) {
+		const struct point_coord *p = &touch_event.point_coord[i];
+
+		/* Only process contacts that are actually reported */
+		if (p->sub_status & SUB_BIT_EXIST)
+			zinitix_report_finger(bt541, i, p);
+	}
 
 	input_mt_sync_frame(bt541->input_dev);
 	input_sync(bt541->input_dev);



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux