diff options
| author | Donggeun Yoo <donggeunyoo.kernel@gmail.com> | 2026-09-02 00:21:26 +0900 |
|---|---|---|
| committer | Jonathan Cameron <jonathan.cameron@oss.qualcomm.com> | 2026-09-07 02:24:53 +0100 |
| commit | e24328974a88aa8541e94e8bb8dfa2ade1b3c45d (patch) | |
| tree | 43a2533acc955d11f5cb8be1ecba0ab8ba4cbb1e /drivers/input/touchscreen/gunze.c | |
| download | linux-stable-e24328974a88aa8541e94e8bb8dfa2ade1b3c45d.tar.gz linux-stable-e24328974a88aa8541e94e8bb8dfa2ade1b3c45d.zip | |
iio: proximity: vl53l0x-i2c: claim direct mode for raw readsgrafted
vl53l0x_read_raw() starts a single-shot ranging measurement and reads
back the result. Once the triggered buffer is enabled the sensor runs in
continuous mode and its data-ready interrupt is routed to the trigger,
so a concurrent in_distance_raw read disturbs the streaming setup and
never gets its completion, returning -ETIMEDOUT.
The original submission claimed direct mode here, but it was dropped
during review because the driver had no buffer support at the time [1].
Continuous (buffered) mode was later added without restoring the
claim [2], reintroducing the conflict.
Reject direct reads while buffered capture is active by claiming direct
mode around the measurement, as the vl53l1x sibling already does.
Fixes: 762186c6e7b1 ("iio: proximity: vl53l0x-i2c: Added continuous mode support")
Link: https://lore.kernel.org/linux-iio/20180911160300.GA9212@himanshu-Vostro-3559/ [1]
Link: https://lore.kernel.org/linux-iio/20240909101508.263085-3-abhashkumarjha123@gmail.com/ [2]
Signed-off-by: Donggeun Yoo <donggeunyoo.kernel@gmail.com>
Cc: stable@vger.kernel.org
Signed-off-by: Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>
Diffstat (limited to 'drivers/input/touchscreen/gunze.c')
| -rw-r--r-- | drivers/input/touchscreen/gunze.c | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c new file mode 100644 index 000000000..2baeb4f3b --- /dev/null +++ b/drivers/input/touchscreen/gunze.c @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2000-2001 Vojtech Pavlik + */ + +/* + * Gunze AHL-51S touchscreen driver for Linux + */ + +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/input.h> +#include <linux/serio.h> + +#define DRIVER_DESC "Gunze AHL-51S touchscreen driver" + +MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +/* + * Definitions & global arrays. + */ + +#define GUNZE_MAX_LENGTH 10 + +/* + * Per-touchscreen data. + */ + +struct gunze { + struct input_dev *dev; + struct serio *serio; + int idx; + unsigned char data[GUNZE_MAX_LENGTH]; + char phys[32]; +}; + +static void gunze_process_packet(struct gunze *gunze) +{ + struct input_dev *dev = gunze->dev; + + if (gunze->idx != GUNZE_MAX_LENGTH || gunze->data[5] != ',' || + (gunze->data[0] != 'T' && gunze->data[0] != 'R')) { + printk(KERN_WARNING "gunze.c: bad packet: >%.*s<\n", GUNZE_MAX_LENGTH, gunze->data); + return; + } + + input_report_abs(dev, ABS_X, simple_strtoul(gunze->data + 1, NULL, 10)); + input_report_abs(dev, ABS_Y, 1024 - simple_strtoul(gunze->data + 6, NULL, 10)); + input_report_key(dev, BTN_TOUCH, gunze->data[0] == 'T'); + input_sync(dev); +} + +static irqreturn_t gunze_interrupt(struct serio *serio, + unsigned char data, unsigned int flags) +{ + struct gunze *gunze = serio_get_drvdata(serio); + + if (data == '\r') { + gunze_process_packet(gunze); + gunze->idx = 0; + } else { + if (gunze->idx < GUNZE_MAX_LENGTH) + gunze->data[gunze->idx++] = data; + } + return IRQ_HANDLED; +} + +/* + * gunze_disconnect() is the opposite of gunze_connect() + */ + +static void gunze_disconnect(struct serio *serio) +{ + struct gunze *gunze = serio_get_drvdata(serio); + + input_get_device(gunze->dev); + input_unregister_device(gunze->dev); + serio_close(serio); + serio_set_drvdata(serio, NULL); + input_put_device(gunze->dev); + kfree(gunze); +} + +/* + * gunze_connect() is the routine that is called when someone adds a + * new serio device that supports Gunze protocol and registers it as + * an input device. + */ + +static int gunze_connect(struct serio *serio, struct serio_driver *drv) +{ + struct gunze *gunze; + struct input_dev *input_dev; + int err; + + gunze = kzalloc_obj(*gunze); + input_dev = input_allocate_device(); + if (!gunze || !input_dev) { + err = -ENOMEM; + goto fail1; + } + + gunze->serio = serio; + gunze->dev = input_dev; + scnprintf(gunze->phys, sizeof(serio->phys), "%s/input0", serio->phys); + + input_dev->name = "Gunze AHL-51S TouchScreen"; + input_dev->phys = gunze->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_GUNZE; + input_dev->id.product = 0x0051; + input_dev->id.version = 0x0100; + input_dev->dev.parent = &serio->dev; + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + input_set_abs_params(input_dev, ABS_X, 24, 1000, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 24, 1000, 0, 0); + + serio_set_drvdata(serio, gunze); + + err = serio_open(serio, drv); + if (err) + goto fail2; + + err = input_register_device(gunze->dev); + if (err) + goto fail3; + + return 0; + + fail3: serio_close(serio); + fail2: serio_set_drvdata(serio, NULL); + fail1: input_free_device(input_dev); + kfree(gunze); + return err; +} + +/* + * The serio driver structure. + */ + +static const struct serio_device_id gunze_serio_ids[] = { + { + .type = SERIO_RS232, + .proto = SERIO_GUNZE, + .id = SERIO_ANY, + .extra = SERIO_ANY, + }, + { 0 } +}; + +MODULE_DEVICE_TABLE(serio, gunze_serio_ids); + +static struct serio_driver gunze_drv = { + .driver = { + .name = "gunze", + }, + .description = DRIVER_DESC, + .id_table = gunze_serio_ids, + .interrupt = gunze_interrupt, + .connect = gunze_connect, + .disconnect = gunze_disconnect, +}; + +module_serio_driver(gunze_drv); |
