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"
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
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
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
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
116 #define VMK80XX_MAX_BOARDS COMEDI_NUM_BOARD_MINORS
118 #define TRANS_OUT_BUSY 1
119 #define TRANS_IN_BUSY 2
120 #define TRANS_IN_RUNNING 3
122 #define IC3_VERSION (1 << 0)
123 #define IC6_VERSION (1 << 1)
125 #define URB_RCV_FLAG (1 << 0)
126 #define URB_SND_FLAG (1 << 1)
128 #ifdef CONFIG_COMEDI_DEBUG
129 static int dbgcm = 1;
134 #define dbgcm(fmt, arg...) \
137 printk(KERN_DEBUG fmt, ##arg); \
145 struct firmware_version {
146 unsigned char ic3_vers[32]; /* USB-Controller */
147 unsigned char ic6_vers[32]; /* CPU */
150 static const struct comedi_lrange vmk8055_range = {
154 static const struct comedi_lrange vmk8061_range = {
155 2, {UNI_RANGE(5), UNI_RANGE(10)}
158 struct vmk80xx_board {
160 enum vmk80xx_model model;
161 const struct comedi_lrange *range;
171 static const struct vmk80xx_board vmk80xx_boardinfo[] = {
173 .name = "K8055 (VM110)",
174 .model = VMK8055_MODEL,
175 .range = &vmk8055_range,
185 .name = "K8061 (VM140)",
186 .model = VMK8061_MODEL,
187 .range = &vmk8061_range,
198 struct vmk80xx_private {
199 struct usb_device *udev;
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;
218 static struct vmk80xx_private vmb[VMK80XX_MAX_BOARDS];
220 static DEFINE_MUTEX(glb_mutex);
222 static void vmk80xx_tx_callback(struct urb *urb)
224 struct vmk80xx_private *dev = urb->context;
225 int stat = urb->status;
227 if (stat && !(stat == -ENOENT
228 || stat == -ECONNRESET || stat == -ESHUTDOWN))
229 dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n",
232 if (!test_bit(TRANS_OUT_BUSY, &dev->flags))
235 clear_bit(TRANS_OUT_BUSY, &dev->flags);
237 wake_up_interruptible(&dev->write_wait);
240 static void vmk80xx_rx_callback(struct urb *urb)
242 struct vmk80xx_private *dev = urb->context;
243 int stat = urb->status;
253 dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n",
260 if (test_bit(TRANS_IN_RUNNING, &dev->flags) && dev->intf) {
261 usb_anchor_urb(urb, &dev->rx_anchor);
263 if (!usb_submit_urb(urb, GFP_KERNEL))
266 dev_err(&urb->dev->dev,
267 "comedi#: vmk80xx: %s - submit urb failed\n",
270 usb_unanchor_urb(urb);
273 clear_bit(TRANS_IN_BUSY, &dev->flags);
275 wake_up_interruptible(&dev->read_wait);
278 static int vmk80xx_check_data_link(struct vmk80xx_private *dev)
280 unsigned int tx_pipe;
281 unsigned int rx_pipe;
285 tx_pipe = usb_sndbulkpipe(dev->udev, 0x01);
286 rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81);
288 tx[0] = VMK8061_CMD_RD_PWR_STAT;
291 * Check that IC6 (PIC16F871) is powered and
292 * running and the data link between IC3 and
293 * IC6 is working properly
295 usb_bulk_msg(dev->udev, tx_pipe, tx, 1, NULL, dev->ep_tx->bInterval);
296 usb_bulk_msg(dev->udev, rx_pipe, rx, 2, NULL, HZ * 10);
301 static void vmk80xx_read_eeprom(struct vmk80xx_private *dev, int flag)
303 unsigned int tx_pipe;
304 unsigned int rx_pipe;
306 unsigned char rx[64];
309 tx_pipe = usb_sndbulkpipe(dev->udev, 0x01);
310 rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81);
312 tx[0] = VMK8061_CMD_RD_VERSION;
315 * Read the firmware version info of IC3 and
316 * IC6 from the internal EEPROM of the IC
318 usb_bulk_msg(dev->udev, tx_pipe, tx, 1, NULL, dev->ep_tx->bInterval);
319 usb_bulk_msg(dev->udev, rx_pipe, rx, 64, &cnt, HZ * 10);
323 if (flag & IC3_VERSION)
324 strncpy(dev->fw.ic3_vers, rx + 1, 24);
325 else /* IC6_VERSION */
326 strncpy(dev->fw.ic6_vers, rx + 25, 24);
329 static int vmk80xx_reset_device(struct vmk80xx_private *dev)
332 unsigned int tx_pipe;
336 urb = usb_alloc_urb(0, GFP_KERNEL);
340 tx_pipe = usb_sndintpipe(dev->udev, 0x01);
342 ival = dev->ep_tx->bInterval;
343 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
345 dev->usb_tx_buf[0] = VMK8055_CMD_RST;
346 dev->usb_tx_buf[1] = 0x00;
347 dev->usb_tx_buf[2] = 0x00;
348 dev->usb_tx_buf[3] = 0x00;
349 dev->usb_tx_buf[4] = 0x00;
350 dev->usb_tx_buf[5] = 0x00;
351 dev->usb_tx_buf[6] = 0x00;
352 dev->usb_tx_buf[7] = 0x00;
354 usb_fill_int_urb(urb, dev->udev, tx_pipe, dev->usb_tx_buf,
355 size, vmk80xx_tx_callback, dev, ival);
357 usb_anchor_urb(urb, &dev->tx_anchor);
359 return usb_submit_urb(urb, GFP_KERNEL);
362 static void vmk80xx_build_int_urb(struct urb *urb, int flag)
364 struct vmk80xx_private *dev = urb->context;
370 void (*callback) (struct urb *);
373 if (flag & URB_RCV_FLAG) {
374 rx_addr = dev->ep_rx->bEndpointAddress;
375 pipe = usb_rcvintpipe(dev->udev, rx_addr);
376 buf = dev->usb_rx_buf;
377 size = le16_to_cpu(dev->ep_rx->wMaxPacketSize);
378 callback = vmk80xx_rx_callback;
379 ival = dev->ep_rx->bInterval;
380 } else { /* URB_SND_FLAG */
381 tx_addr = dev->ep_tx->bEndpointAddress;
382 pipe = usb_sndintpipe(dev->udev, tx_addr);
383 buf = dev->usb_tx_buf;
384 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
385 callback = vmk80xx_tx_callback;
386 ival = dev->ep_tx->bInterval;
389 usb_fill_int_urb(urb, dev->udev, pipe, buf, size, callback, dev, ival);
392 static void vmk80xx_do_bulk_msg(struct vmk80xx_private *dev)
396 unsigned int tx_pipe;
397 unsigned int rx_pipe;
400 set_bit(TRANS_IN_BUSY, &dev->flags);
401 set_bit(TRANS_OUT_BUSY, &dev->flags);
403 tx_addr = dev->ep_tx->bEndpointAddress;
404 rx_addr = dev->ep_rx->bEndpointAddress;
405 tx_pipe = usb_sndbulkpipe(dev->udev, tx_addr);
406 rx_pipe = usb_rcvbulkpipe(dev->udev, rx_addr);
409 * The max packet size attributes of the K8061
410 * input/output endpoints are identical
412 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
414 usb_bulk_msg(dev->udev, tx_pipe, dev->usb_tx_buf,
415 size, NULL, dev->ep_tx->bInterval);
416 usb_bulk_msg(dev->udev, rx_pipe, dev->usb_rx_buf, size, NULL, HZ * 10);
418 clear_bit(TRANS_OUT_BUSY, &dev->flags);
419 clear_bit(TRANS_IN_BUSY, &dev->flags);
422 static int vmk80xx_read_packet(struct vmk80xx_private *dev)
424 const struct vmk80xx_board *boardinfo = dev->board;
431 /* Only useful for interrupt transfers */
432 if (test_bit(TRANS_IN_BUSY, &dev->flags))
433 if (wait_event_interruptible(dev->read_wait,
434 !test_bit(TRANS_IN_BUSY,
438 if (boardinfo->model == VMK8061_MODEL) {
439 vmk80xx_do_bulk_msg(dev);
444 urb = usb_alloc_urb(0, GFP_KERNEL);
449 vmk80xx_build_int_urb(urb, URB_RCV_FLAG);
451 set_bit(TRANS_IN_RUNNING, &dev->flags);
452 set_bit(TRANS_IN_BUSY, &dev->flags);
454 usb_anchor_urb(urb, &dev->rx_anchor);
456 retval = usb_submit_urb(urb, GFP_KERNEL);
460 clear_bit(TRANS_IN_RUNNING, &dev->flags);
461 usb_unanchor_urb(urb);
469 static int vmk80xx_write_packet(struct vmk80xx_private *dev, int cmd)
471 const struct vmk80xx_board *boardinfo = dev->board;
478 if (test_bit(TRANS_OUT_BUSY, &dev->flags))
479 if (wait_event_interruptible(dev->write_wait,
480 !test_bit(TRANS_OUT_BUSY,
484 if (boardinfo->model == VMK8061_MODEL) {
485 dev->usb_tx_buf[0] = cmd;
486 vmk80xx_do_bulk_msg(dev);
491 urb = usb_alloc_urb(0, GFP_KERNEL);
496 vmk80xx_build_int_urb(urb, URB_SND_FLAG);
498 set_bit(TRANS_OUT_BUSY, &dev->flags);
500 usb_anchor_urb(urb, &dev->tx_anchor);
502 dev->usb_tx_buf[0] = cmd;
504 retval = usb_submit_urb(urb, GFP_KERNEL);
508 clear_bit(TRANS_OUT_BUSY, &dev->flags);
509 usb_unanchor_urb(urb);
520 static int rudimentary_check(struct vmk80xx_private *dev, int dir)
529 if (test_bit(TRANS_IN_BUSY, &dev->flags))
533 if (test_bit(TRANS_OUT_BUSY, &dev->flags))
540 static int vmk80xx_ai_rinsn(struct comedi_device *cdev,
541 struct comedi_subdevice *s,
542 struct comedi_insn *insn, unsigned int *data)
544 const struct vmk80xx_board *boardinfo = comedi_board(cdev);
545 struct vmk80xx_private *dev = cdev->private;
550 n = rudimentary_check(dev, DIR_IN);
554 down(&dev->limit_sem);
555 chan = CR_CHAN(insn->chanspec);
557 switch (boardinfo->model) {
560 reg[0] = VMK8055_AI1_REG;
562 reg[0] = VMK8055_AI2_REG;
566 reg[0] = VMK8061_AI_REG1;
567 reg[1] = VMK8061_AI_REG2;
568 dev->usb_tx_buf[0] = VMK8061_CMD_RD_AI;
569 dev->usb_tx_buf[VMK8061_CH_REG] = chan;
573 for (n = 0; n < insn->n; n++) {
574 if (vmk80xx_read_packet(dev))
577 if (boardinfo->model == VMK8055_MODEL) {
578 data[n] = dev->usb_rx_buf[reg[0]];
583 data[n] = dev->usb_rx_buf[reg[0]] + 256 *
584 dev->usb_rx_buf[reg[1]];
592 static int vmk80xx_ao_winsn(struct comedi_device *cdev,
593 struct comedi_subdevice *s,
594 struct comedi_insn *insn, unsigned int *data)
596 const struct vmk80xx_board *boardinfo = comedi_board(cdev);
597 struct vmk80xx_private *dev = cdev->private;
603 n = rudimentary_check(dev, DIR_OUT);
607 down(&dev->limit_sem);
608 chan = CR_CHAN(insn->chanspec);
610 switch (boardinfo->model) {
612 cmd = VMK8055_CMD_WRT_AD;
614 reg = VMK8055_AO1_REG;
616 reg = VMK8055_AO2_REG;
618 default: /* NOTE: avoid compiler warnings */
619 cmd = VMK8061_CMD_SET_AO;
620 reg = VMK8061_AO_REG;
621 dev->usb_tx_buf[VMK8061_CH_REG] = chan;
625 for (n = 0; n < insn->n; n++) {
626 dev->usb_tx_buf[reg] = data[n];
628 if (vmk80xx_write_packet(dev, cmd))
637 static int vmk80xx_ao_rinsn(struct comedi_device *cdev,
638 struct comedi_subdevice *s,
639 struct comedi_insn *insn, unsigned int *data)
641 struct vmk80xx_private *dev = cdev->private;
646 n = rudimentary_check(dev, DIR_IN);
650 down(&dev->limit_sem);
651 chan = CR_CHAN(insn->chanspec);
653 reg = VMK8061_AO_REG - 1;
655 dev->usb_tx_buf[0] = VMK8061_CMD_RD_AO;
657 for (n = 0; n < insn->n; n++) {
658 if (vmk80xx_read_packet(dev))
661 data[n] = dev->usb_rx_buf[reg + chan];
669 static int vmk80xx_di_bits(struct comedi_device *cdev,
670 struct comedi_subdevice *s,
671 struct comedi_insn *insn, unsigned int *data)
673 const struct vmk80xx_board *boardinfo = comedi_board(cdev);
674 struct vmk80xx_private *dev = cdev->private;
675 unsigned char *rx_buf;
679 retval = rudimentary_check(dev, DIR_IN);
683 down(&dev->limit_sem);
685 rx_buf = dev->usb_rx_buf;
687 if (boardinfo->model == VMK8061_MODEL) {
688 reg = VMK8061_DI_REG;
689 dev->usb_tx_buf[0] = VMK8061_CMD_RD_DI;
691 reg = VMK8055_DI_REG;
694 retval = vmk80xx_read_packet(dev);
697 if (boardinfo->model == VMK8055_MODEL)
698 data[1] = (((rx_buf[reg] >> 4) & 0x03) |
699 ((rx_buf[reg] << 2) & 0x04) |
700 ((rx_buf[reg] >> 3) & 0x18));
702 data[1] = rx_buf[reg];
712 static int vmk80xx_di_rinsn(struct comedi_device *cdev,
713 struct comedi_subdevice *s,
714 struct comedi_insn *insn, unsigned int *data)
716 const struct vmk80xx_board *boardinfo = comedi_board(cdev);
717 struct vmk80xx_private *dev = cdev->private;
719 unsigned char *rx_buf;
724 n = rudimentary_check(dev, DIR_IN);
728 down(&dev->limit_sem);
729 chan = CR_CHAN(insn->chanspec);
731 rx_buf = dev->usb_rx_buf;
733 if (boardinfo->model == VMK8061_MODEL) {
734 reg = VMK8061_DI_REG;
735 dev->usb_tx_buf[0] = VMK8061_CMD_RD_DI;
737 reg = VMK8055_DI_REG;
739 for (n = 0; n < insn->n; n++) {
740 if (vmk80xx_read_packet(dev))
743 if (boardinfo->model == VMK8055_MODEL)
744 inp = (((rx_buf[reg] >> 4) & 0x03) |
745 ((rx_buf[reg] << 2) & 0x04) |
746 ((rx_buf[reg] >> 3) & 0x18));
750 data[n] = (inp >> chan) & 1;
758 static int vmk80xx_do_winsn(struct comedi_device *cdev,
759 struct comedi_subdevice *s,
760 struct comedi_insn *insn, unsigned int *data)
762 const struct vmk80xx_board *boardinfo = comedi_board(cdev);
763 struct vmk80xx_private *dev = cdev->private;
765 unsigned char *tx_buf;
770 n = rudimentary_check(dev, DIR_OUT);
774 down(&dev->limit_sem);
775 chan = CR_CHAN(insn->chanspec);
777 tx_buf = dev->usb_tx_buf;
779 for (n = 0; n < insn->n; n++) {
780 if (boardinfo->model == VMK8055_MODEL) {
781 reg = VMK8055_DO_REG;
782 cmd = VMK8055_CMD_WRT_AD;
784 tx_buf[reg] |= (1 << chan);
786 tx_buf[reg] ^= (1 << chan);
787 } else { /* VMK8061_MODEL */
788 reg = VMK8061_DO_REG;
790 cmd = VMK8061_CMD_SET_DO;
791 tx_buf[reg] = 1 << chan;
793 cmd = VMK8061_CMD_CLR_DO;
794 tx_buf[reg] = 0xff - (1 << chan);
798 if (vmk80xx_write_packet(dev, cmd))
807 static int vmk80xx_do_rinsn(struct comedi_device *cdev,
808 struct comedi_subdevice *s,
809 struct comedi_insn *insn, unsigned int *data)
811 struct vmk80xx_private *dev = cdev->private;
816 n = rudimentary_check(dev, DIR_IN);
820 down(&dev->limit_sem);
821 chan = CR_CHAN(insn->chanspec);
823 reg = VMK8061_DO_REG;
825 dev->usb_tx_buf[0] = VMK8061_CMD_RD_DO;
827 for (n = 0; n < insn->n; n++) {
828 if (vmk80xx_read_packet(dev))
831 data[n] = (dev->usb_rx_buf[reg] >> chan) & 1;
839 static int vmk80xx_do_bits(struct comedi_device *cdev,
840 struct comedi_subdevice *s,
841 struct comedi_insn *insn, unsigned int *data)
843 const struct vmk80xx_board *boardinfo = comedi_board(cdev);
844 struct vmk80xx_private *dev = cdev->private;
845 unsigned char *rx_buf, *tx_buf;
854 if (boardinfo->model == VMK8061_MODEL)
857 retval = rudimentary_check(dev, dir);
861 down(&dev->limit_sem);
863 rx_buf = dev->usb_rx_buf;
864 tx_buf = dev->usb_tx_buf;
867 if (boardinfo->model == VMK8055_MODEL) {
868 reg = VMK8055_DO_REG;
869 cmd = VMK8055_CMD_WRT_AD;
870 } else { /* VMK8061_MODEL */
871 reg = VMK8061_DO_REG;
872 cmd = VMK8061_CMD_DO;
875 tx_buf[reg] &= ~data[0];
876 tx_buf[reg] |= (data[0] & data[1]);
878 retval = vmk80xx_write_packet(dev, cmd);
884 if (boardinfo->model == VMK8061_MODEL) {
885 reg = VMK8061_DO_REG;
886 tx_buf[0] = VMK8061_CMD_RD_DO;
888 retval = vmk80xx_read_packet(dev);
891 data[1] = rx_buf[reg];
895 data[1] = tx_buf[reg];
905 static int vmk80xx_cnt_rinsn(struct comedi_device *cdev,
906 struct comedi_subdevice *s,
907 struct comedi_insn *insn, unsigned int *data)
909 const struct vmk80xx_board *boardinfo = comedi_board(cdev);
910 struct vmk80xx_private *dev = cdev->private;
915 n = rudimentary_check(dev, DIR_IN);
919 down(&dev->limit_sem);
920 chan = CR_CHAN(insn->chanspec);
922 switch (boardinfo->model) {
925 reg[0] = VMK8055_CNT1_REG;
927 reg[0] = VMK8055_CNT2_REG;
931 reg[0] = VMK8061_CNT_REG;
932 reg[1] = VMK8061_CNT_REG;
933 dev->usb_tx_buf[0] = VMK8061_CMD_RD_CNT;
937 for (n = 0; n < insn->n; n++) {
938 if (vmk80xx_read_packet(dev))
941 if (boardinfo->model == VMK8055_MODEL)
942 data[n] = dev->usb_rx_buf[reg[0]];
943 else /* VMK8061_MODEL */
944 data[n] = dev->usb_rx_buf[reg[0] * (chan + 1) + 1]
945 + 256 * dev->usb_rx_buf[reg[1] * 2 + 2];
953 static int vmk80xx_cnt_cinsn(struct comedi_device *cdev,
954 struct comedi_subdevice *s,
955 struct comedi_insn *insn, unsigned int *data)
957 const struct vmk80xx_board *boardinfo = comedi_board(cdev);
958 struct vmk80xx_private *dev = cdev->private;
959 unsigned int insn_cmd;
965 n = rudimentary_check(dev, DIR_OUT);
970 if (insn_cmd != INSN_CONFIG_RESET && insn_cmd != GPCT_RESET)
973 down(&dev->limit_sem);
975 chan = CR_CHAN(insn->chanspec);
977 if (boardinfo->model == VMK8055_MODEL) {
979 cmd = VMK8055_CMD_RST_CNT1;
980 reg = VMK8055_CNT1_REG;
982 cmd = VMK8055_CMD_RST_CNT2;
983 reg = VMK8055_CNT2_REG;
986 dev->usb_tx_buf[reg] = 0x00;
988 cmd = VMK8061_CMD_RST_CNT;
991 for (n = 0; n < insn->n; n++)
992 if (vmk80xx_write_packet(dev, cmd))
1000 static int vmk80xx_cnt_winsn(struct comedi_device *cdev,
1001 struct comedi_subdevice *s,
1002 struct comedi_insn *insn, unsigned int *data)
1004 struct vmk80xx_private *dev = cdev->private;
1005 unsigned long debtime;
1011 n = rudimentary_check(dev, DIR_OUT);
1015 down(&dev->limit_sem);
1016 chan = CR_CHAN(insn->chanspec);
1019 cmd = VMK8055_CMD_DEB1_TIME;
1021 cmd = VMK8055_CMD_DEB2_TIME;
1023 for (n = 0; n < insn->n; n++) {
1028 /* TODO: Prevent overflows */
1032 val = int_sqrt(debtime * 1000 / 115);
1033 if (((val + 1) * val) < debtime * 1000 / 115)
1036 dev->usb_tx_buf[6 + chan] = val;
1038 if (vmk80xx_write_packet(dev, cmd))
1042 up(&dev->limit_sem);
1047 static int vmk80xx_pwm_rinsn(struct comedi_device *cdev,
1048 struct comedi_subdevice *s,
1049 struct comedi_insn *insn, unsigned int *data)
1051 struct vmk80xx_private *dev = cdev->private;
1055 n = rudimentary_check(dev, DIR_IN);
1059 down(&dev->limit_sem);
1061 reg[0] = VMK8061_PWM_REG1;
1062 reg[1] = VMK8061_PWM_REG2;
1064 dev->usb_tx_buf[0] = VMK8061_CMD_RD_PWM;
1066 for (n = 0; n < insn->n; n++) {
1067 if (vmk80xx_read_packet(dev))
1070 data[n] = dev->usb_rx_buf[reg[0]] + 4 * dev->usb_rx_buf[reg[1]];
1073 up(&dev->limit_sem);
1078 static int vmk80xx_pwm_winsn(struct comedi_device *cdev,
1079 struct comedi_subdevice *s,
1080 struct comedi_insn *insn, unsigned int *data)
1082 struct vmk80xx_private *dev = cdev->private;
1083 unsigned char *tx_buf;
1088 n = rudimentary_check(dev, DIR_OUT);
1092 down(&dev->limit_sem);
1094 tx_buf = dev->usb_tx_buf;
1096 reg[0] = VMK8061_PWM_REG1;
1097 reg[1] = VMK8061_PWM_REG2;
1099 cmd = VMK8061_CMD_OUT_PWM;
1102 * The followin piece of code was translated from the inline
1103 * assembler code in the DLL source code.
1106 * mov eax, k ; k is the value (data[n])
1107 * and al, 03h ; al are the lower 8 bits of eax
1108 * mov lo, al ; lo is the low part (tx_buf[reg[0]])
1110 * shr eax, 2 ; right shift eax register by 2
1111 * mov hi, al ; hi is the high part (tx_buf[reg[1]])
1114 for (n = 0; n < insn->n; n++) {
1115 tx_buf[reg[0]] = (unsigned char)(data[n] & 0x03);
1116 tx_buf[reg[1]] = (unsigned char)(data[n] >> 2) & 0xff;
1118 if (vmk80xx_write_packet(dev, cmd))
1122 up(&dev->limit_sem);
1127 static int vmk80xx_attach_common(struct comedi_device *cdev,
1128 struct vmk80xx_private *dev)
1130 const struct vmk80xx_board *boardinfo;
1132 struct comedi_subdevice *s;
1135 down(&dev->limit_sem);
1137 boardinfo = dev->board;
1138 cdev->board_ptr = boardinfo;
1139 cdev->board_name = boardinfo->name;
1140 cdev->private = dev;
1142 if (boardinfo->model == VMK8055_MODEL)
1146 ret = comedi_alloc_subdevices(cdev, n_subd);
1148 up(&dev->limit_sem);
1152 /* Analog input subdevice */
1153 s = &cdev->subdevices[0];
1154 s->type = COMEDI_SUBD_AI;
1155 s->subdev_flags = SDF_READABLE | SDF_GROUND;
1156 s->n_chan = boardinfo->ai_chans;
1157 s->maxdata = (1 << boardinfo->ai_bits) - 1;
1158 s->range_table = boardinfo->range;
1159 s->insn_read = vmk80xx_ai_rinsn;
1161 /* Analog output subdevice */
1162 s = &cdev->subdevices[1];
1163 s->type = COMEDI_SUBD_AO;
1164 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
1165 s->n_chan = boardinfo->ao_chans;
1166 s->maxdata = 0x00ff;
1167 s->range_table = boardinfo->range;
1168 s->insn_write = vmk80xx_ao_winsn;
1169 if (boardinfo->model == VMK8061_MODEL) {
1170 s->subdev_flags |= SDF_READABLE;
1171 s->insn_read = vmk80xx_ao_rinsn;
1174 /* Digital input subdevice */
1175 s = &cdev->subdevices[2];
1176 s->type = COMEDI_SUBD_DI;
1177 s->subdev_flags = SDF_READABLE | SDF_GROUND;
1178 s->n_chan = boardinfo->di_chans;
1180 s->insn_read = vmk80xx_di_rinsn;
1181 s->insn_bits = vmk80xx_di_bits;
1183 /* Digital output subdevice */
1184 s = &cdev->subdevices[3];
1185 s->type = COMEDI_SUBD_DO;
1186 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
1189 s->insn_write = vmk80xx_do_winsn;
1190 s->insn_bits = vmk80xx_do_bits;
1191 if (boardinfo->model == VMK8061_MODEL) {
1192 s->subdev_flags |= SDF_READABLE;
1193 s->insn_read = vmk80xx_do_rinsn;
1196 /* Counter subdevice */
1197 s = &cdev->subdevices[4];
1198 s->type = COMEDI_SUBD_COUNTER;
1199 s->subdev_flags = SDF_READABLE;
1201 s->insn_read = vmk80xx_cnt_rinsn;
1202 s->insn_config = vmk80xx_cnt_cinsn;
1203 if (boardinfo->model == VMK8055_MODEL) {
1204 s->subdev_flags |= SDF_WRITEABLE;
1205 s->maxdata = (1 << boardinfo->cnt_bits) - 1;
1206 s->insn_write = vmk80xx_cnt_winsn;
1210 if (boardinfo->model == VMK8061_MODEL) {
1211 s = &cdev->subdevices[5];
1212 s->type = COMEDI_SUBD_PWM;
1213 s->subdev_flags = SDF_READABLE | SDF_WRITEABLE;
1214 s->n_chan = boardinfo->pwm_chans;
1215 s->maxdata = (1 << boardinfo->pwm_bits) - 1;
1216 s->insn_read = vmk80xx_pwm_rinsn;
1217 s->insn_write = vmk80xx_pwm_winsn;
1221 dev_info(cdev->class_dev, "vmk80xx: board #%d [%s] attached\n",
1222 dev->count, boardinfo->name);
1224 up(&dev->limit_sem);
1229 static int vmk80xx_auto_attach(struct comedi_device *cdev,
1230 unsigned long context_unused)
1232 struct usb_interface *intf = comedi_to_usb_interface(cdev);
1236 mutex_lock(&glb_mutex);
1237 for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
1238 if (vmb[i].probed && vmb[i].intf == intf)
1240 if (i == VMK80XX_MAX_BOARDS)
1242 else if (vmb[i].attached)
1245 ret = vmk80xx_attach_common(cdev, &vmb[i]);
1246 mutex_unlock(&glb_mutex);
1250 static void vmk80xx_detach(struct comedi_device *dev)
1252 struct vmk80xx_private *usb = dev->private;
1257 mutex_lock(&glb_mutex);
1258 down(&usb->limit_sem);
1260 dev->private = NULL;
1264 usb_set_intfdata(usb->intf, NULL);
1266 usb_kill_anchored_urbs(&usb->rx_anchor);
1267 usb_kill_anchored_urbs(&usb->tx_anchor);
1269 kfree(usb->usb_rx_buf);
1270 kfree(usb->usb_tx_buf);
1272 up(&usb->limit_sem);
1273 mutex_unlock(&glb_mutex);
1276 static struct comedi_driver vmk80xx_driver = {
1277 .module = THIS_MODULE,
1278 .driver_name = "vmk80xx",
1279 .auto_attach = vmk80xx_auto_attach,
1280 .detach = vmk80xx_detach,
1283 static int vmk80xx_usb_probe(struct usb_interface *intf,
1284 const struct usb_device_id *id)
1286 const struct vmk80xx_board *boardinfo;
1288 struct vmk80xx_private *dev;
1289 struct usb_host_interface *iface_desc;
1290 struct usb_endpoint_descriptor *ep_desc;
1293 mutex_lock(&glb_mutex);
1295 for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
1299 if (i == VMK80XX_MAX_BOARDS) {
1300 mutex_unlock(&glb_mutex);
1306 memset(dev, 0x00, sizeof(*dev));
1309 iface_desc = intf->cur_altsetting;
1310 if (iface_desc->desc.bNumEndpoints != 2)
1313 for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
1314 ep_desc = &iface_desc->endpoint[i].desc;
1316 if (usb_endpoint_is_int_in(ep_desc)) {
1317 dev->ep_rx = ep_desc;
1321 if (usb_endpoint_is_int_out(ep_desc)) {
1322 dev->ep_tx = ep_desc;
1326 if (usb_endpoint_is_bulk_in(ep_desc)) {
1327 dev->ep_rx = ep_desc;
1331 if (usb_endpoint_is_bulk_out(ep_desc)) {
1332 dev->ep_tx = ep_desc;
1337 if (!dev->ep_rx || !dev->ep_tx)
1340 size = le16_to_cpu(dev->ep_rx->wMaxPacketSize);
1341 dev->usb_rx_buf = kmalloc(size, GFP_KERNEL);
1342 if (!dev->usb_rx_buf) {
1343 mutex_unlock(&glb_mutex);
1347 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
1348 dev->usb_tx_buf = kmalloc(size, GFP_KERNEL);
1349 if (!dev->usb_tx_buf) {
1350 kfree(dev->usb_rx_buf);
1351 mutex_unlock(&glb_mutex);
1355 dev->udev = interface_to_usbdev(intf);
1358 sema_init(&dev->limit_sem, 8);
1359 init_waitqueue_head(&dev->read_wait);
1360 init_waitqueue_head(&dev->write_wait);
1362 init_usb_anchor(&dev->rx_anchor);
1363 init_usb_anchor(&dev->tx_anchor);
1365 usb_set_intfdata(intf, dev);
1367 boardinfo = &vmk80xx_boardinfo[id->driver_info];
1368 dev->board = boardinfo;
1370 if (boardinfo->model == VMK8061_MODEL) {
1371 vmk80xx_read_eeprom(dev, IC3_VERSION);
1372 dev_info(&intf->dev, "%s\n", dev->fw.ic3_vers);
1374 if (vmk80xx_check_data_link(dev)) {
1375 vmk80xx_read_eeprom(dev, IC6_VERSION);
1376 dev_info(&intf->dev, "%s\n", dev->fw.ic6_vers);
1378 dbgcm("comedi#: vmk80xx: no conn. to CPU\n");
1382 if (boardinfo->model == VMK8055_MODEL)
1383 vmk80xx_reset_device(dev);
1387 dev_info(&intf->dev, "board #%d [%s] now attached\n",
1388 dev->count, boardinfo->name);
1390 mutex_unlock(&glb_mutex);
1392 comedi_usb_auto_config(intf, &vmk80xx_driver);
1396 mutex_unlock(&glb_mutex);
1401 static const struct usb_device_id vmk80xx_usb_id_table[] = {
1402 { USB_DEVICE(0x10cf, 0x5500), .driver_info = DEVICE_VMK8055 },
1403 { USB_DEVICE(0x10cf, 0x5501), .driver_info = DEVICE_VMK8055 },
1404 { USB_DEVICE(0x10cf, 0x5502), .driver_info = DEVICE_VMK8055 },
1405 { USB_DEVICE(0x10cf, 0x5503), .driver_info = DEVICE_VMK8055 },
1406 { USB_DEVICE(0x10cf, 0x8061), .driver_info = DEVICE_VMK8061 },
1407 { USB_DEVICE(0x10cf, 0x8062), .driver_info = DEVICE_VMK8061 },
1408 { USB_DEVICE(0x10cf, 0x8063), .driver_info = DEVICE_VMK8061 },
1409 { USB_DEVICE(0x10cf, 0x8064), .driver_info = DEVICE_VMK8061 },
1410 { USB_DEVICE(0x10cf, 0x8065), .driver_info = DEVICE_VMK8061 },
1411 { USB_DEVICE(0x10cf, 0x8066), .driver_info = DEVICE_VMK8061 },
1412 { USB_DEVICE(0x10cf, 0x8067), .driver_info = DEVICE_VMK8061 },
1413 { USB_DEVICE(0x10cf, 0x8068), .driver_info = DEVICE_VMK8061 },
1416 MODULE_DEVICE_TABLE(usb, vmk80xx_usb_id_table);
1418 static struct usb_driver vmk80xx_usb_driver = {
1420 .id_table = vmk80xx_usb_id_table,
1421 .probe = vmk80xx_usb_probe,
1422 .disconnect = comedi_usb_auto_unconfig,
1424 module_comedi_usb_driver(vmk80xx_driver, vmk80xx_usb_driver);
1426 MODULE_AUTHOR("Manuel Gebele <forensixs@gmx.de>");
1427 MODULE_DESCRIPTION("Velleman USB Board Low-Level Driver");
1428 MODULE_SUPPORTED_DEVICE("K8055/K8061 aka VM110/VM140");
1429 MODULE_VERSION("0.8.01");
1430 MODULE_LICENSE("GPL");