From patchwork Tue Dec 15 21:21:23 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Dmitry Torokhov X-Patchwork-Id: 7857171 Return-Path: X-Original-To: patchwork-linux-input@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id DBAF5BEEE1 for ; Tue, 15 Dec 2015 21:21:31 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 410E5203E3 for ; Tue, 15 Dec 2015 21:21:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 65E39202FE for ; Tue, 15 Dec 2015 21:21:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S965306AbbLOVV1 (ORCPT ); Tue, 15 Dec 2015 16:21:27 -0500 Received: from mail-pa0-f47.google.com ([209.85.220.47]:34224 "EHLO mail-pa0-f47.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S965279AbbLOVV0 (ORCPT ); Tue, 15 Dec 2015 16:21:26 -0500 Received: by mail-pa0-f47.google.com with SMTP id wq6so11429415pac.1 for ; Tue, 15 Dec 2015 13:21:26 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=date:from:to:cc:subject:message-id:references:mime-version :content-type:content-disposition:content-transfer-encoding :in-reply-to:user-agent; bh=rMPPFb1Y9+Xjpn+FQvOpHNZ1dCdHPA03ndpBppQhqdg=; b=olHtiIlc59GsYSLuWGXAyfKwTCp52bnoH+3xohZtY2tar/mtMA4o36zp+IFiS1KF7d 6BdR30EYu+ryo5cRMzl8f6sPzbQkVByhQSJu+BrY9a0E+mxuao6z1XJmaNaJ5AKxUhhj 8iC61T9v9cqqhwsF2cxu1PeUI5wIRvx3QHepmSNGLfXqgYGd6It9WScHQEhPJeej1QxU 470dQUih0AzEHw7HouadPXPq/JXff/gzD7NekstDWvnJbGQ5wgGgUOoQq6BUmr2r+1t7 qAKQtG7RfelDXGP8PNNW/W4SuKqwFNdXPzCbAcKh5zRez0B5TtzAw2GocA4vUrfq0F3Z SLnA== X-Received: by 10.66.100.163 with SMTP id ez3mr58514387pab.5.1450214485944; Tue, 15 Dec 2015 13:21:25 -0800 (PST) Received: from dtor-ws ([2620:0:1000:1301:71d4:9a90:677f:84a0]) by smtp.gmail.com with ESMTPSA id 26sm24951pfn.61.2015.12.15.13.21.24 (version=TLS1_2 cipher=AES128-SHA bits=128/128); Tue, 15 Dec 2015 13:21:25 -0800 (PST) Date: Tue, 15 Dec 2015 13:21:23 -0800 From: Dmitry Torokhov To: =?iso-8859-1?B?QvZzevZybelueWkgWm9sdOFu?= Cc: linux-input@vger.kernel.org, =?iso-8859-1?B?QvZzevZybelueWkgWm9sdOFu?= Subject: Re: [PATCH] input/touchscreen: New EETI eGalaxTouch serial touchscreen driver Message-ID: <20151215212123.GA18844@dtor-ws> References: <1450178527-26745-1-git-send-email-zboszormenyi@sicom.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <1450178527-26745-1-git-send-email-zboszormenyi@sicom.com> User-Agent: Mutt/1.5.21 (2010-09-15) Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, T_DKIM_INVALID, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 > > 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 > 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 > + * > + * 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 > +#include > +#include > +#include > +#include > +#include > + > +#define DRIVER_DESC "EETI Egalax serial touchscreen driver" > + > +MODULE_AUTHOR("Zoltán Böszörményi "); > +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! 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 + * + * 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 +#include +#include +#include +#include +#include + +#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 "); +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 */