Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: add eGalaxTouch serial touchscreen driver

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>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

authored by

Böszörményi Zoltán and committed by
Dmitry Torokhov
6b0f8f9c f889beaa

+206
+10
drivers/input/touchscreen/Kconfig
··· 295 295 To compile this driver as a module, choose M here: the 296 296 module will be called egalax_ts. 297 297 298 + config TOUCHSCREEN_EGALAX_SERIAL 299 + tristate "EETI eGalax serial touchscreen" 300 + select SERIO 301 + help 302 + Say Y here to enable support for serial connected EETI 303 + eGalax touch panels. 304 + 305 + To compile this driver as a module, choose M here: the 306 + module will be called egalax_ts_serial. 307 + 298 308 config TOUCHSCREEN_FT6236 299 309 tristate "FT6236 I2C touchscreen" 300 310 depends on I2C
+1
drivers/input/touchscreen/Makefile
··· 35 35 obj-$(CONFIG_TOUCHSCREEN_ELAN) += elants_i2c.o 36 36 obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o 37 37 obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o 38 + obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL) += egalax_ts_serial.o 38 39 obj-$(CONFIG_TOUCHSCREEN_FT6236) += ft6236.o 39 40 obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o 40 41 obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o
+194
drivers/input/touchscreen/egalax_ts_serial.c
··· 1 + /* 2 + * EETI Egalax serial touchscreen driver 3 + * 4 + * Copyright (c) 2015 Zoltán Böszörményi <zboszor@pr.hu> 5 + * 6 + * based on the 7 + * 8 + * Hampshire serial touchscreen driver (Copyright (c) 2010 Adam Bennett) 9 + */ 10 + 11 + /* 12 + * This program is free software; you can redistribute it and/or modify it 13 + * under the terms of the GNU General Public License version 2 as published by 14 + * the Free Software Foundation. 15 + */ 16 + 17 + #include <linux/errno.h> 18 + #include <linux/kernel.h> 19 + #include <linux/module.h> 20 + #include <linux/slab.h> 21 + #include <linux/input.h> 22 + #include <linux/serio.h> 23 + 24 + #define DRIVER_DESC "EETI Egalax serial touchscreen driver" 25 + 26 + /* 27 + * Definitions & global arrays. 28 + */ 29 + 30 + #define EGALAX_FORMAT_MAX_LENGTH 6 31 + #define EGALAX_FORMAT_START_BIT BIT(7) 32 + #define EGALAX_FORMAT_PRESSURE_BIT BIT(6) 33 + #define EGALAX_FORMAT_TOUCH_BIT BIT(0) 34 + #define EGALAX_FORMAT_RESOLUTION_MASK 0x06 35 + 36 + #define EGALAX_MIN_XC 0 37 + #define EGALAX_MAX_XC 0x4000 38 + #define EGALAX_MIN_YC 0 39 + #define EGALAX_MAX_YC 0x4000 40 + 41 + /* 42 + * Per-touchscreen data. 43 + */ 44 + struct egalax { 45 + struct input_dev *input; 46 + struct serio *serio; 47 + int idx; 48 + u8 data[EGALAX_FORMAT_MAX_LENGTH]; 49 + char phys[32]; 50 + }; 51 + 52 + static void egalax_process_data(struct egalax *egalax) 53 + { 54 + struct input_dev *dev = egalax->input; 55 + u8 *data = egalax->data; 56 + u16 x, y; 57 + u8 shift; 58 + u8 mask; 59 + 60 + shift = 3 - ((data[0] & EGALAX_FORMAT_RESOLUTION_MASK) >> 1); 61 + mask = 0xff >> (shift + 1); 62 + 63 + x = (((u16)(data[1] & mask) << 7) | (data[2] & 0x7f)) << shift; 64 + y = (((u16)(data[3] & mask) << 7) | (data[4] & 0x7f)) << shift; 65 + 66 + input_report_key(dev, BTN_TOUCH, data[0] & EGALAX_FORMAT_TOUCH_BIT); 67 + input_report_abs(dev, ABS_X, x); 68 + input_report_abs(dev, ABS_Y, y); 69 + input_sync(dev); 70 + } 71 + 72 + static irqreturn_t egalax_interrupt(struct serio *serio, 73 + unsigned char data, unsigned int flags) 74 + { 75 + struct egalax *egalax = serio_get_drvdata(serio); 76 + int pkt_len; 77 + 78 + egalax->data[egalax->idx++] = data; 79 + 80 + if (likely(egalax->data[0] & EGALAX_FORMAT_START_BIT)) { 81 + pkt_len = egalax->data[0] & EGALAX_FORMAT_PRESSURE_BIT ? 6 : 5; 82 + if (pkt_len == egalax->idx) { 83 + egalax_process_data(egalax); 84 + egalax->idx = 0; 85 + } 86 + } else { 87 + dev_dbg(&serio->dev, "unknown/unsynchronized data: %x\n", 88 + egalax->data[0]); 89 + egalax->idx = 0; 90 + } 91 + 92 + return IRQ_HANDLED; 93 + } 94 + 95 + /* 96 + * egalax_connect() is the routine that is called when someone adds a 97 + * new serio device that supports egalax protocol and registers it as 98 + * an input device. This is usually accomplished using inputattach. 99 + */ 100 + static int egalax_connect(struct serio *serio, struct serio_driver *drv) 101 + { 102 + struct egalax *egalax; 103 + struct input_dev *input_dev; 104 + int error; 105 + 106 + egalax = kzalloc(sizeof(struct egalax), GFP_KERNEL); 107 + input_dev = input_allocate_device(); 108 + if (!egalax) { 109 + error = -ENOMEM; 110 + goto err_free_mem; 111 + } 112 + 113 + egalax->serio = serio; 114 + egalax->input = input_dev; 115 + snprintf(egalax->phys, sizeof(egalax->phys), 116 + "%s/input0", serio->phys); 117 + 118 + input_dev->name = "EETI eGalaxTouch Serial TouchScreen"; 119 + input_dev->phys = egalax->phys; 120 + input_dev->id.bustype = BUS_RS232; 121 + input_dev->id.vendor = SERIO_EGALAX; 122 + input_dev->id.product = 0; 123 + input_dev->id.version = 0x0001; 124 + input_dev->dev.parent = &serio->dev; 125 + 126 + input_set_capability(input_dev, EV_KEY, BTN_TOUCH); 127 + input_set_abs_params(input_dev, ABS_X, 128 + EGALAX_MIN_XC, EGALAX_MAX_XC, 0, 0); 129 + input_set_abs_params(input_dev, ABS_Y, 130 + EGALAX_MIN_YC, EGALAX_MAX_YC, 0, 0); 131 + 132 + serio_set_drvdata(serio, egalax); 133 + 134 + error = serio_open(serio, drv); 135 + if (error) 136 + goto err_reset_drvdata; 137 + 138 + error = input_register_device(input_dev); 139 + if (error) 140 + goto err_close_serio; 141 + 142 + return 0; 143 + 144 + err_close_serio: 145 + serio_close(serio); 146 + err_reset_drvdata: 147 + serio_set_drvdata(serio, NULL); 148 + err_free_mem: 149 + input_free_device(input_dev); 150 + kfree(egalax); 151 + return error; 152 + } 153 + 154 + static void egalax_disconnect(struct serio *serio) 155 + { 156 + struct egalax *egalax = serio_get_drvdata(serio); 157 + 158 + serio_close(serio); 159 + serio_set_drvdata(serio, NULL); 160 + input_unregister_device(egalax->input); 161 + kfree(egalax); 162 + } 163 + 164 + /* 165 + * The serio driver structure. 166 + */ 167 + 168 + static const struct serio_device_id egalax_serio_ids[] = { 169 + { 170 + .type = SERIO_RS232, 171 + .proto = SERIO_EGALAX, 172 + .id = SERIO_ANY, 173 + .extra = SERIO_ANY, 174 + }, 175 + { 0 } 176 + }; 177 + 178 + MODULE_DEVICE_TABLE(serio, egalax_serio_ids); 179 + 180 + static struct serio_driver egalax_drv = { 181 + .driver = { 182 + .name = "egalax", 183 + }, 184 + .description = DRIVER_DESC, 185 + .id_table = egalax_serio_ids, 186 + .interrupt = egalax_interrupt, 187 + .connect = egalax_connect, 188 + .disconnect = egalax_disconnect, 189 + }; 190 + module_serio_driver(egalax_drv); 191 + 192 + MODULE_AUTHOR("Zoltán Böszörményi <zboszor@pr.hu>"); 193 + MODULE_DESCRIPTION(DRIVER_DESC); 194 + MODULE_LICENSE("GPL v2");
+1
include/uapi/linux/serio.h
··· 77 77 #define SERIO_PS2MULT 0x3c 78 78 #define SERIO_TSC40 0x3d 79 79 #define SERIO_WACOM_IV 0x3e 80 + #define SERIO_EGALAX 0x3f 80 81 81 82 #endif /* _UAPI_SERIO_H */