2 comedi/drivers/vmk80xx.c
3 Velleman USB Board Low-Level Driver
5 Copyright (C) 2009 Manuel Gebele <forensixs@gmx.de>, Germany
7 COMEDI - Linux Control and Measurement Device Interface
8 Copyright (C) 2000 David A. Schleef <ds@schleef.org>
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.
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.
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.
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
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
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
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>
65 #include "../comedidev.h"
67 #define BOARDNAME "vmk80xx"
69 MODULE_AUTHOR("Manuel Gebele <forensixs@gmx.de>");
70 MODULE_DESCRIPTION("Velleman USB Board Low-Level Driver");
71 MODULE_SUPPORTED_DEVICE("K8055/K8061 aka VM110/VM140");
72 MODULE_VERSION("0.8.01");
73 MODULE_LICENSE("GPL");
80 static const struct usb_device_id vmk80xx_id_table[] = {
81 {USB_DEVICE(0x10cf, 0x5500), .driver_info = DEVICE_VMK8055},
82 {USB_DEVICE(0x10cf, 0x5501), .driver_info = DEVICE_VMK8055},
83 {USB_DEVICE(0x10cf, 0x5502), .driver_info = DEVICE_VMK8055},
84 {USB_DEVICE(0x10cf, 0x5503), .driver_info = DEVICE_VMK8055},
85 {USB_DEVICE(0x10cf, 0x8061), .driver_info = DEVICE_VMK8061},
86 {USB_DEVICE(0x10cf, 0x8062), .driver_info = DEVICE_VMK8061},
87 {USB_DEVICE(0x10cf, 0x8063), .driver_info = DEVICE_VMK8061},
88 {USB_DEVICE(0x10cf, 0x8064), .driver_info = DEVICE_VMK8061},
89 {USB_DEVICE(0x10cf, 0x8065), .driver_info = DEVICE_VMK8061},
90 {USB_DEVICE(0x10cf, 0x8066), .driver_info = DEVICE_VMK8061},
91 {USB_DEVICE(0x10cf, 0x8067), .driver_info = DEVICE_VMK8061},
92 {USB_DEVICE(0x10cf, 0x8068), .driver_info = DEVICE_VMK8061},
93 {} /* terminating entry */
96 MODULE_DEVICE_TABLE(usb, vmk80xx_id_table);
98 #define VMK8055_DI_REG 0x00
99 #define VMK8055_DO_REG 0x01
100 #define VMK8055_AO1_REG 0x02
101 #define VMK8055_AO2_REG 0x03
102 #define VMK8055_AI1_REG 0x02
103 #define VMK8055_AI2_REG 0x03
104 #define VMK8055_CNT1_REG 0x04
105 #define VMK8055_CNT2_REG 0x06
107 #define VMK8061_CH_REG 0x01
108 #define VMK8061_DI_REG 0x01
109 #define VMK8061_DO_REG 0x01
110 #define VMK8061_PWM_REG1 0x01
111 #define VMK8061_PWM_REG2 0x02
112 #define VMK8061_CNT_REG 0x02
113 #define VMK8061_AO_REG 0x02
114 #define VMK8061_AI_REG1 0x02
115 #define VMK8061_AI_REG2 0x03
117 #define VMK8055_CMD_RST 0x00
118 #define VMK8055_CMD_DEB1_TIME 0x01
119 #define VMK8055_CMD_DEB2_TIME 0x02
120 #define VMK8055_CMD_RST_CNT1 0x03
121 #define VMK8055_CMD_RST_CNT2 0x04
122 #define VMK8055_CMD_WRT_AD 0x05
124 #define VMK8061_CMD_RD_AI 0x00
125 #define VMK8061_CMR_RD_ALL_AI 0x01 /* !non-active! */
126 #define VMK8061_CMD_SET_AO 0x02
127 #define VMK8061_CMD_SET_ALL_AO 0x03 /* !non-active! */
128 #define VMK8061_CMD_OUT_PWM 0x04
129 #define VMK8061_CMD_RD_DI 0x05
130 #define VMK8061_CMD_DO 0x06 /* !non-active! */
131 #define VMK8061_CMD_CLR_DO 0x07
132 #define VMK8061_CMD_SET_DO 0x08
133 #define VMK8061_CMD_RD_CNT 0x09 /* TODO: completely pointless? */
134 #define VMK8061_CMD_RST_CNT 0x0a /* TODO: completely pointless? */
135 #define VMK8061_CMD_RD_VERSION 0x0b /* internal usage */
136 #define VMK8061_CMD_RD_JMP_STAT 0x0c /* TODO: not implemented yet */
137 #define VMK8061_CMD_RD_PWR_STAT 0x0d /* internal usage */
138 #define VMK8061_CMD_RD_DO 0x0e
139 #define VMK8061_CMD_RD_AO 0x0f
140 #define VMK8061_CMD_RD_PWM 0x10
142 #define VMK80XX_MAX_BOARDS COMEDI_NUM_BOARD_MINORS
144 #define TRANS_OUT_BUSY 1
145 #define TRANS_IN_BUSY 2
146 #define TRANS_IN_RUNNING 3
148 #define IC3_VERSION (1 << 0)
149 #define IC6_VERSION (1 << 1)
151 #define URB_RCV_FLAG (1 << 0)
152 #define URB_SND_FLAG (1 << 1)
154 #ifdef CONFIG_COMEDI_DEBUG
155 static int dbgcm = 1;
160 #define dbgcm(fmt, arg...) \
163 printk(KERN_DEBUG fmt, ##arg); \
171 struct firmware_version {
172 unsigned char ic3_vers[32]; /* USB-Controller */
173 unsigned char ic6_vers[32]; /* CPU */
176 static const struct comedi_lrange vmk8055_range = {
180 static const struct comedi_lrange vmk8061_range = {
181 2, {UNI_RANGE(5), UNI_RANGE(10)}
184 struct vmk80xx_board {
186 enum vmk80xx_model model;
187 const struct comedi_lrange *range;
212 struct usb_device *udev;
213 struct usb_interface *intf;
214 struct usb_endpoint_descriptor *ep_rx;
215 struct usb_endpoint_descriptor *ep_tx;
216 struct usb_anchor rx_anchor;
217 struct usb_anchor tx_anchor;
218 struct vmk80xx_board board;
219 struct firmware_version fw;
220 struct semaphore limit_sem;
221 wait_queue_head_t read_wait;
222 wait_queue_head_t write_wait;
223 unsigned char *usb_rx_buf;
224 unsigned char *usb_tx_buf;
231 static struct vmk80xx_usb vmb[VMK80XX_MAX_BOARDS];
233 static DEFINE_MUTEX(glb_mutex);
235 static struct comedi_driver driver_vmk80xx; /* see below for initializer */
237 static void vmk80xx_tx_callback(struct urb *urb)
239 struct vmk80xx_usb *dev = urb->context;
240 int stat = urb->status;
242 if (stat && !(stat == -ENOENT
243 || stat == -ECONNRESET || stat == -ESHUTDOWN))
244 dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n",
247 if (!test_bit(TRANS_OUT_BUSY, &dev->flags))
250 clear_bit(TRANS_OUT_BUSY, &dev->flags);
252 wake_up_interruptible(&dev->write_wait);
255 static void vmk80xx_rx_callback(struct urb *urb)
257 struct vmk80xx_usb *dev = urb->context;
258 int stat = urb->status;
268 dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n",
275 if (test_bit(TRANS_IN_RUNNING, &dev->flags) && dev->intf) {
276 usb_anchor_urb(urb, &dev->rx_anchor);
278 if (!usb_submit_urb(urb, GFP_KERNEL))
281 dev_err(&urb->dev->dev,
282 "comedi#: vmk80xx: %s - submit urb failed\n",
285 usb_unanchor_urb(urb);
288 clear_bit(TRANS_IN_BUSY, &dev->flags);
290 wake_up_interruptible(&dev->read_wait);
293 static int vmk80xx_check_data_link(struct vmk80xx_usb *dev)
295 unsigned int tx_pipe;
296 unsigned int rx_pipe;
300 tx_pipe = usb_sndbulkpipe(dev->udev, 0x01);
301 rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81);
303 tx[0] = VMK8061_CMD_RD_PWR_STAT;
306 * Check that IC6 (PIC16F871) is powered and
307 * running and the data link between IC3 and
308 * IC6 is working properly
310 usb_bulk_msg(dev->udev, tx_pipe, tx, 1, NULL, dev->ep_tx->bInterval);
311 usb_bulk_msg(dev->udev, rx_pipe, rx, 2, NULL, HZ * 10);
316 static void vmk80xx_read_eeprom(struct vmk80xx_usb *dev, int flag)
318 unsigned int tx_pipe;
319 unsigned int rx_pipe;
321 unsigned char rx[64];
324 tx_pipe = usb_sndbulkpipe(dev->udev, 0x01);
325 rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81);
327 tx[0] = VMK8061_CMD_RD_VERSION;
330 * Read the firmware version info of IC3 and
331 * IC6 from the internal EEPROM of the IC
333 usb_bulk_msg(dev->udev, tx_pipe, tx, 1, NULL, dev->ep_tx->bInterval);
334 usb_bulk_msg(dev->udev, rx_pipe, rx, 64, &cnt, HZ * 10);
338 if (flag & IC3_VERSION)
339 strncpy(dev->fw.ic3_vers, rx + 1, 24);
340 else /* IC6_VERSION */
341 strncpy(dev->fw.ic6_vers, rx + 25, 24);
344 static int vmk80xx_reset_device(struct vmk80xx_usb *dev)
347 unsigned int tx_pipe;
351 urb = usb_alloc_urb(0, GFP_KERNEL);
355 tx_pipe = usb_sndintpipe(dev->udev, 0x01);
357 ival = dev->ep_tx->bInterval;
358 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
360 dev->usb_tx_buf[0] = VMK8055_CMD_RST;
361 dev->usb_tx_buf[1] = 0x00;
362 dev->usb_tx_buf[2] = 0x00;
363 dev->usb_tx_buf[3] = 0x00;
364 dev->usb_tx_buf[4] = 0x00;
365 dev->usb_tx_buf[5] = 0x00;
366 dev->usb_tx_buf[6] = 0x00;
367 dev->usb_tx_buf[7] = 0x00;
369 usb_fill_int_urb(urb, dev->udev, tx_pipe, dev->usb_tx_buf,
370 size, vmk80xx_tx_callback, dev, ival);
372 usb_anchor_urb(urb, &dev->tx_anchor);
374 return usb_submit_urb(urb, GFP_KERNEL);
377 static void vmk80xx_build_int_urb(struct urb *urb, int flag)
379 struct vmk80xx_usb *dev = urb->context;
385 void (*callback) (struct urb *);
388 if (flag & URB_RCV_FLAG) {
389 rx_addr = dev->ep_rx->bEndpointAddress;
390 pipe = usb_rcvintpipe(dev->udev, rx_addr);
391 buf = dev->usb_rx_buf;
392 size = le16_to_cpu(dev->ep_rx->wMaxPacketSize);
393 callback = vmk80xx_rx_callback;
394 ival = dev->ep_rx->bInterval;
395 } else { /* URB_SND_FLAG */
396 tx_addr = dev->ep_tx->bEndpointAddress;
397 pipe = usb_sndintpipe(dev->udev, tx_addr);
398 buf = dev->usb_tx_buf;
399 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
400 callback = vmk80xx_tx_callback;
401 ival = dev->ep_tx->bInterval;
404 usb_fill_int_urb(urb, dev->udev, pipe, buf, size, callback, dev, ival);
407 static void vmk80xx_do_bulk_msg(struct vmk80xx_usb *dev)
411 unsigned int tx_pipe;
412 unsigned int rx_pipe;
415 set_bit(TRANS_IN_BUSY, &dev->flags);
416 set_bit(TRANS_OUT_BUSY, &dev->flags);
418 tx_addr = dev->ep_tx->bEndpointAddress;
419 rx_addr = dev->ep_rx->bEndpointAddress;
420 tx_pipe = usb_sndbulkpipe(dev->udev, tx_addr);
421 rx_pipe = usb_rcvbulkpipe(dev->udev, rx_addr);
424 * The max packet size attributes of the K8061
425 * input/output endpoints are identical
427 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
429 usb_bulk_msg(dev->udev, tx_pipe, dev->usb_tx_buf,
430 size, NULL, dev->ep_tx->bInterval);
431 usb_bulk_msg(dev->udev, rx_pipe, dev->usb_rx_buf, size, NULL, HZ * 10);
433 clear_bit(TRANS_OUT_BUSY, &dev->flags);
434 clear_bit(TRANS_IN_BUSY, &dev->flags);
437 static int vmk80xx_read_packet(struct vmk80xx_usb *dev)
445 /* Only useful for interrupt transfers */
446 if (test_bit(TRANS_IN_BUSY, &dev->flags))
447 if (wait_event_interruptible(dev->read_wait,
448 !test_bit(TRANS_IN_BUSY,
452 if (dev->board.model == VMK8061_MODEL) {
453 vmk80xx_do_bulk_msg(dev);
458 urb = usb_alloc_urb(0, GFP_KERNEL);
463 vmk80xx_build_int_urb(urb, URB_RCV_FLAG);
465 set_bit(TRANS_IN_RUNNING, &dev->flags);
466 set_bit(TRANS_IN_BUSY, &dev->flags);
468 usb_anchor_urb(urb, &dev->rx_anchor);
470 retval = usb_submit_urb(urb, GFP_KERNEL);
474 clear_bit(TRANS_IN_RUNNING, &dev->flags);
475 usb_unanchor_urb(urb);
483 static int vmk80xx_write_packet(struct vmk80xx_usb *dev, int cmd)
491 if (test_bit(TRANS_OUT_BUSY, &dev->flags))
492 if (wait_event_interruptible(dev->write_wait,
493 !test_bit(TRANS_OUT_BUSY,
497 if (dev->board.model == VMK8061_MODEL) {
498 dev->usb_tx_buf[0] = cmd;
499 vmk80xx_do_bulk_msg(dev);
504 urb = usb_alloc_urb(0, GFP_KERNEL);
509 vmk80xx_build_int_urb(urb, URB_SND_FLAG);
511 set_bit(TRANS_OUT_BUSY, &dev->flags);
513 usb_anchor_urb(urb, &dev->tx_anchor);
515 dev->usb_tx_buf[0] = cmd;
517 retval = usb_submit_urb(urb, GFP_KERNEL);
521 clear_bit(TRANS_OUT_BUSY, &dev->flags);
522 usb_unanchor_urb(urb);
533 static int rudimentary_check(struct vmk80xx_usb *dev, int dir)
542 if (test_bit(TRANS_IN_BUSY, &dev->flags))
546 if (test_bit(TRANS_OUT_BUSY, &dev->flags))
553 static int vmk80xx_ai_rinsn(struct comedi_device *cdev,
554 struct comedi_subdevice *s,
555 struct comedi_insn *insn, unsigned int *data)
557 struct vmk80xx_usb *dev = cdev->private;
562 n = rudimentary_check(dev, DIR_IN);
566 down(&dev->limit_sem);
567 chan = CR_CHAN(insn->chanspec);
569 switch (dev->board.model) {
572 reg[0] = VMK8055_AI1_REG;
574 reg[0] = VMK8055_AI2_REG;
577 reg[0] = VMK8061_AI_REG1;
578 reg[1] = VMK8061_AI_REG2;
579 dev->usb_tx_buf[0] = VMK8061_CMD_RD_AI;
580 dev->usb_tx_buf[VMK8061_CH_REG] = chan;
584 for (n = 0; n < insn->n; n++) {
585 if (vmk80xx_read_packet(dev))
588 if (dev->board.model == VMK8055_MODEL) {
589 data[n] = dev->usb_rx_buf[reg[0]];
594 data[n] = dev->usb_rx_buf[reg[0]] + 256 *
595 dev->usb_rx_buf[reg[1]];
603 static int vmk80xx_ao_winsn(struct comedi_device *cdev,
604 struct comedi_subdevice *s,
605 struct comedi_insn *insn, unsigned int *data)
607 struct vmk80xx_usb *dev = cdev->private;
613 n = rudimentary_check(dev, DIR_OUT);
617 down(&dev->limit_sem);
618 chan = CR_CHAN(insn->chanspec);
620 switch (dev->board.model) {
622 cmd = VMK8055_CMD_WRT_AD;
624 reg = VMK8055_AO1_REG;
626 reg = VMK8055_AO2_REG;
628 default: /* NOTE: avoid compiler warnings */
629 cmd = VMK8061_CMD_SET_AO;
630 reg = VMK8061_AO_REG;
631 dev->usb_tx_buf[VMK8061_CH_REG] = chan;
635 for (n = 0; n < insn->n; n++) {
636 dev->usb_tx_buf[reg] = data[n];
638 if (vmk80xx_write_packet(dev, cmd))
647 static int vmk80xx_ao_rinsn(struct comedi_device *cdev,
648 struct comedi_subdevice *s,
649 struct comedi_insn *insn, unsigned int *data)
651 struct vmk80xx_usb *dev = cdev->private;
656 n = rudimentary_check(dev, DIR_IN);
660 down(&dev->limit_sem);
661 chan = CR_CHAN(insn->chanspec);
663 reg = VMK8061_AO_REG - 1;
665 dev->usb_tx_buf[0] = VMK8061_CMD_RD_AO;
667 for (n = 0; n < insn->n; n++) {
668 if (vmk80xx_read_packet(dev))
671 data[n] = dev->usb_rx_buf[reg + chan];
679 static int vmk80xx_di_bits(struct comedi_device *cdev,
680 struct comedi_subdevice *s,
681 struct comedi_insn *insn, unsigned int *data)
683 struct vmk80xx_usb *dev = cdev->private;
684 unsigned char *rx_buf;
688 retval = rudimentary_check(dev, DIR_IN);
692 down(&dev->limit_sem);
694 rx_buf = dev->usb_rx_buf;
696 if (dev->board.model == VMK8061_MODEL) {
697 reg = VMK8061_DI_REG;
698 dev->usb_tx_buf[0] = VMK8061_CMD_RD_DI;
700 reg = VMK8055_DI_REG;
703 retval = vmk80xx_read_packet(dev);
706 if (dev->board.model == VMK8055_MODEL)
707 data[1] = (((rx_buf[reg] >> 4) & 0x03) |
708 ((rx_buf[reg] << 2) & 0x04) |
709 ((rx_buf[reg] >> 3) & 0x18));
711 data[1] = rx_buf[reg];
721 static int vmk80xx_di_rinsn(struct comedi_device *cdev,
722 struct comedi_subdevice *s,
723 struct comedi_insn *insn, unsigned int *data)
725 struct vmk80xx_usb *dev = cdev->private;
727 unsigned char *rx_buf;
732 n = rudimentary_check(dev, DIR_IN);
736 down(&dev->limit_sem);
737 chan = CR_CHAN(insn->chanspec);
739 rx_buf = dev->usb_rx_buf;
741 if (dev->board.model == VMK8061_MODEL) {
742 reg = VMK8061_DI_REG;
743 dev->usb_tx_buf[0] = VMK8061_CMD_RD_DI;
745 reg = VMK8055_DI_REG;
747 for (n = 0; n < insn->n; n++) {
748 if (vmk80xx_read_packet(dev))
751 if (dev->board.model == VMK8055_MODEL)
752 inp = (((rx_buf[reg] >> 4) & 0x03) |
753 ((rx_buf[reg] << 2) & 0x04) |
754 ((rx_buf[reg] >> 3) & 0x18));
758 data[n] = (inp >> chan) & 1;
766 static int vmk80xx_do_winsn(struct comedi_device *cdev,
767 struct comedi_subdevice *s,
768 struct comedi_insn *insn, unsigned int *data)
770 struct vmk80xx_usb *dev = cdev->private;
772 unsigned char *tx_buf;
777 n = rudimentary_check(dev, DIR_OUT);
781 down(&dev->limit_sem);
782 chan = CR_CHAN(insn->chanspec);
784 tx_buf = dev->usb_tx_buf;
786 for (n = 0; n < insn->n; n++) {
787 if (dev->board.model == VMK8055_MODEL) {
788 reg = VMK8055_DO_REG;
789 cmd = VMK8055_CMD_WRT_AD;
791 tx_buf[reg] |= (1 << chan);
793 tx_buf[reg] ^= (1 << chan);
794 } else { /* VMK8061_MODEL */
795 reg = VMK8061_DO_REG;
797 cmd = VMK8061_CMD_SET_DO;
798 tx_buf[reg] = 1 << chan;
800 cmd = VMK8061_CMD_CLR_DO;
801 tx_buf[reg] = 0xff - (1 << chan);
805 if (vmk80xx_write_packet(dev, cmd))
814 static int vmk80xx_do_rinsn(struct comedi_device *cdev,
815 struct comedi_subdevice *s,
816 struct comedi_insn *insn, unsigned int *data)
818 struct vmk80xx_usb *dev = cdev->private;
823 n = rudimentary_check(dev, DIR_IN);
827 down(&dev->limit_sem);
828 chan = CR_CHAN(insn->chanspec);
830 reg = VMK8061_DO_REG;
832 dev->usb_tx_buf[0] = VMK8061_CMD_RD_DO;
834 for (n = 0; n < insn->n; n++) {
835 if (vmk80xx_read_packet(dev))
838 data[n] = (dev->usb_rx_buf[reg] >> chan) & 1;
846 static int vmk80xx_do_bits(struct comedi_device *cdev,
847 struct comedi_subdevice *s,
848 struct comedi_insn *insn, unsigned int *data)
850 struct vmk80xx_usb *dev = cdev->private;
851 unsigned char *rx_buf, *tx_buf;
860 if (dev->board.model == VMK8061_MODEL)
863 retval = rudimentary_check(dev, dir);
867 down(&dev->limit_sem);
869 rx_buf = dev->usb_rx_buf;
870 tx_buf = dev->usb_tx_buf;
873 if (dev->board.model == VMK8055_MODEL) {
874 reg = VMK8055_DO_REG;
875 cmd = VMK8055_CMD_WRT_AD;
876 } else { /* VMK8061_MODEL */
877 reg = VMK8061_DO_REG;
878 cmd = VMK8061_CMD_DO;
881 tx_buf[reg] &= ~data[0];
882 tx_buf[reg] |= (data[0] & data[1]);
884 retval = vmk80xx_write_packet(dev, cmd);
890 if (dev->board.model == VMK8061_MODEL) {
891 reg = VMK8061_DO_REG;
892 tx_buf[0] = VMK8061_CMD_RD_DO;
894 retval = vmk80xx_read_packet(dev);
897 data[1] = rx_buf[reg];
901 data[1] = tx_buf[reg];
911 static int vmk80xx_cnt_rinsn(struct comedi_device *cdev,
912 struct comedi_subdevice *s,
913 struct comedi_insn *insn, unsigned int *data)
915 struct vmk80xx_usb *dev = cdev->private;
920 n = rudimentary_check(dev, DIR_IN);
924 down(&dev->limit_sem);
925 chan = CR_CHAN(insn->chanspec);
927 switch (dev->board.model) {
930 reg[0] = VMK8055_CNT1_REG;
932 reg[0] = VMK8055_CNT2_REG;
935 reg[0] = VMK8061_CNT_REG;
936 reg[1] = VMK8061_CNT_REG;
937 dev->usb_tx_buf[0] = VMK8061_CMD_RD_CNT;
941 for (n = 0; n < insn->n; n++) {
942 if (vmk80xx_read_packet(dev))
945 if (dev->board.model == VMK8055_MODEL)
946 data[n] = dev->usb_rx_buf[reg[0]];
947 else /* VMK8061_MODEL */
948 data[n] = dev->usb_rx_buf[reg[0] * (chan + 1) + 1]
949 + 256 * dev->usb_rx_buf[reg[1] * 2 + 2];
957 static int vmk80xx_cnt_cinsn(struct comedi_device *cdev,
958 struct comedi_subdevice *s,
959 struct comedi_insn *insn, unsigned int *data)
961 struct vmk80xx_usb *dev = cdev->private;
962 unsigned int insn_cmd;
968 n = rudimentary_check(dev, DIR_OUT);
973 if (insn_cmd != INSN_CONFIG_RESET && insn_cmd != GPCT_RESET)
976 down(&dev->limit_sem);
978 chan = CR_CHAN(insn->chanspec);
980 if (dev->board.model == VMK8055_MODEL) {
982 cmd = VMK8055_CMD_RST_CNT1;
983 reg = VMK8055_CNT1_REG;
985 cmd = VMK8055_CMD_RST_CNT2;
986 reg = VMK8055_CNT2_REG;
989 dev->usb_tx_buf[reg] = 0x00;
991 cmd = VMK8061_CMD_RST_CNT;
994 for (n = 0; n < insn->n; n++)
995 if (vmk80xx_write_packet(dev, cmd))
1003 static int vmk80xx_cnt_winsn(struct comedi_device *cdev,
1004 struct comedi_subdevice *s,
1005 struct comedi_insn *insn, unsigned int *data)
1007 struct vmk80xx_usb *dev = cdev->private;
1008 unsigned long debtime;
1014 n = rudimentary_check(dev, DIR_OUT);
1018 down(&dev->limit_sem);
1019 chan = CR_CHAN(insn->chanspec);
1022 cmd = VMK8055_CMD_DEB1_TIME;
1024 cmd = VMK8055_CMD_DEB2_TIME;
1026 for (n = 0; n < insn->n; n++) {
1031 /* TODO: Prevent overflows */
1035 val = int_sqrt(debtime * 1000 / 115);
1036 if (((val + 1) * val) < debtime * 1000 / 115)
1039 dev->usb_tx_buf[6 + chan] = val;
1041 if (vmk80xx_write_packet(dev, cmd))
1045 up(&dev->limit_sem);
1050 static int vmk80xx_pwm_rinsn(struct comedi_device *cdev,
1051 struct comedi_subdevice *s,
1052 struct comedi_insn *insn, unsigned int *data)
1054 struct vmk80xx_usb *dev = cdev->private;
1058 n = rudimentary_check(dev, DIR_IN);
1062 down(&dev->limit_sem);
1064 reg[0] = VMK8061_PWM_REG1;
1065 reg[1] = VMK8061_PWM_REG2;
1067 dev->usb_tx_buf[0] = VMK8061_CMD_RD_PWM;
1069 for (n = 0; n < insn->n; n++) {
1070 if (vmk80xx_read_packet(dev))
1073 data[n] = dev->usb_rx_buf[reg[0]] + 4 * dev->usb_rx_buf[reg[1]];
1076 up(&dev->limit_sem);
1081 static int vmk80xx_pwm_winsn(struct comedi_device *cdev,
1082 struct comedi_subdevice *s,
1083 struct comedi_insn *insn, unsigned int *data)
1085 struct vmk80xx_usb *dev = cdev->private;
1086 unsigned char *tx_buf;
1091 n = rudimentary_check(dev, DIR_OUT);
1095 down(&dev->limit_sem);
1097 tx_buf = dev->usb_tx_buf;
1099 reg[0] = VMK8061_PWM_REG1;
1100 reg[1] = VMK8061_PWM_REG2;
1102 cmd = VMK8061_CMD_OUT_PWM;
1105 * The followin piece of code was translated from the inline
1106 * assembler code in the DLL source code.
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]])
1113 * shr eax, 2 ; right shift eax register by 2
1114 * mov hi, al ; hi is the high part (tx_buf[reg[1]])
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;
1121 if (vmk80xx_write_packet(dev, cmd))
1125 up(&dev->limit_sem);
1130 static int vmk80xx_attach(struct comedi_device *cdev,
1131 struct comedi_devconfig *it)
1134 struct vmk80xx_usb *dev;
1136 struct comedi_subdevice *s;
1140 mutex_lock(&glb_mutex);
1142 for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
1143 if (vmb[i].probed && !vmb[i].attached)
1146 if (i == VMK80XX_MAX_BOARDS) {
1147 mutex_unlock(&glb_mutex);
1153 down(&dev->limit_sem);
1155 cdev->board_name = dev->board.name;
1156 cdev->private = dev;
1158 if (dev->board.model == VMK8055_MODEL)
1163 ret = comedi_alloc_subdevices(cdev, n_subd);
1165 up(&dev->limit_sem);
1166 mutex_unlock(&glb_mutex);
1170 /* Analog input subdevice */
1171 s = cdev->subdevices + VMK80XX_SUBD_AI;
1172 s->type = COMEDI_SUBD_AI;
1173 s->subdev_flags = SDF_READABLE | SDF_GROUND;
1174 s->n_chan = dev->board.ai_chans;
1175 s->maxdata = (1 << dev->board.ai_bits) - 1;
1176 s->range_table = dev->board.range;
1177 s->insn_read = vmk80xx_ai_rinsn;
1179 /* Analog output subdevice */
1180 s = cdev->subdevices + VMK80XX_SUBD_AO;
1181 s->type = COMEDI_SUBD_AO;
1182 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
1183 s->n_chan = dev->board.ao_chans;
1184 s->maxdata = (1 << dev->board.ao_bits) - 1;
1185 s->range_table = dev->board.range;
1186 s->insn_write = vmk80xx_ao_winsn;
1188 if (dev->board.model == VMK8061_MODEL) {
1189 s->subdev_flags |= SDF_READABLE;
1190 s->insn_read = vmk80xx_ao_rinsn;
1193 /* Digital input subdevice */
1194 s = cdev->subdevices + VMK80XX_SUBD_DI;
1195 s->type = COMEDI_SUBD_DI;
1196 s->subdev_flags = SDF_READABLE | SDF_GROUND;
1197 s->n_chan = dev->board.di_chans;
1199 s->insn_read = vmk80xx_di_rinsn;
1200 s->insn_bits = vmk80xx_di_bits;
1202 /* Digital output subdevice */
1203 s = cdev->subdevices + VMK80XX_SUBD_DO;
1204 s->type = COMEDI_SUBD_DO;
1205 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
1206 s->n_chan = dev->board.do_chans;
1208 s->insn_write = vmk80xx_do_winsn;
1209 s->insn_bits = vmk80xx_do_bits;
1211 if (dev->board.model == VMK8061_MODEL) {
1212 s->subdev_flags |= SDF_READABLE;
1213 s->insn_read = vmk80xx_do_rinsn;
1216 /* Counter subdevice */
1217 s = cdev->subdevices + VMK80XX_SUBD_CNT;
1218 s->type = COMEDI_SUBD_COUNTER;
1219 s->subdev_flags = SDF_READABLE;
1220 s->n_chan = dev->board.cnt_chans;
1221 s->insn_read = vmk80xx_cnt_rinsn;
1222 s->insn_config = vmk80xx_cnt_cinsn;
1224 if (dev->board.model == VMK8055_MODEL) {
1225 s->subdev_flags |= SDF_WRITEABLE;
1226 s->maxdata = (1 << dev->board.cnt_bits) - 1;
1227 s->insn_write = vmk80xx_cnt_winsn;
1231 if (dev->board.model == VMK8061_MODEL) {
1232 s = cdev->subdevices + VMK80XX_SUBD_PWM;
1233 s->type = COMEDI_SUBD_PWM;
1234 s->subdev_flags = SDF_READABLE | SDF_WRITEABLE;
1235 s->n_chan = dev->board.pwm_chans;
1236 s->maxdata = (1 << dev->board.pwm_bits) - 1;
1237 s->insn_read = vmk80xx_pwm_rinsn;
1238 s->insn_write = vmk80xx_pwm_winsn;
1243 minor = cdev->minor;
1246 "comedi%d: vmk80xx: board #%d [%s] attached to comedi\n",
1247 minor, dev->count, dev->board.name);
1249 up(&dev->limit_sem);
1250 mutex_unlock(&glb_mutex);
1255 static void vmk80xx_detach(struct comedi_device *dev)
1257 struct vmk80xx_usb *usb = dev->private;
1260 down(&usb->limit_sem);
1261 dev->private = NULL;
1263 up(&usb->limit_sem);
1267 static int vmk80xx_probe(struct usb_interface *intf,
1268 const struct usb_device_id *id)
1271 struct vmk80xx_usb *dev;
1272 struct usb_host_interface *iface_desc;
1273 struct usb_endpoint_descriptor *ep_desc;
1276 mutex_lock(&glb_mutex);
1278 for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
1282 if (i == VMK80XX_MAX_BOARDS) {
1283 mutex_unlock(&glb_mutex);
1289 memset(dev, 0x00, sizeof(struct vmk80xx_usb));
1292 iface_desc = intf->cur_altsetting;
1293 if (iface_desc->desc.bNumEndpoints != 2)
1296 for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
1297 ep_desc = &iface_desc->endpoint[i].desc;
1299 if (usb_endpoint_is_int_in(ep_desc)) {
1300 dev->ep_rx = ep_desc;
1304 if (usb_endpoint_is_int_out(ep_desc)) {
1305 dev->ep_tx = ep_desc;
1309 if (usb_endpoint_is_bulk_in(ep_desc)) {
1310 dev->ep_rx = ep_desc;
1314 if (usb_endpoint_is_bulk_out(ep_desc)) {
1315 dev->ep_tx = ep_desc;
1320 if (!dev->ep_rx || !dev->ep_tx)
1323 size = le16_to_cpu(dev->ep_rx->wMaxPacketSize);
1324 dev->usb_rx_buf = kmalloc(size, GFP_KERNEL);
1325 if (!dev->usb_rx_buf) {
1326 mutex_unlock(&glb_mutex);
1330 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
1331 dev->usb_tx_buf = kmalloc(size, GFP_KERNEL);
1332 if (!dev->usb_tx_buf) {
1333 kfree(dev->usb_rx_buf);
1334 mutex_unlock(&glb_mutex);
1338 dev->udev = interface_to_usbdev(intf);
1341 sema_init(&dev->limit_sem, 8);
1342 init_waitqueue_head(&dev->read_wait);
1343 init_waitqueue_head(&dev->write_wait);
1345 init_usb_anchor(&dev->rx_anchor);
1346 init_usb_anchor(&dev->tx_anchor);
1348 usb_set_intfdata(intf, dev);
1350 switch (id->driver_info) {
1351 case DEVICE_VMK8055:
1352 dev->board.name = "K8055 (VM110)";
1353 dev->board.model = VMK8055_MODEL;
1354 dev->board.range = &vmk8055_range;
1355 dev->board.ai_chans = 2;
1356 dev->board.ai_bits = 8;
1357 dev->board.ao_chans = 2;
1358 dev->board.ao_bits = 8;
1359 dev->board.di_chans = 5;
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 = 16;
1365 dev->board.pwm_chans = 0;
1366 dev->board.pwm_bits = 0;
1368 case DEVICE_VMK8061:
1369 dev->board.name = "K8061 (VM140)";
1370 dev->board.model = VMK8061_MODEL;
1371 dev->board.range = &vmk8061_range;
1372 dev->board.ai_chans = 8;
1373 dev->board.ai_bits = 10;
1374 dev->board.ao_chans = 8;
1375 dev->board.ao_bits = 8;
1376 dev->board.di_chans = 8;
1377 dev->board.di_bits = 1;
1378 dev->board.do_chans = 8;
1379 dev->board.do_bits = 1;
1380 dev->board.cnt_chans = 2;
1381 dev->board.cnt_bits = 0;
1382 dev->board.pwm_chans = 1;
1383 dev->board.pwm_bits = 10;
1387 if (dev->board.model == VMK8061_MODEL) {
1388 vmk80xx_read_eeprom(dev, IC3_VERSION);
1389 printk(KERN_INFO "comedi#: vmk80xx: %s\n", dev->fw.ic3_vers);
1391 if (vmk80xx_check_data_link(dev)) {
1392 vmk80xx_read_eeprom(dev, IC6_VERSION);
1393 printk(KERN_INFO "comedi#: vmk80xx: %s\n",
1396 dbgcm("comedi#: vmk80xx: no conn. to CPU\n");
1400 if (dev->board.model == VMK8055_MODEL)
1401 vmk80xx_reset_device(dev);
1405 printk(KERN_INFO "comedi#: vmk80xx: board #%d [%s] now attached\n",
1406 dev->count, dev->board.name);
1408 mutex_unlock(&glb_mutex);
1410 comedi_usb_auto_config(intf, &driver_vmk80xx);
1414 mutex_unlock(&glb_mutex);
1419 static void vmk80xx_disconnect(struct usb_interface *intf)
1421 struct vmk80xx_usb *dev = usb_get_intfdata(intf);
1426 comedi_usb_auto_unconfig(intf);
1428 mutex_lock(&glb_mutex);
1429 down(&dev->limit_sem);
1432 usb_set_intfdata(dev->intf, NULL);
1434 usb_kill_anchored_urbs(&dev->rx_anchor);
1435 usb_kill_anchored_urbs(&dev->tx_anchor);
1437 kfree(dev->usb_rx_buf);
1438 kfree(dev->usb_tx_buf);
1440 printk(KERN_INFO "comedi#: vmk80xx: board #%d [%s] now detached\n",
1441 dev->count, dev->board.name);
1443 up(&dev->limit_sem);
1444 mutex_unlock(&glb_mutex);
1447 /* TODO: Add support for suspend, resume, pre_reset,
1448 * post_reset and flush */
1449 static struct usb_driver vmk80xx_driver = {
1451 .probe = vmk80xx_probe,
1452 .disconnect = vmk80xx_disconnect,
1453 .id_table = vmk80xx_id_table
1456 static struct comedi_driver driver_vmk80xx = {
1457 .module = THIS_MODULE,
1458 .driver_name = "vmk80xx",
1459 .attach = vmk80xx_attach,
1460 .detach = vmk80xx_detach
1463 static int __init vmk80xx_init(void)
1467 printk(KERN_INFO "vmk80xx: version 0.8.01 "
1468 "Manuel Gebele <forensixs@gmx.de>\n");
1470 retval = comedi_driver_register(&driver_vmk80xx);
1474 return usb_register(&vmk80xx_driver);
1477 static void __exit vmk80xx_exit(void)
1479 comedi_driver_unregister(&driver_vmk80xx);
1480 usb_deregister(&vmk80xx_driver);
1483 module_init(vmk80xx_init);
1484 module_exit(vmk80xx_exit);