Skip to content

Commit e941dc1

Browse files
linuswdtor
authored andcommitted
Input: zinitix - do not report shadow fingers
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 <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Dmitry Torokhov <[email protected]>
1 parent 327b89f commit e941dc1

File tree

1 file changed

+35
-9
lines changed

1 file changed

+35
-9
lines changed

drivers/input/touchscreen/zinitix.c

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ struct point_coord {
135135

136136
struct touch_event {
137137
__le16 status;
138-
u8 finger_cnt;
138+
u8 finger_mask;
139139
u8 time_stamp;
140140
struct point_coord point_coord[MAX_SUPPORTED_FINGER_NUM];
141141
};
@@ -322,18 +322,40 @@ static int zinitix_send_power_on_sequence(struct bt541_ts_data *bt541)
322322
static void zinitix_report_finger(struct bt541_ts_data *bt541, int slot,
323323
const struct point_coord *p)
324324
{
325+
u16 x, y;
326+
327+
if (unlikely(!(p->sub_status &
328+
(SUB_BIT_UP | SUB_BIT_DOWN | SUB_BIT_MOVE)))) {
329+
dev_dbg(&bt541->client->dev, "unknown finger event %#02x\n",
330+
p->sub_status);
331+
return;
332+
}
333+
334+
x = le16_to_cpu(p->x);
335+
y = le16_to_cpu(p->y);
336+
325337
input_mt_slot(bt541->input_dev, slot);
326-
input_mt_report_slot_state(bt541->input_dev, MT_TOOL_FINGER, true);
327-
touchscreen_report_pos(bt541->input_dev, &bt541->prop,
328-
le16_to_cpu(p->x), le16_to_cpu(p->y), true);
329-
input_report_abs(bt541->input_dev, ABS_MT_TOUCH_MAJOR, p->width);
338+
if (input_mt_report_slot_state(bt541->input_dev, MT_TOOL_FINGER,
339+
!(p->sub_status & SUB_BIT_UP))) {
340+
touchscreen_report_pos(bt541->input_dev,
341+
&bt541->prop, x, y, true);
342+
input_report_abs(bt541->input_dev,
343+
ABS_MT_TOUCH_MAJOR, p->width);
344+
dev_dbg(&bt541->client->dev, "finger %d %s (%u, %u)\n",
345+
slot, p->sub_status & SUB_BIT_DOWN ? "down" : "move",
346+
x, y);
347+
} else {
348+
dev_dbg(&bt541->client->dev, "finger %d up (%u, %u)\n",
349+
slot, x, y);
350+
}
330351
}
331352

332353
static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
333354
{
334355
struct bt541_ts_data *bt541 = bt541_handler;
335356
struct i2c_client *client = bt541->client;
336357
struct touch_event touch_event;
358+
unsigned long finger_mask;
337359
int error;
338360
int i;
339361

@@ -346,10 +368,14 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
346368
goto out;
347369
}
348370

349-
for (i = 0; i < MAX_SUPPORTED_FINGER_NUM; i++)
350-
if (touch_event.point_coord[i].sub_status & SUB_BIT_EXIST)
351-
zinitix_report_finger(bt541, i,
352-
&touch_event.point_coord[i]);
371+
finger_mask = touch_event.finger_mask;
372+
for_each_set_bit(i, &finger_mask, MAX_SUPPORTED_FINGER_NUM) {
373+
const struct point_coord *p = &touch_event.point_coord[i];
374+
375+
/* Only process contacts that are actually reported */
376+
if (p->sub_status & SUB_BIT_EXIST)
377+
zinitix_report_finger(bt541, i, p);
378+
}
353379

354380
input_mt_sync_frame(bt541->input_dev);
355381
input_sync(bt541->input_dev);

0 commit comments

Comments
 (0)