aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Ware <stephen.ware@eqware.net>2008-09-30 14:39:38 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2008-10-17 17:41:01 -0400
commitcbc30118d7a376dab4113f299c0c8f035737a5c3 (patch)
treec81723cea0775df91588079ae31bc2596cc35d89
parent29bac7b7661bbbdbbd32bc1e6cedca22f260da7f (diff)
usb: vstusb.c : new driver for spectrometers used by Vernier Software & Technology, Inc.
This patch adds the vstusb driver to the drivers/usb/misc directory. This driver provides support for Vernier Software & Technology spectrometers, all made by Ocean Optics. The driver provides both IOCTL and read()/write() methods for sending raw data to spectrometers across the bulk channel. Each method allows for a configured timeout. From: Stephen Ware <stephen.ware@eqware.net> Signed-off-by: Dennis O'Brien <dennis.obrien@eqware.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--Documentation/ioctl-number.txt1
-rw-r--r--drivers/usb/misc/Kconfig15
-rw-r--r--drivers/usb/misc/Makefile1
-rw-r--r--drivers/usb/misc/vstusb.c768
-rw-r--r--include/linux/usb/Kbuild1
-rw-r--r--include/linux/usb/vstusb.h71
6 files changed, 857 insertions, 0 deletions
diff --git a/Documentation/ioctl-number.txt b/Documentation/ioctl-number.txt
index f8deb85eef6e..b880ce5dbd33 100644
--- a/Documentation/ioctl-number.txt
+++ b/Documentation/ioctl-number.txt
@@ -92,6 +92,7 @@ Code Seq# Include File Comments
92'J' 00-1F drivers/scsi/gdth_ioctl.h 92'J' 00-1F drivers/scsi/gdth_ioctl.h
93'K' all linux/kd.h 93'K' all linux/kd.h
94'L' 00-1F linux/loop.h 94'L' 00-1F linux/loop.h
95'L' 20-2F driver/usb/misc/vstusb.h
95'L' E0-FF linux/ppdd.h encrypted disk device driver 96'L' E0-FF linux/ppdd.h encrypted disk device driver
96 <http://linux01.gwdg.de/~alatham/ppdd.html> 97 <http://linux01.gwdg.de/~alatham/ppdd.html>
97'M' all linux/soundcard.h 98'M' all linux/soundcard.h
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index 25e1157ab176..e463db5d8188 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -280,3 +280,18 @@ config USB_ISIGHTFW
280 The firmware for this driver must be extracted from the MacOS 280 The firmware for this driver must be extracted from the MacOS
281 driver beforehand. Tools for doing so are available at 281 driver beforehand. Tools for doing so are available at
282 http://bersace03.free.fr 282 http://bersace03.free.fr
283
284config USB_VST
285 tristate "USB VST driver"
286 depends on USB
287 help
288 This driver is intended for Vernier Software Technologies
289 bulk usb devices such as their Ocean-Optics spectrometers or
290 Labquest.
291 It is a bulk channel driver with configurable read and write
292 timeouts.
293
294 To compile this driver as a module, choose M here: the
295 module will be called vstusb.
296
297
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index 39ce4a16b3d4..1334f7bdd7be 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_USB_TEST) += usbtest.o
27obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o 27obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o
28obj-$(CONFIG_USB_USS720) += uss720.o 28obj-$(CONFIG_USB_USS720) += uss720.o
29obj-$(CONFIG_USB_SEVSEG) += usbsevseg.o 29obj-$(CONFIG_USB_SEVSEG) += usbsevseg.o
30obj-$(CONFIG_USB_VST) += vstusb.o
30 31
31obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/ 32obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/
32 33
diff --git a/drivers/usb/misc/vstusb.c b/drivers/usb/misc/vstusb.c
new file mode 100644
index 000000000000..5ad75e4a0323
--- /dev/null
+++ b/drivers/usb/misc/vstusb.c
@@ -0,0 +1,768 @@
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
62static struct usb_device_id id_table[] = {
63 { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB2000)},
64 { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_HR4000)},
65 { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB650)},
66 { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB4000)},
67 { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB325)},
68 { USB_DEVICE(USB_VENDOR_VERNIER, USB_PRODUCT_LABQUEST)},
69 { USB_DEVICE(USB_VENDOR_VERNIER, USB_PRODUCT_LABPRO)},
70 {},
71};
72
73MODULE_DEVICE_TABLE(usb, id_table);
74
75struct vstusb_device {
76 struct mutex lock;
77 struct usb_device *usb_dev;
78 char present;
79 char isopen;
80 struct usb_anchor submitted;
81 int rd_pipe;
82 int rd_timeout_ms;
83 int wr_pipe;
84 int wr_timeout_ms;
85};
86
87static struct usb_driver vstusb_driver;
88
89static int vstusb_open(struct inode *inode, struct file *file)
90{
91 struct vstusb_device *vstdev;
92 struct usb_interface *interface;
93
94 interface = usb_find_interface(&vstusb_driver, iminor(inode));
95
96 if (!interface) {
97 printk(KERN_ERR KBUILD_MODNAME
98 ": %s - error, can't find device for minor %d\n",
99 __func__, iminor(inode));
100 return -ENODEV;
101 }
102
103 vstdev = usb_get_intfdata(interface);
104
105 if (!vstdev)
106 return -ENODEV;
107
108 /* lock this device */
109 mutex_lock(&vstdev->lock);
110
111 /* can only open one time */
112 if ((!vstdev->present) || (vstdev->isopen)) {
113 mutex_unlock(&vstdev->lock);
114 return -EBUSY;
115 }
116
117 vstdev->isopen = 1;
118
119 /* save device in the file's private structure */
120 file->private_data = vstdev;
121
122 dev_dbg(&vstdev->usb_dev->dev, "%s: opened\n", __func__);
123
124 mutex_unlock(&vstdev->lock);
125
126 return 0;
127}
128
129static int vstusb_close(struct inode *inode, struct file *file)
130{
131 struct vstusb_device *vstdev;
132
133 vstdev = file->private_data;
134
135 if (vstdev == NULL)
136 return -ENODEV;
137
138 mutex_lock(&vstdev->lock);
139
140 vstdev->isopen = 0;
141 file->private_data = NULL;
142
143 /* if device is no longer present */
144 if (!vstdev->present) {
145 mutex_unlock(&vstdev->lock);
146 kfree(vstdev);
147 } else
148 mutex_unlock(&vstdev->lock);
149
150 return 0;
151}
152
153static void usb_api_blocking_completion(struct urb *urb)
154{
155 struct completion *completeit = urb->context;
156
157 complete(completeit);
158}
159
160static int vstusb_fill_and_send_urb(struct urb *urb,
161 struct usb_device *usb_dev,
162 unsigned int pipe, void *data,
163 unsigned int len, struct completion *done)
164{
165 struct usb_host_endpoint *ep;
166 struct usb_host_endpoint **hostep;
167 unsigned int pipend;
168
169 int status;
170
171 hostep = usb_pipein(pipe) ? usb_dev->ep_in : usb_dev->ep_out;
172 pipend = usb_pipeendpoint(pipe);
173 ep = hostep[pipend];
174
175 if (!ep || (len == 0))
176 return -EINVAL;
177
178 if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
179 == USB_ENDPOINT_XFER_INT) {
180 pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30);
181 usb_fill_int_urb(urb, usb_dev, pipe, data, len,
182 (usb_complete_t)usb_api_blocking_completion,
183 NULL, ep->desc.bInterval);
184 } else
185 usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
186 (usb_complete_t)usb_api_blocking_completion,
187 NULL);
188
189 init_completion(done);
190 urb->context = done;
191 urb->actual_length = 0;
192 status = usb_submit_urb(urb, GFP_KERNEL);
193
194 return status;
195}
196
197static int vstusb_complete_urb(struct urb *urb, struct completion *done,
198 int timeout, int *actual_length)
199{
200 unsigned long expire;
201 int status;
202
203 expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
204 if (!wait_for_completion_interruptible_timeout(done, expire)) {
205 usb_kill_urb(urb);
206 status = urb->status == -ENOENT ? -ETIMEDOUT : urb->status;
207
208 dev_dbg(&urb->dev->dev,
209 "%s timed out on ep%d%s len=%d/%d, urb status = %d\n",
210 current->comm,
211 usb_pipeendpoint(urb->pipe),
212 usb_pipein(urb->pipe) ? "in" : "out",
213 urb->actual_length,
214 urb->transfer_buffer_length,
215 urb->status);
216
217 } else {
218 if (signal_pending(current)) {
219 /* if really an error */
220 if (urb->status && !((urb->status == -ENOENT) ||
221 (urb->status == -ECONNRESET) ||
222 (urb->status == -ESHUTDOWN))) {
223 status = -EINTR;
224 usb_kill_urb(urb);
225 } else {
226 status = 0;
227 }
228
229 dev_dbg(&urb->dev->dev,
230 "%s: signal pending on ep%d%s len=%d/%d,"
231 "urb status = %d\n",
232 current->comm,
233 usb_pipeendpoint(urb->pipe),
234 usb_pipein(urb->pipe) ? "in" : "out",
235 urb->actual_length,
236 urb->transfer_buffer_length,
237 urb->status);
238
239 } else {
240 status = urb->status;
241 }
242 }
243
244 if (actual_length)
245 *actual_length = urb->actual_length;
246
247 return status;
248}
249
250static ssize_t vstusb_read(struct file *file, char __user *buffer,
251 size_t count, loff_t *ppos)
252{
253 struct vstusb_device *vstdev;
254 int cnt = -1;
255 void *buf;
256 int retval = 0;
257
258 struct urb *urb;
259 struct usb_device *dev;
260 unsigned int pipe;
261 int timeout;
262
263 DECLARE_COMPLETION_ONSTACK(done);
264
265 vstdev = file->private_data;
266
267 if (vstdev == NULL)
268 return -ENODEV;
269
270 /* verify that we actually want to read some data */
271 if (count == 0)
272 return -EINVAL;
273
274 /* lock this object */
275 if (mutex_lock_interruptible(&vstdev->lock))
276 return -ERESTARTSYS;
277
278 /* anyone home */
279 if (!vstdev->present) {
280 mutex_unlock(&vstdev->lock);
281 printk(KERN_ERR KBUILD_MODNAME
282 ": %s: device not present\n", __func__);
283 return -ENODEV;
284 }
285
286 /* pull out the necessary data */
287 dev = vstdev->usb_dev;
288 pipe = usb_rcvbulkpipe(dev, vstdev->rd_pipe);
289 timeout = vstdev->rd_timeout_ms;
290
291 buf = kmalloc(count, GFP_KERNEL);
292 if (buf == NULL) {
293 mutex_unlock(&vstdev->lock);
294 return -ENOMEM;
295 }
296
297 urb = usb_alloc_urb(0, GFP_KERNEL);
298 if (!urb) {
299 kfree(buf);
300 mutex_unlock(&vstdev->lock);
301 return -ENOMEM;
302 }
303
304 usb_anchor_urb(urb, &vstdev->submitted);
305 retval = vstusb_fill_and_send_urb(urb, dev, pipe, buf, count, &done);
306 mutex_unlock(&vstdev->lock);
307 if (retval) {
308 usb_unanchor_urb(urb);
309 dev_err(&dev->dev, "%s: error %d filling and sending urb %d\n",
310 __func__, retval, pipe);
311 goto exit;
312 }
313
314 retval = vstusb_complete_urb(urb, &done, timeout, &cnt);
315 if (retval) {
316 dev_err(&dev->dev, "%s: error %d completing urb %d\n",
317 __func__, retval, pipe);
318 goto exit;
319 }
320
321 if (copy_to_user(buffer, buf, cnt)) {
322 dev_err(&dev->dev, "%s: can't copy_to_user\n", __func__);
323 retval = -EFAULT;
324 } else {
325 retval = cnt;
326 dev_dbg(&dev->dev, "%s: read %d bytes from pipe %d\n",
327 __func__, cnt, pipe);
328 }
329
330exit:
331 usb_free_urb(urb);
332 kfree(buf);
333 return retval;
334}
335
336static ssize_t vstusb_write(struct file *file, const char __user *buffer,
337 size_t count, loff_t *ppos)
338{
339 struct vstusb_device *vstdev;
340 int cnt = -1;
341 void *buf;
342 int retval = 0;
343
344 struct urb *urb;
345 struct usb_device *dev;
346 unsigned int pipe;
347 int timeout;
348
349 DECLARE_COMPLETION_ONSTACK(done);
350
351 vstdev = file->private_data;
352
353 if (vstdev == NULL)
354 return -ENODEV;
355
356 /* verify that we actually have some data to write */
357 if (count == 0)
358 return retval;
359
360 /* lock this object */
361 if (mutex_lock_interruptible(&vstdev->lock))
362 return -ERESTARTSYS;
363
364 /* anyone home */
365 if (!vstdev->present) {
366 mutex_unlock(&vstdev->lock);
367 printk(KERN_ERR KBUILD_MODNAME
368 ": %s: device not present\n", __func__);
369 return -ENODEV;
370 }
371
372 /* pull out the necessary data */
373 dev = vstdev->usb_dev;
374 pipe = usb_sndbulkpipe(dev, vstdev->wr_pipe);
375 timeout = vstdev->wr_timeout_ms;
376
377 buf = kmalloc(count, GFP_KERNEL);
378 if (buf == NULL) {
379 mutex_unlock(&vstdev->lock);
380 return -ENOMEM;
381 }
382
383 urb = usb_alloc_urb(0, GFP_KERNEL);
384 if (!urb) {
385 kfree(buf);
386 mutex_unlock(&vstdev->lock);
387 return -ENOMEM;
388 }
389
390 if (copy_from_user(buf, buffer, count)) {
391 dev_err(&dev->dev, "%s: can't copy_from_user\n", __func__);
392 retval = -EFAULT;
393 goto exit;
394 }
395
396 usb_anchor_urb(urb, &vstdev->submitted);
397 retval = vstusb_fill_and_send_urb(urb, dev, pipe, buf, count, &done);
398 mutex_unlock(&vstdev->lock);
399 if (retval) {
400 usb_unanchor_urb(urb);
401 dev_err(&dev->dev, "%s: error %d filling and sending urb %d\n",
402 __func__, retval, pipe);
403 goto exit;
404 }
405
406 retval = vstusb_complete_urb(urb, &done, timeout, &cnt);
407 if (retval) {
408 dev_err(&dev->dev, "%s: error %d completing urb %d\n",
409 __func__, retval, pipe);
410 goto exit;
411 } else {
412 retval = cnt;
413 dev_dbg(&dev->dev, "%s: sent %d bytes to pipe %d\n",
414 __func__, cnt, pipe);
415 }
416
417exit:
418 usb_free_urb(urb);
419 kfree(buf);
420 return retval;
421}
422
423static long vstusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
424{
425 int retval = 0;
426 int cnt = -1;
427 void __user *data = (void __user *)arg;
428 struct vstusb_args usb_data;
429
430 struct vstusb_device *vstdev;
431 void *buffer = NULL; /* must be initialized. buffer is
432 * referenced on exit but not all
433 * ioctls allocate it */
434
435 struct urb *urb = NULL; /* must be initialized. urb is
436 * referenced on exit but not all
437 * ioctls allocate it */
438 struct usb_device *dev;
439 unsigned int pipe;
440 int timeout;
441
442 DECLARE_COMPLETION_ONSTACK(done);
443
444 vstdev = file->private_data;
445
446 if (_IOC_TYPE(cmd) != VST_IOC_MAGIC) {
447 dev_warn(&vstdev->usb_dev->dev,
448 "%s: ioctl command %x, bad ioctl magic %x, "
449 "expected %x\n", __func__, cmd,
450 _IOC_TYPE(cmd), VST_IOC_MAGIC);
451 return -EINVAL;
452 }
453
454 if (vstdev == NULL)
455 return -ENODEV;
456
457 if (copy_from_user(&usb_data, data, sizeof(struct vstusb_args))) {
458 dev_err(&vstdev->usb_dev->dev, "%s: can't copy_from_user\n",
459 __func__);
460 return -EFAULT;
461 }
462
463 /* lock this object */
464 if (mutex_lock_interruptible(&vstdev->lock)) {
465 retval = -ERESTARTSYS;
466 goto exit;
467 }
468
469 /* anyone home */
470 if (!vstdev->present) {
471 mutex_unlock(&vstdev->lock);
472 dev_err(&vstdev->usb_dev->dev, "%s: device not present\n",
473 __func__);
474 retval = -ENODEV;
475 goto exit;
476 }
477
478 /* pull out the necessary data */
479 dev = vstdev->usb_dev;
480
481 switch (cmd) {
482
483 case IOCTL_VSTUSB_CONFIG_RW:
484
485 vstdev->rd_pipe = usb_data.rd_pipe;
486 vstdev->rd_timeout_ms = usb_data.rd_timeout_ms;
487 vstdev->wr_pipe = usb_data.wr_pipe;
488 vstdev->wr_timeout_ms = usb_data.wr_timeout_ms;
489
490 mutex_unlock(&vstdev->lock);
491
492 dev_dbg(&dev->dev, "%s: setting pipes/timeouts, "
493 "rdpipe = %d, rdtimeout = %d, "
494 "wrpipe = %d, wrtimeout = %d\n", __func__,
495 vstdev->rd_pipe, vstdev->rd_timeout_ms,
496 vstdev->wr_pipe, vstdev->wr_timeout_ms);
497 break;
498
499 case IOCTL_VSTUSB_SEND_PIPE:
500
501 if (usb_data.count == 0) {
502 mutex_unlock(&vstdev->lock);
503 retval = -EINVAL;
504 goto exit;
505 }
506
507 buffer = kmalloc(usb_data.count, GFP_KERNEL);
508 if (buffer == NULL) {
509 mutex_unlock(&vstdev->lock);
510 retval = -ENOMEM;
511 goto exit;
512 }
513
514 urb = usb_alloc_urb(0, GFP_KERNEL);
515 if (!urb) {
516 mutex_unlock(&vstdev->lock);
517 retval = -ENOMEM;
518 goto exit;
519 }
520
521 timeout = usb_data.timeout_ms;
522
523 pipe = usb_sndbulkpipe(dev, usb_data.pipe);
524
525 if (copy_from_user(buffer, usb_data.buffer, usb_data.count)) {
526 dev_err(&dev->dev, "%s: can't copy_from_user\n",
527 __func__);
528 mutex_unlock(&vstdev->lock);
529 retval = -EFAULT;
530 goto exit;
531 }
532
533 usb_anchor_urb(urb, &vstdev->submitted);
534 retval = vstusb_fill_and_send_urb(urb, dev, pipe, buffer,
535 usb_data.count, &done);
536 mutex_unlock(&vstdev->lock);
537 if (retval) {
538 usb_unanchor_urb(urb);
539 dev_err(&dev->dev,
540 "%s: error %d filling and sending urb %d\n",
541 __func__, retval, pipe);
542 goto exit;
543 }
544
545 retval = vstusb_complete_urb(urb, &done, timeout, &cnt);
546 if (retval) {
547 dev_err(&dev->dev, "%s: error %d completing urb %d\n",
548 __func__, retval, pipe);
549 }
550
551 break;
552 case IOCTL_VSTUSB_RECV_PIPE:
553
554 if (usb_data.count == 0) {
555 mutex_unlock(&vstdev->lock);
556 retval = -EINVAL;
557 goto exit;
558 }
559
560 buffer = kmalloc(usb_data.count, GFP_KERNEL);
561 if (buffer == NULL) {
562 mutex_unlock(&vstdev->lock);
563 retval = -ENOMEM;
564 goto exit;
565 }
566
567 urb = usb_alloc_urb(0, GFP_KERNEL);
568 if (!urb) {
569 mutex_unlock(&vstdev->lock);
570 retval = -ENOMEM;
571 goto exit;
572 }
573
574 timeout = usb_data.timeout_ms;
575
576 pipe = usb_rcvbulkpipe(dev, usb_data.pipe);
577
578 usb_anchor_urb(urb, &vstdev->submitted);
579 retval = vstusb_fill_and_send_urb(urb, dev, pipe, buffer,
580 usb_data.count, &done);
581 mutex_unlock(&vstdev->lock);
582 if (retval) {
583 usb_unanchor_urb(urb);
584 dev_err(&dev->dev,
585 "%s: error %d filling and sending urb %d\n",
586 __func__, retval, pipe);
587 goto exit;
588 }
589
590 retval = vstusb_complete_urb(urb, &done, timeout, &cnt);
591 if (retval) {
592 dev_err(&dev->dev, "%s: error %d completing urb %d\n",
593 __func__, retval, pipe);
594 goto exit;
595 }
596
597 if (copy_to_user(usb_data.buffer, buffer, cnt)) {
598 dev_err(&dev->dev, "%s: can't copy_to_user\n",
599 __func__);
600 retval = -EFAULT;
601 goto exit;
602 }
603
604 usb_data.count = cnt;
605 if (copy_to_user(data, &usb_data, sizeof(struct vstusb_args))) {
606 dev_err(&dev->dev, "%s: can't copy_to_user\n",
607 __func__);
608 retval = -EFAULT;
609 } else {
610 dev_dbg(&dev->dev, "%s: recv %d bytes from pipe %d\n",
611 __func__, usb_data.count, usb_data.pipe);
612 }
613
614 break;
615
616 default:
617 mutex_unlock(&vstdev->lock);
618 dev_warn(&dev->dev, "ioctl_vstusb: invalid ioctl cmd %x\n",
619 cmd);
620 return -EINVAL;
621 break;
622 }
623exit:
624 usb_free_urb(urb);
625 kfree(buffer);
626 return retval;
627}
628
629static const struct file_operations vstusb_fops = {
630 .owner = THIS_MODULE,
631 .read = vstusb_read,
632 .write = vstusb_write,
633 .unlocked_ioctl = vstusb_ioctl,
634 .compat_ioctl = vstusb_ioctl,
635 .open = vstusb_open,
636 .release = vstusb_close,
637};
638
639static struct usb_class_driver usb_vstusb_class = {
640 .name = "usb/vstusb%d",
641 .fops = &vstusb_fops,
642 .minor_base = VSTUSB_MINOR_BASE,
643};
644
645static int vstusb_probe(struct usb_interface *intf,
646 const struct usb_device_id *id)
647{
648 struct usb_device *dev = interface_to_usbdev(intf);
649 struct vstusb_device *vstdev;
650 int i;
651 int retval = 0;
652
653 /* allocate memory for our device state and intialize it */
654
655 vstdev = kzalloc(sizeof(*vstdev), GFP_KERNEL);
656 if (vstdev == NULL)
657 return -ENOMEM;
658
659 mutex_init(&vstdev->lock);
660
661 i = dev->descriptor.bcdDevice;
662
663 dev_dbg(&intf->dev, "Version %1d%1d.%1d%1d found at address %d\n",
664 (i & 0xF000) >> 12, (i & 0xF00) >> 8,
665 (i & 0xF0) >> 4, (i & 0xF), dev->devnum);
666
667 vstdev->present = 1;
668 vstdev->isopen = 0;
669 vstdev->usb_dev = dev;
670 init_usb_anchor(&vstdev->submitted);
671
672 usb_set_intfdata(intf, vstdev);
673 retval = usb_register_dev(intf, &usb_vstusb_class);
674 if (retval) {
675 dev_err(&intf->dev,
676 "%s: Not able to get a minor for this device.\n",
677 __func__);
678 usb_set_intfdata(intf, NULL);
679 kfree(vstdev);
680 return retval;
681 }
682
683 /* let the user know what node this device is now attached to */
684 dev_info(&intf->dev,
685 "VST USB Device #%d now attached to major %d minor %d\n",
686 (intf->minor - VSTUSB_MINOR_BASE), USB_MAJOR, intf->minor);
687
688 dev_info(&intf->dev, "%s, %s\n", DRIVER_DESC, DRIVER_VERSION);
689
690 return retval;
691}
692
693static void vstusb_disconnect(struct usb_interface *intf)
694{
695 struct vstusb_device *vstdev = usb_get_intfdata(intf);
696
697 usb_deregister_dev(intf, &usb_vstusb_class);
698 usb_set_intfdata(intf, NULL);
699
700 if (vstdev) {
701
702 mutex_lock(&vstdev->lock);
703 vstdev->present = 0;
704
705 usb_kill_anchored_urbs(&vstdev->submitted);
706
707 /* if the device is not opened, then we clean up right now */
708 if (!vstdev->isopen) {
709 mutex_unlock(&vstdev->lock);
710 kfree(vstdev);
711 } else
712 mutex_unlock(&vstdev->lock);
713
714 }
715}
716
717static int vstusb_suspend(struct usb_interface *intf, pm_message_t message)
718{
719 struct vstusb_device *vstdev = usb_get_intfdata(intf);
720 int time;
721 if (!vstdev)
722 return 0;
723
724 mutex_lock(&vstdev->lock);
725 time = usb_wait_anchor_empty_timeout(&vstdev->submitted, 1000);
726 if (!time)
727 usb_kill_anchored_urbs(&vstdev->submitted);
728 mutex_unlock(&vstdev->lock);
729
730 return 0;
731}
732
733static int vstusb_resume(struct usb_interface *intf)
734{
735 return 0;
736}
737
738static struct usb_driver vstusb_driver = {
739 .name = "vstusb",
740 .probe = vstusb_probe,
741 .disconnect = vstusb_disconnect,
742 .suspend = vstusb_suspend,
743 .resume = vstusb_resume,
744 .id_table = id_table,
745};
746
747static int __init vstusb_init(void)
748{
749 int rc;
750
751 rc = usb_register(&vstusb_driver);
752 if (rc)
753 printk(KERN_ERR "%s: failed to register (%d)", __func__, rc);
754
755 return rc;
756}
757
758static void __exit vstusb_exit(void)
759{
760 usb_deregister(&vstusb_driver);
761}
762
763module_init(vstusb_init);
764module_exit(vstusb_exit);
765
766MODULE_AUTHOR("Dennis O'Brien/Stephen Ware");
767MODULE_DESCRIPTION(DRIVER_VERSION);
768MODULE_LICENSE("GPL");
diff --git a/include/linux/usb/Kbuild b/include/linux/usb/Kbuild
index 29fd73b0bffc..54c446309a2a 100644
--- a/include/linux/usb/Kbuild
+++ b/include/linux/usb/Kbuild
@@ -5,3 +5,4 @@ header-y += gadgetfs.h
5header-y += midi.h 5header-y += midi.h
6header-y += g_printer.h 6header-y += g_printer.h
7header-y += tmc.h 7header-y += tmc.h
8header-y += vstusb.h
diff --git a/include/linux/usb/vstusb.h b/include/linux/usb/vstusb.h
new file mode 100644
index 000000000000..1cfac67191ff
--- /dev/null
+++ b/include/linux/usb/vstusb.h
@@ -0,0 +1,71 @@
1/*****************************************************************************
2 * File: drivers/usb/misc/vstusb.h
3 *
4 * Purpose: Support for the bulk USB Vernier Spectrophotometers
5 *
6 * Author: EQware Engineering, Inc.
7 * Oregon City, OR, USA 97045
8 *
9 * Copyright: 2007, 2008
10 * Vernier Software & Technology
11 * Beaverton, OR, USA 97005
12 *
13 * Web: www.vernier.com
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License version 2 as
17 * published by the Free Software Foundation.
18 *
19 *****************************************************************************/
20/*****************************************************************************
21 *
22 * The vstusb module is a standard usb 'client' driver running on top of the
23 * standard usb host controller stack.
24 *
25 * In general, vstusb supports standard bulk usb pipes. It supports multiple
26 * devices and multiple pipes per device.
27 *
28 * The vstusb driver supports two interfaces:
29 * 1 - ioctl SEND_PIPE/RECV_PIPE - a general bulk write/read msg
30 * interface to any pipe with timeout support;
31 * 2 - standard read/write with ioctl config - offers standard read/write
32 * interface with ioctl configured pipes and timeouts.
33 *
34 * Both interfaces can be signal from other process and will abort its i/o
35 * operation.
36 *
37 * A timeout of 0 means NO timeout. The user can still terminate the read via
38 * signal.
39 *
40 * If using multiple threads with this driver, the user should ensure that
41 * any reads, writes, or ioctls are complete before closing the device.
42 * Changing read/write timeouts or pipes takes effect on next read/write.
43 *
44 *****************************************************************************/
45
46struct vstusb_args {
47 union {
48 /* this struct is used for IOCTL_VSTUSB_SEND_PIPE, *
49 * IOCTL_VSTUSB_RECV_PIPE, and read()/write() fops */
50 struct {
51 void __user *buffer;
52 size_t count;
53 unsigned int timeout_ms;
54 int pipe;
55 };
56
57 /* this one is used for IOCTL_VSTUSB_CONFIG_RW */
58 struct {
59 int rd_pipe;
60 int rd_timeout_ms;
61 int wr_pipe;
62 int wr_timeout_ms;
63 };
64 };
65};
66
67#define VST_IOC_MAGIC 'L'
68#define VST_IOC_FIRST 0x20
69#define IOCTL_VSTUSB_SEND_PIPE _IO(VST_IOC_MAGIC, VST_IOC_FIRST)
70#define IOCTL_VSTUSB_RECV_PIPE _IO(VST_IOC_MAGIC, VST_IOC_FIRST + 1)
71#define IOCTL_VSTUSB_CONFIG_RW _IO(VST_IOC_MAGIC, VST_IOC_FIRST + 2)