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 MODULE_AUTHOR("Manuel Gebele <forensixs@gmx.de>");
68 MODULE_DESCRIPTION("Velleman USB Board Low-Level Driver");
69 MODULE_SUPPORTED_DEVICE("K8055/K8061 aka VM110/VM140");
70 MODULE_VERSION("0.8.01");
71 MODULE_LICENSE("GPL");
78 static struct usb_device_id vmk80xx_id_table[] = {
79 { USB_DEVICE(0x10cf, 0x5500), .driver_info = DEVICE_VMK8055 },
80 { USB_DEVICE(0x10cf, 0x5501), .driver_info = DEVICE_VMK8055 },
81 { USB_DEVICE(0x10cf, 0x5502), .driver_info = DEVICE_VMK8055 },
82 { USB_DEVICE(0x10cf, 0x5503), .driver_info = DEVICE_VMK8055 },
83 { USB_DEVICE(0x10cf, 0x8061), .driver_info = DEVICE_VMK8061 },
84 { USB_DEVICE(0x10cf, 0x8062), .driver_info = DEVICE_VMK8061 },
85 { USB_DEVICE(0x10cf, 0x8063), .driver_info = DEVICE_VMK8061 },
86 { USB_DEVICE(0x10cf, 0x8064), .driver_info = DEVICE_VMK8061 },
87 { USB_DEVICE(0x10cf, 0x8065), .driver_info = DEVICE_VMK8061 },
88 { USB_DEVICE(0x10cf, 0x8066), .driver_info = DEVICE_VMK8061 },
89 { USB_DEVICE(0x10cf, 0x8067), .driver_info = DEVICE_VMK8061 },
90 { USB_DEVICE(0x10cf, 0x8068), .driver_info = DEVICE_VMK8061 },
91 { } /* terminating entry */
94 MODULE_DEVICE_TABLE(usb, vmk80xx_id_table);
96 #define VMK8055_DI_REG 0x00
97 #define VMK8055_DO_REG 0x01
98 #define VMK8055_AO1_REG 0x02
99 #define VMK8055_AO2_REG 0x03
100 #define VMK8055_AI1_REG 0x02
101 #define VMK8055_AI2_REG 0x03
102 #define VMK8055_CNT1_REG 0x04
103 #define VMK8055_CNT2_REG 0x06
105 #define VMK8061_CH_REG 0x01
106 #define VMK8061_DI_REG 0x01
107 #define VMK8061_DO_REG 0x01
108 #define VMK8061_PWM_REG1 0x01
109 #define VMK8061_PWM_REG2 0x02
110 #define VMK8061_CNT_REG 0x02
111 #define VMK8061_AO_REG 0x02
112 #define VMK8061_AI_REG1 0x02
113 #define VMK8061_AI_REG2 0x03
115 #define VMK8055_CMD_RST 0x00
116 #define VMK8055_CMD_DEB1_TIME 0x01
117 #define VMK8055_CMD_DEB2_TIME 0x02
118 #define VMK8055_CMD_RST_CNT1 0x03
119 #define VMK8055_CMD_RST_CNT2 0x04
120 #define VMK8055_CMD_WRT_AD 0x05
122 #define VMK8061_CMD_RD_AI 0x00
123 #define VMK8061_CMR_RD_ALL_AI 0x01 /* !non-active! */
124 #define VMK8061_CMD_SET_AO 0x02
125 #define VMK8061_CMD_SET_ALL_AO 0x03 /* !non-active! */
126 #define VMK8061_CMD_OUT_PWM 0x04
127 #define VMK8061_CMD_RD_DI 0x05
128 #define VMK8061_CMD_DO 0x06 /* !non-active! */
129 #define VMK8061_CMD_CLR_DO 0x07
130 #define VMK8061_CMD_SET_DO 0x08
131 #define VMK8061_CMD_RD_CNT 0x09 /* TODO: completely pointless? */
132 #define VMK8061_CMD_RST_CNT 0x0a /* TODO: completely pointless? */
133 #define VMK8061_CMD_RD_VERSION 0x0b /* internal usage */
134 #define VMK8061_CMD_RD_JMP_STAT 0x0c /* TODO: not implemented yet */
135 #define VMK8061_CMD_RD_PWR_STAT 0x0d /* internal usage */
136 #define VMK8061_CMD_RD_DO 0x0e
137 #define VMK8061_CMD_RD_AO 0x0f
138 #define VMK8061_CMD_RD_PWM 0x10
140 #define VMK80XX_MAX_BOARDS COMEDI_NUM_BOARD_MINORS
142 #define TRANS_OUT_BUSY 1
143 #define TRANS_IN_BUSY 2
144 #define TRANS_IN_RUNNING 3
146 #define IC3_VERSION (1 << 0)
147 #define IC6_VERSION (1 << 1)
149 #define URB_RCV_FLAG (1 << 0)
150 #define URB_SND_FLAG (1 << 1)
152 #define CONFIG_VMK80XX_DEBUG
153 #undef CONFIG_VMK80XX_DEBUG
155 #ifdef CONFIG_VMK80XX_DEBUG
156 static int dbgvm = 1;
161 #ifdef CONFIG_COMEDI_DEBUG
162 static int dbgcm = 1;
167 #define dbgvm(fmt, arg...) \
170 printk(KERN_DEBUG fmt, ##arg); \
173 #define dbgcm(fmt, arg...) \
176 printk(KERN_DEBUG fmt, ##arg); \
184 struct firmware_version {
185 unsigned char ic3_vers[32]; /* USB-Controller */
186 unsigned char ic6_vers[32]; /* CPU */
189 static const struct comedi_lrange vmk8055_range = {
193 static const struct comedi_lrange vmk8061_range = {
194 2, { UNI_RANGE(5), UNI_RANGE(10) }
197 struct vmk80xx_board {
199 enum vmk80xx_model model;
200 const struct comedi_lrange *range;
225 struct usb_device *udev;
226 struct usb_interface *intf;
227 struct usb_endpoint_descriptor *ep_rx;
228 struct usb_endpoint_descriptor *ep_tx;
229 struct usb_anchor rx_anchor;
230 struct usb_anchor tx_anchor;
231 struct vmk80xx_board board;
232 struct firmware_version fw;
233 struct semaphore limit_sem;
234 wait_queue_head_t read_wait;
235 wait_queue_head_t write_wait;
236 unsigned char *usb_rx_buf;
237 unsigned char *usb_tx_buf;
244 static struct vmk80xx_usb vmb[VMK80XX_MAX_BOARDS];
246 static DEFINE_MUTEX(glb_mutex);
248 static void vmk80xx_tx_callback(struct urb *urb)
250 struct vmk80xx_usb *dev = urb->context;
251 int stat = urb->status;
253 dbgvm("vmk80xx: %s\n", __func__);
255 if (stat && !(stat == -ENOENT
256 || stat == -ECONNRESET
257 || stat == -ESHUTDOWN))
258 dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n",
261 if (!test_bit(TRANS_OUT_BUSY, &dev->flags))
264 clear_bit(TRANS_OUT_BUSY, &dev->flags);
266 wake_up_interruptible(&dev->write_wait);
269 static void vmk80xx_rx_callback(struct urb *urb)
271 struct vmk80xx_usb *dev = urb->context;
272 int stat = urb->status;
274 dbgvm("vmk80xx: %s\n", __func__);
284 dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n",
291 if (test_bit(TRANS_IN_RUNNING, &dev->flags) && dev->intf) {
292 usb_anchor_urb(urb, &dev->rx_anchor);
294 if (!usb_submit_urb(urb, GFP_KERNEL))
297 err("comedi#: vmk80xx: %s - submit urb failed\n", __func__);
299 usb_unanchor_urb(urb);
302 clear_bit(TRANS_IN_BUSY, &dev->flags);
304 wake_up_interruptible(&dev->read_wait);
307 static int vmk80xx_check_data_link(struct vmk80xx_usb *dev)
309 unsigned int tx_pipe, rx_pipe;
310 unsigned char tx[1], rx[2];
312 dbgvm("vmk80xx: %s\n", __func__);
314 tx_pipe = usb_sndbulkpipe(dev->udev, 0x01);
315 rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81);
317 tx[0] = VMK8061_CMD_RD_PWR_STAT;
319 /* Check that IC6 (PIC16F871) is powered and
320 * running and the data link between IC3 and
321 * IC6 is working properly */
322 usb_bulk_msg(dev->udev, tx_pipe, tx, 1, NULL,
323 dev->ep_tx->bInterval);
324 usb_bulk_msg(dev->udev, rx_pipe, rx, 2, NULL,
330 static void vmk80xx_read_eeprom(struct vmk80xx_usb *dev, int flag)
332 unsigned int tx_pipe, rx_pipe;
333 unsigned char tx[1], rx[64];
336 dbgvm("vmk80xx: %s\n", __func__);
338 tx_pipe = usb_sndbulkpipe(dev->udev, 0x01);
339 rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81);
341 tx[0] = VMK8061_CMD_RD_VERSION;
343 /* Read the firmware version info of IC3 and
344 * IC6 from the internal EEPROM of the IC */
345 usb_bulk_msg(dev->udev, tx_pipe, tx, 1, NULL,
346 dev->ep_tx->bInterval);
347 usb_bulk_msg(dev->udev, rx_pipe, rx, 64, &cnt,
352 if (flag & IC3_VERSION)
353 strncpy(dev->fw.ic3_vers, rx + 1, 24);
354 else /* IC6_VERSION */
355 strncpy(dev->fw.ic6_vers, rx + 25, 24);
358 static int vmk80xx_reset_device(struct vmk80xx_usb *dev)
361 unsigned int tx_pipe;
365 dbgvm("vmk80xx: %s\n", __func__);
367 urb = usb_alloc_urb(0, GFP_KERNEL);
371 tx_pipe = usb_sndintpipe(dev->udev, 0x01);
373 ival = dev->ep_tx->bInterval;
374 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
376 dev->usb_tx_buf[0] = VMK8055_CMD_RST;
377 dev->usb_tx_buf[1] = 0x00;
378 dev->usb_tx_buf[2] = 0x00;
379 dev->usb_tx_buf[3] = 0x00;
380 dev->usb_tx_buf[4] = 0x00;
381 dev->usb_tx_buf[5] = 0x00;
382 dev->usb_tx_buf[6] = 0x00;
383 dev->usb_tx_buf[7] = 0x00;
385 usb_fill_int_urb(urb, dev->udev, tx_pipe, dev->usb_tx_buf,
386 size, vmk80xx_tx_callback, dev, ival);
388 usb_anchor_urb(urb, &dev->tx_anchor);
390 return usb_submit_urb(urb, GFP_KERNEL);
393 static void vmk80xx_build_int_urb(struct urb *urb, int flag)
395 struct vmk80xx_usb *dev = urb->context;
396 __u8 rx_addr, tx_addr;
400 void (*callback)(struct urb *);
403 dbgvm("vmk80xx: %s\n", __func__);
405 if (flag & URB_RCV_FLAG) {
406 rx_addr = dev->ep_rx->bEndpointAddress;
407 pipe = usb_rcvintpipe(dev->udev, rx_addr);
408 buf = dev->usb_rx_buf;
409 size = le16_to_cpu(dev->ep_rx->wMaxPacketSize);
410 callback = vmk80xx_rx_callback;
411 ival = dev->ep_rx->bInterval;
412 } else { /* URB_SND_FLAG */
413 tx_addr = dev->ep_tx->bEndpointAddress;
414 pipe = usb_sndintpipe(dev->udev, tx_addr);
415 buf = dev->usb_tx_buf;
416 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
417 callback = vmk80xx_tx_callback;
418 ival = dev->ep_tx->bInterval;
421 usb_fill_int_urb(urb, dev->udev, pipe, buf,
422 size, callback, dev, ival);
425 static void vmk80xx_do_bulk_msg(struct vmk80xx_usb *dev)
427 __u8 tx_addr, rx_addr;
428 unsigned int tx_pipe, rx_pipe;
431 dbgvm("vmk80xx: %s\n", __func__);
433 set_bit(TRANS_IN_BUSY, &dev->flags);
434 set_bit(TRANS_OUT_BUSY, &dev->flags);
436 tx_addr = dev->ep_tx->bEndpointAddress;
437 rx_addr = dev->ep_rx->bEndpointAddress;
438 tx_pipe = usb_sndbulkpipe(dev->udev, tx_addr);
439 rx_pipe = usb_rcvbulkpipe(dev->udev, rx_addr);
441 /* The max packet size attributes of the K8061
442 * input/output endpoints are identical */
443 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
445 usb_bulk_msg(dev->udev, tx_pipe, dev->usb_tx_buf,
446 size, NULL, dev->ep_tx->bInterval);
447 usb_bulk_msg(dev->udev, rx_pipe, dev->usb_rx_buf,
448 size, NULL, HZ * 10);
450 clear_bit(TRANS_OUT_BUSY, &dev->flags);
451 clear_bit(TRANS_IN_BUSY, &dev->flags);
454 static int vmk80xx_read_packet(struct vmk80xx_usb *dev)
459 dbgvm("vmk80xx: %s\n", __func__);
464 /* Only useful for interrupt transfers */
465 if (test_bit(TRANS_IN_BUSY, &dev->flags))
466 if (wait_event_interruptible(dev->read_wait,
467 !test_bit(TRANS_IN_BUSY, &dev->flags)))
470 if (dev->board.model == VMK8061_MODEL) {
471 vmk80xx_do_bulk_msg(dev);
476 urb = usb_alloc_urb(0, GFP_KERNEL);
481 vmk80xx_build_int_urb(urb, URB_RCV_FLAG);
483 set_bit(TRANS_IN_RUNNING, &dev->flags);
484 set_bit(TRANS_IN_BUSY, &dev->flags);
486 usb_anchor_urb(urb, &dev->rx_anchor);
488 retval = usb_submit_urb(urb, GFP_KERNEL);
492 clear_bit(TRANS_IN_RUNNING, &dev->flags);
493 usb_unanchor_urb(urb);
501 static int vmk80xx_write_packet(struct vmk80xx_usb *dev, int cmd)
506 dbgvm("vmk80xx: %s\n", __func__);
511 if (test_bit(TRANS_OUT_BUSY, &dev->flags))
512 if (wait_event_interruptible(dev->write_wait,
513 !test_bit(TRANS_OUT_BUSY, &dev->flags)))
516 if (dev->board.model == VMK8061_MODEL) {
517 dev->usb_tx_buf[0] = cmd;
518 vmk80xx_do_bulk_msg(dev);
523 urb = usb_alloc_urb(0, GFP_KERNEL);
528 vmk80xx_build_int_urb(urb, URB_SND_FLAG);
530 set_bit(TRANS_OUT_BUSY, &dev->flags);
532 usb_anchor_urb(urb, &dev->tx_anchor);
534 dev->usb_tx_buf[0] = cmd;
536 retval = usb_submit_urb(urb, GFP_KERNEL);
540 clear_bit(TRANS_OUT_BUSY, &dev->flags);
541 usb_unanchor_urb(urb);
552 #define rudimentary_check(dir) \
558 if (!dev->attached) \
560 if ((dir) & DIR_IN) { \
561 if (test_bit(TRANS_IN_BUSY, &dev->flags)) \
563 } else { /* DIR_OUT */ \
564 if (test_bit(TRANS_OUT_BUSY, &dev->flags)) \
569 static int vmk80xx_ai_rinsn(struct comedi_device *cdev,
570 struct comedi_subdevice *s,
571 struct comedi_insn *insn, unsigned int *data)
573 struct vmk80xx_usb *dev = cdev->private;
577 dbgvm("vmk80xx: %s\n", __func__);
579 rudimentary_check(DIR_IN);
581 down(&dev->limit_sem);
582 chan = CR_CHAN(insn->chanspec);
584 switch (dev->board.model) {
587 reg[0] = VMK8055_AI1_REG;
589 reg[0] = VMK8055_AI2_REG;
592 reg[0] = VMK8061_AI_REG1;
593 reg[1] = VMK8061_AI_REG2;
594 dev->usb_tx_buf[0] = VMK8061_CMD_RD_AI;
595 dev->usb_tx_buf[VMK8061_CH_REG] = chan;
599 for (n = 0; n < insn->n; n++) {
600 if (vmk80xx_read_packet(dev))
603 if (dev->board.model == VMK8055_MODEL) {
604 data[n] = dev->usb_rx_buf[reg[0]];
609 data[n] = dev->usb_rx_buf[reg[0]] + 256 *
610 dev->usb_rx_buf[reg[1]];
618 static int vmk80xx_ao_winsn(struct comedi_device *cdev,
619 struct comedi_subdevice *s,
620 struct comedi_insn *insn, unsigned int *data)
622 struct vmk80xx_usb *dev = cdev->private;
626 dbgvm("vmk80xx: %s\n", __func__);
628 rudimentary_check(DIR_OUT);
630 down(&dev->limit_sem);
631 chan = CR_CHAN(insn->chanspec);
633 switch (dev->board.model) {
635 cmd = VMK8055_CMD_WRT_AD;
637 reg = VMK8055_AO1_REG;
639 reg = VMK8055_AO2_REG;
641 default: /* NOTE: avoid compiler warnings */
642 cmd = VMK8061_CMD_SET_AO;
643 reg = VMK8061_AO_REG;
644 dev->usb_tx_buf[VMK8061_CH_REG] = chan;
648 for (n = 0; n < insn->n; n++) {
649 dev->usb_tx_buf[reg] = data[n];
651 if (vmk80xx_write_packet(dev, cmd))
660 static int vmk80xx_ao_rinsn(struct comedi_device *cdev,
661 struct comedi_subdevice *s,
662 struct comedi_insn *insn, unsigned int *data)
664 struct vmk80xx_usb *dev = cdev->private;
668 dbgvm("vmk80xx: %s\n", __func__);
670 rudimentary_check(DIR_IN);
672 down(&dev->limit_sem);
673 chan = CR_CHAN(insn->chanspec);
675 reg = VMK8061_AO_REG - 1;
677 dev->usb_tx_buf[0] = VMK8061_CMD_RD_AO;
679 for (n = 0; n < insn->n; n++) {
680 if (vmk80xx_read_packet(dev))
683 data[n] = dev->usb_rx_buf[reg+chan];
691 static int vmk80xx_di_rinsn(struct comedi_device *cdev,
692 struct comedi_subdevice *s,
693 struct comedi_insn *insn, unsigned int *data)
695 struct vmk80xx_usb *dev = cdev->private;
697 unsigned char *rx_buf;
701 dbgvm("vmk80xx: %s\n", __func__);
703 rudimentary_check(DIR_IN);
705 down(&dev->limit_sem);
706 chan = CR_CHAN(insn->chanspec);
708 rx_buf = dev->usb_rx_buf;
710 if (dev->board.model == VMK8061_MODEL) {
711 reg = VMK8061_DI_REG;
712 dev->usb_tx_buf[0] = VMK8061_CMD_RD_DI;
714 reg = VMK8055_DI_REG;
716 for (n = 0; n < insn->n; n++) {
717 if (vmk80xx_read_packet(dev))
720 if (dev->board.model == VMK8055_MODEL)
721 inp = (((rx_buf[reg] >> 4) & 0x03) |
722 ((rx_buf[reg] << 2) & 0x04) |
723 ((rx_buf[reg] >> 3) & 0x18));
727 data[n] = ((inp & (1 << chan)) > 0);
735 static int vmk80xx_do_winsn(struct comedi_device *cdev,
736 struct comedi_subdevice *s,
737 struct comedi_insn *insn, unsigned int *data)
740 struct vmk80xx_usb *dev = cdev->private;
742 unsigned char *tx_buf;
746 dbgvm("vmk80xx: %s\n", __func__);
748 rudimentary_check(DIR_OUT);
750 down(&dev->limit_sem);
751 chan = CR_CHAN(insn->chanspec);
753 tx_buf = dev->usb_tx_buf;
755 for (n = 0; n < insn->n; n++) {
756 if (dev->board.model == VMK8055_MODEL) {
757 reg = VMK8055_DO_REG;
758 cmd = VMK8055_CMD_WRT_AD;
760 tx_buf[reg] |= (1 << chan);
762 tx_buf[reg] ^= (1 << chan);
768 reg = VMK8061_DO_REG;
770 cmd = VMK8061_CMD_SET_DO;
771 tx_buf[reg] = 1 << chan;
773 cmd = VMK8061_CMD_CLR_DO;
774 tx_buf[reg] = 0xff - (1 << chan);
778 if (vmk80xx_write_packet(dev, cmd))
787 static int vmk80xx_do_rinsn(struct comedi_device *cdev,
788 struct comedi_subdevice *s,
789 struct comedi_insn *insn, unsigned int *data)
791 struct vmk80xx_usb *dev = cdev->private;
795 dbgvm("vmk80xx: %s\n", __func__);
797 rudimentary_check(DIR_IN);
799 down(&dev->limit_sem);
800 chan = CR_CHAN(insn->chanspec);
802 reg = VMK8061_DO_REG;
805 dev->usb_tx_buf[0] = VMK8061_CMD_RD_DO;
807 for (n = 0; n < insn->n; n++) {
808 if (vmk80xx_read_packet(dev))
811 data[n] = (dev->usb_rx_buf[reg] & mask) >> chan;
819 static int vmk80xx_cnt_rinsn(struct comedi_device *cdev,
820 struct comedi_subdevice *s,
821 struct comedi_insn *insn, unsigned int *data)
823 struct vmk80xx_usb *dev = cdev->private;
827 dbgvm("vmk80xx: %s\n", __func__);
829 rudimentary_check(DIR_IN);
831 down(&dev->limit_sem);
832 chan = CR_CHAN(insn->chanspec);
834 switch (dev->board.model) {
837 reg[0] = VMK8055_CNT1_REG;
839 reg[0] = VMK8055_CNT2_REG;
842 reg[0] = VMK8061_CNT_REG;
843 reg[1] = VMK8061_CNT_REG;
844 dev->usb_tx_buf[0] = VMK8061_CMD_RD_CNT;
848 for (n = 0; n < insn->n; n++) {
849 if (vmk80xx_read_packet(dev))
852 if (dev->board.model == VMK8055_MODEL) {
853 data[n] = dev->usb_rx_buf[reg[0]];
858 data[n] = dev->usb_rx_buf[reg[0]*(chan+1)+1]
859 + 256 * dev->usb_rx_buf[reg[1]*2+2];
867 static int vmk80xx_cnt_cinsn(struct comedi_device *cdev,
868 struct comedi_subdevice *s,
869 struct comedi_insn *insn, unsigned int *data)
871 struct vmk80xx_usb *dev = cdev->private;
872 unsigned int insn_cmd;
876 dbgvm("vmk80xx: %s\n", __func__);
878 rudimentary_check(DIR_OUT);
880 down(&dev->limit_sem);
883 if (insn_cmd != INSN_CONFIG_RESET && insn_cmd != GPCT_RESET)
886 chan = CR_CHAN(insn->chanspec);
888 if (dev->board.model == VMK8055_MODEL) {
890 cmd = VMK8055_CMD_RST_CNT1;
891 reg = VMK8055_CNT1_REG;
893 cmd = VMK8055_CMD_RST_CNT2;
894 reg = VMK8055_CNT2_REG;
897 dev->usb_tx_buf[reg] = 0x00;
899 cmd = VMK8061_CMD_RST_CNT;
901 for (n = 0; n < insn->n; n++)
902 if (vmk80xx_write_packet(dev, cmd))
910 static int vmk80xx_cnt_winsn(struct comedi_device *cdev,
911 struct comedi_subdevice *s,
912 struct comedi_insn *insn, unsigned int *data)
914 struct vmk80xx_usb *dev = cdev->private;
915 unsigned long debtime, val;
919 dbgvm("vmk80xx: %s\n", __func__);
921 rudimentary_check(DIR_OUT);
923 down(&dev->limit_sem);
924 chan = CR_CHAN(insn->chanspec);
927 cmd = VMK8055_CMD_DEB1_TIME;
929 cmd = VMK8055_CMD_DEB2_TIME;
931 for (n = 0; n < insn->n; n++) {
936 /* TODO: Prevent overflows */
940 val = int_sqrt(debtime * 1000 / 115);
941 if (((val + 1) * val) < debtime * 1000 / 115)
944 dev->usb_tx_buf[6+chan] = val;
946 if (vmk80xx_write_packet(dev, cmd))
955 static int vmk80xx_pwm_rinsn(struct comedi_device *cdev,
956 struct comedi_subdevice *s,
957 struct comedi_insn *insn, unsigned int *data)
959 struct vmk80xx_usb *dev = cdev->private;
963 dbgvm("vmk80xx: %s\n", __func__);
965 rudimentary_check(DIR_IN);
967 down(&dev->limit_sem);
969 reg[0] = VMK8061_PWM_REG1;
970 reg[1] = VMK8061_PWM_REG2;
972 dev->usb_tx_buf[0] = VMK8061_CMD_RD_PWM;
974 for (n = 0; n < insn->n; n++) {
975 if (vmk80xx_read_packet(dev))
978 data[n] = dev->usb_rx_buf[reg[0]] + 4 *
979 dev->usb_rx_buf[reg[1]];
987 static int vmk80xx_pwm_winsn(struct comedi_device *cdev,
988 struct comedi_subdevice *s,
989 struct comedi_insn *insn, unsigned int *data)
991 struct vmk80xx_usb *dev = cdev->private;
992 unsigned char *tx_buf;
996 dbgvm("vmk80xx: %s\n", __func__);
998 rudimentary_check(DIR_OUT);
1000 down(&dev->limit_sem);
1002 tx_buf = dev->usb_tx_buf;
1004 reg[0] = VMK8061_PWM_REG1;
1005 reg[1] = VMK8061_PWM_REG2;
1007 cmd = VMK8061_CMD_OUT_PWM;
1010 * The followin piece of code was translated from the inline
1011 * assembler code in the DLL source code.
1014 * mov eax, k ; k is the value (data[n])
1015 * and al, 03h ; al are the lower 8 bits of eax
1016 * mov lo, al ; lo is the low part (tx_buf[reg[0]])
1018 * shr eax, 2 ; right shift eax register by 2
1019 * mov hi, al ; hi is the high part (tx_buf[reg[1]])
1022 for (n = 0; n < insn->n; n++) {
1023 tx_buf[reg[0]] = (unsigned char)(data[n] & 0x03);
1024 tx_buf[reg[1]] = (unsigned char)(data[n] >> 2) & 0xff;
1026 if (vmk80xx_write_packet(dev, cmd))
1030 up(&dev->limit_sem);
1036 vmk80xx_attach(struct comedi_device *cdev, struct comedi_devconfig *it)
1039 struct vmk80xx_usb *dev;
1041 struct comedi_subdevice *s;
1044 dbgvm("vmk80xx: %s\n", __func__);
1046 mutex_lock(&glb_mutex);
1048 for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
1049 if (vmb[i].probed && !vmb[i].attached)
1052 if (i == VMK80XX_MAX_BOARDS) {
1053 mutex_unlock(&glb_mutex);
1059 down(&dev->limit_sem);
1061 cdev->board_name = dev->board.name;
1062 cdev->private = dev;
1064 if (dev->board.model == VMK8055_MODEL)
1069 if (alloc_subdevices(cdev, n_subd) < 0) {
1070 up(&dev->limit_sem);
1071 mutex_unlock(&glb_mutex);
1075 /* Analog input subdevice */
1076 s = cdev->subdevices + VMK80XX_SUBD_AI;
1077 s->type = COMEDI_SUBD_AI;
1078 s->subdev_flags = SDF_READABLE | SDF_GROUND;
1079 s->n_chan = dev->board.ai_chans;
1080 s->maxdata = (1 << dev->board.ai_bits) - 1;
1081 s->range_table = dev->board.range;
1082 s->insn_read = vmk80xx_ai_rinsn;
1084 /* Analog output subdevice */
1085 s = cdev->subdevices + VMK80XX_SUBD_AO;
1086 s->type = COMEDI_SUBD_AO;
1087 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
1088 s->n_chan = dev->board.ao_chans;
1089 s->maxdata = (1 << dev->board.ao_bits) - 1;
1090 s->range_table = dev->board.range;
1091 s->insn_write = vmk80xx_ao_winsn;
1093 if (dev->board.model == VMK8061_MODEL) {
1094 s->subdev_flags |= SDF_READABLE;
1095 s->insn_read = vmk80xx_ao_rinsn;
1098 /* Digital input subdevice */
1099 s = cdev->subdevices + VMK80XX_SUBD_DI;
1100 s->type = COMEDI_SUBD_DI;
1101 s->subdev_flags = SDF_READABLE | SDF_GROUND;
1102 s->n_chan = dev->board.di_chans;
1103 s->maxdata = (1 << dev->board.di_bits) - 1;
1104 s->insn_read = vmk80xx_di_rinsn;
1106 /* Digital output subdevice */
1107 s = cdev->subdevices + VMK80XX_SUBD_DO;
1108 s->type = COMEDI_SUBD_DO;
1109 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
1110 s->n_chan = dev->board.do_chans;
1111 s->maxdata = (1 << dev->board.do_bits) - 1;
1112 s->insn_write = vmk80xx_do_winsn;
1114 if (dev->board.model == VMK8061_MODEL) {
1115 s->subdev_flags |= SDF_READABLE;
1116 s->insn_read = vmk80xx_do_rinsn;
1119 /* Counter subdevice */
1120 s = cdev->subdevices + VMK80XX_SUBD_CNT;
1121 s->type = COMEDI_SUBD_COUNTER;
1122 s->subdev_flags = SDF_READABLE;
1123 s->n_chan = dev->board.cnt_chans;
1124 s->insn_read = vmk80xx_cnt_rinsn;
1125 s->insn_config = vmk80xx_cnt_cinsn;
1127 if (dev->board.model == VMK8055_MODEL) {
1128 s->subdev_flags |= SDF_WRITEABLE;
1129 s->maxdata = (1 << dev->board.cnt_bits) - 1;
1130 s->insn_write = vmk80xx_cnt_winsn;
1134 if (dev->board.model == VMK8061_MODEL) {
1135 s = cdev->subdevices + VMK80XX_SUBD_PWM;
1136 s->type = COMEDI_SUBD_PWM;
1137 s->subdev_flags = SDF_READABLE | SDF_WRITEABLE;
1138 s->n_chan = dev->board.pwm_chans;
1139 s->maxdata = (1 << dev->board.pwm_bits) - 1;
1140 s->insn_read = vmk80xx_pwm_rinsn;
1141 s->insn_write = vmk80xx_pwm_winsn;
1146 minor = cdev->minor;
1149 "comedi%d: vmk80xx: board #%d [%s] attached to comedi\n",
1150 minor, dev->count, dev->board.name);
1152 up(&dev->limit_sem);
1153 mutex_unlock(&glb_mutex);
1158 static int vmk80xx_detach(struct comedi_device *cdev)
1160 struct vmk80xx_usb *dev;
1163 dbgvm("vmk80xx: %s\n", __func__);
1168 dev = cdev->private;
1172 down(&dev->limit_sem);
1174 cdev->private = NULL;
1177 minor = cdev->minor;
1180 "comedi%d: vmk80xx: board #%d [%s] detached from comedi\n",
1181 minor, dev->count, dev->board.name);
1183 up(&dev->limit_sem);
1189 vmk80xx_probe(struct usb_interface *intf, const struct usb_device_id *id)
1192 struct vmk80xx_usb *dev;
1193 struct usb_host_interface *iface_desc;
1194 struct usb_endpoint_descriptor *ep_desc;
1197 dbgvm("vmk80xx: %s\n", __func__);
1199 mutex_lock(&glb_mutex);
1201 for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
1205 if (i == VMK80XX_MAX_BOARDS) {
1206 mutex_unlock(&glb_mutex);
1212 memset(dev, 0x00, sizeof(struct vmk80xx_usb));
1215 iface_desc = intf->cur_altsetting;
1216 if (iface_desc->desc.bNumEndpoints != 2)
1219 for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
1220 ep_desc = &iface_desc->endpoint[i].desc;
1222 if (usb_endpoint_is_int_in(ep_desc)) {
1223 dev->ep_rx = ep_desc;
1227 if (usb_endpoint_is_int_out(ep_desc)) {
1228 dev->ep_tx = ep_desc;
1232 if (usb_endpoint_is_bulk_in(ep_desc)) {
1233 dev->ep_rx = ep_desc;
1237 if (usb_endpoint_is_bulk_out(ep_desc)) {
1238 dev->ep_tx = ep_desc;
1243 if (!dev->ep_rx || !dev->ep_tx)
1246 size = le16_to_cpu(dev->ep_rx->wMaxPacketSize);
1247 dev->usb_rx_buf = kmalloc(size, GFP_KERNEL);
1248 if (!dev->usb_rx_buf) {
1249 mutex_unlock(&glb_mutex);
1253 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
1254 dev->usb_tx_buf = kmalloc(size, GFP_KERNEL);
1255 if (!dev->usb_tx_buf) {
1256 kfree(dev->usb_rx_buf);
1257 mutex_unlock(&glb_mutex);
1261 dev->udev = interface_to_usbdev(intf);
1264 sema_init(&dev->limit_sem, 8);
1265 init_waitqueue_head(&dev->read_wait);
1266 init_waitqueue_head(&dev->write_wait);
1268 init_usb_anchor(&dev->rx_anchor);
1269 init_usb_anchor(&dev->tx_anchor);
1271 usb_set_intfdata(intf, dev);
1273 switch (id->driver_info) {
1274 case DEVICE_VMK8055:
1275 dev->board.name = "K8055 (VM110)";
1276 dev->board.model = VMK8055_MODEL;
1277 dev->board.range = &vmk8055_range;
1278 dev->board.ai_chans = 2;
1279 dev->board.ai_bits = 8;
1280 dev->board.ao_chans = 2;
1281 dev->board.ao_bits = 8;
1282 dev->board.di_chans = 5;
1283 dev->board.di_bits = 1;
1284 dev->board.do_chans = 8;
1285 dev->board.do_bits = 1;
1286 dev->board.cnt_chans = 2;
1287 dev->board.cnt_bits = 16;
1288 dev->board.pwm_chans = 0;
1289 dev->board.pwm_bits = 0;
1291 case DEVICE_VMK8061:
1292 dev->board.name = "K8061 (VM140)";
1293 dev->board.model = VMK8061_MODEL;
1294 dev->board.range = &vmk8061_range;
1295 dev->board.ai_chans = 8;
1296 dev->board.ai_bits = 10;
1297 dev->board.ao_chans = 8;
1298 dev->board.ao_bits = 8;
1299 dev->board.di_chans = 8;
1300 dev->board.di_bits = 1;
1301 dev->board.do_chans = 8;
1302 dev->board.do_bits = 1;
1303 dev->board.cnt_chans = 2;
1304 dev->board.cnt_bits = 0;
1305 dev->board.pwm_chans = 1;
1306 dev->board.pwm_bits = 10;
1310 if (dev->board.model == VMK8061_MODEL) {
1311 vmk80xx_read_eeprom(dev, IC3_VERSION);
1312 printk(KERN_INFO "comedi#: vmk80xx: %s\n",
1315 if (vmk80xx_check_data_link(dev)) {
1316 vmk80xx_read_eeprom(dev, IC6_VERSION);
1317 printk(KERN_INFO "comedi#: vmk80xx: %s\n",
1320 dbgcm("comedi#: vmk80xx: no conn. to CPU\n");
1323 if (dev->board.model == VMK8055_MODEL)
1324 vmk80xx_reset_device(dev);
1328 printk(KERN_INFO "comedi#: vmk80xx: board #%d [%s] now attached\n",
1329 dev->count, dev->board.name);
1331 mutex_unlock(&glb_mutex);
1335 mutex_unlock(&glb_mutex);
1340 static void vmk80xx_disconnect(struct usb_interface *intf)
1342 struct vmk80xx_usb *dev = usb_get_intfdata(intf);
1344 dbgvm("vmk80xx: %s\n", __func__);
1349 mutex_lock(&glb_mutex);
1350 down(&dev->limit_sem);
1353 usb_set_intfdata(dev->intf, NULL);
1355 usb_kill_anchored_urbs(&dev->rx_anchor);
1356 usb_kill_anchored_urbs(&dev->tx_anchor);
1358 kfree(dev->usb_rx_buf);
1359 kfree(dev->usb_tx_buf);
1361 printk(KERN_INFO "comedi#: vmk80xx: board #%d [%s] now detached\n",
1362 dev->count, dev->board.name);
1364 up(&dev->limit_sem);
1365 mutex_unlock(&glb_mutex);
1368 /* TODO: Add support for suspend, resume, pre_reset,
1369 * post_reset and flush */
1370 static struct usb_driver vmk80xx_driver = {
1372 .probe = vmk80xx_probe,
1373 .disconnect = vmk80xx_disconnect,
1374 .id_table = vmk80xx_id_table
1377 static struct comedi_driver driver_vmk80xx = {
1378 .module = THIS_MODULE,
1379 .driver_name = "vmk80xx",
1380 .attach = vmk80xx_attach,
1381 .detach = vmk80xx_detach
1384 static int __init vmk80xx_init(void)
1386 printk(KERN_INFO "vmk80xx: version 0.8.01 "
1387 "Manuel Gebele <forensixs@gmx.de>\n");
1388 usb_register(&vmk80xx_driver);
1389 return comedi_driver_register(&driver_vmk80xx);
1392 static void __exit vmk80xx_exit(void)
1394 comedi_driver_unregister(&driver_vmk80xx);
1395 usb_deregister(&vmk80xx_driver);
1398 module_init(vmk80xx_init);
1399 module_exit(vmk80xx_exit);