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;
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 *devpriv = urb->context;
225 unsigned long *flags = &devpriv->flags;
226 int stat = urb->status;
228 if (stat && !(stat == -ENOENT
229 || stat == -ECONNRESET || stat == -ESHUTDOWN))
230 dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n",
233 if (!test_bit(TRANS_OUT_BUSY, flags))
236 clear_bit(TRANS_OUT_BUSY, flags);
238 wake_up_interruptible(&devpriv->write_wait);
241 static void vmk80xx_rx_callback(struct urb *urb)
243 struct vmk80xx_private *devpriv = urb->context;
244 unsigned long *flags = &devpriv->flags;
245 int stat = urb->status;
255 dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n",
262 if (test_bit(TRANS_IN_RUNNING, flags) && devpriv->intf) {
263 usb_anchor_urb(urb, &devpriv->rx_anchor);
265 if (!usb_submit_urb(urb, GFP_KERNEL))
268 dev_err(&urb->dev->dev,
269 "comedi#: vmk80xx: %s - submit urb failed\n",
272 usb_unanchor_urb(urb);
275 clear_bit(TRANS_IN_BUSY, flags);
277 wake_up_interruptible(&devpriv->read_wait);
280 static int vmk80xx_check_data_link(struct vmk80xx_private *devpriv)
282 struct usb_device *usb = devpriv->usb;
283 unsigned int tx_pipe;
284 unsigned int rx_pipe;
288 tx_pipe = usb_sndbulkpipe(usb, 0x01);
289 rx_pipe = usb_rcvbulkpipe(usb, 0x81);
291 tx[0] = VMK8061_CMD_RD_PWR_STAT;
294 * Check that IC6 (PIC16F871) is powered and
295 * running and the data link between IC3 and
296 * IC6 is working properly
298 usb_bulk_msg(usb, tx_pipe, tx, 1, NULL, devpriv->ep_tx->bInterval);
299 usb_bulk_msg(usb, rx_pipe, rx, 2, NULL, HZ * 10);
304 static void vmk80xx_read_eeprom(struct vmk80xx_private *devpriv, int flag)
306 struct usb_device *usb = devpriv->usb;
307 unsigned int tx_pipe;
308 unsigned int rx_pipe;
310 unsigned char rx[64];
313 tx_pipe = usb_sndbulkpipe(usb, 0x01);
314 rx_pipe = usb_rcvbulkpipe(usb, 0x81);
316 tx[0] = VMK8061_CMD_RD_VERSION;
319 * Read the firmware version info of IC3 and
320 * IC6 from the internal EEPROM of the IC
322 usb_bulk_msg(usb, tx_pipe, tx, 1, NULL, devpriv->ep_tx->bInterval);
323 usb_bulk_msg(usb, rx_pipe, rx, 64, &cnt, HZ * 10);
327 if (flag & IC3_VERSION)
328 strncpy(devpriv->fw.ic3_vers, rx + 1, 24);
329 else /* IC6_VERSION */
330 strncpy(devpriv->fw.ic6_vers, rx + 25, 24);
333 static int vmk80xx_reset_device(struct vmk80xx_private *devpriv)
335 struct usb_device *usb = devpriv->usb;
336 unsigned char *tx_buf = devpriv->usb_tx_buf;
338 unsigned int tx_pipe;
342 urb = usb_alloc_urb(0, GFP_KERNEL);
346 tx_pipe = usb_sndintpipe(usb, 0x01);
348 ival = devpriv->ep_tx->bInterval;
349 size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize);
351 tx_buf[0] = VMK8055_CMD_RST;
360 usb_fill_int_urb(urb, usb, tx_pipe, tx_buf, size,
361 vmk80xx_tx_callback, devpriv, ival);
363 usb_anchor_urb(urb, &devpriv->tx_anchor);
365 return usb_submit_urb(urb, GFP_KERNEL);
368 static void vmk80xx_build_int_urb(struct urb *urb, int flag)
370 struct vmk80xx_private *devpriv = urb->context;
371 struct usb_device *usb = devpriv->usb;
377 void (*callback) (struct urb *);
380 if (flag & URB_RCV_FLAG) {
381 rx_addr = devpriv->ep_rx->bEndpointAddress;
382 pipe = usb_rcvintpipe(usb, rx_addr);
383 buf = devpriv->usb_rx_buf;
384 size = le16_to_cpu(devpriv->ep_rx->wMaxPacketSize);
385 callback = vmk80xx_rx_callback;
386 ival = devpriv->ep_rx->bInterval;
387 } else { /* URB_SND_FLAG */
388 tx_addr = devpriv->ep_tx->bEndpointAddress;
389 pipe = usb_sndintpipe(usb, tx_addr);
390 buf = devpriv->usb_tx_buf;
391 size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize);
392 callback = vmk80xx_tx_callback;
393 ival = devpriv->ep_tx->bInterval;
396 usb_fill_int_urb(urb, usb, pipe, buf, size, callback, devpriv, ival);
399 static void vmk80xx_do_bulk_msg(struct vmk80xx_private *devpriv)
401 struct usb_device *usb = devpriv->usb;
402 unsigned long *flags = &devpriv->flags;
405 unsigned int tx_pipe;
406 unsigned int rx_pipe;
409 set_bit(TRANS_IN_BUSY, flags);
410 set_bit(TRANS_OUT_BUSY, flags);
412 tx_addr = devpriv->ep_tx->bEndpointAddress;
413 rx_addr = devpriv->ep_rx->bEndpointAddress;
414 tx_pipe = usb_sndbulkpipe(usb, tx_addr);
415 rx_pipe = usb_rcvbulkpipe(usb, rx_addr);
418 * The max packet size attributes of the K8061
419 * input/output endpoints are identical
421 size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize);
423 usb_bulk_msg(usb, tx_pipe, devpriv->usb_tx_buf,
424 size, NULL, devpriv->ep_tx->bInterval);
425 usb_bulk_msg(usb, rx_pipe, devpriv->usb_rx_buf, size, NULL, HZ * 10);
427 clear_bit(TRANS_OUT_BUSY, flags);
428 clear_bit(TRANS_IN_BUSY, flags);
431 static int vmk80xx_read_packet(struct vmk80xx_private *devpriv)
433 const struct vmk80xx_board *boardinfo = devpriv->board;
434 unsigned long *flags = &devpriv->flags;
441 /* Only useful for interrupt transfers */
442 if (test_bit(TRANS_IN_BUSY, flags))
443 if (wait_event_interruptible(devpriv->read_wait,
444 !test_bit(TRANS_IN_BUSY, flags)))
447 if (boardinfo->model == VMK8061_MODEL) {
448 vmk80xx_do_bulk_msg(devpriv);
453 urb = usb_alloc_urb(0, GFP_KERNEL);
457 urb->context = devpriv;
458 vmk80xx_build_int_urb(urb, URB_RCV_FLAG);
460 set_bit(TRANS_IN_RUNNING, flags);
461 set_bit(TRANS_IN_BUSY, flags);
463 usb_anchor_urb(urb, &devpriv->rx_anchor);
465 retval = usb_submit_urb(urb, GFP_KERNEL);
469 clear_bit(TRANS_IN_RUNNING, flags);
470 usb_unanchor_urb(urb);
478 static int vmk80xx_write_packet(struct vmk80xx_private *devpriv, int cmd)
480 const struct vmk80xx_board *boardinfo = devpriv->board;
481 unsigned long *flags = &devpriv->flags;
488 if (test_bit(TRANS_OUT_BUSY, flags))
489 if (wait_event_interruptible(devpriv->write_wait,
490 !test_bit(TRANS_OUT_BUSY, flags)))
493 if (boardinfo->model == VMK8061_MODEL) {
494 devpriv->usb_tx_buf[0] = cmd;
495 vmk80xx_do_bulk_msg(devpriv);
500 urb = usb_alloc_urb(0, GFP_KERNEL);
504 urb->context = devpriv;
505 vmk80xx_build_int_urb(urb, URB_SND_FLAG);
507 set_bit(TRANS_OUT_BUSY, flags);
509 usb_anchor_urb(urb, &devpriv->tx_anchor);
511 devpriv->usb_tx_buf[0] = cmd;
513 retval = usb_submit_urb(urb, GFP_KERNEL);
517 clear_bit(TRANS_OUT_BUSY, flags);
518 usb_unanchor_urb(urb);
529 static int rudimentary_check(struct vmk80xx_private *devpriv, int dir)
533 if (!devpriv->probed)
535 if (!devpriv->attached)
538 if (test_bit(TRANS_IN_BUSY, &devpriv->flags))
542 if (test_bit(TRANS_OUT_BUSY, &devpriv->flags))
549 static int vmk80xx_ai_rinsn(struct comedi_device *dev,
550 struct comedi_subdevice *s,
551 struct comedi_insn *insn, unsigned int *data)
553 const struct vmk80xx_board *boardinfo = comedi_board(dev);
554 struct vmk80xx_private *devpriv = dev->private;
559 n = rudimentary_check(devpriv, DIR_IN);
563 down(&devpriv->limit_sem);
564 chan = CR_CHAN(insn->chanspec);
566 switch (boardinfo->model) {
569 reg[0] = VMK8055_AI1_REG;
571 reg[0] = VMK8055_AI2_REG;
575 reg[0] = VMK8061_AI_REG1;
576 reg[1] = VMK8061_AI_REG2;
577 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_AI;
578 devpriv->usb_tx_buf[VMK8061_CH_REG] = chan;
582 for (n = 0; n < insn->n; n++) {
583 if (vmk80xx_read_packet(devpriv))
586 if (boardinfo->model == VMK8055_MODEL) {
587 data[n] = devpriv->usb_rx_buf[reg[0]];
592 data[n] = devpriv->usb_rx_buf[reg[0]] + 256 *
593 devpriv->usb_rx_buf[reg[1]];
596 up(&devpriv->limit_sem);
601 static int vmk80xx_ao_winsn(struct comedi_device *dev,
602 struct comedi_subdevice *s,
603 struct comedi_insn *insn, unsigned int *data)
605 const struct vmk80xx_board *boardinfo = comedi_board(dev);
606 struct vmk80xx_private *devpriv = dev->private;
612 n = rudimentary_check(devpriv, DIR_OUT);
616 down(&devpriv->limit_sem);
617 chan = CR_CHAN(insn->chanspec);
619 switch (boardinfo->model) {
621 cmd = VMK8055_CMD_WRT_AD;
623 reg = VMK8055_AO1_REG;
625 reg = VMK8055_AO2_REG;
627 default: /* NOTE: avoid compiler warnings */
628 cmd = VMK8061_CMD_SET_AO;
629 reg = VMK8061_AO_REG;
630 devpriv->usb_tx_buf[VMK8061_CH_REG] = chan;
634 for (n = 0; n < insn->n; n++) {
635 devpriv->usb_tx_buf[reg] = data[n];
637 if (vmk80xx_write_packet(devpriv, cmd))
641 up(&devpriv->limit_sem);
646 static int vmk80xx_ao_rinsn(struct comedi_device *dev,
647 struct comedi_subdevice *s,
648 struct comedi_insn *insn, unsigned int *data)
650 struct vmk80xx_private *devpriv = dev->private;
655 n = rudimentary_check(devpriv, DIR_IN);
659 down(&devpriv->limit_sem);
660 chan = CR_CHAN(insn->chanspec);
662 reg = VMK8061_AO_REG - 1;
664 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_AO;
666 for (n = 0; n < insn->n; n++) {
667 if (vmk80xx_read_packet(devpriv))
670 data[n] = devpriv->usb_rx_buf[reg + chan];
673 up(&devpriv->limit_sem);
678 static int vmk80xx_di_bits(struct comedi_device *dev,
679 struct comedi_subdevice *s,
680 struct comedi_insn *insn, unsigned int *data)
682 const struct vmk80xx_board *boardinfo = comedi_board(dev);
683 struct vmk80xx_private *devpriv = dev->private;
684 unsigned char *rx_buf;
688 retval = rudimentary_check(devpriv, DIR_IN);
692 down(&devpriv->limit_sem);
694 rx_buf = devpriv->usb_rx_buf;
696 if (boardinfo->model == VMK8061_MODEL) {
697 reg = VMK8061_DI_REG;
698 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_DI;
700 reg = VMK8055_DI_REG;
703 retval = vmk80xx_read_packet(devpriv);
706 if (boardinfo->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];
716 up(&devpriv->limit_sem);
721 static int vmk80xx_di_rinsn(struct comedi_device *dev,
722 struct comedi_subdevice *s,
723 struct comedi_insn *insn, unsigned int *data)
725 const struct vmk80xx_board *boardinfo = comedi_board(dev);
726 struct vmk80xx_private *devpriv = dev->private;
728 unsigned char *rx_buf;
733 n = rudimentary_check(devpriv, DIR_IN);
737 down(&devpriv->limit_sem);
738 chan = CR_CHAN(insn->chanspec);
740 rx_buf = devpriv->usb_rx_buf;
742 if (boardinfo->model == VMK8061_MODEL) {
743 reg = VMK8061_DI_REG;
744 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_DI;
746 reg = VMK8055_DI_REG;
748 for (n = 0; n < insn->n; n++) {
749 if (vmk80xx_read_packet(devpriv))
752 if (boardinfo->model == VMK8055_MODEL)
753 inp = (((rx_buf[reg] >> 4) & 0x03) |
754 ((rx_buf[reg] << 2) & 0x04) |
755 ((rx_buf[reg] >> 3) & 0x18));
759 data[n] = (inp >> chan) & 1;
762 up(&devpriv->limit_sem);
767 static int vmk80xx_do_winsn(struct comedi_device *dev,
768 struct comedi_subdevice *s,
769 struct comedi_insn *insn, unsigned int *data)
771 const struct vmk80xx_board *boardinfo = comedi_board(dev);
772 struct vmk80xx_private *devpriv = dev->private;
774 unsigned char *tx_buf;
779 n = rudimentary_check(devpriv, DIR_OUT);
783 down(&devpriv->limit_sem);
784 chan = CR_CHAN(insn->chanspec);
786 tx_buf = devpriv->usb_tx_buf;
788 for (n = 0; n < insn->n; n++) {
789 if (boardinfo->model == VMK8055_MODEL) {
790 reg = VMK8055_DO_REG;
791 cmd = VMK8055_CMD_WRT_AD;
793 tx_buf[reg] |= (1 << chan);
795 tx_buf[reg] ^= (1 << chan);
796 } else { /* VMK8061_MODEL */
797 reg = VMK8061_DO_REG;
799 cmd = VMK8061_CMD_SET_DO;
800 tx_buf[reg] = 1 << chan;
802 cmd = VMK8061_CMD_CLR_DO;
803 tx_buf[reg] = 0xff - (1 << chan);
807 if (vmk80xx_write_packet(devpriv, cmd))
811 up(&devpriv->limit_sem);
816 static int vmk80xx_do_rinsn(struct comedi_device *dev,
817 struct comedi_subdevice *s,
818 struct comedi_insn *insn, unsigned int *data)
820 struct vmk80xx_private *devpriv = dev->private;
825 n = rudimentary_check(devpriv, DIR_IN);
829 down(&devpriv->limit_sem);
830 chan = CR_CHAN(insn->chanspec);
832 reg = VMK8061_DO_REG;
834 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_DO;
836 for (n = 0; n < insn->n; n++) {
837 if (vmk80xx_read_packet(devpriv))
840 data[n] = (devpriv->usb_rx_buf[reg] >> chan) & 1;
843 up(&devpriv->limit_sem);
848 static int vmk80xx_do_bits(struct comedi_device *dev,
849 struct comedi_subdevice *s,
850 struct comedi_insn *insn, unsigned int *data)
852 const struct vmk80xx_board *boardinfo = comedi_board(dev);
853 struct vmk80xx_private *devpriv = dev->private;
854 unsigned char *rx_buf, *tx_buf;
863 if (boardinfo->model == VMK8061_MODEL)
866 retval = rudimentary_check(devpriv, dir);
870 down(&devpriv->limit_sem);
872 rx_buf = devpriv->usb_rx_buf;
873 tx_buf = devpriv->usb_tx_buf;
876 if (boardinfo->model == VMK8055_MODEL) {
877 reg = VMK8055_DO_REG;
878 cmd = VMK8055_CMD_WRT_AD;
879 } else { /* VMK8061_MODEL */
880 reg = VMK8061_DO_REG;
881 cmd = VMK8061_CMD_DO;
884 tx_buf[reg] &= ~data[0];
885 tx_buf[reg] |= (data[0] & data[1]);
887 retval = vmk80xx_write_packet(devpriv, cmd);
893 if (boardinfo->model == VMK8061_MODEL) {
894 reg = VMK8061_DO_REG;
895 tx_buf[0] = VMK8061_CMD_RD_DO;
897 retval = vmk80xx_read_packet(devpriv);
900 data[1] = rx_buf[reg];
904 data[1] = tx_buf[reg];
909 up(&devpriv->limit_sem);
914 static int vmk80xx_cnt_rinsn(struct comedi_device *dev,
915 struct comedi_subdevice *s,
916 struct comedi_insn *insn, unsigned int *data)
918 const struct vmk80xx_board *boardinfo = comedi_board(dev);
919 struct vmk80xx_private *devpriv = dev->private;
924 n = rudimentary_check(devpriv, DIR_IN);
928 down(&devpriv->limit_sem);
929 chan = CR_CHAN(insn->chanspec);
931 switch (boardinfo->model) {
934 reg[0] = VMK8055_CNT1_REG;
936 reg[0] = VMK8055_CNT2_REG;
940 reg[0] = VMK8061_CNT_REG;
941 reg[1] = VMK8061_CNT_REG;
942 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_CNT;
946 for (n = 0; n < insn->n; n++) {
947 if (vmk80xx_read_packet(devpriv))
950 if (boardinfo->model == VMK8055_MODEL)
951 data[n] = devpriv->usb_rx_buf[reg[0]];
952 else /* VMK8061_MODEL */
953 data[n] = devpriv->usb_rx_buf[reg[0] * (chan + 1) + 1]
954 + 256 * devpriv->usb_rx_buf[reg[1] * 2 + 2];
957 up(&devpriv->limit_sem);
962 static int vmk80xx_cnt_cinsn(struct comedi_device *dev,
963 struct comedi_subdevice *s,
964 struct comedi_insn *insn, unsigned int *data)
966 const struct vmk80xx_board *boardinfo = comedi_board(dev);
967 struct vmk80xx_private *devpriv = dev->private;
968 unsigned int insn_cmd;
974 n = rudimentary_check(devpriv, DIR_OUT);
979 if (insn_cmd != INSN_CONFIG_RESET && insn_cmd != GPCT_RESET)
982 down(&devpriv->limit_sem);
984 chan = CR_CHAN(insn->chanspec);
986 if (boardinfo->model == VMK8055_MODEL) {
988 cmd = VMK8055_CMD_RST_CNT1;
989 reg = VMK8055_CNT1_REG;
991 cmd = VMK8055_CMD_RST_CNT2;
992 reg = VMK8055_CNT2_REG;
995 devpriv->usb_tx_buf[reg] = 0x00;
997 cmd = VMK8061_CMD_RST_CNT;
1000 for (n = 0; n < insn->n; n++)
1001 if (vmk80xx_write_packet(devpriv, cmd))
1004 up(&devpriv->limit_sem);
1009 static int vmk80xx_cnt_winsn(struct comedi_device *dev,
1010 struct comedi_subdevice *s,
1011 struct comedi_insn *insn, unsigned int *data)
1013 struct vmk80xx_private *devpriv = dev->private;
1014 unsigned long debtime;
1020 n = rudimentary_check(devpriv, DIR_OUT);
1024 down(&devpriv->limit_sem);
1025 chan = CR_CHAN(insn->chanspec);
1028 cmd = VMK8055_CMD_DEB1_TIME;
1030 cmd = VMK8055_CMD_DEB2_TIME;
1032 for (n = 0; n < insn->n; n++) {
1037 /* TODO: Prevent overflows */
1041 val = int_sqrt(debtime * 1000 / 115);
1042 if (((val + 1) * val) < debtime * 1000 / 115)
1045 devpriv->usb_tx_buf[6 + chan] = val;
1047 if (vmk80xx_write_packet(devpriv, cmd))
1051 up(&devpriv->limit_sem);
1056 static int vmk80xx_pwm_rinsn(struct comedi_device *dev,
1057 struct comedi_subdevice *s,
1058 struct comedi_insn *insn, unsigned int *data)
1060 struct vmk80xx_private *devpriv = dev->private;
1061 unsigned char *tx_buf;
1062 unsigned char *rx_buf;
1066 n = rudimentary_check(devpriv, DIR_IN);
1070 down(&devpriv->limit_sem);
1072 tx_buf = devpriv->usb_tx_buf;
1073 rx_buf = devpriv->usb_rx_buf;
1075 reg[0] = VMK8061_PWM_REG1;
1076 reg[1] = VMK8061_PWM_REG2;
1078 tx_buf[0] = VMK8061_CMD_RD_PWM;
1080 for (n = 0; n < insn->n; n++) {
1081 if (vmk80xx_read_packet(devpriv))
1084 data[n] = rx_buf[reg[0]] + 4 * rx_buf[reg[1]];
1087 up(&devpriv->limit_sem);
1092 static int vmk80xx_pwm_winsn(struct comedi_device *dev,
1093 struct comedi_subdevice *s,
1094 struct comedi_insn *insn, unsigned int *data)
1096 struct vmk80xx_private *devpriv = dev->private;
1097 unsigned char *tx_buf;
1102 n = rudimentary_check(devpriv, DIR_OUT);
1106 down(&devpriv->limit_sem);
1108 tx_buf = devpriv->usb_tx_buf;
1110 reg[0] = VMK8061_PWM_REG1;
1111 reg[1] = VMK8061_PWM_REG2;
1113 cmd = VMK8061_CMD_OUT_PWM;
1116 * The followin piece of code was translated from the inline
1117 * assembler code in the DLL source code.
1120 * mov eax, k ; k is the value (data[n])
1121 * and al, 03h ; al are the lower 8 bits of eax
1122 * mov lo, al ; lo is the low part (tx_buf[reg[0]])
1124 * shr eax, 2 ; right shift eax register by 2
1125 * mov hi, al ; hi is the high part (tx_buf[reg[1]])
1128 for (n = 0; n < insn->n; n++) {
1129 tx_buf[reg[0]] = (unsigned char)(data[n] & 0x03);
1130 tx_buf[reg[1]] = (unsigned char)(data[n] >> 2) & 0xff;
1132 if (vmk80xx_write_packet(devpriv, cmd))
1136 up(&devpriv->limit_sem);
1141 static int vmk80xx_find_usb_endpoints(struct vmk80xx_private *devpriv,
1142 struct usb_interface *intf)
1144 struct usb_host_interface *iface_desc = intf->cur_altsetting;
1145 struct usb_endpoint_descriptor *ep_desc;
1148 if (iface_desc->desc.bNumEndpoints != 2)
1151 for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
1152 ep_desc = &iface_desc->endpoint[i].desc;
1154 if (usb_endpoint_is_int_in(ep_desc) ||
1155 usb_endpoint_is_bulk_in(ep_desc)) {
1156 if (!devpriv->ep_rx)
1157 devpriv->ep_rx = ep_desc;
1161 if (usb_endpoint_is_int_out(ep_desc) ||
1162 usb_endpoint_is_bulk_out(ep_desc)) {
1163 if (!devpriv->ep_tx)
1164 devpriv->ep_tx = ep_desc;
1169 if (!devpriv->ep_rx || !devpriv->ep_tx)
1175 static int vmk80xx_alloc_usb_buffers(struct vmk80xx_private *devpriv)
1179 size = le16_to_cpu(devpriv->ep_rx->wMaxPacketSize);
1180 devpriv->usb_rx_buf = kmalloc(size, GFP_KERNEL);
1181 if (!devpriv->usb_rx_buf)
1184 size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize);
1185 devpriv->usb_tx_buf = kmalloc(size, GFP_KERNEL);
1186 if (!devpriv->usb_tx_buf) {
1187 kfree(devpriv->usb_rx_buf);
1194 static int vmk80xx_attach_common(struct comedi_device *dev,
1195 struct vmk80xx_private *devpriv)
1197 const struct vmk80xx_board *boardinfo;
1199 struct comedi_subdevice *s;
1202 down(&devpriv->limit_sem);
1204 boardinfo = devpriv->board;
1205 dev->board_ptr = boardinfo;
1206 dev->board_name = boardinfo->name;
1207 dev->private = devpriv;
1209 if (boardinfo->model == VMK8055_MODEL)
1213 ret = comedi_alloc_subdevices(dev, n_subd);
1215 up(&devpriv->limit_sem);
1219 /* Analog input subdevice */
1220 s = &dev->subdevices[0];
1221 s->type = COMEDI_SUBD_AI;
1222 s->subdev_flags = SDF_READABLE | SDF_GROUND;
1223 s->n_chan = boardinfo->ai_chans;
1224 s->maxdata = (1 << boardinfo->ai_bits) - 1;
1225 s->range_table = boardinfo->range;
1226 s->insn_read = vmk80xx_ai_rinsn;
1228 /* Analog output subdevice */
1229 s = &dev->subdevices[1];
1230 s->type = COMEDI_SUBD_AO;
1231 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
1232 s->n_chan = boardinfo->ao_chans;
1233 s->maxdata = 0x00ff;
1234 s->range_table = boardinfo->range;
1235 s->insn_write = vmk80xx_ao_winsn;
1236 if (boardinfo->model == VMK8061_MODEL) {
1237 s->subdev_flags |= SDF_READABLE;
1238 s->insn_read = vmk80xx_ao_rinsn;
1241 /* Digital input subdevice */
1242 s = &dev->subdevices[2];
1243 s->type = COMEDI_SUBD_DI;
1244 s->subdev_flags = SDF_READABLE | SDF_GROUND;
1245 s->n_chan = boardinfo->di_chans;
1247 s->insn_read = vmk80xx_di_rinsn;
1248 s->insn_bits = vmk80xx_di_bits;
1250 /* Digital output subdevice */
1251 s = &dev->subdevices[3];
1252 s->type = COMEDI_SUBD_DO;
1253 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
1256 s->insn_write = vmk80xx_do_winsn;
1257 s->insn_bits = vmk80xx_do_bits;
1258 if (boardinfo->model == VMK8061_MODEL) {
1259 s->subdev_flags |= SDF_READABLE;
1260 s->insn_read = vmk80xx_do_rinsn;
1263 /* Counter subdevice */
1264 s = &dev->subdevices[4];
1265 s->type = COMEDI_SUBD_COUNTER;
1266 s->subdev_flags = SDF_READABLE;
1268 s->insn_read = vmk80xx_cnt_rinsn;
1269 s->insn_config = vmk80xx_cnt_cinsn;
1270 if (boardinfo->model == VMK8055_MODEL) {
1271 s->subdev_flags |= SDF_WRITEABLE;
1272 s->maxdata = (1 << boardinfo->cnt_bits) - 1;
1273 s->insn_write = vmk80xx_cnt_winsn;
1277 if (boardinfo->model == VMK8061_MODEL) {
1278 s = &dev->subdevices[5];
1279 s->type = COMEDI_SUBD_PWM;
1280 s->subdev_flags = SDF_READABLE | SDF_WRITEABLE;
1281 s->n_chan = boardinfo->pwm_chans;
1282 s->maxdata = (1 << boardinfo->pwm_bits) - 1;
1283 s->insn_read = vmk80xx_pwm_rinsn;
1284 s->insn_write = vmk80xx_pwm_winsn;
1287 devpriv->attached = 1;
1288 dev_info(dev->class_dev, "vmk80xx: board #%d [%s] attached\n",
1289 devpriv->count, boardinfo->name);
1291 up(&devpriv->limit_sem);
1296 static int vmk80xx_auto_attach(struct comedi_device *dev,
1297 unsigned long context_unused)
1299 struct usb_interface *intf = comedi_to_usb_interface(dev);
1303 mutex_lock(&glb_mutex);
1304 for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
1305 if (vmb[i].probed && vmb[i].intf == intf)
1307 if (i == VMK80XX_MAX_BOARDS)
1309 else if (vmb[i].attached)
1312 ret = vmk80xx_attach_common(dev, &vmb[i]);
1313 mutex_unlock(&glb_mutex);
1317 static void vmk80xx_detach(struct comedi_device *dev)
1319 struct vmk80xx_private *devpriv = dev->private;
1324 mutex_lock(&glb_mutex);
1325 down(&devpriv->limit_sem);
1327 dev->private = NULL;
1329 devpriv->attached = 0;
1330 devpriv->probed = 0;
1331 usb_set_intfdata(devpriv->intf, NULL);
1333 usb_kill_anchored_urbs(&devpriv->rx_anchor);
1334 usb_kill_anchored_urbs(&devpriv->tx_anchor);
1336 kfree(devpriv->usb_rx_buf);
1337 kfree(devpriv->usb_tx_buf);
1339 up(&devpriv->limit_sem);
1340 mutex_unlock(&glb_mutex);
1343 static struct comedi_driver vmk80xx_driver = {
1344 .module = THIS_MODULE,
1345 .driver_name = "vmk80xx",
1346 .auto_attach = vmk80xx_auto_attach,
1347 .detach = vmk80xx_detach,
1350 static int vmk80xx_usb_probe(struct usb_interface *intf,
1351 const struct usb_device_id *id)
1353 const struct vmk80xx_board *boardinfo;
1354 struct vmk80xx_private *devpriv;
1358 mutex_lock(&glb_mutex);
1360 for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
1364 if (i == VMK80XX_MAX_BOARDS) {
1365 mutex_unlock(&glb_mutex);
1371 memset(devpriv, 0x00, sizeof(*devpriv));
1374 ret = vmk80xx_find_usb_endpoints(devpriv, intf);
1376 mutex_unlock(&glb_mutex);
1380 ret = vmk80xx_alloc_usb_buffers(devpriv);
1382 mutex_unlock(&glb_mutex);
1386 devpriv->usb = interface_to_usbdev(intf);
1387 devpriv->intf = intf;
1389 sema_init(&devpriv->limit_sem, 8);
1390 init_waitqueue_head(&devpriv->read_wait);
1391 init_waitqueue_head(&devpriv->write_wait);
1393 init_usb_anchor(&devpriv->rx_anchor);
1394 init_usb_anchor(&devpriv->tx_anchor);
1396 usb_set_intfdata(intf, devpriv);
1398 boardinfo = &vmk80xx_boardinfo[id->driver_info];
1399 devpriv->board = boardinfo;
1401 if (boardinfo->model == VMK8061_MODEL) {
1402 vmk80xx_read_eeprom(devpriv, IC3_VERSION);
1403 dev_info(&intf->dev, "%s\n", devpriv->fw.ic3_vers);
1405 if (vmk80xx_check_data_link(devpriv)) {
1406 vmk80xx_read_eeprom(devpriv, IC6_VERSION);
1407 dev_info(&intf->dev, "%s\n", devpriv->fw.ic6_vers);
1409 dbgcm("comedi#: vmk80xx: no conn. to CPU\n");
1413 if (boardinfo->model == VMK8055_MODEL)
1414 vmk80xx_reset_device(devpriv);
1416 devpriv->probed = 1;
1418 dev_info(&intf->dev, "board #%d [%s] now attached\n",
1419 devpriv->count, boardinfo->name);
1421 mutex_unlock(&glb_mutex);
1423 comedi_usb_auto_config(intf, &vmk80xx_driver);
1428 static const struct usb_device_id vmk80xx_usb_id_table[] = {
1429 { USB_DEVICE(0x10cf, 0x5500), .driver_info = DEVICE_VMK8055 },
1430 { USB_DEVICE(0x10cf, 0x5501), .driver_info = DEVICE_VMK8055 },
1431 { USB_DEVICE(0x10cf, 0x5502), .driver_info = DEVICE_VMK8055 },
1432 { USB_DEVICE(0x10cf, 0x5503), .driver_info = DEVICE_VMK8055 },
1433 { USB_DEVICE(0x10cf, 0x8061), .driver_info = DEVICE_VMK8061 },
1434 { USB_DEVICE(0x10cf, 0x8062), .driver_info = DEVICE_VMK8061 },
1435 { USB_DEVICE(0x10cf, 0x8063), .driver_info = DEVICE_VMK8061 },
1436 { USB_DEVICE(0x10cf, 0x8064), .driver_info = DEVICE_VMK8061 },
1437 { USB_DEVICE(0x10cf, 0x8065), .driver_info = DEVICE_VMK8061 },
1438 { USB_DEVICE(0x10cf, 0x8066), .driver_info = DEVICE_VMK8061 },
1439 { USB_DEVICE(0x10cf, 0x8067), .driver_info = DEVICE_VMK8061 },
1440 { USB_DEVICE(0x10cf, 0x8068), .driver_info = DEVICE_VMK8061 },
1443 MODULE_DEVICE_TABLE(usb, vmk80xx_usb_id_table);
1445 static struct usb_driver vmk80xx_usb_driver = {
1447 .id_table = vmk80xx_usb_id_table,
1448 .probe = vmk80xx_usb_probe,
1449 .disconnect = comedi_usb_auto_unconfig,
1451 module_comedi_usb_driver(vmk80xx_driver, vmk80xx_usb_driver);
1453 MODULE_AUTHOR("Manuel Gebele <forensixs@gmx.de>");
1454 MODULE_DESCRIPTION("Velleman USB Board Low-Level Driver");
1455 MODULE_SUPPORTED_DEVICE("K8055/K8061 aka VM110/VM140");
1456 MODULE_VERSION("0.8.01");
1457 MODULE_LICENSE("GPL");