Commit | Line | Data |
---|---|---|
cbc30118 SW |
1 | /***************************************************************************** |
2 | * File: drivers/usb/misc/vstusb.c | |
3 | * | |
4 | * Purpose: Support for the bulk USB Vernier Spectrophotometers | |
5 | * | |
6 | * Author: Johnnie Peters | |
7 | * Axian Consulting | |
8 | * Beaverton, OR, USA 97005 | |
9 | * | |
10 | * Modified by: EQware Engineering, Inc. | |
11 | * Oregon City, OR, USA 97045 | |
12 | * | |
13 | * Copyright: 2007, 2008 | |
14 | * Vernier Software & Technology | |
15 | * Beaverton, OR, USA 97005 | |
16 | * | |
17 | * Web: www.vernier.com | |
18 | * | |
19 | * This program is free software; you can redistribute it and/or modify | |
20 | * it under the terms of the GNU General Public License version 2 as | |
21 | * published by the Free Software Foundation. | |
22 | * | |
23 | *****************************************************************************/ | |
24 | #include <linux/kernel.h> | |
25 | #include <linux/errno.h> | |
26 | #include <linux/init.h> | |
27 | #include <linux/slab.h> | |
28 | #include <linux/module.h> | |
29 | #include <linux/mutex.h> | |
30 | #include <linux/uaccess.h> | |
31 | #include <linux/usb.h> | |
32 | ||
33 | #include <linux/usb/vstusb.h> | |
34 | ||
35 | #define DRIVER_VERSION "VST USB Driver Version 1.5" | |
36 | #define DRIVER_DESC "Vernier Software Technology Bulk USB Driver" | |
37 | ||
38 | #ifdef CONFIG_USB_DYNAMIC_MINORS | |
39 | #define VSTUSB_MINOR_BASE 0 | |
40 | #else | |
41 | #define VSTUSB_MINOR_BASE 199 | |
42 | #endif | |
43 | ||
44 | #define USB_VENDOR_OCEANOPTICS 0x2457 | |
45 | #define USB_VENDOR_VERNIER 0x08F7 /* Vernier Software & Technology */ | |
46 | ||
47 | #define USB_PRODUCT_USB2000 0x1002 | |
48 | #define USB_PRODUCT_ADC1000_FW 0x1003 /* firmware download (renumerates) */ | |
49 | #define USB_PRODUCT_ADC1000 0x1004 | |
50 | #define USB_PRODUCT_HR2000_FW 0x1009 /* firmware download (renumerates) */ | |
51 | #define USB_PRODUCT_HR2000 0x100A | |
52 | #define USB_PRODUCT_HR4000_FW 0x1011 /* firmware download (renumerates) */ | |
53 | #define USB_PRODUCT_HR4000 0x1012 | |
54 | #define USB_PRODUCT_USB650 0x1014 /* "Red Tide" */ | |
55 | #define USB_PRODUCT_QE65000 0x1018 | |
56 | #define USB_PRODUCT_USB4000 0x1022 | |
57 | #define USB_PRODUCT_USB325 0x1024 /* "Vernier Spectrometer" */ | |
58 | ||
59 | #define USB_PRODUCT_LABPRO 0x0001 | |
60 | #define USB_PRODUCT_LABQUEST 0x0005 | |
61 | ||
84dcd594 SW |
62 | #define VST_MAXBUFFER (64*1024) |
63 | ||
cbc30118 SW |
64 | static struct usb_device_id id_table[] = { |
65 | { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB2000)}, | |
66 | { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_HR4000)}, | |
67 | { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB650)}, | |
68 | { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB4000)}, | |
69 | { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB325)}, | |
70 | { USB_DEVICE(USB_VENDOR_VERNIER, USB_PRODUCT_LABQUEST)}, | |
71 | { USB_DEVICE(USB_VENDOR_VERNIER, USB_PRODUCT_LABPRO)}, | |
72 | {}, | |
73 | }; | |
74 | ||
75 | MODULE_DEVICE_TABLE(usb, id_table); | |
76 | ||
77 | struct vstusb_device { | |
84dcd594 | 78 | struct kref kref; |
cbc30118 SW |
79 | struct mutex lock; |
80 | struct usb_device *usb_dev; | |
81 | char present; | |
82 | char isopen; | |
83 | struct usb_anchor submitted; | |
84 | int rd_pipe; | |
85 | int rd_timeout_ms; | |
86 | int wr_pipe; | |
87 | int wr_timeout_ms; | |
88 | }; | |
84dcd594 | 89 | #define to_vst_dev(d) container_of(d, struct vstusb_device, kref) |
cbc30118 SW |
90 | |
91 | static struct usb_driver vstusb_driver; | |
92 | ||
84dcd594 SW |
93 | static void vstusb_delete(struct kref *kref) |
94 | { | |
95 | struct vstusb_device *vstdev = to_vst_dev(kref); | |
96 | ||
97 | usb_put_dev(vstdev->usb_dev); | |
98 | kfree(vstdev); | |
99 | } | |
100 | ||
cbc30118 SW |
101 | static int vstusb_open(struct inode *inode, struct file *file) |
102 | { | |
103 | struct vstusb_device *vstdev; | |
104 | struct usb_interface *interface; | |
105 | ||
106 | interface = usb_find_interface(&vstusb_driver, iminor(inode)); | |
107 | ||
108 | if (!interface) { | |
109 | printk(KERN_ERR KBUILD_MODNAME | |
110 | ": %s - error, can't find device for minor %d\n", | |
111 | __func__, iminor(inode)); | |
112 | return -ENODEV; | |
113 | } | |
114 | ||
115 | vstdev = usb_get_intfdata(interface); | |
116 | ||
117 | if (!vstdev) | |
118 | return -ENODEV; | |
119 | ||
120 | /* lock this device */ | |
121 | mutex_lock(&vstdev->lock); | |
122 | ||
123 | /* can only open one time */ | |
124 | if ((!vstdev->present) || (vstdev->isopen)) { | |
125 | mutex_unlock(&vstdev->lock); | |
126 | return -EBUSY; | |
127 | } | |
128 | ||
84dcd594 SW |
129 | /* increment our usage count */ |
130 | kref_get(&vstdev->kref); | |
131 | ||
cbc30118 SW |
132 | vstdev->isopen = 1; |
133 | ||
134 | /* save device in the file's private structure */ | |
135 | file->private_data = vstdev; | |
136 | ||
137 | dev_dbg(&vstdev->usb_dev->dev, "%s: opened\n", __func__); | |
138 | ||
139 | mutex_unlock(&vstdev->lock); | |
140 | ||
141 | return 0; | |
142 | } | |
143 | ||
84dcd594 | 144 | static int vstusb_release(struct inode *inode, struct file *file) |
cbc30118 SW |
145 | { |
146 | struct vstusb_device *vstdev; | |
147 | ||
148 | vstdev = file->private_data; | |
149 | ||
150 | if (vstdev == NULL) | |
151 | return -ENODEV; | |
152 | ||
153 | mutex_lock(&vstdev->lock); | |
154 | ||
155 | vstdev->isopen = 0; | |
cbc30118 | 156 | |
84dcd594 SW |
157 | dev_dbg(&vstdev->usb_dev->dev, "%s: released\n", __func__); |
158 | ||
159 | mutex_unlock(&vstdev->lock); | |
160 | ||
161 | kref_put(&vstdev->kref, vstusb_delete); | |
cbc30118 SW |
162 | |
163 | return 0; | |
164 | } | |
165 | ||
166 | static void usb_api_blocking_completion(struct urb *urb) | |
167 | { | |
168 | struct completion *completeit = urb->context; | |
169 | ||
170 | complete(completeit); | |
171 | } | |
172 | ||
173 | static int vstusb_fill_and_send_urb(struct urb *urb, | |
174 | struct usb_device *usb_dev, | |
175 | unsigned int pipe, void *data, | |
176 | unsigned int len, struct completion *done) | |
177 | { | |
178 | struct usb_host_endpoint *ep; | |
179 | struct usb_host_endpoint **hostep; | |
180 | unsigned int pipend; | |
181 | ||
182 | int status; | |
183 | ||
184 | hostep = usb_pipein(pipe) ? usb_dev->ep_in : usb_dev->ep_out; | |
185 | pipend = usb_pipeendpoint(pipe); | |
186 | ep = hostep[pipend]; | |
187 | ||
188 | if (!ep || (len == 0)) | |
189 | return -EINVAL; | |
190 | ||
191 | if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) | |
192 | == USB_ENDPOINT_XFER_INT) { | |
193 | pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30); | |
194 | usb_fill_int_urb(urb, usb_dev, pipe, data, len, | |
195 | (usb_complete_t)usb_api_blocking_completion, | |
196 | NULL, ep->desc.bInterval); | |
197 | } else | |
198 | usb_fill_bulk_urb(urb, usb_dev, pipe, data, len, | |
199 | (usb_complete_t)usb_api_blocking_completion, | |
200 | NULL); | |
201 | ||
202 | init_completion(done); | |
203 | urb->context = done; | |
204 | urb->actual_length = 0; | |
205 | status = usb_submit_urb(urb, GFP_KERNEL); | |
206 | ||
207 | return status; | |
208 | } | |
209 | ||
210 | static int vstusb_complete_urb(struct urb *urb, struct completion *done, | |
211 | int timeout, int *actual_length) | |
212 | { | |
213 | unsigned long expire; | |
214 | int status; | |
215 | ||
216 | expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT; | |
217 | if (!wait_for_completion_interruptible_timeout(done, expire)) { | |
218 | usb_kill_urb(urb); | |
219 | status = urb->status == -ENOENT ? -ETIMEDOUT : urb->status; | |
220 | ||
221 | dev_dbg(&urb->dev->dev, | |
222 | "%s timed out on ep%d%s len=%d/%d, urb status = %d\n", | |
223 | current->comm, | |
224 | usb_pipeendpoint(urb->pipe), | |
225 | usb_pipein(urb->pipe) ? "in" : "out", | |
226 | urb->actual_length, | |
227 | urb->transfer_buffer_length, | |
228 | urb->status); | |
229 | ||
230 | } else { | |
231 | if (signal_pending(current)) { | |
232 | /* if really an error */ | |
233 | if (urb->status && !((urb->status == -ENOENT) || | |
234 | (urb->status == -ECONNRESET) || | |
235 | (urb->status == -ESHUTDOWN))) { | |
236 | status = -EINTR; | |
237 | usb_kill_urb(urb); | |
238 | } else { | |
239 | status = 0; | |
240 | } | |
241 | ||
242 | dev_dbg(&urb->dev->dev, | |
243 | "%s: signal pending on ep%d%s len=%d/%d," | |
244 | "urb status = %d\n", | |
245 | current->comm, | |
246 | usb_pipeendpoint(urb->pipe), | |
247 | usb_pipein(urb->pipe) ? "in" : "out", | |
248 | urb->actual_length, | |
249 | urb->transfer_buffer_length, | |
250 | urb->status); | |
251 | ||
252 | } else { | |
253 | status = urb->status; | |
254 | } | |
255 | } | |
256 | ||
257 | if (actual_length) | |
258 | *actual_length = urb->actual_length; | |
259 | ||
260 | return status; | |
261 | } | |
262 | ||
263 | static ssize_t vstusb_read(struct file *file, char __user *buffer, | |
264 | size_t count, loff_t *ppos) | |
265 | { | |
266 | struct vstusb_device *vstdev; | |
267 | int cnt = -1; | |
268 | void *buf; | |
269 | int retval = 0; | |
270 | ||
271 | struct urb *urb; | |
272 | struct usb_device *dev; | |
273 | unsigned int pipe; | |
274 | int timeout; | |
275 | ||
276 | DECLARE_COMPLETION_ONSTACK(done); | |
277 | ||
278 | vstdev = file->private_data; | |
279 | ||
280 | if (vstdev == NULL) | |
281 | return -ENODEV; | |
282 | ||
283 | /* verify that we actually want to read some data */ | |
84dcd594 | 284 | if ((count == 0) || (count > VST_MAXBUFFER)) |
cbc30118 SW |
285 | return -EINVAL; |
286 | ||
287 | /* lock this object */ | |
288 | if (mutex_lock_interruptible(&vstdev->lock)) | |
289 | return -ERESTARTSYS; | |
290 | ||
291 | /* anyone home */ | |
292 | if (!vstdev->present) { | |
293 | mutex_unlock(&vstdev->lock); | |
294 | printk(KERN_ERR KBUILD_MODNAME | |
295 | ": %s: device not present\n", __func__); | |
296 | return -ENODEV; | |
297 | } | |
298 | ||
299 | /* pull out the necessary data */ | |
300 | dev = vstdev->usb_dev; | |
301 | pipe = usb_rcvbulkpipe(dev, vstdev->rd_pipe); | |
302 | timeout = vstdev->rd_timeout_ms; | |
303 | ||
304 | buf = kmalloc(count, GFP_KERNEL); | |
305 | if (buf == NULL) { | |
306 | mutex_unlock(&vstdev->lock); | |
307 | return -ENOMEM; | |
308 | } | |
309 | ||
310 | urb = usb_alloc_urb(0, GFP_KERNEL); | |
311 | if (!urb) { | |
312 | kfree(buf); | |
313 | mutex_unlock(&vstdev->lock); | |
314 | return -ENOMEM; | |
315 | } | |
316 | ||
317 | usb_anchor_urb(urb, &vstdev->submitted); | |
318 | retval = vstusb_fill_and_send_urb(urb, dev, pipe, buf, count, &done); | |
319 | mutex_unlock(&vstdev->lock); | |
320 | if (retval) { | |
321 | usb_unanchor_urb(urb); | |
322 | dev_err(&dev->dev, "%s: error %d filling and sending urb %d\n", | |
323 | __func__, retval, pipe); | |
324 | goto exit; | |
325 | } | |
326 | ||
327 | retval = vstusb_complete_urb(urb, &done, timeout, &cnt); | |
328 | if (retval) { | |
329 | dev_err(&dev->dev, "%s: error %d completing urb %d\n", | |
330 | __func__, retval, pipe); | |
331 | goto exit; | |
332 | } | |
333 | ||
334 | if (copy_to_user(buffer, buf, cnt)) { | |
335 | dev_err(&dev->dev, "%s: can't copy_to_user\n", __func__); | |
336 | retval = -EFAULT; | |
337 | } else { | |
338 | retval = cnt; | |
339 | dev_dbg(&dev->dev, "%s: read %d bytes from pipe %d\n", | |
340 | __func__, cnt, pipe); | |
341 | } | |
342 | ||
343 | exit: | |
344 | usb_free_urb(urb); | |
345 | kfree(buf); | |
346 | return retval; | |
347 | } | |
348 | ||
349 | static ssize_t vstusb_write(struct file *file, const char __user *buffer, | |
350 | size_t count, loff_t *ppos) | |
351 | { | |
352 | struct vstusb_device *vstdev; | |
353 | int cnt = -1; | |
354 | void *buf; | |
355 | int retval = 0; | |
356 | ||
357 | struct urb *urb; | |
358 | struct usb_device *dev; | |
359 | unsigned int pipe; | |
360 | int timeout; | |
361 | ||
362 | DECLARE_COMPLETION_ONSTACK(done); | |
363 | ||
364 | vstdev = file->private_data; | |
365 | ||
366 | if (vstdev == NULL) | |
367 | return -ENODEV; | |
368 | ||
369 | /* verify that we actually have some data to write */ | |
84dcd594 | 370 | if ((count == 0) || (count > VST_MAXBUFFER)) |
cbc30118 SW |
371 | return retval; |
372 | ||
373 | /* lock this object */ | |
374 | if (mutex_lock_interruptible(&vstdev->lock)) | |
375 | return -ERESTARTSYS; | |
376 | ||
377 | /* anyone home */ | |
378 | if (!vstdev->present) { | |
379 | mutex_unlock(&vstdev->lock); | |
380 | printk(KERN_ERR KBUILD_MODNAME | |
381 | ": %s: device not present\n", __func__); | |
382 | return -ENODEV; | |
383 | } | |
384 | ||
385 | /* pull out the necessary data */ | |
386 | dev = vstdev->usb_dev; | |
387 | pipe = usb_sndbulkpipe(dev, vstdev->wr_pipe); | |
388 | timeout = vstdev->wr_timeout_ms; | |
389 | ||
390 | buf = kmalloc(count, GFP_KERNEL); | |
391 | if (buf == NULL) { | |
392 | mutex_unlock(&vstdev->lock); | |
393 | return -ENOMEM; | |
394 | } | |
395 | ||
396 | urb = usb_alloc_urb(0, GFP_KERNEL); | |
397 | if (!urb) { | |
398 | kfree(buf); | |
399 | mutex_unlock(&vstdev->lock); | |
400 | return -ENOMEM; | |
401 | } | |
402 | ||
403 | if (copy_from_user(buf, buffer, count)) { | |
a08b43ae | 404 | mutex_unlock(&vstdev->lock); |
cbc30118 SW |
405 | dev_err(&dev->dev, "%s: can't copy_from_user\n", __func__); |
406 | retval = -EFAULT; | |
407 | goto exit; | |
408 | } | |
409 | ||
410 | usb_anchor_urb(urb, &vstdev->submitted); | |
411 | retval = vstusb_fill_and_send_urb(urb, dev, pipe, buf, count, &done); | |
412 | mutex_unlock(&vstdev->lock); | |
413 | if (retval) { | |
414 | usb_unanchor_urb(urb); | |
415 | dev_err(&dev->dev, "%s: error %d filling and sending urb %d\n", | |
416 | __func__, retval, pipe); | |
417 | goto exit; | |
418 | } | |
419 | ||
420 | retval = vstusb_complete_urb(urb, &done, timeout, &cnt); | |
421 | if (retval) { | |
422 | dev_err(&dev->dev, "%s: error %d completing urb %d\n", | |
423 | __func__, retval, pipe); | |
424 | goto exit; | |
425 | } else { | |
426 | retval = cnt; | |
427 | dev_dbg(&dev->dev, "%s: sent %d bytes to pipe %d\n", | |
428 | __func__, cnt, pipe); | |
429 | } | |
430 | ||
431 | exit: | |
432 | usb_free_urb(urb); | |
433 | kfree(buf); | |
434 | return retval; | |
435 | } | |
436 | ||
437 | static long vstusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |
438 | { | |
439 | int retval = 0; | |
440 | int cnt = -1; | |
441 | void __user *data = (void __user *)arg; | |
442 | struct vstusb_args usb_data; | |
443 | ||
444 | struct vstusb_device *vstdev; | |
445 | void *buffer = NULL; /* must be initialized. buffer is | |
446 | * referenced on exit but not all | |
447 | * ioctls allocate it */ | |
448 | ||
449 | struct urb *urb = NULL; /* must be initialized. urb is | |
450 | * referenced on exit but not all | |
451 | * ioctls allocate it */ | |
452 | struct usb_device *dev; | |
453 | unsigned int pipe; | |
454 | int timeout; | |
455 | ||
456 | DECLARE_COMPLETION_ONSTACK(done); | |
457 | ||
458 | vstdev = file->private_data; | |
459 | ||
460 | if (_IOC_TYPE(cmd) != VST_IOC_MAGIC) { | |
461 | dev_warn(&vstdev->usb_dev->dev, | |
462 | "%s: ioctl command %x, bad ioctl magic %x, " | |
463 | "expected %x\n", __func__, cmd, | |
464 | _IOC_TYPE(cmd), VST_IOC_MAGIC); | |
465 | return -EINVAL; | |
466 | } | |
467 | ||
468 | if (vstdev == NULL) | |
469 | return -ENODEV; | |
470 | ||
471 | if (copy_from_user(&usb_data, data, sizeof(struct vstusb_args))) { | |
472 | dev_err(&vstdev->usb_dev->dev, "%s: can't copy_from_user\n", | |
473 | __func__); | |
474 | return -EFAULT; | |
475 | } | |
476 | ||
477 | /* lock this object */ | |
478 | if (mutex_lock_interruptible(&vstdev->lock)) { | |
479 | retval = -ERESTARTSYS; | |
480 | goto exit; | |
481 | } | |
482 | ||
483 | /* anyone home */ | |
484 | if (!vstdev->present) { | |
485 | mutex_unlock(&vstdev->lock); | |
486 | dev_err(&vstdev->usb_dev->dev, "%s: device not present\n", | |
487 | __func__); | |
488 | retval = -ENODEV; | |
489 | goto exit; | |
490 | } | |
491 | ||
492 | /* pull out the necessary data */ | |
493 | dev = vstdev->usb_dev; | |
494 | ||
495 | switch (cmd) { | |
496 | ||
497 | case IOCTL_VSTUSB_CONFIG_RW: | |
498 | ||
499 | vstdev->rd_pipe = usb_data.rd_pipe; | |
500 | vstdev->rd_timeout_ms = usb_data.rd_timeout_ms; | |
501 | vstdev->wr_pipe = usb_data.wr_pipe; | |
502 | vstdev->wr_timeout_ms = usb_data.wr_timeout_ms; | |
503 | ||
504 | mutex_unlock(&vstdev->lock); | |
505 | ||
506 | dev_dbg(&dev->dev, "%s: setting pipes/timeouts, " | |
507 | "rdpipe = %d, rdtimeout = %d, " | |
508 | "wrpipe = %d, wrtimeout = %d\n", __func__, | |
509 | vstdev->rd_pipe, vstdev->rd_timeout_ms, | |
510 | vstdev->wr_pipe, vstdev->wr_timeout_ms); | |
511 | break; | |
512 | ||
513 | case IOCTL_VSTUSB_SEND_PIPE: | |
514 | ||
84dcd594 | 515 | if ((usb_data.count == 0) || (usb_data.count > VST_MAXBUFFER)) { |
cbc30118 SW |
516 | mutex_unlock(&vstdev->lock); |
517 | retval = -EINVAL; | |
518 | goto exit; | |
519 | } | |
520 | ||
521 | buffer = kmalloc(usb_data.count, GFP_KERNEL); | |
522 | if (buffer == NULL) { | |
523 | mutex_unlock(&vstdev->lock); | |
524 | retval = -ENOMEM; | |
525 | goto exit; | |
526 | } | |
527 | ||
528 | urb = usb_alloc_urb(0, GFP_KERNEL); | |
529 | if (!urb) { | |
530 | mutex_unlock(&vstdev->lock); | |
531 | retval = -ENOMEM; | |
532 | goto exit; | |
533 | } | |
534 | ||
535 | timeout = usb_data.timeout_ms; | |
536 | ||
537 | pipe = usb_sndbulkpipe(dev, usb_data.pipe); | |
538 | ||
539 | if (copy_from_user(buffer, usb_data.buffer, usb_data.count)) { | |
540 | dev_err(&dev->dev, "%s: can't copy_from_user\n", | |
541 | __func__); | |
542 | mutex_unlock(&vstdev->lock); | |
543 | retval = -EFAULT; | |
544 | goto exit; | |
545 | } | |
546 | ||
547 | usb_anchor_urb(urb, &vstdev->submitted); | |
548 | retval = vstusb_fill_and_send_urb(urb, dev, pipe, buffer, | |
549 | usb_data.count, &done); | |
550 | mutex_unlock(&vstdev->lock); | |
551 | if (retval) { | |
552 | usb_unanchor_urb(urb); | |
553 | dev_err(&dev->dev, | |
554 | "%s: error %d filling and sending urb %d\n", | |
555 | __func__, retval, pipe); | |
556 | goto exit; | |
557 | } | |
558 | ||
559 | retval = vstusb_complete_urb(urb, &done, timeout, &cnt); | |
560 | if (retval) { | |
561 | dev_err(&dev->dev, "%s: error %d completing urb %d\n", | |
562 | __func__, retval, pipe); | |
563 | } | |
564 | ||
565 | break; | |
566 | case IOCTL_VSTUSB_RECV_PIPE: | |
567 | ||
84dcd594 | 568 | if ((usb_data.count == 0) || (usb_data.count > VST_MAXBUFFER)) { |
cbc30118 SW |
569 | mutex_unlock(&vstdev->lock); |
570 | retval = -EINVAL; | |
571 | goto exit; | |
572 | } | |
573 | ||
574 | buffer = kmalloc(usb_data.count, GFP_KERNEL); | |
575 | if (buffer == NULL) { | |
576 | mutex_unlock(&vstdev->lock); | |
577 | retval = -ENOMEM; | |
578 | goto exit; | |
579 | } | |
580 | ||
581 | urb = usb_alloc_urb(0, GFP_KERNEL); | |
582 | if (!urb) { | |
583 | mutex_unlock(&vstdev->lock); | |
584 | retval = -ENOMEM; | |
585 | goto exit; | |
586 | } | |
587 | ||
588 | timeout = usb_data.timeout_ms; | |
589 | ||
590 | pipe = usb_rcvbulkpipe(dev, usb_data.pipe); | |
591 | ||
592 | usb_anchor_urb(urb, &vstdev->submitted); | |
593 | retval = vstusb_fill_and_send_urb(urb, dev, pipe, buffer, | |
594 | usb_data.count, &done); | |
595 | mutex_unlock(&vstdev->lock); | |
596 | if (retval) { | |
597 | usb_unanchor_urb(urb); | |
598 | dev_err(&dev->dev, | |
599 | "%s: error %d filling and sending urb %d\n", | |
600 | __func__, retval, pipe); | |
601 | goto exit; | |
602 | } | |
603 | ||
604 | retval = vstusb_complete_urb(urb, &done, timeout, &cnt); | |
605 | if (retval) { | |
606 | dev_err(&dev->dev, "%s: error %d completing urb %d\n", | |
607 | __func__, retval, pipe); | |
608 | goto exit; | |
609 | } | |
610 | ||
611 | if (copy_to_user(usb_data.buffer, buffer, cnt)) { | |
612 | dev_err(&dev->dev, "%s: can't copy_to_user\n", | |
613 | __func__); | |
614 | retval = -EFAULT; | |
615 | goto exit; | |
616 | } | |
617 | ||
618 | usb_data.count = cnt; | |
619 | if (copy_to_user(data, &usb_data, sizeof(struct vstusb_args))) { | |
620 | dev_err(&dev->dev, "%s: can't copy_to_user\n", | |
621 | __func__); | |
622 | retval = -EFAULT; | |
623 | } else { | |
6c5ab376 | 624 | dev_dbg(&dev->dev, "%s: recv %zd bytes from pipe %d\n", |
cbc30118 SW |
625 | __func__, usb_data.count, usb_data.pipe); |
626 | } | |
627 | ||
628 | break; | |
629 | ||
630 | default: | |
631 | mutex_unlock(&vstdev->lock); | |
632 | dev_warn(&dev->dev, "ioctl_vstusb: invalid ioctl cmd %x\n", | |
633 | cmd); | |
634 | return -EINVAL; | |
635 | break; | |
636 | } | |
637 | exit: | |
638 | usb_free_urb(urb); | |
639 | kfree(buffer); | |
640 | return retval; | |
641 | } | |
642 | ||
643 | static const struct file_operations vstusb_fops = { | |
644 | .owner = THIS_MODULE, | |
645 | .read = vstusb_read, | |
646 | .write = vstusb_write, | |
647 | .unlocked_ioctl = vstusb_ioctl, | |
648 | .compat_ioctl = vstusb_ioctl, | |
649 | .open = vstusb_open, | |
84dcd594 | 650 | .release = vstusb_release, |
cbc30118 SW |
651 | }; |
652 | ||
653 | static struct usb_class_driver usb_vstusb_class = { | |
654 | .name = "usb/vstusb%d", | |
655 | .fops = &vstusb_fops, | |
656 | .minor_base = VSTUSB_MINOR_BASE, | |
657 | }; | |
658 | ||
659 | static int vstusb_probe(struct usb_interface *intf, | |
660 | const struct usb_device_id *id) | |
661 | { | |
662 | struct usb_device *dev = interface_to_usbdev(intf); | |
663 | struct vstusb_device *vstdev; | |
664 | int i; | |
665 | int retval = 0; | |
666 | ||
667 | /* allocate memory for our device state and intialize it */ | |
668 | ||
669 | vstdev = kzalloc(sizeof(*vstdev), GFP_KERNEL); | |
670 | if (vstdev == NULL) | |
671 | return -ENOMEM; | |
672 | ||
84dcd594 SW |
673 | /* must do usb_get_dev() prior to kref_init() since the kref_put() |
674 | * release function will do a usb_put_dev() */ | |
675 | usb_get_dev(dev); | |
676 | kref_init(&vstdev->kref); | |
cbc30118 SW |
677 | mutex_init(&vstdev->lock); |
678 | ||
679 | i = dev->descriptor.bcdDevice; | |
680 | ||
681 | dev_dbg(&intf->dev, "Version %1d%1d.%1d%1d found at address %d\n", | |
682 | (i & 0xF000) >> 12, (i & 0xF00) >> 8, | |
683 | (i & 0xF0) >> 4, (i & 0xF), dev->devnum); | |
684 | ||
685 | vstdev->present = 1; | |
686 | vstdev->isopen = 0; | |
687 | vstdev->usb_dev = dev; | |
688 | init_usb_anchor(&vstdev->submitted); | |
689 | ||
690 | usb_set_intfdata(intf, vstdev); | |
691 | retval = usb_register_dev(intf, &usb_vstusb_class); | |
692 | if (retval) { | |
693 | dev_err(&intf->dev, | |
694 | "%s: Not able to get a minor for this device.\n", | |
695 | __func__); | |
696 | usb_set_intfdata(intf, NULL); | |
84dcd594 | 697 | kref_put(&vstdev->kref, vstusb_delete); |
cbc30118 SW |
698 | return retval; |
699 | } | |
700 | ||
701 | /* let the user know what node this device is now attached to */ | |
702 | dev_info(&intf->dev, | |
703 | "VST USB Device #%d now attached to major %d minor %d\n", | |
704 | (intf->minor - VSTUSB_MINOR_BASE), USB_MAJOR, intf->minor); | |
705 | ||
706 | dev_info(&intf->dev, "%s, %s\n", DRIVER_DESC, DRIVER_VERSION); | |
707 | ||
708 | return retval; | |
709 | } | |
710 | ||
711 | static void vstusb_disconnect(struct usb_interface *intf) | |
712 | { | |
713 | struct vstusb_device *vstdev = usb_get_intfdata(intf); | |
714 | ||
715 | usb_deregister_dev(intf, &usb_vstusb_class); | |
716 | usb_set_intfdata(intf, NULL); | |
717 | ||
718 | if (vstdev) { | |
719 | ||
720 | mutex_lock(&vstdev->lock); | |
721 | vstdev->present = 0; | |
722 | ||
723 | usb_kill_anchored_urbs(&vstdev->submitted); | |
724 | ||
84dcd594 | 725 | mutex_unlock(&vstdev->lock); |
cbc30118 | 726 | |
84dcd594 | 727 | kref_put(&vstdev->kref, vstusb_delete); |
cbc30118 | 728 | } |
84dcd594 | 729 | |
cbc30118 SW |
730 | } |
731 | ||
732 | static int vstusb_suspend(struct usb_interface *intf, pm_message_t message) | |
733 | { | |
734 | struct vstusb_device *vstdev = usb_get_intfdata(intf); | |
735 | int time; | |
736 | if (!vstdev) | |
737 | return 0; | |
738 | ||
739 | mutex_lock(&vstdev->lock); | |
740 | time = usb_wait_anchor_empty_timeout(&vstdev->submitted, 1000); | |
741 | if (!time) | |
742 | usb_kill_anchored_urbs(&vstdev->submitted); | |
743 | mutex_unlock(&vstdev->lock); | |
744 | ||
745 | return 0; | |
746 | } | |
747 | ||
748 | static int vstusb_resume(struct usb_interface *intf) | |
749 | { | |
750 | return 0; | |
751 | } | |
752 | ||
753 | static struct usb_driver vstusb_driver = { | |
754 | .name = "vstusb", | |
755 | .probe = vstusb_probe, | |
756 | .disconnect = vstusb_disconnect, | |
757 | .suspend = vstusb_suspend, | |
758 | .resume = vstusb_resume, | |
759 | .id_table = id_table, | |
760 | }; | |
761 | ||
762 | static int __init vstusb_init(void) | |
763 | { | |
764 | int rc; | |
765 | ||
766 | rc = usb_register(&vstusb_driver); | |
767 | if (rc) | |
768 | printk(KERN_ERR "%s: failed to register (%d)", __func__, rc); | |
769 | ||
770 | return rc; | |
771 | } | |
772 | ||
773 | static void __exit vstusb_exit(void) | |
774 | { | |
775 | usb_deregister(&vstusb_driver); | |
776 | } | |
777 | ||
778 | module_init(vstusb_init); | |
779 | module_exit(vstusb_exit); | |
780 | ||
781 | MODULE_AUTHOR("Dennis O'Brien/Stephen Ware"); | |
782 | MODULE_DESCRIPTION(DRIVER_VERSION); | |
783 | MODULE_LICENSE("GPL"); |