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 const 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 || stat == -ESHUTDOWN))
257 dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n",
260 if (!test_bit(TRANS_OUT_BUSY, &dev->flags))
263 clear_bit(TRANS_OUT_BUSY, &dev->flags);
265 wake_up_interruptible(&dev->write_wait);
268 static void vmk80xx_rx_callback(struct urb *urb)
270 struct vmk80xx_usb *dev = urb->context;
271 int stat = urb->status;
273 dbgvm("vmk80xx: %s\n", __func__);
283 dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n",
290 if (test_bit(TRANS_IN_RUNNING, &dev->flags) && dev->intf) {
291 usb_anchor_urb(urb, &dev->rx_anchor);
293 if (!usb_submit_urb(urb, GFP_KERNEL))
296 err("comedi#: vmk80xx: %s - submit urb failed\n", __func__);
298 usb_unanchor_urb(urb);
301 clear_bit(TRANS_IN_BUSY, &dev->flags);
303 wake_up_interruptible(&dev->read_wait);
306 static int vmk80xx_check_data_link(struct vmk80xx_usb *dev)
308 unsigned int tx_pipe;
309 unsigned int rx_pipe;
313 dbgvm("vmk80xx: %s\n", __func__);
315 tx_pipe = usb_sndbulkpipe(dev->udev, 0x01);
316 rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81);
318 tx[0] = VMK8061_CMD_RD_PWR_STAT;
321 * Check that IC6 (PIC16F871) is powered and
322 * running and the data link between IC3 and
323 * IC6 is working properly
325 usb_bulk_msg(dev->udev, tx_pipe, tx, 1, NULL, dev->ep_tx->bInterval);
326 usb_bulk_msg(dev->udev, rx_pipe, rx, 2, NULL, HZ * 10);
331 static void vmk80xx_read_eeprom(struct vmk80xx_usb *dev, int flag)
333 unsigned int tx_pipe;
334 unsigned int rx_pipe;
336 unsigned char rx[64];
339 dbgvm("vmk80xx: %s\n", __func__);
341 tx_pipe = usb_sndbulkpipe(dev->udev, 0x01);
342 rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81);
344 tx[0] = VMK8061_CMD_RD_VERSION;
347 * Read the firmware version info of IC3 and
348 * IC6 from the internal EEPROM of the IC
350 usb_bulk_msg(dev->udev, tx_pipe, tx, 1, NULL, dev->ep_tx->bInterval);
351 usb_bulk_msg(dev->udev, rx_pipe, rx, 64, &cnt, HZ * 10);
355 if (flag & IC3_VERSION)
356 strncpy(dev->fw.ic3_vers, rx + 1, 24);
357 else /* IC6_VERSION */
358 strncpy(dev->fw.ic6_vers, rx + 25, 24);
361 static int vmk80xx_reset_device(struct vmk80xx_usb *dev)
364 unsigned int tx_pipe;
368 dbgvm("vmk80xx: %s\n", __func__);
370 urb = usb_alloc_urb(0, GFP_KERNEL);
374 tx_pipe = usb_sndintpipe(dev->udev, 0x01);
376 ival = dev->ep_tx->bInterval;
377 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
379 dev->usb_tx_buf[0] = VMK8055_CMD_RST;
380 dev->usb_tx_buf[1] = 0x00;
381 dev->usb_tx_buf[2] = 0x00;
382 dev->usb_tx_buf[3] = 0x00;
383 dev->usb_tx_buf[4] = 0x00;
384 dev->usb_tx_buf[5] = 0x00;
385 dev->usb_tx_buf[6] = 0x00;
386 dev->usb_tx_buf[7] = 0x00;
388 usb_fill_int_urb(urb, dev->udev, tx_pipe, dev->usb_tx_buf,
389 size, vmk80xx_tx_callback, dev, ival);
391 usb_anchor_urb(urb, &dev->tx_anchor);
393 return usb_submit_urb(urb, GFP_KERNEL);
396 static void vmk80xx_build_int_urb(struct urb *urb, int flag)
398 struct vmk80xx_usb *dev = urb->context;
404 void (*callback) (struct urb *);
407 dbgvm("vmk80xx: %s\n", __func__);
409 if (flag & URB_RCV_FLAG) {
410 rx_addr = dev->ep_rx->bEndpointAddress;
411 pipe = usb_rcvintpipe(dev->udev, rx_addr);
412 buf = dev->usb_rx_buf;
413 size = le16_to_cpu(dev->ep_rx->wMaxPacketSize);
414 callback = vmk80xx_rx_callback;
415 ival = dev->ep_rx->bInterval;
416 } else { /* URB_SND_FLAG */
417 tx_addr = dev->ep_tx->bEndpointAddress;
418 pipe = usb_sndintpipe(dev->udev, tx_addr);
419 buf = dev->usb_tx_buf;
420 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
421 callback = vmk80xx_tx_callback;
422 ival = dev->ep_tx->bInterval;
425 usb_fill_int_urb(urb, dev->udev, pipe, buf, size, callback, dev, ival);
428 static void vmk80xx_do_bulk_msg(struct vmk80xx_usb *dev)
432 unsigned int tx_pipe;
433 unsigned int rx_pipe;
436 dbgvm("vmk80xx: %s\n", __func__);
438 set_bit(TRANS_IN_BUSY, &dev->flags);
439 set_bit(TRANS_OUT_BUSY, &dev->flags);
441 tx_addr = dev->ep_tx->bEndpointAddress;
442 rx_addr = dev->ep_rx->bEndpointAddress;
443 tx_pipe = usb_sndbulkpipe(dev->udev, tx_addr);
444 rx_pipe = usb_rcvbulkpipe(dev->udev, rx_addr);
447 * The max packet size attributes of the K8061
448 * input/output endpoints are identical
450 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
452 usb_bulk_msg(dev->udev, tx_pipe, dev->usb_tx_buf,
453 size, NULL, dev->ep_tx->bInterval);
454 usb_bulk_msg(dev->udev, rx_pipe, dev->usb_rx_buf, size, NULL, HZ * 10);
456 clear_bit(TRANS_OUT_BUSY, &dev->flags);
457 clear_bit(TRANS_IN_BUSY, &dev->flags);
460 static int vmk80xx_read_packet(struct vmk80xx_usb *dev)
465 dbgvm("vmk80xx: %s\n", __func__);
470 /* Only useful for interrupt transfers */
471 if (test_bit(TRANS_IN_BUSY, &dev->flags))
472 if (wait_event_interruptible(dev->read_wait,
473 !test_bit(TRANS_IN_BUSY,
477 if (dev->board.model == VMK8061_MODEL) {
478 vmk80xx_do_bulk_msg(dev);
483 urb = usb_alloc_urb(0, GFP_KERNEL);
488 vmk80xx_build_int_urb(urb, URB_RCV_FLAG);
490 set_bit(TRANS_IN_RUNNING, &dev->flags);
491 set_bit(TRANS_IN_BUSY, &dev->flags);
493 usb_anchor_urb(urb, &dev->rx_anchor);
495 retval = usb_submit_urb(urb, GFP_KERNEL);
499 clear_bit(TRANS_IN_RUNNING, &dev->flags);
500 usb_unanchor_urb(urb);
508 static int vmk80xx_write_packet(struct vmk80xx_usb *dev, int cmd)
513 dbgvm("vmk80xx: %s\n", __func__);
518 if (test_bit(TRANS_OUT_BUSY, &dev->flags))
519 if (wait_event_interruptible(dev->write_wait,
520 !test_bit(TRANS_OUT_BUSY,
524 if (dev->board.model == VMK8061_MODEL) {
525 dev->usb_tx_buf[0] = cmd;
526 vmk80xx_do_bulk_msg(dev);
531 urb = usb_alloc_urb(0, GFP_KERNEL);
536 vmk80xx_build_int_urb(urb, URB_SND_FLAG);
538 set_bit(TRANS_OUT_BUSY, &dev->flags);
540 usb_anchor_urb(urb, &dev->tx_anchor);
542 dev->usb_tx_buf[0] = cmd;
544 retval = usb_submit_urb(urb, GFP_KERNEL);
548 clear_bit(TRANS_OUT_BUSY, &dev->flags);
549 usb_unanchor_urb(urb);
560 #define rudimentary_check(dir) \
566 if (!dev->attached) \
568 if ((dir) & DIR_IN) { \
569 if (test_bit(TRANS_IN_BUSY, &dev->flags)) \
571 } else { /* DIR_OUT */ \
572 if (test_bit(TRANS_OUT_BUSY, &dev->flags)) \
577 static int vmk80xx_ai_rinsn(struct comedi_device *cdev,
578 struct comedi_subdevice *s,
579 struct comedi_insn *insn, unsigned int *data)
581 struct vmk80xx_usb *dev = cdev->private;
586 dbgvm("vmk80xx: %s\n", __func__);
588 rudimentary_check(DIR_IN);
590 down(&dev->limit_sem);
591 chan = CR_CHAN(insn->chanspec);
593 switch (dev->board.model) {
596 reg[0] = VMK8055_AI1_REG;
598 reg[0] = VMK8055_AI2_REG;
601 reg[0] = VMK8061_AI_REG1;
602 reg[1] = VMK8061_AI_REG2;
603 dev->usb_tx_buf[0] = VMK8061_CMD_RD_AI;
604 dev->usb_tx_buf[VMK8061_CH_REG] = chan;
608 for (n = 0; n < insn->n; n++) {
609 if (vmk80xx_read_packet(dev))
612 if (dev->board.model == VMK8055_MODEL) {
613 data[n] = dev->usb_rx_buf[reg[0]];
618 data[n] = dev->usb_rx_buf[reg[0]] + 256 *
619 dev->usb_rx_buf[reg[1]];
627 static int vmk80xx_ao_winsn(struct comedi_device *cdev,
628 struct comedi_subdevice *s,
629 struct comedi_insn *insn, unsigned int *data)
631 struct vmk80xx_usb *dev = cdev->private;
637 dbgvm("vmk80xx: %s\n", __func__);
639 rudimentary_check(DIR_OUT);
641 down(&dev->limit_sem);
642 chan = CR_CHAN(insn->chanspec);
644 switch (dev->board.model) {
646 cmd = VMK8055_CMD_WRT_AD;
648 reg = VMK8055_AO1_REG;
650 reg = VMK8055_AO2_REG;
652 default: /* NOTE: avoid compiler warnings */
653 cmd = VMK8061_CMD_SET_AO;
654 reg = VMK8061_AO_REG;
655 dev->usb_tx_buf[VMK8061_CH_REG] = chan;
659 for (n = 0; n < insn->n; n++) {
660 dev->usb_tx_buf[reg] = data[n];
662 if (vmk80xx_write_packet(dev, cmd))
671 static int vmk80xx_ao_rinsn(struct comedi_device *cdev,
672 struct comedi_subdevice *s,
673 struct comedi_insn *insn, unsigned int *data)
675 struct vmk80xx_usb *dev = cdev->private;
680 dbgvm("vmk80xx: %s\n", __func__);
682 rudimentary_check(DIR_IN);
684 down(&dev->limit_sem);
685 chan = CR_CHAN(insn->chanspec);
687 reg = VMK8061_AO_REG - 1;
689 dev->usb_tx_buf[0] = VMK8061_CMD_RD_AO;
691 for (n = 0; n < insn->n; n++) {
692 if (vmk80xx_read_packet(dev))
695 data[n] = dev->usb_rx_buf[reg + chan];
703 static int vmk80xx_di_rinsn(struct comedi_device *cdev,
704 struct comedi_subdevice *s,
705 struct comedi_insn *insn, unsigned int *data)
707 struct vmk80xx_usb *dev = cdev->private;
709 unsigned char *rx_buf;
714 dbgvm("vmk80xx: %s\n", __func__);
716 rudimentary_check(DIR_IN);
718 down(&dev->limit_sem);
719 chan = CR_CHAN(insn->chanspec);
721 rx_buf = dev->usb_rx_buf;
723 if (dev->board.model == VMK8061_MODEL) {
724 reg = VMK8061_DI_REG;
725 dev->usb_tx_buf[0] = VMK8061_CMD_RD_DI;
727 reg = VMK8055_DI_REG;
729 for (n = 0; n < insn->n; n++) {
730 if (vmk80xx_read_packet(dev))
733 if (dev->board.model == VMK8055_MODEL)
734 inp = (((rx_buf[reg] >> 4) & 0x03) |
735 ((rx_buf[reg] << 2) & 0x04) |
736 ((rx_buf[reg] >> 3) & 0x18));
740 data[n] = ((inp & (1 << chan)) > 0);
748 static int vmk80xx_do_winsn(struct comedi_device *cdev,
749 struct comedi_subdevice *s,
750 struct comedi_insn *insn, unsigned int *data)
752 struct vmk80xx_usb *dev = cdev->private;
754 unsigned char *tx_buf;
759 dbgvm("vmk80xx: %s\n", __func__);
761 rudimentary_check(DIR_OUT);
763 down(&dev->limit_sem);
764 chan = CR_CHAN(insn->chanspec);
766 tx_buf = dev->usb_tx_buf;
768 for (n = 0; n < insn->n; n++) {
769 if (dev->board.model == VMK8055_MODEL) {
770 reg = VMK8055_DO_REG;
771 cmd = VMK8055_CMD_WRT_AD;
773 tx_buf[reg] |= (1 << chan);
775 tx_buf[reg] ^= (1 << chan);
776 } else { /* VMK8061_MODEL */
777 reg = VMK8061_DO_REG;
779 cmd = VMK8061_CMD_SET_DO;
780 tx_buf[reg] = 1 << chan;
782 cmd = VMK8061_CMD_CLR_DO;
783 tx_buf[reg] = 0xff - (1 << chan);
787 if (vmk80xx_write_packet(dev, cmd))
796 static int vmk80xx_do_rinsn(struct comedi_device *cdev,
797 struct comedi_subdevice *s,
798 struct comedi_insn *insn, unsigned int *data)
800 struct vmk80xx_usb *dev = cdev->private;
806 dbgvm("vmk80xx: %s\n", __func__);
808 rudimentary_check(DIR_IN);
810 down(&dev->limit_sem);
811 chan = CR_CHAN(insn->chanspec);
813 reg = VMK8061_DO_REG;
816 dev->usb_tx_buf[0] = VMK8061_CMD_RD_DO;
818 for (n = 0; n < insn->n; n++) {
819 if (vmk80xx_read_packet(dev))
822 data[n] = (dev->usb_rx_buf[reg] & mask) >> chan;
830 static int vmk80xx_cnt_rinsn(struct comedi_device *cdev,
831 struct comedi_subdevice *s,
832 struct comedi_insn *insn, unsigned int *data)
834 struct vmk80xx_usb *dev = cdev->private;
839 dbgvm("vmk80xx: %s\n", __func__);
841 rudimentary_check(DIR_IN);
843 down(&dev->limit_sem);
844 chan = CR_CHAN(insn->chanspec);
846 switch (dev->board.model) {
849 reg[0] = VMK8055_CNT1_REG;
851 reg[0] = VMK8055_CNT2_REG;
854 reg[0] = VMK8061_CNT_REG;
855 reg[1] = VMK8061_CNT_REG;
856 dev->usb_tx_buf[0] = VMK8061_CMD_RD_CNT;
860 for (n = 0; n < insn->n; n++) {
861 if (vmk80xx_read_packet(dev))
864 if (dev->board.model == VMK8055_MODEL)
865 data[n] = dev->usb_rx_buf[reg[0]];
866 else /* VMK8061_MODEL */
867 data[n] = dev->usb_rx_buf[reg[0] * (chan + 1) + 1]
868 + 256 * dev->usb_rx_buf[reg[1] * 2 + 2];
876 static int vmk80xx_cnt_cinsn(struct comedi_device *cdev,
877 struct comedi_subdevice *s,
878 struct comedi_insn *insn, unsigned int *data)
880 struct vmk80xx_usb *dev = cdev->private;
881 unsigned int insn_cmd;
887 dbgvm("vmk80xx: %s\n", __func__);
889 rudimentary_check(DIR_OUT);
891 down(&dev->limit_sem);
894 if (insn_cmd != INSN_CONFIG_RESET && insn_cmd != GPCT_RESET)
897 chan = CR_CHAN(insn->chanspec);
899 if (dev->board.model == VMK8055_MODEL) {
901 cmd = VMK8055_CMD_RST_CNT1;
902 reg = VMK8055_CNT1_REG;
904 cmd = VMK8055_CMD_RST_CNT2;
905 reg = VMK8055_CNT2_REG;
908 dev->usb_tx_buf[reg] = 0x00;
910 cmd = VMK8061_CMD_RST_CNT;
913 for (n = 0; n < insn->n; n++)
914 if (vmk80xx_write_packet(dev, cmd))
922 static int vmk80xx_cnt_winsn(struct comedi_device *cdev,
923 struct comedi_subdevice *s,
924 struct comedi_insn *insn, unsigned int *data)
926 struct vmk80xx_usb *dev = cdev->private;
927 unsigned long debtime;
933 dbgvm("vmk80xx: %s\n", __func__);
935 rudimentary_check(DIR_OUT);
937 down(&dev->limit_sem);
938 chan = CR_CHAN(insn->chanspec);
941 cmd = VMK8055_CMD_DEB1_TIME;
943 cmd = VMK8055_CMD_DEB2_TIME;
945 for (n = 0; n < insn->n; n++) {
950 /* TODO: Prevent overflows */
954 val = int_sqrt(debtime * 1000 / 115);
955 if (((val + 1) * val) < debtime * 1000 / 115)
958 dev->usb_tx_buf[6 + chan] = val;
960 if (vmk80xx_write_packet(dev, cmd))
969 static int vmk80xx_pwm_rinsn(struct comedi_device *cdev,
970 struct comedi_subdevice *s,
971 struct comedi_insn *insn, unsigned int *data)
973 struct vmk80xx_usb *dev = cdev->private;
977 dbgvm("vmk80xx: %s\n", __func__);
979 rudimentary_check(DIR_IN);
981 down(&dev->limit_sem);
983 reg[0] = VMK8061_PWM_REG1;
984 reg[1] = VMK8061_PWM_REG2;
986 dev->usb_tx_buf[0] = VMK8061_CMD_RD_PWM;
988 for (n = 0; n < insn->n; n++) {
989 if (vmk80xx_read_packet(dev))
992 data[n] = dev->usb_rx_buf[reg[0]] + 4 * dev->usb_rx_buf[reg[1]];
1000 static int vmk80xx_pwm_winsn(struct comedi_device *cdev,
1001 struct comedi_subdevice *s,
1002 struct comedi_insn *insn, unsigned int *data)
1004 struct vmk80xx_usb *dev = cdev->private;
1005 unsigned char *tx_buf;
1010 dbgvm("vmk80xx: %s\n", __func__);
1012 rudimentary_check(DIR_OUT);
1014 down(&dev->limit_sem);
1016 tx_buf = dev->usb_tx_buf;
1018 reg[0] = VMK8061_PWM_REG1;
1019 reg[1] = VMK8061_PWM_REG2;
1021 cmd = VMK8061_CMD_OUT_PWM;
1024 * The followin piece of code was translated from the inline
1025 * assembler code in the DLL source code.
1028 * mov eax, k ; k is the value (data[n])
1029 * and al, 03h ; al are the lower 8 bits of eax
1030 * mov lo, al ; lo is the low part (tx_buf[reg[0]])
1032 * shr eax, 2 ; right shift eax register by 2
1033 * mov hi, al ; hi is the high part (tx_buf[reg[1]])
1036 for (n = 0; n < insn->n; n++) {
1037 tx_buf[reg[0]] = (unsigned char)(data[n] & 0x03);
1038 tx_buf[reg[1]] = (unsigned char)(data[n] >> 2) & 0xff;
1040 if (vmk80xx_write_packet(dev, cmd))
1044 up(&dev->limit_sem);
1049 static int vmk80xx_attach(struct comedi_device *cdev,
1050 struct comedi_devconfig *it)
1053 struct vmk80xx_usb *dev;
1055 struct comedi_subdevice *s;
1058 dbgvm("vmk80xx: %s\n", __func__);
1060 mutex_lock(&glb_mutex);
1062 for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
1063 if (vmb[i].probed && !vmb[i].attached)
1066 if (i == VMK80XX_MAX_BOARDS) {
1067 mutex_unlock(&glb_mutex);
1073 down(&dev->limit_sem);
1075 cdev->board_name = dev->board.name;
1076 cdev->private = dev;
1078 if (dev->board.model == VMK8055_MODEL)
1083 if (alloc_subdevices(cdev, n_subd) < 0) {
1084 up(&dev->limit_sem);
1085 mutex_unlock(&glb_mutex);
1089 /* Analog input subdevice */
1090 s = cdev->subdevices + VMK80XX_SUBD_AI;
1091 s->type = COMEDI_SUBD_AI;
1092 s->subdev_flags = SDF_READABLE | SDF_GROUND;
1093 s->n_chan = dev->board.ai_chans;
1094 s->maxdata = (1 << dev->board.ai_bits) - 1;
1095 s->range_table = dev->board.range;
1096 s->insn_read = vmk80xx_ai_rinsn;
1098 /* Analog output subdevice */
1099 s = cdev->subdevices + VMK80XX_SUBD_AO;
1100 s->type = COMEDI_SUBD_AO;
1101 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
1102 s->n_chan = dev->board.ao_chans;
1103 s->maxdata = (1 << dev->board.ao_bits) - 1;
1104 s->range_table = dev->board.range;
1105 s->insn_write = vmk80xx_ao_winsn;
1107 if (dev->board.model == VMK8061_MODEL) {
1108 s->subdev_flags |= SDF_READABLE;
1109 s->insn_read = vmk80xx_ao_rinsn;
1112 /* Digital input subdevice */
1113 s = cdev->subdevices + VMK80XX_SUBD_DI;
1114 s->type = COMEDI_SUBD_DI;
1115 s->subdev_flags = SDF_READABLE | SDF_GROUND;
1116 s->n_chan = dev->board.di_chans;
1117 s->maxdata = (1 << dev->board.di_bits) - 1;
1118 s->insn_read = vmk80xx_di_rinsn;
1120 /* Digital output subdevice */
1121 s = cdev->subdevices + VMK80XX_SUBD_DO;
1122 s->type = COMEDI_SUBD_DO;
1123 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
1124 s->n_chan = dev->board.do_chans;
1125 s->maxdata = (1 << dev->board.do_bits) - 1;
1126 s->insn_write = vmk80xx_do_winsn;
1128 if (dev->board.model == VMK8061_MODEL) {
1129 s->subdev_flags |= SDF_READABLE;
1130 s->insn_read = vmk80xx_do_rinsn;
1133 /* Counter subdevice */
1134 s = cdev->subdevices + VMK80XX_SUBD_CNT;
1135 s->type = COMEDI_SUBD_COUNTER;
1136 s->subdev_flags = SDF_READABLE;
1137 s->n_chan = dev->board.cnt_chans;
1138 s->insn_read = vmk80xx_cnt_rinsn;
1139 s->insn_config = vmk80xx_cnt_cinsn;
1141 if (dev->board.model == VMK8055_MODEL) {
1142 s->subdev_flags |= SDF_WRITEABLE;
1143 s->maxdata = (1 << dev->board.cnt_bits) - 1;
1144 s->insn_write = vmk80xx_cnt_winsn;
1148 if (dev->board.model == VMK8061_MODEL) {
1149 s = cdev->subdevices + VMK80XX_SUBD_PWM;
1150 s->type = COMEDI_SUBD_PWM;
1151 s->subdev_flags = SDF_READABLE | SDF_WRITEABLE;
1152 s->n_chan = dev->board.pwm_chans;
1153 s->maxdata = (1 << dev->board.pwm_bits) - 1;
1154 s->insn_read = vmk80xx_pwm_rinsn;
1155 s->insn_write = vmk80xx_pwm_winsn;
1160 minor = cdev->minor;
1163 "comedi%d: vmk80xx: board #%d [%s] attached to comedi\n",
1164 minor, dev->count, dev->board.name);
1166 up(&dev->limit_sem);
1167 mutex_unlock(&glb_mutex);
1172 static int vmk80xx_detach(struct comedi_device *cdev)
1174 struct vmk80xx_usb *dev;
1177 dbgvm("vmk80xx: %s\n", __func__);
1182 dev = cdev->private;
1186 down(&dev->limit_sem);
1188 cdev->private = NULL;
1191 minor = cdev->minor;
1194 "comedi%d: vmk80xx: board #%d [%s] detached from comedi\n",
1195 minor, dev->count, dev->board.name);
1197 up(&dev->limit_sem);
1202 static int vmk80xx_probe(struct usb_interface *intf,
1203 const struct usb_device_id *id)
1206 struct vmk80xx_usb *dev;
1207 struct usb_host_interface *iface_desc;
1208 struct usb_endpoint_descriptor *ep_desc;
1211 dbgvm("vmk80xx: %s\n", __func__);
1213 mutex_lock(&glb_mutex);
1215 for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
1219 if (i == VMK80XX_MAX_BOARDS) {
1220 mutex_unlock(&glb_mutex);
1226 memset(dev, 0x00, sizeof(struct vmk80xx_usb));
1229 iface_desc = intf->cur_altsetting;
1230 if (iface_desc->desc.bNumEndpoints != 2)
1233 for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
1234 ep_desc = &iface_desc->endpoint[i].desc;
1236 if (usb_endpoint_is_int_in(ep_desc)) {
1237 dev->ep_rx = ep_desc;
1241 if (usb_endpoint_is_int_out(ep_desc)) {
1242 dev->ep_tx = ep_desc;
1246 if (usb_endpoint_is_bulk_in(ep_desc)) {
1247 dev->ep_rx = ep_desc;
1251 if (usb_endpoint_is_bulk_out(ep_desc)) {
1252 dev->ep_tx = ep_desc;
1257 if (!dev->ep_rx || !dev->ep_tx)
1260 size = le16_to_cpu(dev->ep_rx->wMaxPacketSize);
1261 dev->usb_rx_buf = kmalloc(size, GFP_KERNEL);
1262 if (!dev->usb_rx_buf) {
1263 mutex_unlock(&glb_mutex);
1267 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
1268 dev->usb_tx_buf = kmalloc(size, GFP_KERNEL);
1269 if (!dev->usb_tx_buf) {
1270 kfree(dev->usb_rx_buf);
1271 mutex_unlock(&glb_mutex);
1275 dev->udev = interface_to_usbdev(intf);
1278 sema_init(&dev->limit_sem, 8);
1279 init_waitqueue_head(&dev->read_wait);
1280 init_waitqueue_head(&dev->write_wait);
1282 init_usb_anchor(&dev->rx_anchor);
1283 init_usb_anchor(&dev->tx_anchor);
1285 usb_set_intfdata(intf, dev);
1287 switch (id->driver_info) {
1288 case DEVICE_VMK8055:
1289 dev->board.name = "K8055 (VM110)";
1290 dev->board.model = VMK8055_MODEL;
1291 dev->board.range = &vmk8055_range;
1292 dev->board.ai_chans = 2;
1293 dev->board.ai_bits = 8;
1294 dev->board.ao_chans = 2;
1295 dev->board.ao_bits = 8;
1296 dev->board.di_chans = 5;
1297 dev->board.di_bits = 1;
1298 dev->board.do_chans = 8;
1299 dev->board.do_bits = 1;
1300 dev->board.cnt_chans = 2;
1301 dev->board.cnt_bits = 16;
1302 dev->board.pwm_chans = 0;
1303 dev->board.pwm_bits = 0;
1305 case DEVICE_VMK8061:
1306 dev->board.name = "K8061 (VM140)";
1307 dev->board.model = VMK8061_MODEL;
1308 dev->board.range = &vmk8061_range;
1309 dev->board.ai_chans = 8;
1310 dev->board.ai_bits = 10;
1311 dev->board.ao_chans = 8;
1312 dev->board.ao_bits = 8;
1313 dev->board.di_chans = 8;
1314 dev->board.di_bits = 1;
1315 dev->board.do_chans = 8;
1316 dev->board.do_bits = 1;
1317 dev->board.cnt_chans = 2;
1318 dev->board.cnt_bits = 0;
1319 dev->board.pwm_chans = 1;
1320 dev->board.pwm_bits = 10;
1324 if (dev->board.model == VMK8061_MODEL) {
1325 vmk80xx_read_eeprom(dev, IC3_VERSION);
1326 printk(KERN_INFO "comedi#: vmk80xx: %s\n", dev->fw.ic3_vers);
1328 if (vmk80xx_check_data_link(dev)) {
1329 vmk80xx_read_eeprom(dev, IC6_VERSION);
1330 printk(KERN_INFO "comedi#: vmk80xx: %s\n",
1333 dbgcm("comedi#: vmk80xx: no conn. to CPU\n");
1337 if (dev->board.model == VMK8055_MODEL)
1338 vmk80xx_reset_device(dev);
1342 printk(KERN_INFO "comedi#: vmk80xx: board #%d [%s] now attached\n",
1343 dev->count, dev->board.name);
1345 mutex_unlock(&glb_mutex);
1349 mutex_unlock(&glb_mutex);
1354 static void vmk80xx_disconnect(struct usb_interface *intf)
1356 struct vmk80xx_usb *dev = usb_get_intfdata(intf);
1358 dbgvm("vmk80xx: %s\n", __func__);
1363 mutex_lock(&glb_mutex);
1364 down(&dev->limit_sem);
1367 usb_set_intfdata(dev->intf, NULL);
1369 usb_kill_anchored_urbs(&dev->rx_anchor);
1370 usb_kill_anchored_urbs(&dev->tx_anchor);
1372 kfree(dev->usb_rx_buf);
1373 kfree(dev->usb_tx_buf);
1375 printk(KERN_INFO "comedi#: vmk80xx: board #%d [%s] now detached\n",
1376 dev->count, dev->board.name);
1378 up(&dev->limit_sem);
1379 mutex_unlock(&glb_mutex);
1382 /* TODO: Add support for suspend, resume, pre_reset,
1383 * post_reset and flush */
1384 static struct usb_driver vmk80xx_driver = {
1386 .probe = vmk80xx_probe,
1387 .disconnect = vmk80xx_disconnect,
1388 .id_table = vmk80xx_id_table
1391 static struct comedi_driver driver_vmk80xx = {
1392 .module = THIS_MODULE,
1393 .driver_name = "vmk80xx",
1394 .attach = vmk80xx_attach,
1395 .detach = vmk80xx_detach
1398 static int __init vmk80xx_init(void)
1400 printk(KERN_INFO "vmk80xx: version 0.8.01 "
1401 "Manuel Gebele <forensixs@gmx.de>\n");
1402 usb_register(&vmk80xx_driver);
1403 return comedi_driver_register(&driver_vmk80xx);
1406 static void __exit vmk80xx_exit(void)
1408 comedi_driver_unregister(&driver_vmk80xx);
1409 usb_deregister(&vmk80xx_driver);
1412 module_init(vmk80xx_init);
1413 module_exit(vmk80xx_exit);