xref: /linux/drivers/input/touchscreen/usbtouchscreen.c (revision 9e3b25837a20f4d48fef57b0cb8bf750a8cfa8e2)
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
16f7370699SJim Persson  *  - JASTEC USB touch controller/DigiTech DTR-02U
17d05e84e6SDmitry Torokhov  *
1814e40206SJerrold Jones  * Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch>
19d05e84e6SDmitry Torokhov  * Copyright (C) by Todd E. Johnson (mtouchusb.c)
20d05e84e6SDmitry Torokhov  *
21d05e84e6SDmitry Torokhov  * This program is free software; you can redistribute it and/or
22d05e84e6SDmitry Torokhov  * modify it under the terms of the GNU General Public License as
23d05e84e6SDmitry Torokhov  * published by the Free Software Foundation; either version 2 of the
24d05e84e6SDmitry Torokhov  * License, or (at your option) any later version.
25d05e84e6SDmitry Torokhov  *
26d05e84e6SDmitry Torokhov  * This program is distributed in the hope that it will be useful, but
27d05e84e6SDmitry Torokhov  * WITHOUT ANY WARRANTY; without even the implied warranty of
28d05e84e6SDmitry Torokhov  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
29d05e84e6SDmitry Torokhov  * General Public License for more details.
30d05e84e6SDmitry Torokhov  *
31d05e84e6SDmitry Torokhov  * You should have received a copy of the GNU General Public License
32d05e84e6SDmitry Torokhov  * along with this program; if not, write to the Free Software
33d05e84e6SDmitry Torokhov  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
34d05e84e6SDmitry Torokhov  *
35d05e84e6SDmitry Torokhov  * Driver is based on touchkitusb.c
36d05e84e6SDmitry Torokhov  * - ITM parts are from itmtouch.c
37d05e84e6SDmitry Torokhov  * - 3M parts are from mtouchusb.c
38d05e84e6SDmitry Torokhov  * - PanJit parts are from an unmerged driver by Lanslott Gish
39d05e84e6SDmitry Torokhov  * - DMC TSC 10/25 are from Holger Schurig, with ideas from an unmerged
40d05e84e6SDmitry Torokhov  *   driver from Marius Vollmer
41d05e84e6SDmitry Torokhov  *
42d05e84e6SDmitry Torokhov  *****************************************************************************/
43d05e84e6SDmitry Torokhov 
44d05e84e6SDmitry Torokhov //#define DEBUG
45d05e84e6SDmitry Torokhov 
46d05e84e6SDmitry Torokhov #include <linux/kernel.h>
47d05e84e6SDmitry Torokhov #include <linux/slab.h>
48d05e84e6SDmitry Torokhov #include <linux/input.h>
49d05e84e6SDmitry Torokhov #include <linux/module.h>
50d05e84e6SDmitry Torokhov #include <linux/init.h>
51d05e84e6SDmitry Torokhov #include <linux/usb.h>
52d05e84e6SDmitry Torokhov #include <linux/usb/input.h>
53ec42d448SDaniel Ritz #include <linux/hid.h>
54d05e84e6SDmitry Torokhov 
55d05e84e6SDmitry Torokhov 
5662aa366dSDaniel Ritz #define DRIVER_VERSION		"v0.6"
57d05e84e6SDmitry Torokhov #define DRIVER_AUTHOR		"Daniel Ritz <daniel.ritz@gmx.ch>"
58d05e84e6SDmitry Torokhov #define DRIVER_DESC		"USB Touchscreen Driver"
59d05e84e6SDmitry Torokhov 
60d05e84e6SDmitry Torokhov static int swap_xy;
61d05e84e6SDmitry Torokhov module_param(swap_xy, bool, 0644);
62d05e84e6SDmitry Torokhov MODULE_PARM_DESC(swap_xy, "If set X and Y axes are swapped.");
63d05e84e6SDmitry Torokhov 
64c9cbf3d3SDan Streetman static int hwcalib_xy;
65c9cbf3d3SDan Streetman module_param(hwcalib_xy, bool, 0644);
66c9cbf3d3SDan Streetman MODULE_PARM_DESC(hwcalib_xy, "If set hw-calibrated X/Y are used if available");
67c9cbf3d3SDan Streetman 
68d05e84e6SDmitry Torokhov /* device specifc data/functions */
69d05e84e6SDmitry Torokhov struct usbtouch_usb;
70d05e84e6SDmitry Torokhov struct usbtouch_device_info {
71d05e84e6SDmitry Torokhov 	int min_xc, max_xc;
72d05e84e6SDmitry Torokhov 	int min_yc, max_yc;
73d05e84e6SDmitry Torokhov 	int min_press, max_press;
74d05e84e6SDmitry Torokhov 	int rept_size;
75d05e84e6SDmitry Torokhov 
76d05e84e6SDmitry Torokhov 	void (*process_pkt) (struct usbtouch_usb *usbtouch, unsigned char *pkt, int len);
7762aa366dSDaniel Ritz 
7862aa366dSDaniel Ritz 	/*
7962aa366dSDaniel Ritz 	 * used to get the packet len. possible return values:
8062aa366dSDaniel Ritz 	 * > 0: packet len
8162aa366dSDaniel Ritz 	 * = 0: skip one byte
8262aa366dSDaniel Ritz 	 * < 0: -return value more bytes needed
8362aa366dSDaniel Ritz 	 */
84d05e84e6SDmitry Torokhov 	int  (*get_pkt_len) (unsigned char *pkt, int len);
8562aa366dSDaniel Ritz 
86d05e84e6SDmitry Torokhov 	int  (*read_data)   (struct usbtouch_usb *usbtouch, unsigned char *pkt);
87d05e84e6SDmitry Torokhov 	int  (*init)        (struct usbtouch_usb *usbtouch);
88d05e84e6SDmitry Torokhov };
89d05e84e6SDmitry Torokhov 
90d05e84e6SDmitry Torokhov /* a usbtouch device */
91d05e84e6SDmitry Torokhov struct usbtouch_usb {
92d05e84e6SDmitry Torokhov 	unsigned char *data;
93d05e84e6SDmitry Torokhov 	dma_addr_t data_dma;
94d05e84e6SDmitry Torokhov 	unsigned char *buffer;
95d05e84e6SDmitry Torokhov 	int buf_len;
96d05e84e6SDmitry Torokhov 	struct urb *irq;
97d05e84e6SDmitry Torokhov 	struct usb_device *udev;
98d05e84e6SDmitry Torokhov 	struct input_dev *input;
99d05e84e6SDmitry Torokhov 	struct usbtouch_device_info *type;
100d05e84e6SDmitry Torokhov 	char name[128];
101d05e84e6SDmitry Torokhov 	char phys[64];
102d05e84e6SDmitry Torokhov 
103d05e84e6SDmitry Torokhov 	int x, y;
104d05e84e6SDmitry Torokhov 	int touch, press;
105d05e84e6SDmitry Torokhov };
106d05e84e6SDmitry Torokhov 
107d05e84e6SDmitry Torokhov 
108d05e84e6SDmitry Torokhov /* device types */
109d05e84e6SDmitry Torokhov enum {
110ec42d448SDaniel Ritz 	DEVTYPE_IGNORE = -1,
111d05e84e6SDmitry Torokhov 	DEVTYPE_EGALAX,
112d05e84e6SDmitry Torokhov 	DEVTYPE_PANJIT,
113d05e84e6SDmitry Torokhov 	DEVTYPE_3M,
114d05e84e6SDmitry Torokhov 	DEVTYPE_ITM,
115d05e84e6SDmitry Torokhov 	DEVTYPE_ETURBO,
116d05e84e6SDmitry Torokhov 	DEVTYPE_GUNZE,
117d05e84e6SDmitry Torokhov 	DEVTYPE_DMC_TSC10,
118df561fcdSOndrej Zary 	DEVTYPE_IRTOUCH,
119a14a8401SOndrej Zary 	DEVTYPE_IDEALTEK,
1209d5657dbSIlya Frolov 	DEVTYPE_GENERAL_TOUCH,
12114e40206SJerrold Jones 	DEVTYPE_GOTOP,
122f7370699SJim Persson 	DEVTYPE_JASTEC,
123*9e3b2583SFlorian Echtler 	DEVTYPE_E2I,
124d05e84e6SDmitry Torokhov };
125d05e84e6SDmitry Torokhov 
126ec42d448SDaniel Ritz #define USB_DEVICE_HID_CLASS(vend, prod) \
127ec42d448SDaniel Ritz 	.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS \
128139ebe8dSDaniel Ritz 		| USB_DEVICE_ID_MATCH_INT_PROTOCOL \
129ec42d448SDaniel Ritz 		| USB_DEVICE_ID_MATCH_DEVICE, \
130ec42d448SDaniel Ritz 	.idVendor = (vend), \
131ec42d448SDaniel Ritz 	.idProduct = (prod), \
132ec42d448SDaniel Ritz 	.bInterfaceClass = USB_INTERFACE_CLASS_HID, \
133ec42d448SDaniel Ritz 	.bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE
134ec42d448SDaniel Ritz 
135d05e84e6SDmitry Torokhov static struct usb_device_id usbtouch_devices[] = {
136c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
137ec42d448SDaniel Ritz 	/* ignore the HID capable devices, handled by usbhid */
138ec42d448SDaniel Ritz 	{USB_DEVICE_HID_CLASS(0x0eef, 0x0001), .driver_info = DEVTYPE_IGNORE},
139ec42d448SDaniel Ritz 	{USB_DEVICE_HID_CLASS(0x0eef, 0x0002), .driver_info = DEVTYPE_IGNORE},
140ec42d448SDaniel Ritz 
141ec42d448SDaniel Ritz 	/* normal device IDs */
142d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x3823, 0x0001), .driver_info = DEVTYPE_EGALAX},
143d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x3823, 0x0002), .driver_info = DEVTYPE_EGALAX},
144d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x0123, 0x0001), .driver_info = DEVTYPE_EGALAX},
145d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x0eef, 0x0001), .driver_info = DEVTYPE_EGALAX},
146d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x0eef, 0x0002), .driver_info = DEVTYPE_EGALAX},
147d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x1234, 0x0001), .driver_info = DEVTYPE_EGALAX},
148d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x1234, 0x0002), .driver_info = DEVTYPE_EGALAX},
149d05e84e6SDmitry Torokhov #endif
150d05e84e6SDmitry Torokhov 
151c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_PANJIT
152d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x134c, 0x0001), .driver_info = DEVTYPE_PANJIT},
153d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x134c, 0x0002), .driver_info = DEVTYPE_PANJIT},
154d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x134c, 0x0003), .driver_info = DEVTYPE_PANJIT},
155d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x134c, 0x0004), .driver_info = DEVTYPE_PANJIT},
156d05e84e6SDmitry Torokhov #endif
157d05e84e6SDmitry Torokhov 
158c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_3M
159d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x0596, 0x0001), .driver_info = DEVTYPE_3M},
160d05e84e6SDmitry Torokhov #endif
161d05e84e6SDmitry Torokhov 
162c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_ITM
163d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x0403, 0xf9e9), .driver_info = DEVTYPE_ITM},
164d05e84e6SDmitry Torokhov #endif
165d05e84e6SDmitry Torokhov 
166c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_ETURBO
167d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x1234, 0x5678), .driver_info = DEVTYPE_ETURBO},
168d05e84e6SDmitry Torokhov #endif
169d05e84e6SDmitry Torokhov 
170c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_GUNZE
171d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x0637, 0x0001), .driver_info = DEVTYPE_GUNZE},
172d05e84e6SDmitry Torokhov #endif
173d05e84e6SDmitry Torokhov 
174c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_DMC_TSC10
175d05e84e6SDmitry Torokhov 	{USB_DEVICE(0x0afa, 0x03e8), .driver_info = DEVTYPE_DMC_TSC10},
176d05e84e6SDmitry Torokhov #endif
177d05e84e6SDmitry Torokhov 
178df561fcdSOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH
179df561fcdSOndrej Zary 	{USB_DEVICE(0x595a, 0x0001), .driver_info = DEVTYPE_IRTOUCH},
180df561fcdSOndrej Zary 	{USB_DEVICE(0x6615, 0x0001), .driver_info = DEVTYPE_IRTOUCH},
181df561fcdSOndrej Zary #endif
182df561fcdSOndrej Zary 
183a14a8401SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
184a14a8401SOndrej Zary 	{USB_DEVICE(0x1391, 0x1000), .driver_info = DEVTYPE_IDEALTEK},
185a14a8401SOndrej Zary #endif
186a14a8401SOndrej Zary 
1879d5657dbSIlya Frolov #ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
1889d5657dbSIlya Frolov 	{USB_DEVICE(0x0dfc, 0x0001), .driver_info = DEVTYPE_GENERAL_TOUCH},
1899d5657dbSIlya Frolov #endif
1909d5657dbSIlya Frolov 
19114e40206SJerrold Jones #ifdef CONFIG_TOUCHSCREEN_USB_GOTOP
19214e40206SJerrold Jones 	{USB_DEVICE(0x08f2, 0x007f), .driver_info = DEVTYPE_GOTOP},
19314e40206SJerrold Jones 	{USB_DEVICE(0x08f2, 0x00ce), .driver_info = DEVTYPE_GOTOP},
19414e40206SJerrold Jones 	{USB_DEVICE(0x08f2, 0x00f4), .driver_info = DEVTYPE_GOTOP},
19514e40206SJerrold Jones #endif
19614e40206SJerrold Jones 
197f7370699SJim Persson #ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
198f7370699SJim Persson 	{USB_DEVICE(0x0f92, 0x0001), .driver_info = DEVTYPE_JASTEC},
199f7370699SJim Persson #endif
200f7370699SJim Persson 
201*9e3b2583SFlorian Echtler #ifdef CONFIG_TOUCHSCREEN_USB_E2I
202*9e3b2583SFlorian Echtler 	{USB_DEVICE(0x1ac7, 0x0001), .driver_info = DEVTYPE_E2I},
203*9e3b2583SFlorian Echtler #endif
204d05e84e6SDmitry Torokhov 	{}
205d05e84e6SDmitry Torokhov };
206d05e84e6SDmitry Torokhov 
207d05e84e6SDmitry Torokhov 
208d05e84e6SDmitry Torokhov /*****************************************************************************
209*9e3b2583SFlorian Echtler  * e2i Part
210*9e3b2583SFlorian Echtler  */
211*9e3b2583SFlorian Echtler 
212*9e3b2583SFlorian Echtler #ifdef CONFIG_TOUCHSCREEN_USB_E2I
213*9e3b2583SFlorian Echtler static int e2i_init(struct usbtouch_usb *usbtouch)
214*9e3b2583SFlorian Echtler {
215*9e3b2583SFlorian Echtler 	int ret;
216*9e3b2583SFlorian Echtler 
217*9e3b2583SFlorian Echtler 	ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
218*9e3b2583SFlorian Echtler 	                      0x01, 0x02, 0x0000, 0x0081,
219*9e3b2583SFlorian Echtler 	                      NULL, 0, USB_CTRL_SET_TIMEOUT);
220*9e3b2583SFlorian Echtler 
221*9e3b2583SFlorian Echtler 	dbg("%s - usb_control_msg - E2I_RESET - bytes|err: %d",
222*9e3b2583SFlorian Echtler 	    __func__, ret);
223*9e3b2583SFlorian Echtler 	return ret;
224*9e3b2583SFlorian Echtler }
225*9e3b2583SFlorian Echtler 
226*9e3b2583SFlorian Echtler static int e2i_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
227*9e3b2583SFlorian Echtler {
228*9e3b2583SFlorian Echtler 	int tmp = (pkt[0] << 8) | pkt[1];
229*9e3b2583SFlorian Echtler 	dev->x  = (pkt[2] << 8) | pkt[3];
230*9e3b2583SFlorian Echtler 	dev->y  = (pkt[4] << 8) | pkt[5];
231*9e3b2583SFlorian Echtler 
232*9e3b2583SFlorian Echtler 	tmp = tmp - 0xA000;
233*9e3b2583SFlorian Echtler 	dev->touch = (tmp > 0);
234*9e3b2583SFlorian Echtler 	dev->press = (tmp > 0 ? tmp : 0);
235*9e3b2583SFlorian Echtler 
236*9e3b2583SFlorian Echtler 	return 1;
237*9e3b2583SFlorian Echtler }
238*9e3b2583SFlorian Echtler #endif
239*9e3b2583SFlorian Echtler 
240*9e3b2583SFlorian Echtler 
241*9e3b2583SFlorian Echtler /*****************************************************************************
242d05e84e6SDmitry Torokhov  * eGalax part
243d05e84e6SDmitry Torokhov  */
244d05e84e6SDmitry Torokhov 
245c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
246d05e84e6SDmitry Torokhov 
24762aa366dSDaniel Ritz #ifndef MULTI_PACKET
24862aa366dSDaniel Ritz #define MULTI_PACKET
24962aa366dSDaniel Ritz #endif
25062aa366dSDaniel Ritz 
251d05e84e6SDmitry Torokhov #define EGALAX_PKT_TYPE_MASK		0xFE
252d05e84e6SDmitry Torokhov #define EGALAX_PKT_TYPE_REPT		0x80
253d05e84e6SDmitry Torokhov #define EGALAX_PKT_TYPE_DIAG		0x0A
254d05e84e6SDmitry Torokhov 
255d05e84e6SDmitry Torokhov static int egalax_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
256d05e84e6SDmitry Torokhov {
257d05e84e6SDmitry Torokhov 	if ((pkt[0] & EGALAX_PKT_TYPE_MASK) != EGALAX_PKT_TYPE_REPT)
258d05e84e6SDmitry Torokhov 		return 0;
259d05e84e6SDmitry Torokhov 
260d05e84e6SDmitry Torokhov 	dev->x = ((pkt[3] & 0x0F) << 7) | (pkt[4] & 0x7F);
261d05e84e6SDmitry Torokhov 	dev->y = ((pkt[1] & 0x0F) << 7) | (pkt[2] & 0x7F);
262d05e84e6SDmitry Torokhov 	dev->touch = pkt[0] & 0x01;
263d05e84e6SDmitry Torokhov 
264d05e84e6SDmitry Torokhov 	return 1;
265d05e84e6SDmitry Torokhov }
266d05e84e6SDmitry Torokhov 
267d05e84e6SDmitry Torokhov static int egalax_get_pkt_len(unsigned char *buf, int len)
268d05e84e6SDmitry Torokhov {
269d05e84e6SDmitry Torokhov 	switch (buf[0] & EGALAX_PKT_TYPE_MASK) {
270d05e84e6SDmitry Torokhov 	case EGALAX_PKT_TYPE_REPT:
271d05e84e6SDmitry Torokhov 		return 5;
272d05e84e6SDmitry Torokhov 
273d05e84e6SDmitry Torokhov 	case EGALAX_PKT_TYPE_DIAG:
274d05e84e6SDmitry Torokhov 		if (len < 2)
275d05e84e6SDmitry Torokhov 			return -1;
276d05e84e6SDmitry Torokhov 
277d05e84e6SDmitry Torokhov 		return buf[1] + 2;
278d05e84e6SDmitry Torokhov 	}
279d05e84e6SDmitry Torokhov 
280d05e84e6SDmitry Torokhov 	return 0;
281d05e84e6SDmitry Torokhov }
282d05e84e6SDmitry Torokhov #endif
283d05e84e6SDmitry Torokhov 
284d05e84e6SDmitry Torokhov 
285d05e84e6SDmitry Torokhov /*****************************************************************************
286d05e84e6SDmitry Torokhov  * PanJit Part
287d05e84e6SDmitry Torokhov  */
288c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_PANJIT
289d05e84e6SDmitry Torokhov static int panjit_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
290d05e84e6SDmitry Torokhov {
291d05e84e6SDmitry Torokhov 	dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1];
292d05e84e6SDmitry Torokhov 	dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3];
293d05e84e6SDmitry Torokhov 	dev->touch = pkt[0] & 0x01;
294d05e84e6SDmitry Torokhov 
295d05e84e6SDmitry Torokhov 	return 1;
296d05e84e6SDmitry Torokhov }
297d05e84e6SDmitry Torokhov #endif
298d05e84e6SDmitry Torokhov 
299d05e84e6SDmitry Torokhov 
300d05e84e6SDmitry Torokhov /*****************************************************************************
301d05e84e6SDmitry Torokhov  * 3M/Microtouch Part
302d05e84e6SDmitry Torokhov  */
303c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_3M
304d05e84e6SDmitry Torokhov 
305d05e84e6SDmitry Torokhov #define MTOUCHUSB_ASYNC_REPORT          1
306d05e84e6SDmitry Torokhov #define MTOUCHUSB_RESET                 7
307d05e84e6SDmitry Torokhov #define MTOUCHUSB_REQ_CTRLLR_ID         10
308d05e84e6SDmitry Torokhov 
309d05e84e6SDmitry Torokhov static int mtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
310d05e84e6SDmitry Torokhov {
311c9cbf3d3SDan Streetman 	if (hwcalib_xy) {
312c9cbf3d3SDan Streetman 		dev->x = (pkt[4] << 8) | pkt[3];
313c9cbf3d3SDan Streetman 		dev->y = 0xffff - ((pkt[6] << 8) | pkt[5]);
314c9cbf3d3SDan Streetman 	} else {
315d05e84e6SDmitry Torokhov 		dev->x = (pkt[8] << 8) | pkt[7];
316d05e84e6SDmitry Torokhov 		dev->y = (pkt[10] << 8) | pkt[9];
317c9cbf3d3SDan Streetman 	}
318d05e84e6SDmitry Torokhov 	dev->touch = (pkt[2] & 0x40) ? 1 : 0;
319d05e84e6SDmitry Torokhov 
320d05e84e6SDmitry Torokhov 	return 1;
321d05e84e6SDmitry Torokhov }
322d05e84e6SDmitry Torokhov 
323d05e84e6SDmitry Torokhov static int mtouch_init(struct usbtouch_usb *usbtouch)
324d05e84e6SDmitry Torokhov {
325d05e84e6SDmitry Torokhov 	int ret, i;
326d05e84e6SDmitry Torokhov 
327d05e84e6SDmitry Torokhov 	ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
328d05e84e6SDmitry Torokhov 	                      MTOUCHUSB_RESET,
329d05e84e6SDmitry Torokhov 	                      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
330d05e84e6SDmitry Torokhov 	                      1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
331d05e84e6SDmitry Torokhov 	dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d",
332ea3e6c59SHarvey Harrison 	    __func__, ret);
333d05e84e6SDmitry Torokhov 	if (ret < 0)
334d05e84e6SDmitry Torokhov 		return ret;
335d05e84e6SDmitry Torokhov 	msleep(150);
336d05e84e6SDmitry Torokhov 
337d05e84e6SDmitry Torokhov 	for (i = 0; i < 3; i++) {
338d05e84e6SDmitry Torokhov 		ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
339d05e84e6SDmitry Torokhov 				      MTOUCHUSB_ASYNC_REPORT,
340d05e84e6SDmitry Torokhov 				      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
341d05e84e6SDmitry Torokhov 				      1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT);
342d05e84e6SDmitry Torokhov 		dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d",
343ea3e6c59SHarvey Harrison 		    __func__, ret);
344d05e84e6SDmitry Torokhov 		if (ret >= 0)
345d05e84e6SDmitry Torokhov 			break;
346d05e84e6SDmitry Torokhov 		if (ret != -EPIPE)
347d05e84e6SDmitry Torokhov 			return ret;
348d05e84e6SDmitry Torokhov 	}
349d05e84e6SDmitry Torokhov 
350c9cbf3d3SDan Streetman 	/* Default min/max xy are the raw values, override if using hw-calib */
351c9cbf3d3SDan Streetman 	if (hwcalib_xy) {
352c9cbf3d3SDan Streetman 		input_set_abs_params(usbtouch->input, ABS_X, 0, 0xffff, 0, 0);
353c9cbf3d3SDan Streetman 		input_set_abs_params(usbtouch->input, ABS_Y, 0, 0xffff, 0, 0);
354c9cbf3d3SDan Streetman 	}
355c9cbf3d3SDan Streetman 
356d05e84e6SDmitry Torokhov 	return 0;
357d05e84e6SDmitry Torokhov }
358d05e84e6SDmitry Torokhov #endif
359d05e84e6SDmitry Torokhov 
360d05e84e6SDmitry Torokhov 
361d05e84e6SDmitry Torokhov /*****************************************************************************
362d05e84e6SDmitry Torokhov  * ITM Part
363d05e84e6SDmitry Torokhov  */
364c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_ITM
365d05e84e6SDmitry Torokhov static int itm_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
366d05e84e6SDmitry Torokhov {
367d05e84e6SDmitry Torokhov 	int touch;
368d05e84e6SDmitry Torokhov 	/*
369d05e84e6SDmitry Torokhov 	 * ITM devices report invalid x/y data if not touched.
370d05e84e6SDmitry Torokhov 	 * if the screen was touched before but is not touched any more
371d05e84e6SDmitry Torokhov 	 * report touch as 0 with the last valid x/y data once. then stop
372d05e84e6SDmitry Torokhov 	 * reporting data until touched again.
373d05e84e6SDmitry Torokhov 	 */
374d05e84e6SDmitry Torokhov 	dev->press = ((pkt[2] & 0x01) << 7) | (pkt[5] & 0x7F);
375d05e84e6SDmitry Torokhov 
376d05e84e6SDmitry Torokhov 	touch = ~pkt[7] & 0x20;
377d05e84e6SDmitry Torokhov 	if (!touch) {
378d05e84e6SDmitry Torokhov 		if (dev->touch) {
379d05e84e6SDmitry Torokhov 			dev->touch = 0;
380d05e84e6SDmitry Torokhov 			return 1;
381d05e84e6SDmitry Torokhov 		}
382d05e84e6SDmitry Torokhov 
383d05e84e6SDmitry Torokhov 		return 0;
384d05e84e6SDmitry Torokhov 	}
385d05e84e6SDmitry Torokhov 
386d05e84e6SDmitry Torokhov 	dev->x = ((pkt[0] & 0x1F) << 7) | (pkt[3] & 0x7F);
387d05e84e6SDmitry Torokhov 	dev->y = ((pkt[1] & 0x1F) << 7) | (pkt[4] & 0x7F);
388d05e84e6SDmitry Torokhov 	dev->touch = touch;
389d05e84e6SDmitry Torokhov 
390d05e84e6SDmitry Torokhov 	return 1;
391d05e84e6SDmitry Torokhov }
392d05e84e6SDmitry Torokhov #endif
393d05e84e6SDmitry Torokhov 
394d05e84e6SDmitry Torokhov 
395d05e84e6SDmitry Torokhov /*****************************************************************************
396d05e84e6SDmitry Torokhov  * eTurboTouch part
397d05e84e6SDmitry Torokhov  */
398c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_ETURBO
39962aa366dSDaniel Ritz #ifndef MULTI_PACKET
40062aa366dSDaniel Ritz #define MULTI_PACKET
40162aa366dSDaniel Ritz #endif
402d05e84e6SDmitry Torokhov static int eturbo_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
403d05e84e6SDmitry Torokhov {
404d05e84e6SDmitry Torokhov 	unsigned int shift;
405d05e84e6SDmitry Torokhov 
406d05e84e6SDmitry Torokhov 	/* packets should start with sync */
407d05e84e6SDmitry Torokhov 	if (!(pkt[0] & 0x80))
408d05e84e6SDmitry Torokhov 		return 0;
409d05e84e6SDmitry Torokhov 
410d05e84e6SDmitry Torokhov 	shift = (6 - (pkt[0] & 0x03));
411d05e84e6SDmitry Torokhov 	dev->x = ((pkt[3] << 7) | pkt[4]) >> shift;
412d05e84e6SDmitry Torokhov 	dev->y = ((pkt[1] << 7) | pkt[2]) >> shift;
413d05e84e6SDmitry Torokhov 	dev->touch = (pkt[0] & 0x10) ? 1 : 0;
414d05e84e6SDmitry Torokhov 
415d05e84e6SDmitry Torokhov 	return 1;
416d05e84e6SDmitry Torokhov }
417d05e84e6SDmitry Torokhov 
418d05e84e6SDmitry Torokhov static int eturbo_get_pkt_len(unsigned char *buf, int len)
419d05e84e6SDmitry Torokhov {
420d05e84e6SDmitry Torokhov 	if (buf[0] & 0x80)
421d05e84e6SDmitry Torokhov 		return 5;
422d05e84e6SDmitry Torokhov 	if (buf[0] == 0x01)
423d05e84e6SDmitry Torokhov 		return 3;
424d05e84e6SDmitry Torokhov 	return 0;
425d05e84e6SDmitry Torokhov }
426d05e84e6SDmitry Torokhov #endif
427d05e84e6SDmitry Torokhov 
428d05e84e6SDmitry Torokhov 
429d05e84e6SDmitry Torokhov /*****************************************************************************
430d05e84e6SDmitry Torokhov  * Gunze part
431d05e84e6SDmitry Torokhov  */
432c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_GUNZE
433d05e84e6SDmitry Torokhov static int gunze_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
434d05e84e6SDmitry Torokhov {
435d05e84e6SDmitry Torokhov 	if (!(pkt[0] & 0x80) || ((pkt[1] | pkt[2] | pkt[3]) & 0x80))
436d05e84e6SDmitry Torokhov 		return 0;
437d05e84e6SDmitry Torokhov 
438d05e84e6SDmitry Torokhov 	dev->x = ((pkt[0] & 0x1F) << 7) | (pkt[2] & 0x7F);
439d05e84e6SDmitry Torokhov 	dev->y = ((pkt[1] & 0x1F) << 7) | (pkt[3] & 0x7F);
440d05e84e6SDmitry Torokhov 	dev->touch = pkt[0] & 0x20;
441d05e84e6SDmitry Torokhov 
442d05e84e6SDmitry Torokhov 	return 1;
443d05e84e6SDmitry Torokhov }
444d05e84e6SDmitry Torokhov #endif
445d05e84e6SDmitry Torokhov 
446d05e84e6SDmitry Torokhov /*****************************************************************************
447d05e84e6SDmitry Torokhov  * DMC TSC-10/25 Part
448d05e84e6SDmitry Torokhov  *
449d05e84e6SDmitry Torokhov  * Documentation about the controller and it's protocol can be found at
450d05e84e6SDmitry Torokhov  *   http://www.dmccoltd.com/files/controler/tsc10usb_pi_e.pdf
451d05e84e6SDmitry Torokhov  *   http://www.dmccoltd.com/files/controler/tsc25_usb_e.pdf
452d05e84e6SDmitry Torokhov  */
453c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_DMC_TSC10
454d05e84e6SDmitry Torokhov 
455d05e84e6SDmitry Torokhov /* supported data rates. currently using 130 */
456d05e84e6SDmitry Torokhov #define TSC10_RATE_POINT	0x50
457d05e84e6SDmitry Torokhov #define TSC10_RATE_30		0x40
458d05e84e6SDmitry Torokhov #define TSC10_RATE_50		0x41
459d05e84e6SDmitry Torokhov #define TSC10_RATE_80		0x42
460d05e84e6SDmitry Torokhov #define TSC10_RATE_100		0x43
461d05e84e6SDmitry Torokhov #define TSC10_RATE_130		0x44
462d05e84e6SDmitry Torokhov #define TSC10_RATE_150		0x45
463d05e84e6SDmitry Torokhov 
464d05e84e6SDmitry Torokhov /* commands */
465d05e84e6SDmitry Torokhov #define TSC10_CMD_RESET		0x55
466d05e84e6SDmitry Torokhov #define TSC10_CMD_RATE		0x05
467d05e84e6SDmitry Torokhov #define TSC10_CMD_DATA1		0x01
468d05e84e6SDmitry Torokhov 
469d05e84e6SDmitry Torokhov static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
470d05e84e6SDmitry Torokhov {
471d05e84e6SDmitry Torokhov 	struct usb_device *dev = usbtouch->udev;
47276d057ceSOliver Neukum 	int ret = -ENOMEM;
47376d057ceSOliver Neukum 	unsigned char *buf;
474d05e84e6SDmitry Torokhov 
47576d057ceSOliver Neukum 	buf = kmalloc(2, GFP_KERNEL);
47676d057ceSOliver Neukum 	if (!buf)
47776d057ceSOliver Neukum 		goto err_nobuf;
478d05e84e6SDmitry Torokhov 	/* reset */
479d05e84e6SDmitry Torokhov 	buf[0] = buf[1] = 0xFF;
480d05e84e6SDmitry Torokhov 	ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
481d05e84e6SDmitry Torokhov 	                      TSC10_CMD_RESET,
482d05e84e6SDmitry Torokhov 	                      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
483d05e84e6SDmitry Torokhov 	                      0, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
484d05e84e6SDmitry Torokhov 	if (ret < 0)
48576d057ceSOliver Neukum 		goto err_out;
4862ec6f246SNuno Lucas 	if (buf[0] != 0x06) {
48776d057ceSOliver Neukum 		ret = -ENODEV;
48876d057ceSOliver Neukum 		goto err_out;
48976d057ceSOliver Neukum 	}
490d05e84e6SDmitry Torokhov 
491d05e84e6SDmitry Torokhov 	/* set coordinate output rate */
492d05e84e6SDmitry Torokhov 	buf[0] = buf[1] = 0xFF;
493d05e84e6SDmitry Torokhov 	ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
494d05e84e6SDmitry Torokhov 	                      TSC10_CMD_RATE,
495d05e84e6SDmitry Torokhov 	                      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
496d05e84e6SDmitry Torokhov 	                      TSC10_RATE_150, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
497d05e84e6SDmitry Torokhov 	if (ret < 0)
49876d057ceSOliver Neukum 		goto err_out;
4992ec6f246SNuno Lucas 	if ((buf[0] != 0x06) && (buf[0] != 0x15 || buf[1] != 0x01)) {
50076d057ceSOliver Neukum 		ret = -ENODEV;
50176d057ceSOliver Neukum 		goto err_out;
50276d057ceSOliver Neukum 	}
503d05e84e6SDmitry Torokhov 
504d05e84e6SDmitry Torokhov 	/* start sending data */
505d05e84e6SDmitry Torokhov 	ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
506d05e84e6SDmitry Torokhov 	                      TSC10_CMD_DATA1,
507d05e84e6SDmitry Torokhov 	                      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
508d05e84e6SDmitry Torokhov 	                      0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
50976d057ceSOliver Neukum err_out:
51076d057ceSOliver Neukum 	kfree(buf);
51176d057ceSOliver Neukum err_nobuf:
512d05e84e6SDmitry Torokhov 	return ret;
513d05e84e6SDmitry Torokhov }
514d05e84e6SDmitry Torokhov 
515d05e84e6SDmitry Torokhov 
516d05e84e6SDmitry Torokhov static int dmc_tsc10_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
517d05e84e6SDmitry Torokhov {
518d05e84e6SDmitry Torokhov 	dev->x = ((pkt[2] & 0x03) << 8) | pkt[1];
519d05e84e6SDmitry Torokhov 	dev->y = ((pkt[4] & 0x03) << 8) | pkt[3];
520d05e84e6SDmitry Torokhov 	dev->touch = pkt[0] & 0x01;
521d05e84e6SDmitry Torokhov 
522d05e84e6SDmitry Torokhov 	return 1;
523d05e84e6SDmitry Torokhov }
524d05e84e6SDmitry Torokhov #endif
525d05e84e6SDmitry Torokhov 
526d05e84e6SDmitry Torokhov 
527d05e84e6SDmitry Torokhov /*****************************************************************************
528df561fcdSOndrej Zary  * IRTOUCH Part
529df561fcdSOndrej Zary  */
530df561fcdSOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH
531df561fcdSOndrej Zary static int irtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
532df561fcdSOndrej Zary {
533df561fcdSOndrej Zary 	dev->x = (pkt[3] << 8) | pkt[2];
534df561fcdSOndrej Zary 	dev->y = (pkt[5] << 8) | pkt[4];
535df561fcdSOndrej Zary 	dev->touch = (pkt[1] & 0x03) ? 1 : 0;
536df561fcdSOndrej Zary 
537df561fcdSOndrej Zary 	return 1;
538df561fcdSOndrej Zary }
539df561fcdSOndrej Zary #endif
540df561fcdSOndrej Zary 
541df561fcdSOndrej Zary 
542df561fcdSOndrej Zary /*****************************************************************************
543a14a8401SOndrej Zary  * IdealTEK URTC1000 Part
544a14a8401SOndrej Zary  */
545a14a8401SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
54662aa366dSDaniel Ritz #ifndef MULTI_PACKET
54762aa366dSDaniel Ritz #define MULTI_PACKET
54862aa366dSDaniel Ritz #endif
549a14a8401SOndrej Zary static int idealtek_get_pkt_len(unsigned char *buf, int len)
550a14a8401SOndrej Zary {
551a14a8401SOndrej Zary 	if (buf[0] & 0x80)
552a14a8401SOndrej Zary 		return 5;
553a14a8401SOndrej Zary 	if (buf[0] == 0x01)
554a14a8401SOndrej Zary 		return len;
555a14a8401SOndrej Zary 	return 0;
556a14a8401SOndrej Zary }
557a14a8401SOndrej Zary 
558a14a8401SOndrej Zary static int idealtek_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
559a14a8401SOndrej Zary {
560a14a8401SOndrej Zary 	switch (pkt[0] & 0x98) {
561a14a8401SOndrej Zary 	case 0x88:
562a14a8401SOndrej Zary 		/* touch data in IdealTEK mode */
563a14a8401SOndrej Zary 		dev->x = (pkt[1] << 5) | (pkt[2] >> 2);
564a14a8401SOndrej Zary 		dev->y = (pkt[3] << 5) | (pkt[4] >> 2);
565a14a8401SOndrej Zary 		dev->touch = (pkt[0] & 0x40) ? 1 : 0;
566a14a8401SOndrej Zary 		return 1;
567a14a8401SOndrej Zary 
568a14a8401SOndrej Zary 	case 0x98:
569a14a8401SOndrej Zary 		/* touch data in MT emulation mode */
570a14a8401SOndrej Zary 		dev->x = (pkt[2] << 5) | (pkt[1] >> 2);
571a14a8401SOndrej Zary 		dev->y = (pkt[4] << 5) | (pkt[3] >> 2);
572a14a8401SOndrej Zary 		dev->touch = (pkt[0] & 0x40) ? 1 : 0;
573a14a8401SOndrej Zary 		return 1;
574a14a8401SOndrej Zary 
575a14a8401SOndrej Zary 	default:
576a14a8401SOndrej Zary 		return 0;
577a14a8401SOndrej Zary 	}
578a14a8401SOndrej Zary }
579a14a8401SOndrej Zary #endif
580a14a8401SOndrej Zary 
5819d5657dbSIlya Frolov /*****************************************************************************
5829d5657dbSIlya Frolov  * General Touch Part
5839d5657dbSIlya Frolov  */
5849d5657dbSIlya Frolov #ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
5859d5657dbSIlya Frolov static int general_touch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
5869d5657dbSIlya Frolov {
5879d5657dbSIlya Frolov 	dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1] ;
5889d5657dbSIlya Frolov 	dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3] ;
5899d5657dbSIlya Frolov 	dev->press = pkt[5] & 0xff;
5909d5657dbSIlya Frolov 	dev->touch = pkt[0] & 0x01;
5919d5657dbSIlya Frolov 
5929d5657dbSIlya Frolov 	return 1;
5939d5657dbSIlya Frolov }
5949d5657dbSIlya Frolov #endif
595a14a8401SOndrej Zary 
596a14a8401SOndrej Zary /*****************************************************************************
59714e40206SJerrold Jones  * GoTop Part
59814e40206SJerrold Jones  */
59914e40206SJerrold Jones #ifdef CONFIG_TOUCHSCREEN_USB_GOTOP
60014e40206SJerrold Jones static int gotop_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
60114e40206SJerrold Jones {
60214e40206SJerrold Jones 	dev->x = ((pkt[1] & 0x38) << 4) | pkt[2];
60314e40206SJerrold Jones 	dev->y = ((pkt[1] & 0x07) << 7) | pkt[3];
60414e40206SJerrold Jones 	dev->touch = pkt[0] & 0x01;
605f7370699SJim Persson 
606f7370699SJim Persson 	return 1;
607f7370699SJim Persson }
608f7370699SJim Persson #endif
609f7370699SJim Persson 
610f7370699SJim Persson /*****************************************************************************
611f7370699SJim Persson  * JASTEC Part
612f7370699SJim Persson  */
613f7370699SJim Persson #ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
614f7370699SJim Persson static int jastec_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
615f7370699SJim Persson {
616f7370699SJim Persson 	dev->x = ((pkt[0] & 0x3f) << 6) | (pkt[2] & 0x3f);
617f7370699SJim Persson 	dev->y = ((pkt[1] & 0x3f) << 6) | (pkt[3] & 0x3f);
618f7370699SJim Persson 	dev->touch = (pkt[0] & 0x40) >> 6;
619f7370699SJim Persson 
62014e40206SJerrold Jones 	return 1;
62114e40206SJerrold Jones }
62214e40206SJerrold Jones #endif
62314e40206SJerrold Jones 
62414e40206SJerrold Jones 
62514e40206SJerrold Jones /*****************************************************************************
626d05e84e6SDmitry Torokhov  * the different device descriptors
627d05e84e6SDmitry Torokhov  */
62862aa366dSDaniel Ritz #ifdef MULTI_PACKET
62962aa366dSDaniel Ritz static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
63062aa366dSDaniel Ritz 				   unsigned char *pkt, int len);
63162aa366dSDaniel Ritz #endif
63262aa366dSDaniel Ritz 
633d05e84e6SDmitry Torokhov static struct usbtouch_device_info usbtouch_dev_info[] = {
634c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
635d05e84e6SDmitry Torokhov 	[DEVTYPE_EGALAX] = {
636d05e84e6SDmitry Torokhov 		.min_xc		= 0x0,
637d05e84e6SDmitry Torokhov 		.max_xc		= 0x07ff,
638d05e84e6SDmitry Torokhov 		.min_yc		= 0x0,
639d05e84e6SDmitry Torokhov 		.max_yc		= 0x07ff,
640d05e84e6SDmitry Torokhov 		.rept_size	= 16,
641d05e84e6SDmitry Torokhov 		.process_pkt	= usbtouch_process_multi,
642d05e84e6SDmitry Torokhov 		.get_pkt_len	= egalax_get_pkt_len,
643d05e84e6SDmitry Torokhov 		.read_data	= egalax_read_data,
644d05e84e6SDmitry Torokhov 	},
645d05e84e6SDmitry Torokhov #endif
646d05e84e6SDmitry Torokhov 
647c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_PANJIT
648d05e84e6SDmitry Torokhov 	[DEVTYPE_PANJIT] = {
649d05e84e6SDmitry Torokhov 		.min_xc		= 0x0,
650d05e84e6SDmitry Torokhov 		.max_xc		= 0x0fff,
651d05e84e6SDmitry Torokhov 		.min_yc		= 0x0,
652d05e84e6SDmitry Torokhov 		.max_yc		= 0x0fff,
653d05e84e6SDmitry Torokhov 		.rept_size	= 8,
654d05e84e6SDmitry Torokhov 		.read_data	= panjit_read_data,
655d05e84e6SDmitry Torokhov 	},
656d05e84e6SDmitry Torokhov #endif
657d05e84e6SDmitry Torokhov 
658c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_3M
659d05e84e6SDmitry Torokhov 	[DEVTYPE_3M] = {
660d05e84e6SDmitry Torokhov 		.min_xc		= 0x0,
661d05e84e6SDmitry Torokhov 		.max_xc		= 0x4000,
662d05e84e6SDmitry Torokhov 		.min_yc		= 0x0,
663d05e84e6SDmitry Torokhov 		.max_yc		= 0x4000,
664d05e84e6SDmitry Torokhov 		.rept_size	= 11,
665d05e84e6SDmitry Torokhov 		.read_data	= mtouch_read_data,
666d05e84e6SDmitry Torokhov 		.init		= mtouch_init,
667d05e84e6SDmitry Torokhov 	},
668d05e84e6SDmitry Torokhov #endif
669d05e84e6SDmitry Torokhov 
670c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_ITM
671d05e84e6SDmitry Torokhov 	[DEVTYPE_ITM] = {
672d05e84e6SDmitry Torokhov 		.min_xc		= 0x0,
673d05e84e6SDmitry Torokhov 		.max_xc		= 0x0fff,
674d05e84e6SDmitry Torokhov 		.min_yc		= 0x0,
675d05e84e6SDmitry Torokhov 		.max_yc		= 0x0fff,
676d05e84e6SDmitry Torokhov 		.max_press	= 0xff,
677d05e84e6SDmitry Torokhov 		.rept_size	= 8,
678d05e84e6SDmitry Torokhov 		.read_data	= itm_read_data,
679d05e84e6SDmitry Torokhov 	},
680d05e84e6SDmitry Torokhov #endif
681d05e84e6SDmitry Torokhov 
682c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_ETURBO
683d05e84e6SDmitry Torokhov 	[DEVTYPE_ETURBO] = {
684d05e84e6SDmitry Torokhov 		.min_xc		= 0x0,
685d05e84e6SDmitry Torokhov 		.max_xc		= 0x07ff,
686d05e84e6SDmitry Torokhov 		.min_yc		= 0x0,
687d05e84e6SDmitry Torokhov 		.max_yc		= 0x07ff,
688d05e84e6SDmitry Torokhov 		.rept_size	= 8,
689d05e84e6SDmitry Torokhov 		.process_pkt	= usbtouch_process_multi,
690d05e84e6SDmitry Torokhov 		.get_pkt_len	= eturbo_get_pkt_len,
691d05e84e6SDmitry Torokhov 		.read_data	= eturbo_read_data,
692d05e84e6SDmitry Torokhov 	},
693d05e84e6SDmitry Torokhov #endif
694d05e84e6SDmitry Torokhov 
695c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_GUNZE
696d05e84e6SDmitry Torokhov 	[DEVTYPE_GUNZE] = {
697d05e84e6SDmitry Torokhov 		.min_xc		= 0x0,
698d05e84e6SDmitry Torokhov 		.max_xc		= 0x0fff,
699d05e84e6SDmitry Torokhov 		.min_yc		= 0x0,
700d05e84e6SDmitry Torokhov 		.max_yc		= 0x0fff,
701d05e84e6SDmitry Torokhov 		.rept_size	= 4,
702d05e84e6SDmitry Torokhov 		.read_data	= gunze_read_data,
703d05e84e6SDmitry Torokhov 	},
704d05e84e6SDmitry Torokhov #endif
705d05e84e6SDmitry Torokhov 
706c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_DMC_TSC10
707d05e84e6SDmitry Torokhov 	[DEVTYPE_DMC_TSC10] = {
708d05e84e6SDmitry Torokhov 		.min_xc		= 0x0,
709d05e84e6SDmitry Torokhov 		.max_xc		= 0x03ff,
710d05e84e6SDmitry Torokhov 		.min_yc		= 0x0,
711d05e84e6SDmitry Torokhov 		.max_yc		= 0x03ff,
712d05e84e6SDmitry Torokhov 		.rept_size	= 5,
713d05e84e6SDmitry Torokhov 		.init		= dmc_tsc10_init,
714d05e84e6SDmitry Torokhov 		.read_data	= dmc_tsc10_read_data,
715d05e84e6SDmitry Torokhov 	},
716d05e84e6SDmitry Torokhov #endif
717df561fcdSOndrej Zary 
718df561fcdSOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH
719df561fcdSOndrej Zary 	[DEVTYPE_IRTOUCH] = {
720df561fcdSOndrej Zary 		.min_xc		= 0x0,
721df561fcdSOndrej Zary 		.max_xc		= 0x0fff,
722df561fcdSOndrej Zary 		.min_yc		= 0x0,
723df561fcdSOndrej Zary 		.max_yc		= 0x0fff,
724df561fcdSOndrej Zary 		.rept_size	= 8,
725df561fcdSOndrej Zary 		.read_data	= irtouch_read_data,
726df561fcdSOndrej Zary 	},
727df561fcdSOndrej Zary #endif
728a14a8401SOndrej Zary 
729a14a8401SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
730a14a8401SOndrej Zary 	[DEVTYPE_IDEALTEK] = {
731a14a8401SOndrej Zary 		.min_xc		= 0x0,
732a14a8401SOndrej Zary 		.max_xc		= 0x0fff,
733a14a8401SOndrej Zary 		.min_yc		= 0x0,
734a14a8401SOndrej Zary 		.max_yc		= 0x0fff,
735a14a8401SOndrej Zary 		.rept_size	= 8,
736a14a8401SOndrej Zary 		.process_pkt	= usbtouch_process_multi,
737a14a8401SOndrej Zary 		.get_pkt_len	= idealtek_get_pkt_len,
738a14a8401SOndrej Zary 		.read_data	= idealtek_read_data,
739a14a8401SOndrej Zary 	},
740a14a8401SOndrej Zary #endif
7419d5657dbSIlya Frolov 
7429d5657dbSIlya Frolov #ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
7439d5657dbSIlya Frolov 	[DEVTYPE_GENERAL_TOUCH] = {
7449d5657dbSIlya Frolov 		.min_xc		= 0x0,
7459d5657dbSIlya Frolov 		.max_xc		= 0x0500,
7469d5657dbSIlya Frolov 		.min_yc		= 0x0,
7479d5657dbSIlya Frolov 		.max_yc		= 0x0500,
7489d5657dbSIlya Frolov 		.rept_size	= 7,
7499d5657dbSIlya Frolov 		.read_data	= general_touch_read_data,
75014e40206SJerrold Jones 	},
7519d5657dbSIlya Frolov #endif
7529d5657dbSIlya Frolov 
75314e40206SJerrold Jones #ifdef CONFIG_TOUCHSCREEN_USB_GOTOP
75414e40206SJerrold Jones 	[DEVTYPE_GOTOP] = {
75514e40206SJerrold Jones 		.min_xc		= 0x0,
75614e40206SJerrold Jones 		.max_xc		= 0x03ff,
75714e40206SJerrold Jones 		.min_yc		= 0x0,
75814e40206SJerrold Jones 		.max_yc		= 0x03ff,
75914e40206SJerrold Jones 		.rept_size	= 4,
76014e40206SJerrold Jones 		.read_data	= gotop_read_data,
76114e40206SJerrold Jones 	},
76214e40206SJerrold Jones #endif
763f7370699SJim Persson 
764f7370699SJim Persson #ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
765f7370699SJim Persson 	[DEVTYPE_JASTEC] = {
766f7370699SJim Persson 		.min_xc		= 0x0,
767f7370699SJim Persson 		.max_xc		= 0x0fff,
768f7370699SJim Persson 		.min_yc		= 0x0,
769f7370699SJim Persson 		.max_yc		= 0x0fff,
770f7370699SJim Persson 		.rept_size	= 4,
771f7370699SJim Persson 		.read_data	= jastec_read_data,
772f7370699SJim Persson 	},
773f7370699SJim Persson #endif
774*9e3b2583SFlorian Echtler 
775*9e3b2583SFlorian Echtler #ifdef CONFIG_TOUCHSCREEN_USB_E2I
776*9e3b2583SFlorian Echtler 	[DEVTYPE_E2I] = {
777*9e3b2583SFlorian Echtler 		.min_xc		= 0x0,
778*9e3b2583SFlorian Echtler 		.max_xc		= 0x7fff,
779*9e3b2583SFlorian Echtler 		.min_yc		= 0x0,
780*9e3b2583SFlorian Echtler 		.max_yc		= 0x7fff,
781*9e3b2583SFlorian Echtler 		.rept_size	= 6,
782*9e3b2583SFlorian Echtler 		.init		= e2i_init,
783*9e3b2583SFlorian Echtler 		.read_data	= e2i_read_data,
784*9e3b2583SFlorian Echtler 	},
785*9e3b2583SFlorian Echtler #endif
786d05e84e6SDmitry Torokhov };
787d05e84e6SDmitry Torokhov 
788d05e84e6SDmitry Torokhov 
789d05e84e6SDmitry Torokhov /*****************************************************************************
790d05e84e6SDmitry Torokhov  * Generic Part
791d05e84e6SDmitry Torokhov  */
792d05e84e6SDmitry Torokhov static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,
793d05e84e6SDmitry Torokhov                                  unsigned char *pkt, int len)
794d05e84e6SDmitry Torokhov {
795d05e84e6SDmitry Torokhov 	struct usbtouch_device_info *type = usbtouch->type;
796d05e84e6SDmitry Torokhov 
797d05e84e6SDmitry Torokhov 	if (!type->read_data(usbtouch, pkt))
798d05e84e6SDmitry Torokhov 			return;
799d05e84e6SDmitry Torokhov 
800d05e84e6SDmitry Torokhov 	input_report_key(usbtouch->input, BTN_TOUCH, usbtouch->touch);
801d05e84e6SDmitry Torokhov 
802d05e84e6SDmitry Torokhov 	if (swap_xy) {
803d05e84e6SDmitry Torokhov 		input_report_abs(usbtouch->input, ABS_X, usbtouch->y);
804d05e84e6SDmitry Torokhov 		input_report_abs(usbtouch->input, ABS_Y, usbtouch->x);
805d05e84e6SDmitry Torokhov 	} else {
806d05e84e6SDmitry Torokhov 		input_report_abs(usbtouch->input, ABS_X, usbtouch->x);
807d05e84e6SDmitry Torokhov 		input_report_abs(usbtouch->input, ABS_Y, usbtouch->y);
808d05e84e6SDmitry Torokhov 	}
809d05e84e6SDmitry Torokhov 	if (type->max_press)
810d05e84e6SDmitry Torokhov 		input_report_abs(usbtouch->input, ABS_PRESSURE, usbtouch->press);
811d05e84e6SDmitry Torokhov 	input_sync(usbtouch->input);
812d05e84e6SDmitry Torokhov }
813d05e84e6SDmitry Torokhov 
814d05e84e6SDmitry Torokhov 
815d05e84e6SDmitry Torokhov #ifdef MULTI_PACKET
816d05e84e6SDmitry Torokhov static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
817d05e84e6SDmitry Torokhov                                    unsigned char *pkt, int len)
818d05e84e6SDmitry Torokhov {
819d05e84e6SDmitry Torokhov 	unsigned char *buffer;
820d05e84e6SDmitry Torokhov 	int pkt_len, pos, buf_len, tmp;
821d05e84e6SDmitry Torokhov 
822d05e84e6SDmitry Torokhov 	/* process buffer */
823d05e84e6SDmitry Torokhov 	if (unlikely(usbtouch->buf_len)) {
824d05e84e6SDmitry Torokhov 		/* try to get size */
825d05e84e6SDmitry Torokhov 		pkt_len = usbtouch->type->get_pkt_len(
826d05e84e6SDmitry Torokhov 				usbtouch->buffer, usbtouch->buf_len);
827d05e84e6SDmitry Torokhov 
828d05e84e6SDmitry Torokhov 		/* drop? */
829d05e84e6SDmitry Torokhov 		if (unlikely(!pkt_len))
830d05e84e6SDmitry Torokhov 			goto out_flush_buf;
831d05e84e6SDmitry Torokhov 
832d05e84e6SDmitry Torokhov 		/* need to append -pkt_len bytes before able to get size */
833d05e84e6SDmitry Torokhov 		if (unlikely(pkt_len < 0)) {
834d05e84e6SDmitry Torokhov 			int append = -pkt_len;
835d05e84e6SDmitry Torokhov 			if (unlikely(append > len))
836d05e84e6SDmitry Torokhov 			       append = len;
837d05e84e6SDmitry Torokhov 			if (usbtouch->buf_len + append >= usbtouch->type->rept_size)
838d05e84e6SDmitry Torokhov 				goto out_flush_buf;
839d05e84e6SDmitry Torokhov 			memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, append);
840d05e84e6SDmitry Torokhov 			usbtouch->buf_len += append;
841d05e84e6SDmitry Torokhov 
842d05e84e6SDmitry Torokhov 			pkt_len = usbtouch->type->get_pkt_len(
843d05e84e6SDmitry Torokhov 					usbtouch->buffer, usbtouch->buf_len);
844d05e84e6SDmitry Torokhov 			if (pkt_len < 0)
845d05e84e6SDmitry Torokhov 				return;
846d05e84e6SDmitry Torokhov 		}
847d05e84e6SDmitry Torokhov 
848d05e84e6SDmitry Torokhov 		/* append */
849d05e84e6SDmitry Torokhov 		tmp = pkt_len - usbtouch->buf_len;
850d05e84e6SDmitry Torokhov 		if (usbtouch->buf_len + tmp >= usbtouch->type->rept_size)
851d05e84e6SDmitry Torokhov 			goto out_flush_buf;
852d05e84e6SDmitry Torokhov 		memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, tmp);
853d05e84e6SDmitry Torokhov 		usbtouch_process_pkt(usbtouch, usbtouch->buffer, pkt_len);
854d05e84e6SDmitry Torokhov 
855d05e84e6SDmitry Torokhov 		buffer = pkt + tmp;
856d05e84e6SDmitry Torokhov 		buf_len = len - tmp;
857d05e84e6SDmitry Torokhov 	} else {
858d05e84e6SDmitry Torokhov 		buffer = pkt;
859d05e84e6SDmitry Torokhov 		buf_len = len;
860d05e84e6SDmitry Torokhov 	}
861d05e84e6SDmitry Torokhov 
862d05e84e6SDmitry Torokhov 	/* loop over the received packet, process */
863d05e84e6SDmitry Torokhov 	pos = 0;
864d05e84e6SDmitry Torokhov 	while (pos < buf_len) {
865d05e84e6SDmitry Torokhov 		/* get packet len */
86662aa366dSDaniel Ritz 		pkt_len = usbtouch->type->get_pkt_len(buffer + pos,
86762aa366dSDaniel Ritz 							buf_len - pos);
868d05e84e6SDmitry Torokhov 
86962aa366dSDaniel Ritz 		/* unknown packet: skip one byte */
87062aa366dSDaniel Ritz 		if (unlikely(!pkt_len)) {
87162aa366dSDaniel Ritz 			pos++;
87262aa366dSDaniel Ritz 			continue;
87362aa366dSDaniel Ritz 		}
874d05e84e6SDmitry Torokhov 
875d05e84e6SDmitry Torokhov 		/* full packet: process */
876d05e84e6SDmitry Torokhov 		if (likely((pkt_len > 0) && (pkt_len <= buf_len - pos))) {
877d05e84e6SDmitry Torokhov 			usbtouch_process_pkt(usbtouch, buffer + pos, pkt_len);
878d05e84e6SDmitry Torokhov 		} else {
879d05e84e6SDmitry Torokhov 			/* incomplete packet: save in buffer */
880d05e84e6SDmitry Torokhov 			memcpy(usbtouch->buffer, buffer + pos, buf_len - pos);
881d05e84e6SDmitry Torokhov 			usbtouch->buf_len = buf_len - pos;
882d05e84e6SDmitry Torokhov 			return;
883d05e84e6SDmitry Torokhov 		}
884d05e84e6SDmitry Torokhov 		pos += pkt_len;
885d05e84e6SDmitry Torokhov 	}
886d05e84e6SDmitry Torokhov 
887d05e84e6SDmitry Torokhov out_flush_buf:
888d05e84e6SDmitry Torokhov 	usbtouch->buf_len = 0;
889d05e84e6SDmitry Torokhov 	return;
890d05e84e6SDmitry Torokhov }
891d05e84e6SDmitry Torokhov #endif
892d05e84e6SDmitry Torokhov 
893d05e84e6SDmitry Torokhov 
894d05e84e6SDmitry Torokhov static void usbtouch_irq(struct urb *urb)
895d05e84e6SDmitry Torokhov {
896d05e84e6SDmitry Torokhov 	struct usbtouch_usb *usbtouch = urb->context;
897d05e84e6SDmitry Torokhov 	int retval;
898d05e84e6SDmitry Torokhov 
899d05e84e6SDmitry Torokhov 	switch (urb->status) {
900d05e84e6SDmitry Torokhov 	case 0:
901d05e84e6SDmitry Torokhov 		/* success */
902d05e84e6SDmitry Torokhov 		break;
903d05e84e6SDmitry Torokhov 	case -ETIME:
904d05e84e6SDmitry Torokhov 		/* this urb is timing out */
905d05e84e6SDmitry Torokhov 		dbg("%s - urb timed out - was the device unplugged?",
906ea3e6c59SHarvey Harrison 		    __func__);
907d05e84e6SDmitry Torokhov 		return;
908d05e84e6SDmitry Torokhov 	case -ECONNRESET:
909d05e84e6SDmitry Torokhov 	case -ENOENT:
910d05e84e6SDmitry Torokhov 	case -ESHUTDOWN:
911d05e84e6SDmitry Torokhov 		/* this urb is terminated, clean up */
912d05e84e6SDmitry Torokhov 		dbg("%s - urb shutting down with status: %d",
913ea3e6c59SHarvey Harrison 		    __func__, urb->status);
914d05e84e6SDmitry Torokhov 		return;
915d05e84e6SDmitry Torokhov 	default:
916d05e84e6SDmitry Torokhov 		dbg("%s - nonzero urb status received: %d",
917ea3e6c59SHarvey Harrison 		    __func__, urb->status);
918d05e84e6SDmitry Torokhov 		goto exit;
919d05e84e6SDmitry Torokhov 	}
920d05e84e6SDmitry Torokhov 
921d05e84e6SDmitry Torokhov 	usbtouch->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length);
922d05e84e6SDmitry Torokhov 
923d05e84e6SDmitry Torokhov exit:
924d05e84e6SDmitry Torokhov 	retval = usb_submit_urb(urb, GFP_ATOMIC);
925d05e84e6SDmitry Torokhov 	if (retval)
926d05e84e6SDmitry Torokhov 		err("%s - usb_submit_urb failed with result: %d",
927ea3e6c59SHarvey Harrison 		    __func__, retval);
928d05e84e6SDmitry Torokhov }
929d05e84e6SDmitry Torokhov 
930d05e84e6SDmitry Torokhov static int usbtouch_open(struct input_dev *input)
931d05e84e6SDmitry Torokhov {
932d05e84e6SDmitry Torokhov 	struct usbtouch_usb *usbtouch = input_get_drvdata(input);
933d05e84e6SDmitry Torokhov 
934d05e84e6SDmitry Torokhov 	usbtouch->irq->dev = usbtouch->udev;
935d05e84e6SDmitry Torokhov 
936d05e84e6SDmitry Torokhov 	if (usb_submit_urb(usbtouch->irq, GFP_KERNEL))
937d05e84e6SDmitry Torokhov 		return -EIO;
938d05e84e6SDmitry Torokhov 
939d05e84e6SDmitry Torokhov 	return 0;
940d05e84e6SDmitry Torokhov }
941d05e84e6SDmitry Torokhov 
942d05e84e6SDmitry Torokhov static void usbtouch_close(struct input_dev *input)
943d05e84e6SDmitry Torokhov {
944d05e84e6SDmitry Torokhov 	struct usbtouch_usb *usbtouch = input_get_drvdata(input);
945d05e84e6SDmitry Torokhov 
946d05e84e6SDmitry Torokhov 	usb_kill_urb(usbtouch->irq);
947d05e84e6SDmitry Torokhov }
948d05e84e6SDmitry Torokhov 
949d05e84e6SDmitry Torokhov 
950d05e84e6SDmitry Torokhov static void usbtouch_free_buffers(struct usb_device *udev,
951d05e84e6SDmitry Torokhov 				  struct usbtouch_usb *usbtouch)
952d05e84e6SDmitry Torokhov {
953d05e84e6SDmitry Torokhov 	usb_buffer_free(udev, usbtouch->type->rept_size,
954d05e84e6SDmitry Torokhov 	                usbtouch->data, usbtouch->data_dma);
955d05e84e6SDmitry Torokhov 	kfree(usbtouch->buffer);
956d05e84e6SDmitry Torokhov }
957d05e84e6SDmitry Torokhov 
958d05e84e6SDmitry Torokhov 
959d05e84e6SDmitry Torokhov static int usbtouch_probe(struct usb_interface *intf,
960d05e84e6SDmitry Torokhov 			  const struct usb_device_id *id)
961d05e84e6SDmitry Torokhov {
962d05e84e6SDmitry Torokhov 	struct usbtouch_usb *usbtouch;
963d05e84e6SDmitry Torokhov 	struct input_dev *input_dev;
964d05e84e6SDmitry Torokhov 	struct usb_host_interface *interface;
965d05e84e6SDmitry Torokhov 	struct usb_endpoint_descriptor *endpoint;
966d05e84e6SDmitry Torokhov 	struct usb_device *udev = interface_to_usbdev(intf);
967d05e84e6SDmitry Torokhov 	struct usbtouch_device_info *type;
968d05e84e6SDmitry Torokhov 	int err = -ENOMEM;
969d05e84e6SDmitry Torokhov 
970ec42d448SDaniel Ritz 	/* some devices are ignored */
971ec42d448SDaniel Ritz 	if (id->driver_info == DEVTYPE_IGNORE)
972ec42d448SDaniel Ritz 		return -ENODEV;
973ec42d448SDaniel Ritz 
974d05e84e6SDmitry Torokhov 	interface = intf->cur_altsetting;
975d05e84e6SDmitry Torokhov 	endpoint = &interface->endpoint[0].desc;
976d05e84e6SDmitry Torokhov 
977d05e84e6SDmitry Torokhov 	usbtouch = kzalloc(sizeof(struct usbtouch_usb), GFP_KERNEL);
978d05e84e6SDmitry Torokhov 	input_dev = input_allocate_device();
979d05e84e6SDmitry Torokhov 	if (!usbtouch || !input_dev)
980d05e84e6SDmitry Torokhov 		goto out_free;
981d05e84e6SDmitry Torokhov 
982d05e84e6SDmitry Torokhov 	type = &usbtouch_dev_info[id->driver_info];
983d05e84e6SDmitry Torokhov 	usbtouch->type = type;
984d05e84e6SDmitry Torokhov 	if (!type->process_pkt)
985d05e84e6SDmitry Torokhov 		type->process_pkt = usbtouch_process_pkt;
986d05e84e6SDmitry Torokhov 
987d05e84e6SDmitry Torokhov 	usbtouch->data = usb_buffer_alloc(udev, type->rept_size,
988d05e84e6SDmitry Torokhov 	                                  GFP_KERNEL, &usbtouch->data_dma);
989d05e84e6SDmitry Torokhov 	if (!usbtouch->data)
990d05e84e6SDmitry Torokhov 		goto out_free;
991d05e84e6SDmitry Torokhov 
99262aa366dSDaniel Ritz 	if (type->get_pkt_len) {
993d05e84e6SDmitry Torokhov 		usbtouch->buffer = kmalloc(type->rept_size, GFP_KERNEL);
994d05e84e6SDmitry Torokhov 		if (!usbtouch->buffer)
995d05e84e6SDmitry Torokhov 			goto out_free_buffers;
996d05e84e6SDmitry Torokhov 	}
997d05e84e6SDmitry Torokhov 
998d05e84e6SDmitry Torokhov 	usbtouch->irq = usb_alloc_urb(0, GFP_KERNEL);
999d05e84e6SDmitry Torokhov 	if (!usbtouch->irq) {
1000ea3e6c59SHarvey Harrison 		dbg("%s - usb_alloc_urb failed: usbtouch->irq", __func__);
1001d05e84e6SDmitry Torokhov 		goto out_free_buffers;
1002d05e84e6SDmitry Torokhov 	}
1003d05e84e6SDmitry Torokhov 
1004d05e84e6SDmitry Torokhov 	usbtouch->udev = udev;
1005d05e84e6SDmitry Torokhov 	usbtouch->input = input_dev;
1006d05e84e6SDmitry Torokhov 
1007d05e84e6SDmitry Torokhov 	if (udev->manufacturer)
1008d05e84e6SDmitry Torokhov 		strlcpy(usbtouch->name, udev->manufacturer, sizeof(usbtouch->name));
1009d05e84e6SDmitry Torokhov 
1010d05e84e6SDmitry Torokhov 	if (udev->product) {
1011d05e84e6SDmitry Torokhov 		if (udev->manufacturer)
1012d05e84e6SDmitry Torokhov 			strlcat(usbtouch->name, " ", sizeof(usbtouch->name));
1013d05e84e6SDmitry Torokhov 		strlcat(usbtouch->name, udev->product, sizeof(usbtouch->name));
1014d05e84e6SDmitry Torokhov 	}
1015d05e84e6SDmitry Torokhov 
1016d05e84e6SDmitry Torokhov 	if (!strlen(usbtouch->name))
1017d05e84e6SDmitry Torokhov 		snprintf(usbtouch->name, sizeof(usbtouch->name),
1018d05e84e6SDmitry Torokhov 			"USB Touchscreen %04x:%04x",
1019d05e84e6SDmitry Torokhov 			 le16_to_cpu(udev->descriptor.idVendor),
1020d05e84e6SDmitry Torokhov 			 le16_to_cpu(udev->descriptor.idProduct));
1021d05e84e6SDmitry Torokhov 
1022d05e84e6SDmitry Torokhov 	usb_make_path(udev, usbtouch->phys, sizeof(usbtouch->phys));
10237b6dff98SVladimir Shebordaev 	strlcat(usbtouch->phys, "/input0", sizeof(usbtouch->phys));
1024d05e84e6SDmitry Torokhov 
1025d05e84e6SDmitry Torokhov 	input_dev->name = usbtouch->name;
1026d05e84e6SDmitry Torokhov 	input_dev->phys = usbtouch->phys;
1027d05e84e6SDmitry Torokhov 	usb_to_input_id(udev, &input_dev->id);
1028d05e84e6SDmitry Torokhov 	input_dev->dev.parent = &intf->dev;
1029d05e84e6SDmitry Torokhov 
1030d05e84e6SDmitry Torokhov 	input_set_drvdata(input_dev, usbtouch);
1031d05e84e6SDmitry Torokhov 
1032d05e84e6SDmitry Torokhov 	input_dev->open = usbtouch_open;
1033d05e84e6SDmitry Torokhov 	input_dev->close = usbtouch_close;
1034d05e84e6SDmitry Torokhov 
10357b19ada2SJiri Slaby 	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
10367b19ada2SJiri Slaby 	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
1037d05e84e6SDmitry Torokhov 	input_set_abs_params(input_dev, ABS_X, type->min_xc, type->max_xc, 0, 0);
1038d05e84e6SDmitry Torokhov 	input_set_abs_params(input_dev, ABS_Y, type->min_yc, type->max_yc, 0, 0);
1039d05e84e6SDmitry Torokhov 	if (type->max_press)
1040d05e84e6SDmitry Torokhov 		input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press,
1041d05e84e6SDmitry Torokhov 		                     type->max_press, 0, 0);
1042d05e84e6SDmitry Torokhov 
1043d05e84e6SDmitry Torokhov 	usb_fill_int_urb(usbtouch->irq, usbtouch->udev,
1044d05e84e6SDmitry Torokhov 			 usb_rcvintpipe(usbtouch->udev, endpoint->bEndpointAddress),
1045d05e84e6SDmitry Torokhov 			 usbtouch->data, type->rept_size,
1046d05e84e6SDmitry Torokhov 			 usbtouch_irq, usbtouch, endpoint->bInterval);
1047d05e84e6SDmitry Torokhov 
1048d05e84e6SDmitry Torokhov 	usbtouch->irq->dev = usbtouch->udev;
1049d05e84e6SDmitry Torokhov 	usbtouch->irq->transfer_dma = usbtouch->data_dma;
1050d05e84e6SDmitry Torokhov 	usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1051d05e84e6SDmitry Torokhov 
1052d05e84e6SDmitry Torokhov 	/* device specific init */
1053d05e84e6SDmitry Torokhov 	if (type->init) {
1054d05e84e6SDmitry Torokhov 		err = type->init(usbtouch);
1055d05e84e6SDmitry Torokhov 		if (err) {
1056ea3e6c59SHarvey Harrison 			dbg("%s - type->init() failed, err: %d", __func__, err);
1057d05e84e6SDmitry Torokhov 			goto out_free_buffers;
1058d05e84e6SDmitry Torokhov 		}
1059d05e84e6SDmitry Torokhov 	}
1060d05e84e6SDmitry Torokhov 
1061d05e84e6SDmitry Torokhov 	err = input_register_device(usbtouch->input);
1062d05e84e6SDmitry Torokhov 	if (err) {
1063ea3e6c59SHarvey Harrison 		dbg("%s - input_register_device failed, err: %d", __func__, err);
1064d05e84e6SDmitry Torokhov 		goto out_free_buffers;
1065d05e84e6SDmitry Torokhov 	}
1066d05e84e6SDmitry Torokhov 
1067d05e84e6SDmitry Torokhov 	usb_set_intfdata(intf, usbtouch);
1068d05e84e6SDmitry Torokhov 
1069d05e84e6SDmitry Torokhov 	return 0;
1070d05e84e6SDmitry Torokhov 
1071d05e84e6SDmitry Torokhov out_free_buffers:
1072d05e84e6SDmitry Torokhov 	usbtouch_free_buffers(udev, usbtouch);
1073d05e84e6SDmitry Torokhov out_free:
1074d05e84e6SDmitry Torokhov 	input_free_device(input_dev);
1075d05e84e6SDmitry Torokhov 	kfree(usbtouch);
1076d05e84e6SDmitry Torokhov 	return err;
1077d05e84e6SDmitry Torokhov }
1078d05e84e6SDmitry Torokhov 
1079d05e84e6SDmitry Torokhov static void usbtouch_disconnect(struct usb_interface *intf)
1080d05e84e6SDmitry Torokhov {
1081d05e84e6SDmitry Torokhov 	struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
1082d05e84e6SDmitry Torokhov 
1083ea3e6c59SHarvey Harrison 	dbg("%s - called", __func__);
1084d05e84e6SDmitry Torokhov 
1085d05e84e6SDmitry Torokhov 	if (!usbtouch)
1086d05e84e6SDmitry Torokhov 		return;
1087d05e84e6SDmitry Torokhov 
1088ea3e6c59SHarvey Harrison 	dbg("%s - usbtouch is initialized, cleaning up", __func__);
1089d05e84e6SDmitry Torokhov 	usb_set_intfdata(intf, NULL);
1090d05e84e6SDmitry Torokhov 	usb_kill_urb(usbtouch->irq);
1091d05e84e6SDmitry Torokhov 	input_unregister_device(usbtouch->input);
1092d05e84e6SDmitry Torokhov 	usb_free_urb(usbtouch->irq);
1093d05e84e6SDmitry Torokhov 	usbtouch_free_buffers(interface_to_usbdev(intf), usbtouch);
1094d05e84e6SDmitry Torokhov 	kfree(usbtouch);
1095d05e84e6SDmitry Torokhov }
1096d05e84e6SDmitry Torokhov 
1097d05e84e6SDmitry Torokhov MODULE_DEVICE_TABLE(usb, usbtouch_devices);
1098d05e84e6SDmitry Torokhov 
1099d05e84e6SDmitry Torokhov static struct usb_driver usbtouch_driver = {
1100d05e84e6SDmitry Torokhov 	.name		= "usbtouchscreen",
1101d05e84e6SDmitry Torokhov 	.probe		= usbtouch_probe,
1102d05e84e6SDmitry Torokhov 	.disconnect	= usbtouch_disconnect,
1103d05e84e6SDmitry Torokhov 	.id_table	= usbtouch_devices,
1104d05e84e6SDmitry Torokhov };
1105d05e84e6SDmitry Torokhov 
1106d05e84e6SDmitry Torokhov static int __init usbtouch_init(void)
1107d05e84e6SDmitry Torokhov {
1108d05e84e6SDmitry Torokhov 	return usb_register(&usbtouch_driver);
1109d05e84e6SDmitry Torokhov }
1110d05e84e6SDmitry Torokhov 
1111d05e84e6SDmitry Torokhov static void __exit usbtouch_cleanup(void)
1112d05e84e6SDmitry Torokhov {
1113d05e84e6SDmitry Torokhov 	usb_deregister(&usbtouch_driver);
1114d05e84e6SDmitry Torokhov }
1115d05e84e6SDmitry Torokhov 
1116d05e84e6SDmitry Torokhov module_init(usbtouch_init);
1117d05e84e6SDmitry Torokhov module_exit(usbtouch_cleanup);
1118d05e84e6SDmitry Torokhov 
1119d05e84e6SDmitry Torokhov MODULE_AUTHOR(DRIVER_AUTHOR);
1120d05e84e6SDmitry Torokhov MODULE_DESCRIPTION(DRIVER_DESC);
1121d05e84e6SDmitry Torokhov MODULE_LICENSE("GPL");
1122d05e84e6SDmitry Torokhov 
1123d05e84e6SDmitry Torokhov MODULE_ALIAS("touchkitusb");
1124d05e84e6SDmitry Torokhov MODULE_ALIAS("itmtouch");
1125d05e84e6SDmitry Torokhov MODULE_ALIAS("mtouchusb");
1126