Hi Zoltán,

On Tue, Dec 15, 2015 at 12:22:07PM +0100, Böszörményi Zoltán wrote:
> From: Böszörményi Zoltán <zbos...@pr.hu>
> 
> There are two EETI touchscreen drivers in the kernel (eeti_ts and egalax_ts)
> but both are for I2C-connected panels. This is for a different, serial
> and not multi-touch touchscreen panel. The protocol documentation is at
> http://www.eeti.com.tw/pdf/Software%20Programming%20Guide_v2.0.pdf
> 
> Signed-off-by: Böszörményi Zoltán <zbos...@pr.hu>
> 

Thank you for your patch, it looks pretty good, just a few comments
below.

> ---
>  drivers/input/touchscreen/Kconfig  |  10 ++
>  drivers/input/touchscreen/Makefile |   1 +
>  drivers/input/touchscreen/egalax.c | 210 
> +++++++++++++++++++++++++++++++++++++
>  include/uapi/linux/serio.h         |   1 +
>  4 files changed, 222 insertions(+)
>  create mode 100644 drivers/input/touchscreen/egalax.c
> 
> diff --git a/drivers/input/touchscreen/Kconfig 
> b/drivers/input/touchscreen/Kconfig
> index ae33da7..816a9dc 100644
> --- a/drivers/input/touchscreen/Kconfig
> +++ b/drivers/input/touchscreen/Kconfig
> @@ -301,20 +301,30 @@ config TOUCHSCREEN_FT6236
>       depends on GPIOLIB || COMPILE_TEST
>       help
>         Say Y here to enable support for the I2C connected FT6x06 and
>         FT6x36 family of capacitive touchscreen drivers.
>  
>         If unsure, say N.
>  
>         To compile this driver as a module, choose M here: the
>         module will be called ft6236.
>  
> +config TOUCHSCREEN_EGALAX_SERIO

I'd rather called it TOUCHSCREEN_EGALAX_SERIAL

> +     tristate "EETI eGalax serial touchscreen"
> +     select SERIO
> +     help
> +       Say Y here to enable support for serial connected EETI
> +       eGalax touch panels.
> +
> +       To compile this driver as a module, choose M here: the
> +       module will be called egalax.
> +
>  config TOUCHSCREEN_FUJITSU
>       tristate "Fujitsu serial touchscreen"
>       select SERIO
>       help
>         Say Y here if you have the Fujitsu touchscreen (such as one
>         installed in Lifebook P series laptop) connected to your
>         system.
>  
>         If unsure, say N.
>  
> diff --git a/drivers/input/touchscreen/Makefile 
> b/drivers/input/touchscreen/Makefile
> index cbaa6ab..6f63b51 100644
> --- a/drivers/input/touchscreen/Makefile
> +++ b/drivers/input/touchscreen/Makefile
> @@ -28,20 +28,21 @@ obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_SPI)     += cyttsp4_spi.o
>  obj-$(CONFIG_TOUCHSCREEN_DA9034)     += da9034-ts.o
>  obj-$(CONFIG_TOUCHSCREEN_DA9052)     += da9052_tsi.o
>  obj-$(CONFIG_TOUCHSCREEN_DYNAPRO)    += dynapro.o
>  obj-$(CONFIG_TOUCHSCREEN_EDT_FT5X06) += edt-ft5x06.o
>  obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)  += hampshire.o
>  obj-$(CONFIG_TOUCHSCREEN_GUNZE)              += gunze.o
>  obj-$(CONFIG_TOUCHSCREEN_EETI)               += eeti_ts.o
>  obj-$(CONFIG_TOUCHSCREEN_ELAN)               += elants_i2c.o
>  obj-$(CONFIG_TOUCHSCREEN_ELO)                += elo.o
>  obj-$(CONFIG_TOUCHSCREEN_EGALAX)     += egalax_ts.o
> +obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIO)       += egalax.o

I think better name is egalax_ts_serial.

