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