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 *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;
215 static void vmk80xx_tx_callback(struct urb *urb)
217 struct vmk80xx_private *devpriv = urb->context;
218 unsigned long *flags = &devpriv->flags;
219 int stat = urb->status;
221 if (stat && !(stat == -ENOENT
222 || stat == -ECONNRESET || stat == -ESHUTDOWN))
223 dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n",
226 if (!test_bit(TRANS_OUT_BUSY, flags))
229 clear_bit(TRANS_OUT_BUSY, flags);
231 wake_up_interruptible(&devpriv->write_wait);
234 static void vmk80xx_rx_callback(struct urb *urb)
236 struct vmk80xx_private *devpriv = urb->context;
237 unsigned long *flags = &devpriv->flags;
238 int stat = urb->status;
248 dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n",
255 if (test_bit(TRANS_IN_RUNNING, flags) && devpriv->intf) {
256 usb_anchor_urb(urb, &devpriv->rx_anchor);
258 if (!usb_submit_urb(urb, GFP_KERNEL))
261 dev_err(&urb->dev->dev,
262 "comedi#: vmk80xx: %s - submit urb failed\n",
265 usb_unanchor_urb(urb);
268 clear_bit(TRANS_IN_BUSY, flags);
270 wake_up_interruptible(&devpriv->read_wait);
273 static int vmk80xx_check_data_link(struct vmk80xx_private *devpriv)
275 struct usb_device *usb = devpriv->usb;
276 unsigned int tx_pipe;
277 unsigned int rx_pipe;
281 tx_pipe = usb_sndbulkpipe(usb, 0x01);
282 rx_pipe = usb_rcvbulkpipe(usb, 0x81);
284 tx[0] = VMK8061_CMD_RD_PWR_STAT;
287 * Check that IC6 (PIC16F871) is powered and
288 * running and the data link between IC3 and
289 * IC6 is working properly
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);
297 static void vmk80xx_read_eeprom(struct vmk80xx_private *devpriv, int flag)
299 struct usb_device *usb = devpriv->usb;
300 unsigned int tx_pipe;
301 unsigned int rx_pipe;
303 unsigned char rx[64];
306 tx_pipe = usb_sndbulkpipe(usb, 0x01);
307 rx_pipe = usb_rcvbulkpipe(usb, 0x81);
309 tx[0] = VMK8061_CMD_RD_VERSION;
312 * Read the firmware version info of IC3 and
313 * IC6 from the internal EEPROM of the IC
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);
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);
326 static int vmk80xx_reset_device(struct vmk80xx_private *devpriv)
328 struct usb_device *usb = devpriv->usb;
329 unsigned char *tx_buf = devpriv->usb_tx_buf;
331 unsigned int tx_pipe;
335 urb = usb_alloc_urb(0, GFP_KERNEL);
339 tx_pipe = usb_sndintpipe(usb, 0x01);
341 ival = devpriv->ep_tx->bInterval;
342 size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize);
344 tx_buf[0] = VMK8055_CMD_RST;
353 usb_fill_int_urb(urb, usb, tx_pipe, tx_buf, size,
354 vmk80xx_tx_callback, devpriv, ival);
356 usb_anchor_urb(urb, &devpriv->tx_anchor);
358 return usb_submit_urb(urb, GFP_KERNEL);
361 static void vmk80xx_build_int_urb(struct urb *urb, int flag)
363 struct vmk80xx_private *devpriv = urb->context;
364 struct usb_device *usb = devpriv->usb;
370 void (*callback) (struct urb *);
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;
389 usb_fill_int_urb(urb, usb, pipe, buf, size, callback, devpriv, ival);
392 static void vmk80xx_do_bulk_msg(struct vmk80xx_private *devpriv)
394 struct usb_device *usb = devpriv->usb;
395 unsigned long *flags = &devpriv->flags;
398 unsigned int tx_pipe;
399 unsigned int rx_pipe;
402 set_bit(TRANS_IN_BUSY, flags);
403 set_bit(TRANS_OUT_BUSY, flags);
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);
411 * The max packet size attributes of the K8061
412 * input/output endpoints are identical
414 size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize);
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);
420 clear_bit(TRANS_OUT_BUSY, flags);
421 clear_bit(TRANS_IN_BUSY, flags);
424 static int vmk80xx_read_packet(struct vmk80xx_private *devpriv)
426 const struct vmk80xx_board *boardinfo = devpriv->board;
427 unsigned long *flags = &devpriv->flags;
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)))
440 if (boardinfo->model == VMK8061_MODEL) {
441 vmk80xx_do_bulk_msg(devpriv);
446 urb = usb_alloc_urb(0, GFP_KERNEL);
450 urb->context = devpriv;
451 vmk80xx_build_int_urb(urb, URB_RCV_FLAG);
453 set_bit(TRANS_IN_RUNNING, flags);
454 set_bit(TRANS_IN_BUSY, flags);
456 usb_anchor_urb(urb, &devpriv->rx_anchor);
458 retval = usb_submit_urb(urb, GFP_KERNEL);
462 clear_bit(TRANS_IN_RUNNING, flags);
463 usb_unanchor_urb(urb);
471 static int vmk80xx_write_packet(struct vmk80xx_private *devpriv, int cmd)
473 const struct vmk80xx_board *boardinfo = devpriv->board;
474 unsigned long *flags = &devpriv->flags;
481 if (test_bit(TRANS_OUT_BUSY, flags))
482 if (wait_event_interruptible(devpriv->write_wait,
483 !test_bit(TRANS_OUT_BUSY, flags)))
486 if (boardinfo->model == VMK8061_MODEL) {
487 devpriv->usb_tx_buf[0] = cmd;
488 vmk80xx_do_bulk_msg(devpriv);
493 urb = usb_alloc_urb(0, GFP_KERNEL);
497 urb->context = devpriv;
498 vmk80xx_build_int_urb(urb, URB_SND_FLAG);
500 set_bit(TRANS_OUT_BUSY, flags);
502 usb_anchor_urb(urb, &devpriv->tx_anchor);
504 devpriv->usb_tx_buf[0] = cmd;
506 retval = usb_submit_urb(urb, GFP_KERNEL);
510 clear_bit(TRANS_OUT_BUSY, flags);
511 usb_unanchor_urb(urb);
522 static int rudimentary_check(struct vmk80xx_private *devpriv, int dir)
527 if (test_bit(TRANS_IN_BUSY, &devpriv->flags))
531 if (test_bit(TRANS_OUT_BUSY, &devpriv->flags))
538 static int vmk80xx_ai_rinsn(struct comedi_device *dev,
539 struct comedi_subdevice *s,
540 struct comedi_insn *insn, unsigned int *data)
542 const struct vmk80xx_board *boardinfo = comedi_board(dev);
543 struct vmk80xx_private *devpriv = dev->private;
548 n = rudimentary_check(devpriv, DIR_IN);
552 down(&devpriv->limit_sem);
553 chan = CR_CHAN(insn->chanspec);
555 switch (boardinfo->model) {
558 reg[0] = VMK8055_AI1_REG;
560 reg[0] = VMK8055_AI2_REG;
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;
571 for (n = 0; n < insn->n; n++) {
572 if (vmk80xx_read_packet(devpriv))
575 if (boardinfo->model == VMK8055_MODEL) {
576 data[n] = devpriv->usb_rx_buf[reg[0]];
581 data[n] = devpriv->usb_rx_buf[reg[0]] + 256 *
582 devpriv->usb_rx_buf[reg[1]];
585 up(&devpriv->limit_sem);
590 static int vmk80xx_ao_winsn(struct comedi_device *dev,
591 struct comedi_subdevice *s,
592 struct comedi_insn *insn, unsigned int *data)
594 const struct vmk80xx_board *boardinfo = comedi_board(dev);
595 struct vmk80xx_private *devpriv = dev->private;
601 n = rudimentary_check(devpriv, DIR_OUT);
605 down(&devpriv->limit_sem);
606 chan = CR_CHAN(insn->chanspec);
608 switch (boardinfo->model) {
610 cmd = VMK8055_CMD_WRT_AD;
612 reg = VMK8055_AO1_REG;
614 reg = VMK8055_AO2_REG;
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;
623 for (n = 0; n < insn->n; n++) {
624 devpriv->usb_tx_buf[reg] = data[n];
626 if (vmk80xx_write_packet(devpriv, cmd))
630 up(&devpriv->limit_sem);
635 static int vmk80xx_ao_rinsn(struct comedi_device *dev,
636 struct comedi_subdevice *s,
637 struct comedi_insn *insn, unsigned int *data)
639 struct vmk80xx_private *devpriv = dev->private;
644 n = rudimentary_check(devpriv, DIR_IN);
648 down(&devpriv->limit_sem);
649 chan = CR_CHAN(insn->chanspec);
651 reg = VMK8061_AO_REG - 1;
653 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_AO;
655 for (n = 0; n < insn->n; n++) {
656 if (vmk80xx_read_packet(devpriv))
659 data[n] = devpriv->usb_rx_buf[reg + chan];
662 up(&devpriv->limit_sem);
667 static int vmk80xx_di_bits(struct comedi_device *dev,
668 struct comedi_subdevice *s,
669 struct comedi_insn *insn, unsigned int *data)
671 const struct vmk80xx_board *boardinfo = comedi_board(dev);
672 struct vmk80xx_private *devpriv = dev->private;
673 unsigned char *rx_buf;
677 retval = rudimentary_check(devpriv, DIR_IN);
681 down(&devpriv->limit_sem);
683 rx_buf = devpriv->usb_rx_buf;
685 if (boardinfo->model == VMK8061_MODEL) {
686 reg = VMK8061_DI_REG;
687 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_DI;
689 reg = VMK8055_DI_REG;
692 retval = vmk80xx_read_packet(devpriv);
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));
700 data[1] = rx_buf[reg];
705 up(&devpriv->limit_sem);
710 static int vmk80xx_di_rinsn(struct comedi_device *dev,
711 struct comedi_subdevice *s,
712 struct comedi_insn *insn, unsigned int *data)
714 const struct vmk80xx_board *boardinfo = comedi_board(dev);
715 struct vmk80xx_private *devpriv = dev->private;
717 unsigned char *rx_buf;
722 n = rudimentary_check(devpriv, DIR_IN);
726 down(&devpriv->limit_sem);
727 chan = CR_CHAN(insn->chanspec);
729 rx_buf = devpriv->usb_rx_buf;
731 if (boardinfo->model == VMK8061_MODEL) {
732 reg = VMK8061_DI_REG;
733 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_DI;
735 reg = VMK8055_DI_REG;
737 for (n = 0; n < insn->n; n++) {
738 if (vmk80xx_read_packet(devpriv))
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));
748 data[n] = (inp >> chan) & 1;
751 up(&devpriv->limit_sem);
756 static int vmk80xx_do_winsn(struct comedi_device *dev,
757 struct comedi_subdevice *s,
758 struct comedi_insn *insn, unsigned int *data)
760 const struct vmk80xx_board *boardinfo = comedi_board(dev);
761 struct vmk80xx_private *devpriv = dev->private;
763 unsigned char *tx_buf;
768 n = rudimentary_check(devpriv, DIR_OUT);
772 down(&devpriv->limit_sem);
773 chan = CR_CHAN(insn->chanspec);
775 tx_buf = devpriv->usb_tx_buf;
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;
782 tx_buf[reg] |= (1 << chan);
784 tx_buf[reg] ^= (1 << chan);
785 } else { /* VMK8061_MODEL */
786 reg = VMK8061_DO_REG;
788 cmd = VMK8061_CMD_SET_DO;
789 tx_buf[reg] = 1 << chan;
791 cmd = VMK8061_CMD_CLR_DO;
792 tx_buf[reg] = 0xff - (1 << chan);
796 if (vmk80xx_write_packet(devpriv, cmd))
800 up(&devpriv->limit_sem);
805 static int vmk80xx_do_rinsn(struct comedi_device *dev,
806 struct comedi_subdevice *s,
807 struct comedi_insn *insn, unsigned int *data)
809 struct vmk80xx_private *devpriv = dev->private;
814 n = rudimentary_check(devpriv, DIR_IN);
818 down(&devpriv->limit_sem);
819 chan = CR_CHAN(insn->chanspec);
821 reg = VMK8061_DO_REG;
823 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_DO;
825 for (n = 0; n < insn->n; n++) {
826 if (vmk80xx_read_packet(devpriv))
829 data[n] = (devpriv->usb_rx_buf[reg] >> chan) & 1;
832 up(&devpriv->limit_sem);
837 static int vmk80xx_do_bits(struct comedi_device *dev,
838 struct comedi_subdevice *s,
839 struct comedi_insn *insn, unsigned int *data)
841 const struct vmk80xx_board *boardinfo = comedi_board(dev);
842 struct vmk80xx_private *devpriv = dev->private;
843 unsigned char *rx_buf, *tx_buf;
852 if (boardinfo->model == VMK8061_MODEL)
855 retval = rudimentary_check(devpriv, dir);
859 down(&devpriv->limit_sem);
861 rx_buf = devpriv->usb_rx_buf;
862 tx_buf = devpriv->usb_tx_buf;
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;
873 tx_buf[reg] &= ~data[0];
874 tx_buf[reg] |= (data[0] & data[1]);
876 retval = vmk80xx_write_packet(devpriv, cmd);
882 if (boardinfo->model == VMK8061_MODEL) {
883 reg = VMK8061_DO_REG;
884 tx_buf[0] = VMK8061_CMD_RD_DO;
886 retval = vmk80xx_read_packet(devpriv);
889 data[1] = rx_buf[reg];
893 data[1] = tx_buf[reg];
898 up(&devpriv->limit_sem);
903 static int vmk80xx_cnt_rinsn(struct comedi_device *dev,
904 struct comedi_subdevice *s,
905 struct comedi_insn *insn, unsigned int *data)
907 const struct vmk80xx_board *boardinfo = comedi_board(dev);
908 struct vmk80xx_private *devpriv = dev->private;
913 n = rudimentary_check(devpriv, DIR_IN);
917 down(&devpriv->limit_sem);
918 chan = CR_CHAN(insn->chanspec);
920 switch (boardinfo->model) {
923 reg[0] = VMK8055_CNT1_REG;
925 reg[0] = VMK8055_CNT2_REG;
929 reg[0] = VMK8061_CNT_REG;
930 reg[1] = VMK8061_CNT_REG;
931 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_CNT;
935 for (n = 0; n < insn->n; n++) {
936 if (vmk80xx_read_packet(devpriv))
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];
946 up(&devpriv->limit_sem);
951 static int vmk80xx_cnt_cinsn(struct comedi_device *dev,
952 struct comedi_subdevice *s,
953 struct comedi_insn *insn, unsigned int *data)
955 const struct vmk80xx_board *boardinfo = comedi_board(dev);
956 struct vmk80xx_private *devpriv = dev->private;
957 unsigned int insn_cmd;
963 n = rudimentary_check(devpriv, DIR_OUT);
968 if (insn_cmd != INSN_CONFIG_RESET && insn_cmd != GPCT_RESET)
971 down(&devpriv->limit_sem);
973 chan = CR_CHAN(insn->chanspec);
975 if (boardinfo->model == VMK8055_MODEL) {
977 cmd = VMK8055_CMD_RST_CNT1;
978 reg = VMK8055_CNT1_REG;
980 cmd = VMK8055_CMD_RST_CNT2;
981 reg = VMK8055_CNT2_REG;
984 devpriv->usb_tx_buf[reg] = 0x00;
986 cmd = VMK8061_CMD_RST_CNT;
989 for (n = 0; n < insn->n; n++)
990 if (vmk80xx_write_packet(devpriv, cmd))
993 up(&devpriv->limit_sem);
998 static int vmk80xx_cnt_winsn(struct comedi_device *dev,
999 struct comedi_subdevice *s,
1000 struct comedi_insn *insn, unsigned int *data)
1002 struct vmk80xx_private *devpriv = dev->private;
1003 unsigned long debtime;
1009 n = rudimentary_check(devpriv, DIR_OUT);
1013 down(&devpriv->limit_sem);
1014 chan = CR_CHAN(insn->chanspec);
1017 cmd = VMK8055_CMD_DEB1_TIME;
1019 cmd = VMK8055_CMD_DEB2_TIME;
1021 for (n = 0; n < insn->n; n++) {
1026 /* TODO: Prevent overflows */
1030 val = int_sqrt(debtime * 1000 / 115);
1031 if (((val + 1) * val) < debtime * 1000 / 115)
1034 devpriv->usb_tx_buf[6 + chan] = val;
1036 if (vmk80xx_write_packet(devpriv, cmd))
1040 up(&devpriv->limit_sem);
1045 static int vmk80xx_pwm_rinsn(struct comedi_device *dev,
1046 struct comedi_subdevice *s,
1047 struct comedi_insn *insn, unsigned int *data)
1049 struct vmk80xx_private *devpriv = dev->private;
1050 unsigned char *tx_buf;
1051 unsigned char *rx_buf;
1055 n = rudimentary_check(devpriv, DIR_IN);
1059 down(&devpriv->limit_sem);
1061 tx_buf = devpriv->usb_tx_buf;
1062 rx_buf = devpriv->usb_rx_buf;
1064 reg[0] = VMK8061_PWM_REG1;
1065 reg[1] = VMK8061_PWM_REG2;
1067 tx_buf[0] = VMK8061_CMD_RD_PWM;
1069 for (n = 0; n < insn->n; n++) {
1070 if (vmk80xx_read_packet(devpriv))
1073 data[n] = rx_buf[reg[0]] + 4 * rx_buf[reg[1]];
1076 up(&devpriv->limit_sem);
1081 static int vmk80xx_pwm_winsn(struct comedi_device *dev,
1082 struct comedi_subdevice *s,
1083 struct comedi_insn *insn, unsigned int *data)
1085 struct vmk80xx_private *devpriv = dev->private;
1086 unsigned char *tx_buf;
1091 n = rudimentary_check(devpriv, DIR_OUT);
1095 down(&devpriv->limit_sem);
1097 tx_buf = devpriv->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(devpriv, cmd))
1125 up(&devpriv->limit_sem);
1130 static int vmk80xx_find_usb_endpoints(struct comedi_device *dev)
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;
1138 if (iface_desc->desc.bNumEndpoints != 2)
1141 for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
1142 ep_desc = &iface_desc->endpoint[i].desc;
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;
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;
1159 if (!devpriv->ep_rx || !devpriv->ep_tx)
1165 static int vmk80xx_alloc_usb_buffers(struct comedi_device *dev)
1167 struct vmk80xx_private *devpriv = dev->private;
1170 size = le16_to_cpu(devpriv->ep_rx->wMaxPacketSize);
1171 devpriv->usb_rx_buf = kmalloc(size, GFP_KERNEL);
1172 if (!devpriv->usb_rx_buf)
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);
1185 static int vmk80xx_attach_common(struct comedi_device *dev)
1187 const struct vmk80xx_board *boardinfo = comedi_board(dev);
1188 struct vmk80xx_private *devpriv = dev->private;
1189 struct comedi_subdevice *s;
1193 down(&devpriv->limit_sem);
1195 if (boardinfo->model == VMK8055_MODEL)
1199 ret = comedi_alloc_subdevices(dev, n_subd);
1201 up(&devpriv->limit_sem);
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;
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;
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;
1233 s->insn_read = vmk80xx_di_rinsn;
1234 s->insn_bits = vmk80xx_di_bits;
1236 /* Digital output subdevice */
1237 s = &dev->subdevices[3];
1238 s->type = COMEDI_SUBD_DO;
1239 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
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;
1249 /* Counter subdevice */
1250 s = &dev->subdevices[4];
1251 s->type = COMEDI_SUBD_COUNTER;
1252 s->subdev_flags = SDF_READABLE;
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;
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;
1273 up(&devpriv->limit_sem);
1278 static int vmk80xx_auto_attach(struct comedi_device *dev,
1279 unsigned long context)
1281 struct usb_interface *intf = comedi_to_usb_interface(dev);
1282 const struct vmk80xx_board *boardinfo;
1283 struct vmk80xx_private *devpriv;
1286 boardinfo = &vmk80xx_boardinfo[context];
1287 dev->board_ptr = boardinfo;
1288 dev->board_name = boardinfo->name;
1290 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
1293 dev->private = devpriv;
1295 devpriv->usb = interface_to_usbdev(intf);
1296 devpriv->intf = intf;
1297 devpriv->board = boardinfo;
1299 ret = vmk80xx_find_usb_endpoints(dev);
1303 ret = vmk80xx_alloc_usb_buffers(dev);
1307 sema_init(&devpriv->limit_sem, 8);
1308 init_waitqueue_head(&devpriv->read_wait);
1309 init_waitqueue_head(&devpriv->write_wait);
1311 init_usb_anchor(&devpriv->rx_anchor);
1312 init_usb_anchor(&devpriv->tx_anchor);
1314 usb_set_intfdata(intf, devpriv);
1316 if (boardinfo->model == VMK8061_MODEL) {
1317 vmk80xx_read_eeprom(devpriv, IC3_VERSION);
1318 dev_info(&intf->dev, "%s\n", devpriv->fw.ic3_vers);
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);
1324 dbgcm("comedi#: vmk80xx: no conn. to CPU\n");
1328 if (boardinfo->model == VMK8055_MODEL)
1329 vmk80xx_reset_device(devpriv);
1331 return vmk80xx_attach_common(dev);
1334 static void vmk80xx_detach(struct comedi_device *dev)
1336 struct vmk80xx_private *devpriv = dev->private;
1341 down(&devpriv->limit_sem);
1343 usb_set_intfdata(devpriv->intf, NULL);
1345 usb_kill_anchored_urbs(&devpriv->rx_anchor);
1346 usb_kill_anchored_urbs(&devpriv->tx_anchor);
1348 kfree(devpriv->usb_rx_buf);
1349 kfree(devpriv->usb_tx_buf);
1351 up(&devpriv->limit_sem);
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,
1361 static int vmk80xx_usb_probe(struct usb_interface *intf,
1362 const struct usb_device_id *id)
1364 return comedi_usb_auto_config(intf, &vmk80xx_driver, id->driver_info);
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 },
1382 MODULE_DEVICE_TABLE(usb, vmk80xx_usb_id_table);
1384 static struct usb_driver vmk80xx_usb_driver = {
1386 .id_table = vmk80xx_usb_id_table,
1387 .probe = vmk80xx_usb_probe,
1388 .disconnect = comedi_usb_auto_unconfig,
1390 module_comedi_usb_driver(vmk80xx_driver, vmk80xx_usb_driver);
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");