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