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