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 || !input_dev) { 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"); 195