Commit | Line | Data |
---|---|---|
3eb1aa43 JK |
1 | /* |
2 | * Wacom W8001 penabled serial touchscreen driver | |
3 | * | |
4 | * Copyright (c) 2008 Jaya Kumar | |
aaba933e | 5 | * Copyright (c) 2010 Red Hat, Inc. |
5fca6cac | 6 | * Copyright (c) 2010 - 2011 Ping Cheng, Wacom. <pingc@wacom.com> |
3eb1aa43 JK |
7 | * |
8 | * This file is subject to the terms and conditions of the GNU General Public | |
9 | * License. See the file COPYING in the main directory of this archive for | |
10 | * more details. | |
11 | * | |
12 | * Layout based on Elo serial touchscreen driver by Vojtech Pavlik | |
13 | */ | |
14 | ||
15 | #include <linux/errno.h> | |
16 | #include <linux/kernel.h> | |
17 | #include <linux/module.h> | |
18 | #include <linux/slab.h> | |
47c78e89 | 19 | #include <linux/input/mt.h> |
3eb1aa43 JK |
20 | #include <linux/serio.h> |
21 | #include <linux/init.h> | |
22 | #include <linux/ctype.h> | |
a6d38f88 | 23 | #include <linux/delay.h> |
3eb1aa43 JK |
24 | |
25 | #define DRIVER_DESC "Wacom W8001 serial touchscreen driver" | |
26 | ||
27 | MODULE_AUTHOR("Jaya Kumar <jayakumar.lkml@gmail.com>"); | |
28 | MODULE_DESCRIPTION(DRIVER_DESC); | |
29 | MODULE_LICENSE("GPL"); | |
30 | ||
3eb1aa43 | 31 | #define W8001_MAX_LENGTH 11 |
41c372dc DT |
32 | #define W8001_LEAD_MASK 0x80 |
33 | #define W8001_LEAD_BYTE 0x80 | |
34 | #define W8001_TAB_MASK 0x40 | |
35 | #define W8001_TAB_BYTE 0x40 | |
aaba933e PH |
36 | /* set in first byte of touch data packets */ |
37 | #define W8001_TOUCH_MASK (0x10 | W8001_LEAD_MASK) | |
38 | #define W8001_TOUCH_BYTE (0x10 | W8001_LEAD_BYTE) | |
3eb1aa43 | 39 | |
41c372dc DT |
40 | #define W8001_QUERY_PACKET 0x20 |
41 | ||
a6d38f88 | 42 | #define W8001_CMD_STOP '0' |
41c372dc DT |
43 | #define W8001_CMD_START '1' |
44 | #define W8001_CMD_QUERY '*' | |
aaba933e PH |
45 | #define W8001_CMD_TOUCHQUERY '%' |
46 | ||
47 | /* length of data packets in bytes, depends on device. */ | |
48 | #define W8001_PKTLEN_TOUCH93 5 | |
49 | #define W8001_PKTLEN_TOUCH9A 7 | |
50 | #define W8001_PKTLEN_TPCPEN 9 | |
51 | #define W8001_PKTLEN_TPCCTL 11 /* control packet */ | |
52 | #define W8001_PKTLEN_TOUCH2FG 13 | |
3eb1aa43 JK |
53 | |
54 | struct w8001_coord { | |
55 | u8 rdy; | |
56 | u8 tsw; | |
57 | u8 f1; | |
58 | u8 f2; | |
59 | u16 x; | |
60 | u16 y; | |
61 | u16 pen_pressure; | |
62 | u8 tilt_x; | |
63 | u8 tilt_y; | |
64 | }; | |
65 | ||
aaba933e PH |
66 | /* touch query reply packet */ |
67 | struct w8001_touch_query { | |
5fca6cac PC |
68 | u16 x; |
69 | u16 y; | |
aaba933e PH |
70 | u8 panel_res; |
71 | u8 capacity_res; | |
72 | u8 sensor_id; | |
aaba933e PH |
73 | }; |
74 | ||
3eb1aa43 JK |
75 | /* |
76 | * Per-touchscreen data. | |
77 | */ | |
78 | ||
79 | struct w8001 { | |
80 | struct input_dev *dev; | |
81 | struct serio *serio; | |
3eb1aa43 JK |
82 | struct completion cmd_done; |
83 | int id; | |
84 | int idx; | |
41c372dc DT |
85 | unsigned char response_type; |
86 | unsigned char response[W8001_MAX_LENGTH]; | |
3eb1aa43 | 87 | unsigned char data[W8001_MAX_LENGTH]; |
3eb1aa43 | 88 | char phys[32]; |
2072f8db | 89 | int type; |
aaba933e | 90 | unsigned int pktlen; |
5fca6cac PC |
91 | u16 max_touch_x; |
92 | u16 max_touch_y; | |
93 | u16 max_pen_x; | |
94 | u16 max_pen_y; | |
95 | char name[64]; | |
3eb1aa43 JK |
96 | }; |
97 | ||
5fca6cac | 98 | static void parse_pen_data(u8 *data, struct w8001_coord *coord) |
3eb1aa43 | 99 | { |
41c372dc DT |
100 | memset(coord, 0, sizeof(*coord)); |
101 | ||
3eb1aa43 JK |
102 | coord->rdy = data[0] & 0x20; |
103 | coord->tsw = data[0] & 0x01; | |
104 | coord->f1 = data[0] & 0x02; | |
105 | coord->f2 = data[0] & 0x04; | |
106 | ||
107 | coord->x = (data[1] & 0x7F) << 9; | |
108 | coord->x |= (data[2] & 0x7F) << 2; | |
109 | coord->x |= (data[6] & 0x60) >> 5; | |
110 | ||
111 | coord->y = (data[3] & 0x7F) << 9; | |
112 | coord->y |= (data[4] & 0x7F) << 2; | |
113 | coord->y |= (data[6] & 0x18) >> 3; | |
114 | ||
115 | coord->pen_pressure = data[5] & 0x7F; | |
116 | coord->pen_pressure |= (data[6] & 0x07) << 7 ; | |
117 | ||
118 | coord->tilt_x = data[7] & 0x7F; | |
119 | coord->tilt_y = data[8] & 0x7F; | |
3eb1aa43 JK |
120 | } |
121 | ||
5fca6cac PC |
122 | static void parse_single_touch(u8 *data, struct w8001_coord *coord) |
123 | { | |
124 | coord->x = (data[1] << 7) | data[2]; | |
125 | coord->y = (data[3] << 7) | data[4]; | |
126 | coord->tsw = data[0] & 0x01; | |
127 | } | |
128 | ||
129 | static void scale_touch_coordinates(struct w8001 *w8001, | |
130 | unsigned int *x, unsigned int *y) | |
131 | { | |
132 | if (w8001->max_pen_x && w8001->max_touch_x) | |
133 | *x = *x * w8001->max_pen_x / w8001->max_touch_x; | |
134 | ||
135 | if (w8001->max_pen_y && w8001->max_touch_y) | |
136 | *y = *y * w8001->max_pen_y / w8001->max_touch_y; | |
137 | } | |
138 | ||
139 | static void parse_multi_touch(struct w8001 *w8001) | |
5e8b9140 | 140 | { |
5e8b9140 PH |
141 | struct input_dev *dev = w8001->dev; |
142 | unsigned char *data = w8001->data; | |
5fca6cac | 143 | unsigned int x, y; |
5e8b9140 | 144 | int i; |
5fca6cac | 145 | int count = 0; |
5e8b9140 PH |
146 | |
147 | for (i = 0; i < 2; i++) { | |
c5f4dec1 | 148 | bool touch = data[0] & (1 << i); |
5e8b9140 | 149 | |
c5f4dec1 HR |
150 | input_mt_slot(dev, i); |
151 | input_mt_report_slot_state(dev, MT_TOOL_FINGER, touch); | |
152 | if (touch) { | |
5fca6cac PC |
153 | x = (data[6 * i + 1] << 7) | data[6 * i + 2]; |
154 | y = (data[6 * i + 3] << 7) | data[6 * i + 4]; | |
5e8b9140 PH |
155 | /* data[5,6] and [11,12] is finger capacity */ |
156 | ||
5fca6cac PC |
157 | /* scale to pen maximum */ |
158 | scale_touch_coordinates(w8001, &x, &y); | |
159 | ||
5e8b9140 PH |
160 | input_report_abs(dev, ABS_MT_POSITION_X, x); |
161 | input_report_abs(dev, ABS_MT_POSITION_Y, y); | |
5fca6cac | 162 | count++; |
5e8b9140 | 163 | } |
5e8b9140 PH |
164 | } |
165 | ||
5fca6cac PC |
166 | /* emulate single touch events when stylus is out of proximity. |
167 | * This is to make single touch backward support consistent | |
168 | * across all Wacom single touch devices. | |
169 | */ | |
170 | if (w8001->type != BTN_TOOL_PEN && | |
171 | w8001->type != BTN_TOOL_RUBBER) { | |
172 | w8001->type = count == 1 ? BTN_TOOL_FINGER : KEY_RESERVED; | |
173 | input_mt_report_pointer_emulation(dev, true); | |
174 | } | |
175 | ||
5e8b9140 PH |
176 | input_sync(dev); |
177 | } | |
178 | ||
aaba933e PH |
179 | static void parse_touchquery(u8 *data, struct w8001_touch_query *query) |
180 | { | |
181 | memset(query, 0, sizeof(*query)); | |
182 | ||
183 | query->panel_res = data[1]; | |
184 | query->sensor_id = data[2] & 0x7; | |
185 | query->capacity_res = data[7]; | |
186 | ||
187 | query->x = data[3] << 9; | |
188 | query->x |= data[4] << 2; | |
189 | query->x |= (data[2] >> 5) & 0x3; | |
190 | ||
191 | query->y = data[5] << 9; | |
192 | query->y |= data[6] << 2; | |
193 | query->y |= (data[2] >> 3) & 0x3; | |
5fca6cac PC |
194 | |
195 | /* Early days' single-finger touch models need the following defaults */ | |
196 | if (!query->x && !query->y) { | |
197 | query->x = 1024; | |
198 | query->y = 1024; | |
199 | if (query->panel_res) | |
200 | query->x = query->y = (1 << query->panel_res); | |
201 | query->panel_res = 10; | |
202 | } | |
aaba933e PH |
203 | } |
204 | ||
2072f8db PH |
205 | static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord) |
206 | { | |
207 | struct input_dev *dev = w8001->dev; | |
208 | ||
209 | /* | |
210 | * We have 1 bit for proximity (rdy) and 3 bits for tip, side, | |
211 | * side2/eraser. If rdy && f2 are set, this can be either pen + side2, | |
5fca6cac | 212 | * or eraser. Assume: |
2072f8db PH |
213 | * - if dev is already in proximity and f2 is toggled → pen + side2 |
214 | * - if dev comes into proximity with f2 set → eraser | |
215 | * If f2 disappears after assuming eraser, fake proximity out for | |
216 | * eraser and in for pen. | |
217 | */ | |
218 | ||
5fca6cac PC |
219 | switch (w8001->type) { |
220 | case BTN_TOOL_RUBBER: | |
2072f8db PH |
221 | if (!coord->f2) { |
222 | input_report_abs(dev, ABS_PRESSURE, 0); | |
223 | input_report_key(dev, BTN_TOUCH, 0); | |
224 | input_report_key(dev, BTN_STYLUS, 0); | |
225 | input_report_key(dev, BTN_STYLUS2, 0); | |
226 | input_report_key(dev, BTN_TOOL_RUBBER, 0); | |
227 | input_sync(dev); | |
228 | w8001->type = BTN_TOOL_PEN; | |
229 | } | |
5fca6cac PC |
230 | break; |
231 | ||
232 | case BTN_TOOL_FINGER: | |
233 | input_report_key(dev, BTN_TOUCH, 0); | |
234 | input_report_key(dev, BTN_TOOL_FINGER, 0); | |
235 | input_sync(dev); | |
236 | /* fall through */ | |
237 | ||
238 | case KEY_RESERVED: | |
239 | w8001->type = coord->f2 ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; | |
240 | break; | |
241 | ||
242 | default: | |
2072f8db | 243 | input_report_key(dev, BTN_STYLUS2, coord->f2); |
5fca6cac | 244 | break; |
2072f8db PH |
245 | } |
246 | ||
247 | input_report_abs(dev, ABS_X, coord->x); | |
248 | input_report_abs(dev, ABS_Y, coord->y); | |
249 | input_report_abs(dev, ABS_PRESSURE, coord->pen_pressure); | |
250 | input_report_key(dev, BTN_TOUCH, coord->tsw); | |
251 | input_report_key(dev, BTN_STYLUS, coord->f1); | |
252 | input_report_key(dev, w8001->type, coord->rdy); | |
253 | input_sync(dev); | |
254 | ||
255 | if (!coord->rdy) | |
5fca6cac PC |
256 | w8001->type = KEY_RESERVED; |
257 | } | |
258 | ||
259 | static void report_single_touch(struct w8001 *w8001, struct w8001_coord *coord) | |
260 | { | |
261 | struct input_dev *dev = w8001->dev; | |
262 | unsigned int x = coord->x; | |
263 | unsigned int y = coord->y; | |
264 | ||
265 | /* scale to pen maximum */ | |
266 | scale_touch_coordinates(w8001, &x, &y); | |
267 | ||
268 | input_report_abs(dev, ABS_X, x); | |
269 | input_report_abs(dev, ABS_Y, y); | |
270 | input_report_key(dev, BTN_TOUCH, coord->tsw); | |
271 | input_report_key(dev, BTN_TOOL_FINGER, coord->tsw); | |
272 | ||
273 | input_sync(dev); | |
274 | ||
275 | w8001->type = coord->tsw ? BTN_TOOL_FINGER : KEY_RESERVED; | |
2072f8db PH |
276 | } |
277 | ||
41c372dc DT |
278 | static irqreturn_t w8001_interrupt(struct serio *serio, |
279 | unsigned char data, unsigned int flags) | |
3eb1aa43 | 280 | { |
41c372dc | 281 | struct w8001 *w8001 = serio_get_drvdata(serio); |
3eb1aa43 | 282 | struct w8001_coord coord; |
41c372dc | 283 | unsigned char tmp; |
3eb1aa43 JK |
284 | |
285 | w8001->data[w8001->idx] = data; | |
286 | switch (w8001->idx++) { | |
287 | case 0: | |
288 | if ((data & W8001_LEAD_MASK) != W8001_LEAD_BYTE) { | |
289 | pr_debug("w8001: unsynchronized data: 0x%02x\n", data); | |
290 | w8001->idx = 0; | |
291 | } | |
292 | break; | |
41c372dc | 293 | |
aaba933e PH |
294 | case W8001_PKTLEN_TOUCH93 - 1: |
295 | case W8001_PKTLEN_TOUCH9A - 1: | |
5fca6cac PC |
296 | tmp = w8001->data[0] & W8001_TOUCH_BYTE; |
297 | if (tmp != W8001_TOUCH_BYTE) | |
298 | break; | |
299 | ||
300 | if (w8001->pktlen == w8001->idx) { | |
aaba933e | 301 | w8001->idx = 0; |
5fca6cac PC |
302 | if (w8001->type != BTN_TOOL_PEN && |
303 | w8001->type != BTN_TOOL_RUBBER) { | |
304 | parse_single_touch(w8001->data, &coord); | |
305 | report_single_touch(w8001, &coord); | |
306 | } | |
307 | } | |
aaba933e PH |
308 | break; |
309 | ||
310 | /* Pen coordinates packet */ | |
311 | case W8001_PKTLEN_TPCPEN - 1: | |
3eb1aa43 JK |
312 | tmp = w8001->data[0] & W8001_TAB_MASK; |
313 | if (unlikely(tmp == W8001_TAB_BYTE)) | |
314 | break; | |
41c372dc | 315 | |
5fca6cac | 316 | tmp = w8001->data[0] & W8001_TOUCH_BYTE; |
aaba933e PH |
317 | if (tmp == W8001_TOUCH_BYTE) |
318 | break; | |
319 | ||
3eb1aa43 | 320 | w8001->idx = 0; |
5fca6cac | 321 | parse_pen_data(w8001->data, &coord); |
2072f8db | 322 | report_pen_events(w8001, &coord); |
3eb1aa43 | 323 | break; |
41c372dc | 324 | |
aaba933e PH |
325 | /* control packet */ |
326 | case W8001_PKTLEN_TPCCTL - 1: | |
5fca6cac | 327 | tmp = w8001->data[0] & W8001_TOUCH_MASK; |
aaba933e PH |
328 | if (tmp == W8001_TOUCH_BYTE) |
329 | break; | |
330 | ||
3eb1aa43 | 331 | w8001->idx = 0; |
41c372dc DT |
332 | memcpy(w8001->response, w8001->data, W8001_MAX_LENGTH); |
333 | w8001->response_type = W8001_QUERY_PACKET; | |
3eb1aa43 JK |
334 | complete(&w8001->cmd_done); |
335 | break; | |
aaba933e | 336 | |
5e8b9140 | 337 | /* 2 finger touch packet */ |
aaba933e | 338 | case W8001_PKTLEN_TOUCH2FG - 1: |
5e8b9140 | 339 | w8001->idx = 0; |
5fca6cac | 340 | parse_multi_touch(w8001); |
aaba933e | 341 | break; |
3eb1aa43 | 342 | } |
3eb1aa43 JK |
343 | |
344 | return IRQ_HANDLED; | |
345 | } | |
346 | ||
41c372dc DT |
347 | static int w8001_command(struct w8001 *w8001, unsigned char command, |
348 | bool wait_response) | |
3eb1aa43 | 349 | { |
41c372dc | 350 | int rc; |
3eb1aa43 | 351 | |
41c372dc | 352 | w8001->response_type = 0; |
3eb1aa43 | 353 | init_completion(&w8001->cmd_done); |
3eb1aa43 | 354 | |
41c372dc DT |
355 | rc = serio_write(w8001->serio, command); |
356 | if (rc == 0 && wait_response) { | |
3eb1aa43 | 357 | |
41c372dc DT |
358 | wait_for_completion_timeout(&w8001->cmd_done, HZ); |
359 | if (w8001->response_type != W8001_QUERY_PACKET) | |
360 | rc = -EIO; | |
3eb1aa43 JK |
361 | } |
362 | ||
3eb1aa43 JK |
363 | return rc; |
364 | } | |
365 | ||
366 | static int w8001_setup(struct w8001 *w8001) | |
367 | { | |
3eb1aa43 | 368 | struct input_dev *dev = w8001->dev; |
41c372dc | 369 | struct w8001_coord coord; |
5fca6cac | 370 | struct w8001_touch_query touch; |
41c372dc | 371 | int error; |
3eb1aa43 | 372 | |
a6d38f88 | 373 | error = w8001_command(w8001, W8001_CMD_STOP, false); |
41c372dc DT |
374 | if (error) |
375 | return error; | |
3eb1aa43 | 376 | |
a6d38f88 | 377 | msleep(250); /* wait 250ms before querying the device */ |
3eb1aa43 | 378 | |
5fca6cac PC |
379 | dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
380 | strlcat(w8001->name, "Wacom Serial", sizeof(w8001->name)); | |
381 | ||
a6d38f88 PC |
382 | /* penabled? */ |
383 | error = w8001_command(w8001, W8001_CMD_QUERY, true); | |
384 | if (!error) { | |
5fca6cac | 385 | __set_bit(BTN_TOUCH, dev->keybit); |
a6d38f88 PC |
386 | __set_bit(BTN_TOOL_PEN, dev->keybit); |
387 | __set_bit(BTN_TOOL_RUBBER, dev->keybit); | |
388 | __set_bit(BTN_STYLUS, dev->keybit); | |
389 | __set_bit(BTN_STYLUS2, dev->keybit); | |
5fca6cac PC |
390 | |
391 | parse_pen_data(w8001->response, &coord); | |
392 | w8001->max_pen_x = coord.x; | |
393 | w8001->max_pen_y = coord.y; | |
a6d38f88 PC |
394 | |
395 | input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0); | |
396 | input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0); | |
397 | input_set_abs_params(dev, ABS_PRESSURE, 0, coord.pen_pressure, 0, 0); | |
398 | if (coord.tilt_x && coord.tilt_y) { | |
399 | input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0); | |
400 | input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0); | |
401 | } | |
5fca6cac PC |
402 | w8001->id = 0x90; |
403 | strlcat(w8001->name, " Penabled", sizeof(w8001->name)); | |
a6d38f88 | 404 | } |
3eb1aa43 | 405 | |
a6d38f88 | 406 | /* Touch enabled? */ |
aaba933e | 407 | error = w8001_command(w8001, W8001_CMD_TOUCHQUERY, true); |
a6d38f88 PC |
408 | |
409 | /* | |
410 | * Some non-touch devices may reply to the touch query. But their | |
411 | * second byte is empty, which indicates touch is not supported. | |
412 | */ | |
413 | if (!error && w8001->response[1]) { | |
5fca6cac PC |
414 | __set_bit(BTN_TOUCH, dev->keybit); |
415 | __set_bit(BTN_TOOL_FINGER, dev->keybit); | |
aaba933e PH |
416 | |
417 | parse_touchquery(w8001->response, &touch); | |
5fca6cac PC |
418 | w8001->max_touch_x = touch.x; |
419 | w8001->max_touch_y = touch.y; | |
420 | ||
421 | /* scale to pen maximum */ | |
422 | if (w8001->max_pen_x && w8001->max_pen_y) { | |
423 | touch.x = w8001->max_pen_x; | |
424 | touch.y = w8001->max_pen_y; | |
425 | } | |
aaba933e | 426 | |
a6d38f88 PC |
427 | input_set_abs_params(dev, ABS_X, 0, touch.x, 0, 0); |
428 | input_set_abs_params(dev, ABS_Y, 0, touch.y, 0, 0); | |
a6d38f88 | 429 | |
aaba933e PH |
430 | switch (touch.sensor_id) { |
431 | case 0: | |
432 | case 2: | |
433 | w8001->pktlen = W8001_PKTLEN_TOUCH93; | |
5fca6cac PC |
434 | w8001->id = 0x93; |
435 | strlcat(w8001->name, " 1FG", sizeof(w8001->name)); | |
aaba933e | 436 | break; |
5fca6cac | 437 | |
aaba933e PH |
438 | case 1: |
439 | case 3: | |
440 | case 4: | |
441 | w8001->pktlen = W8001_PKTLEN_TOUCH9A; | |
5fca6cac PC |
442 | strlcat(w8001->name, " 1FG", sizeof(w8001->name)); |
443 | w8001->id = 0x9a; | |
aaba933e | 444 | break; |
5fca6cac | 445 | |
aaba933e PH |
446 | case 5: |
447 | w8001->pktlen = W8001_PKTLEN_TOUCH2FG; | |
5e8b9140 | 448 | |
8cde8100 | 449 | input_mt_init_slots(dev, 2); |
5e8b9140 PH |
450 | input_set_abs_params(dev, ABS_MT_POSITION_X, |
451 | 0, touch.x, 0, 0); | |
452 | input_set_abs_params(dev, ABS_MT_POSITION_Y, | |
453 | 0, touch.y, 0, 0); | |
454 | input_set_abs_params(dev, ABS_MT_TOOL_TYPE, | |
c5f4dec1 | 455 | 0, MT_TOOL_MAX, 0, 0); |
5fca6cac PC |
456 | |
457 | strlcat(w8001->name, " 2FG", sizeof(w8001->name)); | |
458 | if (w8001->max_pen_x && w8001->max_pen_y) | |
459 | w8001->id = 0xE3; | |
460 | else | |
461 | w8001->id = 0xE2; | |
aaba933e PH |
462 | break; |
463 | } | |
464 | } | |
465 | ||
5fca6cac PC |
466 | strlcat(w8001->name, " Touchscreen", sizeof(w8001->name)); |
467 | ||
41c372dc | 468 | return w8001_command(w8001, W8001_CMD_START, false); |
3eb1aa43 JK |
469 | } |
470 | ||
471 | /* | |
472 | * w8001_disconnect() is the opposite of w8001_connect() | |
473 | */ | |
474 | ||
475 | static void w8001_disconnect(struct serio *serio) | |
476 | { | |
477 | struct w8001 *w8001 = serio_get_drvdata(serio); | |
478 | ||
479 | input_get_device(w8001->dev); | |
480 | input_unregister_device(w8001->dev); | |
481 | serio_close(serio); | |
482 | serio_set_drvdata(serio, NULL); | |
483 | input_put_device(w8001->dev); | |
484 | kfree(w8001); | |
485 | } | |
486 | ||
487 | /* | |
488 | * w8001_connect() is the routine that is called when someone adds a | |
489 | * new serio device that supports the w8001 protocol and registers it as | |
490 | * an input device. | |
491 | */ | |
492 | ||
493 | static int w8001_connect(struct serio *serio, struct serio_driver *drv) | |
494 | { | |
495 | struct w8001 *w8001; | |
496 | struct input_dev *input_dev; | |
497 | int err; | |
498 | ||
499 | w8001 = kzalloc(sizeof(struct w8001), GFP_KERNEL); | |
500 | input_dev = input_allocate_device(); | |
501 | if (!w8001 || !input_dev) { | |
502 | err = -ENOMEM; | |
503 | goto fail1; | |
504 | } | |
505 | ||
506 | w8001->serio = serio; | |
3eb1aa43 | 507 | w8001->dev = input_dev; |
3eb1aa43 JK |
508 | init_completion(&w8001->cmd_done); |
509 | snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys); | |
510 | ||
3eb1aa43 JK |
511 | serio_set_drvdata(serio, w8001); |
512 | err = serio_open(serio, drv); | |
513 | if (err) | |
514 | goto fail2; | |
515 | ||
41c372dc DT |
516 | err = w8001_setup(w8001); |
517 | if (err) | |
3eb1aa43 JK |
518 | goto fail3; |
519 | ||
5fca6cac PC |
520 | input_dev->name = w8001->name; |
521 | input_dev->phys = w8001->phys; | |
522 | input_dev->id.product = w8001->id; | |
523 | input_dev->id.bustype = BUS_RS232; | |
524 | input_dev->id.vendor = 0x056a; | |
525 | input_dev->id.version = 0x0100; | |
526 | input_dev->dev.parent = &serio->dev; | |
527 | ||
3eb1aa43 JK |
528 | err = input_register_device(w8001->dev); |
529 | if (err) | |
530 | goto fail3; | |
531 | ||
532 | return 0; | |
533 | ||
534 | fail3: | |
535 | serio_close(serio); | |
536 | fail2: | |
537 | serio_set_drvdata(serio, NULL); | |
538 | fail1: | |
539 | input_free_device(input_dev); | |
540 | kfree(w8001); | |
541 | return err; | |
542 | } | |
543 | ||
544 | static struct serio_device_id w8001_serio_ids[] = { | |
545 | { | |
546 | .type = SERIO_RS232, | |
547 | .proto = SERIO_W8001, | |
548 | .id = SERIO_ANY, | |
549 | .extra = SERIO_ANY, | |
550 | }, | |
551 | { 0 } | |
552 | }; | |
553 | ||
554 | MODULE_DEVICE_TABLE(serio, w8001_serio_ids); | |
555 | ||
556 | static struct serio_driver w8001_drv = { | |
557 | .driver = { | |
558 | .name = "w8001", | |
559 | }, | |
560 | .description = DRIVER_DESC, | |
561 | .id_table = w8001_serio_ids, | |
562 | .interrupt = w8001_interrupt, | |
563 | .connect = w8001_connect, | |
564 | .disconnect = w8001_disconnect, | |
565 | }; | |
566 | ||
567 | static int __init w8001_init(void) | |
568 | { | |
569 | return serio_register_driver(&w8001_drv); | |
570 | } | |
571 | ||
572 | static void __exit w8001_exit(void) | |
573 | { | |
574 | serio_unregister_driver(&w8001_drv); | |
575 | } | |
576 | ||
577 | module_init(w8001_init); | |
578 | module_exit(w8001_exit); |