>  obj-$(CONFIG_TOUCHSCREEN_FT6236)     += ft6236.o
>  obj-$(CONFIG_TOUCHSCREEN_FUJITSU)    += fujitsu_ts.o
>  obj-$(CONFIG_TOUCHSCREEN_GOODIX)     += goodix.o
>  obj-$(CONFIG_TOUCHSCREEN_ILI210X)    += ili210x.o
>  obj-$(CONFIG_TOUCHSCREEN_IMX6UL_TSC) += imx6ul_tsc.o
>  obj-$(CONFIG_TOUCHSCREEN_INEXIO)     += inexio.o
>  obj-$(CONFIG_TOUCHSCREEN_INTEL_MID)  += intel-mid-touch.o
>  obj-$(CONFIG_TOUCHSCREEN_IPROC)              += bcm_iproc_tsc.o
>  obj-$(CONFIG_TOUCHSCREEN_LPC32XX)    += lpc32xx_ts.o
>  obj-$(CONFIG_TOUCHSCREEN_MAX11801)   += max11801_ts.o
> diff --git a/drivers/input/touchscreen/egalax.c 
> b/drivers/input/touchscreen/egalax.c
> new file mode 100644
> index 0000000..94ac9bd
> --- /dev/null
> +++ b/drivers/input/touchscreen/egalax.c
> @@ -0,0 +1,210 @@
> +/*
> + * EETI Egalax serial touchscreen driver
> + *
> + * Copyright (c) 2015 Zoltán Böszörményi <zbos...@pr.hu>
> + *
> + * based on the
> + *
> + * Hampshire serial touchscreen driver (Copyright (c) 2010 Adam Bennett)
> + */
> +
> +/*
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published 
> by
> + * the Free Software Foundation.
> + */
> +
> +#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  "EETI Egalax serial touchscreen driver"
> +
> +MODULE_AUTHOR("Zoltán Böszörményi <zbos...@pr.hu>");
> +MODULE_DESCRIPTION(DRIVER_DESC);
> +MODULE_LICENSE("GPL");
> +
> +/*
> + * Definitions & global arrays.
> + */
> +
> +#define EGALAX_FORMAT_MAX_LENGTH 6
> +#define EGALAX_RESPONSE_BEGIN_BYTE 0x80
> +#define EGALAX_FORMAT_PRESSURE_BIT 0x40
> +#define EGALAX_FORMAT_TOUCH_BIT 0x01

We have BIT() macro that would be very useful here.

