6ed70eef149c917d7472d94afcbc89b0877c5279
[pandora-kernel.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         __u8 di_chans;
166         __le16 cnt_bits;
167         __u8 pwm_chans;
168         __le16 pwm_bits;
169 };
170
171 static const struct vmk80xx_board vmk80xx_boardinfo[] = {
172         [DEVICE_VMK8055] = {
173                 .name           = "K8055 (VM110)",
174                 .model          = VMK8055_MODEL,
175                 .range          = &vmk8055_range,
176                 .ai_chans       = 2,
177                 .ai_bits        = 8,
178                 .ao_chans       = 2,
179                 .di_chans       = 6,
180                 .cnt_bits       = 16,
181                 .pwm_chans      = 0,
182                 .pwm_bits       = 0,
183         },
184         [DEVICE_VMK8061] = {
185                 .name           = "K8061 (VM140)",
186                 .model          = VMK8061_MODEL,
187                 .range          = &vmk8061_range,
188                 .ai_chans       = 8,
189                 .ai_bits        = 10,
190                 .ao_chans       = 8,
191                 .di_chans       = 8,
192                 .cnt_bits       = 0,
193                 .pwm_chans      = 1,
194                 .pwm_bits       = 10,
195         },
196 };
197
198 struct vmk80xx_private {
199         struct usb_device *usb;
200         struct usb_interface *intf;
201         struct usb_endpoint_descriptor *ep_rx;
202         struct usb_endpoint_descriptor *ep_tx;
203         struct usb_anchor rx_anchor;
204         struct usb_anchor tx_anchor;
205         const struct vmk80xx_board *board;
206         struct firmware_version fw;
207         struct semaphore limit_sem;
208         wait_queue_head_t read_wait;
209         wait_queue_head_t write_wait;
210         unsigned char *usb_rx_buf;
211         unsigned char *usb_tx_buf;
212         unsigned long flags;
213 };
214
215 static void vmk80xx_tx_callback(struct urb *urb)
216 {
217         struct vmk80xx_private *devpriv = urb->context;
218         unsigned long *flags = &devpriv->flags;
219         int stat = urb->status;
220
221         if (stat && !(stat == -ENOENT
222                       || stat == -ECONNRESET || stat == -ESHUTDOWN))
223                 dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n",
224                       __func__, stat);
225
226         if (!test_bit(TRANS_OUT_BUSY, flags))
227                 return;
228
229         clear_bit(TRANS_OUT_BUSY, flags);
230
231         wake_up_interruptible(&devpriv->write_wait);
232 }
233
234 static void vmk80xx_rx_callback(struct urb *urb)
235 {
236         struct vmk80xx_private *devpriv = urb->context;
237         unsigned long *flags = &devpriv->flags;
238         int stat = urb->status;
239
240         switch (stat) {
241         case 0:
242                 break;
243         case -ENOENT:
244         case -ECONNRESET:
245         case -ESHUTDOWN:
246                 break;
247         default:
248                 dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n",
249                       __func__, stat);
250                 goto resubmit;
251         }
252
253         goto exit;
254 resubmit:
255         if (test_bit(TRANS_IN_RUNNING, flags) && devpriv->intf) {
256                 usb_anchor_urb(urb, &devpriv->rx_anchor);
257
258                 if (!usb_submit_urb(urb, GFP_KERNEL))
259                         goto exit;
260
261                 dev_err(&urb->dev->dev,
262                         "comedi#: vmk80xx: %s - submit urb failed\n",
263                         __func__);
264
265                 usb_unanchor_urb(urb);
266         }
267 exit:
268         clear_bit(TRANS_IN_BUSY, flags);
269
270         wake_up_interruptible(&devpriv->read_wait);
271 }
272
273 static int vmk80xx_check_data_link(struct vmk80xx_private *devpriv)
274 {
275         struct usb_device *usb = devpriv->usb;
276         unsigned int tx_pipe;
277         unsigned int rx_pipe;
278         unsigned char tx[1];
279         unsigned char rx[2];
280
281         tx_pipe = usb_sndbulkpipe(usb, 0x01);
282         rx_pipe = usb_rcvbulkpipe(usb, 0x81);
283
284         tx[0] = VMK8061_CMD_RD_PWR_STAT;
285
286         /*
287          * Check that IC6 (PIC16F871) is powered and
288          * running and the data link between IC3 and
289          * IC6 is working properly
290          */
291         usb_bulk_msg(usb, tx_pipe, tx, 1, NULL, devpriv->ep_tx->bInterval);
292         usb_bulk_msg(usb, rx_pipe, rx, 2, NULL, HZ * 10);
293
294         return (int)rx[1];
295 }
296
297 static void vmk80xx_read_eeprom(struct vmk80xx_private *devpriv, int flag)
298 {
299         struct usb_device *usb = devpriv->usb;
300         unsigned int tx_pipe;
301         unsigned int rx_pipe;
302         unsigned char tx[1];
303         unsigned char rx[64];
304         int cnt;
305
306         tx_pipe = usb_sndbulkpipe(usb, 0x01);
307         rx_pipe = usb_rcvbulkpipe(usb, 0x81);
308
309         tx[0] = VMK8061_CMD_RD_VERSION;
310
311         /*
312          * Read the firmware version info of IC3 and
313          * IC6 from the internal EEPROM of the IC
314          */
315         usb_bulk_msg(usb, tx_pipe, tx, 1, NULL, devpriv->ep_tx->bInterval);
316         usb_bulk_msg(usb, rx_pipe, rx, 64, &cnt, HZ * 10);
317
318         rx[cnt] = '\0';
319
320         if (flag & IC3_VERSION)
321                 strncpy(devpriv->fw.ic3_vers, rx + 1, 24);
322         else                    /* IC6_VERSION */
323                 strncpy(devpriv->fw.ic6_vers, rx + 25, 24);
324 }
325
326 static int vmk80xx_reset_device(struct vmk80xx_private *devpriv)
327 {
328         struct usb_device *usb = devpriv->usb;
329         unsigned char *tx_buf = devpriv->usb_tx_buf;
330         struct urb *urb;
331         unsigned int tx_pipe;
332         int ival;
333         size_t size;
334
335         urb = usb_alloc_urb(0, GFP_KERNEL);
336         if (!urb)
337                 return -ENOMEM;
338
339         tx_pipe = usb_sndintpipe(usb, 0x01);
340
341         ival = devpriv->ep_tx->bInterval;
342         size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize);
343
344         tx_buf[0] = VMK8055_CMD_RST;
345         tx_buf[1] = 0x00;
346         tx_buf[2] = 0x00;
347         tx_buf[3] = 0x00;
348         tx_buf[4] = 0x00;
349         tx_buf[5] = 0x00;
350         tx_buf[6] = 0x00;
351         tx_buf[7] = 0x00;
352
353         usb_fill_int_urb(urb, usb, tx_pipe, tx_buf, size,
354                          vmk80xx_tx_callback, devpriv, ival);
355
356         usb_anchor_urb(urb, &devpriv->tx_anchor);
357
358         return usb_submit_urb(urb, GFP_KERNEL);
359 }
360
361 static void vmk80xx_build_int_urb(struct urb *urb, int flag)
362 {
363         struct vmk80xx_private *devpriv = urb->context;
364         struct usb_device *usb = devpriv->usb;
365         __u8 rx_addr;
366         __u8 tx_addr;
367         unsigned int pipe;
368         unsigned char *buf;
369         size_t size;
370         void (*callback) (struct urb *);
371         int ival;
372
373         if (flag & URB_RCV_FLAG) {
374                 rx_addr = devpriv->ep_rx->bEndpointAddress;
375                 pipe = usb_rcvintpipe(usb, rx_addr);
376                 buf = devpriv->usb_rx_buf;
377                 size = le16_to_cpu(devpriv->ep_rx->wMaxPacketSize);
378                 callback = vmk80xx_rx_callback;
379                 ival = devpriv->ep_rx->bInterval;
380         } else {                /* URB_SND_FLAG */
381                 tx_addr = devpriv->ep_tx->bEndpointAddress;
382                 pipe = usb_sndintpipe(usb, tx_addr);
383                 buf = devpriv->usb_tx_buf;
384                 size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize);
385                 callback = vmk80xx_tx_callback;
386                 ival = devpriv->ep_tx->bInterval;
387         }
388
389         usb_fill_int_urb(urb, usb, pipe, buf, size, callback, devpriv, ival);
390 }
391
392 static void vmk80xx_do_bulk_msg(struct vmk80xx_private *devpriv)
393 {
394         struct usb_device *usb = devpriv->usb;
395         unsigned long *flags = &devpriv->flags;
396         __u8 tx_addr;
397         __u8 rx_addr;
398         unsigned int tx_pipe;
399         unsigned int rx_pipe;
400         size_t size;
401
402         set_bit(TRANS_IN_BUSY, flags);
403         set_bit(TRANS_OUT_BUSY, flags);
404
405         tx_addr = devpriv->ep_tx->bEndpointAddress;
406         rx_addr = devpriv->ep_rx->bEndpointAddress;
407         tx_pipe = usb_sndbulkpipe(usb, tx_addr);
408         rx_pipe = usb_rcvbulkpipe(usb, rx_addr);
409
410         /*
411          * The max packet size attributes of the K8061
412          * input/output endpoints are identical
413          */
414         size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize);
415
416         usb_bulk_msg(usb, tx_pipe, devpriv->usb_tx_buf,
417                      size, NULL, devpriv->ep_tx->bInterval);
418         usb_bulk_msg(usb, rx_pipe, devpriv->usb_rx_buf, size, NULL, HZ * 10);
419
420         clear_bit(TRANS_OUT_BUSY, flags);
421         clear_bit(TRANS_IN_BUSY, flags);
422 }
423
424 static int vmk80xx_read_packet(struct vmk80xx_private *devpriv)
425 {
426         const struct vmk80xx_board *boardinfo = devpriv->board;
427         unsigned long *flags = &devpriv->flags;
428         struct urb *urb;
429         int retval;
430
431         if (!devpriv->intf)
432                 return -ENODEV;
433
434         /* Only useful for interrupt transfers */
435         if (test_bit(TRANS_IN_BUSY, flags))
436                 if (wait_event_interruptible(devpriv->read_wait,
437                                              !test_bit(TRANS_IN_BUSY, flags)))
438                         return -ERESTART;
439
440         if (boardinfo->model == VMK8061_MODEL) {
441                 vmk80xx_do_bulk_msg(devpriv);
442
443                 return 0;
444         }
445
446         urb = usb_alloc_urb(0, GFP_KERNEL);
447         if (!urb)
448                 return -ENOMEM;
449
450         urb->context = devpriv;
451         vmk80xx_build_int_urb(urb, URB_RCV_FLAG);
452
453         set_bit(TRANS_IN_RUNNING, flags);
454         set_bit(TRANS_IN_BUSY, flags);
455
456         usb_anchor_urb(urb, &devpriv->rx_anchor);
457
458         retval = usb_submit_urb(urb, GFP_KERNEL);
459         if (!retval)
460                 goto exit;
461
462         clear_bit(TRANS_IN_RUNNING, flags);
463         usb_unanchor_urb(urb);
464
465 exit:
466         usb_free_urb(urb);
467
468         return retval;
469 }
470
471 static int vmk80xx_write_packet(struct vmk80xx_private *devpriv, int cmd)
472 {
473         const struct vmk80xx_board *boardinfo = devpriv->board;
474         unsigned long *flags = &devpriv->flags;
475         struct urb *urb;
476         int retval;
477
478         if (!devpriv->intf)
479                 return -ENODEV;
480
481         if (test_bit(TRANS_OUT_BUSY, flags))
482                 if (wait_event_interruptible(devpriv->write_wait,
483                                              !test_bit(TRANS_OUT_BUSY, flags)))
484                         return -ERESTART;
485
486         if (boardinfo->model == VMK8061_MODEL) {
487                 devpriv->usb_tx_buf[0] = cmd;
488                 vmk80xx_do_bulk_msg(devpriv);
489
490                 return 0;
491         }
492
493         urb = usb_alloc_urb(0, GFP_KERNEL);
494         if (!urb)
495                 return -ENOMEM;
496
497         urb->context = devpriv;
498         vmk80xx_build_int_urb(urb, URB_SND_FLAG);
499
500         set_bit(TRANS_OUT_BUSY, flags);
501
502         usb_anchor_urb(urb, &devpriv->tx_anchor);
503
504         devpriv->usb_tx_buf[0] = cmd;
505
506         retval = usb_submit_urb(urb, GFP_KERNEL);
507         if (!retval)
508                 goto exit;
509
510         clear_bit(TRANS_OUT_BUSY, flags);
511         usb_unanchor_urb(urb);
512
513 exit:
514         usb_free_urb(urb);
515
516         return retval;
517 }
518
519 #define DIR_IN  1
520 #define DIR_OUT 2
521
522 static int rudimentary_check(struct vmk80xx_private *devpriv, int dir)
523 {
524         if (!devpriv)
525                 return -EFAULT;
526         if (dir & DIR_IN) {
527                 if (test_bit(TRANS_IN_BUSY, &devpriv->flags))
528                         return -EBUSY;
529         }
530         if (dir & DIR_OUT) {
531                 if (test_bit(TRANS_OUT_BUSY, &devpriv->flags))
532                         return -EBUSY;
533         }
534
535         return 0;
536 }
537
538 static int vmk80xx_ai_rinsn(struct comedi_device *dev,
539                             struct comedi_subdevice *s,
540                             struct comedi_insn *insn, unsigned int *data)
541 {
542         const struct vmk80xx_board *boardinfo = comedi_board(dev);
543         struct vmk80xx_private *devpriv = dev->private;
544         int chan;
545         int reg[2];
546         int n;
547
548         n = rudimentary_check(devpriv, DIR_IN);
549         if (n)
550                 return n;
551
552         down(&devpriv->limit_sem);
553         chan = CR_CHAN(insn->chanspec);
554
555         switch (boardinfo->model) {
556         case VMK8055_MODEL:
557                 if (!chan)
558                         reg[0] = VMK8055_AI1_REG;
559                 else
560                         reg[0] = VMK8055_AI2_REG;
561                 break;
562         case VMK8061_MODEL:
563         default:
564                 reg[0] = VMK8061_AI_REG1;
565                 reg[1] = VMK8061_AI_REG2;
566                 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_AI;
567                 devpriv->usb_tx_buf[VMK8061_CH_REG] = chan;
568                 break;
569         }
570
571         for (n = 0; n < insn->n; n++) {
572                 if (vmk80xx_read_packet(devpriv))
573                         break;
574
575                 if (boardinfo->model == VMK8055_MODEL) {
576                         data[n] = devpriv->usb_rx_buf[reg[0]];
577                         continue;
578                 }
579
580                 /* VMK8061_MODEL */
581                 data[n] = devpriv->usb_rx_buf[reg[0]] + 256 *
582                     devpriv->usb_rx_buf[reg[1]];
583         }
584
585         up(&devpriv->limit_sem);
586
587         return n;
588 }
589
590 static int vmk80xx_ao_winsn(struct comedi_device *dev,
591                             struct comedi_subdevice *s,
592                             struct comedi_insn *insn, unsigned int *data)
593 {
594         const struct vmk80xx_board *boardinfo = comedi_board(dev);
595         struct vmk80xx_private *devpriv = dev->private;
596         int chan;
597         int cmd;
598         int reg;
599         int n;
600
601         n = rudimentary_check(devpriv, DIR_OUT);
602         if (n)
603                 return n;
604
605         down(&devpriv->limit_sem);
606         chan = CR_CHAN(insn->chanspec);
607
608         switch (boardinfo->model) {
609         case VMK8055_MODEL:
610                 cmd = VMK8055_CMD_WRT_AD;
611                 if (!chan)
612                         reg = VMK8055_AO1_REG;
613                 else
614                         reg = VMK8055_AO2_REG;
615                 break;
616         default:                /* NOTE: avoid compiler warnings */
617                 cmd = VMK8061_CMD_SET_AO;
618                 reg = VMK8061_AO_REG;
619                 devpriv->usb_tx_buf[VMK8061_CH_REG] = chan;
620                 break;
621         }
622
623         for (n = 0; n < insn->n; n++) {
624                 devpriv->usb_tx_buf[reg] = data[n];
625
626                 if (vmk80xx_write_packet(devpriv, cmd))
627                         break;
628         }
629
630         up(&devpriv->limit_sem);
631
632         return n;
633 }
634
635 static int vmk80xx_ao_rinsn(struct comedi_device *dev,
636                             struct comedi_subdevice *s,
637                             struct comedi_insn *insn, unsigned int *data)
638 {
639         struct vmk80xx_private *devpriv = dev->private;
640         int chan;
641         int reg;
642         int n;
643
644         n = rudimentary_check(devpriv, DIR_IN);
645         if (n)
646                 return n;
647
648         down(&devpriv->limit_sem);
649         chan = CR_CHAN(insn->chanspec);
650
651         reg = VMK8061_AO_REG - 1;
652
653         devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_AO;
654
655         for (n = 0; n < insn->n; n++) {
656                 if (vmk80xx_read_packet(devpriv))
657                         break;
658
659                 data[n] = devpriv->usb_rx_buf[reg + chan];
660         }
661
662         up(&devpriv->limit_sem);
663
664         return n;
665 }
666
667 static int vmk80xx_di_bits(struct comedi_device *dev,
668                            struct comedi_subdevice *s,
669                            struct comedi_insn *insn, unsigned int *data)
670 {
671         const struct vmk80xx_board *boardinfo = comedi_board(dev);
672         struct vmk80xx_private *devpriv = dev->private;
673         unsigned char *rx_buf;
674         int reg;
675         int retval;
676
677         retval = rudimentary_check(devpriv, DIR_IN);
678         if (retval)
679                 return retval;
680
681         down(&devpriv->limit_sem);
682
683         rx_buf = devpriv->usb_rx_buf;
684
685         if (boardinfo->model == VMK8061_MODEL) {
686                 reg = VMK8061_DI_REG;
687                 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_DI;
688         } else {
689                 reg = VMK8055_DI_REG;
690         }
691
692         retval = vmk80xx_read_packet(devpriv);
693
694         if (!retval) {
695                 if (boardinfo->model == VMK8055_MODEL)
696                         data[1] = (((rx_buf[reg] >> 4) & 0x03) |
697                                   ((rx_buf[reg] << 2) & 0x04) |
698                                   ((rx_buf[reg] >> 3) & 0x18));
699                 else
700                         data[1] = rx_buf[reg];
701
702                 retval = 2;
703         }
704
705         up(&devpriv->limit_sem);
706
707         return retval;
708 }
709
710 static int vmk80xx_di_rinsn(struct comedi_device *dev,
711                             struct comedi_subdevice *s,
712                             struct comedi_insn *insn, unsigned int *data)
713 {
714         const struct vmk80xx_board *boardinfo = comedi_board(dev);
715         struct vmk80xx_private *devpriv = dev->private;
716         int chan;
717         unsigned char *rx_buf;
718         int reg;
719         int inp;
720         int n;
721
722         n = rudimentary_check(devpriv, DIR_IN);
723         if (n)
724                 return n;
725
726         down(&devpriv->limit_sem);
727         chan = CR_CHAN(insn->chanspec);
728
729         rx_buf = devpriv->usb_rx_buf;
730
731         if (boardinfo->model == VMK8061_MODEL) {
732                 reg = VMK8061_DI_REG;
733                 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_DI;
734         } else {
735                 reg = VMK8055_DI_REG;
736         }
737         for (n = 0; n < insn->n; n++) {
738                 if (vmk80xx_read_packet(devpriv))
739                         break;
740
741                 if (boardinfo->model == VMK8055_MODEL)
742                         inp = (((rx_buf[reg] >> 4) & 0x03) |
743                                ((rx_buf[reg] << 2) & 0x04) |
744                                ((rx_buf[reg] >> 3) & 0x18));
745                 else
746                         inp = rx_buf[reg];
747
748                 data[n] = (inp >> chan) & 1;
749         }
750
751         up(&devpriv->limit_sem);
752
753         return n;
754 }
755
756 static int vmk80xx_do_winsn(struct comedi_device *dev,
757                             struct comedi_subdevice *s,
758                             struct comedi_insn *insn, unsigned int *data)
759 {
760         const struct vmk80xx_board *boardinfo = comedi_board(dev);
761         struct vmk80xx_private *devpriv = dev->private;
762         int chan;
763         unsigned char *tx_buf;
764         int reg;
765         int cmd;
766         int n;
767
768         n = rudimentary_check(devpriv, DIR_OUT);
769         if (n)
770                 return n;
771
772         down(&devpriv->limit_sem);
773         chan = CR_CHAN(insn->chanspec);
774
775         tx_buf = devpriv->usb_tx_buf;
776
777         for (n = 0; n < insn->n; n++) {
778                 if (boardinfo->model == VMK8055_MODEL) {
779                         reg = VMK8055_DO_REG;
780                         cmd = VMK8055_CMD_WRT_AD;
781                         if (data[n] == 1)
782                                 tx_buf[reg] |= (1 << chan);
783                         else
784                                 tx_buf[reg] ^= (1 << chan);
785                 } else { /* VMK8061_MODEL */
786                         reg = VMK8061_DO_REG;
787                         if (data[n] == 1) {
788                                 cmd = VMK8061_CMD_SET_DO;
789                                 tx_buf[reg] = 1 << chan;
790                         } else {
791                                 cmd = VMK8061_CMD_CLR_DO;
792                                 tx_buf[reg] = 0xff - (1 << chan);
793                         }
794                 }
795
796                 if (vmk80xx_write_packet(devpriv, cmd))
797                         break;
798         }
799
800         up(&devpriv->limit_sem);
801
802         return n;
803 }
804
805 static int vmk80xx_do_rinsn(struct comedi_device *dev,
806                             struct comedi_subdevice *s,
807                             struct comedi_insn *insn, unsigned int *data)
808 {
809         struct vmk80xx_private *devpriv = dev->private;
810         int chan;
811         int reg;
812         int n;
813
814         n = rudimentary_check(devpriv, DIR_IN);
815         if (n)
816                 return n;
817
818         down(&devpriv->limit_sem);
819         chan = CR_CHAN(insn->chanspec);
820
821         reg = VMK8061_DO_REG;
822
823         devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_DO;
824
825         for (n = 0; n < insn->n; n++) {
826                 if (vmk80xx_read_packet(devpriv))
827                         break;
828
829                 data[n] = (devpriv->usb_rx_buf[reg] >> chan) & 1;
830         }
831
832         up(&devpriv->limit_sem);
833
834         return n;
835 }
836
837 static int vmk80xx_do_bits(struct comedi_device *dev,
838                            struct comedi_subdevice *s,
839                            struct comedi_insn *insn, unsigned int *data)
840 {
841         const struct vmk80xx_board *boardinfo = comedi_board(dev);
842         struct vmk80xx_private *devpriv = dev->private;
843         unsigned char *rx_buf, *tx_buf;
844         int dir, reg, cmd;
845         int retval;
846
847         dir = 0;
848
849         if (data[0])
850                 dir |= DIR_OUT;
851
852         if (boardinfo->model == VMK8061_MODEL)
853                 dir |= DIR_IN;
854
855         retval = rudimentary_check(devpriv, dir);
856         if (retval)
857                 return retval;
858
859         down(&devpriv->limit_sem);
860
861         rx_buf = devpriv->usb_rx_buf;
862         tx_buf = devpriv->usb_tx_buf;
863
864         if (data[0]) {
865                 if (boardinfo->model == VMK8055_MODEL) {
866                         reg = VMK8055_DO_REG;
867                         cmd = VMK8055_CMD_WRT_AD;
868                 } else { /* VMK8061_MODEL */
869                         reg = VMK8061_DO_REG;
870                         cmd = VMK8061_CMD_DO;
871                 }
872
873                 tx_buf[reg] &= ~data[0];
874                 tx_buf[reg] |= (data[0] & data[1]);
875
876                 retval = vmk80xx_write_packet(devpriv, cmd);
877
878                 if (retval)
879                         goto out;
880         }
881
882         if (boardinfo->model == VMK8061_MODEL) {
883                 reg = VMK8061_DO_REG;
884                 tx_buf[0] = VMK8061_CMD_RD_DO;
885
886                 retval = vmk80xx_read_packet(devpriv);
887
888                 if (!retval) {
889                         data[1] = rx_buf[reg];
890                         retval = 2;
891                 }
892         } else {
893                 data[1] = tx_buf[reg];
894                 retval = 2;
895         }
896
897 out:
898         up(&devpriv->limit_sem);
899
900         return retval;
901 }
902
903 static int vmk80xx_cnt_rinsn(struct comedi_device *dev,
904                              struct comedi_subdevice *s,
905                              struct comedi_insn *insn, unsigned int *data)
906 {
907         const struct vmk80xx_board *boardinfo = comedi_board(dev);
908         struct vmk80xx_private *devpriv = dev->private;
909         int chan;
910         int reg[2];
911         int n;
912
913         n = rudimentary_check(devpriv, DIR_IN);
914         if (n)
915                 return n;
916
917         down(&devpriv->limit_sem);
918         chan = CR_CHAN(insn->chanspec);
919
920         switch (boardinfo->model) {
921         case VMK8055_MODEL:
922                 if (!chan)
923                         reg[0] = VMK8055_CNT1_REG;
924                 else
925                         reg[0] = VMK8055_CNT2_REG;
926                 break;
927         case VMK8061_MODEL:
928         default:
929                 reg[0] = VMK8061_CNT_REG;
930                 reg[1] = VMK8061_CNT_REG;
931                 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_CNT;
932                 break;
933         }
934
935         for (n = 0; n < insn->n; n++) {
936                 if (vmk80xx_read_packet(devpriv))
937                         break;
938
939                 if (boardinfo->model == VMK8055_MODEL)
940                         data[n] = devpriv->usb_rx_buf[reg[0]];
941                 else /* VMK8061_MODEL */
942                         data[n] = devpriv->usb_rx_buf[reg[0] * (chan + 1) + 1]
943                             + 256 * devpriv->usb_rx_buf[reg[1] * 2 + 2];
944         }
945
946         up(&devpriv->limit_sem);
947
948         return n;
949 }
950
951 static int vmk80xx_cnt_cinsn(struct comedi_device *dev,
952                              struct comedi_subdevice *s,
953                              struct comedi_insn *insn, unsigned int *data)
954 {
955         const struct vmk80xx_board *boardinfo = comedi_board(dev);
956         struct vmk80xx_private *devpriv = dev->private;
957         unsigned int insn_cmd;
958         int chan;
959         int cmd;
960         int reg;
961         int n;
962
963         n = rudimentary_check(devpriv, DIR_OUT);
964         if (n)
965                 return n;
966
967         insn_cmd = data[0];
968         if (insn_cmd != INSN_CONFIG_RESET && insn_cmd != GPCT_RESET)
969                 return -EINVAL;
970
971         down(&devpriv->limit_sem);
972
973         chan = CR_CHAN(insn->chanspec);
974
975         if (boardinfo->model == VMK8055_MODEL) {
976                 if (!chan) {
977                         cmd = VMK8055_CMD_RST_CNT1;
978                         reg = VMK8055_CNT1_REG;
979                 } else {
980                         cmd = VMK8055_CMD_RST_CNT2;
981                         reg = VMK8055_CNT2_REG;
982                 }
983
984                 devpriv->usb_tx_buf[reg] = 0x00;
985         } else {
986                 cmd = VMK8061_CMD_RST_CNT;
987         }
988
989         for (n = 0; n < insn->n; n++)
990                 if (vmk80xx_write_packet(devpriv, cmd))
991                         break;
992
993         up(&devpriv->limit_sem);
994
995         return n;
996 }
997
998 static int vmk80xx_cnt_winsn(struct comedi_device *dev,
999                              struct comedi_subdevice *s,
1000                              struct comedi_insn *insn, unsigned int *data)
1001 {
1002         struct vmk80xx_private *devpriv = dev->private;
1003         unsigned long debtime;
1004         unsigned long val;
1005         int chan;
1006         int cmd;
1007         int n;
1008
1009         n = rudimentary_check(devpriv, DIR_OUT);
1010         if (n)
1011                 return n;
1012
1013         down(&devpriv->limit_sem);
1014         chan = CR_CHAN(insn->chanspec);
1015
1016         if (!chan)
1017                 cmd = VMK8055_CMD_DEB1_TIME;
1018         else
1019                 cmd = VMK8055_CMD_DEB2_TIME;
1020
1021         for (n = 0; n < insn->n; n++) {
1022                 debtime = data[n];
1023                 if (debtime == 0)
1024                         debtime = 1;
1025
1026                 /* TODO: Prevent overflows */
1027                 if (debtime > 7450)
1028                         debtime = 7450;
1029
1030                 val = int_sqrt(debtime * 1000 / 115);
1031                 if (((val + 1) * val) < debtime * 1000 / 115)
1032                         val += 1;
1033
1034                 devpriv->usb_tx_buf[6 + chan] = val;
1035
1036                 if (vmk80xx_write_packet(devpriv, cmd))
1037                         break;
1038         }
1039
1040         up(&devpriv->limit_sem);
1041
1042         return n;
1043 }
1044
1045 static int vmk80xx_pwm_rinsn(struct comedi_device *dev,
1046                              struct comedi_subdevice *s,
1047                              struct comedi_insn *insn, unsigned int *data)
1048 {
1049         struct vmk80xx_private *devpriv = dev->private;
1050         unsigned char *tx_buf;
1051         unsigned char *rx_buf;
1052         int reg[2];
1053         int n;
1054
1055         n = rudimentary_check(devpriv, DIR_IN);
1056         if (n)
1057                 return n;
1058
1059         down(&devpriv->limit_sem);
1060
1061         tx_buf = devpriv->usb_tx_buf;
1062         rx_buf = devpriv->usb_rx_buf;
1063
1064         reg[0] = VMK8061_PWM_REG1;
1065         reg[1] = VMK8061_PWM_REG2;
1066
1067         tx_buf[0] = VMK8061_CMD_RD_PWM;
1068
1069         for (n = 0; n < insn->n; n++) {
1070                 if (vmk80xx_read_packet(devpriv))
1071                         break;
1072
1073                 data[n] = rx_buf[reg[0]] + 4 * rx_buf[reg[1]];
1074         }
1075
1076         up(&devpriv->limit_sem);
1077
1078         return n;
1079 }
1080
1081 static int vmk80xx_pwm_winsn(struct comedi_device *dev,
1082                              struct comedi_subdevice *s,
1083                              struct comedi_insn *insn, unsigned int *data)
1084 {
1085         struct vmk80xx_private *devpriv = dev->private;
1086         unsigned char *tx_buf;
1087         int reg[2];
1088         int cmd;
1089         int n;
1090
1091         n = rudimentary_check(devpriv, DIR_OUT);
1092         if (n)
1093                 return n;
1094
1095         down(&devpriv->limit_sem);
1096
1097         tx_buf = devpriv->usb_tx_buf;
1098
1099         reg[0] = VMK8061_PWM_REG1;
1100         reg[1] = VMK8061_PWM_REG2;
1101
1102         cmd = VMK8061_CMD_OUT_PWM;
1103
1104         /*
1105          * The followin piece of code was translated from the inline
1106          * assembler code in the DLL source code.
1107          *
1108          * asm
1109          *   mov eax, k  ; k is the value (data[n])
1110          *   and al, 03h ; al are the lower 8 bits of eax
1111          *   mov lo, al  ; lo is the low part (tx_buf[reg[0]])
1112          *   mov eax, k
1113          *   shr eax, 2  ; right shift eax register by 2
1114          *   mov hi, al  ; hi is the high part (tx_buf[reg[1]])
1115          * end;
1116          */
1117         for (n = 0; n < insn->n; n++) {
1118                 tx_buf[reg[0]] = (unsigned char)(data[n] & 0x03);
1119                 tx_buf[reg[1]] = (unsigned char)(data[n] >> 2) & 0xff;
1120
1121                 if (vmk80xx_write_packet(devpriv, cmd))
1122                         break;
1123         }
1124
1125         up(&devpriv->limit_sem);
1126
1127         return n;
1128 }
1129
1130 static int vmk80xx_find_usb_endpoints(struct comedi_device *dev)
1131 {
1132         struct vmk80xx_private *devpriv = dev->private;
1133         struct usb_interface *intf = devpriv->intf;
1134         struct usb_host_interface *iface_desc = intf->cur_altsetting;
1135         struct usb_endpoint_descriptor *ep_desc;
1136         int i;
1137
1138         if (iface_desc->desc.bNumEndpoints != 2)
1139                 return -ENODEV;
1140
1141         for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
1142                 ep_desc = &iface_desc->endpoint[i].desc;
1143
1144                 if (usb_endpoint_is_int_in(ep_desc) ||
1145                     usb_endpoint_is_bulk_in(ep_desc)) {
1146                         if (!devpriv->ep_rx)
1147                                 devpriv->ep_rx = ep_desc;
1148                         continue;
1149                 }
1150
1151                 if (usb_endpoint_is_int_out(ep_desc) ||
1152                     usb_endpoint_is_bulk_out(ep_desc)) {
1153                         if (!devpriv->ep_tx)
1154                                 devpriv->ep_tx = ep_desc;
1155                         continue;
1156                 }
1157         }
1158
1159         if (!devpriv->ep_rx || !devpriv->ep_tx)
1160                 return -ENODEV;
1161
1162         return 0;
1163 }
1164
1165 static int vmk80xx_alloc_usb_buffers(struct comedi_device *dev)
1166 {
1167         struct vmk80xx_private *devpriv = dev->private;
1168         size_t size;
1169
1170         size = le16_to_cpu(devpriv->ep_rx->wMaxPacketSize);
1171         devpriv->usb_rx_buf = kmalloc(size, GFP_KERNEL);
1172         if (!devpriv->usb_rx_buf)
1173                 return -ENOMEM;
1174
1175         size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize);
1176         devpriv->usb_tx_buf = kmalloc(size, GFP_KERNEL);
1177         if (!devpriv->usb_tx_buf) {
1178                 kfree(devpriv->usb_rx_buf);
1179                 return -ENOMEM;
1180         }
1181
1182         return 0;
1183 }
1184
1185 static int vmk80xx_attach_common(struct comedi_device *dev)
1186 {
1187         const struct vmk80xx_board *boardinfo = comedi_board(dev);
1188         struct vmk80xx_private *devpriv = dev->private;
1189         struct comedi_subdevice *s;
1190         int n_subd;
1191         int ret;
1192
1193         down(&devpriv->limit_sem);
1194
1195         if (boardinfo->model == VMK8055_MODEL)
1196                 n_subd = 5;
1197         else
1198                 n_subd = 6;
1199         ret = comedi_alloc_subdevices(dev, n_subd);
1200         if (ret) {
1201                 up(&devpriv->limit_sem);
1202                 return ret;
1203         }
1204
1205         /* Analog input subdevice */
1206         s = &dev->subdevices[0];
1207         s->type = COMEDI_SUBD_AI;
1208         s->subdev_flags = SDF_READABLE | SDF_GROUND;
1209         s->n_chan = boardinfo->ai_chans;
1210         s->maxdata = (1 << boardinfo->ai_bits) - 1;
1211         s->range_table = boardinfo->range;
1212         s->insn_read = vmk80xx_ai_rinsn;
1213
1214         /* Analog output subdevice */
1215         s = &dev->subdevices[1];
1216         s->type = COMEDI_SUBD_AO;
1217         s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
1218         s->n_chan = boardinfo->ao_chans;
1219         s->maxdata = 0x00ff;
1220         s->range_table = boardinfo->range;
1221         s->insn_write = vmk80xx_ao_winsn;
1222         if (boardinfo->model == VMK8061_MODEL) {
1223                 s->subdev_flags |= SDF_READABLE;
1224                 s->insn_read = vmk80xx_ao_rinsn;
1225         }
1226
1227         /* Digital input subdevice */
1228         s = &dev->subdevices[2];
1229         s->type = COMEDI_SUBD_DI;
1230         s->subdev_flags = SDF_READABLE | SDF_GROUND;
1231         s->n_chan = boardinfo->di_chans;
1232         s->maxdata = 1;
1233         s->insn_read = vmk80xx_di_rinsn;
1234         s->insn_bits = vmk80xx_di_bits;
1235
1236         /* Digital output subdevice */
1237         s = &dev->subdevices[3];
1238         s->type = COMEDI_SUBD_DO;
1239         s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
1240         s->n_chan = 8;
1241         s->maxdata = 1;
1242         s->insn_write = vmk80xx_do_winsn;
1243         s->insn_bits = vmk80xx_do_bits;
1244         if (boardinfo->model == VMK8061_MODEL) {
1245                 s->subdev_flags |= SDF_READABLE;
1246                 s->insn_read = vmk80xx_do_rinsn;
1247         }
1248
1249         /* Counter subdevice */
1250         s = &dev->subdevices[4];
1251         s->type = COMEDI_SUBD_COUNTER;
1252         s->subdev_flags = SDF_READABLE;
1253         s->n_chan = 2;
1254         s->insn_read = vmk80xx_cnt_rinsn;
1255         s->insn_config = vmk80xx_cnt_cinsn;
1256         if (boardinfo->model == VMK8055_MODEL) {
1257                 s->subdev_flags |= SDF_WRITEABLE;
1258                 s->maxdata = (1 << boardinfo->cnt_bits) - 1;
1259                 s->insn_write = vmk80xx_cnt_winsn;
1260         }
1261
1262         /* PWM subdevice */
1263         if (boardinfo->model == VMK8061_MODEL) {
1264                 s = &dev->subdevices[5];
1265                 s->type = COMEDI_SUBD_PWM;
1266                 s->subdev_flags = SDF_READABLE | SDF_WRITEABLE;
1267                 s->n_chan = boardinfo->pwm_chans;
1268                 s->maxdata = (1 << boardinfo->pwm_bits) - 1;
1269                 s->insn_read = vmk80xx_pwm_rinsn;
1270                 s->insn_write = vmk80xx_pwm_winsn;
1271         }
1272
1273         up(&devpriv->limit_sem);
1274
1275         return 0;
1276 }
1277
1278 static int vmk80xx_auto_attach(struct comedi_device *dev,
1279                                unsigned long context)
1280 {
1281         struct usb_interface *intf = comedi_to_usb_interface(dev);
1282         const struct vmk80xx_board *boardinfo;
1283         struct vmk80xx_private *devpriv;
1284         int ret;
1285
1286         boardinfo = &vmk80xx_boardinfo[context];
1287         dev->board_ptr = boardinfo;
1288         dev->board_name = boardinfo->name;
1289
1290         devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
1291         if (!devpriv)
1292                 return -ENOMEM;
1293         dev->private = devpriv;
1294
1295         devpriv->usb = interface_to_usbdev(intf);
1296         devpriv->intf = intf;
1297         devpriv->board = boardinfo;
1298
1299         ret = vmk80xx_find_usb_endpoints(dev);
1300         if (ret)
1301                 return ret;
1302
1303         ret = vmk80xx_alloc_usb_buffers(dev);
1304         if (ret)
1305                 return ret;
1306
1307         sema_init(&devpriv->limit_sem, 8);
1308         init_waitqueue_head(&devpriv->read_wait);
1309         init_waitqueue_head(&devpriv->write_wait);
1310
1311         init_usb_anchor(&devpriv->rx_anchor);
1312         init_usb_anchor(&devpriv->tx_anchor);
1313
1314         usb_set_intfdata(intf, devpriv);
1315
1316         if (boardinfo->model == VMK8061_MODEL) {
1317                 vmk80xx_read_eeprom(devpriv, IC3_VERSION);
1318                 dev_info(&intf->dev, "%s\n", devpriv->fw.ic3_vers);
1319
1320                 if (vmk80xx_check_data_link(devpriv)) {
1321                         vmk80xx_read_eeprom(devpriv, IC6_VERSION);
1322                         dev_info(&intf->dev, "%s\n", devpriv->fw.ic6_vers);
1323                 } else {
1324                         dbgcm("comedi#: vmk80xx: no conn. to CPU\n");
1325                 }
1326         }
1327
1328         if (boardinfo->model == VMK8055_MODEL)
1329                 vmk80xx_reset_device(devpriv);
1330
1331         return vmk80xx_attach_common(dev);
1332 }
1333
1334 static void vmk80xx_detach(struct comedi_device *dev)
1335 {
1336         struct vmk80xx_private *devpriv = dev->private;
1337
1338         if (!devpriv)
1339                 return;
1340
1341         down(&devpriv->limit_sem);
1342
1343         usb_set_intfdata(devpriv->intf, NULL);
1344
1345         usb_kill_anchored_urbs(&devpriv->rx_anchor);
1346         usb_kill_anchored_urbs(&devpriv->tx_anchor);
1347
1348         kfree(devpriv->usb_rx_buf);
1349         kfree(devpriv->usb_tx_buf);
1350
1351         up(&devpriv->limit_sem);
1352 }
1353
1354 static struct comedi_driver vmk80xx_driver = {
1355         .module         = THIS_MODULE,
1356         .driver_name    = "vmk80xx",
1357         .auto_attach    = vmk80xx_auto_attach,
1358         .detach         = vmk80xx_detach,
1359 };
1360
1361 static int vmk80xx_usb_probe(struct usb_interface *intf,
1362                              const struct usb_device_id *id)
1363 {
1364         return comedi_usb_auto_config(intf, &vmk80xx_driver, id->driver_info);
1365 }
1366
1367 static const struct usb_device_id vmk80xx_usb_id_table[] = {
1368         { USB_DEVICE(0x10cf, 0x5500), .driver_info = DEVICE_VMK8055 },
1369         { USB_DEVICE(0x10cf, 0x5501), .driver_info = DEVICE_VMK8055 },
1370         { USB_DEVICE(0x10cf, 0x5502), .driver_info = DEVICE_VMK8055 },
1371         { USB_DEVICE(0x10cf, 0x5503), .driver_info = DEVICE_VMK8055 },
1372         { USB_DEVICE(0x10cf, 0x8061), .driver_info = DEVICE_VMK8061 },
1373         { USB_DEVICE(0x10cf, 0x8062), .driver_info = DEVICE_VMK8061 },
1374         { USB_DEVICE(0x10cf, 0x8063), .driver_info = DEVICE_VMK8061 },
1375         { USB_DEVICE(0x10cf, 0x8064), .driver_info = DEVICE_VMK8061 },
1376         { USB_DEVICE(0x10cf, 0x8065), .driver_info = DEVICE_VMK8061 },
1377         { USB_DEVICE(0x10cf, 0x8066), .driver_info = DEVICE_VMK8061 },
1378         { USB_DEVICE(0x10cf, 0x8067), .driver_info = DEVICE_VMK8061 },
1379         { USB_DEVICE(0x10cf, 0x8068), .driver_info = DEVICE_VMK8061 },
1380         { }
1381 };
1382 MODULE_DEVICE_TABLE(usb, vmk80xx_usb_id_table);
1383
1384 static struct usb_driver vmk80xx_usb_driver = {
1385         .name           = "vmk80xx",
1386         .id_table       = vmk80xx_usb_id_table,
1387         .probe          = vmk80xx_usb_probe,
1388         .disconnect     = comedi_usb_auto_unconfig,
1389 };
1390 module_comedi_usb_driver(vmk80xx_driver, vmk80xx_usb_driver);
1391
1392 MODULE_AUTHOR("Manuel Gebele <forensixs@gmx.de>");
1393 MODULE_DESCRIPTION("Velleman USB Board Low-Level Driver");
1394 MODULE_SUPPORTED_DEVICE("K8055/K8061 aka VM110/VM140");
1395 MODULE_VERSION("0.8.01");
1396 MODULE_LICENSE("GPL");