Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
1da177e4 LT |
2 | /* |
3 | * Elo serial touchscreen driver | |
4 | * | |
5 | * Copyright (c) 2004 Vojtech Pavlik | |
6 | */ | |
7 | ||
1da177e4 LT |
8 | |
9 | /* | |
10 | * This driver can handle serial Elo touchscreens using either the Elo standard | |
11 | * 'E271-2210' 10-byte protocol, Elo legacy 'E281A-4002' 6-byte protocol, Elo | |
12 | * legacy 'E271-140' 4-byte protocol and Elo legacy 'E261-280' 3-byte protocol. | |
13 | */ | |
14 | ||
15 | #include <linux/errno.h> | |
16 | #include <linux/kernel.h> | |
17 | #include <linux/module.h> | |
18 | #include <linux/slab.h> | |
19 | #include <linux/input.h> | |
20 | #include <linux/serio.h> | |
fae3006e | 21 | #include <linux/ctype.h> |
1da177e4 LT |
22 | |
23 | #define DRIVER_DESC "Elo serial touchscreen driver" | |
24 | ||
25 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | |
26 | MODULE_DESCRIPTION(DRIVER_DESC); | |
27 | MODULE_LICENSE("GPL"); | |
28 | ||
29 | /* | |
30 | * Definitions & global arrays. | |
31 | */ | |
32 | ||
1ce316ef SJ |
33 | #define ELO_MAX_LENGTH 10 |
34 | ||
fae3006e SJ |
35 | #define ELO10_PACKET_LEN 8 |
36 | #define ELO10_TOUCH 0x03 | |
37 | #define ELO10_PRESSURE 0x80 | |
38 | ||
1ce316ef SJ |
39 | #define ELO10_LEAD_BYTE 'U' |
40 | ||
fae3006e SJ |
41 | #define ELO10_ID_CMD 'i' |
42 | ||
1ce316ef | 43 | #define ELO10_TOUCH_PACKET 'T' |
fae3006e SJ |
44 | #define ELO10_ACK_PACKET 'A' |
45 | #define ELI10_ID_PACKET 'I' | |
1da177e4 | 46 | |
1da177e4 LT |
47 | /* |
48 | * Per-touchscreen data. | |
49 | */ | |
50 | ||
51 | struct elo { | |
eca1ed19 | 52 | struct input_dev *dev; |
1da177e4 | 53 | struct serio *serio; |
fae3006e SJ |
54 | struct mutex cmd_mutex; |
55 | struct completion cmd_done; | |
1da177e4 LT |
56 | int id; |
57 | int idx; | |
fae3006e | 58 | unsigned char expected_packet; |
1da177e4 LT |
59 | unsigned char csum; |
60 | unsigned char data[ELO_MAX_LENGTH]; | |
fae3006e | 61 | unsigned char response[ELO10_PACKET_LEN]; |
1da177e4 LT |
62 | char phys[32]; |
63 | }; | |
64 | ||
7d12e780 | 65 | static void elo_process_data_10(struct elo *elo, unsigned char data) |
1da177e4 | 66 | { |
eca1ed19 | 67 | struct input_dev *dev = elo->dev; |
1da177e4 | 68 | |
1ce316ef | 69 | elo->data[elo->idx] = data; |
1da177e4 | 70 | |
8cab9ba1 DT |
71 | switch (elo->idx++) { |
72 | case 0: | |
73 | elo->csum = 0xaa; | |
74 | if (data != ELO10_LEAD_BYTE) { | |
75 | dev_dbg(&elo->serio->dev, | |
76 | "unsynchronized data: 0x%02x\n", data); | |
1da177e4 | 77 | elo->idx = 0; |
8cab9ba1 DT |
78 | } |
79 | break; | |
80 | ||
81 | case 9: | |
82 | elo->idx = 0; | |
83 | if (data != elo->csum) { | |
84 | dev_dbg(&elo->serio->dev, | |
85 | "bad checksum: 0x%02x, expected 0x%02x\n", | |
86 | data, elo->csum); | |
87 | break; | |
88 | } | |
89 | if (elo->data[1] != elo->expected_packet) { | |
90 | if (elo->data[1] != ELO10_TOUCH_PACKET) | |
91 | dev_dbg(&elo->serio->dev, | |
92 | "unexpected packet: 0x%02x\n", | |
93 | elo->data[1]); | |
1da177e4 | 94 | break; |
8cab9ba1 DT |
95 | } |
96 | if (likely(elo->data[1] == ELO10_TOUCH_PACKET)) { | |
97 | input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]); | |
98 | input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]); | |
99 | if (elo->data[2] & ELO10_PRESSURE) | |
100 | input_report_abs(dev, ABS_PRESSURE, | |
101 | (elo->data[8] << 8) | elo->data[7]); | |
102 | input_report_key(dev, BTN_TOUCH, elo->data[2] & ELO10_TOUCH); | |
103 | input_sync(dev); | |
104 | } else if (elo->data[1] == ELO10_ACK_PACKET) { | |
105 | if (elo->data[2] == '0') | |
106 | elo->expected_packet = ELO10_TOUCH_PACKET; | |
107 | complete(&elo->cmd_done); | |
108 | } else { | |
109 | memcpy(elo->response, &elo->data[1], ELO10_PACKET_LEN); | |
110 | elo->expected_packet = ELO10_ACK_PACKET; | |
111 | } | |
112 | break; | |
1da177e4 | 113 | } |
1ce316ef | 114 | elo->csum += data; |
1da177e4 LT |
115 | } |
116 | ||
7d12e780 | 117 | static void elo_process_data_6(struct elo *elo, unsigned char data) |
1da177e4 | 118 | { |
eca1ed19 | 119 | struct input_dev *dev = elo->dev; |
1da177e4 LT |
120 | |
121 | elo->data[elo->idx] = data; | |
122 | ||
123 | switch (elo->idx++) { | |
124 | ||
8cab9ba1 DT |
125 | case 0: |
126 | if ((data & 0xc0) != 0xc0) | |
127 | elo->idx = 0; | |
128 | break; | |
1da177e4 | 129 | |
8cab9ba1 DT |
130 | case 1: |
131 | if ((data & 0xc0) != 0x80) | |
132 | elo->idx = 0; | |
133 | break; | |
1da177e4 | 134 | |
8cab9ba1 DT |
135 | case 2: |
136 | if ((data & 0xc0) != 0x40) | |
137 | elo->idx = 0; | |
138 | break; | |
1da177e4 | 139 | |
8cab9ba1 DT |
140 | case 3: |
141 | if (data & 0xc0) { | |
142 | elo->idx = 0; | |
1da177e4 | 143 | break; |
8cab9ba1 | 144 | } |
1da177e4 | 145 | |
8cab9ba1 DT |
146 | input_report_abs(dev, ABS_X, ((elo->data[0] & 0x3f) << 6) | (elo->data[1] & 0x3f)); |
147 | input_report_abs(dev, ABS_Y, ((elo->data[2] & 0x3f) << 6) | (elo->data[3] & 0x3f)); | |
1da177e4 | 148 | |
8cab9ba1 DT |
149 | if (elo->id == 2) { |
150 | input_report_key(dev, BTN_TOUCH, 1); | |
1da177e4 LT |
151 | input_sync(dev); |
152 | elo->idx = 0; | |
8cab9ba1 DT |
153 | } |
154 | ||
155 | break; | |
156 | ||
157 | case 4: | |
158 | if (data) { | |
159 | input_sync(dev); | |
160 | elo->idx = 0; | |
161 | } | |
162 | break; | |
163 | ||
164 | case 5: | |
165 | if ((data & 0xf0) == 0) { | |
166 | input_report_abs(dev, ABS_PRESSURE, elo->data[5]); | |
167 | input_report_key(dev, BTN_TOUCH, !!elo->data[5]); | |
168 | } | |
169 | input_sync(dev); | |
170 | elo->idx = 0; | |
171 | break; | |
1da177e4 LT |
172 | } |
173 | } | |
174 | ||
7d12e780 | 175 | static void elo_process_data_3(struct elo *elo, unsigned char data) |
1da177e4 | 176 | { |
eca1ed19 | 177 | struct input_dev *dev = elo->dev; |
1da177e4 LT |
178 | |
179 | elo->data[elo->idx] = data; | |
180 | ||
181 | switch (elo->idx++) { | |
182 | ||
8cab9ba1 DT |
183 | case 0: |
184 | if ((data & 0x7f) != 0x01) | |
1da177e4 | 185 | elo->idx = 0; |
8cab9ba1 DT |
186 | break; |
187 | case 2: | |
188 | input_report_key(dev, BTN_TOUCH, !(elo->data[1] & 0x80)); | |
189 | input_report_abs(dev, ABS_X, elo->data[1]); | |
190 | input_report_abs(dev, ABS_Y, elo->data[2]); | |
191 | input_sync(dev); | |
192 | elo->idx = 0; | |
193 | break; | |
1da177e4 LT |
194 | } |
195 | } | |
196 | ||
197 | static irqreturn_t elo_interrupt(struct serio *serio, | |
7d12e780 | 198 | unsigned char data, unsigned int flags) |
1da177e4 | 199 | { |
1ce316ef | 200 | struct elo *elo = serio_get_drvdata(serio); |
1da177e4 | 201 | |
8cab9ba1 DT |
202 | switch (elo->id) { |
203 | case 0: | |
204 | elo_process_data_10(elo, data); | |
205 | break; | |
206 | ||
207 | case 1: | |
208 | case 2: | |
209 | elo_process_data_6(elo, data); | |
210 | break; | |
211 | ||
212 | case 3: | |
213 | elo_process_data_3(elo, data); | |
214 | break; | |
1da177e4 LT |
215 | } |
216 | ||
217 | return IRQ_HANDLED; | |
218 | } | |
219 | ||
fae3006e SJ |
220 | static int elo_command_10(struct elo *elo, unsigned char *packet) |
221 | { | |
222 | int rc = -1; | |
223 | int i; | |
224 | unsigned char csum = 0xaa + ELO10_LEAD_BYTE; | |
225 | ||
226 | mutex_lock(&elo->cmd_mutex); | |
227 | ||
228 | serio_pause_rx(elo->serio); | |
229 | elo->expected_packet = toupper(packet[0]); | |
230 | init_completion(&elo->cmd_done); | |
231 | serio_continue_rx(elo->serio); | |
232 | ||
233 | if (serio_write(elo->serio, ELO10_LEAD_BYTE)) | |
234 | goto out; | |
235 | ||
236 | for (i = 0; i < ELO10_PACKET_LEN; i++) { | |
237 | csum += packet[i]; | |
238 | if (serio_write(elo->serio, packet[i])) | |
239 | goto out; | |
240 | } | |
241 | ||
242 | if (serio_write(elo->serio, csum)) | |
243 | goto out; | |
244 | ||
245 | wait_for_completion_timeout(&elo->cmd_done, HZ); | |
246 | ||
247 | if (elo->expected_packet == ELO10_TOUCH_PACKET) { | |
248 | /* We are back in reporting mode, the command was ACKed */ | |
249 | memcpy(packet, elo->response, ELO10_PACKET_LEN); | |
250 | rc = 0; | |
251 | } | |
252 | ||
253 | out: | |
254 | mutex_unlock(&elo->cmd_mutex); | |
255 | return rc; | |
256 | } | |
257 | ||
258 | static int elo_setup_10(struct elo *elo) | |
259 | { | |
260 | static const char *elo_types[] = { "Accu", "Dura", "Intelli", "Carroll" }; | |
261 | struct input_dev *dev = elo->dev; | |
262 | unsigned char packet[ELO10_PACKET_LEN] = { ELO10_ID_CMD }; | |
263 | ||
264 | if (elo_command_10(elo, packet)) | |
265 | return -1; | |
266 | ||
267 | dev->id.version = (packet[5] << 8) | packet[4]; | |
268 | ||
269 | input_set_abs_params(dev, ABS_X, 96, 4000, 0, 0); | |
270 | input_set_abs_params(dev, ABS_Y, 96, 4000, 0, 0); | |
271 | if (packet[3] & ELO10_PRESSURE) | |
272 | input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); | |
273 | ||
8cab9ba1 DT |
274 | dev_info(&elo->serio->dev, |
275 | "%sTouch touchscreen, fw: %02x.%02x, features: 0x%02x, controller: 0x%02x\n", | |
276 | elo_types[(packet[1] -'0') & 0x03], | |
277 | packet[5], packet[4], packet[3], packet[7]); | |
fae3006e SJ |
278 | |
279 | return 0; | |
280 | } | |
281 | ||
1da177e4 LT |
282 | /* |
283 | * elo_disconnect() is the opposite of elo_connect() | |
284 | */ | |
285 | ||
286 | static void elo_disconnect(struct serio *serio) | |
287 | { | |
6b50d8b8 | 288 | struct elo *elo = serio_get_drvdata(serio); |
1da177e4 | 289 | |
6b50d8b8 | 290 | input_get_device(elo->dev); |
eca1ed19 | 291 | input_unregister_device(elo->dev); |
1da177e4 LT |
292 | serio_close(serio); |
293 | serio_set_drvdata(serio, NULL); | |
6b50d8b8 | 294 | input_put_device(elo->dev); |
1da177e4 LT |
295 | kfree(elo); |
296 | } | |
297 | ||
298 | /* | |
299 | * elo_connect() is the routine that is called when someone adds a | |
300 | * new serio device that supports Gunze protocol and registers it as | |
301 | * an input device. | |
302 | */ | |
303 | ||
304 | static int elo_connect(struct serio *serio, struct serio_driver *drv) | |
305 | { | |
306 | struct elo *elo; | |
eca1ed19 | 307 | struct input_dev *input_dev; |
1da177e4 LT |
308 | int err; |
309 | ||
f81d03d4 | 310 | elo = kzalloc(sizeof(*elo), GFP_KERNEL); |
eca1ed19 DT |
311 | input_dev = input_allocate_device(); |
312 | if (!elo || !input_dev) { | |
313 | err = -ENOMEM; | |
6b50d8b8 | 314 | goto fail1; |
eca1ed19 | 315 | } |
1da177e4 | 316 | |
eca1ed19 DT |
317 | elo->serio = serio; |
318 | elo->id = serio->id.id; | |
319 | elo->dev = input_dev; | |
fae3006e SJ |
320 | elo->expected_packet = ELO10_TOUCH_PACKET; |
321 | mutex_init(&elo->cmd_mutex); | |
322 | init_completion(&elo->cmd_done); | |
eca1ed19 | 323 | snprintf(elo->phys, sizeof(elo->phys), "%s/input0", serio->phys); |
1da177e4 | 324 | |
eca1ed19 DT |
325 | input_dev->name = "Elo Serial TouchScreen"; |
326 | input_dev->phys = elo->phys; | |
327 | input_dev->id.bustype = BUS_RS232; | |
328 | input_dev->id.vendor = SERIO_ELO; | |
329 | input_dev->id.product = elo->id; | |
330 | input_dev->id.version = 0x0100; | |
a5394fb0 | 331 | input_dev->dev.parent = &serio->dev; |
1da177e4 | 332 | |
7b19ada2 JS |
333 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
334 | input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); | |
1da177e4 | 335 | |
fae3006e SJ |
336 | serio_set_drvdata(serio, elo); |
337 | err = serio_open(serio, drv); | |
338 | if (err) | |
339 | goto fail2; | |
340 | ||
1da177e4 LT |
341 | switch (elo->id) { |
342 | ||
8cab9ba1 | 343 | case 0: /* 10-byte protocol */ |
0958351e DC |
344 | if (elo_setup_10(elo)) { |
345 | err = -EIO; | |
8cab9ba1 | 346 | goto fail3; |
0958351e | 347 | } |
fae3006e | 348 | |
8cab9ba1 | 349 | break; |
de1b963a | 350 | |
8cab9ba1 DT |
351 | case 1: /* 6-byte protocol */ |
352 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, 15, 0, 0); | |
6f49c4f5 | 353 | fallthrough; |
1da177e4 | 354 | |
8cab9ba1 DT |
355 | case 2: /* 4-byte protocol */ |
356 | input_set_abs_params(input_dev, ABS_X, 96, 4000, 0, 0); | |
357 | input_set_abs_params(input_dev, ABS_Y, 96, 4000, 0, 0); | |
358 | break; | |
1da177e4 | 359 | |
8cab9ba1 DT |
360 | case 3: /* 3-byte protocol */ |
361 | input_set_abs_params(input_dev, ABS_X, 0, 255, 0, 0); | |
362 | input_set_abs_params(input_dev, ABS_Y, 0, 255, 0, 0); | |
363 | break; | |
1da177e4 LT |
364 | } |
365 | ||
6b50d8b8 DT |
366 | err = input_register_device(elo->dev); |
367 | if (err) | |
368 | goto fail3; | |
1da177e4 LT |
369 | |
370 | return 0; | |
eca1ed19 | 371 | |
6b50d8b8 DT |
372 | fail3: serio_close(serio); |
373 | fail2: serio_set_drvdata(serio, NULL); | |
374 | fail1: input_free_device(input_dev); | |
eca1ed19 DT |
375 | kfree(elo); |
376 | return err; | |
1da177e4 LT |
377 | } |
378 | ||
379 | /* | |
380 | * The serio driver structure. | |
381 | */ | |
382 | ||
4f8d5241 | 383 | static const struct serio_device_id elo_serio_ids[] = { |
1da177e4 LT |
384 | { |
385 | .type = SERIO_RS232, | |
386 | .proto = SERIO_ELO, | |
387 | .id = SERIO_ANY, | |
388 | .extra = SERIO_ANY, | |
389 | }, | |
390 | { 0 } | |
391 | }; | |
392 | ||
393 | MODULE_DEVICE_TABLE(serio, elo_serio_ids); | |
394 | ||
395 | static struct serio_driver elo_drv = { | |
396 | .driver = { | |
397 | .name = "elo", | |
398 | }, | |
399 | .description = DRIVER_DESC, | |
400 | .id_table = elo_serio_ids, | |
401 | .interrupt = elo_interrupt, | |
402 | .connect = elo_connect, | |
403 | .disconnect = elo_disconnect, | |
404 | }; | |
405 | ||
65ac9f7a | 406 | module_serio_driver(elo_drv); |