1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * MicroTouch (3M) serial touchscreen driver 3*1da177e4SLinus Torvalds * 4*1da177e4SLinus Torvalds * Copyright (c) 2004 Vojtech Pavlik 5*1da177e4SLinus Torvalds */ 6*1da177e4SLinus Torvalds 7*1da177e4SLinus Torvalds /* 8*1da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify it 9*1da177e4SLinus Torvalds * under the terms of the GNU General Public License version 2 as published by 10*1da177e4SLinus Torvalds * the Free Software Foundation. 11*1da177e4SLinus Torvalds */ 12*1da177e4SLinus Torvalds 13*1da177e4SLinus Torvalds /* 14*1da177e4SLinus Torvalds * 2005/02/19 Dan Streetman <[email protected]> 15*1da177e4SLinus Torvalds * Copied elo.c and edited for MicroTouch protocol 16*1da177e4SLinus Torvalds */ 17*1da177e4SLinus Torvalds 18*1da177e4SLinus Torvalds #include <linux/errno.h> 19*1da177e4SLinus Torvalds #include <linux/kernel.h> 20*1da177e4SLinus Torvalds #include <linux/module.h> 21*1da177e4SLinus Torvalds #include <linux/slab.h> 22*1da177e4SLinus Torvalds #include <linux/input.h> 23*1da177e4SLinus Torvalds #include <linux/serio.h> 24*1da177e4SLinus Torvalds #include <linux/init.h> 25*1da177e4SLinus Torvalds 26*1da177e4SLinus Torvalds #define DRIVER_DESC "MicroTouch serial touchscreen driver" 27*1da177e4SLinus Torvalds 28*1da177e4SLinus Torvalds MODULE_AUTHOR("Vojtech Pavlik <[email protected]>"); 29*1da177e4SLinus Torvalds MODULE_DESCRIPTION(DRIVER_DESC); 30*1da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 31*1da177e4SLinus Torvalds 32*1da177e4SLinus Torvalds /* 33*1da177e4SLinus Torvalds * Definitions & global arrays. 34*1da177e4SLinus Torvalds */ 35*1da177e4SLinus Torvalds 36*1da177e4SLinus Torvalds #define MTOUCH_FORMAT_TABLET_STATUS_BIT 0x80 37*1da177e4SLinus Torvalds #define MTOUCH_FORMAT_TABLET_TOUCH_BIT 0x40 38*1da177e4SLinus Torvalds #define MTOUCH_FORMAT_TABLET_LENGTH 5 39*1da177e4SLinus Torvalds #define MTOUCH_RESPONSE_BEGIN_BYTE 0x01 40*1da177e4SLinus Torvalds #define MTOUCH_RESPONSE_END_BYTE 0x0d 41*1da177e4SLinus Torvalds 42*1da177e4SLinus Torvalds /* todo: check specs for max length of all responses */ 43*1da177e4SLinus Torvalds #define MTOUCH_MAX_LENGTH 16 44*1da177e4SLinus Torvalds 45*1da177e4SLinus Torvalds #define MTOUCH_MIN_XC 0 46*1da177e4SLinus Torvalds #define MTOUCH_MAX_XC 0x3fff 47*1da177e4SLinus Torvalds #define MTOUCH_MIN_YC 0 48*1da177e4SLinus Torvalds #define MTOUCH_MAX_YC 0x3fff 49*1da177e4SLinus Torvalds 50*1da177e4SLinus Torvalds #define MTOUCH_GET_XC(data) (((data[2])<<7) | data[1]) 51*1da177e4SLinus Torvalds #define MTOUCH_GET_YC(data) (((data[4])<<7) | data[3]) 52*1da177e4SLinus Torvalds #define MTOUCH_GET_TOUCHED(data) (MTOUCH_FORMAT_TABLET_TOUCH_BIT & data[0]) 53*1da177e4SLinus Torvalds 54*1da177e4SLinus Torvalds static char *mtouch_name = "MicroTouch Serial TouchScreen"; 55*1da177e4SLinus Torvalds 56*1da177e4SLinus Torvalds /* 57*1da177e4SLinus Torvalds * Per-touchscreen data. 58*1da177e4SLinus Torvalds */ 59*1da177e4SLinus Torvalds 60*1da177e4SLinus Torvalds struct mtouch { 61*1da177e4SLinus Torvalds struct input_dev dev; 62*1da177e4SLinus Torvalds struct serio *serio; 63*1da177e4SLinus Torvalds int idx; 64*1da177e4SLinus Torvalds unsigned char data[MTOUCH_MAX_LENGTH]; 65*1da177e4SLinus Torvalds char phys[32]; 66*1da177e4SLinus Torvalds }; 67*1da177e4SLinus Torvalds 68*1da177e4SLinus Torvalds static void mtouch_process_format_tablet(struct mtouch *mtouch, struct pt_regs *regs) 69*1da177e4SLinus Torvalds { 70*1da177e4SLinus Torvalds struct input_dev *dev = &mtouch->dev; 71*1da177e4SLinus Torvalds 72*1da177e4SLinus Torvalds if (MTOUCH_FORMAT_TABLET_LENGTH == ++mtouch->idx) { 73*1da177e4SLinus Torvalds input_regs(dev, regs); 74*1da177e4SLinus Torvalds input_report_abs(dev, ABS_X, MTOUCH_GET_XC(mtouch->data)); 75*1da177e4SLinus Torvalds input_report_abs(dev, ABS_Y, MTOUCH_MAX_YC - MTOUCH_GET_YC(mtouch->data)); 76*1da177e4SLinus Torvalds input_report_key(dev, BTN_TOUCH, MTOUCH_GET_TOUCHED(mtouch->data)); 77*1da177e4SLinus Torvalds input_sync(dev); 78*1da177e4SLinus Torvalds 79*1da177e4SLinus Torvalds mtouch->idx = 0; 80*1da177e4SLinus Torvalds } 81*1da177e4SLinus Torvalds } 82*1da177e4SLinus Torvalds 83*1da177e4SLinus Torvalds static void mtouch_process_response(struct mtouch *mtouch, struct pt_regs *regs) 84*1da177e4SLinus Torvalds { 85*1da177e4SLinus Torvalds if (MTOUCH_RESPONSE_END_BYTE == mtouch->data[mtouch->idx++]) { 86*1da177e4SLinus Torvalds /* FIXME - process response */ 87*1da177e4SLinus Torvalds mtouch->idx = 0; 88*1da177e4SLinus Torvalds } else if (MTOUCH_MAX_LENGTH == mtouch->idx) { 89*1da177e4SLinus Torvalds printk(KERN_ERR "mtouch.c: too many response bytes\n"); 90*1da177e4SLinus Torvalds mtouch->idx = 0; 91*1da177e4SLinus Torvalds } 92*1da177e4SLinus Torvalds } 93*1da177e4SLinus Torvalds 94*1da177e4SLinus Torvalds static irqreturn_t mtouch_interrupt(struct serio *serio, 95*1da177e4SLinus Torvalds unsigned char data, unsigned int flags, struct pt_regs *regs) 96*1da177e4SLinus Torvalds { 97*1da177e4SLinus Torvalds struct mtouch* mtouch = serio_get_drvdata(serio); 98*1da177e4SLinus Torvalds 99*1da177e4SLinus Torvalds mtouch->data[mtouch->idx] = data; 100*1da177e4SLinus Torvalds 101*1da177e4SLinus Torvalds if (MTOUCH_FORMAT_TABLET_STATUS_BIT & mtouch->data[0]) 102*1da177e4SLinus Torvalds mtouch_process_format_tablet(mtouch, regs); 103*1da177e4SLinus Torvalds else if (MTOUCH_RESPONSE_BEGIN_BYTE == mtouch->data[0]) 104*1da177e4SLinus Torvalds mtouch_process_response(mtouch, regs); 105*1da177e4SLinus Torvalds else 106*1da177e4SLinus Torvalds printk(KERN_DEBUG "mtouch.c: unknown/unsynchronized data from device, byte %x\n",mtouch->data[0]); 107*1da177e4SLinus Torvalds 108*1da177e4SLinus Torvalds return IRQ_HANDLED; 109*1da177e4SLinus Torvalds } 110*1da177e4SLinus Torvalds 111*1da177e4SLinus Torvalds /* 112*1da177e4SLinus Torvalds * mtouch_disconnect() is the opposite of mtouch_connect() 113*1da177e4SLinus Torvalds */ 114*1da177e4SLinus Torvalds 115*1da177e4SLinus Torvalds static void mtouch_disconnect(struct serio *serio) 116*1da177e4SLinus Torvalds { 117*1da177e4SLinus Torvalds struct mtouch* mtouch = serio_get_drvdata(serio); 118*1da177e4SLinus Torvalds 119*1da177e4SLinus Torvalds input_unregister_device(&mtouch->dev); 120*1da177e4SLinus Torvalds serio_close(serio); 121*1da177e4SLinus Torvalds serio_set_drvdata(serio, NULL); 122*1da177e4SLinus Torvalds kfree(mtouch); 123*1da177e4SLinus Torvalds } 124*1da177e4SLinus Torvalds 125*1da177e4SLinus Torvalds /* 126*1da177e4SLinus Torvalds * mtouch_connect() is the routine that is called when someone adds a 127*1da177e4SLinus Torvalds * new serio device that supports MicroTouch (Format Tablet) protocol and registers it as 128*1da177e4SLinus Torvalds * an input device. 129*1da177e4SLinus Torvalds */ 130*1da177e4SLinus Torvalds 131*1da177e4SLinus Torvalds static int mtouch_connect(struct serio *serio, struct serio_driver *drv) 132*1da177e4SLinus Torvalds { 133*1da177e4SLinus Torvalds struct mtouch *mtouch; 134*1da177e4SLinus Torvalds int err; 135*1da177e4SLinus Torvalds 136*1da177e4SLinus Torvalds if (!(mtouch = kmalloc(sizeof(*mtouch), GFP_KERNEL))) 137*1da177e4SLinus Torvalds return -ENOMEM; 138*1da177e4SLinus Torvalds 139*1da177e4SLinus Torvalds memset(mtouch, 0, sizeof(*mtouch)); 140*1da177e4SLinus Torvalds 141*1da177e4SLinus Torvalds init_input_dev(&mtouch->dev); 142*1da177e4SLinus Torvalds mtouch->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); 143*1da177e4SLinus Torvalds mtouch->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); 144*1da177e4SLinus Torvalds 145*1da177e4SLinus Torvalds input_set_abs_params(&mtouch->dev, ABS_X, MTOUCH_MIN_XC, MTOUCH_MAX_XC, 0, 0); 146*1da177e4SLinus Torvalds input_set_abs_params(&mtouch->dev, ABS_Y, MTOUCH_MIN_YC, MTOUCH_MAX_YC, 0, 0); 147*1da177e4SLinus Torvalds 148*1da177e4SLinus Torvalds mtouch->serio = serio; 149*1da177e4SLinus Torvalds 150*1da177e4SLinus Torvalds sprintf(mtouch->phys, "%s/input0", serio->phys); 151*1da177e4SLinus Torvalds 152*1da177e4SLinus Torvalds mtouch->dev.private = mtouch; 153*1da177e4SLinus Torvalds mtouch->dev.name = mtouch_name; 154*1da177e4SLinus Torvalds mtouch->dev.phys = mtouch->phys; 155*1da177e4SLinus Torvalds mtouch->dev.id.bustype = BUS_RS232; 156*1da177e4SLinus Torvalds mtouch->dev.id.vendor = SERIO_MICROTOUCH; 157*1da177e4SLinus Torvalds mtouch->dev.id.product = 0; 158*1da177e4SLinus Torvalds mtouch->dev.id.version = 0x0100; 159*1da177e4SLinus Torvalds 160*1da177e4SLinus Torvalds serio_set_drvdata(serio, mtouch); 161*1da177e4SLinus Torvalds 162*1da177e4SLinus Torvalds err = serio_open(serio, drv); 163*1da177e4SLinus Torvalds if (err) { 164*1da177e4SLinus Torvalds serio_set_drvdata(serio, NULL); 165*1da177e4SLinus Torvalds kfree(mtouch); 166*1da177e4SLinus Torvalds return err; 167*1da177e4SLinus Torvalds } 168*1da177e4SLinus Torvalds 169*1da177e4SLinus Torvalds input_register_device(&mtouch->dev); 170*1da177e4SLinus Torvalds 171*1da177e4SLinus Torvalds printk(KERN_INFO "input: %s on %s\n", mtouch->dev.name, serio->phys); 172*1da177e4SLinus Torvalds 173*1da177e4SLinus Torvalds return 0; 174*1da177e4SLinus Torvalds } 175*1da177e4SLinus Torvalds 176*1da177e4SLinus Torvalds /* 177*1da177e4SLinus Torvalds * The serio driver structure. 178*1da177e4SLinus Torvalds */ 179*1da177e4SLinus Torvalds 180*1da177e4SLinus Torvalds static struct serio_device_id mtouch_serio_ids[] = { 181*1da177e4SLinus Torvalds { 182*1da177e4SLinus Torvalds .type = SERIO_RS232, 183*1da177e4SLinus Torvalds .proto = SERIO_MICROTOUCH, 184*1da177e4SLinus Torvalds .id = SERIO_ANY, 185*1da177e4SLinus Torvalds .extra = SERIO_ANY, 186*1da177e4SLinus Torvalds }, 187*1da177e4SLinus Torvalds { 0 } 188*1da177e4SLinus Torvalds }; 189*1da177e4SLinus Torvalds 190*1da177e4SLinus Torvalds MODULE_DEVICE_TABLE(serio, mtouch_serio_ids); 191*1da177e4SLinus Torvalds 192*1da177e4SLinus Torvalds static struct serio_driver mtouch_drv = { 193*1da177e4SLinus Torvalds .driver = { 194*1da177e4SLinus Torvalds .name = "mtouch", 195*1da177e4SLinus Torvalds }, 196*1da177e4SLinus Torvalds .description = DRIVER_DESC, 197*1da177e4SLinus Torvalds .id_table = mtouch_serio_ids, 198*1da177e4SLinus Torvalds .interrupt = mtouch_interrupt, 199*1da177e4SLinus Torvalds .connect = mtouch_connect, 200*1da177e4SLinus Torvalds .disconnect = mtouch_disconnect, 201*1da177e4SLinus Torvalds }; 202*1da177e4SLinus Torvalds 203*1da177e4SLinus Torvalds /* 204*1da177e4SLinus Torvalds * The functions for inserting/removing us as a module. 205*1da177e4SLinus Torvalds */ 206*1da177e4SLinus Torvalds 207*1da177e4SLinus Torvalds static int __init mtouch_init(void) 208*1da177e4SLinus Torvalds { 209*1da177e4SLinus Torvalds serio_register_driver(&mtouch_drv); 210*1da177e4SLinus Torvalds return 0; 211*1da177e4SLinus Torvalds } 212*1da177e4SLinus Torvalds 213*1da177e4SLinus Torvalds static void __exit mtouch_exit(void) 214*1da177e4SLinus Torvalds { 215*1da177e4SLinus Torvalds serio_unregister_driver(&mtouch_drv); 216*1da177e4SLinus Torvalds } 217*1da177e4SLinus Torvalds 218*1da177e4SLinus Torvalds module_init(mtouch_init); 219*1da177e4SLinus Torvalds module_exit(mtouch_exit); 220