diff options
Diffstat (limited to 'drivers/input/touchscreen/elo.c')
-rw-r--r-- | drivers/input/touchscreen/elo.c | 167 |
1 files changed, 133 insertions, 34 deletions
diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c index c86a2eb310fd..ab565335ee44 100644 --- a/drivers/input/touchscreen/elo.c +++ b/drivers/input/touchscreen/elo.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/input.h> | 23 | #include <linux/input.h> |
24 | #include <linux/serio.h> | 24 | #include <linux/serio.h> |
25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
26 | #include <linux/ctype.h> | ||
26 | 27 | ||
27 | #define DRIVER_DESC "Elo serial touchscreen driver" | 28 | #define DRIVER_DESC "Elo serial touchscreen driver" |
28 | 29 | ||
@@ -34,7 +35,19 @@ MODULE_LICENSE("GPL"); | |||
34 | * Definitions & global arrays. | 35 | * Definitions & global arrays. |
35 | */ | 36 | */ |
36 | 37 | ||
37 | #define ELO_MAX_LENGTH 10 | 38 | #define ELO_MAX_LENGTH 10 |
39 | |||
40 | #define ELO10_PACKET_LEN 8 | ||
41 | #define ELO10_TOUCH 0x03 | ||
42 | #define ELO10_PRESSURE 0x80 | ||
43 | |||
44 | #define ELO10_LEAD_BYTE 'U' | ||
45 | |||
46 | #define ELO10_ID_CMD 'i' | ||
47 | |||
48 | #define ELO10_TOUCH_PACKET 'T' | ||
49 | #define ELO10_ACK_PACKET 'A' | ||
50 | #define ELI10_ID_PACKET 'I' | ||
38 | 51 | ||
39 | /* | 52 | /* |
40 | * Per-touchscreen data. | 53 | * Per-touchscreen data. |
@@ -43,51 +56,67 @@ MODULE_LICENSE("GPL"); | |||
43 | struct elo { | 56 | struct elo { |
44 | struct input_dev *dev; | 57 | struct input_dev *dev; |
45 | struct serio *serio; | 58 | struct serio *serio; |
59 | struct mutex cmd_mutex; | ||
60 | struct completion cmd_done; | ||
46 | int id; | 61 | int id; |
47 | int idx; | 62 | int idx; |
63 | unsigned char expected_packet; | ||
48 | unsigned char csum; | 64 | unsigned char csum; |
49 | unsigned char data[ELO_MAX_LENGTH]; | 65 | unsigned char data[ELO_MAX_LENGTH]; |
66 | unsigned char response[ELO10_PACKET_LEN]; | ||
50 | char phys[32]; | 67 | char phys[32]; |
51 | }; | 68 | }; |
52 | 69 | ||
53 | static void elo_process_data_10(struct elo* elo, unsigned char data, struct pt_regs *regs) | 70 | static void elo_process_data_10(struct elo *elo, unsigned char data, struct pt_regs *regs) |
54 | { | 71 | { |
55 | struct input_dev *dev = elo->dev; | 72 | struct input_dev *dev = elo->dev; |
56 | 73 | ||
57 | elo->csum += elo->data[elo->idx] = data; | 74 | elo->data[elo->idx] = data; |
58 | |||
59 | switch (elo->idx++) { | 75 | switch (elo->idx++) { |
60 | |||
61 | case 0: | 76 | case 0: |
62 | if (data != 'U') { | 77 | elo->csum = 0xaa; |
78 | if (data != ELO10_LEAD_BYTE) { | ||
79 | pr_debug("elo: unsynchronized data: 0x%02x\n", data); | ||
63 | elo->idx = 0; | 80 | elo->idx = 0; |
64 | elo->csum = 0; | ||
65 | } | ||
66 | break; | ||
67 | |||
68 | case 1: | ||
69 | if (data != 'T') { | ||
70 | elo->idx = 0; | ||
71 | elo->csum = 0; | ||
72 | } | 81 | } |
73 | break; | 82 | break; |
74 | 83 | ||
75 | case 9: | 84 | case 9: |
76 | if (elo->csum) { | 85 | elo->idx = 0; |
86 | if (data != elo->csum) { | ||
87 | pr_debug("elo: bad checksum: 0x%02x, expected 0x%02x\n", | ||
88 | data, elo->csum); | ||
89 | break; | ||
90 | } | ||
91 | if (elo->data[1] != elo->expected_packet) { | ||
92 | if (elo->data[1] != ELO10_TOUCH_PACKET) | ||
93 | pr_debug("elo: unexpected packet: 0x%02x\n", | ||
94 | elo->data[1]); | ||
95 | break; | ||
96 | } | ||
97 | if (likely(elo->data[1] == ELO10_TOUCH_PACKET)) { | ||
77 | input_regs(dev, regs); | 98 | input_regs(dev, regs); |
78 | input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]); | 99 | input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]); |
79 | input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]); | 100 | input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]); |
80 | input_report_abs(dev, ABS_PRESSURE, (elo->data[8] << 8) | elo->data[7]); | 101 | if (elo->data[2] & ELO10_PRESSURE) |
81 | input_report_key(dev, BTN_TOUCH, elo->data[8] || elo->data[7]); | 102 | input_report_abs(dev, ABS_PRESSURE, |
103 | (elo->data[8] << 8) | elo->data[7]); | ||
104 | input_report_key(dev, BTN_TOUCH, elo->data[2] & ELO10_TOUCH); | ||
82 | input_sync(dev); | 105 | input_sync(dev); |
106 | } else if (elo->data[1] == ELO10_ACK_PACKET) { | ||
107 | if (elo->data[2] == '0') | ||
108 | elo->expected_packet = ELO10_TOUCH_PACKET; | ||
109 | complete(&elo->cmd_done); | ||
110 | } else { | ||
111 | memcpy(elo->response, &elo->data[1], ELO10_PACKET_LEN); | ||
112 | elo->expected_packet = ELO10_ACK_PACKET; | ||
83 | } | 113 | } |
84 | elo->idx = 0; | ||
85 | elo->csum = 0; | ||
86 | break; | 114 | break; |
87 | } | 115 | } |
116 | elo->csum += data; | ||
88 | } | 117 | } |
89 | 118 | ||
90 | static void elo_process_data_6(struct elo* elo, unsigned char data, struct pt_regs *regs) | 119 | static void elo_process_data_6(struct elo *elo, unsigned char data, struct pt_regs *regs) |
91 | { | 120 | { |
92 | struct input_dev *dev = elo->dev; | 121 | struct input_dev *dev = elo->dev; |
93 | 122 | ||
@@ -135,7 +164,7 @@ static void elo_process_data_6(struct elo* elo, unsigned char data, struct pt_re | |||
135 | } | 164 | } |
136 | } | 165 | } |
137 | 166 | ||
138 | static void elo_process_data_3(struct elo* elo, unsigned char data, struct pt_regs *regs) | 167 | static void elo_process_data_3(struct elo *elo, unsigned char data, struct pt_regs *regs) |
139 | { | 168 | { |
140 | struct input_dev *dev = elo->dev; | 169 | struct input_dev *dev = elo->dev; |
141 | 170 | ||
@@ -161,7 +190,7 @@ static void elo_process_data_3(struct elo* elo, unsigned char data, struct pt_re | |||
161 | static irqreturn_t elo_interrupt(struct serio *serio, | 190 | static irqreturn_t elo_interrupt(struct serio *serio, |
162 | unsigned char data, unsigned int flags, struct pt_regs *regs) | 191 | unsigned char data, unsigned int flags, struct pt_regs *regs) |
163 | { | 192 | { |
164 | struct elo* elo = serio_get_drvdata(serio); | 193 | struct elo *elo = serio_get_drvdata(serio); |
165 | 194 | ||
166 | switch(elo->id) { | 195 | switch(elo->id) { |
167 | case 0: | 196 | case 0: |
@@ -181,17 +210,81 @@ static irqreturn_t elo_interrupt(struct serio *serio, | |||
181 | return IRQ_HANDLED; | 210 | return IRQ_HANDLED; |
182 | } | 211 | } |
183 | 212 | ||
213 | static int elo_command_10(struct elo *elo, unsigned char *packet) | ||
214 | { | ||
215 | int rc = -1; | ||
216 | int i; | ||
217 | unsigned char csum = 0xaa + ELO10_LEAD_BYTE; | ||
218 | |||
219 | mutex_lock(&elo->cmd_mutex); | ||
220 | |||
221 | serio_pause_rx(elo->serio); | ||
222 | elo->expected_packet = toupper(packet[0]); | ||
223 | init_completion(&elo->cmd_done); | ||
224 | serio_continue_rx(elo->serio); | ||
225 | |||
226 | if (serio_write(elo->serio, ELO10_LEAD_BYTE)) | ||
227 | goto out; | ||
228 | |||
229 | for (i = 0; i < ELO10_PACKET_LEN; i++) { | ||
230 | csum += packet[i]; | ||
231 | if (serio_write(elo->serio, packet[i])) | ||
232 | goto out; | ||
233 | } | ||
234 | |||
235 | if (serio_write(elo->serio, csum)) | ||
236 | goto out; | ||
237 | |||
238 | wait_for_completion_timeout(&elo->cmd_done, HZ); | ||
239 | |||
240 | if (elo->expected_packet == ELO10_TOUCH_PACKET) { | ||
241 | /* We are back in reporting mode, the command was ACKed */ | ||
242 | memcpy(packet, elo->response, ELO10_PACKET_LEN); | ||
243 | rc = 0; | ||
244 | } | ||
245 | |||
246 | out: | ||
247 | mutex_unlock(&elo->cmd_mutex); | ||
248 | return rc; | ||
249 | } | ||
250 | |||
251 | static int elo_setup_10(struct elo *elo) | ||
252 | { | ||
253 | static const char *elo_types[] = { "Accu", "Dura", "Intelli", "Carroll" }; | ||
254 | struct input_dev *dev = elo->dev; | ||
255 | unsigned char packet[ELO10_PACKET_LEN] = { ELO10_ID_CMD }; | ||
256 | |||
257 | if (elo_command_10(elo, packet)) | ||
258 | return -1; | ||
259 | |||
260 | dev->id.version = (packet[5] << 8) | packet[4]; | ||
261 | |||
262 | input_set_abs_params(dev, ABS_X, 96, 4000, 0, 0); | ||
263 | input_set_abs_params(dev, ABS_Y, 96, 4000, 0, 0); | ||
264 | if (packet[3] & ELO10_PRESSURE) | ||
265 | input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); | ||
266 | |||
267 | printk(KERN_INFO "elo: %sTouch touchscreen, fw: %02x.%02x, " | ||
268 | "features: %x02x, controller: 0x%02x\n", | ||
269 | elo_types[(packet[1] -'0') & 0x03], | ||
270 | packet[5], packet[4], packet[3], packet[7]); | ||
271 | |||
272 | return 0; | ||
273 | } | ||
274 | |||
184 | /* | 275 | /* |
185 | * elo_disconnect() is the opposite of elo_connect() | 276 | * elo_disconnect() is the opposite of elo_connect() |
186 | */ | 277 | */ |
187 | 278 | ||
188 | static void elo_disconnect(struct serio *serio) | 279 | static void elo_disconnect(struct serio *serio) |
189 | { | 280 | { |
190 | struct elo* elo = serio_get_drvdata(serio); | 281 | struct elo *elo = serio_get_drvdata(serio); |
191 | 282 | ||
283 | input_get_device(elo->dev); | ||
192 | input_unregister_device(elo->dev); | 284 | input_unregister_device(elo->dev); |
193 | serio_close(serio); | 285 | serio_close(serio); |
194 | serio_set_drvdata(serio, NULL); | 286 | serio_set_drvdata(serio, NULL); |
287 | input_put_device(elo->dev); | ||
195 | kfree(elo); | 288 | kfree(elo); |
196 | } | 289 | } |
197 | 290 | ||
@@ -211,12 +304,15 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv) | |||
211 | input_dev = input_allocate_device(); | 304 | input_dev = input_allocate_device(); |
212 | if (!elo || !input_dev) { | 305 | if (!elo || !input_dev) { |
213 | err = -ENOMEM; | 306 | err = -ENOMEM; |
214 | goto fail; | 307 | goto fail1; |
215 | } | 308 | } |
216 | 309 | ||
217 | elo->serio = serio; | 310 | elo->serio = serio; |
218 | elo->id = serio->id.id; | 311 | elo->id = serio->id.id; |
219 | elo->dev = input_dev; | 312 | elo->dev = input_dev; |
313 | elo->expected_packet = ELO10_TOUCH_PACKET; | ||
314 | mutex_init(&elo->cmd_mutex); | ||
315 | init_completion(&elo->cmd_done); | ||
220 | snprintf(elo->phys, sizeof(elo->phys), "%s/input0", serio->phys); | 316 | snprintf(elo->phys, sizeof(elo->phys), "%s/input0", serio->phys); |
221 | 317 | ||
222 | input_dev->private = elo; | 318 | input_dev->private = elo; |
@@ -231,12 +327,17 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv) | |||
231 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | 327 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); |
232 | input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); | 328 | input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); |
233 | 329 | ||
330 | serio_set_drvdata(serio, elo); | ||
331 | err = serio_open(serio, drv); | ||
332 | if (err) | ||
333 | goto fail2; | ||
334 | |||
234 | switch (elo->id) { | 335 | switch (elo->id) { |
235 | 336 | ||
236 | case 0: /* 10-byte protocol */ | 337 | case 0: /* 10-byte protocol */ |
237 | input_set_abs_params(input_dev, ABS_X, 96, 4000, 0, 0); | 338 | if (elo_setup_10(elo)) |
238 | input_set_abs_params(input_dev, ABS_Y, 96, 4000, 0, 0); | 339 | goto fail3; |
239 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0); | 340 | |
240 | break; | 341 | break; |
241 | 342 | ||
242 | case 1: /* 6-byte protocol */ | 343 | case 1: /* 6-byte protocol */ |
@@ -253,17 +354,15 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv) | |||
253 | break; | 354 | break; |
254 | } | 355 | } |
255 | 356 | ||
256 | serio_set_drvdata(serio, elo); | 357 | err = input_register_device(elo->dev); |
257 | |||
258 | err = serio_open(serio, drv); | ||
259 | if (err) | 358 | if (err) |
260 | goto fail; | 359 | goto fail3; |
261 | 360 | ||
262 | input_register_device(elo->dev); | ||
263 | return 0; | 361 | return 0; |
264 | 362 | ||
265 | fail: serio_set_drvdata(serio, NULL); | 363 | fail3: serio_close(serio); |
266 | input_free_device(input_dev); | 364 | fail2: serio_set_drvdata(serio, NULL); |
365 | fail1: input_free_device(input_dev); | ||
267 | kfree(elo); | 366 | kfree(elo); |
268 | return err; | 367 | return err; |
269 | } | 368 | } |