xref: /linux/drivers/input/touchscreen/usbtouchscreen.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2d05e84e6SDmitry Torokhov /******************************************************************************
3d05e84e6SDmitry Torokhov  * usbtouchscreen.c
4d05e84e6SDmitry Torokhov  * Driver for USB Touchscreens, supporting those devices:
5d05e84e6SDmitry Torokhov  *  - eGalax Touchkit
6d05e84e6SDmitry Torokhov  *    includes eTurboTouch CT-410/510/700
7d05e84e6SDmitry Torokhov  *  - 3M/Microtouch  EX II series
8d05e84e6SDmitry Torokhov  *  - ITM
9d05e84e6SDmitry Torokhov  *  - PanJit TouchSet
10d05e84e6SDmitry Torokhov  *  - eTurboTouch
11d05e84e6SDmitry Torokhov  *  - Gunze AHL61
12d05e84e6SDmitry Torokhov  *  - DMC TSC-10/25
13df561fcdSOndrej Zary  *  - IRTOUCHSYSTEMS/UNITOP
14a14a8401SOndrej Zary  *  - IdealTEK URTC1000
1562aa366dSDaniel Ritz  *  - General Touch
1614e40206SJerrold Jones  *  - GoTop Super_Q2/GogoPen/PenPower tablets
17f7370699SJim Persson  *  - JASTEC USB touch controller/DigiTech DTR-02U
182330ed18SDaniel Silverstone  *  - Zytronic capacitive touchscreen
195197424cSOndrej Zary  *  - NEXIO/iNexio
20d2cc817aSMichael Gebetsroither  *  - Elo TouchSystems 2700 IntelliTouch
21aa87512fSArmando Visconti  *  - EasyTouch USB Dual/Multi touch controller from Data Modul
22d05e84e6SDmitry Torokhov  *
2314e40206SJerrold Jones  * Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch>
24d05e84e6SDmitry Torokhov  * Copyright (C) by Todd E. Johnson (mtouchusb.c)
25d05e84e6SDmitry Torokhov  *
26d05e84e6SDmitry Torokhov  * Driver is based on touchkitusb.c
27d05e84e6SDmitry Torokhov  * - ITM parts are from itmtouch.c
28d05e84e6SDmitry Torokhov  * - 3M parts are from mtouchusb.c
29d05e84e6SDmitry Torokhov  * - PanJit parts are from an unmerged driver by Lanslott Gish
30d05e84e6SDmitry Torokhov  * - DMC TSC 10/25 are from Holger Schurig, with ideas from an unmerged
31d05e84e6SDmitry Torokhov  *   driver from Marius Vollmer
32d05e84e6SDmitry Torokhov  *
33d05e84e6SDmitry Torokhov  *****************************************************************************/
34d05e84e6SDmitry Torokhov 
35d05e84e6SDmitry Torokhov //#define DEBUG
36d05e84e6SDmitry Torokhov 
37d05e84e6SDmitry Torokhov #include <linux/kernel.h>
38d05e84e6SDmitry Torokhov #include <linux/slab.h>
39d05e84e6SDmitry Torokhov #include <linux/input.h>
40d05e84e6SDmitry Torokhov #include <linux/module.h>
41d05e84e6SDmitry Torokhov #include <linux/usb.h>
42d05e84e6SDmitry Torokhov #include <linux/usb/input.h>
43ec42d448SDaniel Ritz #include <linux/hid.h>
4412e510dbSMarcus Folkesson #include <linux/mutex.h>
45d05e84e6SDmitry Torokhov 
4690ab5ee9SRusty Russell static bool swap_xy;
47d05e84e6SDmitry Torokhov module_param(swap_xy, bool, 0644);
48d05e84e6SDmitry Torokhov MODULE_PARM_DESC(swap_xy, "If set X and Y axes are swapped.");
49d05e84e6SDmitry Torokhov 
5090ab5ee9SRusty Russell static bool hwcalib_xy;
51c9cbf3d3SDan Streetman module_param(hwcalib_xy, bool, 0644);
52c9cbf3d3SDan Streetman MODULE_PARM_DESC(hwcalib_xy, "If set hw-calibrated X/Y are used if available");
53c9cbf3d3SDan Streetman 
54d05e84e6SDmitry Torokhov /* device specifc data/functions */
55d05e84e6SDmitry Torokhov struct usbtouch_usb;
56d05e84e6SDmitry Torokhov struct usbtouch_device_info {
57d05e84e6SDmitry Torokhov 	int min_xc, max_xc;
58d05e84e6SDmitry Torokhov 	int min_yc, max_yc;
59d05e84e6SDmitry Torokhov 	int min_press, max_press;
60d05e84e6SDmitry Torokhov 	int rept_size;
61d05e84e6SDmitry Torokhov 
622330ed18SDaniel Silverstone 	/*
632330ed18SDaniel Silverstone 	 * Always service the USB devices irq not just when the input device is
642330ed18SDaniel Silverstone 	 * open. This is useful when devices have a watchdog which prevents us
652330ed18SDaniel Silverstone 	 * from periodically polling the device. Leave this unset unless your
662330ed18SDaniel Silverstone 	 * touchscreen device requires it, as it does consume more of the USB
672330ed18SDaniel Silverstone 	 * bandwidth.
682330ed18SDaniel Silverstone 	 */
692330ed18SDaniel Silverstone 	bool irq_always;
702330ed18SDaniel Silverstone 
7162aa366dSDaniel Ritz 	/*
7262aa366dSDaniel Ritz 	 * used to get the packet len. possible return values:
7362aa366dSDaniel Ritz 	 * > 0: packet len
7462aa366dSDaniel Ritz 	 * = 0: skip one byte
7562aa366dSDaniel Ritz 	 * < 0: -return value more bytes needed
7662aa366dSDaniel Ritz 	 */
77d05e84e6SDmitry Torokhov 	int  (*get_pkt_len) (unsigned char *pkt, int len);
7862aa366dSDaniel Ritz 
79d05e84e6SDmitry Torokhov 	int  (*read_data)   (struct usbtouch_usb *usbtouch, unsigned char *pkt);
80a8aef622SOliver Neukum 	int  (*alloc)       (struct usbtouch_usb *usbtouch);
81d05e84e6SDmitry Torokhov 	int  (*init)        (struct usbtouch_usb *usbtouch);
825197424cSOndrej Zary 	void (*exit)	    (struct usbtouch_usb *usbtouch);
83d05e84e6SDmitry Torokhov };
84d05e84e6SDmitry Torokhov 
85d05e84e6SDmitry Torokhov /* a usbtouch device */
86d05e84e6SDmitry Torokhov struct usbtouch_usb {
87d05e84e6SDmitry Torokhov 	unsigned char *data;
88d05e84e6SDmitry Torokhov 	dma_addr_t data_dma;
894ef38351SChristian Engelmayer 	int data_size;
90d05e84e6SDmitry Torokhov 	unsigned char *buffer;
91d05e84e6SDmitry Torokhov 	int buf_len;
92d05e84e6SDmitry Torokhov 	struct urb *irq;
93fea4d14bSOndrej Zary 	struct usb_interface *interface;
94d05e84e6SDmitry Torokhov 	struct input_dev *input;
95830f06c0SDmitry Torokhov 	const struct usbtouch_device_info *type;
9612e510dbSMarcus Folkesson 	struct mutex pm_mutex;  /* serialize access to open/suspend */
9785f46fbfSMarcus Folkesson 	bool is_open;
98d05e84e6SDmitry Torokhov 	char name[128];
99d05e84e6SDmitry Torokhov 	char phys[64];
1005197424cSOndrej Zary 	void *priv;
101d05e84e6SDmitry Torokhov 
102d05e84e6SDmitry Torokhov 	int x, y;
103d05e84e6SDmitry Torokhov 	int touch, press;
104fbb1c922SDmitry Torokhov 
105fbb1c922SDmitry Torokhov 	void (*process_pkt)(struct usbtouch_usb *usbtouch, unsigned char *pkt, int len);
106d05e84e6SDmitry Torokhov };
107d05e84e6SDmitry Torokhov 
108d05e84e6SDmitry Torokhov 
109d05e84e6SDmitry Torokhov /*****************************************************************************
1109e3b2583SFlorian Echtler  * e2i Part
1119e3b2583SFlorian Echtler  */
1129e3b2583SFlorian Echtler 
1139e3b2583SFlorian Echtler #ifdef CONFIG_TOUCHSCREEN_USB_E2I
e2i_init(struct usbtouch_usb * usbtouch)1149e3b2583SFlorian Echtler static int e2i_init(struct usbtouch_usb *usbtouch)
1159e3b2583SFlorian Echtler {
1169e3b2583SFlorian Echtler 	int ret;
117fea4d14bSOndrej Zary 	struct usb_device *udev = interface_to_usbdev(usbtouch->interface);
1189e3b2583SFlorian Echtler 
11941e81022SJohan Hovold 	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
1209e3b2583SFlorian Echtler 	                      0x01, 0x02, 0x0000, 0x0081,
1219e3b2583SFlorian Echtler 	                      NULL, 0, USB_CTRL_SET_TIMEOUT);
1229e3b2583SFlorian Echtler 
1230a5ebc88SGreg Kroah-Hartman 	dev_dbg(&usbtouch->interface->dev,
124b741ab9dSGreg Kroah-Hartman 		"%s - usb_control_msg - E2I_RESET - bytes|err: %d\n",
1259e3b2583SFlorian Echtler 		__func__, ret);
1269e3b2583SFlorian Echtler 	return ret;
1279e3b2583SFlorian Echtler }
1289e3b2583SFlorian Echtler 
e2i_read_data(struct usbtouch_usb * dev,unsigned char * pkt)1299e3b2583SFlorian Echtler static int e2i_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
1309e3b2583SFlorian Echtler {
1319e3b2583SFlorian Echtler 	int tmp = (pkt[0] << 8) | pkt[1];
1329e3b2583SFlorian Echtler 	dev->x  = (pkt[2] << 8) | pkt[3];
1339e3b2583SFlorian Echtler 	dev->y  = (pkt[4] << 8) | pkt[5];
1349e3b2583SFlorian Echtler 
1359e3b2583SFlorian Echtler 	tmp = tmp - 0xA000;
1369e3b2583SFlorian Echtler 	dev->touch = (tmp > 0);
1379e3b2583SFlorian Echtler 	dev->press = (tmp > 0 ? tmp : 0);
1389e3b2583SFlorian Echtler 
1399e3b2583SFlorian Echtler 	return 1;
1409e3b2583SFlorian Echtler }
1417f787df1SDmitry Torokhov 
1427f787df1SDmitry Torokhov static const struct usbtouch_device_info e2i_dev_info = {
1437f787df1SDmitry Torokhov 	.min_xc		= 0x0,
1447f787df1SDmitry Torokhov 	.max_xc		= 0x7fff,
1457f787df1SDmitry Torokhov 	.min_yc		= 0x0,
1467f787df1SDmitry Torokhov 	.max_yc		= 0x7fff,
1477f787df1SDmitry Torokhov 	.rept_size	= 6,
1487f787df1SDmitry Torokhov 	.init		= e2i_init,
1497f787df1SDmitry Torokhov 	.read_data	= e2i_read_data,
1507f787df1SDmitry Torokhov };
1519e3b2583SFlorian Echtler #endif
1529e3b2583SFlorian Echtler 
1539e3b2583SFlorian Echtler 
1549e3b2583SFlorian Echtler /*****************************************************************************
155d05e84e6SDmitry Torokhov  * eGalax part
156d05e84e6SDmitry Torokhov  */
157d05e84e6SDmitry Torokhov 
158c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
159d05e84e6SDmitry Torokhov 
16062aa366dSDaniel Ritz #ifndef MULTI_PACKET
16162aa366dSDaniel Ritz #define MULTI_PACKET
16262aa366dSDaniel Ritz #endif
16362aa366dSDaniel Ritz 
164d05e84e6SDmitry Torokhov #define EGALAX_PKT_TYPE_MASK		0xFE
165d05e84e6SDmitry Torokhov #define EGALAX_PKT_TYPE_REPT		0x80
166d05e84e6SDmitry Torokhov #define EGALAX_PKT_TYPE_DIAG		0x0A
167d05e84e6SDmitry Torokhov 
egalax_init(struct usbtouch_usb * usbtouch)168037a833eSForest Bond static int egalax_init(struct usbtouch_usb *usbtouch)
169037a833eSForest Bond {
170037a833eSForest Bond 	struct usb_device *udev = interface_to_usbdev(usbtouch->interface);
171*d04f9393SDmitry Torokhov 	int ret, i;
172037a833eSForest Bond 
173037a833eSForest Bond 	/*
174037a833eSForest Bond 	 * An eGalax diagnostic packet kicks the device into using the right
175037a833eSForest Bond 	 * protocol.  We send a "check active" packet.  The response will be
176037a833eSForest Bond 	 * read later and ignored.
177037a833eSForest Bond 	 */
178037a833eSForest Bond 
179*d04f9393SDmitry Torokhov 	u8 *buf __free(kfree) = kmalloc(3, GFP_KERNEL);
180037a833eSForest Bond 	if (!buf)
181037a833eSForest Bond 		return -ENOMEM;
182037a833eSForest Bond 
183037a833eSForest Bond 	buf[0] = EGALAX_PKT_TYPE_DIAG;
184037a833eSForest Bond 	buf[1] = 1;	/* length */
185037a833eSForest Bond 	buf[2] = 'A';	/* command - check active */
186037a833eSForest Bond 
187037a833eSForest Bond 	for (i = 0; i < 3; i++) {
188037a833eSForest Bond 		ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
189037a833eSForest Bond 				      0,
190037a833eSForest Bond 				      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
191037a833eSForest Bond 				      0, 0, buf, 3,
192037a833eSForest Bond 				      USB_CTRL_SET_TIMEOUT);
193037a833eSForest Bond 		if (ret != -EPIPE)
194037a833eSForest Bond 			break;
195037a833eSForest Bond 	}
196037a833eSForest Bond 
197*d04f9393SDmitry Torokhov 	return ret < 0 ? ret : 0;
198037a833eSForest Bond }
199037a833eSForest Bond 
egalax_read_data(struct usbtouch_usb * dev,unsigned char * pkt)200d05e84e6SDmitry Torokhov static int egalax_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
201d05e84e6SDmitry Torokhov {
202d05e84e6SDmitry Torokhov 	if ((pkt[0] & EGALAX_PKT_TYPE_MASK) != EGALAX_PKT_TYPE_REPT)
203d05e84e6SDmitry Torokhov 		return 0;
204d05e84e6SDmitry Torokhov 
205d05e84e6SDmitry Torokhov 	dev->x = ((pkt[3] & 0x0F) << 7) | (pkt[4] & 0x7F);
206d05e84e6SDmitry Torokhov 	dev->y = ((pkt[1] & 0x0F) << 7) | (pkt[2] & 0x7F);
207d05e84e6SDmitry Torokhov 	dev->touch = pkt[0] & 0x01;
208d05e84e6SDmitry Torokhov 
209d05e84e6SDmitry Torokhov 	return 1;
210d05e84e6SDmitry Torokhov }
211d05e84e6SDmitry Torokhov 
egalax_get_pkt_len(unsigned char * buf,int len)212d05e84e6SDmitry Torokhov static int egalax_get_pkt_len(unsigned char *buf, int len)
213d05e84e6SDmitry Torokhov {
214d05e84e6SDmitry Torokhov 	switch (buf[0] & EGALAX_PKT_TYPE_MASK) {
215d05e84e6SDmitry Torokhov 	case EGALAX_PKT_TYPE_REPT:
216d05e84e6SDmitry Torokhov 		return 5;
217d05e84e6SDmitry Torokhov 
218d05e84e6SDmitry Torokhov 	case EGALAX_PKT_TYPE_DIAG:
219d05e84e6SDmitry Torokhov 		if (len < 2)
220d05e84e6SDmitry Torokhov 			return -1;
221d05e84e6SDmitry Torokhov 
222d05e84e6SDmitry Torokhov 		return buf[1] + 2;
223d05e84e6SDmitry Torokhov 	}
224d05e84e6SDmitry Torokhov 
225d05e84e6SDmitry Torokhov 	return 0;
226d05e84e6SDmitry Torokhov }
2277f787df1SDmitry Torokhov 
2287f787df1SDmitry Torokhov static const struct usbtouch_device_info egalax_dev_info = {
2297f787df1SDmitry Torokhov 	.min_xc		= 0x0,
2307f787df1SDmitry Torokhov 	.max_xc		= 0x07ff,
2317f787df1SDmitry Torokhov 	.min_yc		= 0x0,
2327f787df1SDmitry Torokhov 	.max_yc		= 0x07ff,
2337f787df1SDmitry Torokhov 	.rept_size	= 16,
2347f787df1SDmitry Torokhov 	.get_pkt_len	= egalax_get_pkt_len,
2357f787df1SDmitry Torokhov 	.read_data	= egalax_read_data,
2367f787df1SDmitry Torokhov 	.init		= egalax_init,
2377f787df1SDmitry Torokhov };
238d05e84e6SDmitry Torokhov #endif
239d05e84e6SDmitry Torokhov 
240aa87512fSArmando Visconti /*****************************************************************************
241aa87512fSArmando Visconti  * EasyTouch part
242aa87512fSArmando Visconti  */
243aa87512fSArmando Visconti 
244aa87512fSArmando Visconti #ifdef CONFIG_TOUCHSCREEN_USB_EASYTOUCH
245aa87512fSArmando Visconti 
246aa87512fSArmando Visconti #ifndef MULTI_PACKET
247aa87512fSArmando Visconti #define MULTI_PACKET
248aa87512fSArmando Visconti #endif
249aa87512fSArmando Visconti 
250aa87512fSArmando Visconti #define ETOUCH_PKT_TYPE_MASK		0xFE
251aa87512fSArmando Visconti #define ETOUCH_PKT_TYPE_REPT		0x80
252aa87512fSArmando Visconti #define ETOUCH_PKT_TYPE_REPT2		0xB0
253aa87512fSArmando Visconti #define ETOUCH_PKT_TYPE_DIAG		0x0A
254aa87512fSArmando Visconti 
etouch_read_data(struct usbtouch_usb * dev,unsigned char * pkt)255aa87512fSArmando Visconti static int etouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
256aa87512fSArmando Visconti {
257aa87512fSArmando Visconti 	if ((pkt[0] & ETOUCH_PKT_TYPE_MASK) != ETOUCH_PKT_TYPE_REPT &&
258aa87512fSArmando Visconti 		(pkt[0] & ETOUCH_PKT_TYPE_MASK) != ETOUCH_PKT_TYPE_REPT2)
259aa87512fSArmando Visconti 		return 0;
260aa87512fSArmando Visconti 
261aa87512fSArmando Visconti 	dev->x = ((pkt[1] & 0x1F) << 7) | (pkt[2] & 0x7F);
262aa87512fSArmando Visconti 	dev->y = ((pkt[3] & 0x1F) << 7) | (pkt[4] & 0x7F);
263aa87512fSArmando Visconti 	dev->touch = pkt[0] & 0x01;
264aa87512fSArmando Visconti 
265aa87512fSArmando Visconti 	return 1;
266aa87512fSArmando Visconti }
267aa87512fSArmando Visconti 
etouch_get_pkt_len(unsigned char * buf,int len)268aa87512fSArmando Visconti static int etouch_get_pkt_len(unsigned char *buf, int len)
269aa87512fSArmando Visconti {
270aa87512fSArmando Visconti 	switch (buf[0] & ETOUCH_PKT_TYPE_MASK) {
271aa87512fSArmando Visconti 	case ETOUCH_PKT_TYPE_REPT:
272aa87512fSArmando Visconti 	case ETOUCH_PKT_TYPE_REPT2:
273aa87512fSArmando Visconti 		return 5;
274aa87512fSArmando Visconti 
275aa87512fSArmando Visconti 	case ETOUCH_PKT_TYPE_DIAG:
276aa87512fSArmando Visconti 		if (len < 2)
277aa87512fSArmando Visconti 			return -1;
278aa87512fSArmando Visconti 
279aa87512fSArmando Visconti 		return buf[1] + 2;
280aa87512fSArmando Visconti 	}
281aa87512fSArmando Visconti 
282aa87512fSArmando Visconti 	return 0;
283aa87512fSArmando Visconti }
2847f787df1SDmitry Torokhov 
2857f787df1SDmitry Torokhov static const struct usbtouch_device_info etouch_dev_info = {
2867f787df1SDmitry Torokhov 	.min_xc		= 0x0,
2877f787df1SDmitry Torokhov 	.max_xc		= 0x07ff,
2887f787df1SDmitry Torokhov 	.min_yc		= 0x0,
2897f787df1SDmitry Torokhov 	.max_yc		= 0x07ff,
2907f787df1SDmitry Torokhov 	.rept_size	= 16,
2917f787df1SDmitry Torokhov 	.get_pkt_len	= etouch_get_pkt_len,
2927f787df1SDmitry Torokhov 	.read_data	= etouch_read_data,
2937f787df1SDmitry Torokhov };
294aa87512fSArmando Visconti #endif
295d05e84e6SDmitry Torokhov 
296d05e84e6SDmitry Torokhov /*****************************************************************************
297d05e84e6SDmitry Torokhov  * PanJit Part
298d05e84e6SDmitry Torokhov  */
299c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_PANJIT
panjit_read_data(struct usbtouch_usb * dev,unsigned char * pkt)300d05e84e6SDmitry Torokhov static int panjit_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
301d05e84e6SDmitry Torokhov {
302d05e84e6SDmitry Torokhov 	dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1];
303d05e84e6SDmitry Torokhov 	dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3];
304d05e84e6SDmitry Torokhov 	dev->touch = pkt[0] & 0x01;
305d05e84e6SDmitry Torokhov 
306d05e84e6SDmitry Torokhov 	return 1;
307d05e84e6SDmitry Torokhov }
3087f787df1SDmitry Torokhov 
3097f787df1SDmitry Torokhov static const struct usbtouch_device_info panjit_dev_info = {
3107f787df1SDmitry Torokhov 	.min_xc		= 0x0,
3117f787df1SDmitry Torokhov 	.max_xc		= 0x0fff,
3127f787df1SDmitry Torokhov 	.min_yc		= 0x0,
3137f787df1SDmitry Torokhov 	.max_yc		= 0x0fff,
3147f787df1SDmitry Torokhov 	.rept_size	= 8,
3157f787df1SDmitry Torokhov 	.read_data	= panjit_read_data,
3167f787df1SDmitry Torokhov };
317d05e84e6SDmitry Torokhov #endif
318d05e84e6SDmitry Torokhov 
319d05e84e6SDmitry Torokhov 
320d05e84e6SDmitry Torokhov /*****************************************************************************
321d05e84e6SDmitry Torokhov  * 3M/Microtouch Part
322d05e84e6SDmitry Torokhov  */
323c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_3M
324d05e84e6SDmitry Torokhov 
325d05e84e6SDmitry Torokhov #define MTOUCHUSB_ASYNC_REPORT          1
326d05e84e6SDmitry Torokhov #define MTOUCHUSB_RESET                 7
327d05e84e6SDmitry Torokhov #define MTOUCHUSB_REQ_CTRLLR_ID         10
328d05e84e6SDmitry Torokhov 
32989f84b84SNick Dyer #define MTOUCHUSB_REQ_CTRLLR_ID_LEN	16
33089f84b84SNick Dyer 
mtouch_read_data(struct usbtouch_usb * dev,unsigned char * pkt)331d05e84e6SDmitry Torokhov static int mtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
332d05e84e6SDmitry Torokhov {
333c9cbf3d3SDan Streetman 	if (hwcalib_xy) {
334c9cbf3d3SDan Streetman 		dev->x = (pkt[4] << 8) | pkt[3];
335c9cbf3d3SDan Streetman 		dev->y = 0xffff - ((pkt[6] << 8) | pkt[5]);
336c9cbf3d3SDan Streetman 	} else {
337d05e84e6SDmitry Torokhov 		dev->x = (pkt[8] << 8) | pkt[7];
338d05e84e6SDmitry Torokhov 		dev->y = (pkt[10] << 8) | pkt[9];
339c9cbf3d3SDan Streetman 	}
340d05e84e6SDmitry Torokhov 	dev->touch = (pkt[2] & 0x40) ? 1 : 0;
341d05e84e6SDmitry Torokhov 
342d05e84e6SDmitry Torokhov 	return 1;
343d05e84e6SDmitry Torokhov }
344d05e84e6SDmitry Torokhov 
34589f84b84SNick Dyer struct mtouch_priv {
34689f84b84SNick Dyer 	u8 fw_rev_major;
34789f84b84SNick Dyer 	u8 fw_rev_minor;
34889f84b84SNick Dyer };
34989f84b84SNick Dyer 
mtouch_get_fw_revision(struct usbtouch_usb * usbtouch)35089f84b84SNick Dyer static int mtouch_get_fw_revision(struct usbtouch_usb *usbtouch)
35189f84b84SNick Dyer {
35289f84b84SNick Dyer 	struct usb_device *udev = interface_to_usbdev(usbtouch->interface);
35389f84b84SNick Dyer 	struct mtouch_priv *priv = usbtouch->priv;
35489f84b84SNick Dyer 	int ret;
35589f84b84SNick Dyer 
356*d04f9393SDmitry Torokhov 	u8 *buf __free(kfree) = kzalloc(MTOUCHUSB_REQ_CTRLLR_ID_LEN, GFP_NOIO);
35789f84b84SNick Dyer 	if (!buf)
35889f84b84SNick Dyer 		return -ENOMEM;
35989f84b84SNick Dyer 
36089f84b84SNick Dyer 	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
36189f84b84SNick Dyer 			      MTOUCHUSB_REQ_CTRLLR_ID,
36289f84b84SNick Dyer 			      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
36389f84b84SNick Dyer 			      0, 0, buf, MTOUCHUSB_REQ_CTRLLR_ID_LEN,
36489f84b84SNick Dyer 			      USB_CTRL_SET_TIMEOUT);
36589f84b84SNick Dyer 	if (ret != MTOUCHUSB_REQ_CTRLLR_ID_LEN) {
36689f84b84SNick Dyer 		dev_warn(&usbtouch->interface->dev,
36789f84b84SNick Dyer 			 "Failed to read FW rev: %d\n", ret);
368*d04f9393SDmitry Torokhov 		return ret < 0 ? ret : -EIO;
36989f84b84SNick Dyer 	}
37089f84b84SNick Dyer 
37189f84b84SNick Dyer 	priv->fw_rev_major = buf[3];
37289f84b84SNick Dyer 	priv->fw_rev_minor = buf[4];
37389f84b84SNick Dyer 
374*d04f9393SDmitry Torokhov 	return 0;
37589f84b84SNick Dyer }
37689f84b84SNick Dyer 
mtouch_alloc(struct usbtouch_usb * usbtouch)37789f84b84SNick Dyer static int mtouch_alloc(struct usbtouch_usb *usbtouch)
37889f84b84SNick Dyer {
379f81d03d4SErick Archer 	struct mtouch_priv *priv;
38089f84b84SNick Dyer 
381f81d03d4SErick Archer 	priv = kmalloc(sizeof(*priv), GFP_KERNEL);
382f81d03d4SErick Archer 	if (!priv)
38389f84b84SNick Dyer 		return -ENOMEM;
38489f84b84SNick Dyer 
385f81d03d4SErick Archer 	usbtouch->priv = priv;
38689f84b84SNick Dyer 	return 0;
38789f84b84SNick Dyer }
38889f84b84SNick Dyer 
mtouch_init(struct usbtouch_usb * usbtouch)389d05e84e6SDmitry Torokhov static int mtouch_init(struct usbtouch_usb *usbtouch)
390d05e84e6SDmitry Torokhov {
391d05e84e6SDmitry Torokhov 	int ret, i;
392fea4d14bSOndrej Zary 	struct usb_device *udev = interface_to_usbdev(usbtouch->interface);
393d05e84e6SDmitry Torokhov 
39489f84b84SNick Dyer 	ret = mtouch_get_fw_revision(usbtouch);
39589f84b84SNick Dyer 	if (ret)
39689f84b84SNick Dyer 		return ret;
39789f84b84SNick Dyer 
39841e81022SJohan Hovold 	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
399d05e84e6SDmitry Torokhov 	                      MTOUCHUSB_RESET,
400d05e84e6SDmitry Torokhov 	                      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
401d05e84e6SDmitry Torokhov 	                      1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
4020a5ebc88SGreg Kroah-Hartman 	dev_dbg(&usbtouch->interface->dev,
403b741ab9dSGreg Kroah-Hartman 		"%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d\n",
404ea3e6c59SHarvey Harrison 		__func__, ret);
405d05e84e6SDmitry Torokhov 	if (ret < 0)
406d05e84e6SDmitry Torokhov 		return ret;
407d05e84e6SDmitry Torokhov 	msleep(150);
408d05e84e6SDmitry Torokhov 
409d05e84e6SDmitry Torokhov 	for (i = 0; i < 3; i++) {
41041e81022SJohan Hovold 		ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
411d05e84e6SDmitry Torokhov 				      MTOUCHUSB_ASYNC_REPORT,
412d05e84e6SDmitry Torokhov 				      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
413d05e84e6SDmitry Torokhov 				      1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT);
4140a5ebc88SGreg Kroah-Hartman 		dev_dbg(&usbtouch->interface->dev,
415b741ab9dSGreg Kroah-Hartman 			"%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d\n",
416ea3e6c59SHarvey Harrison 			__func__, ret);
417d05e84e6SDmitry Torokhov 		if (ret >= 0)
418d05e84e6SDmitry Torokhov 			break;
419d05e84e6SDmitry Torokhov 		if (ret != -EPIPE)
420d05e84e6SDmitry Torokhov 			return ret;
421d05e84e6SDmitry Torokhov 	}
422d05e84e6SDmitry Torokhov 
423c9cbf3d3SDan Streetman 	/* Default min/max xy are the raw values, override if using hw-calib */
424c9cbf3d3SDan Streetman 	if (hwcalib_xy) {
425c9cbf3d3SDan Streetman 		input_set_abs_params(usbtouch->input, ABS_X, 0, 0xffff, 0, 0);
426c9cbf3d3SDan Streetman 		input_set_abs_params(usbtouch->input, ABS_Y, 0, 0xffff, 0, 0);
427c9cbf3d3SDan Streetman 	}
428c9cbf3d3SDan Streetman 
429d05e84e6SDmitry Torokhov 	return 0;
430d05e84e6SDmitry Torokhov }
43189f84b84SNick Dyer 
mtouch_exit(struct usbtouch_usb * usbtouch)43289f84b84SNick Dyer static void mtouch_exit(struct usbtouch_usb *usbtouch)
43389f84b84SNick Dyer {
43489f84b84SNick Dyer 	struct mtouch_priv *priv = usbtouch->priv;
43589f84b84SNick Dyer 
43689f84b84SNick Dyer 	kfree(priv);
43789f84b84SNick Dyer }
4387f787df1SDmitry Torokhov 
4397f787df1SDmitry Torokhov static struct usbtouch_device_info mtouch_dev_info = {
4407f787df1SDmitry Torokhov 	.min_xc		= 0x0,
4417f787df1SDmitry Torokhov 	.max_xc		= 0x4000,
4427f787df1SDmitry Torokhov 	.min_yc		= 0x0,
4437f787df1SDmitry Torokhov 	.max_yc		= 0x4000,
4447f787df1SDmitry Torokhov 	.rept_size	= 11,
4457f787df1SDmitry Torokhov 	.read_data	= mtouch_read_data,
4467f787df1SDmitry Torokhov 	.alloc		= mtouch_alloc,
4477f787df1SDmitry Torokhov 	.init		= mtouch_init,
4487f787df1SDmitry Torokhov 	.exit		= mtouch_exit,
4497f787df1SDmitry Torokhov };
4507f787df1SDmitry Torokhov 
mtouch_firmware_rev_show(struct device * dev,struct device_attribute * attr,char * output)4517f787df1SDmitry Torokhov static ssize_t mtouch_firmware_rev_show(struct device *dev,
4527f787df1SDmitry Torokhov 				struct device_attribute *attr, char *output)
4537f787df1SDmitry Torokhov {
4547f787df1SDmitry Torokhov 	struct usb_interface *intf = to_usb_interface(dev);
4557f787df1SDmitry Torokhov 	struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
4567f787df1SDmitry Torokhov 	struct mtouch_priv *priv = usbtouch->priv;
4577f787df1SDmitry Torokhov 
4587f787df1SDmitry Torokhov 	return sysfs_emit(output, "%1x.%1x\n",
4597f787df1SDmitry Torokhov 			  priv->fw_rev_major, priv->fw_rev_minor);
4607f787df1SDmitry Torokhov }
4617f787df1SDmitry Torokhov static DEVICE_ATTR(firmware_rev, 0444, mtouch_firmware_rev_show, NULL);
4627f787df1SDmitry Torokhov 
4637f787df1SDmitry Torokhov static struct attribute *mtouch_attrs[] = {
4647f787df1SDmitry Torokhov 	&dev_attr_firmware_rev.attr,
4657f787df1SDmitry Torokhov 	NULL
4667f787df1SDmitry Torokhov };
4677f787df1SDmitry Torokhov 
mtouch_group_visible(struct kobject * kobj)4687f787df1SDmitry Torokhov static bool mtouch_group_visible(struct kobject *kobj)
4697f787df1SDmitry Torokhov {
4707f787df1SDmitry Torokhov 	struct device *dev = kobj_to_dev(kobj);
4717f787df1SDmitry Torokhov 	struct usb_interface *intf = to_usb_interface(dev);
4727f787df1SDmitry Torokhov 	struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
4737f787df1SDmitry Torokhov 
4747f787df1SDmitry Torokhov 	return usbtouch->type == &mtouch_dev_info;
4757f787df1SDmitry Torokhov }
4767f787df1SDmitry Torokhov 
4777f787df1SDmitry Torokhov DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(mtouch);
4787f787df1SDmitry Torokhov 
4797f787df1SDmitry Torokhov static const struct attribute_group mtouch_attr_group = {
4807f787df1SDmitry Torokhov 	.is_visible = SYSFS_GROUP_VISIBLE(mtouch),
4817f787df1SDmitry Torokhov 	.attrs = mtouch_attrs,
4827f787df1SDmitry Torokhov };
483d05e84e6SDmitry Torokhov #endif
484d05e84e6SDmitry Torokhov 
485d05e84e6SDmitry Torokhov 
486d05e84e6SDmitry Torokhov /*****************************************************************************
487d05e84e6SDmitry Torokhov  * ITM Part
488d05e84e6SDmitry Torokhov  */
489c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_ITM
itm_read_data(struct usbtouch_usb * dev,unsigned char * pkt)490d05e84e6SDmitry Torokhov static int itm_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
491d05e84e6SDmitry Torokhov {
492d05e84e6SDmitry Torokhov 	int touch;
493d05e84e6SDmitry Torokhov 	/*
494d05e84e6SDmitry Torokhov 	 * ITM devices report invalid x/y data if not touched.
495d05e84e6SDmitry Torokhov 	 * if the screen was touched before but is not touched any more
496d05e84e6SDmitry Torokhov 	 * report touch as 0 with the last valid x/y data once. then stop
497d05e84e6SDmitry Torokhov 	 * reporting data until touched again.
498d05e84e6SDmitry Torokhov 	 */
499d05e84e6SDmitry Torokhov 	dev->press = ((pkt[2] & 0x01) << 7) | (pkt[5] & 0x7F);
500d05e84e6SDmitry Torokhov 
501d05e84e6SDmitry Torokhov 	touch = ~pkt[7] & 0x20;
502d05e84e6SDmitry Torokhov 	if (!touch) {
503d05e84e6SDmitry Torokhov 		if (dev->touch) {
504d05e84e6SDmitry Torokhov 			dev->touch = 0;
505d05e84e6SDmitry Torokhov 			return 1;
506d05e84e6SDmitry Torokhov 		}
507d05e84e6SDmitry Torokhov 
508d05e84e6SDmitry Torokhov 		return 0;
509d05e84e6SDmitry Torokhov 	}
510d05e84e6SDmitry Torokhov 
511d05e84e6SDmitry Torokhov 	dev->x = ((pkt[0] & 0x1F) << 7) | (pkt[3] & 0x7F);
512d05e84e6SDmitry Torokhov 	dev->y = ((pkt[1] & 0x1F) << 7) | (pkt[4] & 0x7F);
513d05e84e6SDmitry Torokhov 	dev->touch = touch;
514d05e84e6SDmitry Torokhov 
515d05e84e6SDmitry Torokhov 	return 1;
516d05e84e6SDmitry Torokhov }
5177f787df1SDmitry Torokhov 
5187f787df1SDmitry Torokhov static const struct usbtouch_device_info itm_dev_info = {
5197f787df1SDmitry Torokhov 	.min_xc		= 0x0,
5207f787df1SDmitry Torokhov 	.max_xc		= 0x0fff,
5217f787df1SDmitry Torokhov 	.min_yc		= 0x0,
5227f787df1SDmitry Torokhov 	.max_yc		= 0x0fff,
5237f787df1SDmitry Torokhov 	.max_press	= 0xff,
5247f787df1SDmitry Torokhov 	.rept_size	= 8,
5257f787df1SDmitry Torokhov 	.read_data	= itm_read_data,
5267f787df1SDmitry Torokhov };
527d05e84e6SDmitry Torokhov #endif
528d05e84e6SDmitry Torokhov 
529d05e84e6SDmitry Torokhov 
530d05e84e6SDmitry Torokhov /*****************************************************************************
531d05e84e6SDmitry Torokhov  * eTurboTouch part
532d05e84e6SDmitry Torokhov  */
533c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_ETURBO
53462aa366dSDaniel Ritz #ifndef MULTI_PACKET
53562aa366dSDaniel Ritz #define MULTI_PACKET
53662aa366dSDaniel Ritz #endif
eturbo_read_data(struct usbtouch_usb * dev,unsigned char * pkt)537d05e84e6SDmitry Torokhov static int eturbo_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
538d05e84e6SDmitry Torokhov {
539d05e84e6SDmitry Torokhov 	unsigned int shift;
540d05e84e6SDmitry Torokhov 
541d05e84e6SDmitry Torokhov 	/* packets should start with sync */
542d05e84e6SDmitry Torokhov 	if (!(pkt[0] & 0x80))
543d05e84e6SDmitry Torokhov 		return 0;
544d05e84e6SDmitry Torokhov 
545d05e84e6SDmitry Torokhov 	shift = (6 - (pkt[0] & 0x03));
546d05e84e6SDmitry Torokhov 	dev->x = ((pkt[3] << 7) | pkt[4]) >> shift;
547d05e84e6SDmitry Torokhov 	dev->y = ((pkt[1] << 7) | pkt[2]) >> shift;
548d05e84e6SDmitry Torokhov 	dev->touch = (pkt[0] & 0x10) ? 1 : 0;
549d05e84e6SDmitry Torokhov 
550d05e84e6SDmitry Torokhov 	return 1;
551d05e84e6SDmitry Torokhov }
552d05e84e6SDmitry Torokhov 
eturbo_get_pkt_len(unsigned char * buf,int len)553d05e84e6SDmitry Torokhov static int eturbo_get_pkt_len(unsigned char *buf, int len)
554d05e84e6SDmitry Torokhov {
555d05e84e6SDmitry Torokhov 	if (buf[0] & 0x80)
556d05e84e6SDmitry Torokhov 		return 5;
557d05e84e6SDmitry Torokhov 	if (buf[0] == 0x01)
558d05e84e6SDmitry Torokhov 		return 3;
559d05e84e6SDmitry Torokhov 	return 0;
560d05e84e6SDmitry Torokhov }
5617f787df1SDmitry Torokhov 
5627f787df1SDmitry Torokhov static const struct usbtouch_device_info eturbo_dev_info = {
5637f787df1SDmitry Torokhov 	.min_xc		= 0x0,
5647f787df1SDmitry Torokhov 	.max_xc		= 0x07ff,
5657f787df1SDmitry Torokhov 	.min_yc		= 0x0,
5667f787df1SDmitry Torokhov 	.max_yc		= 0x07ff,
5677f787df1SDmitry Torokhov 	.rept_size	= 8,
5687f787df1SDmitry Torokhov 	.get_pkt_len	= eturbo_get_pkt_len,
5697f787df1SDmitry Torokhov 	.read_data	= eturbo_read_data,
5707f787df1SDmitry Torokhov };
571d05e84e6SDmitry Torokhov #endif
572d05e84e6SDmitry Torokhov 
573d05e84e6SDmitry Torokhov 
574d05e84e6SDmitry Torokhov /*****************************************************************************
575d05e84e6SDmitry Torokhov  * Gunze part
576d05e84e6SDmitry Torokhov  */
577c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_GUNZE
gunze_read_data(struct usbtouch_usb * dev,unsigned char * pkt)578d05e84e6SDmitry Torokhov static int gunze_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
579d05e84e6SDmitry Torokhov {
580d05e84e6SDmitry Torokhov 	if (!(pkt[0] & 0x80) || ((pkt[1] | pkt[2] | pkt[3]) & 0x80))
581d05e84e6SDmitry Torokhov 		return 0;
582d05e84e6SDmitry Torokhov 
583d05e84e6SDmitry Torokhov 	dev->x = ((pkt[0] & 0x1F) << 7) | (pkt[2] & 0x7F);
584d05e84e6SDmitry Torokhov 	dev->y = ((pkt[1] & 0x1F) << 7) | (pkt[3] & 0x7F);
585d05e84e6SDmitry Torokhov 	dev->touch = pkt[0] & 0x20;
586d05e84e6SDmitry Torokhov 
587d05e84e6SDmitry Torokhov 	return 1;
588d05e84e6SDmitry Torokhov }
5897f787df1SDmitry Torokhov 
5907f787df1SDmitry Torokhov static const struct usbtouch_device_info gunze_dev_info = {
5917f787df1SDmitry Torokhov 	.min_xc		= 0x0,
5927f787df1SDmitry Torokhov 	.max_xc		= 0x0fff,
5937f787df1SDmitry Torokhov 	.min_yc		= 0x0,
5947f787df1SDmitry Torokhov 	.max_yc		= 0x0fff,
5957f787df1SDmitry Torokhov 	.rept_size	= 4,
5967f787df1SDmitry Torokhov 	.read_data	= gunze_read_data,
5977f787df1SDmitry Torokhov };
598d05e84e6SDmitry Torokhov #endif
599d05e84e6SDmitry Torokhov 
600d05e84e6SDmitry Torokhov /*****************************************************************************
601d05e84e6SDmitry Torokhov  * DMC TSC-10/25 Part
602d05e84e6SDmitry Torokhov  *
603d05e84e6SDmitry Torokhov  * Documentation about the controller and it's protocol can be found at
604d05e84e6SDmitry Torokhov  *   http://www.dmccoltd.com/files/controler/tsc10usb_pi_e.pdf
605d05e84e6SDmitry Torokhov  *   http://www.dmccoltd.com/files/controler/tsc25_usb_e.pdf
606d05e84e6SDmitry Torokhov  */
607c6f8d706SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_DMC_TSC10
608d05e84e6SDmitry Torokhov 
609d05e84e6SDmitry Torokhov /* supported data rates. currently using 130 */
610d05e84e6SDmitry Torokhov #define TSC10_RATE_POINT	0x50
611d05e84e6SDmitry Torokhov #define TSC10_RATE_30		0x40
612d05e84e6SDmitry Torokhov #define TSC10_RATE_50		0x41
613d05e84e6SDmitry Torokhov #define TSC10_RATE_80		0x42
614d05e84e6SDmitry Torokhov #define TSC10_RATE_100		0x43
615d05e84e6SDmitry Torokhov #define TSC10_RATE_130		0x44
616d05e84e6SDmitry Torokhov #define TSC10_RATE_150		0x45
617d05e84e6SDmitry Torokhov 
618d05e84e6SDmitry Torokhov /* commands */
619d05e84e6SDmitry Torokhov #define TSC10_CMD_RESET		0x55
620d05e84e6SDmitry Torokhov #define TSC10_CMD_RATE		0x05
621d05e84e6SDmitry Torokhov #define TSC10_CMD_DATA1		0x01
622d05e84e6SDmitry Torokhov 
dmc_tsc10_init(struct usbtouch_usb * usbtouch)623d05e84e6SDmitry Torokhov static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
624d05e84e6SDmitry Torokhov {
625fea4d14bSOndrej Zary 	struct usb_device *dev = interface_to_usbdev(usbtouch->interface);
626*d04f9393SDmitry Torokhov 	int ret;
627d05e84e6SDmitry Torokhov 
628*d04f9393SDmitry Torokhov 	u8 *buf __free(kfree) = kmalloc(2, GFP_NOIO);
62976d057ceSOliver Neukum 	if (!buf)
630*d04f9393SDmitry Torokhov 		return -ENOMEM;
631*d04f9393SDmitry Torokhov 
632d05e84e6SDmitry Torokhov 	/* reset */
633d05e84e6SDmitry Torokhov 	buf[0] = buf[1] = 0xFF;
634d05e84e6SDmitry Torokhov 	ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
635d05e84e6SDmitry Torokhov 			      TSC10_CMD_RESET,
636d05e84e6SDmitry Torokhov 			      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
637d05e84e6SDmitry Torokhov 			      0, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
638d05e84e6SDmitry Torokhov 	if (ret < 0)
639*d04f9393SDmitry Torokhov 		return ret;
640*d04f9393SDmitry Torokhov 
641*d04f9393SDmitry Torokhov 	if (buf[0] != 0x06)
642*d04f9393SDmitry Torokhov 		return -ENODEV;
643d05e84e6SDmitry Torokhov 
64496849170SBernhard Bender 	/* TSC-25 data sheet specifies a delay after the RESET command */
64596849170SBernhard Bender 	msleep(150);
64696849170SBernhard Bender 
647d05e84e6SDmitry Torokhov 	/* set coordinate output rate */
648d05e84e6SDmitry Torokhov 	buf[0] = buf[1] = 0xFF;
649d05e84e6SDmitry Torokhov 	ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
650d05e84e6SDmitry Torokhov 			      TSC10_CMD_RATE,
651d05e84e6SDmitry Torokhov 			      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
652d05e84e6SDmitry Torokhov 			      TSC10_RATE_150, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
653d05e84e6SDmitry Torokhov 	if (ret < 0)
654*d04f9393SDmitry Torokhov 		return ret;
655*d04f9393SDmitry Torokhov 
656*d04f9393SDmitry Torokhov 	if (buf[0] != 0x06 && (buf[0] != 0x15 || buf[1] != 0x01))
657*d04f9393SDmitry Torokhov 		return -ENODEV;
658d05e84e6SDmitry Torokhov 
659d05e84e6SDmitry Torokhov 	/* start sending data */
660*d04f9393SDmitry Torokhov 	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
661d05e84e6SDmitry Torokhov 			       TSC10_CMD_DATA1,
662d05e84e6SDmitry Torokhov 			       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
663d05e84e6SDmitry Torokhov 			       0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
664d05e84e6SDmitry Torokhov }
665d05e84e6SDmitry Torokhov 
dmc_tsc10_read_data(struct usbtouch_usb * dev,unsigned char * pkt)666d05e84e6SDmitry Torokhov static int dmc_tsc10_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
667d05e84e6SDmitry Torokhov {
668d05e84e6SDmitry Torokhov 	dev->x = ((pkt[2] & 0x03) << 8) | pkt[1];
669d05e84e6SDmitry Torokhov 	dev->y = ((pkt[4] & 0x03) << 8) | pkt[3];
670d05e84e6SDmitry Torokhov 	dev->touch = pkt[0] & 0x01;
671d05e84e6SDmitry Torokhov 
672d05e84e6SDmitry Torokhov 	return 1;
673d05e84e6SDmitry Torokhov }
6747f787df1SDmitry Torokhov 
6757f787df1SDmitry Torokhov static const struct usbtouch_device_info dmc_tsc10_dev_info = {
6767f787df1SDmitry Torokhov 	.min_xc		= 0x0,
6777f787df1SDmitry Torokhov 	.max_xc		= 0x03ff,
6787f787df1SDmitry Torokhov 	.min_yc		= 0x0,
6797f787df1SDmitry Torokhov 	.max_yc		= 0x03ff,
6807f787df1SDmitry Torokhov 	.rept_size	= 5,
6817f787df1SDmitry Torokhov 	.init		= dmc_tsc10_init,
6827f787df1SDmitry Torokhov 	.read_data	= dmc_tsc10_read_data,
6837f787df1SDmitry Torokhov };
684d05e84e6SDmitry Torokhov #endif
685d05e84e6SDmitry Torokhov 
686d05e84e6SDmitry Torokhov 
687d05e84e6SDmitry Torokhov /*****************************************************************************
688df561fcdSOndrej Zary  * IRTOUCH Part
689df561fcdSOndrej Zary  */
690df561fcdSOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH
irtouch_read_data(struct usbtouch_usb * dev,unsigned char * pkt)691df561fcdSOndrej Zary static int irtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
692df561fcdSOndrej Zary {
693df561fcdSOndrej Zary 	dev->x = (pkt[3] << 8) | pkt[2];
694df561fcdSOndrej Zary 	dev->y = (pkt[5] << 8) | pkt[4];
695df561fcdSOndrej Zary 	dev->touch = (pkt[1] & 0x03) ? 1 : 0;
696df561fcdSOndrej Zary 
697df561fcdSOndrej Zary 	return 1;
698df561fcdSOndrej Zary }
6997f787df1SDmitry Torokhov 
7007f787df1SDmitry Torokhov static const struct usbtouch_device_info irtouch_dev_info = {
7017f787df1SDmitry Torokhov 	.min_xc		= 0x0,
7027f787df1SDmitry Torokhov 	.max_xc		= 0x0fff,
7037f787df1SDmitry Torokhov 	.min_yc		= 0x0,
7047f787df1SDmitry Torokhov 	.max_yc		= 0x0fff,
7057f787df1SDmitry Torokhov 	.rept_size	= 8,
7067f787df1SDmitry Torokhov 	.read_data	= irtouch_read_data,
7077f787df1SDmitry Torokhov };
7087f787df1SDmitry Torokhov 
7097f787df1SDmitry Torokhov static const struct usbtouch_device_info irtouch_hires_dev_info = {
7107f787df1SDmitry Torokhov 	.min_xc		= 0x0,
7117f787df1SDmitry Torokhov 	.max_xc		= 0x7fff,
7127f787df1SDmitry Torokhov 	.min_yc		= 0x0,
7137f787df1SDmitry Torokhov 	.max_yc		= 0x7fff,
7147f787df1SDmitry Torokhov 	.rept_size	= 8,
7157f787df1SDmitry Torokhov 	.read_data	= irtouch_read_data,
7167f787df1SDmitry Torokhov };
717df561fcdSOndrej Zary #endif
718df561fcdSOndrej Zary 
719dbe1420bSPetr Štetiar /*****************************************************************************
72038771bb4SPetr Štetiar  * ET&T TC5UH/TC4UM part
721dbe1420bSPetr Štetiar  */
72238771bb4SPetr Štetiar #ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC45USB
tc45usb_read_data(struct usbtouch_usb * dev,unsigned char * pkt)72338771bb4SPetr Štetiar static int tc45usb_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
724dbe1420bSPetr Štetiar {
725dbe1420bSPetr Štetiar 	dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1];
726dbe1420bSPetr Štetiar 	dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3];
727dbe1420bSPetr Štetiar 	dev->touch = pkt[0] & 0x01;
728dbe1420bSPetr Štetiar 
729dbe1420bSPetr Štetiar 	return 1;
730dbe1420bSPetr Štetiar }
7317f787df1SDmitry Torokhov 
7327f787df1SDmitry Torokhov static const struct usbtouch_device_info tc45usb_dev_info = {
7337f787df1SDmitry Torokhov 	.min_xc		= 0x0,
7347f787df1SDmitry Torokhov 	.max_xc		= 0x0fff,
7357f787df1SDmitry Torokhov 	.min_yc		= 0x0,
7367f787df1SDmitry Torokhov 	.max_yc		= 0x0fff,
7377f787df1SDmitry Torokhov 	.rept_size	= 5,
7387f787df1SDmitry Torokhov 	.read_data	= tc45usb_read_data,
7397f787df1SDmitry Torokhov };
740dbe1420bSPetr Štetiar #endif
741df561fcdSOndrej Zary 
742df561fcdSOndrej Zary /*****************************************************************************
743a14a8401SOndrej Zary  * IdealTEK URTC1000 Part
744a14a8401SOndrej Zary  */
745a14a8401SOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
74662aa366dSDaniel Ritz #ifndef MULTI_PACKET
74762aa366dSDaniel Ritz #define MULTI_PACKET
74862aa366dSDaniel Ritz #endif
idealtek_get_pkt_len(unsigned char * buf,int len)749a14a8401SOndrej Zary static int idealtek_get_pkt_len(unsigned char *buf, int len)
750a14a8401SOndrej Zary {
751a14a8401SOndrej Zary 	if (buf[0] & 0x80)
752a14a8401SOndrej Zary 		return 5;
753a14a8401SOndrej Zary 	if (buf[0] == 0x01)
754a14a8401SOndrej Zary 		return len;
755a14a8401SOndrej Zary 	return 0;
756a14a8401SOndrej Zary }
757a14a8401SOndrej Zary 
idealtek_read_data(struct usbtouch_usb * dev,unsigned char * pkt)758a14a8401SOndrej Zary static int idealtek_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
759a14a8401SOndrej Zary {
760a14a8401SOndrej Zary 	switch (pkt[0] & 0x98) {
761a14a8401SOndrej Zary 	case 0x88:
762a14a8401SOndrej Zary 		/* touch data in IdealTEK mode */
763a14a8401SOndrej Zary 		dev->x = (pkt[1] << 5) | (pkt[2] >> 2);
764a14a8401SOndrej Zary 		dev->y = (pkt[3] << 5) | (pkt[4] >> 2);
765a14a8401SOndrej Zary 		dev->touch = (pkt[0] & 0x40) ? 1 : 0;
766a14a8401SOndrej Zary 		return 1;
767a14a8401SOndrej Zary 
768a14a8401SOndrej Zary 	case 0x98:
769a14a8401SOndrej Zary 		/* touch data in MT emulation mode */
770a14a8401SOndrej Zary 		dev->x = (pkt[2] << 5) | (pkt[1] >> 2);
771a14a8401SOndrej Zary 		dev->y = (pkt[4] << 5) | (pkt[3] >> 2);
772a14a8401SOndrej Zary 		dev->touch = (pkt[0] & 0x40) ? 1 : 0;
773a14a8401SOndrej Zary 		return 1;
774a14a8401SOndrej Zary 
775a14a8401SOndrej Zary 	default:
776a14a8401SOndrej Zary 		return 0;
777a14a8401SOndrej Zary 	}
778a14a8401SOndrej Zary }
7797f787df1SDmitry Torokhov 
7807f787df1SDmitry Torokhov static const struct usbtouch_device_info idealtek_dev_info = {
7817f787df1SDmitry Torokhov 	.min_xc		= 0x0,
7827f787df1SDmitry Torokhov 	.max_xc		= 0x0fff,
7837f787df1SDmitry Torokhov 	.min_yc		= 0x0,
7847f787df1SDmitry Torokhov 	.max_yc		= 0x0fff,
7857f787df1SDmitry Torokhov 	.rept_size	= 8,
7867f787df1SDmitry Torokhov 	.get_pkt_len	= idealtek_get_pkt_len,
7877f787df1SDmitry Torokhov 	.read_data	= idealtek_read_data,
7887f787df1SDmitry Torokhov };
789a14a8401SOndrej Zary #endif
790a14a8401SOndrej Zary 
7919d5657dbSIlya Frolov /*****************************************************************************
7929d5657dbSIlya Frolov  * General Touch Part
7939d5657dbSIlya Frolov  */
7949d5657dbSIlya Frolov #ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
general_touch_read_data(struct usbtouch_usb * dev,unsigned char * pkt)7959d5657dbSIlya Frolov static int general_touch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
7969d5657dbSIlya Frolov {
797eb083ba2SRoy Yin 	dev->x = (pkt[2] << 8) | pkt[1];
798eb083ba2SRoy Yin 	dev->y = (pkt[4] << 8) | pkt[3];
7999d5657dbSIlya Frolov 	dev->press = pkt[5] & 0xff;
8009d5657dbSIlya Frolov 	dev->touch = pkt[0] & 0x01;
8019d5657dbSIlya Frolov 
8029d5657dbSIlya Frolov 	return 1;
8039d5657dbSIlya Frolov }
8047f787df1SDmitry Torokhov 
8057f787df1SDmitry Torokhov static const struct usbtouch_device_info general_touch_dev_info = {
8067f787df1SDmitry Torokhov 	.min_xc		= 0x0,
8077f787df1SDmitry Torokhov 	.max_xc		= 0x7fff,
8087f787df1SDmitry Torokhov 	.min_yc		= 0x0,
8097f787df1SDmitry Torokhov 	.max_yc		= 0x7fff,
8107f787df1SDmitry Torokhov 	.rept_size	= 7,
8117f787df1SDmitry Torokhov 	.read_data	= general_touch_read_data,
8127f787df1SDmitry Torokhov };
8139d5657dbSIlya Frolov #endif
814a14a8401SOndrej Zary 
815a14a8401SOndrej Zary /*****************************************************************************
81614e40206SJerrold Jones  * GoTop Part
81714e40206SJerrold Jones  */
81814e40206SJerrold Jones #ifdef CONFIG_TOUCHSCREEN_USB_GOTOP
gotop_read_data(struct usbtouch_usb * dev,unsigned char * pkt)81914e40206SJerrold Jones static int gotop_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
82014e40206SJerrold Jones {
82114e40206SJerrold Jones 	dev->x = ((pkt[1] & 0x38) << 4) | pkt[2];
82214e40206SJerrold Jones 	dev->y = ((pkt[1] & 0x07) << 7) | pkt[3];
82314e40206SJerrold Jones 	dev->touch = pkt[0] & 0x01;
824f7370699SJim Persson 
825f7370699SJim Persson 	return 1;
826f7370699SJim Persson }
8277f787df1SDmitry Torokhov 
8287f787df1SDmitry Torokhov static const struct usbtouch_device_info gotop_dev_info = {
8297f787df1SDmitry Torokhov 	.min_xc		= 0x0,
8307f787df1SDmitry Torokhov 	.max_xc		= 0x03ff,
8317f787df1SDmitry Torokhov 	.min_yc		= 0x0,
8327f787df1SDmitry Torokhov 	.max_yc		= 0x03ff,
8337f787df1SDmitry Torokhov 	.rept_size	= 4,
8347f787df1SDmitry Torokhov 	.read_data	= gotop_read_data,
8357f787df1SDmitry Torokhov };
836f7370699SJim Persson #endif
837f7370699SJim Persson 
838f7370699SJim Persson /*****************************************************************************
839f7370699SJim Persson  * JASTEC Part
840f7370699SJim Persson  */
841f7370699SJim Persson #ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
jastec_read_data(struct usbtouch_usb * dev,unsigned char * pkt)842f7370699SJim Persson static int jastec_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
843f7370699SJim Persson {
844f7370699SJim Persson 	dev->x = ((pkt[0] & 0x3f) << 6) | (pkt[2] & 0x3f);
845f7370699SJim Persson 	dev->y = ((pkt[1] & 0x3f) << 6) | (pkt[3] & 0x3f);
846f7370699SJim Persson 	dev->touch = (pkt[0] & 0x40) >> 6;
847f7370699SJim Persson 
84814e40206SJerrold Jones 	return 1;
84914e40206SJerrold Jones }
8507f787df1SDmitry Torokhov 
8517f787df1SDmitry Torokhov static const struct usbtouch_device_info jastec_dev_info = {
8527f787df1SDmitry Torokhov 	.min_xc		= 0x0,
8537f787df1SDmitry Torokhov 	.max_xc		= 0x0fff,
8547f787df1SDmitry Torokhov 	.min_yc		= 0x0,
8557f787df1SDmitry Torokhov 	.max_yc		= 0x0fff,
8567f787df1SDmitry Torokhov 	.rept_size	= 4,
8577f787df1SDmitry Torokhov 	.read_data	= jastec_read_data,
8587f787df1SDmitry Torokhov };
85914e40206SJerrold Jones #endif
86014e40206SJerrold Jones 
8612330ed18SDaniel Silverstone /*****************************************************************************
8622330ed18SDaniel Silverstone  * Zytronic Part
8632330ed18SDaniel Silverstone  */
8642330ed18SDaniel Silverstone #ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC
zytronic_read_data(struct usbtouch_usb * dev,unsigned char * pkt)8652330ed18SDaniel Silverstone static int zytronic_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
8662330ed18SDaniel Silverstone {
8670a5ebc88SGreg Kroah-Hartman 	struct usb_interface *intf = dev->interface;
868b741ab9dSGreg Kroah-Hartman 
8692330ed18SDaniel Silverstone 	switch (pkt[0]) {
8702330ed18SDaniel Silverstone 	case 0x3A: /* command response */
8710a5ebc88SGreg Kroah-Hartman 		dev_dbg(&intf->dev, "%s: Command response %d\n", __func__, pkt[1]);
8722330ed18SDaniel Silverstone 		break;
8732330ed18SDaniel Silverstone 
8742330ed18SDaniel Silverstone 	case 0xC0: /* down */
8752330ed18SDaniel Silverstone 		dev->x = (pkt[1] & 0x7f) | ((pkt[2] & 0x07) << 7);
8762330ed18SDaniel Silverstone 		dev->y = (pkt[3] & 0x7f) | ((pkt[4] & 0x07) << 7);
8772330ed18SDaniel Silverstone 		dev->touch = 1;
8780a5ebc88SGreg Kroah-Hartman 		dev_dbg(&intf->dev, "%s: down %d,%d\n", __func__, dev->x, dev->y);
8792330ed18SDaniel Silverstone 		return 1;
8802330ed18SDaniel Silverstone 
8812330ed18SDaniel Silverstone 	case 0x80: /* up */
8822330ed18SDaniel Silverstone 		dev->x = (pkt[1] & 0x7f) | ((pkt[2] & 0x07) << 7);
8832330ed18SDaniel Silverstone 		dev->y = (pkt[3] & 0x7f) | ((pkt[4] & 0x07) << 7);
8842330ed18SDaniel Silverstone 		dev->touch = 0;
8850a5ebc88SGreg Kroah-Hartman 		dev_dbg(&intf->dev, "%s: up %d,%d\n", __func__, dev->x, dev->y);
8862330ed18SDaniel Silverstone 		return 1;
8872330ed18SDaniel Silverstone 
8882330ed18SDaniel Silverstone 	default:
8890a5ebc88SGreg Kroah-Hartman 		dev_dbg(&intf->dev, "%s: Unknown return %d\n", __func__, pkt[0]);
8902330ed18SDaniel Silverstone 		break;
8912330ed18SDaniel Silverstone 	}
8922330ed18SDaniel Silverstone 
8932330ed18SDaniel Silverstone 	return 0;
8942330ed18SDaniel Silverstone }
8957f787df1SDmitry Torokhov 
8967f787df1SDmitry Torokhov static const struct usbtouch_device_info zytronic_dev_info = {
8977f787df1SDmitry Torokhov 	.min_xc		= 0x0,
8987f787df1SDmitry Torokhov 	.max_xc		= 0x03ff,
8997f787df1SDmitry Torokhov 	.min_yc		= 0x0,
9007f787df1SDmitry Torokhov 	.max_yc		= 0x03ff,
9017f787df1SDmitry Torokhov 	.rept_size	= 5,
9027f787df1SDmitry Torokhov 	.read_data	= zytronic_read_data,
9037f787df1SDmitry Torokhov 	.irq_always     = true,
9047f787df1SDmitry Torokhov };
9052330ed18SDaniel Silverstone #endif
90614e40206SJerrold Jones 
90714e40206SJerrold Jones /*****************************************************************************
9085197424cSOndrej Zary  * NEXIO Part
9095197424cSOndrej Zary  */
9105197424cSOndrej Zary #ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
9115197424cSOndrej Zary 
9125197424cSOndrej Zary #define NEXIO_TIMEOUT	5000
9135197424cSOndrej Zary #define NEXIO_BUFSIZE	1024
9145197424cSOndrej Zary #define NEXIO_THRESHOLD	50
9155197424cSOndrej Zary 
9165197424cSOndrej Zary struct nexio_priv {
9175197424cSOndrej Zary 	struct urb *ack;
9185197424cSOndrej Zary 	unsigned char *ack_buf;
9195197424cSOndrej Zary };
9205197424cSOndrej Zary 
9215197424cSOndrej Zary struct nexio_touch_packet {
9225197424cSOndrej Zary 	u8	flags;		/* 0xe1 = touch, 0xe1 = release */
9235197424cSOndrej Zary 	__be16	data_len;	/* total bytes of touch data */
9245197424cSOndrej Zary 	__be16	x_len;		/* bytes for X axis */
9255197424cSOndrej Zary 	__be16	y_len;		/* bytes for Y axis */
9265197424cSOndrej Zary 	u8	data[];
9275197424cSOndrej Zary } __attribute__ ((packed));
9285197424cSOndrej Zary 
9295197424cSOndrej Zary static unsigned char nexio_ack_pkt[2] = { 0xaa, 0x02 };
9305197424cSOndrej Zary static unsigned char nexio_init_pkt[4] = { 0x82, 0x04, 0x0a, 0x0f };
9315197424cSOndrej Zary 
nexio_ack_complete(struct urb * urb)9325197424cSOndrej Zary static void nexio_ack_complete(struct urb *urb)
9335197424cSOndrej Zary {
9345197424cSOndrej Zary }
9355197424cSOndrej Zary 
nexio_alloc(struct usbtouch_usb * usbtouch)936a8aef622SOliver Neukum static int nexio_alloc(struct usbtouch_usb *usbtouch)
937a8aef622SOliver Neukum {
938a8aef622SOliver Neukum 	struct nexio_priv *priv;
939a8aef622SOliver Neukum 	int ret = -ENOMEM;
940a8aef622SOliver Neukum 
941f81d03d4SErick Archer 	priv = kmalloc(sizeof(*priv), GFP_KERNEL);
942f81d03d4SErick Archer 	if (!priv)
943a8aef622SOliver Neukum 		goto out_buf;
944a8aef622SOliver Neukum 
945f81d03d4SErick Archer 	usbtouch->priv = priv;
946a8aef622SOliver Neukum 	priv->ack_buf = kmemdup(nexio_ack_pkt, sizeof(nexio_ack_pkt),
947a8aef622SOliver Neukum 				GFP_KERNEL);
948a8aef622SOliver Neukum 	if (!priv->ack_buf)
949a8aef622SOliver Neukum 		goto err_priv;
950a8aef622SOliver Neukum 
951a8aef622SOliver Neukum 	priv->ack = usb_alloc_urb(0, GFP_KERNEL);
952a8aef622SOliver Neukum 	if (!priv->ack) {
9530a5ebc88SGreg Kroah-Hartman 		dev_dbg(&usbtouch->interface->dev,
954b741ab9dSGreg Kroah-Hartman 			"%s - usb_alloc_urb failed: usbtouch->ack\n", __func__);
955a8aef622SOliver Neukum 		goto err_ack_buf;
956a8aef622SOliver Neukum 	}
957a8aef622SOliver Neukum 
958a8aef622SOliver Neukum 	return 0;
959a8aef622SOliver Neukum 
960a8aef622SOliver Neukum err_ack_buf:
961a8aef622SOliver Neukum 	kfree(priv->ack_buf);
962a8aef622SOliver Neukum err_priv:
963a8aef622SOliver Neukum 	kfree(priv);
964a8aef622SOliver Neukum out_buf:
965a8aef622SOliver Neukum 	return ret;
966a8aef622SOliver Neukum }
967a8aef622SOliver Neukum 
nexio_init(struct usbtouch_usb * usbtouch)9685197424cSOndrej Zary static int nexio_init(struct usbtouch_usb *usbtouch)
9695197424cSOndrej Zary {
9705197424cSOndrej Zary 	struct usb_device *dev = interface_to_usbdev(usbtouch->interface);
9715197424cSOndrej Zary 	struct usb_host_interface *interface = usbtouch->interface->cur_altsetting;
972a8aef622SOliver Neukum 	struct nexio_priv *priv = usbtouch->priv;
9735197424cSOndrej Zary 	int ret = -ENOMEM;
9745197424cSOndrej Zary 	int actual_len, i;
9755197424cSOndrej Zary 	char *firmware_ver = NULL, *device_name = NULL;
9765197424cSOndrej Zary 	int input_ep = 0, output_ep = 0;
9775197424cSOndrej Zary 
9785197424cSOndrej Zary 	/* find first input and output endpoint */
9795197424cSOndrej Zary 	for (i = 0; i < interface->desc.bNumEndpoints; i++) {
9805197424cSOndrej Zary 		if (!input_ep &&
9815197424cSOndrej Zary 		    usb_endpoint_dir_in(&interface->endpoint[i].desc))
9825197424cSOndrej Zary 			input_ep = interface->endpoint[i].desc.bEndpointAddress;
9835197424cSOndrej Zary 		if (!output_ep &&
9845197424cSOndrej Zary 		    usb_endpoint_dir_out(&interface->endpoint[i].desc))
9855197424cSOndrej Zary 			output_ep = interface->endpoint[i].desc.bEndpointAddress;
9865197424cSOndrej Zary 	}
9875197424cSOndrej Zary 	if (!input_ep || !output_ep)
9885197424cSOndrej Zary 		return -ENXIO;
9895197424cSOndrej Zary 
990*d04f9393SDmitry Torokhov 	u8 *buf __free(kfree) = kmalloc(NEXIO_BUFSIZE, GFP_NOIO);
9915197424cSOndrej Zary 	if (!buf)
992*d04f9393SDmitry Torokhov 		return -ENOMEM;
9935197424cSOndrej Zary 
9945197424cSOndrej Zary 	/* two empty reads */
9955197424cSOndrej Zary 	for (i = 0; i < 2; i++) {
9965197424cSOndrej Zary 		ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, input_ep),
9975197424cSOndrej Zary 				   buf, NEXIO_BUFSIZE, &actual_len,
9985197424cSOndrej Zary 				   NEXIO_TIMEOUT);
9995197424cSOndrej Zary 		if (ret < 0)
1000*d04f9393SDmitry Torokhov 			return ret;
10015197424cSOndrej Zary 	}
10025197424cSOndrej Zary 
10035197424cSOndrej Zary 	/* send init command */
10045197424cSOndrej Zary 	memcpy(buf, nexio_init_pkt, sizeof(nexio_init_pkt));
10055197424cSOndrej Zary 	ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, output_ep),
10065197424cSOndrej Zary 			   buf, sizeof(nexio_init_pkt), &actual_len,
10075197424cSOndrej Zary 			   NEXIO_TIMEOUT);
10085197424cSOndrej Zary 	if (ret < 0)
1009*d04f9393SDmitry Torokhov 		return ret;
10105197424cSOndrej Zary 
10115197424cSOndrej Zary 	/* read replies */
10125197424cSOndrej Zary 	for (i = 0; i < 3; i++) {
10135197424cSOndrej Zary 		memset(buf, 0, NEXIO_BUFSIZE);
10145197424cSOndrej Zary 		ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, input_ep),
10155197424cSOndrej Zary 				   buf, NEXIO_BUFSIZE, &actual_len,
10165197424cSOndrej Zary 				   NEXIO_TIMEOUT);
10175197424cSOndrej Zary 		if (ret < 0 || actual_len < 1 || buf[1] != actual_len)
10185197424cSOndrej Zary 			continue;
10195197424cSOndrej Zary 		switch (buf[0]) {
10205197424cSOndrej Zary 		case 0x83:	/* firmware version */
10215197424cSOndrej Zary 			if (!firmware_ver)
1022a8aef622SOliver Neukum 				firmware_ver = kstrdup(&buf[2], GFP_NOIO);
10235197424cSOndrej Zary 			break;
10245197424cSOndrej Zary 		case 0x84:	/* device name */
10255197424cSOndrej Zary 			if (!device_name)
1026a8aef622SOliver Neukum 				device_name = kstrdup(&buf[2], GFP_NOIO);
10275197424cSOndrej Zary 			break;
10285197424cSOndrej Zary 		}
10295197424cSOndrej Zary 	}
10305197424cSOndrej Zary 
10315197424cSOndrej Zary 	printk(KERN_INFO "Nexio device: %s, firmware version: %s\n",
10325197424cSOndrej Zary 	       device_name, firmware_ver);
10335197424cSOndrej Zary 
10345197424cSOndrej Zary 	kfree(firmware_ver);
10355197424cSOndrej Zary 	kfree(device_name);
10365197424cSOndrej Zary 
10375197424cSOndrej Zary 	usb_fill_bulk_urb(priv->ack, dev, usb_sndbulkpipe(dev, output_ep),
10385197424cSOndrej Zary 			  priv->ack_buf, sizeof(nexio_ack_pkt),
10395197424cSOndrej Zary 			  nexio_ack_complete, usbtouch);
10405197424cSOndrej Zary 
1041*d04f9393SDmitry Torokhov 	return 0;
10425197424cSOndrej Zary }
10435197424cSOndrej Zary 
nexio_exit(struct usbtouch_usb * usbtouch)10445197424cSOndrej Zary static void nexio_exit(struct usbtouch_usb *usbtouch)
10455197424cSOndrej Zary {
10465197424cSOndrej Zary 	struct nexio_priv *priv = usbtouch->priv;
10475197424cSOndrej Zary 
10485197424cSOndrej Zary 	usb_kill_urb(priv->ack);
10495197424cSOndrej Zary 	usb_free_urb(priv->ack);
10505197424cSOndrej Zary 	kfree(priv->ack_buf);
10515197424cSOndrej Zary 	kfree(priv);
10525197424cSOndrej Zary }
10535197424cSOndrej Zary 
nexio_read_data(struct usbtouch_usb * usbtouch,unsigned char * pkt)10545197424cSOndrej Zary static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
10555197424cSOndrej Zary {
105633f93726SLee Jones 	struct device *dev = &usbtouch->interface->dev;
10575197424cSOndrej Zary 	struct nexio_touch_packet *packet = (void *) pkt;
10585197424cSOndrej Zary 	struct nexio_priv *priv = usbtouch->priv;
10594aa5bbecSDmitry Torokhov 	unsigned int data_len = be16_to_cpu(packet->data_len);
10604aa5bbecSDmitry Torokhov 	unsigned int x_len = be16_to_cpu(packet->x_len);
10614aa5bbecSDmitry Torokhov 	unsigned int y_len = be16_to_cpu(packet->y_len);
10624aa5bbecSDmitry Torokhov 	int x, y, begin_x, begin_y, end_x, end_y, w, h, ret;
10635197424cSOndrej Zary 
10645197424cSOndrej Zary 	/* got touch data? */
10655197424cSOndrej Zary 	if ((pkt[0] & 0xe0) != 0xe0)
10665197424cSOndrej Zary 		return 0;
10675197424cSOndrej Zary 
10684aa5bbecSDmitry Torokhov 	if (data_len > 0xff)
10694aa5bbecSDmitry Torokhov 		data_len -= 0x100;
10704aa5bbecSDmitry Torokhov 	if (x_len > 0xff)
10714aa5bbecSDmitry Torokhov 		x_len -= 0x80;
1072388bbcadSOndrej Zary 
10735197424cSOndrej Zary 	/* send ACK */
10745197424cSOndrej Zary 	ret = usb_submit_urb(priv->ack, GFP_ATOMIC);
107533f93726SLee Jones 	if (ret)
107633f93726SLee Jones 		dev_warn(dev, "Failed to submit ACK URB: %d\n", ret);
10775197424cSOndrej Zary 
1078830f06c0SDmitry Torokhov 	if (!input_abs_get_max(usbtouch->input, ABS_X)) {
10794aa5bbecSDmitry Torokhov 		input_set_abs_params(usbtouch->input, ABS_X,
1080830f06c0SDmitry Torokhov 				     0, 2 * x_len, 0, 0);
10814aa5bbecSDmitry Torokhov 		input_set_abs_params(usbtouch->input, ABS_Y,
1082830f06c0SDmitry Torokhov 				     0, 2 * y_len, 0, 0);
10835197424cSOndrej Zary 	}
10845197424cSOndrej Zary 	/*
10855197424cSOndrej Zary 	 * The device reports state of IR sensors on X and Y axes.
10865197424cSOndrej Zary 	 * Each byte represents "darkness" percentage (0-100) of one element.
10875197424cSOndrej Zary 	 * 17" touchscreen reports only 64 x 52 bytes so the resolution is low.
10885197424cSOndrej Zary 	 * This also means that there's a limited multi-touch capability but
10895197424cSOndrej Zary 	 * it's disabled (and untested) here as there's no X driver for that.
10905197424cSOndrej Zary 	 */
10915197424cSOndrej Zary 	begin_x = end_x = begin_y = end_y = -1;
10924aa5bbecSDmitry Torokhov 	for (x = 0; x < x_len; x++) {
10935197424cSOndrej Zary 		if (begin_x == -1 && packet->data[x] > NEXIO_THRESHOLD) {
10945197424cSOndrej Zary 			begin_x = x;
10955197424cSOndrej Zary 			continue;
10965197424cSOndrej Zary 		}
10975197424cSOndrej Zary 		if (end_x == -1 && begin_x != -1 && packet->data[x] < NEXIO_THRESHOLD) {
10985197424cSOndrej Zary 			end_x = x - 1;
10994aa5bbecSDmitry Torokhov 			for (y = x_len; y < data_len; y++) {
11005197424cSOndrej Zary 				if (begin_y == -1 && packet->data[y] > NEXIO_THRESHOLD) {
11014aa5bbecSDmitry Torokhov 					begin_y = y - x_len;
11025197424cSOndrej Zary 					continue;
11035197424cSOndrej Zary 				}
11045197424cSOndrej Zary 				if (end_y == -1 &&
11055197424cSOndrej Zary 				    begin_y != -1 && packet->data[y] < NEXIO_THRESHOLD) {
11064aa5bbecSDmitry Torokhov 					end_y = y - 1 - x_len;
11075197424cSOndrej Zary 					w = end_x - begin_x;
11085197424cSOndrej Zary 					h = end_y - begin_y;
11095197424cSOndrej Zary #if 0
11105197424cSOndrej Zary 					/* multi-touch */
11115197424cSOndrej Zary 					input_report_abs(usbtouch->input,
11125197424cSOndrej Zary 						    ABS_MT_TOUCH_MAJOR, max(w,h));
11135197424cSOndrej Zary 					input_report_abs(usbtouch->input,
11145197424cSOndrej Zary 						    ABS_MT_TOUCH_MINOR, min(x,h));
11155197424cSOndrej Zary 					input_report_abs(usbtouch->input,
11165197424cSOndrej Zary 						    ABS_MT_POSITION_X, 2*begin_x+w);
11175197424cSOndrej Zary 					input_report_abs(usbtouch->input,
11185197424cSOndrej Zary 						    ABS_MT_POSITION_Y, 2*begin_y+h);
11195197424cSOndrej Zary 					input_report_abs(usbtouch->input,
11205197424cSOndrej Zary 						    ABS_MT_ORIENTATION, w > h);
11215197424cSOndrej Zary 					input_mt_sync(usbtouch->input);
11225197424cSOndrej Zary #endif
11235197424cSOndrej Zary 					/* single touch */
11245197424cSOndrej Zary 					usbtouch->x = 2 * begin_x + w;
11255197424cSOndrej Zary 					usbtouch->y = 2 * begin_y + h;
11265197424cSOndrej Zary 					usbtouch->touch = packet->flags & 0x01;
11275197424cSOndrej Zary 					begin_y = end_y = -1;
11285197424cSOndrej Zary 					return 1;
11295197424cSOndrej Zary 				}
11305197424cSOndrej Zary 			}
11315197424cSOndrej Zary 			begin_x = end_x = -1;
11325197424cSOndrej Zary 		}
11335197424cSOndrej Zary 
11345197424cSOndrej Zary 	}
11355197424cSOndrej Zary 	return 0;
11365197424cSOndrej Zary }
11377f787df1SDmitry Torokhov 
11387f787df1SDmitry Torokhov static const struct usbtouch_device_info nexio_dev_info = {
11397f787df1SDmitry Torokhov 	.rept_size	= 1024,
11407f787df1SDmitry Torokhov 	.irq_always	= true,
11417f787df1SDmitry Torokhov 	.read_data	= nexio_read_data,
11427f787df1SDmitry Torokhov 	.alloc		= nexio_alloc,
11437f787df1SDmitry Torokhov 	.init		= nexio_init,
11447f787df1SDmitry Torokhov 	.exit		= nexio_exit,
11457f787df1SDmitry Torokhov };
11465197424cSOndrej Zary #endif
11475197424cSOndrej Zary 
11485197424cSOndrej Zary 
11495197424cSOndrej Zary /*****************************************************************************
1150d2cc817aSMichael Gebetsroither  * ELO part
1151d2cc817aSMichael Gebetsroither  */
1152d2cc817aSMichael Gebetsroither 
1153d2cc817aSMichael Gebetsroither #ifdef CONFIG_TOUCHSCREEN_USB_ELO
1154d2cc817aSMichael Gebetsroither 
elo_read_data(struct usbtouch_usb * dev,unsigned char * pkt)1155d2cc817aSMichael Gebetsroither static int elo_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
1156d2cc817aSMichael Gebetsroither {
1157d2cc817aSMichael Gebetsroither 	dev->x = (pkt[3] << 8) | pkt[2];
1158d2cc817aSMichael Gebetsroither 	dev->y = (pkt[5] << 8) | pkt[4];
1159d2cc817aSMichael Gebetsroither 	dev->touch = pkt[6] > 0;
1160d2cc817aSMichael Gebetsroither 	dev->press = pkt[6];
1161d2cc817aSMichael Gebetsroither 
1162d2cc817aSMichael Gebetsroither 	return 1;
1163d2cc817aSMichael Gebetsroither }
1164d2cc817aSMichael Gebetsroither 
11657f787df1SDmitry Torokhov static const struct usbtouch_device_info elo_dev_info = {
1166d2cc817aSMichael Gebetsroither 	.min_xc		= 0x0,
1167d2cc817aSMichael Gebetsroither 	.max_xc		= 0x0fff,
1168d2cc817aSMichael Gebetsroither 	.min_yc		= 0x0,
1169d2cc817aSMichael Gebetsroither 	.max_yc		= 0x0fff,
1170d2cc817aSMichael Gebetsroither 	.max_press	= 0xff,
1171d2cc817aSMichael Gebetsroither 	.rept_size	= 8,
1172d2cc817aSMichael Gebetsroither 	.read_data	= elo_read_data,
1173d05e84e6SDmitry Torokhov };
11747f787df1SDmitry Torokhov #endif
1175d05e84e6SDmitry Torokhov 
1176d05e84e6SDmitry Torokhov 
1177d05e84e6SDmitry Torokhov /*****************************************************************************
1178d05e84e6SDmitry Torokhov  * Generic Part
1179d05e84e6SDmitry Torokhov  */
usbtouch_process_pkt(struct usbtouch_usb * usbtouch,unsigned char * pkt,int len)1180d05e84e6SDmitry Torokhov static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,
1181d05e84e6SDmitry Torokhov                                  unsigned char *pkt, int len)
1182d05e84e6SDmitry Torokhov {
1183830f06c0SDmitry Torokhov 	const struct usbtouch_device_info *type = usbtouch->type;
1184d05e84e6SDmitry Torokhov 
1185d05e84e6SDmitry Torokhov 	if (!type->read_data(usbtouch, pkt))
1186d05e84e6SDmitry Torokhov 		return;
1187d05e84e6SDmitry Torokhov 
1188d05e84e6SDmitry Torokhov 	input_report_key(usbtouch->input, BTN_TOUCH, usbtouch->touch);
1189d05e84e6SDmitry Torokhov 
1190d05e84e6SDmitry Torokhov 	if (swap_xy) {
1191d05e84e6SDmitry Torokhov 		input_report_abs(usbtouch->input, ABS_X, usbtouch->y);
1192d05e84e6SDmitry Torokhov 		input_report_abs(usbtouch->input, ABS_Y, usbtouch->x);
1193d05e84e6SDmitry Torokhov 	} else {
1194d05e84e6SDmitry Torokhov 		input_report_abs(usbtouch->input, ABS_X, usbtouch->x);
1195d05e84e6SDmitry Torokhov 		input_report_abs(usbtouch->input, ABS_Y, usbtouch->y);
1196d05e84e6SDmitry Torokhov 	}
1197d05e84e6SDmitry Torokhov 	if (type->max_press)
1198d05e84e6SDmitry Torokhov 		input_report_abs(usbtouch->input, ABS_PRESSURE, usbtouch->press);
1199d05e84e6SDmitry Torokhov 	input_sync(usbtouch->input);
1200d05e84e6SDmitry Torokhov }
1201d05e84e6SDmitry Torokhov 
1202d05e84e6SDmitry Torokhov 
1203d05e84e6SDmitry Torokhov #ifdef MULTI_PACKET
usbtouch_process_multi(struct usbtouch_usb * usbtouch,unsigned char * pkt,int len)1204d05e84e6SDmitry Torokhov static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
1205d05e84e6SDmitry Torokhov                                    unsigned char *pkt, int len)
1206d05e84e6SDmitry Torokhov {
1207d05e84e6SDmitry Torokhov 	unsigned char *buffer;
1208d05e84e6SDmitry Torokhov 	int pkt_len, pos, buf_len, tmp;
1209d05e84e6SDmitry Torokhov 
1210d05e84e6SDmitry Torokhov 	/* process buffer */
1211d05e84e6SDmitry Torokhov 	if (unlikely(usbtouch->buf_len)) {
1212d05e84e6SDmitry Torokhov 		/* try to get size */
1213d05e84e6SDmitry Torokhov 		pkt_len = usbtouch->type->get_pkt_len(
1214d05e84e6SDmitry Torokhov 				usbtouch->buffer, usbtouch->buf_len);
1215d05e84e6SDmitry Torokhov 
1216d05e84e6SDmitry Torokhov 		/* drop? */
1217d05e84e6SDmitry Torokhov 		if (unlikely(!pkt_len))
1218d05e84e6SDmitry Torokhov 			goto out_flush_buf;
1219d05e84e6SDmitry Torokhov 
1220d05e84e6SDmitry Torokhov 		/* need to append -pkt_len bytes before able to get size */
1221d05e84e6SDmitry Torokhov 		if (unlikely(pkt_len < 0)) {
1222d05e84e6SDmitry Torokhov 			int append = -pkt_len;
1223d05e84e6SDmitry Torokhov 			if (unlikely(append > len))
1224d05e84e6SDmitry Torokhov 			       append = len;
1225d05e84e6SDmitry Torokhov 			if (usbtouch->buf_len + append >= usbtouch->type->rept_size)
1226d05e84e6SDmitry Torokhov 				goto out_flush_buf;
1227d05e84e6SDmitry Torokhov 			memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, append);
1228d05e84e6SDmitry Torokhov 			usbtouch->buf_len += append;
1229d05e84e6SDmitry Torokhov 
1230d05e84e6SDmitry Torokhov 			pkt_len = usbtouch->type->get_pkt_len(
1231d05e84e6SDmitry Torokhov 					usbtouch->buffer, usbtouch->buf_len);
1232d05e84e6SDmitry Torokhov 			if (pkt_len < 0)
1233d05e84e6SDmitry Torokhov 				return;
1234d05e84e6SDmitry Torokhov 		}
1235d05e84e6SDmitry Torokhov 
1236d05e84e6SDmitry Torokhov 		/* append */
1237d05e84e6SDmitry Torokhov 		tmp = pkt_len - usbtouch->buf_len;
1238d05e84e6SDmitry Torokhov 		if (usbtouch->buf_len + tmp >= usbtouch->type->rept_size)
1239d05e84e6SDmitry Torokhov 			goto out_flush_buf;
1240d05e84e6SDmitry Torokhov 		memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, tmp);
1241d05e84e6SDmitry Torokhov 		usbtouch_process_pkt(usbtouch, usbtouch->buffer, pkt_len);
1242d05e84e6SDmitry Torokhov 
1243d05e84e6SDmitry Torokhov 		buffer = pkt + tmp;
1244d05e84e6SDmitry Torokhov 		buf_len = len - tmp;
1245d05e84e6SDmitry Torokhov 	} else {
1246d05e84e6SDmitry Torokhov 		buffer = pkt;
1247d05e84e6SDmitry Torokhov 		buf_len = len;
1248d05e84e6SDmitry Torokhov 	}
1249d05e84e6SDmitry Torokhov 
1250d05e84e6SDmitry Torokhov 	/* loop over the received packet, process */
1251d05e84e6SDmitry Torokhov 	pos = 0;
1252d05e84e6SDmitry Torokhov 	while (pos < buf_len) {
1253d05e84e6SDmitry Torokhov 		/* get packet len */
125462aa366dSDaniel Ritz 		pkt_len = usbtouch->type->get_pkt_len(buffer + pos,
125562aa366dSDaniel Ritz 							buf_len - pos);
1256d05e84e6SDmitry Torokhov 
125762aa366dSDaniel Ritz 		/* unknown packet: skip one byte */
125862aa366dSDaniel Ritz 		if (unlikely(!pkt_len)) {
125962aa366dSDaniel Ritz 			pos++;
126062aa366dSDaniel Ritz 			continue;
126162aa366dSDaniel Ritz 		}
1262d05e84e6SDmitry Torokhov 
1263d05e84e6SDmitry Torokhov 		/* full packet: process */
1264d05e84e6SDmitry Torokhov 		if (likely((pkt_len > 0) && (pkt_len <= buf_len - pos))) {
1265d05e84e6SDmitry Torokhov 			usbtouch_process_pkt(usbtouch, buffer + pos, pkt_len);
1266d05e84e6SDmitry Torokhov 		} else {
1267d05e84e6SDmitry Torokhov 			/* incomplete packet: save in buffer */
1268d05e84e6SDmitry Torokhov 			memcpy(usbtouch->buffer, buffer + pos, buf_len - pos);
1269d05e84e6SDmitry Torokhov 			usbtouch->buf_len = buf_len - pos;
1270d05e84e6SDmitry Torokhov 			return;
1271d05e84e6SDmitry Torokhov 		}
1272d05e84e6SDmitry Torokhov 		pos += pkt_len;
1273d05e84e6SDmitry Torokhov 	}
1274d05e84e6SDmitry Torokhov 
1275d05e84e6SDmitry Torokhov out_flush_buf:
1276d05e84e6SDmitry Torokhov 	usbtouch->buf_len = 0;
1277d05e84e6SDmitry Torokhov 	return;
1278d05e84e6SDmitry Torokhov }
1279fbb1c922SDmitry Torokhov #else
usbtouch_process_multi(struct usbtouch_usb * usbtouch,unsigned char * pkt,int len)1280fbb1c922SDmitry Torokhov static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
1281fbb1c922SDmitry Torokhov                                    unsigned char *pkt, int len)
1282fbb1c922SDmitry Torokhov {
1283fbb1c922SDmitry Torokhov 	dev_WARN_ONCE(&usbtouch->interface->dev, 1,
1284fbb1c922SDmitry Torokhov 		      "Protocol has ->get_pkt_len() without #define MULTI_PACKET");
1285fbb1c922SDmitry Torokhov }
1286d05e84e6SDmitry Torokhov #endif
1287d05e84e6SDmitry Torokhov 
usbtouch_irq(struct urb * urb)1288d05e84e6SDmitry Torokhov static void usbtouch_irq(struct urb *urb)
1289d05e84e6SDmitry Torokhov {
1290d05e84e6SDmitry Torokhov 	struct usbtouch_usb *usbtouch = urb->context;
12910a5ebc88SGreg Kroah-Hartman 	struct device *dev = &usbtouch->interface->dev;
1292d05e84e6SDmitry Torokhov 	int retval;
1293d05e84e6SDmitry Torokhov 
1294d05e84e6SDmitry Torokhov 	switch (urb->status) {
1295d05e84e6SDmitry Torokhov 	case 0:
1296d05e84e6SDmitry Torokhov 		/* success */
1297d05e84e6SDmitry Torokhov 		break;
1298d05e84e6SDmitry Torokhov 	case -ETIME:
1299d05e84e6SDmitry Torokhov 		/* this urb is timing out */
1300b741ab9dSGreg Kroah-Hartman 		dev_dbg(dev,
1301b741ab9dSGreg Kroah-Hartman 			"%s - urb timed out - was the device unplugged?\n",
1302ea3e6c59SHarvey Harrison 			__func__);
1303d05e84e6SDmitry Torokhov 		return;
1304d05e84e6SDmitry Torokhov 	case -ECONNRESET:
1305d05e84e6SDmitry Torokhov 	case -ENOENT:
1306d05e84e6SDmitry Torokhov 	case -ESHUTDOWN:
13075197424cSOndrej Zary 	case -EPIPE:
1308d05e84e6SDmitry Torokhov 		/* this urb is terminated, clean up */
1309b741ab9dSGreg Kroah-Hartman 		dev_dbg(dev, "%s - urb shutting down with status: %d\n",
1310ea3e6c59SHarvey Harrison 			__func__, urb->status);
1311d05e84e6SDmitry Torokhov 		return;
1312d05e84e6SDmitry Torokhov 	default:
1313b741ab9dSGreg Kroah-Hartman 		dev_dbg(dev, "%s - nonzero urb status received: %d\n",
1314ea3e6c59SHarvey Harrison 			__func__, urb->status);
1315d05e84e6SDmitry Torokhov 		goto exit;
1316d05e84e6SDmitry Torokhov 	}
1317d05e84e6SDmitry Torokhov 
1318fbb1c922SDmitry Torokhov 	usbtouch->process_pkt(usbtouch, usbtouch->data, urb->actual_length);
1319d05e84e6SDmitry Torokhov 
1320d05e84e6SDmitry Torokhov exit:
13215d9efc59SOliver Neukum 	usb_mark_last_busy(interface_to_usbdev(usbtouch->interface));
1322d05e84e6SDmitry Torokhov 	retval = usb_submit_urb(urb, GFP_ATOMIC);
1323d05e84e6SDmitry Torokhov 	if (retval)
13240a5ebc88SGreg Kroah-Hartman 		dev_err(dev, "%s - usb_submit_urb failed with result: %d\n",
1325ea3e6c59SHarvey Harrison 			__func__, retval);
1326d05e84e6SDmitry Torokhov }
1327d05e84e6SDmitry Torokhov 
usbtouch_start_io(struct usbtouch_usb * usbtouch)1328f784adb6SDmitry Torokhov static int usbtouch_start_io(struct usbtouch_usb *usbtouch)
1329f784adb6SDmitry Torokhov {
1330f784adb6SDmitry Torokhov 	guard(mutex)(&usbtouch->pm_mutex);
1331f784adb6SDmitry Torokhov 
1332f784adb6SDmitry Torokhov 	if (!usbtouch->type->irq_always)
1333f784adb6SDmitry Torokhov 		if (usb_submit_urb(usbtouch->irq, GFP_KERNEL))
1334f784adb6SDmitry Torokhov 			return -EIO;
1335f784adb6SDmitry Torokhov 
1336f784adb6SDmitry Torokhov 	usbtouch->interface->needs_remote_wakeup = 1;
1337f784adb6SDmitry Torokhov 	usbtouch->is_open = true;
1338f784adb6SDmitry Torokhov 
1339f784adb6SDmitry Torokhov 	return 0;
1340f784adb6SDmitry Torokhov }
1341f784adb6SDmitry Torokhov 
usbtouch_open(struct input_dev * input)1342d05e84e6SDmitry Torokhov static int usbtouch_open(struct input_dev *input)
1343d05e84e6SDmitry Torokhov {
1344d05e84e6SDmitry Torokhov 	struct usbtouch_usb *usbtouch = input_get_drvdata(input);
13455d9efc59SOliver Neukum 	int r;
1346d05e84e6SDmitry Torokhov 
1347fea4d14bSOndrej Zary 	usbtouch->irq->dev = interface_to_usbdev(usbtouch->interface);
1348d05e84e6SDmitry Torokhov 
13495d9efc59SOliver Neukum 	r = usb_autopm_get_interface(usbtouch->interface) ? -EIO : 0;
1350f784adb6SDmitry Torokhov 	if (r)
1351f784adb6SDmitry Torokhov 		return r;
13525d9efc59SOliver Neukum 
1353f784adb6SDmitry Torokhov 	r = usbtouch_start_io(usbtouch);
1354d05e84e6SDmitry Torokhov 
13555d9efc59SOliver Neukum 	usb_autopm_put_interface(usbtouch->interface);
13565d9efc59SOliver Neukum 	return r;
1357d05e84e6SDmitry Torokhov }
1358d05e84e6SDmitry Torokhov 
usbtouch_close(struct input_dev * input)1359d05e84e6SDmitry Torokhov static void usbtouch_close(struct input_dev *input)
1360d05e84e6SDmitry Torokhov {
1361d05e84e6SDmitry Torokhov 	struct usbtouch_usb *usbtouch = input_get_drvdata(input);
13625d9efc59SOliver Neukum 	int r;
1363d05e84e6SDmitry Torokhov 
1364f784adb6SDmitry Torokhov 	scoped_guard(mutex, &usbtouch->pm_mutex) {
13652330ed18SDaniel Silverstone 		if (!usbtouch->type->irq_always)
1366d05e84e6SDmitry Torokhov 			usb_kill_urb(usbtouch->irq);
136785f46fbfSMarcus Folkesson 		usbtouch->is_open = false;
1368f784adb6SDmitry Torokhov 	}
136912e510dbSMarcus Folkesson 
13705d9efc59SOliver Neukum 	r = usb_autopm_get_interface(usbtouch->interface);
13715d9efc59SOliver Neukum 	usbtouch->interface->needs_remote_wakeup = 0;
13725d9efc59SOliver Neukum 	if (!r)
13735d9efc59SOliver Neukum 		usb_autopm_put_interface(usbtouch->interface);
1374d05e84e6SDmitry Torokhov }
1375d05e84e6SDmitry Torokhov 
usbtouch_suspend(struct usb_interface * intf,pm_message_t message)1376f784adb6SDmitry Torokhov static int usbtouch_suspend(struct usb_interface *intf, pm_message_t message)
1377ed4299e1SOliver Neukum {
1378ed4299e1SOliver Neukum 	struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
1379ed4299e1SOliver Neukum 
1380ed4299e1SOliver Neukum 	usb_kill_urb(usbtouch->irq);
1381ed4299e1SOliver Neukum 
1382ed4299e1SOliver Neukum 	return 0;
1383ed4299e1SOliver Neukum }
1384ed4299e1SOliver Neukum 
usbtouch_resume(struct usb_interface * intf)1385ed4299e1SOliver Neukum static int usbtouch_resume(struct usb_interface *intf)
1386ed4299e1SOliver Neukum {
1387ed4299e1SOliver Neukum 	struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
1388ed4299e1SOliver Neukum 
1389f784adb6SDmitry Torokhov 	guard(mutex)(&usbtouch->pm_mutex);
1390f784adb6SDmitry Torokhov 
139185f46fbfSMarcus Folkesson 	if (usbtouch->is_open || usbtouch->type->irq_always)
1392f784adb6SDmitry Torokhov 		return usb_submit_urb(usbtouch->irq, GFP_NOIO);
1393ed4299e1SOliver Neukum 
1394f784adb6SDmitry Torokhov 	return 0;
1395ed4299e1SOliver Neukum }
1396d05e84e6SDmitry Torokhov 
usbtouch_reset_resume(struct usb_interface * intf)1397a8aef622SOliver Neukum static int usbtouch_reset_resume(struct usb_interface *intf)
1398a8aef622SOliver Neukum {
1399a8aef622SOliver Neukum 	struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
1400f784adb6SDmitry Torokhov 	int err;
1401a8aef622SOliver Neukum 
1402a8aef622SOliver Neukum 	/* reinit the device */
1403a8aef622SOliver Neukum 	if (usbtouch->type->init) {
1404a8aef622SOliver Neukum 		err = usbtouch->type->init(usbtouch);
1405a8aef622SOliver Neukum 		if (err) {
14060a5ebc88SGreg Kroah-Hartman 			dev_dbg(&intf->dev,
1407b741ab9dSGreg Kroah-Hartman 				"%s - type->init() failed, err: %d\n",
1408a8aef622SOliver Neukum 				__func__, err);
1409a8aef622SOliver Neukum 			return err;
1410a8aef622SOliver Neukum 		}
1411a8aef622SOliver Neukum 	}
1412a8aef622SOliver Neukum 
1413a8aef622SOliver Neukum 	/* restart IO if needed */
1414f784adb6SDmitry Torokhov 	guard(mutex)(&usbtouch->pm_mutex);
1415a8aef622SOliver Neukum 
1416f784adb6SDmitry Torokhov 	if (usbtouch->is_open)
1417f784adb6SDmitry Torokhov 		return usb_submit_urb(usbtouch->irq, GFP_NOIO);
1418f784adb6SDmitry Torokhov 
1419f784adb6SDmitry Torokhov 	return 0;
1420a8aef622SOliver Neukum }
1421a8aef622SOliver Neukum 
usbtouch_free_buffers(struct usb_device * udev,struct usbtouch_usb * usbtouch)1422d05e84e6SDmitry Torokhov static void usbtouch_free_buffers(struct usb_device *udev,
1423d05e84e6SDmitry Torokhov 				  struct usbtouch_usb *usbtouch)
1424d05e84e6SDmitry Torokhov {
14254ef38351SChristian Engelmayer 	usb_free_coherent(udev, usbtouch->data_size,
1426d05e84e6SDmitry Torokhov 			  usbtouch->data, usbtouch->data_dma);
1427d05e84e6SDmitry Torokhov 	kfree(usbtouch->buffer);
1428d05e84e6SDmitry Torokhov }
1429d05e84e6SDmitry Torokhov 
1430f4a5e359SOndrej Zary static struct usb_endpoint_descriptor *
usbtouch_get_input_endpoint(struct usb_host_interface * interface)1431f4a5e359SOndrej Zary usbtouch_get_input_endpoint(struct usb_host_interface *interface)
1432f4a5e359SOndrej Zary {
1433f4a5e359SOndrej Zary 	int i;
1434f4a5e359SOndrej Zary 
1435f4a5e359SOndrej Zary 	for (i = 0; i < interface->desc.bNumEndpoints; i++)
1436f4a5e359SOndrej Zary 		if (usb_endpoint_dir_in(&interface->endpoint[i].desc))
1437f4a5e359SOndrej Zary 			return &interface->endpoint[i].desc;
1438f4a5e359SOndrej Zary 
1439f4a5e359SOndrej Zary 	return NULL;
1440f4a5e359SOndrej Zary }
1441d05e84e6SDmitry Torokhov 
usbtouch_probe(struct usb_interface * intf,const struct usb_device_id * id)1442d05e84e6SDmitry Torokhov static int usbtouch_probe(struct usb_interface *intf,
1443d05e84e6SDmitry Torokhov 			  const struct usb_device_id *id)
1444d05e84e6SDmitry Torokhov {
1445d05e84e6SDmitry Torokhov 	struct usbtouch_usb *usbtouch;
1446d05e84e6SDmitry Torokhov 	struct input_dev *input_dev;
1447d05e84e6SDmitry Torokhov 	struct usb_endpoint_descriptor *endpoint;
1448d05e84e6SDmitry Torokhov 	struct usb_device *udev = interface_to_usbdev(intf);
1449830f06c0SDmitry Torokhov 	const struct usbtouch_device_info *type;
1450d05e84e6SDmitry Torokhov 	int err = -ENOMEM;
1451d05e84e6SDmitry Torokhov 
1452ec42d448SDaniel Ritz 	/* some devices are ignored */
14537f787df1SDmitry Torokhov 	type = (const struct usbtouch_device_info *)id->driver_info;
14547f787df1SDmitry Torokhov 	if (!type)
1455039d4ed3SJohan Hovold 		return -ENODEV;
1456039d4ed3SJohan Hovold 
1457f4a5e359SOndrej Zary 	endpoint = usbtouch_get_input_endpoint(intf->cur_altsetting);
1458f4a5e359SOndrej Zary 	if (!endpoint)
1459f4a5e359SOndrej Zary 		return -ENXIO;
1460d05e84e6SDmitry Torokhov 
1461f81d03d4SErick Archer 	usbtouch = kzalloc(sizeof(*usbtouch), GFP_KERNEL);
1462d05e84e6SDmitry Torokhov 	input_dev = input_allocate_device();
1463d05e84e6SDmitry Torokhov 	if (!usbtouch || !input_dev)
1464d05e84e6SDmitry Torokhov 		goto out_free;
1465d05e84e6SDmitry Torokhov 
1466b55d996fSOliver Neukum 	mutex_init(&usbtouch->pm_mutex);
1467d05e84e6SDmitry Torokhov 	usbtouch->type = type;
1468d05e84e6SDmitry Torokhov 
14694ef38351SChristian Engelmayer 	usbtouch->data_size = type->rept_size;
14704ef38351SChristian Engelmayer 	if (type->get_pkt_len) {
14714ef38351SChristian Engelmayer 		/*
14724ef38351SChristian Engelmayer 		 * When dealing with variable-length packets we should
14734ef38351SChristian Engelmayer 		 * not request more than wMaxPacketSize bytes at once
14744ef38351SChristian Engelmayer 		 * as we do not know if there is more data coming or
14754ef38351SChristian Engelmayer 		 * we filled exactly wMaxPacketSize bytes and there is
14764ef38351SChristian Engelmayer 		 * nothing else.
14774ef38351SChristian Engelmayer 		 */
14784ef38351SChristian Engelmayer 		usbtouch->data_size = min(usbtouch->data_size,
14794ef38351SChristian Engelmayer 					  usb_endpoint_maxp(endpoint));
14804ef38351SChristian Engelmayer 	}
14814ef38351SChristian Engelmayer 
14824ef38351SChristian Engelmayer 	usbtouch->data = usb_alloc_coherent(udev, usbtouch->data_size,
1483d05e84e6SDmitry Torokhov 					    GFP_KERNEL, &usbtouch->data_dma);
1484d05e84e6SDmitry Torokhov 	if (!usbtouch->data)
1485d05e84e6SDmitry Torokhov 		goto out_free;
1486d05e84e6SDmitry Torokhov 
148762aa366dSDaniel Ritz 	if (type->get_pkt_len) {
1488d05e84e6SDmitry Torokhov 		usbtouch->buffer = kmalloc(type->rept_size, GFP_KERNEL);
1489d05e84e6SDmitry Torokhov 		if (!usbtouch->buffer)
1490d05e84e6SDmitry Torokhov 			goto out_free_buffers;
1491fbb1c922SDmitry Torokhov 		usbtouch->process_pkt = usbtouch_process_multi;
1492fbb1c922SDmitry Torokhov 	} else {
1493fbb1c922SDmitry Torokhov 		usbtouch->process_pkt = usbtouch_process_pkt;
1494d05e84e6SDmitry Torokhov 	}
1495d05e84e6SDmitry Torokhov 
1496d05e84e6SDmitry Torokhov 	usbtouch->irq = usb_alloc_urb(0, GFP_KERNEL);
1497d05e84e6SDmitry Torokhov 	if (!usbtouch->irq) {
1498b741ab9dSGreg Kroah-Hartman 		dev_dbg(&intf->dev,
1499b741ab9dSGreg Kroah-Hartman 			"%s - usb_alloc_urb failed: usbtouch->irq\n", __func__);
1500d05e84e6SDmitry Torokhov 		goto out_free_buffers;
1501d05e84e6SDmitry Torokhov 	}
1502d05e84e6SDmitry Torokhov 
1503fea4d14bSOndrej Zary 	usbtouch->interface = intf;
1504d05e84e6SDmitry Torokhov 	usbtouch->input = input_dev;
1505d05e84e6SDmitry Torokhov 
1506d05e84e6SDmitry Torokhov 	if (udev->manufacturer)
1507a9f08ad7SWolfram Sang 		strscpy(usbtouch->name, udev->manufacturer, sizeof(usbtouch->name));
1508d05e84e6SDmitry Torokhov 
1509d05e84e6SDmitry Torokhov 	if (udev->product) {
1510d05e84e6SDmitry Torokhov 		if (udev->manufacturer)
1511d05e84e6SDmitry Torokhov 			strlcat(usbtouch->name, " ", sizeof(usbtouch->name));
1512d05e84e6SDmitry Torokhov 		strlcat(usbtouch->name, udev->product, sizeof(usbtouch->name));
1513d05e84e6SDmitry Torokhov 	}
1514d05e84e6SDmitry Torokhov 
1515d05e84e6SDmitry Torokhov 	if (!strlen(usbtouch->name))
1516d05e84e6SDmitry Torokhov 		snprintf(usbtouch->name, sizeof(usbtouch->name),
1517d05e84e6SDmitry Torokhov 			"USB Touchscreen %04x:%04x",
1518d05e84e6SDmitry Torokhov 			 le16_to_cpu(udev->descriptor.idVendor),
1519d05e84e6SDmitry Torokhov 			 le16_to_cpu(udev->descriptor.idProduct));
1520d05e84e6SDmitry Torokhov 
1521d05e84e6SDmitry Torokhov 	usb_make_path(udev, usbtouch->phys, sizeof(usbtouch->phys));
15227b6dff98SVladimir Shebordaev 	strlcat(usbtouch->phys, "/input0", sizeof(usbtouch->phys));
1523d05e84e6SDmitry Torokhov 
1524d05e84e6SDmitry Torokhov 	input_dev->name = usbtouch->name;
1525d05e84e6SDmitry Torokhov 	input_dev->phys = usbtouch->phys;
1526d05e84e6SDmitry Torokhov 	usb_to_input_id(udev, &input_dev->id);
1527d05e84e6SDmitry Torokhov 	input_dev->dev.parent = &intf->dev;
1528d05e84e6SDmitry Torokhov 
1529d05e84e6SDmitry Torokhov 	input_set_drvdata(input_dev, usbtouch);
1530d05e84e6SDmitry Torokhov 
1531d05e84e6SDmitry Torokhov 	input_dev->open = usbtouch_open;
1532d05e84e6SDmitry Torokhov 	input_dev->close = usbtouch_close;
1533d05e84e6SDmitry Torokhov 
15347b19ada2SJiri Slaby 	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
15357b19ada2SJiri Slaby 	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
1536d05e84e6SDmitry Torokhov 	input_set_abs_params(input_dev, ABS_X, type->min_xc, type->max_xc, 0, 0);
1537d05e84e6SDmitry Torokhov 	input_set_abs_params(input_dev, ABS_Y, type->min_yc, type->max_yc, 0, 0);
1538d05e84e6SDmitry Torokhov 	if (type->max_press)
1539d05e84e6SDmitry Torokhov 		input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press,
1540d05e84e6SDmitry Torokhov 		                     type->max_press, 0, 0);
1541d05e84e6SDmitry Torokhov 
15425197424cSOndrej Zary 	if (usb_endpoint_type(endpoint) == USB_ENDPOINT_XFER_INT)
1543fea4d14bSOndrej Zary 		usb_fill_int_urb(usbtouch->irq, udev,
1544fea4d14bSOndrej Zary 			 usb_rcvintpipe(udev, endpoint->bEndpointAddress),
15454ef38351SChristian Engelmayer 			 usbtouch->data, usbtouch->data_size,
1546d05e84e6SDmitry Torokhov 			 usbtouch_irq, usbtouch, endpoint->bInterval);
15475197424cSOndrej Zary 	else
15485197424cSOndrej Zary 		usb_fill_bulk_urb(usbtouch->irq, udev,
15495197424cSOndrej Zary 			 usb_rcvbulkpipe(udev, endpoint->bEndpointAddress),
15504ef38351SChristian Engelmayer 			 usbtouch->data, usbtouch->data_size,
15515197424cSOndrej Zary 			 usbtouch_irq, usbtouch);
1552d05e84e6SDmitry Torokhov 
1553fea4d14bSOndrej Zary 	usbtouch->irq->dev = udev;
1554d05e84e6SDmitry Torokhov 	usbtouch->irq->transfer_dma = usbtouch->data_dma;
1555d05e84e6SDmitry Torokhov 	usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1556d05e84e6SDmitry Torokhov 
1557a8aef622SOliver Neukum 	/* device specific allocations */
1558a8aef622SOliver Neukum 	if (type->alloc) {
1559a8aef622SOliver Neukum 		err = type->alloc(usbtouch);
1560a8aef622SOliver Neukum 		if (err) {
1561b741ab9dSGreg Kroah-Hartman 			dev_dbg(&intf->dev,
1562b741ab9dSGreg Kroah-Hartman 				"%s - type->alloc() failed, err: %d\n",
1563b741ab9dSGreg Kroah-Hartman 				__func__, err);
1564a8aef622SOliver Neukum 			goto out_free_urb;
1565a8aef622SOliver Neukum 		}
1566a8aef622SOliver Neukum 	}
1567a8aef622SOliver Neukum 
1568a8aef622SOliver Neukum 	/* device specific initialisation*/
1569d05e84e6SDmitry Torokhov 	if (type->init) {
1570d05e84e6SDmitry Torokhov 		err = type->init(usbtouch);
1571d05e84e6SDmitry Torokhov 		if (err) {
1572b741ab9dSGreg Kroah-Hartman 			dev_dbg(&intf->dev,
1573b741ab9dSGreg Kroah-Hartman 				"%s - type->init() failed, err: %d\n",
1574b741ab9dSGreg Kroah-Hartman 				__func__, err);
1575a8aef622SOliver Neukum 			goto out_do_exit;
1576d05e84e6SDmitry Torokhov 		}
1577d05e84e6SDmitry Torokhov 	}
1578d05e84e6SDmitry Torokhov 
1579d05e84e6SDmitry Torokhov 	err = input_register_device(usbtouch->input);
1580d05e84e6SDmitry Torokhov 	if (err) {
1581b741ab9dSGreg Kroah-Hartman 		dev_dbg(&intf->dev,
1582b741ab9dSGreg Kroah-Hartman 			"%s - input_register_device failed, err: %d\n",
1583b741ab9dSGreg Kroah-Hartman 			__func__, err);
15845197424cSOndrej Zary 		goto out_do_exit;
1585d05e84e6SDmitry Torokhov 	}
1586d05e84e6SDmitry Torokhov 
1587d05e84e6SDmitry Torokhov 	usb_set_intfdata(intf, usbtouch);
1588d05e84e6SDmitry Torokhov 
15891e87a430SOndrej Zary 	if (usbtouch->type->irq_always) {
15905d9efc59SOliver Neukum 		/* this can't fail */
15915d9efc59SOliver Neukum 		usb_autopm_get_interface(intf);
15921e87a430SOndrej Zary 		err = usb_submit_urb(usbtouch->irq, GFP_KERNEL);
15931e87a430SOndrej Zary 		if (err) {
15945d9efc59SOliver Neukum 			usb_autopm_put_interface(intf);
15950a5ebc88SGreg Kroah-Hartman 			dev_err(&intf->dev,
1596e27ad0feSGreg Kroah-Hartman 				"%s - usb_submit_urb failed with result: %d\n",
15971e87a430SOndrej Zary 				__func__, err);
15981e87a430SOndrej Zary 			goto out_unregister_input;
15991e87a430SOndrej Zary 		}
16001e87a430SOndrej Zary 	}
16012330ed18SDaniel Silverstone 
1602d05e84e6SDmitry Torokhov 	return 0;
1603d05e84e6SDmitry Torokhov 
16041e87a430SOndrej Zary out_unregister_input:
16051e87a430SOndrej Zary 	input_unregister_device(input_dev);
16061e87a430SOndrej Zary 	input_dev = NULL;
16075197424cSOndrej Zary out_do_exit:
16085197424cSOndrej Zary 	if (type->exit)
16095197424cSOndrej Zary 		type->exit(usbtouch);
16101e87a430SOndrej Zary out_free_urb:
16111e87a430SOndrej Zary 	usb_free_urb(usbtouch->irq);
1612d05e84e6SDmitry Torokhov out_free_buffers:
1613d05e84e6SDmitry Torokhov 	usbtouch_free_buffers(udev, usbtouch);
1614d05e84e6SDmitry Torokhov out_free:
1615d05e84e6SDmitry Torokhov 	input_free_device(input_dev);
1616d05e84e6SDmitry Torokhov 	kfree(usbtouch);
1617d05e84e6SDmitry Torokhov 	return err;
1618d05e84e6SDmitry Torokhov }
1619d05e84e6SDmitry Torokhov 
usbtouch_disconnect(struct usb_interface * intf)1620d05e84e6SDmitry Torokhov static void usbtouch_disconnect(struct usb_interface *intf)
1621d05e84e6SDmitry Torokhov {
1622d05e84e6SDmitry Torokhov 	struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
1623d05e84e6SDmitry Torokhov 
1624d05e84e6SDmitry Torokhov 	if (!usbtouch)
1625d05e84e6SDmitry Torokhov 		return;
1626d05e84e6SDmitry Torokhov 
16270a5ebc88SGreg Kroah-Hartman 	dev_dbg(&intf->dev,
1628b741ab9dSGreg Kroah-Hartman 		"%s - usbtouch is initialized, cleaning up\n", __func__);
1629b741ab9dSGreg Kroah-Hartman 
1630d05e84e6SDmitry Torokhov 	usb_set_intfdata(intf, NULL);
1631722232bcSOliver Neukum 	/* this will stop IO via close */
1632d05e84e6SDmitry Torokhov 	input_unregister_device(usbtouch->input);
1633d05e84e6SDmitry Torokhov 	usb_free_urb(usbtouch->irq);
16345197424cSOndrej Zary 	if (usbtouch->type->exit)
16355197424cSOndrej Zary 		usbtouch->type->exit(usbtouch);
1636d05e84e6SDmitry Torokhov 	usbtouch_free_buffers(interface_to_usbdev(intf), usbtouch);
1637d05e84e6SDmitry Torokhov 	kfree(usbtouch);
1638d05e84e6SDmitry Torokhov }
1639d05e84e6SDmitry Torokhov 
16406797e19dSDmitry Torokhov static const struct attribute_group *usbtouch_groups[] = {
16416797e19dSDmitry Torokhov #ifdef CONFIG_TOUCHSCREEN_USB_3M
16426797e19dSDmitry Torokhov 	&mtouch_attr_group,
16436797e19dSDmitry Torokhov #endif
16446797e19dSDmitry Torokhov 	NULL
16456797e19dSDmitry Torokhov };
16466797e19dSDmitry Torokhov 
1647ca95a47eSDmitry Torokhov static const struct usb_device_id usbtouch_devices[] = {
1648ca95a47eSDmitry Torokhov #ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
1649ca95a47eSDmitry Torokhov 	/* ignore the HID capable devices, handled by usbhid */
1650ca95a47eSDmitry Torokhov 	{ USB_DEVICE_INTERFACE_CLASS(0x0eef, 0x0001, USB_INTERFACE_CLASS_HID),
16517f787df1SDmitry Torokhov 		.driver_info = 0 },
1652ca95a47eSDmitry Torokhov 	{ USB_DEVICE_INTERFACE_CLASS(0x0eef, 0x0002, USB_INTERFACE_CLASS_HID),
16537f787df1SDmitry Torokhov 		.driver_info = 0 },
1654ca95a47eSDmitry Torokhov 
1655ca95a47eSDmitry Torokhov 	/* normal device IDs */
16567f787df1SDmitry Torokhov 	{ USB_DEVICE(0x3823, 0x0001),
16577f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&egalax_dev_info },
16587f787df1SDmitry Torokhov 	{ USB_DEVICE(0x3823, 0x0002),
16597f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&egalax_dev_info },
16607f787df1SDmitry Torokhov 	{ USB_DEVICE(0x0123, 0x0001),
16617f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&egalax_dev_info },
16627f787df1SDmitry Torokhov 	{ USB_DEVICE(0x0eef, 0x0001),
16637f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&egalax_dev_info },
16647f787df1SDmitry Torokhov 	{ USB_DEVICE(0x0eef, 0x0002),
16657f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&egalax_dev_info },
16667f787df1SDmitry Torokhov 	{ USB_DEVICE(0x1234, 0x0001),
16677f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&egalax_dev_info },
16687f787df1SDmitry Torokhov 	{ USB_DEVICE(0x1234, 0x0002),
16697f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&egalax_dev_info },
1670ca95a47eSDmitry Torokhov #endif
1671ca95a47eSDmitry Torokhov 
1672ca95a47eSDmitry Torokhov #ifdef CONFIG_TOUCHSCREEN_USB_PANJIT
16737f787df1SDmitry Torokhov 	{ USB_DEVICE(0x134c, 0x0001),
16747f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&panjit_dev_info },
16757f787df1SDmitry Torokhov 	{ USB_DEVICE(0x134c, 0x0002),
16767f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&panjit_dev_info },
16777f787df1SDmitry Torokhov 	{ USB_DEVICE(0x134c, 0x0003),
16787f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&panjit_dev_info },
16797f787df1SDmitry Torokhov 	{ USB_DEVICE(0x134c, 0x0004),
16807f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&panjit_dev_info },
1681ca95a47eSDmitry Torokhov #endif
1682ca95a47eSDmitry Torokhov 
1683ca95a47eSDmitry Torokhov #ifdef CONFIG_TOUCHSCREEN_USB_3M
16847f787df1SDmitry Torokhov 	{ USB_DEVICE(0x0596, 0x0001),
16857f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&mtouch_dev_info },
1686ca95a47eSDmitry Torokhov #endif
1687ca95a47eSDmitry Torokhov 
1688ca95a47eSDmitry Torokhov #ifdef CONFIG_TOUCHSCREEN_USB_ITM
16897f787df1SDmitry Torokhov 	{ USB_DEVICE(0x0403, 0xf9e9),
16907f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&itm_dev_info },
16917f787df1SDmitry Torokhov 	{ USB_DEVICE(0x16e3, 0xf9e9),
16927f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&itm_dev_info },
1693ca95a47eSDmitry Torokhov #endif
1694ca95a47eSDmitry Torokhov 
1695ca95a47eSDmitry Torokhov #ifdef CONFIG_TOUCHSCREEN_USB_ETURBO
16967f787df1SDmitry Torokhov 	{ USB_DEVICE(0x1234, 0x5678),
16977f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&eturbo_dev_info },
1698ca95a47eSDmitry Torokhov #endif
1699ca95a47eSDmitry Torokhov 
1700ca95a47eSDmitry Torokhov #ifdef CONFIG_TOUCHSCREEN_USB_GUNZE
17017f787df1SDmitry Torokhov 	{ USB_DEVICE(0x0637, 0x0001),
17027f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&gunze_dev_info },
1703ca95a47eSDmitry Torokhov #endif
1704ca95a47eSDmitry Torokhov 
1705ca95a47eSDmitry Torokhov #ifdef CONFIG_TOUCHSCREEN_USB_DMC_TSC10
17067f787df1SDmitry Torokhov 	{ USB_DEVICE(0x0afa, 0x03e8),
17077f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&dmc_tsc10_dev_info },
1708ca95a47eSDmitry Torokhov #endif
1709ca95a47eSDmitry Torokhov 
1710ca95a47eSDmitry Torokhov #ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH
17117f787df1SDmitry Torokhov 	{ USB_DEVICE(0x255e, 0x0001),
17127f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&irtouch_dev_info },
17137f787df1SDmitry Torokhov 	{ USB_DEVICE(0x595a, 0x0001),
17147f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&irtouch_dev_info },
17157f787df1SDmitry Torokhov 	{ USB_DEVICE(0x6615, 0x0001),
17167f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&irtouch_dev_info },
17177f787df1SDmitry Torokhov 	{ USB_DEVICE(0x6615, 0x0012),
17187f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&irtouch_hires_dev_info },
1719ca95a47eSDmitry Torokhov #endif
1720ca95a47eSDmitry Torokhov 
1721ca95a47eSDmitry Torokhov #ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
17227f787df1SDmitry Torokhov 	{ USB_DEVICE(0x1391, 0x1000),
17237f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&idealtek_dev_info },
1724ca95a47eSDmitry Torokhov #endif
1725ca95a47eSDmitry Torokhov 
1726ca95a47eSDmitry Torokhov #ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
17277f787df1SDmitry Torokhov 	{ USB_DEVICE(0x0dfc, 0x0001),
17287f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&general_touch_dev_info },
1729ca95a47eSDmitry Torokhov #endif
1730ca95a47eSDmitry Torokhov 
1731ca95a47eSDmitry Torokhov #ifdef CONFIG_TOUCHSCREEN_USB_GOTOP
17327f787df1SDmitry Torokhov 	{ USB_DEVICE(0x08f2, 0x007f),
17337f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&gotop_dev_info },
17347f787df1SDmitry Torokhov 	{ USB_DEVICE(0x08f2, 0x00ce),
17357f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&gotop_dev_info },
17367f787df1SDmitry Torokhov 	{ USB_DEVICE(0x08f2, 0x00f4),
17377f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&gotop_dev_info },
1738ca95a47eSDmitry Torokhov #endif
1739ca95a47eSDmitry Torokhov 
1740ca95a47eSDmitry Torokhov #ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
17417f787df1SDmitry Torokhov 	{ USB_DEVICE(0x0f92, 0x0001),
17427f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&jastec_dev_info },
1743ca95a47eSDmitry Torokhov #endif
1744ca95a47eSDmitry Torokhov 
1745ca95a47eSDmitry Torokhov #ifdef CONFIG_TOUCHSCREEN_USB_E2I
17467f787df1SDmitry Torokhov 	{ USB_DEVICE(0x1ac7, 0x0001),
17477f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&e2i_dev_info },
1748ca95a47eSDmitry Torokhov #endif
1749ca95a47eSDmitry Torokhov 
1750ca95a47eSDmitry Torokhov #ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC
17517f787df1SDmitry Torokhov 	{ USB_DEVICE(0x14c8, 0x0003),
17527f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&zytronic_dev_info },
1753ca95a47eSDmitry Torokhov #endif
1754ca95a47eSDmitry Torokhov 
1755ca95a47eSDmitry Torokhov #ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC45USB
1756ca95a47eSDmitry Torokhov 	/* TC5UH */
17577f787df1SDmitry Torokhov 	{ USB_DEVICE(0x0664, 0x0309),
17587f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&tc45usb_dev_info },
1759ca95a47eSDmitry Torokhov 	/* TC4UM */
17607f787df1SDmitry Torokhov 	{ USB_DEVICE(0x0664, 0x0306),
17617f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&tc45usb_dev_info },
1762ca95a47eSDmitry Torokhov #endif
1763ca95a47eSDmitry Torokhov 
1764ca95a47eSDmitry Torokhov #ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
1765ca95a47eSDmitry Torokhov 	/* data interface only */
1766ca95a47eSDmitry Torokhov 	{ USB_DEVICE_AND_INTERFACE_INFO(0x10f0, 0x2002, 0x0a, 0x00, 0x00),
17677f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&nexio_dev_info },
1768ca95a47eSDmitry Torokhov 	{ USB_DEVICE_AND_INTERFACE_INFO(0x1870, 0x0001, 0x0a, 0x00, 0x00),
17697f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&nexio_dev_info },
1770ca95a47eSDmitry Torokhov #endif
1771ca95a47eSDmitry Torokhov 
1772ca95a47eSDmitry Torokhov #ifdef CONFIG_TOUCHSCREEN_USB_ELO
17737f787df1SDmitry Torokhov 	{ USB_DEVICE(0x04e7, 0x0020),
17747f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&elo_dev_info },
1775ca95a47eSDmitry Torokhov #endif
1776ca95a47eSDmitry Torokhov 
1777ca95a47eSDmitry Torokhov #ifdef CONFIG_TOUCHSCREEN_USB_EASYTOUCH
17787f787df1SDmitry Torokhov 	{ USB_DEVICE(0x7374, 0x0001),
17797f787df1SDmitry Torokhov 		.driver_info = (kernel_ulong_t)&etouch_dev_info },
1780ca95a47eSDmitry Torokhov #endif
1781ca95a47eSDmitry Torokhov 
1782ca95a47eSDmitry Torokhov 	{ }
1783ca95a47eSDmitry Torokhov };
1784d05e84e6SDmitry Torokhov MODULE_DEVICE_TABLE(usb, usbtouch_devices);
1785d05e84e6SDmitry Torokhov 
1786d05e84e6SDmitry Torokhov static struct usb_driver usbtouch_driver = {
1787d05e84e6SDmitry Torokhov 	.name		= "usbtouchscreen",
1788d05e84e6SDmitry Torokhov 	.probe		= usbtouch_probe,
1789d05e84e6SDmitry Torokhov 	.disconnect	= usbtouch_disconnect,
1790ed4299e1SOliver Neukum 	.suspend	= usbtouch_suspend,
1791ed4299e1SOliver Neukum 	.resume		= usbtouch_resume,
1792a8aef622SOliver Neukum 	.reset_resume	= usbtouch_reset_resume,
1793d05e84e6SDmitry Torokhov 	.id_table	= usbtouch_devices,
17946797e19dSDmitry Torokhov 	.dev_groups	= usbtouch_groups,
17955d9efc59SOliver Neukum 	.supports_autosuspend = 1,
1796d05e84e6SDmitry Torokhov };
1797d05e84e6SDmitry Torokhov 
179808642e7cSGreg Kroah-Hartman module_usb_driver(usbtouch_driver);
1799d05e84e6SDmitry Torokhov 
1800698c03b4SJulia Lawall MODULE_AUTHOR("Daniel Ritz <daniel.ritz@gmx.ch>");
1801698c03b4SJulia Lawall MODULE_DESCRIPTION("USB Touchscreen Driver");
1802d05e84e6SDmitry Torokhov MODULE_LICENSE("GPL");
1803d05e84e6SDmitry Torokhov 
1804d05e84e6SDmitry Torokhov MODULE_ALIAS("touchkitusb");
1805d05e84e6SDmitry Torokhov MODULE_ALIAS("itmtouch");
1806d05e84e6SDmitry Torokhov MODULE_ALIAS("mtouchusb");
1807