touchright.c (3815B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Touchright 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#include <linux/errno.h> 14#include <linux/kernel.h> 15#include <linux/module.h> 16#include <linux/slab.h> 17#include <linux/input.h> 18#include <linux/serio.h> 19 20#define DRIVER_DESC "Touchright serial touchscreen driver" 21 22MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>"); 23MODULE_DESCRIPTION(DRIVER_DESC); 24MODULE_LICENSE("GPL"); 25 26/* 27 * Definitions & global arrays. 28 */ 29 30#define TR_FORMAT_TOUCH_BIT 0x01 31#define TR_FORMAT_STATUS_BYTE 0x40 32#define TR_FORMAT_STATUS_MASK ~TR_FORMAT_TOUCH_BIT 33 34#define TR_LENGTH 5 35 36#define TR_MIN_XC 0 37#define TR_MAX_XC 0x1ff 38#define TR_MIN_YC 0 39#define TR_MAX_YC 0x1ff 40 41/* 42 * Per-touchscreen data. 43 */ 44 45struct tr { 46 struct input_dev *dev; 47 struct serio *serio; 48 int idx; 49 unsigned char data[TR_LENGTH]; 50 char phys[32]; 51}; 52 53static irqreturn_t tr_interrupt(struct serio *serio, 54 unsigned char data, unsigned int flags) 55{ 56 struct tr *tr = serio_get_drvdata(serio); 57 struct input_dev *dev = tr->dev; 58 59 tr->data[tr->idx] = data; 60 61 if ((tr->data[0] & TR_FORMAT_STATUS_MASK) == TR_FORMAT_STATUS_BYTE) { 62 if (++tr->idx == TR_LENGTH) { 63 input_report_abs(dev, ABS_X, 64 (tr->data[1] << 5) | (tr->data[2] >> 1)); 65 input_report_abs(dev, ABS_Y, 66 (tr->data[3] << 5) | (tr->data[4] >> 1)); 67 input_report_key(dev, BTN_TOUCH, 68 tr->data[0] & TR_FORMAT_TOUCH_BIT); 69 input_sync(dev); 70 tr->idx = 0; 71 } 72 } 73 74 return IRQ_HANDLED; 75} 76 77/* 78 * tr_disconnect() is the opposite of tr_connect() 79 */ 80 81static void tr_disconnect(struct serio *serio) 82{ 83 struct tr *tr = serio_get_drvdata(serio); 84 85 input_get_device(tr->dev); 86 input_unregister_device(tr->dev); 87 serio_close(serio); 88 serio_set_drvdata(serio, NULL); 89 input_put_device(tr->dev); 90 kfree(tr); 91} 92 93/* 94 * tr_connect() is the routine that is called when someone adds a 95 * new serio device that supports the Touchright protocol and registers it as 96 * an input device. 97 */ 98 99static int tr_connect(struct serio *serio, struct serio_driver *drv) 100{ 101 struct tr *tr; 102 struct input_dev *input_dev; 103 int err; 104 105 tr = kzalloc(sizeof(struct tr), GFP_KERNEL); 106 input_dev = input_allocate_device(); 107 if (!tr || !input_dev) { 108 err = -ENOMEM; 109 goto fail1; 110 } 111 112 tr->serio = serio; 113 tr->dev = input_dev; 114 snprintf(tr->phys, sizeof(tr->phys), "%s/input0", serio->phys); 115 116 input_dev->name = "Touchright Serial TouchScreen"; 117 input_dev->phys = tr->phys; 118 input_dev->id.bustype = BUS_RS232; 119 input_dev->id.vendor = SERIO_TOUCHRIGHT; 120 input_dev->id.product = 0; 121 input_dev->id.version = 0x0100; 122 input_dev->dev.parent = &serio->dev; 123 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 124 input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); 125 input_set_abs_params(tr->dev, ABS_X, TR_MIN_XC, TR_MAX_XC, 0, 0); 126 input_set_abs_params(tr->dev, ABS_Y, TR_MIN_YC, TR_MAX_YC, 0, 0); 127 128 serio_set_drvdata(serio, tr); 129 130 err = serio_open(serio, drv); 131 if (err) 132 goto fail2; 133 134 err = input_register_device(tr->dev); 135 if (err) 136 goto fail3; 137 138 return 0; 139 140 fail3: serio_close(serio); 141 fail2: serio_set_drvdata(serio, NULL); 142 fail1: input_free_device(input_dev); 143 kfree(tr); 144 return err; 145} 146 147/* 148 * The serio driver structure. 149 */ 150 151static const struct serio_device_id tr_serio_ids[] = { 152 { 153 .type = SERIO_RS232, 154 .proto = SERIO_TOUCHRIGHT, 155 .id = SERIO_ANY, 156 .extra = SERIO_ANY, 157 }, 158 { 0 } 159}; 160 161MODULE_DEVICE_TABLE(serio, tr_serio_ids); 162 163static struct serio_driver tr_drv = { 164 .driver = { 165 .name = "touchright", 166 }, 167 .description = DRIVER_DESC, 168 .id_table = tr_serio_ids, 169 .interrupt = tr_interrupt, 170 .connect = tr_connect, 171 .disconnect = tr_disconnect, 172}; 173 174module_serio_driver(tr_drv);