kernel
Révision | e55eff121bd732afdbcbf78ae2adcd012a3fe5bf (tree) |
---|---|
l'heure | 2019-02-12 15:40:31 |
Auteur | Supratim <sup270792@gmai...> |
Commiter | Chih-Wei Huang |
Input: add PQ Labs IR touchscreen driver
Signed-off-by: Chih-Wei Huang <cwhuang@linux.org.tw>
@@ -3019,6 +3019,7 @@ CONFIG_TOUCHSCREEN_ZFORCE=m | ||
3019 | 3019 | CONFIG_TOUCHSCREEN_ROHM_BU21023=m |
3020 | 3020 | CONFIG_TOUCHSCREEN_NWFERMI=m |
3021 | 3021 | CONFIG_TOUCHSCREEN_DWAV_USB_MT=m |
3022 | +CONFIG_TOUCHSCREEN_PQLABS_USB=m | |
3022 | 3023 | CONFIG_INPUT_MISC=y |
3023 | 3024 | CONFIG_INPUT_88PM80X_ONKEY=m |
3024 | 3025 | CONFIG_INPUT_AD714X=m |
@@ -3079,6 +3079,7 @@ CONFIG_TOUCHSCREEN_ZFORCE=m | ||
3079 | 3079 | CONFIG_TOUCHSCREEN_ROHM_BU21023=m |
3080 | 3080 | CONFIG_TOUCHSCREEN_NWFERMI=m |
3081 | 3081 | CONFIG_TOUCHSCREEN_DWAV_USB_MT=m |
3082 | +CONFIG_TOUCHSCREEN_PQLABS_USB=m | |
3082 | 3083 | CONFIG_INPUT_MISC=y |
3083 | 3084 | CONFIG_INPUT_88PM80X_ONKEY=m |
3084 | 3085 | CONFIG_INPUT_AD714X=m |
@@ -1321,4 +1321,14 @@ config TOUCHSCREEN_DWAV_USB_MT | ||
1321 | 1321 | To compile this driver as a module, choose M here: the |
1322 | 1322 | module will be called dwav-usb-mt. |
1323 | 1323 | |
1324 | +config TOUCHSCREEN_PQLABS_USB | |
1325 | + tristate "PQ Labs IR MultiTouch Screen Driver" | |
1326 | + depends on USB | |
1327 | + help | |
1328 | + Say Y here if you have a PQ LABS IR MultiTouch Screen | |
1329 | + connected to your system. | |
1330 | + | |
1331 | + To compile this driver as a module, choose M here: the | |
1332 | + module will be called usb_pqlabs. | |
1333 | + | |
1324 | 1334 | endif |
@@ -111,3 +111,4 @@ obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o | ||
111 | 111 | obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o |
112 | 112 | obj-$(CONFIG_TOUCHSCREEN_NWFERMI) += nw-fermi.o |
113 | 113 | obj-$(CONFIG_TOUCHSCREEN_DWAV_USB_MT) += dwav-usb-mt.o |
114 | +obj-$(CONFIG_TOUCHSCREEN_PQLABS_USB) += usb_pqlabs.o |
@@ -0,0 +1,1088 @@ | ||
1 | +/* | |
2 | + * USB pqlabs driver - 130101 | |
3 | + * | |
4 | + * Copyright (C) 2001-2004 Jemini | |
5 | + * | |
6 | + * This program is free software; you can redistribute it and/or | |
7 | + * modify it under the terms of the GNU General Public License as | |
8 | + * published by the Free Software Foundation, version 2. | |
9 | + * | |
10 | + * This driver is based on the 2.6.3 version of drivers/usb/usb-pqlabseton.c | |
11 | + * but has been rewritten to be easier to read and use. | |
12 | + * | |
13 | + */ | |
14 | + | |
15 | +#include <linux/kernel.h> | |
16 | +#include <linux/errno.h> | |
17 | +#include <linux/init.h> | |
18 | +#include <linux/slab.h> | |
19 | +#include <linux/module.h> | |
20 | +#include <linux/kref.h> | |
21 | +#include <linux/uaccess.h> | |
22 | +#include <linux/usb.h> | |
23 | +#include <linux/mutex.h> | |
24 | +#include <linux/compat.h> | |
25 | +#include <linux/input.h> | |
26 | +#include <linux/input/mt.h> | |
27 | +#include <linux/hiddev.h> | |
28 | +#include <linux/mm.h> | |
29 | +#include <linux/version.h> | |
30 | + | |
31 | +#define PQ 2 | |
32 | +#define PRODUCT PQ | |
33 | + | |
34 | +/* Define these values to match your devices */ | |
35 | +#define USB_PQLABS_VENDOR_ID 0x1EF1 | |
36 | +#define USB_PQLABS_PRODUCT_ID 0x0001 | |
37 | +#define USB_PQLABS_PRODUCT_BULK_ID 0x0011 | |
38 | + | |
39 | +#define USB_PQLABS_INTERFACE_CLASS 0xFF | |
40 | +#define USB_PQLABS_INTERFACE_SUBCLASS 0x0 | |
41 | +#define USB_PQLABS_INTERFACE_PROTOCOL 0x0 | |
42 | +#define CUR_DRIVER_VERSION 0x140729 | |
43 | + | |
44 | +static const char *TOUCHSCREEN_NAME = "PQLABS Multi TouchScreen"; | |
45 | + | |
46 | +struct pqlabs_string_descriptor | |
47 | +{ | |
48 | + __s32 index; | |
49 | + char value[256]; | |
50 | +}; | |
51 | + | |
52 | +struct pqlabs_cmd_string | |
53 | +{ | |
54 | + __s32 index; | |
55 | + char buf[64]; | |
56 | +}; | |
57 | + | |
58 | +#define USB_IOCTL_GET_STRING _IOR('Q', 0x04, struct pqlabs_string_descriptor) | |
59 | +#define USB_IOCTL_CLEAR_FEATURE _IOR('Q', 0x05, int) | |
60 | +#define USB_IOCTL_WRITE_HID_CMD _IOR('Q', 0x06, struct pqlabs_cmd_string) | |
61 | +#define USB_IOCTL_GET_DRIVER_VERSION _IOR('Q', 0x07, unsigned int) | |
62 | +#define USB_IOCTL_CLEAR_URB _IOR('Q', 0x08, unsigned int) | |
63 | +#define USB_IOCTL_RESET_DEVICE _IOR('Q', 0x09, unsigned int) | |
64 | + | |
65 | + | |
66 | +#if 1 | |
67 | +#define pq_trace(msg...) \ | |
68 | + do { \ | |
69 | + printk(KERN_DEBUG "pqlabs: " msg); \ | |
70 | + } while (0) | |
71 | + | |
72 | +#define err(msg...) \ | |
73 | + do { \ | |
74 | + printk(KERN_DEBUG "pqlabs: " msg); \ | |
75 | + } while (0) | |
76 | +#endif | |
77 | + | |
78 | +/* table of devices that work with this driver */ | |
79 | +static struct usb_device_id pqlabs_table[] = { | |
80 | + {USB_DEVICE_AND_INTERFACE_INFO(USB_PQLABS_VENDOR_ID, | |
81 | + USB_PQLABS_PRODUCT_ID, | |
82 | + USB_PQLABS_INTERFACE_CLASS, | |
83 | + USB_PQLABS_INTERFACE_SUBCLASS, | |
84 | + USB_PQLABS_INTERFACE_PROTOCOL)}, | |
85 | + {USB_DEVICE_AND_INTERFACE_INFO(USB_PQLABS_VENDOR_ID, | |
86 | + USB_PQLABS_PRODUCT_BULK_ID, | |
87 | + USB_PQLABS_INTERFACE_CLASS, | |
88 | + USB_PQLABS_INTERFACE_SUBCLASS, | |
89 | + USB_PQLABS_INTERFACE_PROTOCOL)}, | |
90 | + { } /* Terminating entry */ | |
91 | +}; | |
92 | +MODULE_DEVICE_TABLE(usb, pqlabs_table); | |
93 | + | |
94 | +/* Get a minor range for your devices from the usb maintainer */ | |
95 | +#define USB_pqlabs_MINOR_BASE 192 | |
96 | + | |
97 | +/* our private defines. if this grows any larger, use your own .h file */ | |
98 | +#define MAX_TRANSFER (PAGE_SIZE - 512) | |
99 | +/* MAX_TRANSFER is chosen so that the VM is not stressed by | |
100 | + allocations > PAGE_SIZE and the number of packets in a page | |
101 | + is an integer 512 is the largest possible packet on EHCI */ | |
102 | +#define WRITES_IN_FLIGHT 8 | |
103 | +#define MAX_BUFFER_NUMBER 1 | |
104 | +/* arbitrarily chosen */ | |
105 | + | |
106 | +/* Structure to hold all of our device specific stuff */ | |
107 | +struct usb_pqlabs { | |
108 | + struct usb_device *udev; /* the usb device for this device */ | |
109 | + struct usb_interface *interface; /* the interface for this device */ | |
110 | + struct semaphore limit_sem; /* limiting the number of writes in progress */ | |
111 | + struct usb_anchor submitted; /* in case we need to retract our submissions */ | |
112 | + struct urb *bulk_in_urb; /* the urb to read data with */ | |
113 | + unsigned char *bulk_in_buffer; /* the buffer to receive data */ | |
114 | + size_t bulk_in_size; /* the size of the receive buffer */ | |
115 | + size_t bulk_in_filled; /* number of bytes in the buffer */ | |
116 | + size_t bulk_in_copied; /* already copied to user space */ | |
117 | + size_t bulk_total; | |
118 | + __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ | |
119 | + __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ | |
120 | + int errors; /* the last request tanked */ | |
121 | + int open_count; /* count the number of openers */ | |
122 | + bool ongoing_read; /* a read is going on */ | |
123 | + bool processed_urb; /* indicates we haven't processed the urb */ | |
124 | + bool submitted_urb; | |
125 | + spinlock_t err_lock; /* lock for errors */ | |
126 | + struct kref kref; | |
127 | + struct mutex io_mutex; /* synchronize I/O with disconnect */ | |
128 | + struct completion bulk_in_completion; /* to wait for an ongoing read */ | |
129 | + bool disconnecting; | |
130 | + struct input_dev *input_dev; | |
131 | + char phys[32]; | |
132 | + | |
133 | + int bufferIndex; | |
134 | + size_t total_size; | |
135 | + char extraFlag; | |
136 | +}; | |
137 | +#define to_pqlabs_dev(d) container_of(d, struct usb_pqlabs, kref) | |
138 | +#define MAX_SUPPORT_POINTS 32 | |
139 | + | |
140 | + | |
141 | +static struct usb_driver pqlabs_driver; | |
142 | +static void pqlabs_draw_down(struct usb_pqlabs *dev); | |
143 | + | |
144 | +static void pqlabs_delete(struct kref *kref) | |
145 | +{ | |
146 | + struct usb_pqlabs *dev = to_pqlabs_dev(kref); | |
147 | + | |
148 | + usb_free_urb(dev->bulk_in_urb); | |
149 | + usb_put_dev(dev->udev); | |
150 | + kfree(dev->bulk_in_buffer); | |
151 | + kfree(dev); | |
152 | +} | |
153 | + | |
154 | +static int pqlabs_open(struct inode *inode, struct file *file) | |
155 | +{ | |
156 | + struct usb_pqlabs *dev; | |
157 | + struct usb_interface *interface; | |
158 | + int subminor; | |
159 | + int retval = 0; | |
160 | + | |
161 | + subminor = iminor(inode); | |
162 | + | |
163 | + interface = usb_find_interface(&pqlabs_driver, subminor); | |
164 | + if (!interface) | |
165 | + { | |
166 | + err("%s - error, can't find device for minor %d", __func__, subminor); | |
167 | + retval = -ENODEV; | |
168 | + goto exit; | |
169 | + } | |
170 | + | |
171 | + dev = usb_get_intfdata(interface); | |
172 | + if (!dev) { | |
173 | + retval = -ENODEV; | |
174 | + goto exit; | |
175 | + } | |
176 | + | |
177 | + /* increment our usage count for the device */ | |
178 | + kref_get(&dev->kref); | |
179 | + | |
180 | + /* lock the device to allow correctly handling errors | |
181 | + * in resumption */ | |
182 | + mutex_lock(&dev->io_mutex); | |
183 | + | |
184 | + if (!dev->open_count++) { | |
185 | + retval = usb_autopm_get_interface(interface); | |
186 | + if (retval) { | |
187 | + dev->open_count--; | |
188 | + mutex_unlock(&dev->io_mutex); | |
189 | + kref_put(&dev->kref, pqlabs_delete); | |
190 | + goto exit; | |
191 | + } | |
192 | + } else { //uncomment this block if you want exclusive open | |
193 | + retval = -EBUSY; | |
194 | + dev->open_count--; | |
195 | + mutex_unlock(&dev->io_mutex); | |
196 | + kref_put(&dev->kref, pqlabs_delete); | |
197 | + goto exit; | |
198 | + } | |
199 | + /* prevent the device from being autosuspended */ | |
200 | + | |
201 | + /* save our object in the file's private structure */ | |
202 | + dev->bufferIndex = 0; | |
203 | + file->private_data = dev; | |
204 | + mutex_unlock(&dev->io_mutex); | |
205 | + | |
206 | +exit: | |
207 | + return retval; | |
208 | +} | |
209 | + | |
210 | +static int pqlabs_release(struct inode *inode, struct file *file) | |
211 | +{ | |
212 | + struct usb_pqlabs *dev; | |
213 | + | |
214 | + dev = (struct usb_pqlabs *)file->private_data; | |
215 | + if (dev == NULL) | |
216 | + return -ENODEV; | |
217 | + | |
218 | + /* allow the device to be autosuspended */ | |
219 | + mutex_lock(&dev->io_mutex); | |
220 | + if (!--dev->open_count && dev->interface) | |
221 | + usb_autopm_put_interface(dev->interface); | |
222 | + mutex_unlock(&dev->io_mutex); | |
223 | + | |
224 | + printk("%s: submitted_urb = %d\n", __func__, dev->submitted_urb); | |
225 | + if (dev->submitted_urb); | |
226 | + complete(&dev->bulk_in_completion); | |
227 | + | |
228 | + spin_lock(&dev->err_lock); | |
229 | + dev->ongoing_read = 0; | |
230 | + dev->submitted_urb = 0; | |
231 | + spin_unlock(&dev->err_lock); | |
232 | + | |
233 | + /* decrement the count on our device */ | |
234 | + kref_put(&dev->kref, pqlabs_delete); | |
235 | + return 0; | |
236 | +} | |
237 | + | |
238 | +static int pqlabs_flush(struct file *file, fl_owner_t id) | |
239 | +{ | |
240 | + struct usb_pqlabs *dev; | |
241 | + int res; | |
242 | + | |
243 | + dev = (struct usb_pqlabs *)file->private_data; | |
244 | + if (dev == NULL) | |
245 | + return -ENODEV; | |
246 | + | |
247 | + /* wait for io to stop */ | |
248 | + mutex_lock(&dev->io_mutex); | |
249 | + pqlabs_draw_down(dev); | |
250 | + | |
251 | + /* read out errors, leave subsequent opens a clean slate */ | |
252 | + spin_lock_irq(&dev->err_lock); | |
253 | + res = dev->errors ? (dev->errors == -EPIPE ? -EPIPE : -EIO) : 0; | |
254 | + dev->errors = 0; | |
255 | + spin_unlock_irq(&dev->err_lock); | |
256 | + | |
257 | + mutex_unlock(&dev->io_mutex); | |
258 | + | |
259 | + return res; | |
260 | +} | |
261 | + | |
262 | +static void pqlabs_read_bulk_callback(struct urb *urb) | |
263 | +{ | |
264 | + struct usb_pqlabs *dev; | |
265 | + dev = urb->context; | |
266 | + | |
267 | + /* sync/async unlink faults aren't errors */ | |
268 | + if (urb->status) | |
269 | + { | |
270 | + if (!(urb->status == -ENOENT || | |
271 | + urb->status == -ECONNRESET || | |
272 | + urb->status == -ESHUTDOWN)) | |
273 | + err("%s - nonzero read bulk status received: %d\n", __func__, urb->status); | |
274 | + dev->errors = urb->status; | |
275 | + } | |
276 | + else | |
277 | + { | |
278 | + dev->bulk_in_filled = urb->actual_length; | |
279 | + //if (dev->bulk_in_filled == 0) dev->bulk_in_filled = dev->bulk_in_size + 1; | |
280 | + } | |
281 | + | |
282 | + dev->submitted_urb = 0; | |
283 | + complete(&dev->bulk_in_completion); | |
284 | +} | |
285 | + | |
286 | +static int pqlabs_do_read_io(struct usb_pqlabs *dev, size_t count) | |
287 | +{ | |
288 | + int rv; | |
289 | + | |
290 | + /* prepare a read */ | |
291 | + usb_fill_bulk_urb(dev->bulk_in_urb, | |
292 | + dev->udev, | |
293 | + usb_rcvbulkpipe(dev->udev, | |
294 | + dev->bulk_in_endpointAddr), | |
295 | + dev->bulk_in_buffer, | |
296 | + min(dev->bulk_in_size, count), | |
297 | + pqlabs_read_bulk_callback, | |
298 | + dev); | |
299 | + | |
300 | + /* do it */ | |
301 | + rv = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL); | |
302 | + if (rv < 0) | |
303 | + { | |
304 | + err("%s - failed submitting read urb, error %d", __func__, rv); | |
305 | + dev->bulk_in_filled = 0; | |
306 | + rv = (rv == -ENOMEM) ? rv : -EIO; | |
307 | + } | |
308 | + else | |
309 | + { | |
310 | + dev->submitted_urb = 1; | |
311 | + } | |
312 | + return rv; | |
313 | +} | |
314 | + | |
315 | +#define READ_USB_MAX_LENGTH (8 * 1024) | |
316 | +#define READ_USB_TIMEOUT (1000) //(3000) | |
317 | +static ssize_t pqlabs_read(struct file *file, char *buffer, size_t count, loff_t *ppos) | |
318 | +{ | |
319 | + struct usb_pqlabs *dev; | |
320 | + int rv; | |
321 | + // bool ongoing_io; | |
322 | + | |
323 | + dev = (struct usb_pqlabs *)file->private_data; | |
324 | + | |
325 | + /* if we cannot read at all, return EOF */ | |
326 | + if (!dev->bulk_in_urb || !count || count > READ_USB_MAX_LENGTH) return 0; | |
327 | + | |
328 | + if (dev->disconnecting || dev->open_count == 0) return -ENODEV; | |
329 | + | |
330 | + /* no concurrent readers */ | |
331 | + rv = mutex_lock_interruptible(&dev->io_mutex); | |
332 | + if (rv < 0) | |
333 | + { | |
334 | + return rv; | |
335 | + } | |
336 | + | |
337 | + if (!dev->interface) | |
338 | + { | |
339 | + /* disconnect() was called */ | |
340 | + rv = -ENODEV; | |
341 | + goto exit; | |
342 | + } | |
343 | + | |
344 | + dev->bulk_in_filled = 0; | |
345 | + dev->processed_urb = 0; | |
346 | + | |
347 | + //printk("%s: Enter\n", __func__); | |
348 | + | |
349 | + if (!(dev->processed_urb) && dev->submitted_urb) | |
350 | + { | |
351 | + rv = wait_for_completion_interruptible_timeout(&dev->bulk_in_completion, msecs_to_jiffies(READ_USB_TIMEOUT)); | |
352 | + //rv = wait_for_completion_interruptible(&dev->bulk_in_completion); | |
353 | + if (rv <= 0) | |
354 | + { | |
355 | + err("%s: processed_urb = 0 && submitted_urb = 1\n", __func__); | |
356 | + usb_kill_urb(dev->bulk_in_urb); | |
357 | + dev->submitted_urb = 0; | |
358 | + goto exit; | |
359 | + } | |
360 | + } | |
361 | + else | |
362 | + { | |
363 | + rv = pqlabs_do_read_io(dev, count); | |
364 | + if (rv < 0) | |
365 | + { | |
366 | + err("%s: pqlabs_do_read_io failed!\n", __func__); | |
367 | + goto exit; | |
368 | + } | |
369 | + | |
370 | + while(1) | |
371 | + { | |
372 | + | |
373 | + rv = wait_for_completion_interruptible_timeout(&dev->bulk_in_completion, msecs_to_jiffies(READ_USB_TIMEOUT)); | |
374 | + if (rv == msecs_to_jiffies(READ_USB_TIMEOUT) && dev->bulk_in_filled == 0) | |
375 | + { | |
376 | + rv = wait_for_completion_interruptible_timeout(&dev->bulk_in_completion, msecs_to_jiffies(READ_USB_TIMEOUT)); | |
377 | + } | |
378 | + | |
379 | + //printk("before wait for completion\n"); | |
380 | + //wait_for_completion(&dev->bulk_in_completion); | |
381 | + //printk("after wait for completion\n"); | |
382 | + | |
383 | + if (rv > 0) break; | |
384 | + | |
385 | + if (rv == 0) | |
386 | + { | |
387 | + err("%s: timeout!\n", __func__); | |
388 | + if (dev->disconnecting == 1) | |
389 | + { | |
390 | + err("%s: disconnected break!\n", __func__); | |
391 | + goto exit; | |
392 | + } | |
393 | + dev->submitted_urb = 0; | |
394 | + rv = -ETIME; | |
395 | + usb_kill_urb(dev->bulk_in_urb); | |
396 | + goto exit; | |
397 | + } | |
398 | + | |
399 | + if (rv < 0) | |
400 | + { | |
401 | + err("%s: rv < 0\n", __func__); | |
402 | + usb_kill_urb(dev->bulk_in_urb); | |
403 | + dev->submitted_urb = 0; | |
404 | + goto exit; | |
405 | + } | |
406 | + } | |
407 | + } | |
408 | + | |
409 | + rv = dev->errors; | |
410 | + if (rv < 0) | |
411 | + { | |
412 | + dev->errors = 0; | |
413 | + rv = (rv == -EPIPE) ? rv : -EIO; | |
414 | + err("%s: dev->error < 0\n", __func__); | |
415 | + goto exit; | |
416 | + } | |
417 | + | |
418 | + if (dev->bulk_in_filled == 0) | |
419 | + { | |
420 | + rv = 0; | |
421 | + err("%s: bulk_in_filled = 0\n", __func__); | |
422 | + goto exit; | |
423 | + } | |
424 | + | |
425 | + //if (dev->bulk_in_filled) | |
426 | + //printk("head: 0x%08X\n", *(unsigned int *)(dev->bulk_in_buffer)); | |
427 | + if (copy_to_user(buffer, dev->bulk_in_buffer, dev->bulk_in_filled)) | |
428 | + rv = -EFAULT; | |
429 | + else | |
430 | + rv = dev->bulk_in_filled; | |
431 | +exit: | |
432 | + mutex_unlock(&dev->io_mutex); | |
433 | + return rv; | |
434 | +} | |
435 | + | |
436 | +static void pqlabs_write_bulk_callback(struct urb *urb) | |
437 | +{ | |
438 | + struct usb_pqlabs *dev; | |
439 | + | |
440 | + dev = urb->context; | |
441 | + | |
442 | + /* sync/async unlink faults aren't errors */ | |
443 | + if (urb->status) { | |
444 | + /* | |
445 | + if (!(urb->status == -ENOENT || | |
446 | + urb->status == -ECONNRESET || | |
447 | + urb->status == -ESHUTDOWN)) | |
448 | + err("%s - nonzero write bulk status received: %d", | |
449 | + __func__, urb->status); | |
450 | + */ | |
451 | + spin_lock(&dev->err_lock); | |
452 | + dev->errors = urb->status; | |
453 | + spin_unlock(&dev->err_lock); | |
454 | + } | |
455 | + | |
456 | + /* free up our allocated buffer */ | |
457 | + usb_free_coherent(urb->dev, urb->transfer_buffer_length, | |
458 | + urb->transfer_buffer, urb->transfer_dma); | |
459 | + up(&dev->limit_sem); | |
460 | +} | |
461 | + | |
462 | +static ssize_t pqlabs_write(struct file *file, const char *user_buffer, | |
463 | + size_t count, loff_t *ppos) | |
464 | +{ | |
465 | + struct usb_pqlabs *dev; | |
466 | + int retval = -1; | |
467 | + struct urb *urb = NULL; | |
468 | + char *buf = NULL; | |
469 | + size_t writesize = min(count, (size_t)MAX_TRANSFER); | |
470 | + | |
471 | + dev = (struct usb_pqlabs*)file->private_data; | |
472 | + | |
473 | + /* verify that we actually have some data to write */ | |
474 | + if (count == 0) | |
475 | + goto exit; | |
476 | + | |
477 | + if (dev->disconnecting || dev->open_count == 0) return -ENODEV; | |
478 | + | |
479 | + /* | |
480 | + * limit the number of URBs in flight to stop a user from using up all | |
481 | + * RAM | |
482 | + */ | |
483 | + if (!(file->f_flags & O_NONBLOCK)) { | |
484 | + if (down_interruptible(&dev->limit_sem)) { | |
485 | + retval = -ERESTARTSYS; | |
486 | + goto exit; | |
487 | + } | |
488 | + } else { | |
489 | + if (down_trylock(&dev->limit_sem)) { | |
490 | + retval = -EAGAIN; | |
491 | + goto exit; | |
492 | + } | |
493 | + } | |
494 | + | |
495 | + spin_lock_irq(&dev->err_lock); | |
496 | + retval = dev->errors; | |
497 | + if (retval < 0) { | |
498 | + /* any error is reported once */ | |
499 | + dev->errors = 0; | |
500 | + /* to preserve notifications about reset */ | |
501 | + retval = (retval == -EPIPE) ? retval : -EIO; | |
502 | + } | |
503 | + spin_unlock_irq(&dev->err_lock); | |
504 | + if (retval < 0) | |
505 | + goto error; | |
506 | + | |
507 | + /* create a urb, and a buffer for it, and copy the data to the urb */ | |
508 | + urb = usb_alloc_urb(0, GFP_KERNEL); | |
509 | + if (!urb) { | |
510 | + retval = -ENOMEM; | |
511 | + goto error; | |
512 | + } | |
513 | + | |
514 | + buf = usb_alloc_coherent(dev->udev, writesize, GFP_KERNEL, | |
515 | + &urb->transfer_dma); | |
516 | + if (!buf) { | |
517 | + retval = -ENOMEM; | |
518 | + goto error; | |
519 | + } | |
520 | + | |
521 | + if (copy_from_user(buf, user_buffer, writesize)) { | |
522 | + retval = -EFAULT; | |
523 | + goto error; | |
524 | + } | |
525 | + | |
526 | + /* this lock makes sure we don't submit URBs to gone devices */ | |
527 | + mutex_lock(&dev->io_mutex); | |
528 | + if (!dev->interface) { /* disconnect() was called */ | |
529 | + mutex_unlock(&dev->io_mutex); | |
530 | + retval = -ENODEV; | |
531 | + goto error; | |
532 | + } | |
533 | + | |
534 | + /* initialize the urb properly */ | |
535 | + usb_fill_bulk_urb(urb, dev->udev, | |
536 | + usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), | |
537 | + buf, writesize, pqlabs_write_bulk_callback, dev); | |
538 | + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | |
539 | + usb_anchor_urb(urb, &dev->submitted); | |
540 | + | |
541 | + /* send the data out the bulk port */ | |
542 | + retval = usb_submit_urb(urb, GFP_KERNEL); | |
543 | + mutex_unlock(&dev->io_mutex); | |
544 | + if (retval) { | |
545 | +// err("%s - failed submitting write urb, error %d", __func__, retval); | |
546 | + goto error_unanchor; | |
547 | + } | |
548 | + | |
549 | + /* | |
550 | + * release our reference to this urb, the USB core will eventually free | |
551 | + * it entirely | |
552 | + */ | |
553 | + usb_free_urb(urb); | |
554 | + | |
555 | + | |
556 | + return writesize; | |
557 | + | |
558 | +error_unanchor: | |
559 | + usb_unanchor_urb(urb); | |
560 | +error: | |
561 | + if (urb) { | |
562 | + usb_free_coherent(dev->udev, writesize, buf, urb->transfer_dma); | |
563 | + usb_free_urb(urb); | |
564 | + } | |
565 | + up(&dev->limit_sem); | |
566 | + | |
567 | +exit: | |
568 | + return retval; | |
569 | +} | |
570 | + | |
571 | +static long pqlabs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |
572 | +{ | |
573 | + struct usb_device *udev; | |
574 | + struct usb_pqlabs *dev; | |
575 | + int ret, result; | |
576 | + int len, idx; | |
577 | + char *buf; | |
578 | + int i; | |
579 | + void __user *user_arg = (void __user *)arg; | |
580 | + | |
581 | + ret = 0; | |
582 | + len = 0; | |
583 | + dev = (struct usb_pqlabs *)file->private_data; | |
584 | + udev = dev->udev; | |
585 | + | |
586 | + if (cmd == USB_IOCTL_GET_STRING) | |
587 | + { | |
588 | + if (get_user(idx, (int __user *)user_arg)) | |
589 | + { | |
590 | + err("pqlabs: get idx failed!\n"); | |
591 | + return -EFAULT; | |
592 | + } | |
593 | + | |
594 | + if (udev->state == USB_STATE_SUSPENDED) return -EHOSTUNREACH; | |
595 | + | |
596 | + if ((buf = kmalloc(256, GFP_KERNEL)) == NULL) return -ENOMEM; | |
597 | + | |
598 | + for(i = 0; i < 3; i++) | |
599 | + { | |
600 | + result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), | |
601 | + USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, | |
602 | + (USB_DT_STRING << 8) + idx, 0x0409, buf, 255, | |
603 | + USB_CTRL_GET_TIMEOUT); | |
604 | + if (result == 0 || result == -EPIPE) continue; | |
605 | + | |
606 | + if (result > 1 && ((u8 *)buf)[1] != USB_DT_STRING) | |
607 | + { | |
608 | + result = -ENODATA; | |
609 | + continue; | |
610 | + } | |
611 | + break; | |
612 | + } | |
613 | + | |
614 | + if (result > 0) | |
615 | + { | |
616 | + len = buf[0]; | |
617 | + if (copy_to_user(user_arg + sizeof(int), buf, len + 1)) | |
618 | + { | |
619 | + kfree(buf); | |
620 | + return -EFAULT; | |
621 | + } | |
622 | + } | |
623 | + kfree(buf); | |
624 | + return len; | |
625 | + } | |
626 | + else if (cmd == USB_IOCTL_CLEAR_FEATURE) | |
627 | + { | |
628 | + char dBuf[8]; | |
629 | + if (udev->state == USB_STATE_SUSPENDED) return -EHOSTUNREACH; | |
630 | + | |
631 | + | |
632 | + result = usb_control_msg(udev, | |
633 | + usb_sndctrlpipe(udev, 0), | |
634 | + USB_REQ_CLEAR_FEATURE, | |
635 | + USB_TYPE_STANDARD | USB_RECIP_ENDPOINT, | |
636 | + 0, 0x82, dBuf, 8, | |
637 | + 500); | |
638 | + return result; | |
639 | + } | |
640 | + else if (cmd == USB_IOCTL_CLEAR_URB) | |
641 | + { | |
642 | + | |
643 | + //if (dev->disconnecting == 0) | |
644 | + //usb_reset_endpoint(dev->udev, 0x82); | |
645 | + //usb_queue_reset_device(dev->interface); | |
646 | + //usb_reset_device(dev->udev); | |
647 | + return 0; | |
648 | + } | |
649 | + else if (cmd == HIDIOCGSTRING) | |
650 | + { | |
651 | + if (get_user(idx, (int __user *)user_arg)) | |
652 | + { | |
653 | + err("pqlabs: get hid idx failed!\n"); | |
654 | + return -EFAULT; | |
655 | + } | |
656 | + | |
657 | + if (udev->state == USB_STATE_SUSPENDED) return -EHOSTUNREACH; | |
658 | + | |
659 | + if ((buf = kmalloc(HID_STRING_SIZE, GFP_KERNEL)) == NULL) return -ENOMEM; | |
660 | + | |
661 | + if ((len = usb_string(udev, idx, buf, HID_STRING_SIZE-1)) < 0) | |
662 | + { | |
663 | + kfree(buf); | |
664 | + return -EINVAL; | |
665 | + } | |
666 | + | |
667 | + if (copy_to_user(user_arg+sizeof(int), buf, len+1)) | |
668 | + { | |
669 | + kfree(buf); | |
670 | + return -EFAULT; | |
671 | + } | |
672 | + | |
673 | + kfree(buf); | |
674 | + return len; | |
675 | + } | |
676 | + else if (cmd == USB_IOCTL_WRITE_HID_CMD) | |
677 | + { | |
678 | + if (get_user(idx, (int __user *)user_arg)) | |
679 | + { | |
680 | + err("pqlabs: get write command length failed!\n"); | |
681 | + return -EFAULT; | |
682 | + } | |
683 | + | |
684 | + if (idx > 64) idx = 64; | |
685 | + | |
686 | + if (udev->state == USB_STATE_SUSPENDED) return -EHOSTUNREACH; | |
687 | + | |
688 | + if ((buf = kmalloc(64, GFP_KERNEL)) == NULL) return -ENOMEM; | |
689 | + | |
690 | + if (copy_from_user(buf, user_arg + sizeof(int), idx)) | |
691 | + { | |
692 | + kfree(buf); | |
693 | + return -EFAULT; | |
694 | + } | |
695 | + | |
696 | + pq_trace("idx = %d, buf[0] = %d\n", idx, buf[0]); | |
697 | + ret = usb_control_msg(udev, | |
698 | + usb_rcvctrlpipe(udev, 0), | |
699 | + 0xF0, | |
700 | + USB_TYPE_VENDOR | USB_DIR_IN, | |
701 | + buf[0], 0, buf, idx, | |
702 | + USB_CTRL_GET_TIMEOUT); | |
703 | + kfree(buf); | |
704 | + } else if (cmd == USB_IOCTL_RESET_DEVICE) { | |
705 | + usb_queue_reset_device(dev->interface); | |
706 | + } | |
707 | + | |
708 | + return ret; | |
709 | +} | |
710 | + | |
711 | +#define PT_SIZE 10 | |
712 | + | |
713 | +/* Sysfs method to input simulated | |
714 | + coordinates to the virtual | |
715 | + mouse driver */ | |
716 | +static ssize_t write_vms(struct device *device, struct device_attribute *attr, const char *buffer, size_t count) | |
717 | +{ | |
718 | + int type, slot; | |
719 | + int ptCount; | |
720 | + int i; | |
721 | +// int ret; | |
722 | + int x, y, w, h; | |
723 | + struct usb_interface *iface = to_usb_interface(device); | |
724 | + struct usb_pqlabs *dev = (struct usb_pqlabs *)usb_get_intfdata(iface); | |
725 | +// char *pWalk = buffer; | |
726 | + | |
727 | + /* ID Counts + \n | |
728 | + contactid + x + y + width + height + \n | |
729 | + */ | |
730 | + ptCount = buffer[0]; | |
731 | + for (i = 0; i < ptCount; i++) | |
732 | + { | |
733 | + type = buffer[i * PT_SIZE + 1]; | |
734 | + slot = buffer[i * PT_SIZE + 2]; | |
735 | + x = buffer[i * PT_SIZE + 3] | (buffer[i * PT_SIZE + 4] << 8); | |
736 | + y = buffer[i * PT_SIZE + 5] | (buffer[i * PT_SIZE + 6] << 8); | |
737 | + w = buffer[i * PT_SIZE + 7] | (buffer[i * PT_SIZE + 8] << 8); | |
738 | + h = buffer[i * PT_SIZE + 9] | (buffer[i * PT_SIZE + 10] << 8); | |
739 | + | |
740 | + if (type == 0x3) // DOWN OR MOVE | |
741 | + { | |
742 | + input_mt_slot(dev->input_dev, slot); | |
743 | + input_mt_report_slot_state(dev->input_dev, MT_TOOL_FINGER, true); | |
744 | + input_report_abs(dev->input_dev, ABS_MT_POSITION_X, x); | |
745 | + input_report_abs(dev->input_dev, ABS_MT_POSITION_Y, y); | |
746 | + input_report_abs(dev->input_dev, ABS_MT_ORIENTATION, w > h); | |
747 | + input_report_abs(dev->input_dev, ABS_MT_TOUCH_MAJOR, w); | |
748 | + input_report_abs(dev->input_dev, ABS_MT_TOUCH_MINOR, h); | |
749 | + | |
750 | + } | |
751 | + else if (type == 0x2) // UP | |
752 | + { | |
753 | + input_mt_slot(dev->input_dev, slot); | |
754 | + input_mt_report_slot_state(dev->input_dev, MT_TOOL_FINGER, false); | |
755 | + } | |
756 | + } | |
757 | + input_sync(dev->input_dev); | |
758 | + | |
759 | + return ptCount; | |
760 | +} | |
761 | + | |
762 | +/* Attach the sysfs write method */ | |
763 | +DEVICE_ATTR(coordinates, 0644, NULL, write_vms); | |
764 | + | |
765 | + | |
766 | +static ssize_t write_flag(struct device *device, struct device_attribute *attr, const char *buffer, size_t count) | |
767 | +{ | |
768 | + struct usb_interface *iface = to_usb_interface(device); | |
769 | + struct usb_pqlabs *dev = (struct usb_pqlabs *)usb_get_intfdata(iface); | |
770 | + dev->extraFlag = buffer[0]; | |
771 | + | |
772 | + return 1; | |
773 | +} | |
774 | + | |
775 | +static ssize_t read_flag(struct device *device, struct device_attribute *attr, char *buffer) | |
776 | +{ | |
777 | + struct usb_interface *iface = to_usb_interface(device); | |
778 | + struct usb_pqlabs *dev = (struct usb_pqlabs *)usb_get_intfdata(iface); | |
779 | + buffer[0] = dev->extraFlag; | |
780 | + | |
781 | + return 1; | |
782 | +} | |
783 | + | |
784 | +DEVICE_ATTR(flag, 0770, read_flag, write_flag); | |
785 | + | |
786 | + | |
787 | +/* Attribute Descriptor */ | |
788 | +static struct attribute *vms_attrs[] = { | |
789 | + &dev_attr_coordinates.attr, | |
790 | + &dev_attr_flag.attr, | |
791 | + NULL | |
792 | +}; | |
793 | + | |
794 | + | |
795 | +/* Attribute group */ | |
796 | +static struct attribute_group vms_attr_group = { | |
797 | + .attrs = vms_attrs, | |
798 | +}; | |
799 | + | |
800 | + | |
801 | + | |
802 | +#if defined CONFIG_COMPAT | |
803 | +static long pqlabs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |
804 | +{ | |
805 | + unsigned long translated_arg = (unsigned long)compat_ptr(arg); | |
806 | + return pqlabs_ioctl(file, cmd, translated_arg); | |
807 | +} | |
808 | +#endif | |
809 | + | |
810 | +static const struct file_operations pqlabs_fops = { | |
811 | + .owner = THIS_MODULE, | |
812 | + .read = pqlabs_read, | |
813 | + .write = pqlabs_write, | |
814 | + .open = pqlabs_open, | |
815 | + .release = pqlabs_release, | |
816 | + .flush = pqlabs_flush, | |
817 | + .unlocked_ioctl = pqlabs_ioctl, | |
818 | +#if defined CONFIG_COMPAT | |
819 | + .compat_ioctl = pqlabs_compat_ioctl, | |
820 | +#endif | |
821 | +}; | |
822 | + | |
823 | +/* | |
824 | + * usb class driver info in order to get a minor number from the usb core, | |
825 | + * and to have the device registered with the driver core | |
826 | + */ | |
827 | +static struct usb_class_driver pqlabs_class = { | |
828 | + .name = "pqlabs_bulk%d", | |
829 | + .fops = &pqlabs_fops, | |
830 | + .minor_base = USB_pqlabs_MINOR_BASE, | |
831 | +}; | |
832 | + | |
833 | +static int pqlabs_probe(struct usb_interface *interface, | |
834 | + const struct usb_device_id *id) | |
835 | +{ | |
836 | + struct usb_pqlabs *dev; | |
837 | + struct usb_host_interface *iface_desc; | |
838 | + struct usb_endpoint_descriptor *endpoint; | |
839 | + size_t buffer_size; | |
840 | + int i; | |
841 | + int retval = -ENOMEM; | |
842 | + | |
843 | + /* allocate memory for our device state and initialize it */ | |
844 | + dev = kzalloc(sizeof(*dev), GFP_KERNEL); | |
845 | + if (!dev) | |
846 | + { | |
847 | + //err("Out of memory"); | |
848 | + goto error; | |
849 | + } | |
850 | + kref_init(&dev->kref); | |
851 | + sema_init(&dev->limit_sem, WRITES_IN_FLIGHT); | |
852 | + mutex_init(&dev->io_mutex); | |
853 | + spin_lock_init(&dev->err_lock); | |
854 | + init_usb_anchor(&dev->submitted); | |
855 | + init_completion(&dev->bulk_in_completion); | |
856 | + | |
857 | + dev->udev = usb_get_dev(interface_to_usbdev(interface)); | |
858 | + dev->interface = interface; | |
859 | + dev->disconnecting = false; | |
860 | + dev->extraFlag = 0; | |
861 | + | |
862 | + /* set up the endpoint information */ | |
863 | + /* use only the first bulk-in and bulk-out endpoints */ | |
864 | + iface_desc = interface->cur_altsetting; | |
865 | + | |
866 | + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) | |
867 | + { | |
868 | + endpoint = &iface_desc->endpoint[i].desc; | |
869 | + if (!dev->bulk_in_endpointAddr && usb_endpoint_is_bulk_in(endpoint)) | |
870 | + { | |
871 | + /* we found a bulk in endpoint */ | |
872 | + buffer_size = READ_USB_MAX_LENGTH; //le16_to_cpu(endpoint->wMaxPacketSize); | |
873 | + dev->total_size = buffer_size * MAX_BUFFER_NUMBER; | |
874 | + dev->bulk_in_size = buffer_size; | |
875 | + dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; | |
876 | + dev->bulk_in_buffer = kmalloc(dev->total_size, GFP_KERNEL); | |
877 | + if (!dev->bulk_in_buffer) | |
878 | + { | |
879 | + err("Could not allocate bulk_in_buffer"); | |
880 | + goto error; | |
881 | + } | |
882 | + | |
883 | + dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL); | |
884 | + if (!dev->bulk_in_urb) | |
885 | + { | |
886 | + err("Could not allocate bulk_in_urb"); | |
887 | + goto error; | |
888 | + } | |
889 | + } | |
890 | + | |
891 | + if (!dev->bulk_out_endpointAddr && | |
892 | + usb_endpoint_is_bulk_out(endpoint)) { | |
893 | + /* we found a bulk out endpoint */ | |
894 | + dev->bulk_out_endpointAddr = endpoint->bEndpointAddress; | |
895 | + } | |
896 | + } | |
897 | + | |
898 | + /* save our data pointer in this interface device */ | |
899 | + usb_set_intfdata(interface, dev); | |
900 | + | |
901 | + /* we can register the device now, as it is ready */ | |
902 | + retval = usb_register_dev(interface, &pqlabs_class); | |
903 | + if (retval) { | |
904 | + /* something prevented us from registering this driver */ | |
905 | + //err("Not able to get a minor for this device."); | |
906 | + usb_set_intfdata(interface, NULL); | |
907 | + goto error; | |
908 | + } | |
909 | + | |
910 | + dev->input_dev = input_allocate_device(); | |
911 | + if (dev->input_dev == NULL) | |
912 | + { | |
913 | + retval = -ENOMEM; | |
914 | + printk("Failed to allocate input device\n"); | |
915 | + goto error; | |
916 | + } | |
917 | + | |
918 | + __set_bit(INPUT_PROP_DIRECT, dev->input_dev->propbit); | |
919 | + __set_bit(EV_ABS, dev->input_dev->evbit); | |
920 | + | |
921 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) | |
922 | + input_mt_init_slots(dev->input_dev, MAX_SUPPORT_POINTS, 0); | |
923 | +#else | |
924 | + input_mt_init_slots(dev->input_dev, MAX_SUPPORT_POINTS); | |
925 | +#endif | |
926 | + input_set_abs_params(dev->input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0); | |
927 | + input_set_abs_params(dev->input_dev, ABS_MT_TOUCH_MAJOR, 0, 0xFFFF, 0, 0); | |
928 | + input_set_abs_params(dev->input_dev, ABS_MT_TOUCH_MINOR, 0, 0xFFFF, 0, 0); | |
929 | + input_set_abs_params(dev->input_dev, ABS_MT_POSITION_X, 0, 0xFFFF, 0, 0); | |
930 | + input_set_abs_params(dev->input_dev, ABS_MT_POSITION_Y, 0, 0xFFFF, 0, 0); | |
931 | + input_set_abs_params(dev->input_dev, ABS_X, 0, 0xFFFF, 0, 0); | |
932 | + input_set_abs_params(dev->input_dev, ABS_Y, 0, 0xFFFF, 0, 0); | |
933 | + sprintf(dev->phys, "input/pqlabs"); | |
934 | + dev->input_dev->name = TOUCHSCREEN_NAME; | |
935 | + dev->input_dev->phys = dev->phys; | |
936 | + dev->input_dev->id.bustype = BUS_USB; | |
937 | + dev->input_dev->id.vendor = 0x1EF1; | |
938 | + dev->input_dev->id.product = 0x0002; | |
939 | + dev->input_dev->id.version = 0x0001; //screen firmware version | |
940 | + | |
941 | + retval = input_register_device(dev->input_dev); | |
942 | + if (retval) | |
943 | + { | |
944 | + printk("Probe: Unable to register %s input device\n", dev->input_dev->name); | |
945 | + retval = -1; | |
946 | + goto error; | |
947 | + } | |
948 | + | |
949 | + /* Create a sysfs node to read simulated coordinates */ | |
950 | + sysfs_create_group(&interface->dev.kobj, &vms_attr_group); | |
951 | + //sysfs_create_group(&dev->input_dev->dev.kobj, &vms_attr_group); | |
952 | + | |
953 | + /* let the user know what node this device is now attached to */ | |
954 | + dev_info(&interface->dev, | |
955 | + "USB pqlabs bulk device now attached to USBpqlabs-%d", | |
956 | + interface->minor); | |
957 | + return 0; | |
958 | + | |
959 | +error: | |
960 | + if (dev->input_dev) | |
961 | + { | |
962 | + input_free_device(dev->input_dev); | |
963 | + } | |
964 | + | |
965 | + if (dev) | |
966 | + /* this frees allocated memory */ | |
967 | + kref_put(&dev->kref, pqlabs_delete); | |
968 | + return retval; | |
969 | +} | |
970 | + | |
971 | +static void pqlabs_disconnect(struct usb_interface *interface) | |
972 | +{ | |
973 | + struct usb_pqlabs *dev; | |
974 | + //int minor = interface->minor; | |
975 | + | |
976 | + dev = usb_get_intfdata(interface); | |
977 | + dev->disconnecting = true; | |
978 | + printk("%s: submitted_urb = %d\n", __func__, dev->submitted_urb); | |
979 | + if (dev->submitted_urb); | |
980 | + complete(&dev->bulk_in_completion); | |
981 | + | |
982 | + mutex_lock(&dev->io_mutex); | |
983 | + | |
984 | + sysfs_remove_group(&interface->dev.kobj, &vms_attr_group); | |
985 | + //sysfs_remove_group(&dev->input_dev->dev.kobj, &vms_attr_group); | |
986 | + input_mt_destroy_slots(dev->input_dev); | |
987 | + input_unregister_device(dev->input_dev); | |
988 | + if (dev->input_dev) | |
989 | + { | |
990 | + input_free_device(dev->input_dev); | |
991 | + } | |
992 | + usb_set_intfdata(interface, NULL); | |
993 | + | |
994 | + /* give back our minor */ | |
995 | + usb_deregister_dev(interface, &pqlabs_class); | |
996 | + | |
997 | + /* prevent more I/O from starting */ | |
998 | + dev->interface = NULL; | |
999 | + mutex_unlock(&dev->io_mutex); | |
1000 | + | |
1001 | + usb_kill_anchored_urbs(&dev->submitted); | |
1002 | + | |
1003 | + /* decrement our usage count */ | |
1004 | + kref_put(&dev->kref, pqlabs_delete); | |
1005 | + | |
1006 | + //dev_info(&interface->dev, "USB pqlabseton #%d now disconnected", minor); | |
1007 | +} | |
1008 | + | |
1009 | +static void pqlabs_draw_down(struct usb_pqlabs *dev) | |
1010 | +{ | |
1011 | + int time; | |
1012 | + | |
1013 | + time = usb_wait_anchor_empty_timeout(&dev->submitted, 1000); | |
1014 | + if (!time) | |
1015 | + usb_kill_anchored_urbs(&dev->submitted); | |
1016 | + usb_kill_urb(dev->bulk_in_urb); | |
1017 | +} | |
1018 | + | |
1019 | +static int pqlabs_suspend(struct usb_interface *intf, pm_message_t message) | |
1020 | +{ | |
1021 | + struct usb_pqlabs *dev = usb_get_intfdata(intf); | |
1022 | + | |
1023 | + if (!dev) | |
1024 | + return 0; | |
1025 | + pqlabs_draw_down(dev); | |
1026 | + return 0; | |
1027 | +} | |
1028 | + | |
1029 | +static int pqlabs_resume(struct usb_interface *intf) | |
1030 | +{ | |
1031 | + return 0; | |
1032 | +} | |
1033 | + | |
1034 | +static int pqlabs_pre_reset(struct usb_interface *intf) | |
1035 | +{ | |
1036 | + struct usb_pqlabs *dev = usb_get_intfdata(intf); | |
1037 | + | |
1038 | + mutex_lock(&dev->io_mutex); | |
1039 | + pqlabs_draw_down(dev); | |
1040 | + | |
1041 | + return 0; | |
1042 | +} | |
1043 | + | |
1044 | +static int pqlabs_post_reset(struct usb_interface *intf) | |
1045 | +{ | |
1046 | + struct usb_pqlabs *dev = usb_get_intfdata(intf); | |
1047 | + | |
1048 | + /* we are sure no URBs are active - no locking needed */ | |
1049 | + dev->errors = -EPIPE; | |
1050 | + mutex_unlock(&dev->io_mutex); | |
1051 | + | |
1052 | + return 0; | |
1053 | +} | |
1054 | + | |
1055 | +static struct usb_driver pqlabs_driver = { | |
1056 | + .name = "pqlabs_bulk", | |
1057 | + .probe = pqlabs_probe, | |
1058 | + .disconnect = pqlabs_disconnect, | |
1059 | + .suspend = pqlabs_suspend, | |
1060 | + .resume = pqlabs_resume, | |
1061 | + .pre_reset = pqlabs_pre_reset, | |
1062 | + .post_reset = pqlabs_post_reset, | |
1063 | + .id_table = pqlabs_table, | |
1064 | + .supports_autosuspend = 1, | |
1065 | +}; | |
1066 | + | |
1067 | +static int __init usb_pqlabs_init(void) | |
1068 | +{ | |
1069 | + int result; | |
1070 | + | |
1071 | + /* register this driver with the USB subsystem */ | |
1072 | + result = usb_register(&pqlabs_driver); | |
1073 | + if (result) | |
1074 | + err("usb_register failed. Error number %d", result); | |
1075 | + | |
1076 | + return result; | |
1077 | +} | |
1078 | + | |
1079 | +static void __exit usb_pqlabs_exit(void) | |
1080 | +{ | |
1081 | + /* deregister this driver with the USB subsystem */ | |
1082 | + usb_deregister(&pqlabs_driver); | |
1083 | +} | |
1084 | + | |
1085 | +module_init(usb_pqlabs_init); | |
1086 | +module_exit(usb_pqlabs_exit); | |
1087 | + | |
1088 | +MODULE_LICENSE("GPL"); |