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