Commit | Line | Data |
---|---|---|
3eb1aa43 JK |
1 | /* |
2 | * Wacom W8001 penabled serial touchscreen driver | |
3 | * | |
4 | * Copyright (c) 2008 Jaya Kumar | |
5 | * | |
6 | * This file is subject to the terms and conditions of the GNU General Public | |
7 | * License. See the file COPYING in the main directory of this archive for | |
8 | * more details. | |
9 | * | |
10 | * Layout based on Elo serial touchscreen driver by Vojtech Pavlik | |
11 | */ | |
12 | ||
13 | #include <linux/errno.h> | |
14 | #include <linux/kernel.h> | |
15 | #include <linux/module.h> | |
16 | #include <linux/slab.h> | |
17 | #include <linux/input.h> | |
18 | #include <linux/serio.h> | |
19 | #include <linux/init.h> | |
20 | #include <linux/ctype.h> | |
21 | ||
22 | #define DRIVER_DESC "Wacom W8001 serial touchscreen driver" | |
23 | ||
24 | MODULE_AUTHOR("Jaya Kumar <jayakumar.lkml@gmail.com>"); | |
25 | MODULE_DESCRIPTION(DRIVER_DESC); | |
26 | MODULE_LICENSE("GPL"); | |
27 | ||
28 | /* | |
29 | * Definitions & global arrays. | |
30 | */ | |
31 | ||
32 | #define W8001_MAX_LENGTH 11 | |
33 | #define W8001_PACKET_LEN 11 | |
34 | #define W8001_LEAD_MASK 0x80 | |
35 | #define W8001_LEAD_BYTE 0x80 | |
36 | #define W8001_TAB_MASK 0x40 | |
37 | #define W8001_TAB_BYTE 0x40 | |
38 | ||
39 | #define W8001_QUERY_PACKET 0x20 | |
40 | ||
41 | struct w8001_coord { | |
42 | u8 rdy; | |
43 | u8 tsw; | |
44 | u8 f1; | |
45 | u8 f2; | |
46 | u16 x; | |
47 | u16 y; | |
48 | u16 pen_pressure; | |
49 | u8 tilt_x; | |
50 | u8 tilt_y; | |
51 | }; | |
52 | ||
53 | /* | |
54 | * Per-touchscreen data. | |
55 | */ | |
56 | ||
57 | struct w8001 { | |
58 | struct input_dev *dev; | |
59 | struct serio *serio; | |
60 | struct mutex cmd_mutex; | |
61 | struct completion cmd_done; | |
62 | int id; | |
63 | int idx; | |
64 | unsigned char expected_packet; | |
65 | unsigned char data[W8001_MAX_LENGTH]; | |
66 | unsigned char response[W8001_PACKET_LEN]; | |
67 | char phys[32]; | |
68 | }; | |
69 | ||
70 | static int parse_data(u8 *data, struct w8001_coord *coord) | |
71 | { | |
72 | coord->rdy = data[0] & 0x20; | |
73 | coord->tsw = data[0] & 0x01; | |
74 | coord->f1 = data[0] & 0x02; | |
75 | coord->f2 = data[0] & 0x04; | |
76 | ||
77 | coord->x = (data[1] & 0x7F) << 9; | |
78 | coord->x |= (data[2] & 0x7F) << 2; | |
79 | coord->x |= (data[6] & 0x60) >> 5; | |
80 | ||
81 | coord->y = (data[3] & 0x7F) << 9; | |
82 | coord->y |= (data[4] & 0x7F) << 2; | |
83 | coord->y |= (data[6] & 0x18) >> 3; | |
84 | ||
85 | coord->pen_pressure = data[5] & 0x7F; | |
86 | coord->pen_pressure |= (data[6] & 0x07) << 7 ; | |
87 | ||
88 | coord->tilt_x = data[7] & 0x7F; | |
89 | coord->tilt_y = data[8] & 0x7F; | |
90 | ||
91 | return 0; | |
92 | } | |
93 | ||
94 | static void w8001_process_data(struct w8001 *w8001, unsigned char data) | |
95 | { | |
96 | struct input_dev *dev = w8001->dev; | |
97 | u8 tmp; | |
98 | struct w8001_coord coord; | |
99 | ||
100 | w8001->data[w8001->idx] = data; | |
101 | switch (w8001->idx++) { | |
102 | case 0: | |
103 | if ((data & W8001_LEAD_MASK) != W8001_LEAD_BYTE) { | |
104 | pr_debug("w8001: unsynchronized data: 0x%02x\n", data); | |
105 | w8001->idx = 0; | |
106 | } | |
107 | break; | |
108 | case 8: | |
109 | tmp = w8001->data[0] & W8001_TAB_MASK; | |
110 | if (unlikely(tmp == W8001_TAB_BYTE)) | |
111 | break; | |
112 | w8001->idx = 0; | |
113 | memset(&coord, 0, sizeof(coord)); | |
114 | parse_data(w8001->data, &coord); | |
115 | input_report_abs(dev, ABS_X, coord.x); | |
116 | input_report_abs(dev, ABS_Y, coord.y); | |
117 | input_report_abs(dev, ABS_PRESSURE, coord.pen_pressure); | |
118 | input_report_key(dev, BTN_TOUCH, coord.tsw); | |
119 | input_sync(dev); | |
120 | break; | |
121 | case 10: | |
122 | w8001->idx = 0; | |
123 | memcpy(w8001->response, &w8001->data, W8001_PACKET_LEN); | |
124 | w8001->expected_packet = W8001_QUERY_PACKET; | |
125 | complete(&w8001->cmd_done); | |
126 | break; | |
127 | } | |
128 | } | |
129 | ||
130 | ||
131 | static irqreturn_t w8001_interrupt(struct serio *serio, | |
132 | unsigned char data, unsigned int flags) | |
133 | { | |
134 | struct w8001 *w8001 = serio_get_drvdata(serio); | |
135 | ||
136 | w8001_process_data(w8001, data); | |
137 | ||
138 | return IRQ_HANDLED; | |
139 | } | |
140 | ||
141 | static int w8001_async_command(struct w8001 *w8001, unsigned char *packet, | |
142 | int len) | |
143 | { | |
144 | int rc = -1; | |
145 | int i; | |
146 | ||
147 | mutex_lock(&w8001->cmd_mutex); | |
148 | ||
149 | for (i = 0; i < len; i++) { | |
150 | if (serio_write(w8001->serio, packet[i])) | |
151 | goto out; | |
152 | } | |
153 | rc = 0; | |
154 | ||
155 | out: | |
156 | mutex_unlock(&w8001->cmd_mutex); | |
157 | return rc; | |
158 | } | |
159 | ||
160 | static int w8001_command(struct w8001 *w8001, unsigned char *packet, int len) | |
161 | { | |
162 | int rc = -1; | |
163 | int i; | |
164 | ||
165 | mutex_lock(&w8001->cmd_mutex); | |
166 | ||
167 | serio_pause_rx(w8001->serio); | |
168 | init_completion(&w8001->cmd_done); | |
169 | serio_continue_rx(w8001->serio); | |
170 | ||
171 | for (i = 0; i < len; i++) { | |
172 | if (serio_write(w8001->serio, packet[i])) | |
173 | goto out; | |
174 | } | |
175 | ||
176 | wait_for_completion_timeout(&w8001->cmd_done, HZ); | |
177 | ||
178 | if (w8001->expected_packet == W8001_QUERY_PACKET) { | |
179 | /* We are back in reporting mode, the query was ACKed */ | |
180 | memcpy(packet, w8001->response, W8001_PACKET_LEN); | |
181 | rc = 0; | |
182 | } | |
183 | ||
184 | out: | |
185 | mutex_unlock(&w8001->cmd_mutex); | |
186 | return rc; | |
187 | } | |
188 | ||
189 | static int w8001_setup(struct w8001 *w8001) | |
190 | { | |
191 | struct w8001_coord coord; | |
192 | struct input_dev *dev = w8001->dev; | |
193 | unsigned char start[1] = { '1' }; | |
194 | unsigned char query[11] = { '*' }; | |
195 | ||
196 | if (w8001_command(w8001, query, 1)) | |
197 | return -1; | |
198 | ||
199 | memset(&coord, 0, sizeof(coord)); | |
200 | parse_data(query, &coord); | |
201 | ||
202 | input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0); | |
203 | input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0); | |
204 | input_set_abs_params(dev, ABS_PRESSURE, 0, coord.pen_pressure, 0, 0); | |
205 | input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0); | |
206 | input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0); | |
207 | ||
208 | if (w8001_async_command(w8001, start, 1)) | |
209 | return -1; | |
210 | ||
211 | return 0; | |
212 | } | |
213 | ||
214 | /* | |
215 | * w8001_disconnect() is the opposite of w8001_connect() | |
216 | */ | |
217 | ||
218 | static void w8001_disconnect(struct serio *serio) | |
219 | { | |
220 | struct w8001 *w8001 = serio_get_drvdata(serio); | |
221 | ||
222 | input_get_device(w8001->dev); | |
223 | input_unregister_device(w8001->dev); | |
224 | serio_close(serio); | |
225 | serio_set_drvdata(serio, NULL); | |
226 | input_put_device(w8001->dev); | |
227 | kfree(w8001); | |
228 | } | |
229 | ||
230 | /* | |
231 | * w8001_connect() is the routine that is called when someone adds a | |
232 | * new serio device that supports the w8001 protocol and registers it as | |
233 | * an input device. | |
234 | */ | |
235 | ||
236 | static int w8001_connect(struct serio *serio, struct serio_driver *drv) | |
237 | { | |
238 | struct w8001 *w8001; | |
239 | struct input_dev *input_dev; | |
240 | int err; | |
241 | ||
242 | w8001 = kzalloc(sizeof(struct w8001), GFP_KERNEL); | |
243 | input_dev = input_allocate_device(); | |
244 | if (!w8001 || !input_dev) { | |
245 | err = -ENOMEM; | |
246 | goto fail1; | |
247 | } | |
248 | ||
249 | w8001->serio = serio; | |
250 | w8001->id = serio->id.id; | |
251 | w8001->dev = input_dev; | |
252 | mutex_init(&w8001->cmd_mutex); | |
253 | init_completion(&w8001->cmd_done); | |
254 | snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys); | |
255 | ||
256 | input_dev->name = "Wacom W8001 Penabled Serial TouchScreen"; | |
257 | input_dev->phys = w8001->phys; | |
258 | input_dev->id.bustype = BUS_RS232; | |
259 | input_dev->id.vendor = SERIO_W8001; | |
260 | input_dev->id.product = w8001->id; | |
261 | input_dev->id.version = 0x0100; | |
262 | input_dev->dev.parent = &serio->dev; | |
263 | ||
264 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | |
265 | input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); | |
266 | ||
267 | serio_set_drvdata(serio, w8001); | |
268 | err = serio_open(serio, drv); | |
269 | if (err) | |
270 | goto fail2; | |
271 | ||
272 | if (w8001_setup(w8001)) | |
273 | goto fail3; | |
274 | ||
275 | err = input_register_device(w8001->dev); | |
276 | if (err) | |
277 | goto fail3; | |
278 | ||
279 | return 0; | |
280 | ||
281 | fail3: | |
282 | serio_close(serio); | |
283 | fail2: | |
284 | serio_set_drvdata(serio, NULL); | |
285 | fail1: | |
286 | input_free_device(input_dev); | |
287 | kfree(w8001); | |
288 | return err; | |
289 | } | |
290 | ||
291 | static struct serio_device_id w8001_serio_ids[] = { | |
292 | { | |
293 | .type = SERIO_RS232, | |
294 | .proto = SERIO_W8001, | |
295 | .id = SERIO_ANY, | |
296 | .extra = SERIO_ANY, | |
297 | }, | |
298 | { 0 } | |
299 | }; | |
300 | ||
301 | MODULE_DEVICE_TABLE(serio, w8001_serio_ids); | |
302 | ||
303 | static struct serio_driver w8001_drv = { | |
304 | .driver = { | |
305 | .name = "w8001", | |
306 | }, | |
307 | .description = DRIVER_DESC, | |
308 | .id_table = w8001_serio_ids, | |
309 | .interrupt = w8001_interrupt, | |
310 | .connect = w8001_connect, | |
311 | .disconnect = w8001_disconnect, | |
312 | }; | |
313 | ||
314 | static int __init w8001_init(void) | |
315 | { | |
316 | return serio_register_driver(&w8001_drv); | |
317 | } | |
318 | ||
319 | static void __exit w8001_exit(void) | |
320 | { | |
321 | serio_unregister_driver(&w8001_drv); | |
322 | } | |
323 | ||
324 | module_init(w8001_init); | |
325 | module_exit(w8001_exit); |