diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/input/touchscreen/elo.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/input/touchscreen/elo.c')
-rw-r--r-- | drivers/input/touchscreen/elo.c | 315 |
1 files changed, 315 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c new file mode 100644 index 000000000000..546ce599334e --- /dev/null +++ b/drivers/input/touchscreen/elo.c | |||
@@ -0,0 +1,315 @@ | |||
1 | /* | ||
2 | * Elo 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 | * This driver can handle serial Elo touchscreens using either the Elo standard | ||
15 | * 'E271-2210' 10-byte protocol, Elo legacy 'E281A-4002' 6-byte protocol, Elo | ||
16 | * legacy 'E271-140' 4-byte protocol and Elo legacy 'E261-280' 3-byte protocol. | ||
17 | */ | ||
18 | |||
19 | #include <linux/errno.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/input.h> | ||
24 | #include <linux/serio.h> | ||
25 | #include <linux/init.h> | ||
26 | |||
27 | #define DRIVER_DESC "Elo serial touchscreen driver" | ||
28 | |||
29 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | ||
30 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
31 | MODULE_LICENSE("GPL"); | ||
32 | |||
33 | /* | ||
34 | * Definitions & global arrays. | ||
35 | */ | ||
36 | |||
37 | #define ELO_MAX_LENGTH 10 | ||
38 | |||
39 | static char *elo_name = "Elo Serial TouchScreen"; | ||
40 | |||
41 | /* | ||
42 | * Per-touchscreen data. | ||
43 | */ | ||
44 | |||
45 | struct elo { | ||
46 | struct input_dev dev; | ||
47 | struct serio *serio; | ||
48 | int id; | ||
49 | int idx; | ||
50 | unsigned char csum; | ||
51 | unsigned char data[ELO_MAX_LENGTH]; | ||
52 | char phys[32]; | ||
53 | }; | ||
54 | |||
55 | static void elo_process_data_10(struct elo* elo, unsigned char data, struct pt_regs *regs) | ||
56 | { | ||
57 | struct input_dev *dev = &elo->dev; | ||
58 | |||
59 | elo->csum += elo->data[elo->idx] = data; | ||
60 | |||
61 | switch (elo->idx++) { | ||
62 | |||
63 | case 0: | ||
64 | if (data != 'U') { | ||
65 | elo->idx = 0; | ||
66 | elo->csum = 0; | ||
67 | } | ||
68 | break; | ||
69 | |||
70 | case 1: | ||
71 | if (data != 'T') { | ||
72 | elo->idx = 0; | ||
73 | elo->csum = 0; | ||
74 | } | ||
75 | break; | ||
76 | |||
77 | case 9: | ||
78 | if (elo->csum) { | ||
79 | input_regs(dev, regs); | ||
80 | input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]); | ||
81 | input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]); | ||
82 | input_report_abs(dev, ABS_PRESSURE, (elo->data[8] << 8) | elo->data[7]); | ||
83 | input_report_key(dev, BTN_TOUCH, elo->data[2] & 3); | ||
84 | input_sync(dev); | ||
85 | } | ||
86 | elo->idx = 0; | ||
87 | elo->csum = 0; | ||
88 | break; | ||
89 | } | ||
90 | } | ||
91 | |||
92 | static void elo_process_data_6(struct elo* elo, unsigned char data, struct pt_regs *regs) | ||
93 | { | ||
94 | struct input_dev *dev = &elo->dev; | ||
95 | |||
96 | elo->data[elo->idx] = data; | ||
97 | |||
98 | switch (elo->idx++) { | ||
99 | |||
100 | case 0: if ((data & 0xc0) != 0xc0) elo->idx = 0; break; | ||
101 | case 1: if ((data & 0xc0) != 0x80) elo->idx = 0; break; | ||
102 | case 2: if ((data & 0xc0) != 0x40) elo->idx = 0; break; | ||
103 | |||
104 | case 3: | ||
105 | if (data & 0xc0) { | ||
106 | elo->idx = 0; | ||
107 | break; | ||
108 | } | ||
109 | |||
110 | input_regs(dev, regs); | ||
111 | input_report_abs(dev, ABS_X, ((elo->data[0] & 0x3f) << 6) | (elo->data[1] & 0x3f)); | ||
112 | input_report_abs(dev, ABS_Y, ((elo->data[2] & 0x3f) << 6) | (elo->data[3] & 0x3f)); | ||
113 | |||
114 | if (elo->id == 2) { | ||
115 | input_report_key(dev, BTN_TOUCH, 1); | ||
116 | input_sync(dev); | ||
117 | elo->idx = 0; | ||
118 | } | ||
119 | |||
120 | break; | ||
121 | |||
122 | case 4: | ||
123 | if (data) { | ||
124 | input_sync(dev); | ||
125 | elo->idx = 0; | ||
126 | } | ||
127 | break; | ||
128 | |||
129 | case 5: | ||
130 | if ((data & 0xf0) == 0) { | ||
131 | input_report_abs(dev, ABS_PRESSURE, elo->data[5]); | ||
132 | input_report_key(dev, BTN_TOUCH, elo->data[5]); | ||
133 | } | ||
134 | input_sync(dev); | ||
135 | elo->idx = 0; | ||
136 | break; | ||
137 | } | ||
138 | } | ||
139 | |||
140 | static void elo_process_data_3(struct elo* elo, unsigned char data, struct pt_regs *regs) | ||
141 | { | ||
142 | struct input_dev *dev = &elo->dev; | ||
143 | |||
144 | elo->data[elo->idx] = data; | ||
145 | |||
146 | switch (elo->idx++) { | ||
147 | |||
148 | case 0: | ||
149 | if ((data & 0x7f) != 0x01) | ||
150 | elo->idx = 0; | ||
151 | break; | ||
152 | case 2: | ||
153 | input_regs(dev, regs); | ||
154 | input_report_key(dev, BTN_TOUCH, !(elo->data[1] & 0x80)); | ||
155 | input_report_abs(dev, ABS_X, elo->data[1]); | ||
156 | input_report_abs(dev, ABS_Y, elo->data[2]); | ||
157 | input_sync(dev); | ||
158 | elo->idx = 0; | ||
159 | break; | ||
160 | } | ||
161 | } | ||
162 | |||
163 | static irqreturn_t elo_interrupt(struct serio *serio, | ||
164 | unsigned char data, unsigned int flags, struct pt_regs *regs) | ||
165 | { | ||
166 | struct elo* elo = serio_get_drvdata(serio); | ||
167 | |||
168 | switch(elo->id) { | ||
169 | case 0: | ||
170 | elo_process_data_10(elo, data, regs); | ||
171 | break; | ||
172 | |||
173 | case 1: | ||
174 | case 2: | ||
175 | elo_process_data_6(elo, data, regs); | ||
176 | break; | ||
177 | |||
178 | case 3: | ||
179 | elo_process_data_3(elo, data, regs); | ||
180 | break; | ||
181 | } | ||
182 | |||
183 | return IRQ_HANDLED; | ||
184 | } | ||
185 | |||
186 | /* | ||
187 | * elo_disconnect() is the opposite of elo_connect() | ||
188 | */ | ||
189 | |||
190 | static void elo_disconnect(struct serio *serio) | ||
191 | { | ||
192 | struct elo* elo = serio_get_drvdata(serio); | ||
193 | |||
194 | input_unregister_device(&elo->dev); | ||
195 | serio_close(serio); | ||
196 | serio_set_drvdata(serio, NULL); | ||
197 | kfree(elo); | ||
198 | } | ||
199 | |||
200 | /* | ||
201 | * elo_connect() is the routine that is called when someone adds a | ||
202 | * new serio device that supports Gunze protocol and registers it as | ||
203 | * an input device. | ||
204 | */ | ||
205 | |||
206 | static int elo_connect(struct serio *serio, struct serio_driver *drv) | ||
207 | { | ||
208 | struct elo *elo; | ||
209 | int err; | ||
210 | |||
211 | if (!(elo = kmalloc(sizeof(struct elo), GFP_KERNEL))) | ||
212 | return -ENOMEM; | ||
213 | |||
214 | memset(elo, 0, sizeof(struct elo)); | ||
215 | |||
216 | init_input_dev(&elo->dev); | ||
217 | elo->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
218 | elo->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); | ||
219 | |||
220 | elo->id = serio->id.id; | ||
221 | |||
222 | switch (elo->id) { | ||
223 | |||
224 | case 0: /* 10-byte protocol */ | ||
225 | input_set_abs_params(&elo->dev, ABS_X, 96, 4000, 0, 0); | ||
226 | input_set_abs_params(&elo->dev, ABS_Y, 96, 4000, 0, 0); | ||
227 | input_set_abs_params(&elo->dev, ABS_PRESSURE, 0, 255, 0, 0); | ||
228 | break; | ||
229 | |||
230 | case 1: /* 6-byte protocol */ | ||
231 | input_set_abs_params(&elo->dev, ABS_PRESSURE, 0, 15, 0, 0); | ||
232 | |||
233 | case 2: /* 4-byte protocol */ | ||
234 | input_set_abs_params(&elo->dev, ABS_X, 96, 4000, 0, 0); | ||
235 | input_set_abs_params(&elo->dev, ABS_Y, 96, 4000, 0, 0); | ||
236 | break; | ||
237 | |||
238 | case 3: /* 3-byte protocol */ | ||
239 | input_set_abs_params(&elo->dev, ABS_X, 0, 255, 0, 0); | ||
240 | input_set_abs_params(&elo->dev, ABS_Y, 0, 255, 0, 0); | ||
241 | break; | ||
242 | } | ||
243 | |||
244 | elo->serio = serio; | ||
245 | |||
246 | sprintf(elo->phys, "%s/input0", serio->phys); | ||
247 | |||
248 | elo->dev.private = elo; | ||
249 | elo->dev.name = elo_name; | ||
250 | elo->dev.phys = elo->phys; | ||
251 | elo->dev.id.bustype = BUS_RS232; | ||
252 | elo->dev.id.vendor = SERIO_ELO; | ||
253 | elo->dev.id.product = elo->id; | ||
254 | elo->dev.id.version = 0x0100; | ||
255 | |||
256 | serio_set_drvdata(serio, elo); | ||
257 | |||
258 | err = serio_open(serio, drv); | ||
259 | if (err) { | ||
260 | serio_set_drvdata(serio, NULL); | ||
261 | kfree(elo); | ||
262 | return err; | ||
263 | } | ||
264 | |||
265 | input_register_device(&elo->dev); | ||
266 | |||
267 | printk(KERN_INFO "input: %s on %s\n", elo_name, serio->phys); | ||
268 | |||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | /* | ||
273 | * The serio driver structure. | ||
274 | */ | ||
275 | |||
276 | static struct serio_device_id elo_serio_ids[] = { | ||
277 | { | ||
278 | .type = SERIO_RS232, | ||
279 | .proto = SERIO_ELO, | ||
280 | .id = SERIO_ANY, | ||
281 | .extra = SERIO_ANY, | ||
282 | }, | ||
283 | { 0 } | ||
284 | }; | ||
285 | |||
286 | MODULE_DEVICE_TABLE(serio, elo_serio_ids); | ||
287 | |||
288 | static struct serio_driver elo_drv = { | ||
289 | .driver = { | ||
290 | .name = "elo", | ||
291 | }, | ||
292 | .description = DRIVER_DESC, | ||
293 | .id_table = elo_serio_ids, | ||
294 | .interrupt = elo_interrupt, | ||
295 | .connect = elo_connect, | ||
296 | .disconnect = elo_disconnect, | ||
297 | }; | ||
298 | |||
299 | /* | ||
300 | * The functions for inserting/removing us as a module. | ||
301 | */ | ||
302 | |||
303 | static int __init elo_init(void) | ||
304 | { | ||
305 | serio_register_driver(&elo_drv); | ||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | static void __exit elo_exit(void) | ||
310 | { | ||
311 | serio_unregister_driver(&elo_drv); | ||
312 | } | ||
313 | |||
314 | module_init(elo_init); | ||
315 | module_exit(elo_exit); | ||