]>
Commit | Line | Data |
---|---|---|
1d3e2023 DR |
1 | /****************************************************************************** |
2 | * usbtouchscreen.c | |
3 | * Driver for USB Touchscreens, supporting those devices: | |
4 | * - eGalax Touchkit | |
5d892665 DR |
5 | * includes eTurboTouch CT-410/510/700 |
6 | * - 3M/Microtouch EX II series | |
1d3e2023 DR |
7 | * - ITM |
8 | * - PanJit TouchSet | |
5d892665 DR |
9 | * - eTurboTouch |
10 | * - Gunze AHL61 | |
24ced062 | 11 | * - DMC TSC-10/25 |
df561fcd | 12 | * - IRTOUCHSYSTEMS/UNITOP |
1d3e2023 DR |
13 | * |
14 | * Copyright (C) 2004-2006 by Daniel Ritz <daniel.ritz@gmx.ch> | |
15 | * Copyright (C) by Todd E. Johnson (mtouchusb.c) | |
16 | * | |
17 | * This program is free software; you can redistribute it and/or | |
18 | * modify it under the terms of the GNU General Public License as | |
19 | * published by the Free Software Foundation; either version 2 of the | |
20 | * License, or (at your option) any later version. | |
21 | * | |
22 | * This program is distributed in the hope that it will be useful, but | |
23 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
25 | * General Public License for more details. | |
26 | * | |
27 | * You should have received a copy of the GNU General Public License | |
28 | * along with this program; if not, write to the Free Software | |
29 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
30 | * | |
31 | * Driver is based on touchkitusb.c | |
32 | * - ITM parts are from itmtouch.c | |
33 | * - 3M parts are from mtouchusb.c | |
34 | * - PanJit parts are from an unmerged driver by Lanslott Gish | |
24ced062 HS |
35 | * - DMC TSC 10/25 are from Holger Schurig, with ideas from an unmerged |
36 | * driver from Marius Vollmer | |
1d3e2023 DR |
37 | * |
38 | *****************************************************************************/ | |
39 | ||
40 | //#define DEBUG | |
41 | ||
1d3e2023 DR |
42 | #include <linux/kernel.h> |
43 | #include <linux/slab.h> | |
44 | #include <linux/input.h> | |
45 | #include <linux/module.h> | |
46 | #include <linux/init.h> | |
47 | #include <linux/usb.h> | |
ae0dadcf | 48 | #include <linux/usb/input.h> |
1d3e2023 DR |
49 | |
50 | ||
24ced062 | 51 | #define DRIVER_VERSION "v0.5" |
1d3e2023 DR |
52 | #define DRIVER_AUTHOR "Daniel Ritz <daniel.ritz@gmx.ch>" |
53 | #define DRIVER_DESC "USB Touchscreen Driver" | |
54 | ||
55 | static int swap_xy; | |
56 | module_param(swap_xy, bool, 0644); | |
57 | MODULE_PARM_DESC(swap_xy, "If set X and Y axes are swapped."); | |
58 | ||
59 | /* device specifc data/functions */ | |
60 | struct usbtouch_usb; | |
61 | struct usbtouch_device_info { | |
62 | int min_xc, max_xc; | |
63 | int min_yc, max_yc; | |
64 | int min_press, max_press; | |
65 | int rept_size; | |
66 | int flags; | |
67 | ||
7d12e780 | 68 | void (*process_pkt) (struct usbtouch_usb *usbtouch, unsigned char *pkt, int len); |
5d892665 | 69 | int (*get_pkt_len) (unsigned char *pkt, int len); |
c9d8c2b3 | 70 | int (*read_data) (struct usbtouch_usb *usbtouch, unsigned char *pkt); |
1d3e2023 DR |
71 | int (*init) (struct usbtouch_usb *usbtouch); |
72 | }; | |
73 | ||
74 | #define USBTOUCH_FLG_BUFFER 0x01 | |
75 | ||
76 | ||
77 | /* a usbtouch device */ | |
78 | struct usbtouch_usb { | |
79 | unsigned char *data; | |
80 | dma_addr_t data_dma; | |
81 | unsigned char *buffer; | |
82 | int buf_len; | |
83 | struct urb *irq; | |
84 | struct usb_device *udev; | |
85 | struct input_dev *input; | |
86 | struct usbtouch_device_info *type; | |
87 | char name[128]; | |
88 | char phys[64]; | |
c9d8c2b3 DR |
89 | |
90 | int x, y; | |
91 | int touch, press; | |
1d3e2023 DR |
92 | }; |
93 | ||
5d892665 | 94 | |
c6f8d706 | 95 | #if defined(CONFIG_TOUCHSCREEN_USB_EGALAX) || defined(CONFIG_TOUCHSCREEN_USB_ETURBO) |
5d892665 DR |
96 | #define MULTI_PACKET |
97 | #endif | |
98 | ||
99 | #ifdef MULTI_PACKET | |
100 | static void usbtouch_process_multi(struct usbtouch_usb *usbtouch, | |
5d892665 DR |
101 | unsigned char *pkt, int len); |
102 | #endif | |
1d3e2023 DR |
103 | |
104 | /* device types */ | |
105 | enum { | |
106 | DEVTPYE_DUMMY = -1, | |
107 | DEVTYPE_EGALAX, | |
108 | DEVTYPE_PANJIT, | |
109 | DEVTYPE_3M, | |
110 | DEVTYPE_ITM, | |
5d892665 DR |
111 | DEVTYPE_ETURBO, |
112 | DEVTYPE_GUNZE, | |
24ced062 | 113 | DEVTYPE_DMC_TSC10, |
df561fcd | 114 | DEVTYPE_IRTOUCH, |
1d3e2023 DR |
115 | }; |
116 | ||
117 | static struct usb_device_id usbtouch_devices[] = { | |
c6f8d706 | 118 | #ifdef CONFIG_TOUCHSCREEN_USB_EGALAX |
1d3e2023 | 119 | {USB_DEVICE(0x3823, 0x0001), .driver_info = DEVTYPE_EGALAX}, |
5d892665 | 120 | {USB_DEVICE(0x3823, 0x0002), .driver_info = DEVTYPE_EGALAX}, |
1d3e2023 DR |
121 | {USB_DEVICE(0x0123, 0x0001), .driver_info = DEVTYPE_EGALAX}, |
122 | {USB_DEVICE(0x0eef, 0x0001), .driver_info = DEVTYPE_EGALAX}, | |
123 | {USB_DEVICE(0x0eef, 0x0002), .driver_info = DEVTYPE_EGALAX}, | |
5d892665 DR |
124 | {USB_DEVICE(0x1234, 0x0001), .driver_info = DEVTYPE_EGALAX}, |
125 | {USB_DEVICE(0x1234, 0x0002), .driver_info = DEVTYPE_EGALAX}, | |
1d3e2023 DR |
126 | #endif |
127 | ||
c6f8d706 | 128 | #ifdef CONFIG_TOUCHSCREEN_USB_PANJIT |
1d3e2023 DR |
129 | {USB_DEVICE(0x134c, 0x0001), .driver_info = DEVTYPE_PANJIT}, |
130 | {USB_DEVICE(0x134c, 0x0002), .driver_info = DEVTYPE_PANJIT}, | |
131 | {USB_DEVICE(0x134c, 0x0003), .driver_info = DEVTYPE_PANJIT}, | |
132 | {USB_DEVICE(0x134c, 0x0004), .driver_info = DEVTYPE_PANJIT}, | |
133 | #endif | |
134 | ||
c6f8d706 | 135 | #ifdef CONFIG_TOUCHSCREEN_USB_3M |
1d3e2023 DR |
136 | {USB_DEVICE(0x0596, 0x0001), .driver_info = DEVTYPE_3M}, |
137 | #endif | |
138 | ||
c6f8d706 | 139 | #ifdef CONFIG_TOUCHSCREEN_USB_ITM |
1d3e2023 DR |
140 | {USB_DEVICE(0x0403, 0xf9e9), .driver_info = DEVTYPE_ITM}, |
141 | #endif | |
142 | ||
c6f8d706 | 143 | #ifdef CONFIG_TOUCHSCREEN_USB_ETURBO |
5d892665 DR |
144 | {USB_DEVICE(0x1234, 0x5678), .driver_info = DEVTYPE_ETURBO}, |
145 | #endif | |
146 | ||
c6f8d706 | 147 | #ifdef CONFIG_TOUCHSCREEN_USB_GUNZE |
5d892665 DR |
148 | {USB_DEVICE(0x0637, 0x0001), .driver_info = DEVTYPE_GUNZE}, |
149 | #endif | |
150 | ||
c6f8d706 | 151 | #ifdef CONFIG_TOUCHSCREEN_USB_DMC_TSC10 |
24ced062 HS |
152 | {USB_DEVICE(0x0afa, 0x03e8), .driver_info = DEVTYPE_DMC_TSC10}, |
153 | #endif | |
154 | ||
df561fcd OZ |
155 | #ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH |
156 | {USB_DEVICE(0x595a, 0x0001), .driver_info = DEVTYPE_IRTOUCH}, | |
157 | {USB_DEVICE(0x6615, 0x0001), .driver_info = DEVTYPE_IRTOUCH}, | |
158 | #endif | |
159 | ||
1d3e2023 DR |
160 | {} |
161 | }; | |
162 | ||
163 | ||
164 | /***************************************************************************** | |
165 | * eGalax part | |
166 | */ | |
167 | ||
c6f8d706 | 168 | #ifdef CONFIG_TOUCHSCREEN_USB_EGALAX |
1d3e2023 DR |
169 | |
170 | #define EGALAX_PKT_TYPE_MASK 0xFE | |
171 | #define EGALAX_PKT_TYPE_REPT 0x80 | |
172 | #define EGALAX_PKT_TYPE_DIAG 0x0A | |
173 | ||
c9d8c2b3 | 174 | static int egalax_read_data(struct usbtouch_usb *dev, unsigned char *pkt) |
1d3e2023 DR |
175 | { |
176 | if ((pkt[0] & EGALAX_PKT_TYPE_MASK) != EGALAX_PKT_TYPE_REPT) | |
177 | return 0; | |
178 | ||
c9d8c2b3 DR |
179 | dev->x = ((pkt[3] & 0x0F) << 7) | (pkt[4] & 0x7F); |
180 | dev->y = ((pkt[1] & 0x0F) << 7) | (pkt[2] & 0x7F); | |
181 | dev->touch = pkt[0] & 0x01; | |
1d3e2023 DR |
182 | |
183 | return 1; | |
1d3e2023 DR |
184 | } |
185 | ||
5d892665 | 186 | static int egalax_get_pkt_len(unsigned char *buf, int len) |
1d3e2023 DR |
187 | { |
188 | switch (buf[0] & EGALAX_PKT_TYPE_MASK) { | |
189 | case EGALAX_PKT_TYPE_REPT: | |
190 | return 5; | |
191 | ||
192 | case EGALAX_PKT_TYPE_DIAG: | |
5d892665 DR |
193 | if (len < 2) |
194 | return -1; | |
195 | ||
1d3e2023 DR |
196 | return buf[1] + 2; |
197 | } | |
198 | ||
199 | return 0; | |
200 | } | |
1d3e2023 DR |
201 | #endif |
202 | ||
203 | ||
204 | /***************************************************************************** | |
205 | * PanJit Part | |
206 | */ | |
c6f8d706 | 207 | #ifdef CONFIG_TOUCHSCREEN_USB_PANJIT |
c9d8c2b3 | 208 | static int panjit_read_data(struct usbtouch_usb *dev, unsigned char *pkt) |
1d3e2023 | 209 | { |
c9d8c2b3 DR |
210 | dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1]; |
211 | dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3]; | |
212 | dev->touch = pkt[0] & 0x01; | |
1d3e2023 DR |
213 | |
214 | return 1; | |
215 | } | |
216 | #endif | |
217 | ||
218 | ||
219 | /***************************************************************************** | |
220 | * 3M/Microtouch Part | |
221 | */ | |
c6f8d706 | 222 | #ifdef CONFIG_TOUCHSCREEN_USB_3M |
1d3e2023 DR |
223 | |
224 | #define MTOUCHUSB_ASYNC_REPORT 1 | |
225 | #define MTOUCHUSB_RESET 7 | |
226 | #define MTOUCHUSB_REQ_CTRLLR_ID 10 | |
227 | ||
c9d8c2b3 | 228 | static int mtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt) |
1d3e2023 | 229 | { |
c9d8c2b3 DR |
230 | dev->x = (pkt[8] << 8) | pkt[7]; |
231 | dev->y = (pkt[10] << 8) | pkt[9]; | |
232 | dev->touch = (pkt[2] & 0x40) ? 1 : 0; | |
1d3e2023 DR |
233 | |
234 | return 1; | |
235 | } | |
236 | ||
237 | static int mtouch_init(struct usbtouch_usb *usbtouch) | |
238 | { | |
5d892665 | 239 | int ret, i; |
1d3e2023 DR |
240 | |
241 | ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0), | |
242 | MTOUCHUSB_RESET, | |
243 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
244 | 1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); | |
245 | dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d", | |
246 | __FUNCTION__, ret); | |
247 | if (ret < 0) | |
248 | return ret; | |
5d892665 DR |
249 | msleep(150); |
250 | ||
251 | for (i = 0; i < 3; i++) { | |
252 | ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0), | |
253 | MTOUCHUSB_ASYNC_REPORT, | |
254 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
255 | 1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT); | |
256 | dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d", | |
257 | __FUNCTION__, ret); | |
258 | if (ret >= 0) | |
259 | break; | |
260 | if (ret != -EPIPE) | |
261 | return ret; | |
262 | } | |
1d3e2023 DR |
263 | |
264 | return 0; | |
265 | } | |
266 | #endif | |
267 | ||
268 | ||
269 | /***************************************************************************** | |
270 | * ITM Part | |
271 | */ | |
c6f8d706 | 272 | #ifdef CONFIG_TOUCHSCREEN_USB_ITM |
c9d8c2b3 | 273 | static int itm_read_data(struct usbtouch_usb *dev, unsigned char *pkt) |
1d3e2023 | 274 | { |
c9d8c2b3 DR |
275 | int touch; |
276 | /* | |
277 | * ITM devices report invalid x/y data if not touched. | |
278 | * if the screen was touched before but is not touched any more | |
279 | * report touch as 0 with the last valid x/y data once. then stop | |
280 | * reporting data until touched again. | |
281 | */ | |
282 | dev->press = ((pkt[2] & 0x01) << 7) | (pkt[5] & 0x7F); | |
283 | ||
284 | touch = ~pkt[7] & 0x20; | |
285 | if (!touch) { | |
286 | if (dev->touch) { | |
287 | dev->touch = 0; | |
288 | return 1; | |
289 | } | |
290 | ||
291 | return 0; | |
292 | } | |
293 | ||
294 | dev->x = ((pkt[0] & 0x1F) << 7) | (pkt[3] & 0x7F); | |
295 | dev->y = ((pkt[1] & 0x1F) << 7) | (pkt[4] & 0x7F); | |
296 | dev->touch = touch; | |
1d3e2023 | 297 | |
c9d8c2b3 | 298 | return 1; |
1d3e2023 DR |
299 | } |
300 | #endif | |
301 | ||
302 | ||
5d892665 DR |
303 | /***************************************************************************** |
304 | * eTurboTouch part | |
305 | */ | |
c6f8d706 | 306 | #ifdef CONFIG_TOUCHSCREEN_USB_ETURBO |
c9d8c2b3 | 307 | static int eturbo_read_data(struct usbtouch_usb *dev, unsigned char *pkt) |
5d892665 DR |
308 | { |
309 | unsigned int shift; | |
310 | ||
311 | /* packets should start with sync */ | |
312 | if (!(pkt[0] & 0x80)) | |
313 | return 0; | |
314 | ||
315 | shift = (6 - (pkt[0] & 0x03)); | |
c9d8c2b3 DR |
316 | dev->x = ((pkt[3] << 7) | pkt[4]) >> shift; |
317 | dev->y = ((pkt[1] << 7) | pkt[2]) >> shift; | |
318 | dev->touch = (pkt[0] & 0x10) ? 1 : 0; | |
5d892665 DR |
319 | |
320 | return 1; | |
321 | } | |
322 | ||
323 | static int eturbo_get_pkt_len(unsigned char *buf, int len) | |
324 | { | |
325 | if (buf[0] & 0x80) | |
326 | return 5; | |
327 | if (buf[0] == 0x01) | |
328 | return 3; | |
329 | return 0; | |
330 | } | |
331 | #endif | |
332 | ||
333 | ||
334 | /***************************************************************************** | |
335 | * Gunze part | |
336 | */ | |
c6f8d706 | 337 | #ifdef CONFIG_TOUCHSCREEN_USB_GUNZE |
c9d8c2b3 | 338 | static int gunze_read_data(struct usbtouch_usb *dev, unsigned char *pkt) |
5d892665 DR |
339 | { |
340 | if (!(pkt[0] & 0x80) || ((pkt[1] | pkt[2] | pkt[3]) & 0x80)) | |
341 | return 0; | |
342 | ||
c9d8c2b3 DR |
343 | dev->x = ((pkt[0] & 0x1F) << 7) | (pkt[2] & 0x7F); |
344 | dev->y = ((pkt[1] & 0x1F) << 7) | (pkt[3] & 0x7F); | |
345 | dev->touch = pkt[0] & 0x20; | |
5d892665 DR |
346 | |
347 | return 1; | |
348 | } | |
349 | #endif | |
350 | ||
24ced062 HS |
351 | /***************************************************************************** |
352 | * DMC TSC-10/25 Part | |
353 | * | |
354 | * Documentation about the controller and it's protocol can be found at | |
355 | * http://www.dmccoltd.com/files/controler/tsc10usb_pi_e.pdf | |
356 | * http://www.dmccoltd.com/files/controler/tsc25_usb_e.pdf | |
357 | */ | |
c6f8d706 | 358 | #ifdef CONFIG_TOUCHSCREEN_USB_DMC_TSC10 |
24ced062 HS |
359 | |
360 | /* supported data rates. currently using 130 */ | |
361 | #define TSC10_RATE_POINT 0x50 | |
362 | #define TSC10_RATE_30 0x40 | |
363 | #define TSC10_RATE_50 0x41 | |
364 | #define TSC10_RATE_80 0x42 | |
365 | #define TSC10_RATE_100 0x43 | |
366 | #define TSC10_RATE_130 0x44 | |
367 | #define TSC10_RATE_150 0x45 | |
368 | ||
369 | /* commands */ | |
370 | #define TSC10_CMD_RESET 0x55 | |
371 | #define TSC10_CMD_RATE 0x05 | |
372 | #define TSC10_CMD_DATA1 0x01 | |
373 | ||
374 | static int dmc_tsc10_init(struct usbtouch_usb *usbtouch) | |
375 | { | |
376 | struct usb_device *dev = usbtouch->udev; | |
377 | int ret; | |
378 | unsigned char buf[2]; | |
379 | ||
380 | /* reset */ | |
381 | buf[0] = buf[1] = 0xFF; | |
382 | ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0), | |
383 | TSC10_CMD_RESET, | |
384 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
385 | 0, 0, buf, 2, USB_CTRL_SET_TIMEOUT); | |
386 | if (ret < 0) | |
387 | return ret; | |
388 | if (buf[0] != 0x06 || buf[1] != 0x00) | |
389 | return -ENODEV; | |
390 | ||
391 | /* set coordinate output rate */ | |
392 | buf[0] = buf[1] = 0xFF; | |
393 | ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0), | |
394 | TSC10_CMD_RATE, | |
395 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
396 | TSC10_RATE_150, 0, buf, 2, USB_CTRL_SET_TIMEOUT); | |
397 | if (ret < 0) | |
398 | return ret; | |
399 | if (buf[0] != 0x06 || buf[1] != 0x00) | |
400 | return -ENODEV; | |
401 | ||
402 | /* start sending data */ | |
403 | ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0), | |
404 | TSC10_CMD_DATA1, | |
405 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
406 | 0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); | |
407 | if (ret < 0) | |
408 | return ret; | |
409 | ||
410 | return 0; | |
411 | } | |
412 | ||
413 | ||
c9d8c2b3 | 414 | static int dmc_tsc10_read_data(struct usbtouch_usb *dev, unsigned char *pkt) |
24ced062 | 415 | { |
c9d8c2b3 DR |
416 | dev->x = ((pkt[2] & 0x03) << 8) | pkt[1]; |
417 | dev->y = ((pkt[4] & 0x03) << 8) | pkt[3]; | |
418 | dev->touch = pkt[0] & 0x01; | |
24ced062 HS |
419 | |
420 | return 1; | |
421 | } | |
422 | #endif | |
423 | ||
424 | ||
df561fcd OZ |
425 | /***************************************************************************** |
426 | * IRTOUCH Part | |
427 | */ | |
428 | #ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH | |
429 | static int irtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt) | |
430 | { | |
431 | dev->x = (pkt[3] << 8) | pkt[2]; | |
432 | dev->y = (pkt[5] << 8) | pkt[4]; | |
433 | dev->touch = (pkt[1] & 0x03) ? 1 : 0; | |
434 | ||
435 | return 1; | |
436 | } | |
437 | #endif | |
438 | ||
439 | ||
1d3e2023 DR |
440 | /***************************************************************************** |
441 | * the different device descriptors | |
442 | */ | |
443 | static struct usbtouch_device_info usbtouch_dev_info[] = { | |
c6f8d706 | 444 | #ifdef CONFIG_TOUCHSCREEN_USB_EGALAX |
1d3e2023 DR |
445 | [DEVTYPE_EGALAX] = { |
446 | .min_xc = 0x0, | |
447 | .max_xc = 0x07ff, | |
448 | .min_yc = 0x0, | |
449 | .max_yc = 0x07ff, | |
450 | .rept_size = 16, | |
451 | .flags = USBTOUCH_FLG_BUFFER, | |
5d892665 DR |
452 | .process_pkt = usbtouch_process_multi, |
453 | .get_pkt_len = egalax_get_pkt_len, | |
1d3e2023 DR |
454 | .read_data = egalax_read_data, |
455 | }, | |
456 | #endif | |
457 | ||
c6f8d706 | 458 | #ifdef CONFIG_TOUCHSCREEN_USB_PANJIT |
1d3e2023 DR |
459 | [DEVTYPE_PANJIT] = { |
460 | .min_xc = 0x0, | |
461 | .max_xc = 0x0fff, | |
462 | .min_yc = 0x0, | |
463 | .max_yc = 0x0fff, | |
464 | .rept_size = 8, | |
465 | .read_data = panjit_read_data, | |
466 | }, | |
467 | #endif | |
468 | ||
c6f8d706 | 469 | #ifdef CONFIG_TOUCHSCREEN_USB_3M |
1d3e2023 DR |
470 | [DEVTYPE_3M] = { |
471 | .min_xc = 0x0, | |
472 | .max_xc = 0x4000, | |
473 | .min_yc = 0x0, | |
474 | .max_yc = 0x4000, | |
475 | .rept_size = 11, | |
476 | .read_data = mtouch_read_data, | |
477 | .init = mtouch_init, | |
478 | }, | |
479 | #endif | |
480 | ||
c6f8d706 | 481 | #ifdef CONFIG_TOUCHSCREEN_USB_ITM |
1d3e2023 DR |
482 | [DEVTYPE_ITM] = { |
483 | .min_xc = 0x0, | |
484 | .max_xc = 0x0fff, | |
485 | .min_yc = 0x0, | |
486 | .max_yc = 0x0fff, | |
487 | .max_press = 0xff, | |
488 | .rept_size = 8, | |
489 | .read_data = itm_read_data, | |
490 | }, | |
491 | #endif | |
5d892665 | 492 | |
c6f8d706 | 493 | #ifdef CONFIG_TOUCHSCREEN_USB_ETURBO |
5d892665 DR |
494 | [DEVTYPE_ETURBO] = { |
495 | .min_xc = 0x0, | |
496 | .max_xc = 0x07ff, | |
497 | .min_yc = 0x0, | |
498 | .max_yc = 0x07ff, | |
499 | .rept_size = 8, | |
500 | .flags = USBTOUCH_FLG_BUFFER, | |
501 | .process_pkt = usbtouch_process_multi, | |
502 | .get_pkt_len = eturbo_get_pkt_len, | |
503 | .read_data = eturbo_read_data, | |
504 | }, | |
505 | #endif | |
506 | ||
c6f8d706 | 507 | #ifdef CONFIG_TOUCHSCREEN_USB_GUNZE |
5d892665 DR |
508 | [DEVTYPE_GUNZE] = { |
509 | .min_xc = 0x0, | |
510 | .max_xc = 0x0fff, | |
511 | .min_yc = 0x0, | |
512 | .max_yc = 0x0fff, | |
513 | .rept_size = 4, | |
514 | .read_data = gunze_read_data, | |
515 | }, | |
516 | #endif | |
24ced062 | 517 | |
c6f8d706 | 518 | #ifdef CONFIG_TOUCHSCREEN_USB_DMC_TSC10 |
24ced062 HS |
519 | [DEVTYPE_DMC_TSC10] = { |
520 | .min_xc = 0x0, | |
521 | .max_xc = 0x03ff, | |
522 | .min_yc = 0x0, | |
523 | .max_yc = 0x03ff, | |
524 | .rept_size = 5, | |
525 | .init = dmc_tsc10_init, | |
526 | .read_data = dmc_tsc10_read_data, | |
527 | }, | |
528 | #endif | |
df561fcd OZ |
529 | |
530 | #ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH | |
531 | [DEVTYPE_IRTOUCH] = { | |
532 | .min_xc = 0x0, | |
533 | .max_xc = 0x0fff, | |
534 | .min_yc = 0x0, | |
535 | .max_yc = 0x0fff, | |
536 | .rept_size = 8, | |
537 | .read_data = irtouch_read_data, | |
538 | }, | |
539 | #endif | |
1d3e2023 DR |
540 | }; |
541 | ||
542 | ||
543 | /***************************************************************************** | |
544 | * Generic Part | |
545 | */ | |
546 | static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch, | |
7d12e780 | 547 | unsigned char *pkt, int len) |
1d3e2023 | 548 | { |
1d3e2023 DR |
549 | struct usbtouch_device_info *type = usbtouch->type; |
550 | ||
c9d8c2b3 | 551 | if (!type->read_data(usbtouch, pkt)) |
1d3e2023 DR |
552 | return; |
553 | ||
c9d8c2b3 | 554 | input_report_key(usbtouch->input, BTN_TOUCH, usbtouch->touch); |
1d3e2023 DR |
555 | |
556 | if (swap_xy) { | |
c9d8c2b3 DR |
557 | input_report_abs(usbtouch->input, ABS_X, usbtouch->y); |
558 | input_report_abs(usbtouch->input, ABS_Y, usbtouch->x); | |
1d3e2023 | 559 | } else { |
c9d8c2b3 DR |
560 | input_report_abs(usbtouch->input, ABS_X, usbtouch->x); |
561 | input_report_abs(usbtouch->input, ABS_Y, usbtouch->y); | |
1d3e2023 DR |
562 | } |
563 | if (type->max_press) | |
c9d8c2b3 | 564 | input_report_abs(usbtouch->input, ABS_PRESSURE, usbtouch->press); |
1d3e2023 DR |
565 | input_sync(usbtouch->input); |
566 | } | |
567 | ||
568 | ||
5d892665 DR |
569 | #ifdef MULTI_PACKET |
570 | static void usbtouch_process_multi(struct usbtouch_usb *usbtouch, | |
5d892665 DR |
571 | unsigned char *pkt, int len) |
572 | { | |
573 | unsigned char *buffer; | |
574 | int pkt_len, pos, buf_len, tmp; | |
575 | ||
576 | /* process buffer */ | |
577 | if (unlikely(usbtouch->buf_len)) { | |
578 | /* try to get size */ | |
579 | pkt_len = usbtouch->type->get_pkt_len( | |
580 | usbtouch->buffer, usbtouch->buf_len); | |
581 | ||
582 | /* drop? */ | |
583 | if (unlikely(!pkt_len)) | |
584 | goto out_flush_buf; | |
585 | ||
586 | /* need to append -pkt_len bytes before able to get size */ | |
587 | if (unlikely(pkt_len < 0)) { | |
588 | int append = -pkt_len; | |
589 | if (unlikely(append > len)) | |
590 | append = len; | |
591 | if (usbtouch->buf_len + append >= usbtouch->type->rept_size) | |
592 | goto out_flush_buf; | |
593 | memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, append); | |
594 | usbtouch->buf_len += append; | |
595 | ||
596 | pkt_len = usbtouch->type->get_pkt_len( | |
597 | usbtouch->buffer, usbtouch->buf_len); | |
598 | if (pkt_len < 0) | |
599 | return; | |
600 | } | |
601 | ||
602 | /* append */ | |
603 | tmp = pkt_len - usbtouch->buf_len; | |
604 | if (usbtouch->buf_len + tmp >= usbtouch->type->rept_size) | |
605 | goto out_flush_buf; | |
606 | memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, tmp); | |
7d12e780 | 607 | usbtouch_process_pkt(usbtouch, usbtouch->buffer, pkt_len); |
5d892665 DR |
608 | |
609 | buffer = pkt + tmp; | |
610 | buf_len = len - tmp; | |
611 | } else { | |
612 | buffer = pkt; | |
613 | buf_len = len; | |
614 | } | |
615 | ||
616 | /* loop over the received packet, process */ | |
617 | pos = 0; | |
618 | while (pos < buf_len) { | |
619 | /* get packet len */ | |
620 | pkt_len = usbtouch->type->get_pkt_len(buffer + pos, len); | |
621 | ||
622 | /* unknown packet: drop everything */ | |
623 | if (unlikely(!pkt_len)) | |
624 | goto out_flush_buf; | |
625 | ||
626 | /* full packet: process */ | |
627 | if (likely((pkt_len > 0) && (pkt_len <= buf_len - pos))) { | |
7d12e780 | 628 | usbtouch_process_pkt(usbtouch, buffer + pos, pkt_len); |
5d892665 DR |
629 | } else { |
630 | /* incomplete packet: save in buffer */ | |
631 | memcpy(usbtouch->buffer, buffer + pos, buf_len - pos); | |
632 | usbtouch->buf_len = buf_len - pos; | |
633 | return; | |
634 | } | |
635 | pos += pkt_len; | |
636 | } | |
637 | ||
638 | out_flush_buf: | |
639 | usbtouch->buf_len = 0; | |
640 | return; | |
641 | } | |
642 | #endif | |
643 | ||
644 | ||
7d12e780 | 645 | static void usbtouch_irq(struct urb *urb) |
1d3e2023 DR |
646 | { |
647 | struct usbtouch_usb *usbtouch = urb->context; | |
648 | int retval; | |
649 | ||
650 | switch (urb->status) { | |
651 | case 0: | |
652 | /* success */ | |
653 | break; | |
38e2bfc9 | 654 | case -ETIME: |
1d3e2023 DR |
655 | /* this urb is timing out */ |
656 | dbg("%s - urb timed out - was the device unplugged?", | |
657 | __FUNCTION__); | |
658 | return; | |
659 | case -ECONNRESET: | |
660 | case -ENOENT: | |
661 | case -ESHUTDOWN: | |
662 | /* this urb is terminated, clean up */ | |
663 | dbg("%s - urb shutting down with status: %d", | |
664 | __FUNCTION__, urb->status); | |
665 | return; | |
666 | default: | |
667 | dbg("%s - nonzero urb status received: %d", | |
668 | __FUNCTION__, urb->status); | |
669 | goto exit; | |
670 | } | |
671 | ||
7d12e780 | 672 | usbtouch->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length); |
1d3e2023 DR |
673 | |
674 | exit: | |
675 | retval = usb_submit_urb(urb, GFP_ATOMIC); | |
676 | if (retval) | |
677 | err("%s - usb_submit_urb failed with result: %d", | |
678 | __FUNCTION__, retval); | |
679 | } | |
680 | ||
681 | static int usbtouch_open(struct input_dev *input) | |
682 | { | |
7791bdae | 683 | struct usbtouch_usb *usbtouch = input_get_drvdata(input); |
1d3e2023 DR |
684 | |
685 | usbtouch->irq->dev = usbtouch->udev; | |
686 | ||
687 | if (usb_submit_urb(usbtouch->irq, GFP_KERNEL)) | |
688 | return -EIO; | |
689 | ||
690 | return 0; | |
691 | } | |
692 | ||
693 | static void usbtouch_close(struct input_dev *input) | |
694 | { | |
7791bdae | 695 | struct usbtouch_usb *usbtouch = input_get_drvdata(input); |
1d3e2023 DR |
696 | |
697 | usb_kill_urb(usbtouch->irq); | |
698 | } | |
699 | ||
700 | ||
701 | static void usbtouch_free_buffers(struct usb_device *udev, | |
702 | struct usbtouch_usb *usbtouch) | |
703 | { | |
e37a97d4 DT |
704 | usb_buffer_free(udev, usbtouch->type->rept_size, |
705 | usbtouch->data, usbtouch->data_dma); | |
1d3e2023 DR |
706 | kfree(usbtouch->buffer); |
707 | } | |
708 | ||
709 | ||
710 | static int usbtouch_probe(struct usb_interface *intf, | |
711 | const struct usb_device_id *id) | |
712 | { | |
713 | struct usbtouch_usb *usbtouch; | |
714 | struct input_dev *input_dev; | |
715 | struct usb_host_interface *interface; | |
716 | struct usb_endpoint_descriptor *endpoint; | |
717 | struct usb_device *udev = interface_to_usbdev(intf); | |
718 | struct usbtouch_device_info *type; | |
5d892665 | 719 | int err = -ENOMEM; |
1d3e2023 DR |
720 | |
721 | interface = intf->cur_altsetting; | |
722 | endpoint = &interface->endpoint[0].desc; | |
723 | ||
724 | usbtouch = kzalloc(sizeof(struct usbtouch_usb), GFP_KERNEL); | |
725 | input_dev = input_allocate_device(); | |
726 | if (!usbtouch || !input_dev) | |
727 | goto out_free; | |
728 | ||
729 | type = &usbtouch_dev_info[id->driver_info]; | |
730 | usbtouch->type = type; | |
731 | if (!type->process_pkt) | |
732 | type->process_pkt = usbtouch_process_pkt; | |
733 | ||
734 | usbtouch->data = usb_buffer_alloc(udev, type->rept_size, | |
e94b1766 | 735 | GFP_KERNEL, &usbtouch->data_dma); |
1d3e2023 DR |
736 | if (!usbtouch->data) |
737 | goto out_free; | |
738 | ||
739 | if (type->flags & USBTOUCH_FLG_BUFFER) { | |
740 | usbtouch->buffer = kmalloc(type->rept_size, GFP_KERNEL); | |
741 | if (!usbtouch->buffer) | |
742 | goto out_free_buffers; | |
743 | } | |
744 | ||
745 | usbtouch->irq = usb_alloc_urb(0, GFP_KERNEL); | |
746 | if (!usbtouch->irq) { | |
747 | dbg("%s - usb_alloc_urb failed: usbtouch->irq", __FUNCTION__); | |
748 | goto out_free_buffers; | |
749 | } | |
750 | ||
751 | usbtouch->udev = udev; | |
752 | usbtouch->input = input_dev; | |
753 | ||
754 | if (udev->manufacturer) | |
755 | strlcpy(usbtouch->name, udev->manufacturer, sizeof(usbtouch->name)); | |
756 | ||
757 | if (udev->product) { | |
758 | if (udev->manufacturer) | |
759 | strlcat(usbtouch->name, " ", sizeof(usbtouch->name)); | |
760 | strlcat(usbtouch->name, udev->product, sizeof(usbtouch->name)); | |
761 | } | |
762 | ||
763 | if (!strlen(usbtouch->name)) | |
764 | snprintf(usbtouch->name, sizeof(usbtouch->name), | |
765 | "USB Touchscreen %04x:%04x", | |
766 | le16_to_cpu(udev->descriptor.idVendor), | |
767 | le16_to_cpu(udev->descriptor.idProduct)); | |
768 | ||
769 | usb_make_path(udev, usbtouch->phys, sizeof(usbtouch->phys)); | |
770 | strlcpy(usbtouch->phys, "/input0", sizeof(usbtouch->phys)); | |
771 | ||
772 | input_dev->name = usbtouch->name; | |
773 | input_dev->phys = usbtouch->phys; | |
774 | usb_to_input_id(udev, &input_dev->id); | |
c0f82d57 | 775 | input_dev->dev.parent = &intf->dev; |
7791bdae DT |
776 | |
777 | input_set_drvdata(input_dev, usbtouch); | |
778 | ||
1d3e2023 DR |
779 | input_dev->open = usbtouch_open; |
780 | input_dev->close = usbtouch_close; | |
781 | ||
782 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | |
783 | input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); | |
784 | input_set_abs_params(input_dev, ABS_X, type->min_xc, type->max_xc, 0, 0); | |
785 | input_set_abs_params(input_dev, ABS_Y, type->min_yc, type->max_yc, 0, 0); | |
786 | if (type->max_press) | |
787 | input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press, | |
788 | type->max_press, 0, 0); | |
789 | ||
790 | usb_fill_int_urb(usbtouch->irq, usbtouch->udev, | |
d8fa59a8 | 791 | usb_rcvintpipe(usbtouch->udev, endpoint->bEndpointAddress), |
1d3e2023 DR |
792 | usbtouch->data, type->rept_size, |
793 | usbtouch_irq, usbtouch, endpoint->bInterval); | |
794 | ||
5d892665 | 795 | usbtouch->irq->dev = usbtouch->udev; |
1d3e2023 DR |
796 | usbtouch->irq->transfer_dma = usbtouch->data_dma; |
797 | usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | |
798 | ||
799 | /* device specific init */ | |
800 | if (type->init) { | |
801 | err = type->init(usbtouch); | |
802 | if (err) { | |
803 | dbg("%s - type->init() failed, err: %d", __FUNCTION__, err); | |
804 | goto out_free_buffers; | |
805 | } | |
806 | } | |
807 | ||
808 | err = input_register_device(usbtouch->input); | |
809 | if (err) { | |
810 | dbg("%s - input_register_device failed, err: %d", __FUNCTION__, err); | |
811 | goto out_free_buffers; | |
812 | } | |
813 | ||
814 | usb_set_intfdata(intf, usbtouch); | |
815 | ||
816 | return 0; | |
817 | ||
818 | out_free_buffers: | |
819 | usbtouch_free_buffers(udev, usbtouch); | |
820 | out_free: | |
821 | input_free_device(input_dev); | |
822 | kfree(usbtouch); | |
5d892665 | 823 | return err; |
1d3e2023 DR |
824 | } |
825 | ||
826 | static void usbtouch_disconnect(struct usb_interface *intf) | |
827 | { | |
828 | struct usbtouch_usb *usbtouch = usb_get_intfdata(intf); | |
829 | ||
830 | dbg("%s - called", __FUNCTION__); | |
831 | ||
832 | if (!usbtouch) | |
833 | return; | |
834 | ||
835 | dbg("%s - usbtouch is initialized, cleaning up", __FUNCTION__); | |
836 | usb_set_intfdata(intf, NULL); | |
837 | usb_kill_urb(usbtouch->irq); | |
838 | input_unregister_device(usbtouch->input); | |
839 | usb_free_urb(usbtouch->irq); | |
840 | usbtouch_free_buffers(interface_to_usbdev(intf), usbtouch); | |
841 | kfree(usbtouch); | |
842 | } | |
843 | ||
844 | MODULE_DEVICE_TABLE(usb, usbtouch_devices); | |
845 | ||
846 | static struct usb_driver usbtouch_driver = { | |
847 | .name = "usbtouchscreen", | |
848 | .probe = usbtouch_probe, | |
849 | .disconnect = usbtouch_disconnect, | |
850 | .id_table = usbtouch_devices, | |
851 | }; | |
852 | ||
853 | static int __init usbtouch_init(void) | |
854 | { | |
855 | return usb_register(&usbtouch_driver); | |
856 | } | |
857 | ||
858 | static void __exit usbtouch_cleanup(void) | |
859 | { | |
860 | usb_deregister(&usbtouch_driver); | |
861 | } | |
862 | ||
863 | module_init(usbtouch_init); | |
864 | module_exit(usbtouch_cleanup); | |
865 | ||
866 | MODULE_AUTHOR(DRIVER_AUTHOR); | |
867 | MODULE_DESCRIPTION(DRIVER_DESC); | |
868 | MODULE_LICENSE("GPL"); | |
869 | ||
870 | MODULE_ALIAS("touchkitusb"); | |
871 | MODULE_ALIAS("itmtouch"); | |
872 | MODULE_ALIAS("mtouchusb"); |