1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Touchwindow serial touchscreen driver 4 * 5 * Copyright (c) 2006 Rick Koch <n1gp@hotmail.com> 6 * 7 * Based on MicroTouch driver (drivers/input/touchscreen/mtouch.c) 8 * Copyright (c) 2004 Vojtech Pavlik 9 * and Dan Streetman <ddstreet@ieee.org> 10 */ 11 12 13 /* 14 * 2005/02/19 Rick Koch: 15 * The Touchwindow I used is made by Edmark Corp. and 16 * constantly outputs a stream of 0's unless it is touched. 17 * It then outputs 3 bytes: X, Y, and a copy of Y. 18 */ 19 20 #include <linux/errno.h> 21 #include <linux/kernel.h> 22 #include <linux/module.h> 23 #include <linux/slab.h> 24 #include <linux/input.h> 25 #include <linux/serio.h> 26 27 #define DRIVER_DESC "Touchwindow serial touchscreen driver" 28 29 MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>"); 30 MODULE_DESCRIPTION(DRIVER_DESC); 31 MODULE_LICENSE("GPL"); 32 33 /* 34 * Definitions & global arrays. 35 */ 36 37 #define TW_LENGTH 3 38 39 #define TW_MIN_XC 0 40 #define TW_MAX_XC 0xff 41 #define TW_MIN_YC 0 42 #define TW_MAX_YC 0xff 43 44 /* 45 * Per-touchscreen data. 46 */ 47 48 struct tw { 49 struct input_dev *dev; 50 struct serio *serio; 51 int idx; 52 int touched; 53 unsigned char data[TW_LENGTH]; 54 char phys[32]; 55 }; 56 57 static irqreturn_t tw_interrupt(struct serio *serio, 58 unsigned char data, unsigned int flags) 59 { 60 struct tw *tw = serio_get_drvdata(serio); 61 struct input_dev *dev = tw->dev; 62 63 if (data) { /* touch */ 64 tw->touched = 1; 65 tw->data[tw->idx++] = data; 66 /* a full packet ends the accumulation, valid or not */ 67 if (tw->idx == TW_LENGTH) { 68 /* report only if the two Y's are the same */ 69 if (tw->data[1] == tw->data[2]) { 70 input_report_abs(dev, ABS_X, tw->data[0]); 71 input_report_abs(dev, ABS_Y, tw->data[1]); 72 input_report_key(dev, BTN_TOUCH, 1); 73 input_sync(dev); 74 } 75 tw->idx = 0; 76 } 77 } else if (tw->touched) { /* untouch */ 78 input_report_key(dev, BTN_TOUCH, 0); 79 input_sync(dev); 80 tw->idx = 0; 81 tw->touched = 0; 82 } 83 84 return IRQ_HANDLED; 85 } 86 87 /* 88 * tw_disconnect() is the opposite of tw_connect() 89 */ 90 91 static void tw_disconnect(struct serio *serio) 92 { 93 struct tw *tw = serio_get_drvdata(serio); 94 95 input_get_device(tw->dev); 96 input_unregister_device(tw->dev); 97 serio_close(serio); 98 serio_set_drvdata(serio, NULL); 99 input_put_device(tw->dev); 100 kfree(tw); 101 } 102 103 /* 104 * tw_connect() is the routine that is called when someone adds a 105 * new serio device that supports the Touchwin protocol and registers it as 106 * an input device. 107 */ 108 109 static int tw_connect(struct serio *serio, struct serio_driver *drv) 110 { 111 struct tw *tw; 112 struct input_dev *input_dev; 113 int err; 114 115 tw = kzalloc_obj(*tw); 116 input_dev = input_allocate_device(); 117 if (!tw || !input_dev) { 118 err = -ENOMEM; 119 goto fail1; 120 } 121 122 tw->serio = serio; 123 tw->dev = input_dev; 124 scnprintf(tw->phys, sizeof(tw->phys), "%s/input0", serio->phys); 125 126 input_dev->name = "Touchwindow Serial TouchScreen"; 127 input_dev->phys = tw->phys; 128 input_dev->id.bustype = BUS_RS232; 129 input_dev->id.vendor = SERIO_TOUCHWIN; 130 input_dev->id.product = 0; 131 input_dev->id.version = 0x0100; 132 input_dev->dev.parent = &serio->dev; 133 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 134 input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); 135 input_set_abs_params(tw->dev, ABS_X, TW_MIN_XC, TW_MAX_XC, 0, 0); 136 input_set_abs_params(tw->dev, ABS_Y, TW_MIN_YC, TW_MAX_YC, 0, 0); 137 138 serio_set_drvdata(serio, tw); 139 140 err = serio_open(serio, drv); 141 if (err) 142 goto fail2; 143 144 err = input_register_device(tw->dev); 145 if (err) 146 goto fail3; 147 148 return 0; 149 150 fail3: serio_close(serio); 151 fail2: serio_set_drvdata(serio, NULL); 152 fail1: input_free_device(input_dev); 153 kfree(tw); 154 return err; 155 } 156 157 /* 158 * The serio driver structure. 159 */ 160 161 static const struct serio_device_id tw_serio_ids[] = { 162 { 163 .type = SERIO_RS232, 164 .proto = SERIO_TOUCHWIN, 165 .id = SERIO_ANY, 166 .extra = SERIO_ANY, 167 }, 168 { 0 } 169 }; 170 171 MODULE_DEVICE_TABLE(serio, tw_serio_ids); 172 173 static struct serio_driver tw_drv = { 174 .driver = { 175 .name = "touchwin", 176 }, 177 .description = DRIVER_DESC, 178 .id_table = tw_serio_ids, 179 .interrupt = tw_interrupt, 180 .connect = tw_connect, 181 .disconnect = tw_disconnect, 182 }; 183 184 module_serio_driver(tw_drv); 185