input/touchscreen: New EETI eGalaxTouch serial touchscreen driver
diff mbox

Message ID 20151215212123.GA18844@dtor-ws
State Superseded
Headers show

Commit Message

Dmitry Torokhov Dec. 15, 2015, 9:21 p.m. UTC
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 <zboszor@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 <zboszor@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 <zboszor@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 <zboszor@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!

Comments

Böszörményi Zoltán Dec. 16, 2015, 12:43 p.m. UTC | #1
2015-12-15 22:21 keltezéssel, Dmitry Torokhov írta:
> 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 <zboszor@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 <zboszor@pr.hu>
>>
> Thank you for your patch, it looks pretty good, just a few comments
> below.
>
>> +config TOUCHSCREEN_EGALAX_SERIO
> I'd rather called it TOUCHSCREEN_EGALAX_SERIAL

It doesn't matter, I am not attached to names.

>> +obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIO)	+= egalax.o
> I think better name is egalax_ts_serial.

Sure, I was thinking about it myself.

>>  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 <zboszor@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 <zboszor@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.

See my comment below.

>> +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.

OK, whatever you think is better. I am not familiar with the input
subsystem internals.

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

While the code itself didn't look suspicious at first, testing showed
that it doesn't work when compiled in with 4.4-rc5, while my original
code did. You got the mask and expanding my macros wrong.
I will submit a v3 patch, as yours was v2.

Thanks,
Zoltán Böszörményi

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch
diff mbox

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 <zboszor@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 <zboszor@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 */