11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * MicroTouch (3M) serial touchscreen driver 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (c) 2004 Vojtech Pavlik 51da177e4SLinus Torvalds */ 61da177e4SLinus Torvalds 71da177e4SLinus Torvalds /* 81da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify it 91da177e4SLinus Torvalds * under the terms of the GNU General Public License version 2 as published by 101da177e4SLinus Torvalds * the Free Software Foundation. 111da177e4SLinus Torvalds */ 121da177e4SLinus Torvalds 131da177e4SLinus Torvalds /* 141da177e4SLinus Torvalds * 2005/02/19 Dan Streetman <[email protected]> 151da177e4SLinus Torvalds * Copied elo.c and edited for MicroTouch protocol 161da177e4SLinus Torvalds */ 171da177e4SLinus Torvalds 181da177e4SLinus Torvalds #include <linux/errno.h> 191da177e4SLinus Torvalds #include <linux/kernel.h> 201da177e4SLinus Torvalds #include <linux/module.h> 211da177e4SLinus Torvalds #include <linux/slab.h> 221da177e4SLinus Torvalds #include <linux/input.h> 231da177e4SLinus Torvalds #include <linux/serio.h> 241da177e4SLinus Torvalds #include <linux/init.h> 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds #define DRIVER_DESC "MicroTouch serial touchscreen driver" 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds MODULE_AUTHOR("Vojtech Pavlik <[email protected]>"); 291da177e4SLinus Torvalds MODULE_DESCRIPTION(DRIVER_DESC); 301da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds /* 331da177e4SLinus Torvalds * Definitions & global arrays. 341da177e4SLinus Torvalds */ 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds #define MTOUCH_FORMAT_TABLET_STATUS_BIT 0x80 371da177e4SLinus Torvalds #define MTOUCH_FORMAT_TABLET_TOUCH_BIT 0x40 381da177e4SLinus Torvalds #define MTOUCH_FORMAT_TABLET_LENGTH 5 391da177e4SLinus Torvalds #define MTOUCH_RESPONSE_BEGIN_BYTE 0x01 401da177e4SLinus Torvalds #define MTOUCH_RESPONSE_END_BYTE 0x0d 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds /* todo: check specs for max length of all responses */ 431da177e4SLinus Torvalds #define MTOUCH_MAX_LENGTH 16 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds #define MTOUCH_MIN_XC 0 461da177e4SLinus Torvalds #define MTOUCH_MAX_XC 0x3fff 471da177e4SLinus Torvalds #define MTOUCH_MIN_YC 0 481da177e4SLinus Torvalds #define MTOUCH_MAX_YC 0x3fff 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds #define MTOUCH_GET_XC(data) (((data[2])<<7) | data[1]) 511da177e4SLinus Torvalds #define MTOUCH_GET_YC(data) (((data[4])<<7) | data[3]) 521da177e4SLinus Torvalds #define MTOUCH_GET_TOUCHED(data) (MTOUCH_FORMAT_TABLET_TOUCH_BIT & data[0]) 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds /* 551da177e4SLinus Torvalds * Per-touchscreen data. 561da177e4SLinus Torvalds */ 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds struct mtouch { 59eca1ed19SDmitry Torokhov struct input_dev *dev; 601da177e4SLinus Torvalds struct serio *serio; 611da177e4SLinus Torvalds int idx; 621da177e4SLinus Torvalds unsigned char data[MTOUCH_MAX_LENGTH]; 631da177e4SLinus Torvalds char phys[32]; 641da177e4SLinus Torvalds }; 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds static void mtouch_process_format_tablet(struct mtouch *mtouch, struct pt_regs *regs) 671da177e4SLinus Torvalds { 68eca1ed19SDmitry Torokhov struct input_dev *dev = mtouch->dev; 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds if (MTOUCH_FORMAT_TABLET_LENGTH == ++mtouch->idx) { 711da177e4SLinus Torvalds input_regs(dev, regs); 721da177e4SLinus Torvalds input_report_abs(dev, ABS_X, MTOUCH_GET_XC(mtouch->data)); 731da177e4SLinus Torvalds input_report_abs(dev, ABS_Y, MTOUCH_MAX_YC - MTOUCH_GET_YC(mtouch->data)); 741da177e4SLinus Torvalds input_report_key(dev, BTN_TOUCH, MTOUCH_GET_TOUCHED(mtouch->data)); 751da177e4SLinus Torvalds input_sync(dev); 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds mtouch->idx = 0; 781da177e4SLinus Torvalds } 791da177e4SLinus Torvalds } 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds static void mtouch_process_response(struct mtouch *mtouch, struct pt_regs *regs) 821da177e4SLinus Torvalds { 831da177e4SLinus Torvalds if (MTOUCH_RESPONSE_END_BYTE == mtouch->data[mtouch->idx++]) { 841da177e4SLinus Torvalds /* FIXME - process response */ 851da177e4SLinus Torvalds mtouch->idx = 0; 861da177e4SLinus Torvalds } else if (MTOUCH_MAX_LENGTH == mtouch->idx) { 871da177e4SLinus Torvalds printk(KERN_ERR "mtouch.c: too many response bytes\n"); 881da177e4SLinus Torvalds mtouch->idx = 0; 891da177e4SLinus Torvalds } 901da177e4SLinus Torvalds } 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds static irqreturn_t mtouch_interrupt(struct serio *serio, 931da177e4SLinus Torvalds unsigned char data, unsigned int flags, struct pt_regs *regs) 941da177e4SLinus Torvalds { 951da177e4SLinus Torvalds struct mtouch* mtouch = serio_get_drvdata(serio); 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds mtouch->data[mtouch->idx] = data; 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds if (MTOUCH_FORMAT_TABLET_STATUS_BIT & mtouch->data[0]) 1001da177e4SLinus Torvalds mtouch_process_format_tablet(mtouch, regs); 1011da177e4SLinus Torvalds else if (MTOUCH_RESPONSE_BEGIN_BYTE == mtouch->data[0]) 1021da177e4SLinus Torvalds mtouch_process_response(mtouch, regs); 1031da177e4SLinus Torvalds else 1041da177e4SLinus Torvalds printk(KERN_DEBUG "mtouch.c: unknown/unsynchronized data from device, byte %x\n",mtouch->data[0]); 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds return IRQ_HANDLED; 1071da177e4SLinus Torvalds } 1081da177e4SLinus Torvalds 1091da177e4SLinus Torvalds /* 1101da177e4SLinus Torvalds * mtouch_disconnect() is the opposite of mtouch_connect() 1111da177e4SLinus Torvalds */ 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds static void mtouch_disconnect(struct serio *serio) 1141da177e4SLinus Torvalds { 1151da177e4SLinus Torvalds struct mtouch* mtouch = serio_get_drvdata(serio); 1161da177e4SLinus Torvalds 117eca1ed19SDmitry Torokhov input_get_device(mtouch->dev); 118eca1ed19SDmitry Torokhov input_unregister_device(mtouch->dev); 1191da177e4SLinus Torvalds serio_close(serio); 1201da177e4SLinus Torvalds serio_set_drvdata(serio, NULL); 121eca1ed19SDmitry Torokhov input_put_device(mtouch->dev); 1221da177e4SLinus Torvalds kfree(mtouch); 1231da177e4SLinus Torvalds } 1241da177e4SLinus Torvalds 1251da177e4SLinus Torvalds /* 1261da177e4SLinus Torvalds * mtouch_connect() is the routine that is called when someone adds a 1271da177e4SLinus Torvalds * new serio device that supports MicroTouch (Format Tablet) protocol and registers it as 1281da177e4SLinus Torvalds * an input device. 1291da177e4SLinus Torvalds */ 1301da177e4SLinus Torvalds 1311da177e4SLinus Torvalds static int mtouch_connect(struct serio *serio, struct serio_driver *drv) 1321da177e4SLinus Torvalds { 1331da177e4SLinus Torvalds struct mtouch *mtouch; 134eca1ed19SDmitry Torokhov struct input_dev *input_dev; 1351da177e4SLinus Torvalds int err; 1361da177e4SLinus Torvalds 137eca1ed19SDmitry Torokhov mtouch = kzalloc(sizeof(struct mtouch), GFP_KERNEL); 138eca1ed19SDmitry Torokhov input_dev = input_allocate_device(); 139eca1ed19SDmitry Torokhov if (!mtouch || !input_dev) { 140eca1ed19SDmitry Torokhov err = -ENOMEM; 141eca1ed19SDmitry Torokhov goto fail; 142eca1ed19SDmitry Torokhov } 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds mtouch->serio = serio; 145eca1ed19SDmitry Torokhov mtouch->dev = input_dev; 146*a21466ccSDmitry Torokhov snprintf(mtouch->phys, sizeof(mtouch->phys), "%s/input0", serio->phys); 1471da177e4SLinus Torvalds 148eca1ed19SDmitry Torokhov input_dev->private = mtouch; 149eca1ed19SDmitry Torokhov input_dev->name = "MicroTouch Serial TouchScreen"; 150eca1ed19SDmitry Torokhov input_dev->phys = mtouch->phys; 151eca1ed19SDmitry Torokhov input_dev->id.bustype = BUS_RS232; 152eca1ed19SDmitry Torokhov input_dev->id.vendor = SERIO_MICROTOUCH; 153eca1ed19SDmitry Torokhov input_dev->id.product = 0; 154eca1ed19SDmitry Torokhov input_dev->id.version = 0x0100; 155eca1ed19SDmitry Torokhov input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); 156eca1ed19SDmitry Torokhov input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); 157eca1ed19SDmitry Torokhov input_set_abs_params(mtouch->dev, ABS_X, MTOUCH_MIN_XC, MTOUCH_MAX_XC, 0, 0); 158eca1ed19SDmitry Torokhov input_set_abs_params(mtouch->dev, ABS_Y, MTOUCH_MIN_YC, MTOUCH_MAX_YC, 0, 0); 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds serio_set_drvdata(serio, mtouch); 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds err = serio_open(serio, drv); 163eca1ed19SDmitry Torokhov if (err) 164eca1ed19SDmitry Torokhov goto fail; 1651da177e4SLinus Torvalds 166eca1ed19SDmitry Torokhov input_register_device(mtouch->dev); 1671da177e4SLinus Torvalds 1681da177e4SLinus Torvalds return 0; 169eca1ed19SDmitry Torokhov 170eca1ed19SDmitry Torokhov fail: serio_set_drvdata(serio, NULL); 171eca1ed19SDmitry Torokhov input_free_device(input_dev); 172eca1ed19SDmitry Torokhov kfree(mtouch); 173eca1ed19SDmitry Torokhov return err; 1741da177e4SLinus Torvalds } 1751da177e4SLinus Torvalds 1761da177e4SLinus Torvalds /* 1771da177e4SLinus Torvalds * The serio driver structure. 1781da177e4SLinus Torvalds */ 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds static struct serio_device_id mtouch_serio_ids[] = { 1811da177e4SLinus Torvalds { 1821da177e4SLinus Torvalds .type = SERIO_RS232, 1831da177e4SLinus Torvalds .proto = SERIO_MICROTOUCH, 1841da177e4SLinus Torvalds .id = SERIO_ANY, 1851da177e4SLinus Torvalds .extra = SERIO_ANY, 1861da177e4SLinus Torvalds }, 1871da177e4SLinus Torvalds { 0 } 1881da177e4SLinus Torvalds }; 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds MODULE_DEVICE_TABLE(serio, mtouch_serio_ids); 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds static struct serio_driver mtouch_drv = { 1931da177e4SLinus Torvalds .driver = { 1941da177e4SLinus Torvalds .name = "mtouch", 1951da177e4SLinus Torvalds }, 1961da177e4SLinus Torvalds .description = DRIVER_DESC, 1971da177e4SLinus Torvalds .id_table = mtouch_serio_ids, 1981da177e4SLinus Torvalds .interrupt = mtouch_interrupt, 1991da177e4SLinus Torvalds .connect = mtouch_connect, 2001da177e4SLinus Torvalds .disconnect = mtouch_disconnect, 2011da177e4SLinus Torvalds }; 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds /* 2041da177e4SLinus Torvalds * The functions for inserting/removing us as a module. 2051da177e4SLinus Torvalds */ 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds static int __init mtouch_init(void) 2081da177e4SLinus Torvalds { 2091da177e4SLinus Torvalds serio_register_driver(&mtouch_drv); 2101da177e4SLinus Torvalds return 0; 2111da177e4SLinus Torvalds } 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds static void __exit mtouch_exit(void) 2141da177e4SLinus Torvalds { 2151da177e4SLinus Torvalds serio_unregister_driver(&mtouch_drv); 2161da177e4SLinus Torvalds } 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds module_init(mtouch_init); 2191da177e4SLinus Torvalds module_exit(mtouch_exit); 220