xref: /linux/drivers/input/touchscreen/usbtouchscreen.c (revision c9cbf3d3b35f198fab39e98d696312dd0b97a69a)
1d05e84e6SDmitry Torokhov /******************************************************************************
2d05e84e6SDmitry Torokhov  * usbtouchscreen.c
3d05e84e6SDmitry Torokhov  * Driver for USB Touchscreens, supporting those devices:
4d05e84e6SDmitry Torokhov  *  - eGalax Touchkit
5d05e84e6SDmitry Torokhov  *    includes eTurboTouch CT-410/510/700
6d05e84e6SDmitry Torokhov  *  - 3M/Microtouch  EX II series
7d05e84e6SDmitry Torokhov  *  - ITM
8d05e84e6SDmitry Torokhov  *  - PanJit TouchSet
9d05e84e6SDmitry Torokhov  *  - eTurboTouch
10d05e84e6SDmitry Torokhov  *  - Gunze AHL61
11d05e84e6SDmitry Torokhov  *  - DMC TSC-10/25
12df561fcdSOndrej Zary  *  - IRTOUCHSYSTEMS/UNITOP
13a14a8401SOndrej Zary  *  - IdealTEK URTC1000
1462aa366dSDaniel Ritz  *  - General Touch
1514e40206SJerrold Jones  *  - GoTop Super_Q2/GogoPen/PenPower tablets
16d05e84e6SDmitry Torokhov  *
1714e40206SJerrold Jones  * Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch>
18d05e84e6SDmitry Torokhov  * Copyright (C) by Todd E. Johnson (mtouchusb.c)
19d05e84e6SDmitry Torokhov  *
20d05e84e6SDmitry Torokhov  * This program is free software; you can redistribute it and/or
21d05e84e6SDmitry Torokhov  * modify it under the terms of the GNU General Public License as
22d05e84e6SDmitry Torokhov  * published by the Free Software Foundation; either version 2 of the
23d05e84e6SDmitry Torokhov  * License, or (at your option) any later version.
24d05e84e6SDmitry Torokhov  *
25d05e84e6SDmitry Torokhov  * This program is distributed in the hope that it will be useful, but
26d05e84e6SDmitry Torokhov  * WITHOUT ANY WARRANTY; without even the implied warranty of
27d05e84e6SDmitry Torokhov  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
28d05e84e6SDmitry Torokhov  * General Public License for more details.
29d05e84e6SDmitry Torokhov  *
30d05e84e6SDmitry Torokhov  * You should have received a copy of the GNU General Public License
31d05e84e6SDmitry Torokhov  * along with this program; if not, write to the Free Software
32d05e84e6SDmitry Torokhov  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
33d05e84e6SDmitry Torokhov  *
34d05e84e6SDmitry Torokhov  * Driver is based on touchkitusb.c
35d05e84e6SDmitry Torokhov  * - ITM parts are from itmtouch.c
36d05e84e6SDmitry Torokhov  * - 3M parts are from mtouchusb.c
37d05e84e6SDmitry Torokhov  * - PanJit parts are from an unmerged driver by Lanslott Gish
38d05e84e6SDmitry Torokhov  * - DMC TSC 10/25 are from Holger Schurig, with ideas from an unmerged
39d05e84e6SDmitry Torokhov  *   driver from Marius Vollmer
40d05e84e6SDmitry Torokhov  *
41d05e84e6SDmitry Torokhov  *****************************************************************************/
42d05e84e6SDmitry Torokhov 
43d05e84e6SDmitry Torokhov //#define DEBUG
44d05e84e6SDmitry Torokhov 
45d05e84e6SDmitry Torokhov #include <linux/kernel.h>
46d05e84e6SDmitry Torokhov #include <linux/slab.h>
47d05e84e6SDmitry Torokhov #include <linux/input.h>
48d05e84e6SDmitry Torokhov #include <linux/module.h>
49d05e84e6SDmitry Torokhov #include <linux/init.h>
50d05e84e6SDmitry Torokhov #include <linux/usb.h>
51d05e84e6SDmitry Torokhov #include <linux/usb/input.h>
52ec42d448SDaniel Ritz #include <linux/hid.h>
53d05e84e6SDmitry Torokhov 
54d05e84e6SDmitry Torokhov 
5562aa366dSDaniel Ritz #define DRIVER_VERSION		"v0.6"
56d05e84e6SDmitry Torokhov #define DRIVER_AUTHOR		"Daniel Ritz <daniel.ritz@gmx.ch>"
57d05e84e6SDmitry Torokhov #define DRIVER_DESC		"USB Touchscreen Driver"
58d05e84e6SDmitry Torokhov 
59d05e84e6SDmitry Torokhov static int swap_xy;
60d05e84e6SDmitry Torokhov module_param(swap_xy, bool, 0644);
61d05e84e6SDmitry Torokhov MODULE_PARM_DESC(swap_xy, "If set X and Y axes are swapped.");
62d05e84e6SDmitry Torokhov 
63*c9cbf3d3SDan Streetman static int hwcalib_xy;
64*c9cbf3d3SDan Streetman module_param(hwcalib_xy, bool, 0644);
65*c9cbf3d3SDan Streetman MODULE_PARM_DESC(hwcalib_xy, "If set hw-calibrated X/Y are used if available");
66*c9cbf3d3SDan Streetman 
67d05e84e6SDmitry Torokhov /* device specifc data/functions */
68d05e84e6SDmitry Torokhov struct usbtouch_usb;
69d05e84e6SDmitry Torokhov struct usbtouch_device_info {
70d05e84e6SDmitry Torokhov 	int min_xc, max_xc;
71d05e84e6SDmitry Torokhov 	int min_yc, max_yc;
72d05e84e6SDmitry Torokhov 	int min_press, max_press;
73d05e84e6SDmitry Torokhov 	int rept_size;
74d05e84e6SDmitry Torokhov 
75d05e84e6SDmitry Torokhov 	void (*process_pkt) (struct usbtouch_usb *usbtouch, unsigned char *pkt, int len);
7662aa366dSDaniel Ritz 
7762aa366dSDaniel Ritz 	/*
7862aa366dSDaniel Ritz 	 * used to get the packet len. possible return values:
7962aa366dSDaniel Ritz 	 * > 0: packet len
8062aa366dSDaniel Ritz 	 * = 0: skip one byte
8162aa366dSDaniel Ritz 	 * < 0: -return value more bytes needed
8262aa366dSDaniel Ritz 	 */
83d05e84e6SDmitry Torokhov 	int  (*get_pkt_len) (unsigned char *pkt, int len);
8462aa366dSDaniel Ritz 
85d05e84e6SDmitry Torokhov 	int  (*read_data)   (struct usbtouch_usb *usbtouch, unsigned char *pkt);
86d05e84e6SDmitry Torokhov 	int  (*init)        (struct usbtouch_usb *usbtouch);
87d05e84e6SDmitry Torokhov };
88d05e84e6SDmitry Torokhov 
89d05e84e6SDmitry Torokhov /* a usbtouch device */
90d05e84e6SDmitry Torokhov struct usbtouch_usb {
91d05e84e6SDmitry Torokhov 	unsigned char *data;
92d05e84e6SDmitry Torokhov 	dma_addr_t data_dma;
93d05e84e6SDmitry Torokhov 	unsigned char *buffer;
94d05e84e6SDmitry Torokhov 	int buf_len;
95d05e84e6SDmitry Torokhov 	struct urb *irq;
96d05e84e6SDmitry Torokhov 	struct usb_device *udev;
97d05e84e6SDmitry Torokhov 	struct input_dev *input;
98d05e84e6SDmitry Torokhov 	struct usbtouch_device_info *type;
99d05e84e6SDmitry Torokhov 	char name[128];
100d05e84e6SDmitry Torokhov 	char phys[64];
101d05e84e6SDmitry Torokhov 
102d05e84e6SDmitry Torokhov 	int x, y;
103d05e84e6SDmitry Torokhov 	int touch, press;
104d05e84e6SDmitry Torokhov };
105d05e84e6SDmitry Torokhov 
106d05e84e6SDmitry Torokhov 
107d05e84e6SDmitry Torokhov /* device types */
108d05e84e6SDmitry Torokhov enum {
109ec42d448SDaniel Ritz 	DEVTYPE_IGNORE = -1,
110d05e84e6SDmitry Torokhov 	DEVTYPE_EGALAX,
111d05e84e6SDmitry Torokhov 	DEVTYPE_PANJIT,
112d05e84e6SDmitry Torokhov 	DEVTYPE_3M,
113d05e84e6SDmitry Torokhov 	DEVTYPE_ITM,
114d05e84e6SDmitry Torokhov 	DEVTYPE_ETURBO,
115d05e84e6SDmitry Torokhov 	DEVTYPE_GUNZE,
116d05e84e6SDmitry Torokhov 	DEVTYPE_DMC_TSC10,
117df561fcdSOndrej Zary 	DEVTYPE_IRTOUCH,
118a14a8401SOndrej Zary 	DEVTYPE_IDEALTEK,
1199d5657dbSIlya Frolov 	DEVTYPE_GENERAL_TOUCH,
12014e40206SJerrold Jones 	DEVTYPE_GOTOP,
121d05e84e6SDmitry Torokhov };
122d05e84e6SDmitry Torokhov 
123ec42d448SDaniel Ritz #define USB_DEVICE_HID_CLASS(vend, prod) \
124ec42d448SDaniel Ritz 	.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS \
125ec42d448SDaniel Ritz 		| USB_DEVICE_ID_MATCH_DEVICE, \
126ec42d448SDaniel Ritz 	.idVendor = (vend), \
127ec42d448SDaniel Ritz 	.idProduct = (prod), \
128ec42d448SDaniel Ritz 	.bInterfaceClass = USB_INTERFACE_CLASS_HID, \
129ec42d448SDaniel Ritz 	.bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE
130ec42d448SDaniel Ritz 
131d05e84e6SDmitry Torokhov static struct usb_device_id usbtouch_devices[] = {
132c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
133ec42d448SDaniel Ritz 	/* ignore the HID capable devices, handled by usbhid */
134ec42d448SDaniel Ritz 	{USB_DEVICE_HID_CLASS(0x0eef, 0x0001), .driver_info = DEVTYPE_IGNORE},
135ec42d448SDaniel Ritz 	{USB_DEVICE_HID_CLASS(0x0eef, 0x0002), .driver_info = DEVTYPE_IGNORE},
136ec42d448SDaniel Ritz 
137ec42d448SDaniel Ritz 	/* normal device IDs */
138d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x3823, 0x0001), .driver_info = DEVTYPE_EGALAX},
139d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x3823, 0x0002), .driver_info = DEVTYPE_EGALAX},
140d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x0123, 0x0001), .driver_info = DEVTYPE_EGALAX},
141d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x0eef, 0x0001), .driver_info = DEVTYPE_EGALAX},
142d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x0eef, 0x0002), .driver_info = DEVTYPE_EGALAX},
143d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x1234, 0x0001), .driver_info = DEVTYPE_EGALAX},
144d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x1234, 0x0002), .driver_info = DEVTYPE_EGALAX},
145d05e84e6SDmitry Torokhov #endif
146d05e84e6SDmitry Torokhov 
147c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_PANJIT
148d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x134c, 0x0001), .driver_info = DEVTYPE_PANJIT},
149d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x134c, 0x0002), .driver_info = DEVTYPE_PANJIT},
150d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x134c, 0x0003), .driver_info = DEVTYPE_PANJIT},
151d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x134c, 0x0004), .driver_info = DEVTYPE_PANJIT},
152d05e84e6SDmitry Torokhov #endif
153d05e84e6SDmitry Torokhov 
154c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_3M
155d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x0596, 0x0001), .driver_info = DEVTYPE_3M},
156d05e84e6SDmitry Torokhov #endif
157d05e84e6SDmitry Torokhov 
158c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_ITM
159d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x0403, 0xf9e9), .driver_info = DEVTYPE_ITM},
160d05e84e6SDmitry Torokhov #endif
161d05e84e6SDmitry Torokhov 
162c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_ETURBO
163d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x1234, 0x5678), .driver_info = DEVTYPE_ETURBO},
164d05e84e6SDmitry Torokhov #endif
165d05e84e6SDmitry Torokhov 
166c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_GUNZE
167d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x0637, 0x0001), .driver_info = DEVTYPE_GUNZE},
168d05e84e6SDmitry Torokhov #endif
169d05e84e6SDmitry Torokhov 
170c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_DMC_TSC10
171d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x0afa, 0x03e8), .driver_info = DEVTYPE_DMC_TSC10},
172d05e84e6SDmitry Torokhov #endif
173d05e84e6SDmitry Torokhov 
174df561fcdSOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH
175df561fcdSOndrej Zary 	{USB_DEVICE(0x595a, 0x0001), .driver_info = DEVTYPE_IRTOUCH},
176df561fcdSOndrej Zary 	{USB_DEVICE(0x6615, 0x0001), .driver_info = DEVTYPE_IRTOUCH},
177df561fcdSOndrej Zary #endif
178df561fcdSOndrej Zary 
179a14a8401SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
180a14a8401SOndrej Zary 	{USB_DEVICE(0x1391, 0x1000), .driver_info = DEVTYPE_IDEALTEK},
181a14a8401SOndrej Zary #endif
182a14a8401SOndrej Zary 
1839d5657dbSIlya Frolov #ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
1849d5657dbSIlya Frolov 	{USB_DEVICE(0x0dfc, 0x0001), .driver_info = DEVTYPE_GENERAL_TOUCH},
1859d5657dbSIlya Frolov #endif
1869d5657dbSIlya Frolov 
18714e40206SJerrold Jones #ifdef CONFIG_TOUCHSCREEN_USB_GOTOP
18814e40206SJerrold Jones 	{USB_DEVICE(0x08f2, 0x007f), .driver_info = DEVTYPE_GOTOP},
18914e40206SJerrold Jones 	{USB_DEVICE(0x08f2, 0x00ce), .driver_info = DEVTYPE_GOTOP},
19014e40206SJerrold Jones 	{USB_DEVICE(0x08f2, 0x00f4), .driver_info = DEVTYPE_GOTOP},
19114e40206SJerrold Jones #endif
19214e40206SJerrold Jones 
193d05e84e6SDmitry Torokhov 	{}
194d05e84e6SDmitry Torokhov };
195d05e84e6SDmitry Torokhov 
196d05e84e6SDmitry Torokhov 
197d05e84e6SDmitry Torokhov /*****************************************************************************
198d05e84e6SDmitry Torokhov  * eGalax part
199d05e84e6SDmitry Torokhov  */
200d05e84e6SDmitry Torokhov 
201c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
202d05e84e6SDmitry Torokhov 
20362aa366dSDaniel Ritz #ifndef MULTI_PACKET
20462aa366dSDaniel Ritz #define MULTI_PACKET
20562aa366dSDaniel Ritz #endif
20662aa366dSDaniel Ritz 
207d05e84e6SDmitry Torokhov #define EGALAX_PKT_TYPE_MASK		0xFE
208d05e84e6SDmitry Torokhov #define EGALAX_PKT_TYPE_REPT		0x80
209d05e84e6SDmitry Torokhov #define EGALAX_PKT_TYPE_DIAG		0x0A
210d05e84e6SDmitry Torokhov 
211d05e84e6SDmitry Torokhov static int egalax_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
212d05e84e6SDmitry Torokhov {
213d05e84e6SDmitry Torokhov 	if ((pkt[0] & EGALAX_PKT_TYPE_MASK) != EGALAX_PKT_TYPE_REPT)
214d05e84e6SDmitry Torokhov 		return 0;
215d05e84e6SDmitry Torokhov 
216d05e84e6SDmitry Torokhov 	dev->x = ((pkt[3] & 0x0F) << 7) | (pkt[4] & 0x7F);
217d05e84e6SDmitry Torokhov 	dev->y = ((pkt[1] & 0x0F) << 7) | (pkt[2] & 0x7F);
218d05e84e6SDmitry Torokhov 	dev->touch = pkt[0] & 0x01;
219d05e84e6SDmitry Torokhov 
220d05e84e6SDmitry Torokhov 	return 1;
221d05e84e6SDmitry Torokhov }
222d05e84e6SDmitry Torokhov 
223d05e84e6SDmitry Torokhov static int egalax_get_pkt_len(unsigned char *buf, int len)
224d05e84e6SDmitry Torokhov {
225d05e84e6SDmitry Torokhov 	switch (buf[0] & EGALAX_PKT_TYPE_MASK) {
226d05e84e6SDmitry Torokhov 	case EGALAX_PKT_TYPE_REPT:
227d05e84e6SDmitry Torokhov 		return 5;
228d05e84e6SDmitry Torokhov 
229d05e84e6SDmitry Torokhov 	case EGALAX_PKT_TYPE_DIAG:
230d05e84e6SDmitry Torokhov 		if (len < 2)
231d05e84e6SDmitry Torokhov 			return -1;
232d05e84e6SDmitry Torokhov 
233d05e84e6SDmitry Torokhov 		return buf[1] + 2;
234d05e84e6SDmitry Torokhov 	}
235d05e84e6SDmitry Torokhov 
236d05e84e6SDmitry Torokhov 	return 0;
237d05e84e6SDmitry Torokhov }
238d05e84e6SDmitry Torokhov #endif
239d05e84e6SDmitry Torokhov 
240d05e84e6SDmitry Torokhov 
241d05e84e6SDmitry Torokhov /*****************************************************************************
242d05e84e6SDmitry Torokhov  * PanJit Part
243d05e84e6SDmitry Torokhov  */
244c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_PANJIT
245d05e84e6SDmitry Torokhov static int panjit_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
246d05e84e6SDmitry Torokhov {
247d05e84e6SDmitry Torokhov 	dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1];
248d05e84e6SDmitry Torokhov 	dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3];
249d05e84e6SDmitry Torokhov 	dev->touch = pkt[0] & 0x01;
250d05e84e6SDmitry Torokhov 
251d05e84e6SDmitry Torokhov 	return 1;
252d05e84e6SDmitry Torokhov }
253d05e84e6SDmitry Torokhov #endif
254d05e84e6SDmitry Torokhov 
255d05e84e6SDmitry Torokhov 
256d05e84e6SDmitry Torokhov /*****************************************************************************
257d05e84e6SDmitry Torokhov  * 3M/Microtouch Part
258d05e84e6SDmitry Torokhov  */
259c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_3M
260d05e84e6SDmitry Torokhov 
261d05e84e6SDmitry Torokhov #define MTOUCHUSB_ASYNC_REPORT          1
262d05e84e6SDmitry Torokhov #define MTOUCHUSB_RESET                 7
263d05e84e6SDmitry Torokhov #define MTOUCHUSB_REQ_CTRLLR_ID         10
264d05e84e6SDmitry Torokhov 
265d05e84e6SDmitry Torokhov static int mtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
266d05e84e6SDmitry Torokhov {
267*c9cbf3d3SDan Streetman 	if (hwcalib_xy) {
268*c9cbf3d3SDan Streetman 		dev->x = (pkt[4] << 8) | pkt[3];
269*c9cbf3d3SDan Streetman 		dev->y = 0xffff - ((pkt[6] << 8) | pkt[5]);
270*c9cbf3d3SDan Streetman 	} else {
271d05e84e6SDmitry Torokhov 		dev->x = (pkt[8] << 8) | pkt[7];
272d05e84e6SDmitry Torokhov 		dev->y = (pkt[10] << 8) | pkt[9];
273*c9cbf3d3SDan Streetman 	}
274d05e84e6SDmitry Torokhov 	dev->touch = (pkt[2] & 0x40) ? 1 : 0;
275d05e84e6SDmitry Torokhov 
276d05e84e6SDmitry Torokhov 	return 1;
277d05e84e6SDmitry Torokhov }
278d05e84e6SDmitry Torokhov 
279d05e84e6SDmitry Torokhov static int mtouch_init(struct usbtouch_usb *usbtouch)
280d05e84e6SDmitry Torokhov {
281d05e84e6SDmitry Torokhov 	int ret, i;
282d05e84e6SDmitry Torokhov 
283d05e84e6SDmitry Torokhov 	ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
284d05e84e6SDmitry Torokhov 	                      MTOUCHUSB_RESET,
285d05e84e6SDmitry Torokhov 	                      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
286d05e84e6SDmitry Torokhov 	                      1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
287d05e84e6SDmitry Torokhov 	dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d",
288ea3e6c59SHarvey Harrison 	    __func__, ret);
289d05e84e6SDmitry Torokhov 	if (ret < 0)
290d05e84e6SDmitry Torokhov 		return ret;
291d05e84e6SDmitry Torokhov 	msleep(150);
292d05e84e6SDmitry Torokhov 
293d05e84e6SDmitry Torokhov 	for (i = 0; i < 3; i++) {
294d05e84e6SDmitry Torokhov 		ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
295d05e84e6SDmitry Torokhov 				      MTOUCHUSB_ASYNC_REPORT,
296d05e84e6SDmitry Torokhov 				      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
297d05e84e6SDmitry Torokhov 				      1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT);
298d05e84e6SDmitry Torokhov 		dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d",
299ea3e6c59SHarvey Harrison 		    __func__, ret);
300d05e84e6SDmitry Torokhov 		if (ret >= 0)
301d05e84e6SDmitry Torokhov 			break;
302d05e84e6SDmitry Torokhov 		if (ret != -EPIPE)
303d05e84e6SDmitry Torokhov 			return ret;
304d05e84e6SDmitry Torokhov 	}
305d05e84e6SDmitry Torokhov 
306*c9cbf3d3SDan Streetman 	/* Default min/max xy are the raw values, override if using hw-calib */
307*c9cbf3d3SDan Streetman 	if (hwcalib_xy) {
308*c9cbf3d3SDan Streetman 		input_set_abs_params(usbtouch->input, ABS_X, 0, 0xffff, 0, 0);
309*c9cbf3d3SDan Streetman 		input_set_abs_params(usbtouch->input, ABS_Y, 0, 0xffff, 0, 0);
310*c9cbf3d3SDan Streetman 	}
311*c9cbf3d3SDan Streetman 
312d05e84e6SDmitry Torokhov 	return 0;
313d05e84e6SDmitry Torokhov }
314d05e84e6SDmitry Torokhov #endif
315d05e84e6SDmitry Torokhov 
316d05e84e6SDmitry Torokhov 
317d05e84e6SDmitry Torokhov /*****************************************************************************
318d05e84e6SDmitry Torokhov  * ITM Part
319d05e84e6SDmitry Torokhov  */
320c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_ITM
321d05e84e6SDmitry Torokhov static int itm_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
322d05e84e6SDmitry Torokhov {
323d05e84e6SDmitry Torokhov 	int touch;
324d05e84e6SDmitry Torokhov 	/*
325d05e84e6SDmitry Torokhov 	 * ITM devices report invalid x/y data if not touched.
326d05e84e6SDmitry Torokhov 	 * if the screen was touched before but is not touched any more
327d05e84e6SDmitry Torokhov 	 * report touch as 0 with the last valid x/y data once. then stop
328d05e84e6SDmitry Torokhov 	 * reporting data until touched again.
329d05e84e6SDmitry Torokhov 	 */
330d05e84e6SDmitry Torokhov 	dev->press = ((pkt[2] & 0x01) << 7) | (pkt[5] & 0x7F);
331d05e84e6SDmitry Torokhov 
332d05e84e6SDmitry Torokhov 	touch = ~pkt[7] & 0x20;
333d05e84e6SDmitry Torokhov 	if (!touch) {
334d05e84e6SDmitry Torokhov 		if (dev->touch) {
335d05e84e6SDmitry Torokhov 			dev->touch = 0;
336d05e84e6SDmitry Torokhov 			return 1;
337d05e84e6SDmitry Torokhov 		}
338d05e84e6SDmitry Torokhov 
339d05e84e6SDmitry Torokhov 		return 0;
340d05e84e6SDmitry Torokhov 	}
341d05e84e6SDmitry Torokhov 
342d05e84e6SDmitry Torokhov 	dev->x = ((pkt[0] & 0x1F) << 7) | (pkt[3] & 0x7F);
343d05e84e6SDmitry Torokhov 	dev->y = ((pkt[1] & 0x1F) << 7) | (pkt[4] & 0x7F);
344d05e84e6SDmitry Torokhov 	dev->touch = touch;
345d05e84e6SDmitry Torokhov 
346d05e84e6SDmitry Torokhov 	return 1;
347d05e84e6SDmitry Torokhov }
348d05e84e6SDmitry Torokhov #endif
349d05e84e6SDmitry Torokhov 
350d05e84e6SDmitry Torokhov 
351d05e84e6SDmitry Torokhov /*****************************************************************************
352d05e84e6SDmitry Torokhov  * eTurboTouch part
353d05e84e6SDmitry Torokhov  */
354c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_ETURBO
35562aa366dSDaniel Ritz #ifndef MULTI_PACKET
35662aa366dSDaniel Ritz #define MULTI_PACKET
35762aa366dSDaniel Ritz #endif
358d05e84e6SDmitry Torokhov static int eturbo_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
359d05e84e6SDmitry Torokhov {
360d05e84e6SDmitry Torokhov 	unsigned int shift;
361d05e84e6SDmitry Torokhov 
362d05e84e6SDmitry Torokhov 	/* packets should start with sync */
363d05e84e6SDmitry Torokhov 	if (!(pkt[0] & 0x80))
364d05e84e6SDmitry Torokhov 		return 0;
365d05e84e6SDmitry Torokhov 
366d05e84e6SDmitry Torokhov 	shift = (6 - (pkt[0] & 0x03));
367d05e84e6SDmitry Torokhov 	dev->x = ((pkt[3] << 7) | pkt[4]) >> shift;
368d05e84e6SDmitry Torokhov 	dev->y = ((pkt[1] << 7) | pkt[2]) >> shift;
369d05e84e6SDmitry Torokhov 	dev->touch = (pkt[0] & 0x10) ? 1 : 0;
370d05e84e6SDmitry Torokhov 
371d05e84e6SDmitry Torokhov 	return 1;
372d05e84e6SDmitry Torokhov }
373d05e84e6SDmitry Torokhov 
374d05e84e6SDmitry Torokhov static int eturbo_get_pkt_len(unsigned char *buf, int len)
375d05e84e6SDmitry Torokhov {
376d05e84e6SDmitry Torokhov 	if (buf[0] & 0x80)
377d05e84e6SDmitry Torokhov 		return 5;
378d05e84e6SDmitry Torokhov 	if (buf[0] == 0x01)
379d05e84e6SDmitry Torokhov 		return 3;
380d05e84e6SDmitry Torokhov 	return 0;
381d05e84e6SDmitry Torokhov }
382d05e84e6SDmitry Torokhov #endif
383d05e84e6SDmitry Torokhov 
384d05e84e6SDmitry Torokhov 
385d05e84e6SDmitry Torokhov /*****************************************************************************
386d05e84e6SDmitry Torokhov  * Gunze part
387d05e84e6SDmitry Torokhov  */
388c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_GUNZE
389d05e84e6SDmitry Torokhov static int gunze_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
390d05e84e6SDmitry Torokhov {
391d05e84e6SDmitry Torokhov 	if (!(pkt[0] & 0x80) || ((pkt[1] | pkt[2] | pkt[3]) & 0x80))
392d05e84e6SDmitry Torokhov 		return 0;
393d05e84e6SDmitry Torokhov 
394d05e84e6SDmitry Torokhov 	dev->x = ((pkt[0] & 0x1F) << 7) | (pkt[2] & 0x7F);
395d05e84e6SDmitry Torokhov 	dev->y = ((pkt[1] & 0x1F) << 7) | (pkt[3] & 0x7F);
396d05e84e6SDmitry Torokhov 	dev->touch = pkt[0] & 0x20;
397d05e84e6SDmitry Torokhov 
398d05e84e6SDmitry Torokhov 	return 1;
399d05e84e6SDmitry Torokhov }
400d05e84e6SDmitry Torokhov #endif
401d05e84e6SDmitry Torokhov 
402d05e84e6SDmitry Torokhov /*****************************************************************************
403d05e84e6SDmitry Torokhov  * DMC TSC-10/25 Part
404d05e84e6SDmitry Torokhov  *
405d05e84e6SDmitry Torokhov  * Documentation about the controller and it's protocol can be found at
406d05e84e6SDmitry Torokhov  *   http://www.dmccoltd.com/files/controler/tsc10usb_pi_e.pdf
407d05e84e6SDmitry Torokhov  *   http://www.dmccoltd.com/files/controler/tsc25_usb_e.pdf
408d05e84e6SDmitry Torokhov  */
409c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_DMC_TSC10
410d05e84e6SDmitry Torokhov 
411d05e84e6SDmitry Torokhov /* supported data rates. currently using 130 */
412d05e84e6SDmitry Torokhov #define TSC10_RATE_POINT	0x50
413d05e84e6SDmitry Torokhov #define TSC10_RATE_30		0x40
414d05e84e6SDmitry Torokhov #define TSC10_RATE_50		0x41
415d05e84e6SDmitry Torokhov #define TSC10_RATE_80		0x42
416d05e84e6SDmitry Torokhov #define TSC10_RATE_100		0x43
417d05e84e6SDmitry Torokhov #define TSC10_RATE_130		0x44
418d05e84e6SDmitry Torokhov #define TSC10_RATE_150		0x45
419d05e84e6SDmitry Torokhov 
420d05e84e6SDmitry Torokhov /* commands */
421d05e84e6SDmitry Torokhov #define TSC10_CMD_RESET		0x55
422d05e84e6SDmitry Torokhov #define TSC10_CMD_RATE		0x05
423d05e84e6SDmitry Torokhov #define TSC10_CMD_DATA1		0x01
424d05e84e6SDmitry Torokhov 
425d05e84e6SDmitry Torokhov static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
426d05e84e6SDmitry Torokhov {
427d05e84e6SDmitry Torokhov 	struct usb_device *dev = usbtouch->udev;
42876d057ceSOliver Neukum 	int ret = -ENOMEM;
42976d057ceSOliver Neukum 	unsigned char *buf;
430d05e84e6SDmitry Torokhov 
43176d057ceSOliver Neukum 	buf = kmalloc(2, GFP_KERNEL);
43276d057ceSOliver Neukum 	if (!buf)
43376d057ceSOliver Neukum 		goto err_nobuf;
434d05e84e6SDmitry Torokhov 	/* reset */
435d05e84e6SDmitry Torokhov 	buf[0] = buf[1] = 0xFF;
436d05e84e6SDmitry Torokhov 	ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
437d05e84e6SDmitry Torokhov 	                      TSC10_CMD_RESET,
438d05e84e6SDmitry Torokhov 	                      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
439d05e84e6SDmitry Torokhov 	                      0, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
440d05e84e6SDmitry Torokhov 	if (ret < 0)
44176d057ceSOliver Neukum 		goto err_out;
4422ec6f246SNuno Lucas 	if (buf[0] != 0x06) {
44376d057ceSOliver Neukum 		ret = -ENODEV;
44476d057ceSOliver Neukum 		goto err_out;
44576d057ceSOliver Neukum 	}
446d05e84e6SDmitry Torokhov 
447d05e84e6SDmitry Torokhov 	/* set coordinate output rate */
448d05e84e6SDmitry Torokhov 	buf[0] = buf[1] = 0xFF;
449d05e84e6SDmitry Torokhov 	ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
450d05e84e6SDmitry Torokhov 	                      TSC10_CMD_RATE,
451d05e84e6SDmitry Torokhov 	                      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
452d05e84e6SDmitry Torokhov 	                      TSC10_RATE_150, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
453d05e84e6SDmitry Torokhov 	if (ret < 0)
45476d057ceSOliver Neukum 		goto err_out;
4552ec6f246SNuno Lucas 	if ((buf[0] != 0x06) && (buf[0] != 0x15 || buf[1] != 0x01)) {
45676d057ceSOliver Neukum 		ret = -ENODEV;
45776d057ceSOliver Neukum 		goto err_out;
45876d057ceSOliver Neukum 	}
459d05e84e6SDmitry Torokhov 
460d05e84e6SDmitry Torokhov 	/* start sending data */
461d05e84e6SDmitry Torokhov 	ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
462d05e84e6SDmitry Torokhov 	                      TSC10_CMD_DATA1,
463d05e84e6SDmitry Torokhov 	                      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
464d05e84e6SDmitry Torokhov 	                      0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
46576d057ceSOliver Neukum err_out:
46676d057ceSOliver Neukum 	kfree(buf);
46776d057ceSOliver Neukum err_nobuf:
468d05e84e6SDmitry Torokhov 	return ret;
469d05e84e6SDmitry Torokhov }
470d05e84e6SDmitry Torokhov 
471d05e84e6SDmitry Torokhov 
472d05e84e6SDmitry Torokhov static int dmc_tsc10_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
473d05e84e6SDmitry Torokhov {
474d05e84e6SDmitry Torokhov 	dev->x = ((pkt[2] & 0x03) << 8) | pkt[1];
475d05e84e6SDmitry Torokhov 	dev->y = ((pkt[4] & 0x03) << 8) | pkt[3];
476d05e84e6SDmitry Torokhov 	dev->touch = pkt[0] & 0x01;
477d05e84e6SDmitry Torokhov 
478d05e84e6SDmitry Torokhov 	return 1;
479d05e84e6SDmitry Torokhov }
480d05e84e6SDmitry Torokhov #endif
481d05e84e6SDmitry Torokhov 
482d05e84e6SDmitry Torokhov 
483d05e84e6SDmitry Torokhov /*****************************************************************************
484df561fcdSOndrej Zary  * IRTOUCH Part
485df561fcdSOndrej Zary  */
486df561fcdSOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH
487df561fcdSOndrej Zary static int irtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
488df561fcdSOndrej Zary {
489df561fcdSOndrej Zary 	dev->x = (pkt[3] << 8) | pkt[2];
490df561fcdSOndrej Zary 	dev->y = (pkt[5] << 8) | pkt[4];
491df561fcdSOndrej Zary 	dev->touch = (pkt[1] & 0x03) ? 1 : 0;
492df561fcdSOndrej Zary 
493df561fcdSOndrej Zary 	return 1;
494df561fcdSOndrej Zary }
495df561fcdSOndrej Zary #endif
496df561fcdSOndrej Zary 
497df561fcdSOndrej Zary 
498df561fcdSOndrej Zary /*****************************************************************************
499a14a8401SOndrej Zary  * IdealTEK URTC1000 Part
500a14a8401SOndrej Zary  */
501a14a8401SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
50262aa366dSDaniel Ritz #ifndef MULTI_PACKET
50362aa366dSDaniel Ritz #define MULTI_PACKET
50462aa366dSDaniel Ritz #endif
505a14a8401SOndrej Zary static int idealtek_get_pkt_len(unsigned char *buf, int len)
506a14a8401SOndrej Zary {
507a14a8401SOndrej Zary 	if (buf[0] & 0x80)
508a14a8401SOndrej Zary 		return 5;
509a14a8401SOndrej Zary 	if (buf[0] == 0x01)
510a14a8401SOndrej Zary 		return len;
511a14a8401SOndrej Zary 	return 0;
512a14a8401SOndrej Zary }
513a14a8401SOndrej Zary 
514a14a8401SOndrej Zary static int idealtek_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
515a14a8401SOndrej Zary {
516a14a8401SOndrej Zary 	switch (pkt[0] & 0x98) {
517a14a8401SOndrej Zary 	case 0x88:
518a14a8401SOndrej Zary 		/* touch data in IdealTEK mode */
519a14a8401SOndrej Zary 		dev->x = (pkt[1] << 5) | (pkt[2] >> 2);
520a14a8401SOndrej Zary 		dev->y = (pkt[3] << 5) | (pkt[4] >> 2);
521a14a8401SOndrej Zary 		dev->touch = (pkt[0] & 0x40) ? 1 : 0;
522a14a8401SOndrej Zary 		return 1;
523a14a8401SOndrej Zary 
524a14a8401SOndrej Zary 	case 0x98:
525a14a8401SOndrej Zary 		/* touch data in MT emulation mode */
526a14a8401SOndrej Zary 		dev->x = (pkt[2] << 5) | (pkt[1] >> 2);
527a14a8401SOndrej Zary 		dev->y = (pkt[4] << 5) | (pkt[3] >> 2);
528a14a8401SOndrej Zary 		dev->touch = (pkt[0] & 0x40) ? 1 : 0;
529a14a8401SOndrej Zary 		return 1;
530a14a8401SOndrej Zary 
531a14a8401SOndrej Zary 	default:
532a14a8401SOndrej Zary 		return 0;
533a14a8401SOndrej Zary 	}
534a14a8401SOndrej Zary }
535a14a8401SOndrej Zary #endif
536a14a8401SOndrej Zary 
5379d5657dbSIlya Frolov /*****************************************************************************
5389d5657dbSIlya Frolov  * General Touch Part
5399d5657dbSIlya Frolov  */
5409d5657dbSIlya Frolov #ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
5419d5657dbSIlya Frolov static int general_touch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
5429d5657dbSIlya Frolov {
5439d5657dbSIlya Frolov 	dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1] ;
5449d5657dbSIlya Frolov 	dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3] ;
5459d5657dbSIlya Frolov 	dev->press = pkt[5] & 0xff;
5469d5657dbSIlya Frolov 	dev->touch = pkt[0] & 0x01;
5479d5657dbSIlya Frolov 
5489d5657dbSIlya Frolov 	return 1;
5499d5657dbSIlya Frolov }
5509d5657dbSIlya Frolov #endif
551a14a8401SOndrej Zary 
552a14a8401SOndrej Zary /*****************************************************************************
55314e40206SJerrold Jones  * GoTop Part
55414e40206SJerrold Jones  */
55514e40206SJerrold Jones #ifdef CONFIG_TOUCHSCREEN_USB_GOTOP
55614e40206SJerrold Jones static int gotop_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
55714e40206SJerrold Jones {
55814e40206SJerrold Jones 	dev->x = ((pkt[1] & 0x38) << 4) | pkt[2];
55914e40206SJerrold Jones 	dev->y = ((pkt[1] & 0x07) << 7) | pkt[3];
56014e40206SJerrold Jones 	dev->touch = pkt[0] & 0x01;
56114e40206SJerrold Jones 	return 1;
56214e40206SJerrold Jones }
56314e40206SJerrold Jones #endif
56414e40206SJerrold Jones 
56514e40206SJerrold Jones 
56614e40206SJerrold Jones /*****************************************************************************
567d05e84e6SDmitry Torokhov  * the different device descriptors
568d05e84e6SDmitry Torokhov  */
56962aa366dSDaniel Ritz #ifdef MULTI_PACKET
57062aa366dSDaniel Ritz static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
57162aa366dSDaniel Ritz 				   unsigned char *pkt, int len);
57262aa366dSDaniel Ritz #endif
57362aa366dSDaniel Ritz 
574d05e84e6SDmitry Torokhov static struct usbtouch_device_info usbtouch_dev_info[] = {
575c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
576d05e84e6SDmitry Torokhov 	[DEVTYPE_EGALAX] = {
577d05e84e6SDmitry Torokhov 		.min_xc		= 0x0,
578d05e84e6SDmitry Torokhov 		.max_xc		= 0x07ff,
579d05e84e6SDmitry Torokhov 		.min_yc		= 0x0,
580d05e84e6SDmitry Torokhov 		.max_yc		= 0x07ff,
581d05e84e6SDmitry Torokhov 		.rept_size	= 16,
582d05e84e6SDmitry Torokhov 		.process_pkt	= usbtouch_process_multi,
583d05e84e6SDmitry Torokhov 		.get_pkt_len	= egalax_get_pkt_len,
584d05e84e6SDmitry Torokhov 		.read_data	= egalax_read_data,
585d05e84e6SDmitry Torokhov 	},
586d05e84e6SDmitry Torokhov #endif
587d05e84e6SDmitry Torokhov 
588c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_PANJIT
589d05e84e6SDmitry Torokhov 	[DEVTYPE_PANJIT] = {
590d05e84e6SDmitry Torokhov 		.min_xc		= 0x0,
591d05e84e6SDmitry Torokhov 		.max_xc		= 0x0fff,
592d05e84e6SDmitry Torokhov 		.min_yc		= 0x0,
593d05e84e6SDmitry Torokhov 		.max_yc		= 0x0fff,
594d05e84e6SDmitry Torokhov 		.rept_size	= 8,
595d05e84e6SDmitry Torokhov 		.read_data	= panjit_read_data,
596d05e84e6SDmitry Torokhov 	},
597d05e84e6SDmitry Torokhov #endif
598d05e84e6SDmitry Torokhov 
599c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_3M
600d05e84e6SDmitry Torokhov 	[DEVTYPE_3M] = {
601d05e84e6SDmitry Torokhov 		.min_xc		= 0x0,
602d05e84e6SDmitry Torokhov 		.max_xc		= 0x4000,
603d05e84e6SDmitry Torokhov 		.min_yc		= 0x0,
604d05e84e6SDmitry Torokhov 		.max_yc		= 0x4000,
605d05e84e6SDmitry Torokhov 		.rept_size	= 11,
606d05e84e6SDmitry Torokhov 		.read_data	= mtouch_read_data,
607d05e84e6SDmitry Torokhov 		.init		= mtouch_init,
608d05e84e6SDmitry Torokhov 	},
609d05e84e6SDmitry Torokhov #endif
610d05e84e6SDmitry Torokhov 
611c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_ITM
612d05e84e6SDmitry Torokhov 	[DEVTYPE_ITM] = {
613d05e84e6SDmitry Torokhov 		.min_xc		= 0x0,
614d05e84e6SDmitry Torokhov 		.max_xc		= 0x0fff,
615d05e84e6SDmitry Torokhov 		.min_yc		= 0x0,
616d05e84e6SDmitry Torokhov 		.max_yc		= 0x0fff,
617d05e84e6SDmitry Torokhov 		.max_press	= 0xff,
618d05e84e6SDmitry Torokhov 		.rept_size	= 8,
619d05e84e6SDmitry Torokhov 		.read_data	= itm_read_data,
620d05e84e6SDmitry Torokhov 	},
621d05e84e6SDmitry Torokhov #endif
622d05e84e6SDmitry Torokhov 
623c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_ETURBO
624d05e84e6SDmitry Torokhov 	[DEVTYPE_ETURBO] = {
625d05e84e6SDmitry Torokhov 		.min_xc		= 0x0,
626d05e84e6SDmitry Torokhov 		.max_xc		= 0x07ff,
627d05e84e6SDmitry Torokhov 		.min_yc		= 0x0,
628d05e84e6SDmitry Torokhov 		.max_yc		= 0x07ff,
629d05e84e6SDmitry Torokhov 		.rept_size	= 8,
630d05e84e6SDmitry Torokhov 		.process_pkt	= usbtouch_process_multi,
631d05e84e6SDmitry Torokhov 		.get_pkt_len	= eturbo_get_pkt_len,
632d05e84e6SDmitry Torokhov 		.read_data	= eturbo_read_data,
633d05e84e6SDmitry Torokhov 	},
634d05e84e6SDmitry Torokhov #endif
635d05e84e6SDmitry Torokhov 
636c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_GUNZE
637d05e84e6SDmitry Torokhov 	[DEVTYPE_GUNZE] = {
638d05e84e6SDmitry Torokhov 		.min_xc		= 0x0,
639d05e84e6SDmitry Torokhov 		.max_xc		= 0x0fff,
640d05e84e6SDmitry Torokhov 		.min_yc		= 0x0,
641d05e84e6SDmitry Torokhov 		.max_yc		= 0x0fff,
642d05e84e6SDmitry Torokhov 		.rept_size	= 4,
643d05e84e6SDmitry Torokhov 		.read_data	= gunze_read_data,
644d05e84e6SDmitry Torokhov 	},
645d05e84e6SDmitry Torokhov #endif
646d05e84e6SDmitry Torokhov 
647c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_DMC_TSC10
648d05e84e6SDmitry Torokhov 	[DEVTYPE_DMC_TSC10] = {
649d05e84e6SDmitry Torokhov 		.min_xc		= 0x0,
650d05e84e6SDmitry Torokhov 		.max_xc		= 0x03ff,
651d05e84e6SDmitry Torokhov 		.min_yc		= 0x0,
652d05e84e6SDmitry Torokhov 		.max_yc		= 0x03ff,
653d05e84e6SDmitry Torokhov 		.rept_size	= 5,
654d05e84e6SDmitry Torokhov 		.init		= dmc_tsc10_init,
655d05e84e6SDmitry Torokhov 		.read_data	= dmc_tsc10_read_data,
656d05e84e6SDmitry Torokhov 	},
657d05e84e6SDmitry Torokhov #endif
658df561fcdSOndrej Zary 
659df561fcdSOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH
660df561fcdSOndrej Zary 	[DEVTYPE_IRTOUCH] = {
661df561fcdSOndrej Zary 		.min_xc		= 0x0,
662df561fcdSOndrej Zary 		.max_xc		= 0x0fff,
663df561fcdSOndrej Zary 		.min_yc		= 0x0,
664df561fcdSOndrej Zary 		.max_yc		= 0x0fff,
665df561fcdSOndrej Zary 		.rept_size	= 8,
666df561fcdSOndrej Zary 		.read_data	= irtouch_read_data,
667df561fcdSOndrej Zary 	},
668df561fcdSOndrej Zary #endif
669a14a8401SOndrej Zary 
670a14a8401SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
671a14a8401SOndrej Zary 	[DEVTYPE_IDEALTEK] = {
672a14a8401SOndrej Zary 		.min_xc		= 0x0,
673a14a8401SOndrej Zary 		.max_xc		= 0x0fff,
674a14a8401SOndrej Zary 		.min_yc		= 0x0,
675a14a8401SOndrej Zary 		.max_yc		= 0x0fff,
676a14a8401SOndrej Zary 		.rept_size	= 8,
677a14a8401SOndrej Zary 		.process_pkt	= usbtouch_process_multi,
678a14a8401SOndrej Zary 		.get_pkt_len	= idealtek_get_pkt_len,
679a14a8401SOndrej Zary 		.read_data	= idealtek_read_data,
680a14a8401SOndrej Zary 	},
681a14a8401SOndrej Zary #endif
6829d5657dbSIlya Frolov 
6839d5657dbSIlya Frolov #ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
6849d5657dbSIlya Frolov 	[DEVTYPE_GENERAL_TOUCH] = {
6859d5657dbSIlya Frolov 		.min_xc		= 0x0,
6869d5657dbSIlya Frolov 		.max_xc		= 0x0500,
6879d5657dbSIlya Frolov 		.min_yc		= 0x0,
6889d5657dbSIlya Frolov 		.max_yc		= 0x0500,
6899d5657dbSIlya Frolov 		.rept_size	= 7,
6909d5657dbSIlya Frolov 		.read_data	= general_touch_read_data,
69114e40206SJerrold Jones 	},
6929d5657dbSIlya Frolov #endif
6939d5657dbSIlya Frolov 
69414e40206SJerrold Jones #ifdef CONFIG_TOUCHSCREEN_USB_GOTOP
69514e40206SJerrold Jones 	[DEVTYPE_GOTOP] = {
69614e40206SJerrold Jones 		.min_xc		= 0x0,
69714e40206SJerrold Jones 		.max_xc		= 0x03ff,
69814e40206SJerrold Jones 		.min_yc		= 0x0,
69914e40206SJerrold Jones 		.max_yc		= 0x03ff,
70014e40206SJerrold Jones 		.rept_size	= 4,
70114e40206SJerrold Jones 		.read_data	= gotop_read_data,
70214e40206SJerrold Jones 	},
70314e40206SJerrold Jones #endif
704d05e84e6SDmitry Torokhov };
705d05e84e6SDmitry Torokhov 
706d05e84e6SDmitry Torokhov 
707d05e84e6SDmitry Torokhov /*****************************************************************************
708d05e84e6SDmitry Torokhov  * Generic Part
709d05e84e6SDmitry Torokhov  */
710d05e84e6SDmitry Torokhov static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,
711d05e84e6SDmitry Torokhov                                  unsigned char *pkt, int len)
712d05e84e6SDmitry Torokhov {
713d05e84e6SDmitry Torokhov 	struct usbtouch_device_info *type = usbtouch->type;
714d05e84e6SDmitry Torokhov 
715d05e84e6SDmitry Torokhov 	if (!type->read_data(usbtouch, pkt))
716d05e84e6SDmitry Torokhov 			return;
717d05e84e6SDmitry Torokhov 
718d05e84e6SDmitry Torokhov 	input_report_key(usbtouch->input, BTN_TOUCH, usbtouch->touch);
719d05e84e6SDmitry Torokhov 
720d05e84e6SDmitry Torokhov 	if (swap_xy) {
721d05e84e6SDmitry Torokhov 		input_report_abs(usbtouch->input, ABS_X, usbtouch->y);
722d05e84e6SDmitry Torokhov 		input_report_abs(usbtouch->input, ABS_Y, usbtouch->x);
723d05e84e6SDmitry Torokhov 	} else {
724d05e84e6SDmitry Torokhov 		input_report_abs(usbtouch->input, ABS_X, usbtouch->x);
725d05e84e6SDmitry Torokhov 		input_report_abs(usbtouch->input, ABS_Y, usbtouch->y);
726d05e84e6SDmitry Torokhov 	}
727d05e84e6SDmitry Torokhov 	if (type->max_press)
728d05e84e6SDmitry Torokhov 		input_report_abs(usbtouch->input, ABS_PRESSURE, usbtouch->press);
729d05e84e6SDmitry Torokhov 	input_sync(usbtouch->input);
730d05e84e6SDmitry Torokhov }
731d05e84e6SDmitry Torokhov 
732d05e84e6SDmitry Torokhov 
733d05e84e6SDmitry Torokhov #ifdef MULTI_PACKET
734d05e84e6SDmitry Torokhov static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
735d05e84e6SDmitry Torokhov                                    unsigned char *pkt, int len)
736d05e84e6SDmitry Torokhov {
737d05e84e6SDmitry Torokhov 	unsigned char *buffer;
738d05e84e6SDmitry Torokhov 	int pkt_len, pos, buf_len, tmp;
739d05e84e6SDmitry Torokhov 
740d05e84e6SDmitry Torokhov 	/* process buffer */
741d05e84e6SDmitry Torokhov 	if (unlikely(usbtouch->buf_len)) {
742d05e84e6SDmitry Torokhov 		/* try to get size */
743d05e84e6SDmitry Torokhov 		pkt_len = usbtouch->type->get_pkt_len(
744d05e84e6SDmitry Torokhov 				usbtouch->buffer, usbtouch->buf_len);
745d05e84e6SDmitry Torokhov 
746d05e84e6SDmitry Torokhov 		/* drop? */
747d05e84e6SDmitry Torokhov 		if (unlikely(!pkt_len))
748d05e84e6SDmitry Torokhov 			goto out_flush_buf;
749d05e84e6SDmitry Torokhov 
750d05e84e6SDmitry Torokhov 		/* need to append -pkt_len bytes before able to get size */
751d05e84e6SDmitry Torokhov 		if (unlikely(pkt_len < 0)) {
752d05e84e6SDmitry Torokhov 			int append = -pkt_len;
753d05e84e6SDmitry Torokhov 			if (unlikely(append > len))
754d05e84e6SDmitry Torokhov 			       append = len;
755d05e84e6SDmitry Torokhov 			if (usbtouch->buf_len + append >= usbtouch->type->rept_size)
756d05e84e6SDmitry Torokhov 				goto out_flush_buf;
757d05e84e6SDmitry Torokhov 			memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, append);
758d05e84e6SDmitry Torokhov 			usbtouch->buf_len += append;
759d05e84e6SDmitry Torokhov 
760d05e84e6SDmitry Torokhov 			pkt_len = usbtouch->type->get_pkt_len(
761d05e84e6SDmitry Torokhov 					usbtouch->buffer, usbtouch->buf_len);
762d05e84e6SDmitry Torokhov 			if (pkt_len < 0)
763d05e84e6SDmitry Torokhov 				return;
764d05e84e6SDmitry Torokhov 		}
765d05e84e6SDmitry Torokhov 
766d05e84e6SDmitry Torokhov 		/* append */
767d05e84e6SDmitry Torokhov 		tmp = pkt_len - usbtouch->buf_len;
768d05e84e6SDmitry Torokhov 		if (usbtouch->buf_len + tmp >= usbtouch->type->rept_size)
769d05e84e6SDmitry Torokhov 			goto out_flush_buf;
770d05e84e6SDmitry Torokhov 		memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, tmp);
771d05e84e6SDmitry Torokhov 		usbtouch_process_pkt(usbtouch, usbtouch->buffer, pkt_len);
772d05e84e6SDmitry Torokhov 
773d05e84e6SDmitry Torokhov 		buffer = pkt + tmp;
774d05e84e6SDmitry Torokhov 		buf_len = len - tmp;
775d05e84e6SDmitry Torokhov 	} else {
776d05e84e6SDmitry Torokhov 		buffer = pkt;
777d05e84e6SDmitry Torokhov 		buf_len = len;
778d05e84e6SDmitry Torokhov 	}
779d05e84e6SDmitry Torokhov 
780d05e84e6SDmitry Torokhov 	/* loop over the received packet, process */
781d05e84e6SDmitry Torokhov 	pos = 0;
782d05e84e6SDmitry Torokhov 	while (pos < buf_len) {
783d05e84e6SDmitry Torokhov 		/* get packet len */
78462aa366dSDaniel Ritz 		pkt_len = usbtouch->type->get_pkt_len(buffer + pos,
78562aa366dSDaniel Ritz 							buf_len - pos);
786d05e84e6SDmitry Torokhov 
78762aa366dSDaniel Ritz 		/* unknown packet: skip one byte */
78862aa366dSDaniel Ritz 		if (unlikely(!pkt_len)) {
78962aa366dSDaniel Ritz 			pos++;
79062aa366dSDaniel Ritz 			continue;
79162aa366dSDaniel Ritz 		}
792d05e84e6SDmitry Torokhov 
793d05e84e6SDmitry Torokhov 		/* full packet: process */
794d05e84e6SDmitry Torokhov 		if (likely((pkt_len > 0) && (pkt_len <= buf_len - pos))) {
795d05e84e6SDmitry Torokhov 			usbtouch_process_pkt(usbtouch, buffer + pos, pkt_len);
796d05e84e6SDmitry Torokhov 		} else {
797d05e84e6SDmitry Torokhov 			/* incomplete packet: save in buffer */
798d05e84e6SDmitry Torokhov 			memcpy(usbtouch->buffer, buffer + pos, buf_len - pos);
799d05e84e6SDmitry Torokhov 			usbtouch->buf_len = buf_len - pos;
800d05e84e6SDmitry Torokhov 			return;
801d05e84e6SDmitry Torokhov 		}
802d05e84e6SDmitry Torokhov 		pos += pkt_len;
803d05e84e6SDmitry Torokhov 	}
804d05e84e6SDmitry Torokhov 
805d05e84e6SDmitry Torokhov out_flush_buf:
806d05e84e6SDmitry Torokhov 	usbtouch->buf_len = 0;
807d05e84e6SDmitry Torokhov 	return;
808d05e84e6SDmitry Torokhov }
809d05e84e6SDmitry Torokhov #endif
810d05e84e6SDmitry Torokhov 
811d05e84e6SDmitry Torokhov 
812d05e84e6SDmitry Torokhov static void usbtouch_irq(struct urb *urb)
813d05e84e6SDmitry Torokhov {
814d05e84e6SDmitry Torokhov 	struct usbtouch_usb *usbtouch = urb->context;
815d05e84e6SDmitry Torokhov 	int retval;
816d05e84e6SDmitry Torokhov 
817d05e84e6SDmitry Torokhov 	switch (urb->status) {
818d05e84e6SDmitry Torokhov 	case 0:
819d05e84e6SDmitry Torokhov 		/* success */
820d05e84e6SDmitry Torokhov 		break;
821d05e84e6SDmitry Torokhov 	case -ETIME:
822d05e84e6SDmitry Torokhov 		/* this urb is timing out */
823d05e84e6SDmitry Torokhov 		dbg("%s - urb timed out - was the device unplugged?",
824ea3e6c59SHarvey Harrison 		    __func__);
825d05e84e6SDmitry Torokhov 		return;
826d05e84e6SDmitry Torokhov 	case -ECONNRESET:
827d05e84e6SDmitry Torokhov 	case -ENOENT:
828d05e84e6SDmitry Torokhov 	case -ESHUTDOWN:
829d05e84e6SDmitry Torokhov 		/* this urb is terminated, clean up */
830d05e84e6SDmitry Torokhov 		dbg("%s - urb shutting down with status: %d",
831ea3e6c59SHarvey Harrison 		    __func__, urb->status);
832d05e84e6SDmitry Torokhov 		return;
833d05e84e6SDmitry Torokhov 	default:
834d05e84e6SDmitry Torokhov 		dbg("%s - nonzero urb status received: %d",
835ea3e6c59SHarvey Harrison 		    __func__, urb->status);
836d05e84e6SDmitry Torokhov 		goto exit;
837d05e84e6SDmitry Torokhov 	}
838d05e84e6SDmitry Torokhov 
839d05e84e6SDmitry Torokhov 	usbtouch->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length);
840d05e84e6SDmitry Torokhov 
841d05e84e6SDmitry Torokhov exit:
842d05e84e6SDmitry Torokhov 	retval = usb_submit_urb(urb, GFP_ATOMIC);
843d05e84e6SDmitry Torokhov 	if (retval)
844d05e84e6SDmitry Torokhov 		err("%s - usb_submit_urb failed with result: %d",
845ea3e6c59SHarvey Harrison 		    __func__, retval);
846d05e84e6SDmitry Torokhov }
847d05e84e6SDmitry Torokhov 
848d05e84e6SDmitry Torokhov static int usbtouch_open(struct input_dev *input)
849d05e84e6SDmitry Torokhov {
850d05e84e6SDmitry Torokhov 	struct usbtouch_usb *usbtouch = input_get_drvdata(input);
851d05e84e6SDmitry Torokhov 
852d05e84e6SDmitry Torokhov 	usbtouch->irq->dev = usbtouch->udev;
853d05e84e6SDmitry Torokhov 
854d05e84e6SDmitry Torokhov 	if (usb_submit_urb(usbtouch->irq, GFP_KERNEL))
855d05e84e6SDmitry Torokhov 		return -EIO;
856d05e84e6SDmitry Torokhov 
857d05e84e6SDmitry Torokhov 	return 0;
858d05e84e6SDmitry Torokhov }
859d05e84e6SDmitry Torokhov 
860d05e84e6SDmitry Torokhov static void usbtouch_close(struct input_dev *input)
861d05e84e6SDmitry Torokhov {
862d05e84e6SDmitry Torokhov 	struct usbtouch_usb *usbtouch = input_get_drvdata(input);
863d05e84e6SDmitry Torokhov 
864d05e84e6SDmitry Torokhov 	usb_kill_urb(usbtouch->irq);
865d05e84e6SDmitry Torokhov }
866d05e84e6SDmitry Torokhov 
867d05e84e6SDmitry Torokhov 
868d05e84e6SDmitry Torokhov static void usbtouch_free_buffers(struct usb_device *udev,
869d05e84e6SDmitry Torokhov 				  struct usbtouch_usb *usbtouch)
870d05e84e6SDmitry Torokhov {
871d05e84e6SDmitry Torokhov 	usb_buffer_free(udev, usbtouch->type->rept_size,
872d05e84e6SDmitry Torokhov 	                usbtouch->data, usbtouch->data_dma);
873d05e84e6SDmitry Torokhov 	kfree(usbtouch->buffer);
874d05e84e6SDmitry Torokhov }
875d05e84e6SDmitry Torokhov 
876d05e84e6SDmitry Torokhov 
877d05e84e6SDmitry Torokhov static int usbtouch_probe(struct usb_interface *intf,
878d05e84e6SDmitry Torokhov 			  const struct usb_device_id *id)
879d05e84e6SDmitry Torokhov {
880d05e84e6SDmitry Torokhov 	struct usbtouch_usb *usbtouch;
881d05e84e6SDmitry Torokhov 	struct input_dev *input_dev;
882d05e84e6SDmitry Torokhov 	struct usb_host_interface *interface;
883d05e84e6SDmitry Torokhov 	struct usb_endpoint_descriptor *endpoint;
884d05e84e6SDmitry Torokhov 	struct usb_device *udev = interface_to_usbdev(intf);
885d05e84e6SDmitry Torokhov 	struct usbtouch_device_info *type;
886d05e84e6SDmitry Torokhov 	int err = -ENOMEM;
887d05e84e6SDmitry Torokhov 
888ec42d448SDaniel Ritz 	/* some devices are ignored */
889ec42d448SDaniel Ritz 	if (id->driver_info == DEVTYPE_IGNORE)
890ec42d448SDaniel Ritz 		return -ENODEV;
891ec42d448SDaniel Ritz 
892d05e84e6SDmitry Torokhov 	interface = intf->cur_altsetting;
893d05e84e6SDmitry Torokhov 	endpoint = &interface->endpoint[0].desc;
894d05e84e6SDmitry Torokhov 
895d05e84e6SDmitry Torokhov 	usbtouch = kzalloc(sizeof(struct usbtouch_usb), GFP_KERNEL);
896d05e84e6SDmitry Torokhov 	input_dev = input_allocate_device();
897d05e84e6SDmitry Torokhov 	if (!usbtouch || !input_dev)
898d05e84e6SDmitry Torokhov 		goto out_free;
899d05e84e6SDmitry Torokhov 
900d05e84e6SDmitry Torokhov 	type = &usbtouch_dev_info[id->driver_info];
901d05e84e6SDmitry Torokhov 	usbtouch->type = type;
902d05e84e6SDmitry Torokhov 	if (!type->process_pkt)
903d05e84e6SDmitry Torokhov 		type->process_pkt = usbtouch_process_pkt;
904d05e84e6SDmitry Torokhov 
905d05e84e6SDmitry Torokhov 	usbtouch->data = usb_buffer_alloc(udev, type->rept_size,
906d05e84e6SDmitry Torokhov 	                                  GFP_KERNEL, &usbtouch->data_dma);
907d05e84e6SDmitry Torokhov 	if (!usbtouch->data)
908d05e84e6SDmitry Torokhov 		goto out_free;
909d05e84e6SDmitry Torokhov 
91062aa366dSDaniel Ritz 	if (type->get_pkt_len) {
911d05e84e6SDmitry Torokhov 		usbtouch->buffer = kmalloc(type->rept_size, GFP_KERNEL);
912d05e84e6SDmitry Torokhov 		if (!usbtouch->buffer)
913d05e84e6SDmitry Torokhov 			goto out_free_buffers;
914d05e84e6SDmitry Torokhov 	}
915d05e84e6SDmitry Torokhov 
916d05e84e6SDmitry Torokhov 	usbtouch->irq = usb_alloc_urb(0, GFP_KERNEL);
917d05e84e6SDmitry Torokhov 	if (!usbtouch->irq) {
918ea3e6c59SHarvey Harrison 		dbg("%s - usb_alloc_urb failed: usbtouch->irq", __func__);
919d05e84e6SDmitry Torokhov 		goto out_free_buffers;
920d05e84e6SDmitry Torokhov 	}
921d05e84e6SDmitry Torokhov 
922d05e84e6SDmitry Torokhov 	usbtouch->udev = udev;
923d05e84e6SDmitry Torokhov 	usbtouch->input = input_dev;
924d05e84e6SDmitry Torokhov 
925d05e84e6SDmitry Torokhov 	if (udev->manufacturer)
926d05e84e6SDmitry Torokhov 		strlcpy(usbtouch->name, udev->manufacturer, sizeof(usbtouch->name));
927d05e84e6SDmitry Torokhov 
928d05e84e6SDmitry Torokhov 	if (udev->product) {
929d05e84e6SDmitry Torokhov 		if (udev->manufacturer)
930d05e84e6SDmitry Torokhov 			strlcat(usbtouch->name, " ", sizeof(usbtouch->name));
931d05e84e6SDmitry Torokhov 		strlcat(usbtouch->name, udev->product, sizeof(usbtouch->name));
932d05e84e6SDmitry Torokhov 	}
933d05e84e6SDmitry Torokhov 
934d05e84e6SDmitry Torokhov 	if (!strlen(usbtouch->name))
935d05e84e6SDmitry Torokhov 		snprintf(usbtouch->name, sizeof(usbtouch->name),
936d05e84e6SDmitry Torokhov 			"USB Touchscreen %04x:%04x",
937d05e84e6SDmitry Torokhov 			 le16_to_cpu(udev->descriptor.idVendor),
938d05e84e6SDmitry Torokhov 			 le16_to_cpu(udev->descriptor.idProduct));
939d05e84e6SDmitry Torokhov 
940d05e84e6SDmitry Torokhov 	usb_make_path(udev, usbtouch->phys, sizeof(usbtouch->phys));
9417b6dff98SVladimir Shebordaev 	strlcat(usbtouch->phys, "/input0", sizeof(usbtouch->phys));
942d05e84e6SDmitry Torokhov 
943d05e84e6SDmitry Torokhov 	input_dev->name = usbtouch->name;
944d05e84e6SDmitry Torokhov 	input_dev->phys = usbtouch->phys;
945d05e84e6SDmitry Torokhov 	usb_to_input_id(udev, &input_dev->id);
946d05e84e6SDmitry Torokhov 	input_dev->dev.parent = &intf->dev;
947d05e84e6SDmitry Torokhov 
948d05e84e6SDmitry Torokhov 	input_set_drvdata(input_dev, usbtouch);
949d05e84e6SDmitry Torokhov 
950d05e84e6SDmitry Torokhov 	input_dev->open = usbtouch_open;
951d05e84e6SDmitry Torokhov 	input_dev->close = usbtouch_close;
952d05e84e6SDmitry Torokhov 
9537b19ada2SJiri Slaby 	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
9547b19ada2SJiri Slaby 	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
955d05e84e6SDmitry Torokhov 	input_set_abs_params(input_dev, ABS_X, type->min_xc, type->max_xc, 0, 0);
956d05e84e6SDmitry Torokhov 	input_set_abs_params(input_dev, ABS_Y, type->min_yc, type->max_yc, 0, 0);
957d05e84e6SDmitry Torokhov 	if (type->max_press)
958d05e84e6SDmitry Torokhov 		input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press,
959d05e84e6SDmitry Torokhov 		                     type->max_press, 0, 0);
960d05e84e6SDmitry Torokhov 
961d05e84e6SDmitry Torokhov 	usb_fill_int_urb(usbtouch->irq, usbtouch->udev,
962d05e84e6SDmitry Torokhov 			 usb_rcvintpipe(usbtouch->udev, endpoint->bEndpointAddress),
963d05e84e6SDmitry Torokhov 			 usbtouch->data, type->rept_size,
964d05e84e6SDmitry Torokhov 			 usbtouch_irq, usbtouch, endpoint->bInterval);
965d05e84e6SDmitry Torokhov 
966d05e84e6SDmitry Torokhov 	usbtouch->irq->dev = usbtouch->udev;
967d05e84e6SDmitry Torokhov 	usbtouch->irq->transfer_dma = usbtouch->data_dma;
968d05e84e6SDmitry Torokhov 	usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
969d05e84e6SDmitry Torokhov 
970d05e84e6SDmitry Torokhov 	/* device specific init */
971d05e84e6SDmitry Torokhov 	if (type->init) {
972d05e84e6SDmitry Torokhov 		err = type->init(usbtouch);
973d05e84e6SDmitry Torokhov 		if (err) {
974ea3e6c59SHarvey Harrison 			dbg("%s - type->init() failed, err: %d", __func__, err);
975d05e84e6SDmitry Torokhov 			goto out_free_buffers;
976d05e84e6SDmitry Torokhov 		}
977d05e84e6SDmitry Torokhov 	}
978d05e84e6SDmitry Torokhov 
979d05e84e6SDmitry Torokhov 	err = input_register_device(usbtouch->input);
980d05e84e6SDmitry Torokhov 	if (err) {
981ea3e6c59SHarvey Harrison 		dbg("%s - input_register_device failed, err: %d", __func__, err);
982d05e84e6SDmitry Torokhov 		goto out_free_buffers;
983d05e84e6SDmitry Torokhov 	}
984d05e84e6SDmitry Torokhov 
985d05e84e6SDmitry Torokhov 	usb_set_intfdata(intf, usbtouch);
986d05e84e6SDmitry Torokhov 
987d05e84e6SDmitry Torokhov 	return 0;
988d05e84e6SDmitry Torokhov 
989d05e84e6SDmitry Torokhov out_free_buffers:
990d05e84e6SDmitry Torokhov 	usbtouch_free_buffers(udev, usbtouch);
991d05e84e6SDmitry Torokhov out_free:
992d05e84e6SDmitry Torokhov 	input_free_device(input_dev);
993d05e84e6SDmitry Torokhov 	kfree(usbtouch);
994d05e84e6SDmitry Torokhov 	return err;
995d05e84e6SDmitry Torokhov }
996d05e84e6SDmitry Torokhov 
997d05e84e6SDmitry Torokhov static void usbtouch_disconnect(struct usb_interface *intf)
998d05e84e6SDmitry Torokhov {
999d05e84e6SDmitry Torokhov 	struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
1000d05e84e6SDmitry Torokhov 
1001ea3e6c59SHarvey Harrison 	dbg("%s - called", __func__);
1002d05e84e6SDmitry Torokhov 
1003d05e84e6SDmitry Torokhov 	if (!usbtouch)
1004d05e84e6SDmitry Torokhov 		return;
1005d05e84e6SDmitry Torokhov 
1006ea3e6c59SHarvey Harrison 	dbg("%s - usbtouch is initialized, cleaning up", __func__);
1007d05e84e6SDmitry Torokhov 	usb_set_intfdata(intf, NULL);
1008d05e84e6SDmitry Torokhov 	usb_kill_urb(usbtouch->irq);
1009d05e84e6SDmitry Torokhov 	input_unregister_device(usbtouch->input);
1010d05e84e6SDmitry Torokhov 	usb_free_urb(usbtouch->irq);
1011d05e84e6SDmitry Torokhov 	usbtouch_free_buffers(interface_to_usbdev(intf), usbtouch);
1012d05e84e6SDmitry Torokhov 	kfree(usbtouch);
1013d05e84e6SDmitry Torokhov }
1014d05e84e6SDmitry Torokhov 
1015d05e84e6SDmitry Torokhov MODULE_DEVICE_TABLE(usb, usbtouch_devices);
1016d05e84e6SDmitry Torokhov 
1017d05e84e6SDmitry Torokhov static struct usb_driver usbtouch_driver = {
1018d05e84e6SDmitry Torokhov 	.name		= "usbtouchscreen",
1019d05e84e6SDmitry Torokhov 	.probe		= usbtouch_probe,
1020d05e84e6SDmitry Torokhov 	.disconnect	= usbtouch_disconnect,
1021d05e84e6SDmitry Torokhov 	.id_table	= usbtouch_devices,
1022d05e84e6SDmitry Torokhov };
1023d05e84e6SDmitry Torokhov 
1024d05e84e6SDmitry Torokhov static int __init usbtouch_init(void)
1025d05e84e6SDmitry Torokhov {
1026d05e84e6SDmitry Torokhov 	return usb_register(&usbtouch_driver);
1027d05e84e6SDmitry Torokhov }
1028d05e84e6SDmitry Torokhov 
1029d05e84e6SDmitry Torokhov static void __exit usbtouch_cleanup(void)
1030d05e84e6SDmitry Torokhov {
1031d05e84e6SDmitry Torokhov 	usb_deregister(&usbtouch_driver);
1032d05e84e6SDmitry Torokhov }
1033d05e84e6SDmitry Torokhov 
1034d05e84e6SDmitry Torokhov module_init(usbtouch_init);
1035d05e84e6SDmitry Torokhov module_exit(usbtouch_cleanup);
1036d05e84e6SDmitry Torokhov 
1037d05e84e6SDmitry Torokhov MODULE_AUTHOR(DRIVER_AUTHOR);
1038d05e84e6SDmitry Torokhov MODULE_DESCRIPTION(DRIVER_DESC);
1039d05e84e6SDmitry Torokhov MODULE_LICENSE("GPL");
1040d05e84e6SDmitry Torokhov 
1041d05e84e6SDmitry Torokhov MODULE_ALIAS("touchkitusb");
1042d05e84e6SDmitry Torokhov MODULE_ALIAS("itmtouch");
1043d05e84e6SDmitry Torokhov MODULE_ALIAS("mtouchusb");
1044