Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git...
[deliverable/linux.git] / drivers / staging / comedi / drivers / vmk80xx.c
1 /*
2 comedi/drivers/vmk80xx.c
3 Velleman USB Board Low-Level Driver
4
5 Copyright (C) 2009 Manuel Gebele <forensixs@gmx.de>, Germany
6
7 COMEDI - Linux Control and Measurement Device Interface
8 Copyright (C) 2000 David A. Schleef <ds@schleef.org>
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
24 */
25 /*
26 Driver: vmk80xx
27 Description: Velleman USB Board Low-Level Driver
28 Devices: K8055/K8061 aka VM110/VM140
29 Author: Manuel Gebele <forensixs@gmx.de>
30 Updated: Sun, 10 May 2009 11:14:59 +0200
31 Status: works
32
33 Supports:
34 - analog input
35 - analog output
36 - digital input
37 - digital output
38 - counter
39 - pwm
40 */
41 /*
42 Changelog:
43
44 0.8.81 -3- code completely rewritten (adjust driver logic)
45 0.8.81 -2- full support for K8061
46 0.8.81 -1- fix some mistaken among others the number of
47 supported boards and I/O handling
48
49 0.7.76 -4- renamed to vmk80xx
50 0.7.76 -3- detect K8061 (only theoretically supported)
51 0.7.76 -2- code completely rewritten (adjust driver logic)
52 0.7.76 -1- support for digital and counter subdevice
53 */
54
55 #include <linux/kernel.h>
56 #include <linux/module.h>
57 #include <linux/mutex.h>
58 #include <linux/errno.h>
59 #include <linux/input.h>
60 #include <linux/slab.h>
61 #include <linux/poll.h>
62 #include <linux/usb.h>
63 #include <linux/uaccess.h>
64
65 #include "../comedidev.h"
66
67 enum {
68 DEVICE_VMK8055,
69 DEVICE_VMK8061
70 };
71
72 #define VMK8055_DI_REG 0x00
73 #define VMK8055_DO_REG 0x01
74 #define VMK8055_AO1_REG 0x02
75 #define VMK8055_AO2_REG 0x03
76 #define VMK8055_AI1_REG 0x02
77 #define VMK8055_AI2_REG 0x03
78 #define VMK8055_CNT1_REG 0x04
79 #define VMK8055_CNT2_REG 0x06
80
81 #define VMK8061_CH_REG 0x01
82 #define VMK8061_DI_REG 0x01
83 #define VMK8061_DO_REG 0x01
84 #define VMK8061_PWM_REG1 0x01
85 #define VMK8061_PWM_REG2 0x02
86 #define VMK8061_CNT_REG 0x02
87 #define VMK8061_AO_REG 0x02
88 #define VMK8061_AI_REG1 0x02
89 #define VMK8061_AI_REG2 0x03
90
91 #define VMK8055_CMD_RST 0x00
92 #define VMK8055_CMD_DEB1_TIME 0x01
93 #define VMK8055_CMD_DEB2_TIME 0x02
94 #define VMK8055_CMD_RST_CNT1 0x03
95 #define VMK8055_CMD_RST_CNT2 0x04
96 #define VMK8055_CMD_WRT_AD 0x05
97
98 #define VMK8061_CMD_RD_AI 0x00
99 #define VMK8061_CMR_RD_ALL_AI 0x01 /* !non-active! */
100 #define VMK8061_CMD_SET_AO 0x02
101 #define VMK8061_CMD_SET_ALL_AO 0x03 /* !non-active! */
102 #define VMK8061_CMD_OUT_PWM 0x04
103 #define VMK8061_CMD_RD_DI 0x05
104 #define VMK8061_CMD_DO 0x06 /* !non-active! */
105 #define VMK8061_CMD_CLR_DO 0x07
106 #define VMK8061_CMD_SET_DO 0x08
107 #define VMK8061_CMD_RD_CNT 0x09 /* TODO: completely pointless? */
108 #define VMK8061_CMD_RST_CNT 0x0a /* TODO: completely pointless? */
109 #define VMK8061_CMD_RD_VERSION 0x0b /* internal usage */
110 #define VMK8061_CMD_RD_JMP_STAT 0x0c /* TODO: not implemented yet */
111 #define VMK8061_CMD_RD_PWR_STAT 0x0d /* internal usage */
112 #define VMK8061_CMD_RD_DO 0x0e
113 #define VMK8061_CMD_RD_AO 0x0f
114 #define VMK8061_CMD_RD_PWM 0x10
115
116 #define VMK80XX_MAX_BOARDS COMEDI_NUM_BOARD_MINORS
117
118 #define TRANS_OUT_BUSY 1
119 #define TRANS_IN_BUSY 2
120 #define TRANS_IN_RUNNING 3
121
122 #define IC3_VERSION (1 << 0)
123 #define IC6_VERSION (1 << 1)
124
125 #define URB_RCV_FLAG (1 << 0)
126 #define URB_SND_FLAG (1 << 1)
127
128 #ifdef CONFIG_COMEDI_DEBUG
129 static int dbgcm = 1;
130 #else
131 static int dbgcm;
132 #endif
133
134 #define dbgcm(fmt, arg...) \
135 do { \
136 if (dbgcm) \
137 printk(KERN_DEBUG fmt, ##arg); \
138 } while (0)
139
140 enum vmk80xx_model {
141 VMK8055_MODEL,
142 VMK8061_MODEL
143 };
144
145 struct firmware_version {
146 unsigned char ic3_vers[32]; /* USB-Controller */
147 unsigned char ic6_vers[32]; /* CPU */
148 };
149
150 static const struct comedi_lrange vmk8055_range = {
151 1, {UNI_RANGE(5)}
152 };
153
154 static const struct comedi_lrange vmk8061_range = {
155 2, {UNI_RANGE(5), UNI_RANGE(10)}
156 };
157
158 struct vmk80xx_board {
159 const char *name;
160 enum vmk80xx_model model;
161 const struct comedi_lrange *range;
162 __u8 ai_chans;
163 __le16 ai_bits;
164 __u8 ao_chans;
165 __le16 ao_bits;
166 __u8 di_chans;
167 __le16 di_bits;
168 __u8 do_chans;
169 __le16 do_bits;
170 __u8 cnt_chans;
171 __le16 cnt_bits;
172 __u8 pwm_chans;
173 __le16 pwm_bits;
174 };
175
176 enum {
177 VMK80XX_SUBD_AI,
178 VMK80XX_SUBD_AO,
179 VMK80XX_SUBD_DI,
180 VMK80XX_SUBD_DO,
181 VMK80XX_SUBD_CNT,
182 VMK80XX_SUBD_PWM,
183 };
184
185 struct vmk80xx_usb {
186 struct usb_device *udev;
187 struct usb_interface *intf;
188 struct usb_endpoint_descriptor *ep_rx;
189 struct usb_endpoint_descriptor *ep_tx;
190 struct usb_anchor rx_anchor;
191 struct usb_anchor tx_anchor;
192 struct vmk80xx_board board;
193 struct firmware_version fw;
194 struct semaphore limit_sem;
195 wait_queue_head_t read_wait;
196 wait_queue_head_t write_wait;
197 unsigned char *usb_rx_buf;
198 unsigned char *usb_tx_buf;
199 unsigned long flags;
200 int probed;
201 int attached;
202 int count;
203 };
204
205 static struct vmk80xx_usb vmb[VMK80XX_MAX_BOARDS];
206
207 static DEFINE_MUTEX(glb_mutex);
208
209 static void vmk80xx_tx_callback(struct urb *urb)
210 {
211 struct vmk80xx_usb *dev = urb->context;
212 int stat = urb->status;
213
214 if (stat && !(stat == -ENOENT
215 || stat == -ECONNRESET || stat == -ESHUTDOWN))
216 dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n",
217 __func__, stat);
218
219 if (!test_bit(TRANS_OUT_BUSY, &dev->flags))
220 return;
221
222 clear_bit(TRANS_OUT_BUSY, &dev->flags);
223
224 wake_up_interruptible(&dev->write_wait);
225 }
226
227 static void vmk80xx_rx_callback(struct urb *urb)
228 {
229 struct vmk80xx_usb *dev = urb->context;
230 int stat = urb->status;
231
232 switch (stat) {
233 case 0:
234 break;
235 case -ENOENT:
236 case -ECONNRESET:
237 case -ESHUTDOWN:
238 break;
239 default:
240 dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n",
241 __func__, stat);
242 goto resubmit;
243 }
244
245 goto exit;
246 resubmit:
247 if (test_bit(TRANS_IN_RUNNING, &dev->flags) && dev->intf) {
248 usb_anchor_urb(urb, &dev->rx_anchor);
249
250 if (!usb_submit_urb(urb, GFP_KERNEL))
251 goto exit;
252
253 dev_err(&urb->dev->dev,
254 "comedi#: vmk80xx: %s - submit urb failed\n",
255 __func__);
256
257 usb_unanchor_urb(urb);
258 }
259 exit:
260 clear_bit(TRANS_IN_BUSY, &dev->flags);
261
262 wake_up_interruptible(&dev->read_wait);
263 }
264
265 static int vmk80xx_check_data_link(struct vmk80xx_usb *dev)
266 {
267 unsigned int tx_pipe;
268 unsigned int rx_pipe;
269 unsigned char tx[1];
270 unsigned char rx[2];
271
272 tx_pipe = usb_sndbulkpipe(dev->udev, 0x01);
273 rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81);
274
275 tx[0] = VMK8061_CMD_RD_PWR_STAT;
276
277 /*
278 * Check that IC6 (PIC16F871) is powered and
279 * running and the data link between IC3 and
280 * IC6 is working properly
281 */
282 usb_bulk_msg(dev->udev, tx_pipe, tx, 1, NULL, dev->ep_tx->bInterval);
283 usb_bulk_msg(dev->udev, rx_pipe, rx, 2, NULL, HZ * 10);
284
285 return (int)rx[1];
286 }
287
288 static void vmk80xx_read_eeprom(struct vmk80xx_usb *dev, int flag)
289 {
290 unsigned int tx_pipe;
291 unsigned int rx_pipe;
292 unsigned char tx[1];
293 unsigned char rx[64];
294 int cnt;
295
296 tx_pipe = usb_sndbulkpipe(dev->udev, 0x01);
297 rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81);
298
299 tx[0] = VMK8061_CMD_RD_VERSION;
300
301 /*
302 * Read the firmware version info of IC3 and
303 * IC6 from the internal EEPROM of the IC
304 */
305 usb_bulk_msg(dev->udev, tx_pipe, tx, 1, NULL, dev->ep_tx->bInterval);
306 usb_bulk_msg(dev->udev, rx_pipe, rx, 64, &cnt, HZ * 10);
307
308 rx[cnt] = '\0';
309
310 if (flag & IC3_VERSION)
311 strncpy(dev->fw.ic3_vers, rx + 1, 24);
312 else /* IC6_VERSION */
313 strncpy(dev->fw.ic6_vers, rx + 25, 24);
314 }
315
316 static int vmk80xx_reset_device(struct vmk80xx_usb *dev)
317 {
318 struct urb *urb;
319 unsigned int tx_pipe;
320 int ival;
321 size_t size;
322
323 urb = usb_alloc_urb(0, GFP_KERNEL);
324 if (!urb)
325 return -ENOMEM;
326
327 tx_pipe = usb_sndintpipe(dev->udev, 0x01);
328
329 ival = dev->ep_tx->bInterval;
330 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
331
332 dev->usb_tx_buf[0] = VMK8055_CMD_RST;
333 dev->usb_tx_buf[1] = 0x00;
334 dev->usb_tx_buf[2] = 0x00;
335 dev->usb_tx_buf[3] = 0x00;
336 dev->usb_tx_buf[4] = 0x00;
337 dev->usb_tx_buf[5] = 0x00;
338 dev->usb_tx_buf[6] = 0x00;
339 dev->usb_tx_buf[7] = 0x00;
340
341 usb_fill_int_urb(urb, dev->udev, tx_pipe, dev->usb_tx_buf,
342 size, vmk80xx_tx_callback, dev, ival);
343
344 usb_anchor_urb(urb, &dev->tx_anchor);
345
346 return usb_submit_urb(urb, GFP_KERNEL);
347 }
348
349 static void vmk80xx_build_int_urb(struct urb *urb, int flag)
350 {
351 struct vmk80xx_usb *dev = urb->context;
352 __u8 rx_addr;
353 __u8 tx_addr;
354 unsigned int pipe;
355 unsigned char *buf;
356 size_t size;
357 void (*callback) (struct urb *);
358 int ival;
359
360 if (flag & URB_RCV_FLAG) {
361 rx_addr = dev->ep_rx->bEndpointAddress;
362 pipe = usb_rcvintpipe(dev->udev, rx_addr);
363 buf = dev->usb_rx_buf;
364 size = le16_to_cpu(dev->ep_rx->wMaxPacketSize);
365 callback = vmk80xx_rx_callback;
366 ival = dev->ep_rx->bInterval;
367 } else { /* URB_SND_FLAG */
368 tx_addr = dev->ep_tx->bEndpointAddress;
369 pipe = usb_sndintpipe(dev->udev, tx_addr);
370 buf = dev->usb_tx_buf;
371 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
372 callback = vmk80xx_tx_callback;
373 ival = dev->ep_tx->bInterval;
374 }
375
376 usb_fill_int_urb(urb, dev->udev, pipe, buf, size, callback, dev, ival);
377 }
378
379 static void vmk80xx_do_bulk_msg(struct vmk80xx_usb *dev)
380 {
381 __u8 tx_addr;
382 __u8 rx_addr;
383 unsigned int tx_pipe;
384 unsigned int rx_pipe;
385 size_t size;
386
387 set_bit(TRANS_IN_BUSY, &dev->flags);
388 set_bit(TRANS_OUT_BUSY, &dev->flags);
389
390 tx_addr = dev->ep_tx->bEndpointAddress;
391 rx_addr = dev->ep_rx->bEndpointAddress;
392 tx_pipe = usb_sndbulkpipe(dev->udev, tx_addr);
393 rx_pipe = usb_rcvbulkpipe(dev->udev, rx_addr);
394
395 /*
396 * The max packet size attributes of the K8061
397 * input/output endpoints are identical
398 */
399 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
400
401 usb_bulk_msg(dev->udev, tx_pipe, dev->usb_tx_buf,
402 size, NULL, dev->ep_tx->bInterval);
403 usb_bulk_msg(dev->udev, rx_pipe, dev->usb_rx_buf, size, NULL, HZ * 10);
404
405 clear_bit(TRANS_OUT_BUSY, &dev->flags);
406 clear_bit(TRANS_IN_BUSY, &dev->flags);
407 }
408
409 static int vmk80xx_read_packet(struct vmk80xx_usb *dev)
410 {
411 struct urb *urb;
412 int retval;
413
414 if (!dev->intf)
415 return -ENODEV;
416
417 /* Only useful for interrupt transfers */
418 if (test_bit(TRANS_IN_BUSY, &dev->flags))
419 if (wait_event_interruptible(dev->read_wait,
420 !test_bit(TRANS_IN_BUSY,
421 &dev->flags)))
422 return -ERESTART;
423
424 if (dev->board.model == VMK8061_MODEL) {
425 vmk80xx_do_bulk_msg(dev);
426
427 return 0;
428 }
429
430 urb = usb_alloc_urb(0, GFP_KERNEL);
431 if (!urb)
432 return -ENOMEM;
433
434 urb->context = dev;
435 vmk80xx_build_int_urb(urb, URB_RCV_FLAG);
436
437 set_bit(TRANS_IN_RUNNING, &dev->flags);
438 set_bit(TRANS_IN_BUSY, &dev->flags);
439
440 usb_anchor_urb(urb, &dev->rx_anchor);
441
442 retval = usb_submit_urb(urb, GFP_KERNEL);
443 if (!retval)
444 goto exit;
445
446 clear_bit(TRANS_IN_RUNNING, &dev->flags);
447 usb_unanchor_urb(urb);
448
449 exit:
450 usb_free_urb(urb);
451
452 return retval;
453 }
454
455 static int vmk80xx_write_packet(struct vmk80xx_usb *dev, int cmd)
456 {
457 struct urb *urb;
458 int retval;
459
460 if (!dev->intf)
461 return -ENODEV;
462
463 if (test_bit(TRANS_OUT_BUSY, &dev->flags))
464 if (wait_event_interruptible(dev->write_wait,
465 !test_bit(TRANS_OUT_BUSY,
466 &dev->flags)))
467 return -ERESTART;
468
469 if (dev->board.model == VMK8061_MODEL) {
470 dev->usb_tx_buf[0] = cmd;
471 vmk80xx_do_bulk_msg(dev);
472
473 return 0;
474 }
475
476 urb = usb_alloc_urb(0, GFP_KERNEL);
477 if (!urb)
478 return -ENOMEM;
479
480 urb->context = dev;
481 vmk80xx_build_int_urb(urb, URB_SND_FLAG);
482
483 set_bit(TRANS_OUT_BUSY, &dev->flags);
484
485 usb_anchor_urb(urb, &dev->tx_anchor);
486
487 dev->usb_tx_buf[0] = cmd;
488
489 retval = usb_submit_urb(urb, GFP_KERNEL);
490 if (!retval)
491 goto exit;
492
493 clear_bit(TRANS_OUT_BUSY, &dev->flags);
494 usb_unanchor_urb(urb);
495
496 exit:
497 usb_free_urb(urb);
498
499 return retval;
500 }
501
502 #define DIR_IN 1
503 #define DIR_OUT 2
504
505 static int rudimentary_check(struct vmk80xx_usb *dev, int dir)
506 {
507 if (!dev)
508 return -EFAULT;
509 if (!dev->probed)
510 return -ENODEV;
511 if (!dev->attached)
512 return -ENODEV;
513 if (dir & DIR_IN) {
514 if (test_bit(TRANS_IN_BUSY, &dev->flags))
515 return -EBUSY;
516 }
517 if (dir & DIR_OUT) {
518 if (test_bit(TRANS_OUT_BUSY, &dev->flags))
519 return -EBUSY;
520 }
521
522 return 0;
523 }
524
525 static int vmk80xx_ai_rinsn(struct comedi_device *cdev,
526 struct comedi_subdevice *s,
527 struct comedi_insn *insn, unsigned int *data)
528 {
529 struct vmk80xx_usb *dev = cdev->private;
530 int chan;
531 int reg[2];
532 int n;
533
534 n = rudimentary_check(dev, DIR_IN);
535 if (n)
536 return n;
537
538 down(&dev->limit_sem);
539 chan = CR_CHAN(insn->chanspec);
540
541 switch (dev->board.model) {
542 case VMK8055_MODEL:
543 if (!chan)
544 reg[0] = VMK8055_AI1_REG;
545 else
546 reg[0] = VMK8055_AI2_REG;
547 break;
548 case VMK8061_MODEL:
549 reg[0] = VMK8061_AI_REG1;
550 reg[1] = VMK8061_AI_REG2;
551 dev->usb_tx_buf[0] = VMK8061_CMD_RD_AI;
552 dev->usb_tx_buf[VMK8061_CH_REG] = chan;
553 break;
554 }
555
556 for (n = 0; n < insn->n; n++) {
557 if (vmk80xx_read_packet(dev))
558 break;
559
560 if (dev->board.model == VMK8055_MODEL) {
561 data[n] = dev->usb_rx_buf[reg[0]];
562 continue;
563 }
564
565 /* VMK8061_MODEL */
566 data[n] = dev->usb_rx_buf[reg[0]] + 256 *
567 dev->usb_rx_buf[reg[1]];
568 }
569
570 up(&dev->limit_sem);
571
572 return n;
573 }
574
575 static int vmk80xx_ao_winsn(struct comedi_device *cdev,
576 struct comedi_subdevice *s,
577 struct comedi_insn *insn, unsigned int *data)
578 {
579 struct vmk80xx_usb *dev = cdev->private;
580 int chan;
581 int cmd;
582 int reg;
583 int n;
584
585 n = rudimentary_check(dev, DIR_OUT);
586 if (n)
587 return n;
588
589 down(&dev->limit_sem);
590 chan = CR_CHAN(insn->chanspec);
591
592 switch (dev->board.model) {
593 case VMK8055_MODEL:
594 cmd = VMK8055_CMD_WRT_AD;
595 if (!chan)
596 reg = VMK8055_AO1_REG;
597 else
598 reg = VMK8055_AO2_REG;
599 break;
600 default: /* NOTE: avoid compiler warnings */
601 cmd = VMK8061_CMD_SET_AO;
602 reg = VMK8061_AO_REG;
603 dev->usb_tx_buf[VMK8061_CH_REG] = chan;
604 break;
605 }
606
607 for (n = 0; n < insn->n; n++) {
608 dev->usb_tx_buf[reg] = data[n];
609
610 if (vmk80xx_write_packet(dev, cmd))
611 break;
612 }
613
614 up(&dev->limit_sem);
615
616 return n;
617 }
618
619 static int vmk80xx_ao_rinsn(struct comedi_device *cdev,
620 struct comedi_subdevice *s,
621 struct comedi_insn *insn, unsigned int *data)
622 {
623 struct vmk80xx_usb *dev = cdev->private;
624 int chan;
625 int reg;
626 int n;
627
628 n = rudimentary_check(dev, DIR_IN);
629 if (n)
630 return n;
631
632 down(&dev->limit_sem);
633 chan = CR_CHAN(insn->chanspec);
634
635 reg = VMK8061_AO_REG - 1;
636
637 dev->usb_tx_buf[0] = VMK8061_CMD_RD_AO;
638
639 for (n = 0; n < insn->n; n++) {
640 if (vmk80xx_read_packet(dev))
641 break;
642
643 data[n] = dev->usb_rx_buf[reg + chan];
644 }
645
646 up(&dev->limit_sem);
647
648 return n;
649 }
650
651 static int vmk80xx_di_bits(struct comedi_device *cdev,
652 struct comedi_subdevice *s,
653 struct comedi_insn *insn, unsigned int *data)
654 {
655 struct vmk80xx_usb *dev = cdev->private;
656 unsigned char *rx_buf;
657 int reg;
658 int retval;
659
660 retval = rudimentary_check(dev, DIR_IN);
661 if (retval)
662 return retval;
663
664 down(&dev->limit_sem);
665
666 rx_buf = dev->usb_rx_buf;
667
668 if (dev->board.model == VMK8061_MODEL) {
669 reg = VMK8061_DI_REG;
670 dev->usb_tx_buf[0] = VMK8061_CMD_RD_DI;
671 } else {
672 reg = VMK8055_DI_REG;
673 }
674
675 retval = vmk80xx_read_packet(dev);
676
677 if (!retval) {
678 if (dev->board.model == VMK8055_MODEL)
679 data[1] = (((rx_buf[reg] >> 4) & 0x03) |
680 ((rx_buf[reg] << 2) & 0x04) |
681 ((rx_buf[reg] >> 3) & 0x18));
682 else
683 data[1] = rx_buf[reg];
684
685 retval = 2;
686 }
687
688 up(&dev->limit_sem);
689
690 return retval;
691 }
692
693 static int vmk80xx_di_rinsn(struct comedi_device *cdev,
694 struct comedi_subdevice *s,
695 struct comedi_insn *insn, unsigned int *data)
696 {
697 struct vmk80xx_usb *dev = cdev->private;
698 int chan;
699 unsigned char *rx_buf;
700 int reg;
701 int inp;
702 int n;
703
704 n = rudimentary_check(dev, DIR_IN);
705 if (n)
706 return n;
707
708 down(&dev->limit_sem);
709 chan = CR_CHAN(insn->chanspec);
710
711 rx_buf = dev->usb_rx_buf;
712
713 if (dev->board.model == VMK8061_MODEL) {
714 reg = VMK8061_DI_REG;
715 dev->usb_tx_buf[0] = VMK8061_CMD_RD_DI;
716 } else {
717 reg = VMK8055_DI_REG;
718 }
719 for (n = 0; n < insn->n; n++) {
720 if (vmk80xx_read_packet(dev))
721 break;
722
723 if (dev->board.model == VMK8055_MODEL)
724 inp = (((rx_buf[reg] >> 4) & 0x03) |
725 ((rx_buf[reg] << 2) & 0x04) |
726 ((rx_buf[reg] >> 3) & 0x18));
727 else
728 inp = rx_buf[reg];
729
730 data[n] = (inp >> chan) & 1;
731 }
732
733 up(&dev->limit_sem);
734
735 return n;
736 }
737
738 static int vmk80xx_do_winsn(struct comedi_device *cdev,
739 struct comedi_subdevice *s,
740 struct comedi_insn *insn, unsigned int *data)
741 {
742 struct vmk80xx_usb *dev = cdev->private;
743 int chan;
744 unsigned char *tx_buf;
745 int reg;
746 int cmd;
747 int n;
748
749 n = rudimentary_check(dev, DIR_OUT);
750 if (n)
751 return n;
752
753 down(&dev->limit_sem);
754 chan = CR_CHAN(insn->chanspec);
755
756 tx_buf = dev->usb_tx_buf;
757
758 for (n = 0; n < insn->n; n++) {
759 if (dev->board.model == VMK8055_MODEL) {
760 reg = VMK8055_DO_REG;
761 cmd = VMK8055_CMD_WRT_AD;
762 if (data[n] == 1)
763 tx_buf[reg] |= (1 << chan);
764 else
765 tx_buf[reg] ^= (1 << chan);
766 } else { /* VMK8061_MODEL */
767 reg = VMK8061_DO_REG;
768 if (data[n] == 1) {
769 cmd = VMK8061_CMD_SET_DO;
770 tx_buf[reg] = 1 << chan;
771 } else {
772 cmd = VMK8061_CMD_CLR_DO;
773 tx_buf[reg] = 0xff - (1 << chan);
774 }
775 }
776
777 if (vmk80xx_write_packet(dev, cmd))
778 break;
779 }
780
781 up(&dev->limit_sem);
782
783 return n;
784 }
785
786 static int vmk80xx_do_rinsn(struct comedi_device *cdev,
787 struct comedi_subdevice *s,
788 struct comedi_insn *insn, unsigned int *data)
789 {
790 struct vmk80xx_usb *dev = cdev->private;
791 int chan;
792 int reg;
793 int n;
794
795 n = rudimentary_check(dev, DIR_IN);
796 if (n)
797 return n;
798
799 down(&dev->limit_sem);
800 chan = CR_CHAN(insn->chanspec);
801
802 reg = VMK8061_DO_REG;
803
804 dev->usb_tx_buf[0] = VMK8061_CMD_RD_DO;
805
806 for (n = 0; n < insn->n; n++) {
807 if (vmk80xx_read_packet(dev))
808 break;
809
810 data[n] = (dev->usb_rx_buf[reg] >> chan) & 1;
811 }
812
813 up(&dev->limit_sem);
814
815 return n;
816 }
817
818 static int vmk80xx_do_bits(struct comedi_device *cdev,
819 struct comedi_subdevice *s,
820 struct comedi_insn *insn, unsigned int *data)
821 {
822 struct vmk80xx_usb *dev = cdev->private;
823 unsigned char *rx_buf, *tx_buf;
824 int dir, reg, cmd;
825 int retval;
826
827 dir = 0;
828
829 if (data[0])
830 dir |= DIR_OUT;
831
832 if (dev->board.model == VMK8061_MODEL)
833 dir |= DIR_IN;
834
835 retval = rudimentary_check(dev, dir);
836 if (retval)
837 return retval;
838
839 down(&dev->limit_sem);
840
841 rx_buf = dev->usb_rx_buf;
842 tx_buf = dev->usb_tx_buf;
843
844 if (data[0]) {
845 if (dev->board.model == VMK8055_MODEL) {
846 reg = VMK8055_DO_REG;
847 cmd = VMK8055_CMD_WRT_AD;
848 } else { /* VMK8061_MODEL */
849 reg = VMK8061_DO_REG;
850 cmd = VMK8061_CMD_DO;
851 }
852
853 tx_buf[reg] &= ~data[0];
854 tx_buf[reg] |= (data[0] & data[1]);
855
856 retval = vmk80xx_write_packet(dev, cmd);
857
858 if (retval)
859 goto out;
860 }
861
862 if (dev->board.model == VMK8061_MODEL) {
863 reg = VMK8061_DO_REG;
864 tx_buf[0] = VMK8061_CMD_RD_DO;
865
866 retval = vmk80xx_read_packet(dev);
867
868 if (!retval) {
869 data[1] = rx_buf[reg];
870 retval = 2;
871 }
872 } else {
873 data[1] = tx_buf[reg];
874 retval = 2;
875 }
876
877 out:
878 up(&dev->limit_sem);
879
880 return retval;
881 }
882
883 static int vmk80xx_cnt_rinsn(struct comedi_device *cdev,
884 struct comedi_subdevice *s,
885 struct comedi_insn *insn, unsigned int *data)
886 {
887 struct vmk80xx_usb *dev = cdev->private;
888 int chan;
889 int reg[2];
890 int n;
891
892 n = rudimentary_check(dev, DIR_IN);
893 if (n)
894 return n;
895
896 down(&dev->limit_sem);
897 chan = CR_CHAN(insn->chanspec);
898
899 switch (dev->board.model) {
900 case VMK8055_MODEL:
901 if (!chan)
902 reg[0] = VMK8055_CNT1_REG;
903 else
904 reg[0] = VMK8055_CNT2_REG;
905 break;
906 case VMK8061_MODEL:
907 reg[0] = VMK8061_CNT_REG;
908 reg[1] = VMK8061_CNT_REG;
909 dev->usb_tx_buf[0] = VMK8061_CMD_RD_CNT;
910 break;
911 }
912
913 for (n = 0; n < insn->n; n++) {
914 if (vmk80xx_read_packet(dev))
915 break;
916
917 if (dev->board.model == VMK8055_MODEL)
918 data[n] = dev->usb_rx_buf[reg[0]];
919 else /* VMK8061_MODEL */
920 data[n] = dev->usb_rx_buf[reg[0] * (chan + 1) + 1]
921 + 256 * dev->usb_rx_buf[reg[1] * 2 + 2];
922 }
923
924 up(&dev->limit_sem);
925
926 return n;
927 }
928
929 static int vmk80xx_cnt_cinsn(struct comedi_device *cdev,
930 struct comedi_subdevice *s,
931 struct comedi_insn *insn, unsigned int *data)
932 {
933 struct vmk80xx_usb *dev = cdev->private;
934 unsigned int insn_cmd;
935 int chan;
936 int cmd;
937 int reg;
938 int n;
939
940 n = rudimentary_check(dev, DIR_OUT);
941 if (n)
942 return n;
943
944 insn_cmd = data[0];
945 if (insn_cmd != INSN_CONFIG_RESET && insn_cmd != GPCT_RESET)
946 return -EINVAL;
947
948 down(&dev->limit_sem);
949
950 chan = CR_CHAN(insn->chanspec);
951
952 if (dev->board.model == VMK8055_MODEL) {
953 if (!chan) {
954 cmd = VMK8055_CMD_RST_CNT1;
955 reg = VMK8055_CNT1_REG;
956 } else {
957 cmd = VMK8055_CMD_RST_CNT2;
958 reg = VMK8055_CNT2_REG;
959 }
960
961 dev->usb_tx_buf[reg] = 0x00;
962 } else {
963 cmd = VMK8061_CMD_RST_CNT;
964 }
965
966 for (n = 0; n < insn->n; n++)
967 if (vmk80xx_write_packet(dev, cmd))
968 break;
969
970 up(&dev->limit_sem);
971
972 return n;
973 }
974
975 static int vmk80xx_cnt_winsn(struct comedi_device *cdev,
976 struct comedi_subdevice *s,
977 struct comedi_insn *insn, unsigned int *data)
978 {
979 struct vmk80xx_usb *dev = cdev->private;
980 unsigned long debtime;
981 unsigned long val;
982 int chan;
983 int cmd;
984 int n;
985
986 n = rudimentary_check(dev, DIR_OUT);
987 if (n)
988 return n;
989
990 down(&dev->limit_sem);
991 chan = CR_CHAN(insn->chanspec);
992
993 if (!chan)
994 cmd = VMK8055_CMD_DEB1_TIME;
995 else
996 cmd = VMK8055_CMD_DEB2_TIME;
997
998 for (n = 0; n < insn->n; n++) {
999 debtime = data[n];
1000 if (debtime == 0)
1001 debtime = 1;
1002
1003 /* TODO: Prevent overflows */
1004 if (debtime > 7450)
1005 debtime = 7450;
1006
1007 val = int_sqrt(debtime * 1000 / 115);
1008 if (((val + 1) * val) < debtime * 1000 / 115)
1009 val += 1;
1010
1011 dev->usb_tx_buf[6 + chan] = val;
1012
1013 if (vmk80xx_write_packet(dev, cmd))
1014 break;
1015 }
1016
1017 up(&dev->limit_sem);
1018
1019 return n;
1020 }
1021
1022 static int vmk80xx_pwm_rinsn(struct comedi_device *cdev,
1023 struct comedi_subdevice *s,
1024 struct comedi_insn *insn, unsigned int *data)
1025 {
1026 struct vmk80xx_usb *dev = cdev->private;
1027 int reg[2];
1028 int n;
1029
1030 n = rudimentary_check(dev, DIR_IN);
1031 if (n)
1032 return n;
1033
1034 down(&dev->limit_sem);
1035
1036 reg[0] = VMK8061_PWM_REG1;
1037 reg[1] = VMK8061_PWM_REG2;
1038
1039 dev->usb_tx_buf[0] = VMK8061_CMD_RD_PWM;
1040
1041 for (n = 0; n < insn->n; n++) {
1042 if (vmk80xx_read_packet(dev))
1043 break;
1044
1045 data[n] = dev->usb_rx_buf[reg[0]] + 4 * dev->usb_rx_buf[reg[1]];
1046 }
1047
1048 up(&dev->limit_sem);
1049
1050 return n;
1051 }
1052
1053 static int vmk80xx_pwm_winsn(struct comedi_device *cdev,
1054 struct comedi_subdevice *s,
1055 struct comedi_insn *insn, unsigned int *data)
1056 {
1057 struct vmk80xx_usb *dev = cdev->private;
1058 unsigned char *tx_buf;
1059 int reg[2];
1060 int cmd;
1061 int n;
1062
1063 n = rudimentary_check(dev, DIR_OUT);
1064 if (n)
1065 return n;
1066
1067 down(&dev->limit_sem);
1068
1069 tx_buf = dev->usb_tx_buf;
1070
1071 reg[0] = VMK8061_PWM_REG1;
1072 reg[1] = VMK8061_PWM_REG2;
1073
1074 cmd = VMK8061_CMD_OUT_PWM;
1075
1076 /*
1077 * The followin piece of code was translated from the inline
1078 * assembler code in the DLL source code.
1079 *
1080 * asm
1081 * mov eax, k ; k is the value (data[n])
1082 * and al, 03h ; al are the lower 8 bits of eax
1083 * mov lo, al ; lo is the low part (tx_buf[reg[0]])
1084 * mov eax, k
1085 * shr eax, 2 ; right shift eax register by 2
1086 * mov hi, al ; hi is the high part (tx_buf[reg[1]])
1087 * end;
1088 */
1089 for (n = 0; n < insn->n; n++) {
1090 tx_buf[reg[0]] = (unsigned char)(data[n] & 0x03);
1091 tx_buf[reg[1]] = (unsigned char)(data[n] >> 2) & 0xff;
1092
1093 if (vmk80xx_write_packet(dev, cmd))
1094 break;
1095 }
1096
1097 up(&dev->limit_sem);
1098
1099 return n;
1100 }
1101
1102 static int vmk80xx_attach_common(struct comedi_device *cdev,
1103 struct vmk80xx_usb *dev)
1104 {
1105 int n_subd;
1106 struct comedi_subdevice *s;
1107 int ret;
1108
1109 down(&dev->limit_sem);
1110 cdev->board_name = dev->board.name;
1111 cdev->private = dev;
1112 if (dev->board.model == VMK8055_MODEL)
1113 n_subd = 5;
1114 else
1115 n_subd = 6;
1116 ret = comedi_alloc_subdevices(cdev, n_subd);
1117 if (ret) {
1118 up(&dev->limit_sem);
1119 return ret;
1120 }
1121 /* Analog input subdevice */
1122 s = cdev->subdevices + VMK80XX_SUBD_AI;
1123 s->type = COMEDI_SUBD_AI;
1124 s->subdev_flags = SDF_READABLE | SDF_GROUND;
1125 s->n_chan = dev->board.ai_chans;
1126 s->maxdata = (1 << dev->board.ai_bits) - 1;
1127 s->range_table = dev->board.range;
1128 s->insn_read = vmk80xx_ai_rinsn;
1129 /* Analog output subdevice */
1130 s = cdev->subdevices + VMK80XX_SUBD_AO;
1131 s->type = COMEDI_SUBD_AO;
1132 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
1133 s->n_chan = dev->board.ao_chans;
1134 s->maxdata = (1 << dev->board.ao_bits) - 1;
1135 s->range_table = dev->board.range;
1136 s->insn_write = vmk80xx_ao_winsn;
1137 if (dev->board.model == VMK8061_MODEL) {
1138 s->subdev_flags |= SDF_READABLE;
1139 s->insn_read = vmk80xx_ao_rinsn;
1140 }
1141 /* Digital input subdevice */
1142 s = cdev->subdevices + VMK80XX_SUBD_DI;
1143 s->type = COMEDI_SUBD_DI;
1144 s->subdev_flags = SDF_READABLE | SDF_GROUND;
1145 s->n_chan = dev->board.di_chans;
1146 s->maxdata = 1;
1147 s->insn_read = vmk80xx_di_rinsn;
1148 s->insn_bits = vmk80xx_di_bits;
1149 /* Digital output subdevice */
1150 s = cdev->subdevices + VMK80XX_SUBD_DO;
1151 s->type = COMEDI_SUBD_DO;
1152 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
1153 s->n_chan = dev->board.do_chans;
1154 s->maxdata = 1;
1155 s->insn_write = vmk80xx_do_winsn;
1156 s->insn_bits = vmk80xx_do_bits;
1157 if (dev->board.model == VMK8061_MODEL) {
1158 s->subdev_flags |= SDF_READABLE;
1159 s->insn_read = vmk80xx_do_rinsn;
1160 }
1161 /* Counter subdevice */
1162 s = cdev->subdevices + VMK80XX_SUBD_CNT;
1163 s->type = COMEDI_SUBD_COUNTER;
1164 s->subdev_flags = SDF_READABLE;
1165 s->n_chan = dev->board.cnt_chans;
1166 s->insn_read = vmk80xx_cnt_rinsn;
1167 s->insn_config = vmk80xx_cnt_cinsn;
1168 if (dev->board.model == VMK8055_MODEL) {
1169 s->subdev_flags |= SDF_WRITEABLE;
1170 s->maxdata = (1 << dev->board.cnt_bits) - 1;
1171 s->insn_write = vmk80xx_cnt_winsn;
1172 }
1173 /* PWM subdevice */
1174 if (dev->board.model == VMK8061_MODEL) {
1175 s = cdev->subdevices + VMK80XX_SUBD_PWM;
1176 s->type = COMEDI_SUBD_PWM;
1177 s->subdev_flags = SDF_READABLE | SDF_WRITEABLE;
1178 s->n_chan = dev->board.pwm_chans;
1179 s->maxdata = (1 << dev->board.pwm_bits) - 1;
1180 s->insn_read = vmk80xx_pwm_rinsn;
1181 s->insn_write = vmk80xx_pwm_winsn;
1182 }
1183 dev->attached = 1;
1184 dev_info(cdev->class_dev, "vmk80xx: board #%d [%s] attached\n",
1185 dev->count, dev->board.name);
1186 up(&dev->limit_sem);
1187 return 0;
1188 }
1189
1190 /* called for COMEDI_DEVCONFIG ioctl for board_name "vmk80xx" */
1191 static int vmk80xx_attach(struct comedi_device *cdev,
1192 struct comedi_devconfig *it)
1193 {
1194 int i;
1195 int ret;
1196
1197 mutex_lock(&glb_mutex);
1198 for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
1199 if (vmb[i].probed && !vmb[i].attached)
1200 break;
1201 if (i == VMK80XX_MAX_BOARDS)
1202 ret = -ENODEV;
1203 else
1204 ret = vmk80xx_attach_common(cdev, &vmb[i]);
1205 mutex_unlock(&glb_mutex);
1206 return ret;
1207 }
1208
1209 /* called via comedi_usb_auto_config() */
1210 static int vmk80xx_attach_usb(struct comedi_device *cdev,
1211 struct usb_interface *intf)
1212 {
1213 int i;
1214 int ret;
1215
1216 mutex_lock(&glb_mutex);
1217 for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
1218 if (vmb[i].probed && vmb[i].intf == intf)
1219 break;
1220 if (i == VMK80XX_MAX_BOARDS)
1221 ret = -ENODEV;
1222 else if (vmb[i].attached)
1223 ret = -EBUSY;
1224 else
1225 ret = vmk80xx_attach_common(cdev, &vmb[i]);
1226 mutex_unlock(&glb_mutex);
1227 return ret;
1228 }
1229
1230 static void vmk80xx_detach(struct comedi_device *dev)
1231 {
1232 struct vmk80xx_usb *usb = dev->private;
1233
1234 if (usb) {
1235 down(&usb->limit_sem);
1236 dev->private = NULL;
1237 usb->attached = 0;
1238 up(&usb->limit_sem);
1239 }
1240 }
1241
1242 static struct comedi_driver vmk80xx_driver = {
1243 .module = THIS_MODULE,
1244 .driver_name = "vmk80xx",
1245 .attach = vmk80xx_attach,
1246 .detach = vmk80xx_detach,
1247 .attach_usb = vmk80xx_attach_usb,
1248 };
1249
1250 static int vmk80xx_usb_probe(struct usb_interface *intf,
1251 const struct usb_device_id *id)
1252 {
1253 int i;
1254 struct vmk80xx_usb *dev;
1255 struct usb_host_interface *iface_desc;
1256 struct usb_endpoint_descriptor *ep_desc;
1257 size_t size;
1258
1259 mutex_lock(&glb_mutex);
1260
1261 for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
1262 if (!vmb[i].probed)
1263 break;
1264
1265 if (i == VMK80XX_MAX_BOARDS) {
1266 mutex_unlock(&glb_mutex);
1267 return -EMFILE;
1268 }
1269
1270 dev = &vmb[i];
1271
1272 memset(dev, 0x00, sizeof(struct vmk80xx_usb));
1273 dev->count = i;
1274
1275 iface_desc = intf->cur_altsetting;
1276 if (iface_desc->desc.bNumEndpoints != 2)
1277 goto error;
1278
1279 for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
1280 ep_desc = &iface_desc->endpoint[i].desc;
1281
1282 if (usb_endpoint_is_int_in(ep_desc)) {
1283 dev->ep_rx = ep_desc;
1284 continue;
1285 }
1286
1287 if (usb_endpoint_is_int_out(ep_desc)) {
1288 dev->ep_tx = ep_desc;
1289 continue;
1290 }
1291
1292 if (usb_endpoint_is_bulk_in(ep_desc)) {
1293 dev->ep_rx = ep_desc;
1294 continue;
1295 }
1296
1297 if (usb_endpoint_is_bulk_out(ep_desc)) {
1298 dev->ep_tx = ep_desc;
1299 continue;
1300 }
1301 }
1302
1303 if (!dev->ep_rx || !dev->ep_tx)
1304 goto error;
1305
1306 size = le16_to_cpu(dev->ep_rx->wMaxPacketSize);
1307 dev->usb_rx_buf = kmalloc(size, GFP_KERNEL);
1308 if (!dev->usb_rx_buf) {
1309 mutex_unlock(&glb_mutex);
1310 return -ENOMEM;
1311 }
1312
1313 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
1314 dev->usb_tx_buf = kmalloc(size, GFP_KERNEL);
1315 if (!dev->usb_tx_buf) {
1316 kfree(dev->usb_rx_buf);
1317 mutex_unlock(&glb_mutex);
1318 return -ENOMEM;
1319 }
1320
1321 dev->udev = interface_to_usbdev(intf);
1322 dev->intf = intf;
1323
1324 sema_init(&dev->limit_sem, 8);
1325 init_waitqueue_head(&dev->read_wait);
1326 init_waitqueue_head(&dev->write_wait);
1327
1328 init_usb_anchor(&dev->rx_anchor);
1329 init_usb_anchor(&dev->tx_anchor);
1330
1331 usb_set_intfdata(intf, dev);
1332
1333 switch (id->driver_info) {
1334 case DEVICE_VMK8055:
1335 dev->board.name = "K8055 (VM110)";
1336 dev->board.model = VMK8055_MODEL;
1337 dev->board.range = &vmk8055_range;
1338 dev->board.ai_chans = 2;
1339 dev->board.ai_bits = 8;
1340 dev->board.ao_chans = 2;
1341 dev->board.ao_bits = 8;
1342 dev->board.di_chans = 5;
1343 dev->board.di_bits = 1;
1344 dev->board.do_chans = 8;
1345 dev->board.do_bits = 1;
1346 dev->board.cnt_chans = 2;
1347 dev->board.cnt_bits = 16;
1348 dev->board.pwm_chans = 0;
1349 dev->board.pwm_bits = 0;
1350 break;
1351 case DEVICE_VMK8061:
1352 dev->board.name = "K8061 (VM140)";
1353 dev->board.model = VMK8061_MODEL;
1354 dev->board.range = &vmk8061_range;
1355 dev->board.ai_chans = 8;
1356 dev->board.ai_bits = 10;
1357 dev->board.ao_chans = 8;
1358 dev->board.ao_bits = 8;
1359 dev->board.di_chans = 8;
1360 dev->board.di_bits = 1;
1361 dev->board.do_chans = 8;
1362 dev->board.do_bits = 1;
1363 dev->board.cnt_chans = 2;
1364 dev->board.cnt_bits = 0;
1365 dev->board.pwm_chans = 1;
1366 dev->board.pwm_bits = 10;
1367 break;
1368 }
1369
1370 if (dev->board.model == VMK8061_MODEL) {
1371 vmk80xx_read_eeprom(dev, IC3_VERSION);
1372 printk(KERN_INFO "comedi#: vmk80xx: %s\n", dev->fw.ic3_vers);
1373
1374 if (vmk80xx_check_data_link(dev)) {
1375 vmk80xx_read_eeprom(dev, IC6_VERSION);
1376 printk(KERN_INFO "comedi#: vmk80xx: %s\n",
1377 dev->fw.ic6_vers);
1378 } else {
1379 dbgcm("comedi#: vmk80xx: no conn. to CPU\n");
1380 }
1381 }
1382
1383 if (dev->board.model == VMK8055_MODEL)
1384 vmk80xx_reset_device(dev);
1385
1386 dev->probed = 1;
1387
1388 printk(KERN_INFO "comedi#: vmk80xx: board #%d [%s] now attached\n",
1389 dev->count, dev->board.name);
1390
1391 mutex_unlock(&glb_mutex);
1392
1393 comedi_usb_auto_config(intf, &vmk80xx_driver);
1394
1395 return 0;
1396 error:
1397 mutex_unlock(&glb_mutex);
1398
1399 return -ENODEV;
1400 }
1401
1402 static void vmk80xx_usb_disconnect(struct usb_interface *intf)
1403 {
1404 struct vmk80xx_usb *dev = usb_get_intfdata(intf);
1405
1406 if (!dev)
1407 return;
1408
1409 comedi_usb_auto_unconfig(intf);
1410
1411 mutex_lock(&glb_mutex);
1412 down(&dev->limit_sem);
1413
1414 dev->probed = 0;
1415 usb_set_intfdata(dev->intf, NULL);
1416
1417 usb_kill_anchored_urbs(&dev->rx_anchor);
1418 usb_kill_anchored_urbs(&dev->tx_anchor);
1419
1420 kfree(dev->usb_rx_buf);
1421 kfree(dev->usb_tx_buf);
1422
1423 printk(KERN_INFO "comedi#: vmk80xx: board #%d [%s] now detached\n",
1424 dev->count, dev->board.name);
1425
1426 up(&dev->limit_sem);
1427 mutex_unlock(&glb_mutex);
1428 }
1429
1430 static const struct usb_device_id vmk80xx_usb_id_table[] = {
1431 { USB_DEVICE(0x10cf, 0x5500), .driver_info = DEVICE_VMK8055 },
1432 { USB_DEVICE(0x10cf, 0x5501), .driver_info = DEVICE_VMK8055 },
1433 { USB_DEVICE(0x10cf, 0x5502), .driver_info = DEVICE_VMK8055 },
1434 { USB_DEVICE(0x10cf, 0x5503), .driver_info = DEVICE_VMK8055 },
1435 { USB_DEVICE(0x10cf, 0x8061), .driver_info = DEVICE_VMK8061 },
1436 { USB_DEVICE(0x10cf, 0x8062), .driver_info = DEVICE_VMK8061 },
1437 { USB_DEVICE(0x10cf, 0x8063), .driver_info = DEVICE_VMK8061 },
1438 { USB_DEVICE(0x10cf, 0x8064), .driver_info = DEVICE_VMK8061 },
1439 { USB_DEVICE(0x10cf, 0x8065), .driver_info = DEVICE_VMK8061 },
1440 { USB_DEVICE(0x10cf, 0x8066), .driver_info = DEVICE_VMK8061 },
1441 { USB_DEVICE(0x10cf, 0x8067), .driver_info = DEVICE_VMK8061 },
1442 { USB_DEVICE(0x10cf, 0x8068), .driver_info = DEVICE_VMK8061 },
1443 { }
1444 };
1445 MODULE_DEVICE_TABLE(usb, vmk80xx_usb_id_table);
1446
1447 /* TODO: Add support for suspend, resume, pre_reset,
1448 * post_reset and flush */
1449 static struct usb_driver vmk80xx_usb_driver = {
1450 .name = "vmk80xx",
1451 .probe = vmk80xx_usb_probe,
1452 .disconnect = vmk80xx_usb_disconnect,
1453 .id_table = vmk80xx_usb_id_table,
1454 };
1455 module_comedi_usb_driver(vmk80xx_driver, vmk80xx_usb_driver);
1456
1457 MODULE_AUTHOR("Manuel Gebele <forensixs@gmx.de>");
1458 MODULE_DESCRIPTION("Velleman USB Board Low-Level Driver");
1459 MODULE_SUPPORTED_DEVICE("K8055/K8061 aka VM110/VM140");
1460 MODULE_VERSION("0.8.01");
1461 MODULE_LICENSE("GPL");
This page took 0.072756 seconds and 6 git commands to generate.