diff options
Diffstat (limited to 'drivers/input/touchscreen/elo.c')
-rw-r--r-- | drivers/input/touchscreen/elo.c | 124 |
1 files changed, 107 insertions, 17 deletions
diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c index fe6e1a428674..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 | ||
@@ -36,9 +37,17 @@ MODULE_LICENSE("GPL"); | |||
36 | 37 | ||
37 | #define ELO_MAX_LENGTH 10 | 38 | #define ELO_MAX_LENGTH 10 |
38 | 39 | ||
40 | #define ELO10_PACKET_LEN 8 | ||
41 | #define ELO10_TOUCH 0x03 | ||
42 | #define ELO10_PRESSURE 0x80 | ||
43 | |||
39 | #define ELO10_LEAD_BYTE 'U' | 44 | #define ELO10_LEAD_BYTE 'U' |
40 | 45 | ||
46 | #define ELO10_ID_CMD 'i' | ||
47 | |||
41 | #define ELO10_TOUCH_PACKET 'T' | 48 | #define ELO10_TOUCH_PACKET 'T' |
49 | #define ELO10_ACK_PACKET 'A' | ||
50 | #define ELI10_ID_PACKET 'I' | ||
42 | 51 | ||
43 | /* | 52 | /* |
44 | * Per-touchscreen data. | 53 | * Per-touchscreen data. |
@@ -47,10 +56,14 @@ MODULE_LICENSE("GPL"); | |||
47 | struct elo { | 56 | struct elo { |
48 | struct input_dev *dev; | 57 | struct input_dev *dev; |
49 | struct serio *serio; | 58 | struct serio *serio; |
59 | struct mutex cmd_mutex; | ||
60 | struct completion cmd_done; | ||
50 | int id; | 61 | int id; |
51 | int idx; | 62 | int idx; |
63 | unsigned char expected_packet; | ||
52 | unsigned char csum; | 64 | unsigned char csum; |
53 | unsigned char data[ELO_MAX_LENGTH]; | 65 | unsigned char data[ELO_MAX_LENGTH]; |
66 | unsigned char response[ELO10_PACKET_LEN]; | ||
54 | char phys[32]; | 67 | char phys[32]; |
55 | }; | 68 | }; |
56 | 69 | ||
@@ -75,16 +88,29 @@ static void elo_process_data_10(struct elo *elo, unsigned char data, struct pt_r | |||
75 | data, elo->csum); | 88 | data, elo->csum); |
76 | break; | 89 | break; |
77 | } | 90 | } |
78 | if (elo->data[1] != ELO10_TOUCH_PACKET) { | 91 | if (elo->data[1] != elo->expected_packet) { |
79 | pr_debug(elo: "unexpected packet: 0x%02x\n", elo->data[1]); | 92 | if (elo->data[1] != ELO10_TOUCH_PACKET) |
93 | pr_debug("elo: unexpected packet: 0x%02x\n", | ||
94 | elo->data[1]); | ||
80 | break; | 95 | break; |
81 | } | 96 | } |
82 | input_regs(dev, regs); | 97 | if (likely(elo->data[1] == ELO10_TOUCH_PACKET)) { |
83 | input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]); | 98 | input_regs(dev, regs); |
84 | input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]); | 99 | input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]); |
85 | input_report_abs(dev, ABS_PRESSURE, (elo->data[8] << 8) | elo->data[7]); | 100 | input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]); |
86 | input_report_key(dev, BTN_TOUCH, elo->data[8] || elo->data[7]); | 101 | if (elo->data[2] & ELO10_PRESSURE) |
87 | input_sync(dev); | 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); | ||
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; | ||
113 | } | ||
88 | break; | 114 | break; |
89 | } | 115 | } |
90 | elo->csum += data; | 116 | elo->csum += data; |
@@ -184,6 +210,68 @@ static irqreturn_t elo_interrupt(struct serio *serio, | |||
184 | return IRQ_HANDLED; | 210 | return IRQ_HANDLED; |
185 | } | 211 | } |
186 | 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 | |||
187 | /* | 275 | /* |
188 | * elo_disconnect() is the opposite of elo_connect() | 276 | * elo_disconnect() is the opposite of elo_connect() |
189 | */ | 277 | */ |
@@ -222,6 +310,9 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv) | |||
222 | elo->serio = serio; | 310 | elo->serio = serio; |
223 | elo->id = serio->id.id; | 311 | elo->id = serio->id.id; |
224 | 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); | ||
225 | snprintf(elo->phys, sizeof(elo->phys), "%s/input0", serio->phys); | 316 | snprintf(elo->phys, sizeof(elo->phys), "%s/input0", serio->phys); |
226 | 317 | ||
227 | input_dev->private = elo; | 318 | input_dev->private = elo; |
@@ -236,12 +327,17 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv) | |||
236 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | 327 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); |
237 | input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); | 328 | input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); |
238 | 329 | ||
330 | serio_set_drvdata(serio, elo); | ||
331 | err = serio_open(serio, drv); | ||
332 | if (err) | ||
333 | goto fail2; | ||
334 | |||
239 | switch (elo->id) { | 335 | switch (elo->id) { |
240 | 336 | ||
241 | case 0: /* 10-byte protocol */ | 337 | case 0: /* 10-byte protocol */ |
242 | input_set_abs_params(input_dev, ABS_X, 96, 4000, 0, 0); | 338 | if (elo_setup_10(elo)) |
243 | input_set_abs_params(input_dev, ABS_Y, 96, 4000, 0, 0); | 339 | goto fail3; |
244 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0); | 340 | |
245 | break; | 341 | break; |
246 | 342 | ||
247 | case 1: /* 6-byte protocol */ | 343 | case 1: /* 6-byte protocol */ |
@@ -258,12 +354,6 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv) | |||
258 | break; | 354 | break; |
259 | } | 355 | } |
260 | 356 | ||
261 | serio_set_drvdata(serio, elo); | ||
262 | |||
263 | err = serio_open(serio, drv); | ||
264 | if (err) | ||
265 | goto fail2; | ||
266 | |||
267 | err = input_register_device(elo->dev); | 357 | err = input_register_device(elo->dev); |
268 | if (err) | 358 | if (err) |
269 | goto fail3; | 359 | goto fail3; |