* [PATCH 0/5] Support zinitix touch modes 0 and 1, dt changes to Galaxy J6 (j6lte)
@ 2026-07-23 19:24 Kaustabh Chakraborty
2026-07-23 19:24 ` [PATCH 1/5] Input: zinitix - check all available fingers for every touch event Kaustabh Chakraborty
` (4 more replies)
0 siblings, 5 replies; 9+ messages in thread
From: Kaustabh Chakraborty @ 2026-07-23 19:24 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Srba, Linus Walleij, Peter Griffin, Alim Akhtar
Cc: linux-input, linux-kernel, devicetree, linux-arm-kernel,
linux-samsung-soc, Kaustabh Chakraborty
The zinitix family of touchscreens support at least three modes, called
0, 1, and 2. At least some digitizers (including, but not limited to
ZT7548) are able to support multiple modes. Currently, the driver in
linux supports mode 2 only. This series aims to add support for modes 0
and 1, accompanied with necessary architectural changes.
Among other things, perhaps the biggest difference between multiple
modes is how the touch report schema is laid out. Modes may skip
reporting certain properties such as touch width and pressure. For more
implementation details, the android driver [1] can be referred to, which
was also the primary reference material for these changes.
The last patch is for the Samsung Galaxy J6 (samsung-j6lte), which has a
zinitix touchscreen digitizer. By default, mode 2 is assumed for the
touchscreen, however the downstream kernel driver [1] for this device
uses mode 0 by default. This creates an issue with aftermarket
digitizers where mode 2 implementation isn't available simply because
it's not required by the driver downstream.
This last patch needs to be accepted into next only when the former
patches are in next.
[1] https://github.com/samsungexynos7870/android_kernel_samsung_exynos7870/blob/master/drivers/input/touchscreen/zinitix/zinitix_zt75xx_ts.c
Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
---
Kaustabh Chakraborty (5):
Input: zinitix - check all available fingers for every touch event
Input: zinitix - do not ignore non-moving fingers
Input: zinitix - add support for modes 0 and 1
dt-bindings: input/ts/zinitix: document mode 0
arm64: dts: exynos7870-j6lte: set mode 0 as default for zinitix touchscreen
.../bindings/input/touchscreen/zinitix,bt400.yaml | 4 +-
arch/arm64/boot/dts/exynos/exynos7870-j6lte.dts | 2 +
drivers/input/touchscreen/zinitix.c | 144 +++++++++++++++++++--
3 files changed, 136 insertions(+), 14 deletions(-)
---
base-commit: 290aaf24a551d5a0dce037e3fab30820f9113a10
change-id: 20260723-zinitix-modes-9c4d409b9ee3
Best regards,
--
Kaustabh Chakraborty <kauschluss@disroot.org>
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 1/5] Input: zinitix - check all available fingers for every touch event
2026-07-23 19:24 [PATCH 0/5] Support zinitix touch modes 0 and 1, dt changes to Galaxy J6 (j6lte) Kaustabh Chakraborty
@ 2026-07-23 19:24 ` Kaustabh Chakraborty
2026-07-23 19:33 ` sashiko-bot
2026-07-23 19:24 ` [PATCH 2/5] Input: zinitix - do not ignore non-moving fingers Kaustabh Chakraborty
` (3 subsequent siblings)
4 siblings, 1 reply; 9+ messages in thread
From: Kaustabh Chakraborty @ 2026-07-23 19:24 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Srba, Linus Walleij, Peter Griffin, Alim Akhtar
Cc: linux-input, linux-kernel, devicetree, linux-arm-kernel,
linux-samsung-soc, Kaustabh Chakraborty
When this initial driver was first added to tree, that is, in commit
26822652c85e ("Input: add zinitix touchscreen driver"), the touch_event
struct had a field called finger_cnt. It was supposed to report how many
fingers are touching the screen.
But then, in commit e941dc13fd37 ("Input: zinitix - do not report shadow
fingers"), some touchscreens reportedly exposed a bit mask for the
fingers, instead of the count. So the code was changed to bitwise
iteration.
With my testing on the ZT7548 touchscreen of the Galaxy J6, I find the
former to be true. This shows that there's two valid methods depending
on what hardware the driver is made to work on.
One solution is to implement both methods, and use some flag to select
between the two. However, this introduces more implementation overhead,
and a possibility of regression on devices the driver is expected to work.
Instead, unconditionally check all fingers. The finger_mask field is now
left unused, thus serving as padding bytes in the struct. For each
finger, zinitix_report_finger() is called if the status reports the
SUB_BIT_EXIST bit, so phantom fingers are not going to be a thing.
Moreover, the android driver [1] does exactly that, so it's a tried
method of implementation.
Link: https://android.googlesource.com/kernel/bcm/+/23d376ef33aa4c500a5ea24a290f029d5f8e2de3/drivers/input/touchscreen/zinitix_touch.c#1942 [1]
Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
---
drivers/input/touchscreen/zinitix.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c
index 0c36765bd79f..3421b8ffb19b 100644
--- a/drivers/input/touchscreen/zinitix.c
+++ b/drivers/input/touchscreen/zinitix.c
@@ -445,7 +445,6 @@ 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;
__le16 icon_events;
int error;
int i;
@@ -470,8 +469,7 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
zinitix_report_keys(bt541, le16_to_cpu(icon_events));
}
- finger_mask = touch_event.finger_mask;
- for_each_set_bit(i, &finger_mask, MAX_SUPPORTED_FINGER_NUM) {
+ for (i = 0; i < MAX_SUPPORTED_FINGER_NUM; i++) {
const struct point_coord *p = &touch_event.point_coord[i];
/* Only process contacts that are actually reported */
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 2/5] Input: zinitix - do not ignore non-moving fingers
2026-07-23 19:24 [PATCH 0/5] Support zinitix touch modes 0 and 1, dt changes to Galaxy J6 (j6lte) Kaustabh Chakraborty
2026-07-23 19:24 ` [PATCH 1/5] Input: zinitix - check all available fingers for every touch event Kaustabh Chakraborty
@ 2026-07-23 19:24 ` Kaustabh Chakraborty
2026-07-23 19:32 ` sashiko-bot
2026-07-23 19:24 ` [PATCH 3/5] Input: zinitix - add support for modes 0 and 1 Kaustabh Chakraborty
` (2 subsequent siblings)
4 siblings, 1 reply; 9+ messages in thread
From: Kaustabh Chakraborty @ 2026-07-23 19:24 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Srba, Linus Walleij, Peter Griffin, Alim Akhtar
Cc: linux-input, linux-kernel, devicetree, linux-arm-kernel,
linux-samsung-soc, Kaustabh Chakraborty
With the ZT7548 touchscreen present in the Galaxy J6, multitouch does not
work reliably. This is due to the fact that the driver reports fingers
only when their state is changed, so it's either placed against the
scren, moved, or drawn away from the screen.
The function which is responsible for this is zinitix_report_finger().
This function is called from the IRQ handler, under the following
condition:
if (p->sub_status & SUB_BIT_EXIST)
zinitix_report_finger(bt541, i, p);
This implies and ensures that every valid finger must have the
SUB_BIT_EXIST flag.
However, at the beginning of the function, it refuses to recognize any
finger if it has none of SUB_BIT_UP | SUB_BIT_DOWN | SUB_BIT_MOVE. This
excludes fingers in reports which do not move from the position since
the previous interrupt. Add SUB_BIT_EXIST to the list of valid bits.
Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
---
drivers/input/touchscreen/zinitix.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c
index 3421b8ffb19b..fdcb80f52c91 100644
--- a/drivers/input/touchscreen/zinitix.c
+++ b/drivers/input/touchscreen/zinitix.c
@@ -406,7 +406,7 @@ static void zinitix_report_finger(struct bt541_ts_data *bt541, int slot,
u16 x, y;
if (unlikely(!(p->sub_status &
- (SUB_BIT_UP | SUB_BIT_DOWN | SUB_BIT_MOVE)))) {
+ (SUB_BIT_EXIST | SUB_BIT_UP | SUB_BIT_DOWN | SUB_BIT_MOVE)))) {
dev_dbg(&bt541->client->dev, "unknown finger event %#02x\n",
p->sub_status);
return;
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 3/5] Input: zinitix - add support for modes 0 and 1
2026-07-23 19:24 [PATCH 0/5] Support zinitix touch modes 0 and 1, dt changes to Galaxy J6 (j6lte) Kaustabh Chakraborty
2026-07-23 19:24 ` [PATCH 1/5] Input: zinitix - check all available fingers for every touch event Kaustabh Chakraborty
2026-07-23 19:24 ` [PATCH 2/5] Input: zinitix - do not ignore non-moving fingers Kaustabh Chakraborty
@ 2026-07-23 19:24 ` Kaustabh Chakraborty
2026-07-23 19:33 ` sashiko-bot
2026-07-23 19:24 ` [PATCH 4/5] dt-bindings: input/ts/zinitix: document mode 0 Kaustabh Chakraborty
2026-07-23 19:24 ` [PATCH 5/5] arm64: dts: exynos7870-j6lte: set mode 0 as default for zinitix touchscreen Kaustabh Chakraborty
4 siblings, 1 reply; 9+ messages in thread
From: Kaustabh Chakraborty @ 2026-07-23 19:24 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Srba, Linus Walleij, Peter Griffin, Alim Akhtar
Cc: linux-input, linux-kernel, devicetree, linux-arm-kernel,
linux-samsung-soc, Kaustabh Chakraborty
Zinitix touchscreens have three modes, numbered 0 to 2. The driver
implements mode 2, and leaves out modes 0 and 1. The difference in the
touchscreen modes is the schema of the event data.
Implement modes 0 and 1 in the driver, along with their event structs.
Maintain a common, canonical event struct which is to be the superset of
the mode-specific structs. With that, introduce functions to convert the
mode event info to the canonical format.
Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
---
drivers/input/touchscreen/zinitix.c | 138 +++++++++++++++++++++++++++++++++---
1 file changed, 130 insertions(+), 8 deletions(-)
diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c
index fdcb80f52c91..42010f23445e 100644
--- a/drivers/input/touchscreen/zinitix.c
+++ b/drivers/input/touchscreen/zinitix.c
@@ -145,7 +145,37 @@ struct point_coord {
u8 angle;
};
+struct point_coord_mode0 {
+ __le16 x;
+ __le16 y;
+ u8 width;
+ u8 sub_status;
+};
+
struct touch_event {
+ __le16 status;
+ __le16 event_flag;
+ u8 finger_mask;
+ u8 time_stamp;
+ struct point_coord point_coord[MAX_SUPPORTED_FINGER_NUM];
+};
+
+struct touch_event_mode0 {
+ __le16 status;
+ u8 finger_mask;
+ u8 time_stamp;
+ struct point_coord_mode0 point_coord[MAX_SUPPORTED_FINGER_NUM];
+};
+
+struct touch_event_mode1 {
+ __le16 status;
+ __le16 event_flag;
+ u8 finger_mask;
+ u8 time_stamp;
+ struct point_coord_mode0 point_coord[MAX_SUPPORTED_FINGER_NUM];
+};
+
+struct touch_event_mode2 {
__le16 status;
u8 finger_mask;
u8 time_stamp;
@@ -440,6 +470,103 @@ static void zinitix_report_keys(struct bt541_ts_data *bt541, u16 icon_events)
bt541->keycodes[i], icon_events & BIT(i));
}
+static int zinitix_read_point_status_mode0(struct bt541_ts_data *bt541,
+ struct touch_event *event)
+{
+ struct touch_event_mode0 event_mode0;
+ int ret;
+ int i;
+
+ ret = zinitix_read_data(bt541->client, ZINITIX_POINT_STATUS_REG,
+ &event_mode0, sizeof(struct touch_event_mode0));
+ if (ret)
+ return ret;
+
+ event->status = event_mode0.status;
+ event->finger_mask = event_mode0.finger_mask;
+ event->time_stamp = event_mode0.time_stamp;
+
+ for (i = 0; i < ARRAY_SIZE(event_mode0.point_coord); i++) {
+ event->point_coord[i].x = event_mode0.point_coord[i].x;
+ event->point_coord[i].y = event_mode0.point_coord[i].y;
+ event->point_coord[i].width = event_mode0.point_coord[i].width;
+ event->point_coord[i].sub_status = event_mode0.point_coord[i].sub_status;
+ }
+
+ return 0;
+}
+
+static int zinitix_read_point_status_mode1(struct bt541_ts_data *bt541,
+ struct touch_event *event)
+{
+ struct touch_event_mode1 event_mode1;
+ int ret;
+ int i;
+
+ ret = zinitix_read_data(bt541->client, ZINITIX_POINT_STATUS_REG,
+ &event_mode1, sizeof(struct touch_event_mode1));
+ if (ret)
+ return ret;
+
+ event->status = event_mode1.status;
+ event->event_flag = event_mode1.event_flag;
+ event->finger_mask = event_mode1.finger_mask;
+ event->time_stamp = event_mode1.time_stamp;
+
+ for (i = 0; i < ARRAY_SIZE(event_mode1.point_coord); i++) {
+ event->point_coord[i].x = event_mode1.point_coord[i].x;
+ event->point_coord[i].y = event_mode1.point_coord[i].y;
+ event->point_coord[i].width = event_mode1.point_coord[i].width;
+ event->point_coord[i].sub_status = event_mode1.point_coord[i].sub_status;
+ }
+
+ return 0;
+}
+
+static int zinitix_read_point_status_mode2(struct bt541_ts_data *bt541,
+ struct touch_event *event)
+{
+ struct touch_event_mode2 event_mode2;
+ int ret;
+ int i;
+
+ ret = zinitix_read_data(bt541->client, ZINITIX_POINT_STATUS_REG,
+ &event_mode2, sizeof(struct touch_event_mode2));
+ if (ret)
+ return ret;
+
+ event->status = event_mode2.status;
+ event->finger_mask = event_mode2.finger_mask;
+ event->time_stamp = event_mode2.time_stamp;
+
+ for (i = 0; i < ARRAY_SIZE(event_mode2.point_coord); i++) {
+ event->point_coord[i].x = event_mode2.point_coord[i].x;
+ event->point_coord[i].y = event_mode2.point_coord[i].y;
+ event->point_coord[i].width = event_mode2.point_coord[i].width;
+ event->point_coord[i].sub_status = event_mode2.point_coord[i].sub_status;
+ event->point_coord[i].minor_width = event_mode2.point_coord[i].minor_width;
+ event->point_coord[i].angle = event_mode2.point_coord[i].angle;
+ }
+
+ return 0;
+}
+static int zinitix_read_point_status(struct bt541_ts_data *bt541,
+ struct touch_event *event)
+{
+ switch (bt541->zinitix_mode) {
+ case 0:
+ return zinitix_read_point_status_mode0(bt541, event);
+ case 1:
+ return zinitix_read_point_status_mode1(bt541, event);
+ case 2:
+ return zinitix_read_point_status_mode2(bt541, event);
+ default:
+ dev_err(&bt541->client->dev, "Mode %d is unsupported\n",
+ bt541->zinitix_mode);
+ return -EINVAL;
+ }
+}
+
static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
{
struct bt541_ts_data *bt541 = bt541_handler;
@@ -451,8 +578,7 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
memset(&touch_event, 0, sizeof(struct touch_event));
- error = zinitix_read_data(bt541->client, ZINITIX_POINT_STATUS_REG,
- &touch_event, sizeof(struct touch_event));
+ error = zinitix_read_point_status(bt541, &touch_event);
if (error) {
dev_err(&client->dev, "Failed to read in touchpoint struct\n");
goto out;
@@ -682,13 +808,9 @@ static int zinitix_ts_probe(struct i2c_client *client)
bt541->zinitix_mode = DEFAULT_TOUCH_POINT_MODE;
}
- if (bt541->zinitix_mode != 2) {
- /*
- * If there are devices that don't support mode 2, support
- * for other modes (0, 1) will be needed.
- */
+ if (bt541->zinitix_mode > 2) {
dev_err(&client->dev,
- "Malformed zinitix,mode property, must be 2 (supplied: %d)\n",
+ "Malformed zinitix,mode property, must be 0, 1, or 2 (supplied: %d)\n",
bt541->zinitix_mode);
return -EINVAL;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 4/5] dt-bindings: input/ts/zinitix: document mode 0
2026-07-23 19:24 [PATCH 0/5] Support zinitix touch modes 0 and 1, dt changes to Galaxy J6 (j6lte) Kaustabh Chakraborty
` (2 preceding siblings ...)
2026-07-23 19:24 ` [PATCH 3/5] Input: zinitix - add support for modes 0 and 1 Kaustabh Chakraborty
@ 2026-07-23 19:24 ` Kaustabh Chakraborty
2026-07-23 19:24 ` [PATCH 5/5] arm64: dts: exynos7870-j6lte: set mode 0 as default for zinitix touchscreen Kaustabh Chakraborty
4 siblings, 0 replies; 9+ messages in thread
From: Kaustabh Chakraborty @ 2026-07-23 19:24 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Srba, Linus Walleij, Peter Griffin, Alim Akhtar
Cc: linux-input, linux-kernel, devicetree, linux-arm-kernel,
linux-samsung-soc, Kaustabh Chakraborty
Zinitix touchscreens support three modes, numbered 0 to 2. These modes
differ based on their event report schema.
The devicetree schema does not mention mode 0, thus does not consider it
as a valid state. Add it.
Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
---
.../devicetree/bindings/input/touchscreen/zinitix,bt400.yaml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/input/touchscreen/zinitix,bt400.yaml b/Documentation/devicetree/bindings/input/touchscreen/zinitix,bt400.yaml
index f1ce837b16df..9b51212ea9b9 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/zinitix,bt400.yaml
+++ b/Documentation/devicetree/bindings/input/touchscreen/zinitix,bt400.yaml
@@ -76,9 +76,9 @@ properties:
zinitix,mode:
description: Mode of reporting touch points. Some modes may not work
with a particular ts firmware for unknown reasons. Available modes are
- 1 and 2. Mode 2 is the default and preferred.
+ 0, 1, and 2. Mode 2 is the default and preferred.
$ref: /schemas/types.yaml#/definitions/uint32
- enum: [1, 2]
+ enum: [0, 1, 2]
linux,keycodes:
description:
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 5/5] arm64: dts: exynos7870-j6lte: set mode 0 as default for zinitix touchscreen
2026-07-23 19:24 [PATCH 0/5] Support zinitix touch modes 0 and 1, dt changes to Galaxy J6 (j6lte) Kaustabh Chakraborty
` (3 preceding siblings ...)
2026-07-23 19:24 ` [PATCH 4/5] dt-bindings: input/ts/zinitix: document mode 0 Kaustabh Chakraborty
@ 2026-07-23 19:24 ` Kaustabh Chakraborty
4 siblings, 0 replies; 9+ messages in thread
From: Kaustabh Chakraborty @ 2026-07-23 19:24 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Srba, Linus Walleij, Peter Griffin, Alim Akhtar
Cc: linux-input, linux-kernel, devicetree, linux-arm-kernel,
linux-samsung-soc, Kaustabh Chakraborty
The ZT7548 chip in the Galaxy J6 is actually able to support mode 2 (the
recommended mode) just fine.
However, the downstream kernel driver utilizes mode 0. This creates a
problem in the aftermarket world where fake touch digitizers only
implement the bare minimum functionality, as used by the downstream
driver, to compromise on cost, which leads to such chips implementing
mode 0 only. To ensure touch works on those devices, set the default
mode to 0.
Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
---
arch/arm64/boot/dts/exynos/exynos7870-j6lte.dts | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm64/boot/dts/exynos/exynos7870-j6lte.dts b/arch/arm64/boot/dts/exynos/exynos7870-j6lte.dts
index de30d0970336..bd8f798c9810 100644
--- a/arch/arm64/boot/dts/exynos/exynos7870-j6lte.dts
+++ b/arch/arm64/boot/dts/exynos/exynos7870-j6lte.dts
@@ -424,6 +424,8 @@ touchscreen@20 {
touchscreen-size-y = <1480>;
vdd-supply = <&vdd_ldo34>;
+
+ zinitix,mode = <0>;
};
};
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 2/5] Input: zinitix - do not ignore non-moving fingers
2026-07-23 19:24 ` [PATCH 2/5] Input: zinitix - do not ignore non-moving fingers Kaustabh Chakraborty
@ 2026-07-23 19:32 ` sashiko-bot
0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-07-23 19:32 UTC (permalink / raw)
To: Kaustabh Chakraborty
Cc: devicetree, robh, dmitry.torokhov, conor+dt, linux-input
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
New issues:
- [Low] The validation check in `zinitix_report_finger()` is mathematically impossible to trigger, turning the validation block into dead code and bypassing all event validation.
Pre-existing issues:
- [High] The input device is registered before all driver private data is fully initialized, exposing incomplete state to userspace and violating subsystem rules.
- [High] Regulators enabled in `zinitix_start()` are not disabled on initialization failure paths, leading to a leaked reference count.
- [High] I2C transfers are performed using stack-allocated buffers, which violates kernel safety guidelines for DMA-mapped memory.
--
--- Patch [2]: [PATCH 2/5] Input: zinitix - do not ignore non-moving fingers ---
commit 014178afb268830e3c3cda63dc0ca293fa9a9335
Author: Kaustabh Chakraborty <kauschluss@disroot.org>
Input: zinitix - do not ignore non-moving fingers
This commit addresses an issue with the ZT7548 touchscreen where non-moving
fingers are ignored. It updates the validation mask in zinitix_report_finger()
to include the SUB_BIT_EXIST flag. This ensures fingers that haven't moved
since the last interrupt are properly recognized.
> diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c
> index 3421b8ffb19b2..fdcb80f52c917 100644
> --- a/drivers/input/touchscreen/zinitix.c
> +++ b/drivers/input/touchscreen/zinitix.c
> @@ -406,7 +406,7 @@ static void zinitix_report_finger(struct bt541_ts_data *bt541, int slot,
> u16 x, y;
>
> if (unlikely(!(p->sub_status &
> - (SUB_BIT_UP | SUB_BIT_DOWN | SUB_BIT_MOVE)))) {
> + (SUB_BIT_EXIST | SUB_BIT_UP | SUB_BIT_DOWN | SUB_BIT_MOVE)))) {
[Severity: Low]
Is this validation check mathematically impossible to trigger now?
The caller zinitix_ts_irq_handler() already verifies if SUB_BIT_EXIST is set:
zinitix_ts_irq_handler() {
...
if (p->sub_status & SUB_BIT_EXIST)
zinitix_report_finger(bt541, i, p);
...
}
Since SUB_BIT_EXIST is strictly guaranteed to be present when this function
is called, the bitwise AND always evaluates to a non-zero value.
This means the negated condition will always evaluate to false, rendering
the entire event validation block and its debug log dead code.
> dev_dbg(&bt541->client->dev, "unknown finger event %#02x\n",
> p->sub_status);
> return;
[Severity: High]
This isn't a bug introduced by this patch, but does the input device
registration happen before all driver private data is fully initialized?
In zinitix_ts_probe():
...
error = zinitix_init_input_dev(bt541);
...
error = device_property_read_u32(&client->dev, "zinitix,mode",
&bt541->zinitix_mode);
...
If a userspace process opens the input device immediately upon registration
in zinitix_init_input_dev(), the driver could configure the hardware using
an uninitialized bt541->zinitix_mode.
Could this place the touchscreen into an unsupported mode?
[Severity: High]
This is a pre-existing issue, but are the regulators enabled in
zinitix_start() correctly disabled on initialization failure paths?
zinitix_start() {
...
error = regulator_bulk_enable(ARRAY_SIZE(bt541->supplies),
bt541->supplies);
...
error = zinitix_send_power_on_sequence(bt541);
if (error) {
dev_err(&bt541->client->dev,
"Error while sending power-on sequence: %d\n", error);
return error;
}
...
}
If zinitix_send_power_on_sequence() or zinitix_init_touch() fail, the
function returns without disabling the regulators.
Since the input subsystem considers the device closed on open failure, it
will not call zinitix_input_close().
Could repeated open attempts leak the regulator references?
[Severity: High]
This is a pre-existing issue, but do the I2C transfers use stack-allocated
buffers?
zinitix_write_cmd() {
__le16 reg_le = cpu_to_le16(reg);
int ret;
ret = i2c_master_send(client, (u8 *)®_le, sizeof(reg_le));
...
}
zinitix_ts_irq_handler() {
struct touch_event touch_event;
...
error = zinitix_read_data(bt541->client, ZINITIX_POINT_STATUS_REG,
&touch_event, sizeof(struct touch_event));
...
}
Passing stack-allocated buffers to I2C transfer functions can lead to
memory corruption or DMA API warnings if the underlying I2C controller
driver attempts to use DMA.
Are these buffers safe given that stack memory is not guaranteed to be
DMA-coherent?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260724-zinitix-modes-v1-0-f6df7d86a878@disroot.org?part=2
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 3/5] Input: zinitix - add support for modes 0 and 1
2026-07-23 19:24 ` [PATCH 3/5] Input: zinitix - add support for modes 0 and 1 Kaustabh Chakraborty
@ 2026-07-23 19:33 ` sashiko-bot
0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-07-23 19:33 UTC (permalink / raw)
To: Kaustabh Chakraborty
Cc: devicetree, robh, linux-input, conor+dt, dmitry.torokhov
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] The input device is registered and exposed to userspace before its driver private data (`zinitix_mode`) is fully parsed and initialized, creating a race condition.
- [High] Stack-allocated buffers are passed to I2C transfer functions, which is unsafe and can lead to memory corruption or kernel panics if the I2C adapter relies on DMA.
--
--- Patch [3]: [PATCH 3/5] Input: zinitix - add support for modes 0 and 1 ---
commit 0a0b84e68f36f7bf2e3b751801c1b10ca100ae2e
Author: Kaustabh Chakraborty <kauschluss@disroot.org>
Input: zinitix - add support for modes 0 and 1
This commit implements support for touchscreen modes 0 and 1 in the zinitix
driver by introducing mode-specific event structures. It maintains a common
canonical event structure and adds functions to convert mode-specific event
data into this common format.
> diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c
> index fdcb80f52c917..42010f23445e3 100644
> --- a/drivers/input/touchscreen/zinitix.c
> +++ b/drivers/input/touchscreen/zinitix.c
[ ... ]
> @@ -440,6 +470,103 @@ static void zinitix_report_keys(struct bt541_ts_data *bt541, u16 icon_events)
> bt541->keycodes[i], icon_events & BIT(i));
> }
>
> +static int zinitix_read_point_status_mode0(struct bt541_ts_data *bt541,
> + struct touch_event *event)
> +{
> + struct touch_event_mode0 event_mode0;
> + int ret;
> + int i;
> +
> + ret = zinitix_read_data(bt541->client, ZINITIX_POINT_STATUS_REG,
> + &event_mode0, sizeof(struct touch_event_mode0));
[Severity: High]
This isn't a bug introduced by this patch, but does passing stack-allocated
buffers to I2C transfer functions risk memory corruption?
Looking at zinitix_read_point_status_mode0(), the stack-allocated
event_mode0 structure is passed via zinitix_read_data() to i2c_master_recv().
Because kernel stacks are typically virtually mapped with CONFIG_VMAP_STACK
and are not physically contiguous, if the underlying I2C controller driver
attempts to DMA-map this memory, it can lead to memory corruption or kernel
panics.
This pattern is pre-existing in the driver, but the new mode implementations
continue to use it.
> + if (ret)
> + return ret;
[ ... ]
> @@ -682,13 +808,9 @@ static int zinitix_ts_probe(struct i2c_client *client)
> bt541->zinitix_mode = DEFAULT_TOUCH_POINT_MODE;
> }
>
> - if (bt541->zinitix_mode != 2) {
> - /*
> - * If there are devices that don't support mode 2, support
> - * for other modes (0, 1) will be needed.
> - */
> + if (bt541->zinitix_mode > 2) {
> dev_err(&client->dev,
> - "Malformed zinitix,mode property, must be 2 (supplied: %d)\n",
> + "Malformed zinitix,mode property, must be 0, 1, or 2 (supplied: %d)\n",
> bt541->zinitix_mode);
[Severity: High]
This is a pre-existing issue, but could parsing and validating zinitix_mode
after the input device is registered cause a race condition with userspace?
In zinitix_ts_probe(), zinitix_init_input_dev() is called earlier, which
registers the input device and makes it available to userspace. If userspace
opens the device immediately (e.g., via udev uevents), the hardware might
be initialized with an uninitialized zinitix_mode (0 instead of the intended
mode) before this device property parsing executes. This can lead to the
interrupt handler processing garbage data.
Would it be better to read and validate the "zinitix,mode" property before
calling zinitix_init_input_dev()?
> return -EINVAL;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260724-zinitix-modes-v1-0-f6df7d86a878@disroot.org?part=3
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 1/5] Input: zinitix - check all available fingers for every touch event
2026-07-23 19:24 ` [PATCH 1/5] Input: zinitix - check all available fingers for every touch event Kaustabh Chakraborty
@ 2026-07-23 19:33 ` sashiko-bot
0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-07-23 19:33 UTC (permalink / raw)
To: Kaustabh Chakraborty
Cc: dmitry.torokhov, devicetree, linux-input, robh, conor+dt
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] The patch reintroduces the 'shadow fingers' bug on BT404 touchscreens by reverting the core logic of commit e941dc13fd37.
Pre-existing issues:
- [High] The driver passes stack-allocated variables as buffers to I2C transfer functions (`i2c_master_send`, `i2c_master_recv`), which violates the I2C API contract and is unsafe if the subsystem uses DMA.
--
--- Patch [1]: [PATCH 1/5] Input: zinitix - check all available fingers for every touch event ---
commit 3c2f3ba29bf59a45063f7eee69e37d4b205c7c37
Author: Kaustabh Chakraborty <kauschluss@disroot.org>
Input: zinitix - check all available fingers for every touch event
This commit modifies the zinitix touchscreen driver to unconditionally iterate
over all available finger slots up to MAX_SUPPORTED_FINGER_NUM. It relies
only on SUB_BIT_EXIST instead of using the finger_mask field.
Link: https://android.googlesource.com/kernel/bcm/+/23d376ef33aa4c500a5ea24a290f029d5f8e2de3/drivers/input/touchscreen/zinitix_touch.c#1942 [1]
> diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c
> index 0c36765bd79f8..3421b8ffb19b2 100644
> --- a/drivers/input/touchscreen/zinitix.c
> +++ b/drivers/input/touchscreen/zinitix.c
> @@ -445,7 +445,6 @@ 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;
[Severity: High]
This isn't a bug introduced by this patch, but does passing this
stack-allocated touch_event directly to zinitix_read_data() cause problems
with I2C DMA transfers?
Since zinitix_read_data() wraps i2c_master_recv() and passes this buffer:
zinitix_ts_irq_handler() {
...
error = zinitix_read_data(bt541->client, ZINITIX_POINT_STATUS_REG,
&touch_event, sizeof(struct touch_event));
...
}
Could this lead to memory corruption or kernel panics when CONFIG_VMAP_STACK
is enabled, as stack memory isn't physically contiguous for DMA? This same
pattern appears with local variables passed to i2c_master_send() in
zinitix_read_data() and zinitix_write_u16().
> - unsigned long finger_mask;
> __le16 icon_events;
> int error;
> int i;
[ ... ]
> @@ -470,8 +469,7 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
> zinitix_report_keys(bt541, le16_to_cpu(icon_events));
> }
>
> - finger_mask = touch_event.finger_mask;
> - for_each_set_bit(i, &finger_mask, MAX_SUPPORTED_FINGER_NUM) {
> + for (i = 0; i < MAX_SUPPORTED_FINGER_NUM; i++) {
[Severity: High]
Does this change reintroduce the shadow fingers regression on BT404
touchscreens?
By unconditionally iterating over all slots and relying solely on
SUB_BIT_EXIST instead of the finger_mask:
zinitix_ts_irq_handler() {
...
for (i = 0; i < MAX_SUPPORTED_FINGER_NUM; i++) {
const struct point_coord *p = &touch_event.point_coord[i];
if (p->sub_status & SUB_BIT_EXIST)
zinitix_report_finger(bt541, i, p);
...
}
Won't this break functionality on BT404 firmwares which erroneously populate
multiple slots with SUB_BIT_EXIST set for a single physical touch? This
appears to revert the core logic explicitly introduced in commit
e941dc13fd37 to filter out those phantom fingers.
> const struct point_coord *p = &touch_event.point_coord[i];
>
> /* Only process contacts that are actually reported */
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260724-zinitix-modes-v1-0-f6df7d86a878@disroot.org?part=1
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-07-23 19:33 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-23 19:24 [PATCH 0/5] Support zinitix touch modes 0 and 1, dt changes to Galaxy J6 (j6lte) Kaustabh Chakraborty
2026-07-23 19:24 ` [PATCH 1/5] Input: zinitix - check all available fingers for every touch event Kaustabh Chakraborty
2026-07-23 19:33 ` sashiko-bot
2026-07-23 19:24 ` [PATCH 2/5] Input: zinitix - do not ignore non-moving fingers Kaustabh Chakraborty
2026-07-23 19:32 ` sashiko-bot
2026-07-23 19:24 ` [PATCH 3/5] Input: zinitix - add support for modes 0 and 1 Kaustabh Chakraborty
2026-07-23 19:33 ` sashiko-bot
2026-07-23 19:24 ` [PATCH 4/5] dt-bindings: input/ts/zinitix: document mode 0 Kaustabh Chakraborty
2026-07-23 19:24 ` [PATCH 5/5] arm64: dts: exynos7870-j6lte: set mode 0 as default for zinitix touchscreen Kaustabh Chakraborty
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox