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