]>
Commit | Line | Data |
---|---|---|
1 | From: Jiri Kosina <jkosina@suse.cz> | |
2 | Subject: Elo USB touchscreen driver | |
3 | Patch-mainline: will be submitted for 2.6.28 | |
4 | References: FATE#304972 | |
5 | ||
6 | This is a driver for Elo USB touchscreen devices. | |
7 | ||
8 | Signed-off-by: Vojtech Pavlik <vojtech@suse.cz> | |
9 | Acked-by: Jiri Kosina <jkosina@suse.cz> | |
10 | ||
11 | --- | |
12 | drivers/hid/usbhid/hid-quirks.c | 4 | |
13 | drivers/input/touchscreen/Kconfig | 12 + | |
14 | drivers/input/touchscreen/Makefile | 1 | |
15 | drivers/input/touchscreen/elousb.c | 305 +++++++++++++++++++++++++++++++++++++ | |
16 | 4 files changed, 322 insertions(+) | |
17 | ||
18 | --- a/drivers/hid/usbhid/hid-quirks.c | |
19 | +++ b/drivers/hid/usbhid/hid-quirks.c | |
20 | @@ -138,7 +138,9 @@ | |
21 | #define USB_DEVICE_ID_DMI_ENC 0x5fab | |
22 | ||
23 | #define USB_VENDOR_ID_ELO 0x04E7 | |
24 | +#define USB_DEVICE_ID_ELO_4000U 0x0009 | |
25 | #define USB_DEVICE_ID_ELO_TS2700 0x0020 | |
26 | +#define USB_DEVICE_ID_ELO_4500U 0x0030 | |
27 | ||
28 | #define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f | |
29 | #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 | |
30 | @@ -485,6 +487,8 @@ static const struct hid_blacklist { | |
31 | { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE }, | |
32 | { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE }, | |
33 | { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE }, | |
34 | + { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_4000U, HID_QUIRK_IGNORE }, | |
35 | + { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_4500U, HID_QUIRK_IGNORE }, | |
36 | { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE }, | |
37 | { USB_VENDOR_ID_GENERAL_TOUCH, 0x0001, HID_QUIRK_IGNORE }, | |
38 | { USB_VENDOR_ID_GENERAL_TOUCH, 0x0002, HID_QUIRK_IGNORE }, | |
39 | --- /dev/null | |
40 | +++ b/drivers/input/touchscreen/elousb.c | |
41 | @@ -0,0 +1,305 @@ | |
42 | +/* | |
43 | + * Copyright (c) 1999-2001 Vojtech Pavlik | |
44 | + * | |
45 | + * Elo USB touchscreen support | |
46 | + */ | |
47 | + | |
48 | +/* | |
49 | + * This program is free software; you can redistribute it and/or modify | |
50 | + * it under the terms of the GNU General Public License as published by | |
51 | + * the Free Software Foundation; either version 2 of the License. | |
52 | + * | |
53 | + * This program is distributed in the hope that it will be useful, | |
54 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
55 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
56 | + * GNU General Public License for more details. | |
57 | + * | |
58 | + * You should have received a copy of the GNU General Public License | |
59 | + * along with this program; if not, write to the Free Software | |
60 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
61 | + * | |
62 | + * Should you need to contact me, the author, you can do so either by | |
63 | + * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail: | |
64 | + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | |
65 | + */ | |
66 | + | |
67 | +#include <linux/kernel.h> | |
68 | +#include <linux/slab.h> | |
69 | +#include <linux/module.h> | |
70 | +#include <linux/init.h> | |
71 | +#include <linux/usb.h> | |
72 | +#include <linux/usb/input.h> | |
73 | +#include <linux/hid.h> | |
74 | +#include <linux/input.h> | |
75 | + | |
76 | +/* | |
77 | + * Version Information | |
78 | + */ | |
79 | +#define DRIVER_VERSION "v1.1" | |
80 | +#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@suse.cz>" | |
81 | +#define DRIVER_DESC "Elo USB touchscreen driver" | |
82 | +#define DRIVER_LICENSE "GPL" | |
83 | + | |
84 | +MODULE_AUTHOR(DRIVER_AUTHOR); | |
85 | +MODULE_DESCRIPTION(DRIVER_DESC); | |
86 | +MODULE_LICENSE(DRIVER_LICENSE); | |
87 | + | |
88 | +struct elousb { | |
89 | + char name[128]; | |
90 | + char phys[64]; | |
91 | + struct usb_device *usbdev; | |
92 | + struct input_dev *dev; | |
93 | + struct urb *irq; | |
94 | + | |
95 | + unsigned char *data; | |
96 | + dma_addr_t data_dma; | |
97 | +}; | |
98 | + | |
99 | +static void elousb_irq(struct urb *urb) | |
100 | +{ | |
101 | + struct elousb *elo = urb->context; | |
102 | + unsigned char *data = elo->data; | |
103 | + struct input_dev *dev = elo->dev; | |
104 | + int status; | |
105 | + | |
106 | + switch (urb->status) { | |
107 | + case 0: /* success */ | |
108 | + break; | |
109 | + case -ECONNRESET: /* unlink */ | |
110 | + case -ENOENT: | |
111 | + case -ESHUTDOWN: | |
112 | + return; | |
113 | + /* -EPIPE: should clear the halt */ | |
114 | + default: /* error */ | |
115 | + goto resubmit; | |
116 | + } | |
117 | + | |
118 | + if (data[0] != 'T') /* Mandatory ELO packet marker */ | |
119 | + return; | |
120 | + | |
121 | + | |
122 | + input_report_abs(dev, ABS_X, ((u32)data[3] << 8) | data[2]); | |
123 | + input_report_abs(dev, ABS_Y, ((u32)data[5] << 8) | data[4]); | |
124 | + | |
125 | + input_report_abs(dev, ABS_PRESSURE, | |
126 | + (data[1] & 0x80) ? (((u32)data[7] << 8) | data[6]): 0); | |
127 | + | |
128 | + if (data[1] & 0x03) { | |
129 | + input_report_key(dev, BTN_TOUCH, 1); | |
130 | + input_sync(dev); | |
131 | + } | |
132 | + | |
133 | + if (data[1] & 0x04) | |
134 | + input_report_key(dev, BTN_TOUCH, 0); | |
135 | + | |
136 | + input_sync(dev); | |
137 | + | |
138 | +resubmit: | |
139 | + status = usb_submit_urb (urb, GFP_ATOMIC); | |
140 | + if (status) | |
141 | + err ("can't resubmit intr, %s-%s/input0, status %d", | |
142 | + elo->usbdev->bus->bus_name, | |
143 | + elo->usbdev->devpath, status); | |
144 | +} | |
145 | + | |
146 | +static int elousb_open(struct input_dev *dev) | |
147 | +{ | |
148 | + struct elousb *elo = input_get_drvdata(dev); | |
149 | + | |
150 | + elo->irq->dev = elo->usbdev; | |
151 | + if (usb_submit_urb(elo->irq, GFP_KERNEL)) | |
152 | + return -EIO; | |
153 | + | |
154 | + return 0; | |
155 | +} | |
156 | + | |
157 | +static void elousb_close(struct input_dev *dev) | |
158 | +{ | |
159 | + struct elousb *elo = input_get_drvdata(dev); | |
160 | + | |
161 | + usb_kill_urb(elo->irq); | |
162 | +} | |
163 | + | |
164 | +static int elousb_probe(struct usb_interface *intf, const struct usb_device_id *id) | |
165 | +{ | |
166 | + struct usb_device *dev = interface_to_usbdev(intf); | |
167 | + struct usb_host_interface *interface; | |
168 | + struct usb_endpoint_descriptor *endpoint; | |
169 | + struct hid_descriptor *hdesc; | |
170 | + struct elousb *elo; | |
171 | + struct input_dev *input_dev; | |
172 | + int pipe, i; | |
173 | + unsigned int rsize = 0; | |
174 | + int error = -ENOMEM; | |
175 | + char *rdesc; | |
176 | + | |
177 | + interface = intf->cur_altsetting; | |
178 | + | |
179 | + if (interface->desc.bNumEndpoints != 1) | |
180 | + return -ENODEV; | |
181 | + | |
182 | + endpoint = &interface->endpoint[0].desc; | |
183 | + if (!(endpoint->bEndpointAddress & USB_DIR_IN)) | |
184 | + return -ENODEV; | |
185 | + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) | |
186 | + return -ENODEV; | |
187 | + | |
188 | + if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) && | |
189 | + (!interface->desc.bNumEndpoints || | |
190 | + usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) { | |
191 | + err("HID class descriptor not present"); | |
192 | + return -ENODEV; | |
193 | + } | |
194 | + | |
195 | + for (i = 0; i < hdesc->bNumDescriptors; i++) | |
196 | + if (hdesc->desc[i].bDescriptorType == HID_DT_REPORT) | |
197 | + rsize = le16_to_cpu(hdesc->desc[i].wDescriptorLength); | |
198 | + | |
199 | + if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) { | |
200 | + err("weird size of report descriptor (%u)", rsize); | |
201 | + return -ENODEV; | |
202 | + } | |
203 | + | |
204 | + | |
205 | + pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); | |
206 | + | |
207 | + elo = kzalloc(sizeof(struct elousb), GFP_KERNEL); | |
208 | + input_dev = input_allocate_device(); | |
209 | + if (!elo || !input_dev) | |
210 | + goto fail1; | |
211 | + | |
212 | + elo->data = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &elo->data_dma); | |
213 | + if (!elo->data) | |
214 | + goto fail1; | |
215 | + | |
216 | + elo->irq = usb_alloc_urb(0, GFP_KERNEL); | |
217 | + if (!elo->irq) | |
218 | + goto fail2; | |
219 | + | |
220 | + if (!(rdesc = kmalloc(rsize, GFP_KERNEL))) | |
221 | + goto fail3; | |
222 | + | |
223 | + elo->usbdev = dev; | |
224 | + elo->dev = input_dev; | |
225 | + | |
226 | + if ((error = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | |
227 | + HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, | |
228 | + interface->desc.bInterfaceNumber, | |
229 | + NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) { | |
230 | + err("setting HID idle timeout failed, error %d", error); | |
231 | + error = -ENODEV; | |
232 | + goto fail4; | |
233 | + } | |
234 | + | |
235 | + if ((error = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), | |
236 | + USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN, | |
237 | + HID_DT_REPORT << 8, interface->desc.bInterfaceNumber, | |
238 | + rdesc, rsize, USB_CTRL_GET_TIMEOUT)) < rsize) { | |
239 | + err("reading HID report descriptor failed, error %d", error); | |
240 | + error = -ENODEV; | |
241 | + goto fail4; | |
242 | + } | |
243 | + | |
244 | + if (dev->manufacturer) | |
245 | + strlcpy(elo->name, dev->manufacturer, sizeof(elo->name)); | |
246 | + | |
247 | + if (dev->product) { | |
248 | + if (dev->manufacturer) | |
249 | + strlcat(elo->name, " ", sizeof(elo->name)); | |
250 | + strlcat(elo->name, dev->product, sizeof(elo->name)); | |
251 | + } | |
252 | + | |
253 | + if (!strlen(elo->name)) | |
254 | + snprintf(elo->name, sizeof(elo->name), | |
255 | + "Elo touchscreen %04x:%04x", | |
256 | + le16_to_cpu(dev->descriptor.idVendor), | |
257 | + le16_to_cpu(dev->descriptor.idProduct)); | |
258 | + | |
259 | + usb_make_path(dev, elo->phys, sizeof(elo->phys)); | |
260 | + strlcat(elo->phys, "/input0", sizeof(elo->phys)); | |
261 | + | |
262 | + input_dev->name = elo->name; | |
263 | + input_dev->phys = elo->phys; | |
264 | + usb_to_input_id(dev, &input_dev->id); | |
265 | + input_dev->dev.parent = &intf->dev; | |
266 | + | |
267 | + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | |
268 | + set_bit(BTN_TOUCH, input_dev->keybit); | |
269 | + input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y); | |
270 | + set_bit(ABS_PRESSURE, input_dev->absbit); | |
271 | + | |
272 | + input_set_abs_params(input_dev, ABS_X, 0, 4000, 0, 0); | |
273 | + input_set_abs_params(input_dev, ABS_Y, 0, 3840, 0, 0); | |
274 | + input_set_abs_params(input_dev, ABS_PRESSURE, 0, 256, 0, 0); | |
275 | + | |
276 | + input_set_drvdata(input_dev, elo); | |
277 | + | |
278 | + input_dev->open = elousb_open; | |
279 | + input_dev->close = elousb_close; | |
280 | + | |
281 | + usb_fill_int_urb(elo->irq, dev, pipe, elo->data, 8, | |
282 | + elousb_irq, elo, endpoint->bInterval); | |
283 | + elo->irq->transfer_dma = elo->data_dma; | |
284 | + elo->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | |
285 | + | |
286 | + input_register_device(elo->dev); | |
287 | + | |
288 | + usb_set_intfdata(intf, elo); | |
289 | + return 0; | |
290 | + | |
291 | +fail4: | |
292 | + kfree(rdesc); | |
293 | +fail3: | |
294 | + usb_free_urb(elo->irq); | |
295 | +fail2: | |
296 | + usb_buffer_free(dev, 8, elo->data, elo->data_dma); | |
297 | +fail1: | |
298 | + input_free_device(input_dev); | |
299 | + kfree(elo); | |
300 | + return -ENOMEM; | |
301 | +} | |
302 | + | |
303 | +static void elousb_disconnect(struct usb_interface *intf) | |
304 | +{ | |
305 | + struct elousb *elo = usb_get_intfdata (intf); | |
306 | + | |
307 | + usb_set_intfdata(intf, NULL); | |
308 | + if (elo) { | |
309 | + usb_kill_urb(elo->irq); | |
310 | + input_unregister_device(elo->dev); | |
311 | + usb_free_urb(elo->irq); | |
312 | + usb_buffer_free(interface_to_usbdev(intf), 8, elo->data, elo->data_dma); | |
313 | + kfree(elo); | |
314 | + } | |
315 | +} | |
316 | + | |
317 | +static struct usb_device_id elousb_id_table [] = { | |
318 | + { USB_DEVICE(0x04e7, 0x0009) }, /* CarrolTouch 4000U */ | |
319 | + { USB_DEVICE(0x04e7, 0x0030) }, /* CarrolTouch 4500U */ | |
320 | + { } /* Terminating entry */ | |
321 | +}; | |
322 | + | |
323 | +MODULE_DEVICE_TABLE (usb, elousb_id_table); | |
324 | + | |
325 | +static struct usb_driver elousb_driver = { | |
326 | + .name = "elousb", | |
327 | + .probe = elousb_probe, | |
328 | + .disconnect = elousb_disconnect, | |
329 | + .id_table = elousb_id_table, | |
330 | +}; | |
331 | + | |
332 | +static int __init elousb_init(void) | |
333 | +{ | |
334 | + int retval = usb_register(&elousb_driver); | |
335 | + if (retval == 0) | |
336 | + info(DRIVER_VERSION ":" DRIVER_DESC); | |
337 | + return retval; | |
338 | +} | |
339 | + | |
340 | +static void __exit elousb_exit(void) | |
341 | +{ | |
342 | + usb_deregister(&elousb_driver); | |
343 | +} | |
344 | + | |
345 | +module_init(elousb_init); | |
346 | +module_exit(elousb_exit); | |
347 | --- a/drivers/input/touchscreen/Kconfig | |
348 | +++ b/drivers/input/touchscreen/Kconfig | |
349 | @@ -91,6 +91,18 @@ config TOUCHSCREEN_ELO | |
350 | To compile this driver as a module, choose M here: the | |
351 | module will be called elo. | |
352 | ||
353 | +config TOUCHSCREEN_ELOUSB | |
354 | + tristate "Elo USB touchscreens" | |
355 | + select USB | |
356 | + help | |
357 | + Say Y here if you have an Elo USB touchscreen connected to | |
358 | + your system. | |
359 | + | |
360 | + If unsure, say N. | |
361 | + | |
362 | + To compile this driver as a module, choose M here: the | |
363 | + module will be called elousb. | |
364 | + | |
365 | config TOUCHSCREEN_MTOUCH | |
366 | tristate "MicroTouch serial touchscreens" | |
367 | select SERIO | |
368 | --- a/drivers/input/touchscreen/Makefile | |
369 | +++ b/drivers/input/touchscreen/Makefile | |
370 | @@ -12,6 +12,7 @@ obj-$(CONFIG_TOUCHSCREEN_BITSY) += h360 | |
371 | obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o | |
372 | obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o | |
373 | obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o | |
374 | +obj-$(CONFIG_TOUCHSCREEN_ELOUSB) += elousb.o | |
375 | obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o | |
376 | obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o | |
377 | obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o |