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. After augmenting the driver to remember all fingers we report in a single touch event and filter out any duplicates we get this debug print: DOWN Zinitix-TS 3-0020: finger 0 down (257, 664) Zinitix-TS 3-0020: finger 1 up (0, 0) Zinitix-TS 3-0020: ignore shadow finger 2 at (257, 664) Zinitix-TS 3-0020: ignore shadow finger 3 at (0, 0) Zinitix-TS 3-0020: ignore shadow finger 4 at (257, 664) UP Zinitix-TS 3-0020: finger 0 up (257, 664) Zinitix-TS 3-0020: ignore shadow finger 2 at (257, 664) Zinitix-TS 3-0020: ignore shadow finger 4 at (257, 664) As it is physically impossible to place two fingers at the same point at the screen this seems safe to do. The "finger 1 up (0, 0)" type messages of releaseing ghost fingers does not go away, and even though this is mostly incorrect too, we cannot rule out some finger being released at (0, 0) in the generic case, so it needs to stay. Notice that the ghostly release of fingers 1 and 3 only happens on finger down events, not on finger up. This appears to me as the best we can do. After this my screen is nicely interactive. Cc: Michael Srba <Michael.Srba@xxxxxxxxx> Cc: Nikita Travkin <nikita@xxxxxxx> Signed-off-by: Linus Walleij <linus.walleij@xxxxxxxxxx> --- drivers/input/touchscreen/zinitix.c | 78 ++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 12 deletions(-) diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c index 129ebc810de8..7655a09b65bc 100644 --- a/drivers/input/touchscreen/zinitix.c +++ b/drivers/input/touchscreen/zinitix.c @@ -319,14 +319,72 @@ static int zinitix_send_power_on_sequence(struct bt541_ts_data *bt541) return 0; } -static void zinitix_report_finger(struct bt541_ts_data *bt541, int slot, - const struct point_coord *p) +static void zinitix_report_fingers(struct bt541_ts_data *bt541, struct touch_event *te) { - 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); + struct point_coord *p; + u16 reported_x[MAX_SUPPORTED_FINGER_NUM]; + u16 reported_y[MAX_SUPPORTED_FINGER_NUM]; + u16 x, y; + int i, j; + int ridx = 0; + bool ignore; + + for (i = 0; i < MAX_SUPPORTED_FINGER_NUM; i++) { + p = &te->point_coord[i]; + + /* Skip nonexisting fingers */ + if (!p->sub_status & SUB_BIT_EXIST) + continue; + + x = le16_to_cpu(p->x); + y = le16_to_cpu(p->y); + + /* + * Check if this has already been reported and is just a shadow + * finger + */ + ignore = false; + for (j = 0; j < ridx; j++) { + if (x == reported_x[j] && y == reported_y[j]) { + ignore = true; + break; + } + } + + if (ignore) { + dev_dbg(&bt541->client->dev, + "ignore shadow finger %d at (%u, %u)\n", i, x, y); + continue; + } + + input_mt_slot(bt541->input_dev, i); + + if (p->sub_status & BIT_DOWN) { + /* Finger down */ + input_mt_report_slot_state(bt541->input_dev, MT_TOOL_FINGER, true); + 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 down (%u, %u)\n", i, x, y); + } else if (p->sub_status & BIT_UP) { + /* Release finger */ + input_mt_report_slot_state(bt541->input_dev, MT_TOOL_FINGER, false); + touchscreen_report_pos(bt541->input_dev, &bt541->prop, x, y, true); + input_report_abs(bt541->input_dev, ABS_MT_TOUCH_MAJOR, 0); + dev_dbg(&bt541->client->dev, "finger %d up (%u, %u)\n", i, x, y); + } else if (p->sub_status & BIT_MOVE) { + /* Finger moves while pressed down */ + input_mt_report_slot_state(bt541->input_dev, MT_TOOL_FINGER, true); + 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 move (%u, %u)\n", i, x, y); + } else { + dev_dbg(&bt541->client->dev, "unknown finger event\n"); + } + + reported_x[ridx] = x; + reported_y[ridx] = y; + ridx++; + } } static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler) @@ -335,7 +393,6 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler) struct i2c_client *client = bt541->client; struct touch_event touch_event; int error; - int i; memset(&touch_event, 0, sizeof(struct touch_event)); @@ -346,10 +403,7 @@ 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]); + zinitix_report_fingers(bt541, &touch_event); input_mt_sync_frame(bt541->input_dev); input_sync(bt541->input_dev); -- 2.34.1