> +#define EGALAX_FORMAT_RESOLUTION 0x06
> +
> +#define EGALAX_MIN_XC 0
> +#define EGALAX_MAX_XC 0x4000
> +#define EGALAX_MIN_YC 0
> +#define EGALAX_MAX_YC 0x4000
> +
> +#define EGALAX_GET_XC(data, resbits, shift) ((((data[1] & (resbits)) << 7) | 
> (data[2] & 0x7f)) << shift)
> +#define EGALAX_GET_YC(data, resbits, shift) ((((data[3] & (resbits)) << 7) | 
> (data[4] & 0x7f)) << shift)
> +#define EGALAX_GET_TOUCHED(data) (EGALAX_FORMAT_TOUCH_BIT & data[0])
> +
> +/*
> + * Per-touchscreen data.
> + */
> +
> +struct egalax {
> +     struct input_dev *dev;
> +     struct serio *serio;
> +     int idx;
> +     int bytes;
> +     int resbits;
> +     int shift;
> +     unsigned char data[EGALAX_FORMAT_MAX_LENGTH];
> +     char phys[32];
> +};
> +
> +static void egalax_process_data(struct egalax *pegalax)
> +{
> +     struct input_dev *dev = pegalax->dev;
> +
> +     if (++pegalax->idx == pegalax->bytes) {
> +             input_report_abs(dev, ABS_X, EGALAX_GET_XC(pegalax->data, 
> pegalax->resbits, pegalax->shift));
> +             input_report_abs(dev, ABS_Y, EGALAX_GET_YC(pegalax->data, 
> pegalax->resbits, pegalax->shift));
> +             input_report_key(dev, BTN_TOUCH, 
> EGALAX_GET_TOUCHED(pegalax->data));
> +             input_sync(dev);
> +
> +             pegalax->idx = 0;
> +     }
> +}
> +
> +static irqreturn_t egalax_interrupt(struct serio *serio,
> +             unsigned char data, unsigned int flags)
> +{
> +     struct egalax *pegalax = serio_get_drvdata(serio);
> +
> +     pegalax->data[pegalax->idx] = data;
> +
> +     if (EGALAX_RESPONSE_BEGIN_BYTE & pegalax->data[0]) {
> +             pegalax->bytes = (EGALAX_FORMAT_PRESSURE_BIT & pegalax->data[0] 
> ? 6 : 5);
> +             switch ((EGALAX_FORMAT_RESOLUTION & pegalax->data[0]) >> 1) {
> +             case 0:
> +                     pegalax->resbits = 0x0f;
> +                     pegalax->shift = 3;
> +                     break;
> +             case 1:
> +                     pegalax->resbits = 0x1f;
> +                     pegalax->shift = 2;
> +                     break;
> +             case 2:
> +                     pegalax->resbits = 0x3f;
> +                     pegalax->shift = 1;
> +                     break;
> +             default:
> +                     pegalax->resbits = 0x7f;
> +                     pegalax->shift = 0;
> +                     break;
> +             }
> +             egalax_process_data(pegalax);

There is no reason to recalculate shift and mask on every byte and call
egalax_process_data(), better is to wait till you get full packet and
then do the claculations. Also I think you can avoid conditional
computation (switch) here.

> +     }
> +     else
> +             dev_dbg(&serio->dev, "unknown/unsynchronized data: %x\n",
> +                     pegalax->data[0]);
> +
> +     return IRQ_HANDLED;
> +}
> +
> +static void egalax_disconnect(struct serio *serio)
> +{
> +     struct egalax *pegalax = serio_get_drvdata(serio);
> +
> +     input_get_device(pegalax->dev);
> +     input_unregister_device(pegalax->dev);
> +     serio_close(serio);
> +     serio_set_drvdata(serio, NULL);
> +     input_put_device(pegalax->dev);
> +     kfree(pegalax);

This is needlessly complicated (although I do know we have this code in
other drivers). Since we do not send any data *to* the touch controller
we can close the port first and then unregister the device.

Could you please try the version of the patch below and let me know if
it works for you?

Thanks!

-- 
Dmitry


Input: input/touchscreen - new EETI eGalaxTouch serial touchscreen driver

From: Böszörményi Zoltán <zbos...@pr.hu>

There are two EETI touchscreen drivers in the kernel (eeti_ts and egalax_ts)
but both are for I2C-connected panels. This is for a different, serial
and not multi-touch touchscreen panel. The protocol documentation is at
http://www.eeti.com.tw/pdf/Software%20Programming%20Guide_v2.0.pdf

Signed-off-by: Böszörményi Zoltán <zbos...@pr.hu>
Signed-off-by: Dmitry Torokhov <dmitry.torok...@gmail.com>
---
 drivers/input/touchscreen/Kconfig            |   10 +
 drivers/input/touchscreen/Makefile           |    1 
 drivers/input/touchscreen/egalax_ts_serial.c |  194 ++++++++++++++++++++++++++
 include/uapi/linux/serio.h                   |    1 
 4 files changed, 206 insertions(+)
 create mode 100644 drivers/input/touchscreen/egalax_ts_serial.c

diff --git a/drivers/input/touchscreen/Kconfig 
b/drivers/input/touchscreen/Kconfig
index 901160a..09707d8 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -295,6 +295,16 @@ config TOUCHSCREEN_EGALAX
          To compile this driver as a module, choose M here: the
          module will be called egalax_ts.
 
+config TOUCHSCREEN_EGALAX_SERIAL
+       tristate "EETI eGalax serial touchscreen"
+       select SERIO
+       help
+         Say Y here to enable support for serial connected EETI
+         eGalax touch panels.
+
+         To compile this driver as a module, choose M here: the
+         module will be called egalax_ts_serial.
+
 config TOUCHSCREEN_FT6236
        tristate "FT6236 I2C touchscreen"
        depends on I2C
diff --git a/drivers/input/touchscreen/Makefile 
b/drivers/input/touchscreen/Makefile
index f60ef31..c5cabdf 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_TOUCHSCREEN_EETI)                += eeti_ts.o
 obj-$(CONFIG_TOUCHSCREEN_ELAN)         += elants_i2c.o
 obj-$(CONFIG_TOUCHSCREEN_ELO)          += elo.o
 obj-$(CONFIG_TOUCHSCREEN_EGALAX)       += egalax_ts.o
+obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL)        += egalax_ts_serial.o
 obj-$(CONFIG_TOUCHSCREEN_FT6236)       += ft6236.o
 obj-$(CONFIG_TOUCHSCREEN_FUJITSU)      += fujitsu_ts.o
 obj-$(CONFIG_TOUCHSCREEN_GOODIX)       += goodix.o
diff --git a/drivers/input/touchscreen/egalax_ts_serial.c 
b/drivers/input/touchscreen/egalax_ts_serial.c
new file mode 100644
index 0000000..76cef21
--- /dev/null
+++ b/drivers/input/touchscreen/egalax_ts_serial.c
@@ -0,0 +1,194 @@
+/*
+ * EETI Egalax serial touchscreen driver
+ *
+ * Copyright (c) 2015 Zoltán Böszörményi <zbos...@pr.hu>
+ *
+ * based on the
+ *
+ * Hampshire serial touchscreen driver (Copyright (c) 2010 Adam Bennett)
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#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    "EETI Egalax serial touchscreen driver"
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define EGALAX_FORMAT_MAX_LENGTH       6
+#define EGALAX_FORMAT_START_BIT                BIT(7)
+#define EGALAX_FORMAT_PRESSURE_BIT     BIT(6)
+#define EGALAX_FORMAT_TOUCH_BIT                BIT(0)
+#define EGALAX_FORMAT_RESOLUTION_MASK  0x06
+
+#define EGALAX_MIN_XC                  0
+#define EGALAX_MAX_XC                  0x4000
+#define EGALAX_MIN_YC                  0
+#define EGALAX_MAX_YC                  0x4000
+
+/*
+ * Per-touchscreen data.
+ */
+struct egalax {
+       struct input_dev *input;
+       struct serio *serio;
+       int idx;
+       u8 data[EGALAX_FORMAT_MAX_LENGTH];
+       char phys[32];
+};
+
+static void egalax_process_data(struct egalax *egalax)
+{
+       struct input_dev *dev = egalax->input;
+       u8 *data = egalax->data;
+       u16 x, y;
+       u8 shift;
+       u8 mask;
+
+       shift = 3 - ((data[0] & EGALAX_FORMAT_RESOLUTION_MASK) >> 1);
+       mask = -1U >> (shift + 1);
+
+       x = (((u16)data[1] & mask) << 7) | ((data[2] & 0x7f) << shift);
+       y = (((u16)data[3] & mask) << 7) | ((data[4] & 0x7f) << shift);
+
+       input_report_key(dev, BTN_TOUCH, data[0] & EGALAX_FORMAT_TOUCH_BIT);
+       input_report_abs(dev, ABS_X, x);
+       input_report_abs(dev, ABS_Y, y);
+       input_sync(dev);
+}
+
+static irqreturn_t egalax_interrupt(struct serio *serio,
+                                   unsigned char data, unsigned int flags)
+{
+       struct egalax *egalax = serio_get_drvdata(serio);
+       int pkt_len;
+
+       egalax->data[egalax->idx++] = data;
+
+       if (likely(egalax->data[0] & EGALAX_FORMAT_START_BIT)) {
+               pkt_len = egalax->data[0] & EGALAX_FORMAT_PRESSURE_BIT ? 6 : 5;
+               if (pkt_len == egalax->idx) {
+                       egalax_process_data(egalax);
+                       egalax->idx = 0;
+               }
+       } else {
+               dev_dbg(&serio->dev, "unknown/unsynchronized data: %x\n",
+                       egalax->data[0]);
+               egalax->idx = 0;
+       }
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * egalax_connect() is the routine that is called when someone adds a
+ * new serio device that supports egalax protocol and registers it as
+ * an input device. This is usually accomplished using inputattach.
+ */
+static int egalax_connect(struct serio *serio, struct serio_driver *drv)
+{
+       struct egalax *egalax;
+       struct input_dev *input_dev;
+       int error;
+
+       egalax = kzalloc(sizeof(struct egalax), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!egalax) {
+               error = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       egalax->serio = serio;
+       egalax->input = input_dev;
+       snprintf(egalax->phys, sizeof(egalax->phys),
+                "%s/input0", serio->phys);
+
+       input_dev->name = "EETI eGalaxTouch Serial TouchScreen";
+       input_dev->phys = egalax->phys;
+       input_dev->id.bustype = BUS_RS232;
+       input_dev->id.vendor = SERIO_EGALAX;
+       input_dev->id.product = 0;
+       input_dev->id.version = 0x0001;
+       input_dev->dev.parent = &serio->dev;
+
+       input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
+       input_set_abs_params(input_dev, ABS_X,
+                            EGALAX_MIN_XC, EGALAX_MAX_XC, 0, 0);
+       input_set_abs_params(input_dev, ABS_Y,
+                            EGALAX_MIN_YC, EGALAX_MAX_YC, 0, 0);
+
+       serio_set_drvdata(serio, egalax);
+
+       error = serio_open(serio, drv);
+       if (error)
+               goto err_reset_drvdata;
+
+       error = input_register_device(input_dev);
+       if (error)
+               goto err_close_serio;
+
+       return 0;
+
+err_close_serio:
+       serio_close(serio);
+err_reset_drvdata:
+       serio_set_drvdata(serio, NULL);
+err_free_mem:
+       input_free_device(input_dev);
+       kfree(egalax);
+       return error;
+}
+
+static void egalax_disconnect(struct serio *serio)
+{
+       struct egalax *egalax = serio_get_drvdata(serio);
+
+       serio_close(serio);
+       serio_set_drvdata(serio, NULL);
+       input_unregister_device(egalax->input);
+       kfree(egalax);
+}
+
+/*
+ * The serio driver structure.
+ */
+
+static const struct serio_device_id egalax_serio_ids[] = {
+       {
+               .type   = SERIO_RS232,
+               .proto  = SERIO_EGALAX,
+               .id     = SERIO_ANY,
+               .extra  = SERIO_ANY,
+       },
+       { 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, egalax_serio_ids);
+
+static struct serio_driver egalax_drv = {
+       .driver         = {
+               .name   = "egalax",
+       },
+       .description    = DRIVER_DESC,
+       .id_table       = egalax_serio_ids,
+       .interrupt      = egalax_interrupt,
+       .connect        = egalax_connect,
+       .disconnect     = egalax_disconnect,
+};
+module_serio_driver(egalax_drv);
+
+MODULE_AUTHOR("Zoltán Böszörményi <zbos...@pr.hu>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL v2");
diff --git a/include/uapi/linux/serio.h b/include/uapi/linux/serio.h
index becdd78..c2ea169 100644
--- a/include/uapi/linux/serio.h
+++ b/include/uapi/linux/serio.h
@@ -77,5 +77,6 @@
 #define SERIO_PS2MULT  0x3c
 #define SERIO_TSC40    0x3d
 #define SERIO_WACOM_IV 0x3e
+#define SERIO_EGALAX   0x3f
 
 #endif /* _UAPI_SERIO_H */
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to