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.
22 * Description: Velleman USB Board Low-Level Driver
23 * Devices: [Velleman] K8055 (K8055/VM110), K8061 (K8061/VM140),
24 * VM110 (K8055/VM110), VM140 (K8061/VM140)
25 * Author: Manuel Gebele <forensixs@gmx.de>
26 * Updated: Sun, 10 May 2009 11:14:59 +0200
38 #include <linux/kernel.h>
39 #include <linux/module.h>
40 #include <linux/mutex.h>
41 #include <linux/errno.h>
42 #include <linux/input.h>
43 #include <linux/slab.h>
44 #include <linux/poll.h>
45 #include <linux/uaccess.h>
47 #include "../comedi_usb.h"
54 #define VMK8055_DI_REG 0x00
55 #define VMK8055_DO_REG 0x01
56 #define VMK8055_AO1_REG 0x02
57 #define VMK8055_AO2_REG 0x03
58 #define VMK8055_AI1_REG 0x02
59 #define VMK8055_AI2_REG 0x03
60 #define VMK8055_CNT1_REG 0x04
61 #define VMK8055_CNT2_REG 0x06
63 #define VMK8061_CH_REG 0x01
64 #define VMK8061_DI_REG 0x01
65 #define VMK8061_DO_REG 0x01
66 #define VMK8061_PWM_REG1 0x01
67 #define VMK8061_PWM_REG2 0x02
68 #define VMK8061_CNT_REG 0x02
69 #define VMK8061_AO_REG 0x02
70 #define VMK8061_AI_REG1 0x02
71 #define VMK8061_AI_REG2 0x03
73 #define VMK8055_CMD_RST 0x00
74 #define VMK8055_CMD_DEB1_TIME 0x01
75 #define VMK8055_CMD_DEB2_TIME 0x02
76 #define VMK8055_CMD_RST_CNT1 0x03
77 #define VMK8055_CMD_RST_CNT2 0x04
78 #define VMK8055_CMD_WRT_AD 0x05
80 #define VMK8061_CMD_RD_AI 0x00
81 #define VMK8061_CMR_RD_ALL_AI 0x01 /* !non-active! */
82 #define VMK8061_CMD_SET_AO 0x02
83 #define VMK8061_CMD_SET_ALL_AO 0x03 /* !non-active! */
84 #define VMK8061_CMD_OUT_PWM 0x04
85 #define VMK8061_CMD_RD_DI 0x05
86 #define VMK8061_CMD_DO 0x06 /* !non-active! */
87 #define VMK8061_CMD_CLR_DO 0x07
88 #define VMK8061_CMD_SET_DO 0x08
89 #define VMK8061_CMD_RD_CNT 0x09 /* TODO: completely pointless? */
90 #define VMK8061_CMD_RST_CNT 0x0a /* TODO: completely pointless? */
91 #define VMK8061_CMD_RD_VERSION 0x0b /* internal usage */
92 #define VMK8061_CMD_RD_JMP_STAT 0x0c /* TODO: not implemented yet */
93 #define VMK8061_CMD_RD_PWR_STAT 0x0d /* internal usage */
94 #define VMK8061_CMD_RD_DO 0x0e
95 #define VMK8061_CMD_RD_AO 0x0f
96 #define VMK8061_CMD_RD_PWM 0x10
98 #define IC3_VERSION (1 << 0)
99 #define IC6_VERSION (1 << 1)
106 struct firmware_version
{
107 unsigned char ic3_vers
[32]; /* USB-Controller */
108 unsigned char ic6_vers
[32]; /* CPU */
111 static const struct comedi_lrange vmk8061_range
= {
118 struct vmk80xx_board
{
120 enum vmk80xx_model model
;
121 const struct comedi_lrange
*range
;
123 unsigned int ai_maxdata
;
126 unsigned int cnt_maxdata
;
128 unsigned int pwm_maxdata
;
131 static const struct vmk80xx_board vmk80xx_boardinfo
[] = {
133 .name
= "K8055 (VM110)",
134 .model
= VMK8055_MODEL
,
135 .range
= &range_unipolar5
,
137 .ai_maxdata
= 0x00ff,
140 .cnt_maxdata
= 0xffff,
143 .name
= "K8061 (VM140)",
144 .model
= VMK8061_MODEL
,
145 .range
= &vmk8061_range
,
147 .ai_maxdata
= 0x03ff,
150 .cnt_maxdata
= 0, /* unknown, device is not writeable */
152 .pwm_maxdata
= 0x03ff,
156 struct vmk80xx_private
{
157 struct usb_endpoint_descriptor
*ep_rx
;
158 struct usb_endpoint_descriptor
*ep_tx
;
159 struct firmware_version fw
;
160 struct semaphore limit_sem
;
161 unsigned char *usb_rx_buf
;
162 unsigned char *usb_tx_buf
;
163 enum vmk80xx_model model
;
166 static int vmk80xx_check_data_link(struct comedi_device
*dev
)
168 struct vmk80xx_private
*devpriv
= dev
->private;
169 struct usb_device
*usb
= comedi_to_usb_dev(dev
);
170 unsigned int tx_pipe
;
171 unsigned int rx_pipe
;
175 tx_pipe
= usb_sndbulkpipe(usb
, 0x01);
176 rx_pipe
= usb_rcvbulkpipe(usb
, 0x81);
178 tx
[0] = VMK8061_CMD_RD_PWR_STAT
;
181 * Check that IC6 (PIC16F871) is powered and
182 * running and the data link between IC3 and
183 * IC6 is working properly
185 usb_bulk_msg(usb
, tx_pipe
, tx
, 1, NULL
, devpriv
->ep_tx
->bInterval
);
186 usb_bulk_msg(usb
, rx_pipe
, rx
, 2, NULL
, HZ
* 10);
191 static void vmk80xx_read_eeprom(struct comedi_device
*dev
, int flag
)
193 struct vmk80xx_private
*devpriv
= dev
->private;
194 struct usb_device
*usb
= comedi_to_usb_dev(dev
);
195 unsigned int tx_pipe
;
196 unsigned int rx_pipe
;
198 unsigned char rx
[64];
201 tx_pipe
= usb_sndbulkpipe(usb
, 0x01);
202 rx_pipe
= usb_rcvbulkpipe(usb
, 0x81);
204 tx
[0] = VMK8061_CMD_RD_VERSION
;
207 * Read the firmware version info of IC3 and
208 * IC6 from the internal EEPROM of the IC
210 usb_bulk_msg(usb
, tx_pipe
, tx
, 1, NULL
, devpriv
->ep_tx
->bInterval
);
211 usb_bulk_msg(usb
, rx_pipe
, rx
, 64, &cnt
, HZ
* 10);
215 if (flag
& IC3_VERSION
)
216 strncpy(devpriv
->fw
.ic3_vers
, rx
+ 1, 24);
217 else /* IC6_VERSION */
218 strncpy(devpriv
->fw
.ic6_vers
, rx
+ 25, 24);
221 static void vmk80xx_do_bulk_msg(struct comedi_device
*dev
)
223 struct vmk80xx_private
*devpriv
= dev
->private;
224 struct usb_device
*usb
= comedi_to_usb_dev(dev
);
227 unsigned int tx_pipe
;
228 unsigned int rx_pipe
;
231 tx_addr
= devpriv
->ep_tx
->bEndpointAddress
;
232 rx_addr
= devpriv
->ep_rx
->bEndpointAddress
;
233 tx_pipe
= usb_sndbulkpipe(usb
, tx_addr
);
234 rx_pipe
= usb_rcvbulkpipe(usb
, rx_addr
);
237 * The max packet size attributes of the K8061
238 * input/output endpoints are identical
240 size
= le16_to_cpu(devpriv
->ep_tx
->wMaxPacketSize
);
242 usb_bulk_msg(usb
, tx_pipe
, devpriv
->usb_tx_buf
,
243 size
, NULL
, devpriv
->ep_tx
->bInterval
);
244 usb_bulk_msg(usb
, rx_pipe
, devpriv
->usb_rx_buf
, size
, NULL
, HZ
* 10);
247 static int vmk80xx_read_packet(struct comedi_device
*dev
)
249 struct vmk80xx_private
*devpriv
= dev
->private;
250 struct usb_device
*usb
= comedi_to_usb_dev(dev
);
251 struct usb_endpoint_descriptor
*ep
;
254 if (devpriv
->model
== VMK8061_MODEL
) {
255 vmk80xx_do_bulk_msg(dev
);
260 pipe
= usb_rcvintpipe(usb
, ep
->bEndpointAddress
);
261 return usb_interrupt_msg(usb
, pipe
, devpriv
->usb_rx_buf
,
262 le16_to_cpu(ep
->wMaxPacketSize
), NULL
,
266 static int vmk80xx_write_packet(struct comedi_device
*dev
, int cmd
)
268 struct vmk80xx_private
*devpriv
= dev
->private;
269 struct usb_device
*usb
= comedi_to_usb_dev(dev
);
270 struct usb_endpoint_descriptor
*ep
;
273 devpriv
->usb_tx_buf
[0] = cmd
;
275 if (devpriv
->model
== VMK8061_MODEL
) {
276 vmk80xx_do_bulk_msg(dev
);
281 pipe
= usb_sndintpipe(usb
, ep
->bEndpointAddress
);
282 return usb_interrupt_msg(usb
, pipe
, devpriv
->usb_tx_buf
,
283 le16_to_cpu(ep
->wMaxPacketSize
), NULL
,
287 static int vmk80xx_reset_device(struct comedi_device
*dev
)
289 struct vmk80xx_private
*devpriv
= dev
->private;
293 size
= le16_to_cpu(devpriv
->ep_tx
->wMaxPacketSize
);
294 memset(devpriv
->usb_tx_buf
, 0, size
);
295 retval
= vmk80xx_write_packet(dev
, VMK8055_CMD_RST
);
298 /* set outputs to known state as we cannot read them */
299 return vmk80xx_write_packet(dev
, VMK8055_CMD_WRT_AD
);
302 static int vmk80xx_ai_insn_read(struct comedi_device
*dev
,
303 struct comedi_subdevice
*s
,
304 struct comedi_insn
*insn
,
307 struct vmk80xx_private
*devpriv
= dev
->private;
312 down(&devpriv
->limit_sem
);
313 chan
= CR_CHAN(insn
->chanspec
);
315 switch (devpriv
->model
) {
318 reg
[0] = VMK8055_AI1_REG
;
320 reg
[0] = VMK8055_AI2_REG
;
324 reg
[0] = VMK8061_AI_REG1
;
325 reg
[1] = VMK8061_AI_REG2
;
326 devpriv
->usb_tx_buf
[0] = VMK8061_CMD_RD_AI
;
327 devpriv
->usb_tx_buf
[VMK8061_CH_REG
] = chan
;
331 for (n
= 0; n
< insn
->n
; n
++) {
332 if (vmk80xx_read_packet(dev
))
335 if (devpriv
->model
== VMK8055_MODEL
) {
336 data
[n
] = devpriv
->usb_rx_buf
[reg
[0]];
341 data
[n
] = devpriv
->usb_rx_buf
[reg
[0]] + 256 *
342 devpriv
->usb_rx_buf
[reg
[1]];
345 up(&devpriv
->limit_sem
);
350 static int vmk80xx_ao_insn_write(struct comedi_device
*dev
,
351 struct comedi_subdevice
*s
,
352 struct comedi_insn
*insn
,
355 struct vmk80xx_private
*devpriv
= dev
->private;
361 down(&devpriv
->limit_sem
);
362 chan
= CR_CHAN(insn
->chanspec
);
364 switch (devpriv
->model
) {
366 cmd
= VMK8055_CMD_WRT_AD
;
368 reg
= VMK8055_AO1_REG
;
370 reg
= VMK8055_AO2_REG
;
372 default: /* NOTE: avoid compiler warnings */
373 cmd
= VMK8061_CMD_SET_AO
;
374 reg
= VMK8061_AO_REG
;
375 devpriv
->usb_tx_buf
[VMK8061_CH_REG
] = chan
;
379 for (n
= 0; n
< insn
->n
; n
++) {
380 devpriv
->usb_tx_buf
[reg
] = data
[n
];
382 if (vmk80xx_write_packet(dev
, cmd
))
386 up(&devpriv
->limit_sem
);
391 static int vmk80xx_ao_insn_read(struct comedi_device
*dev
,
392 struct comedi_subdevice
*s
,
393 struct comedi_insn
*insn
,
396 struct vmk80xx_private
*devpriv
= dev
->private;
401 down(&devpriv
->limit_sem
);
402 chan
= CR_CHAN(insn
->chanspec
);
404 reg
= VMK8061_AO_REG
- 1;
406 devpriv
->usb_tx_buf
[0] = VMK8061_CMD_RD_AO
;
408 for (n
= 0; n
< insn
->n
; n
++) {
409 if (vmk80xx_read_packet(dev
))
412 data
[n
] = devpriv
->usb_rx_buf
[reg
+ chan
];
415 up(&devpriv
->limit_sem
);
420 static int vmk80xx_di_insn_bits(struct comedi_device
*dev
,
421 struct comedi_subdevice
*s
,
422 struct comedi_insn
*insn
,
425 struct vmk80xx_private
*devpriv
= dev
->private;
426 unsigned char *rx_buf
;
430 down(&devpriv
->limit_sem
);
432 rx_buf
= devpriv
->usb_rx_buf
;
434 if (devpriv
->model
== VMK8061_MODEL
) {
435 reg
= VMK8061_DI_REG
;
436 devpriv
->usb_tx_buf
[0] = VMK8061_CMD_RD_DI
;
438 reg
= VMK8055_DI_REG
;
441 retval
= vmk80xx_read_packet(dev
);
444 if (devpriv
->model
== VMK8055_MODEL
)
445 data
[1] = (((rx_buf
[reg
] >> 4) & 0x03) |
446 ((rx_buf
[reg
] << 2) & 0x04) |
447 ((rx_buf
[reg
] >> 3) & 0x18));
449 data
[1] = rx_buf
[reg
];
454 up(&devpriv
->limit_sem
);
459 static int vmk80xx_do_insn_bits(struct comedi_device
*dev
,
460 struct comedi_subdevice
*s
,
461 struct comedi_insn
*insn
,
464 struct vmk80xx_private
*devpriv
= dev
->private;
465 unsigned char *rx_buf
= devpriv
->usb_rx_buf
;
466 unsigned char *tx_buf
= devpriv
->usb_tx_buf
;
470 if (devpriv
->model
== VMK8061_MODEL
) {
471 reg
= VMK8061_DO_REG
;
472 cmd
= VMK8061_CMD_DO
;
473 } else { /* VMK8055_MODEL */
474 reg
= VMK8055_DO_REG
;
475 cmd
= VMK8055_CMD_WRT_AD
;
478 down(&devpriv
->limit_sem
);
480 if (comedi_dio_update_state(s
, data
)) {
481 tx_buf
[reg
] = s
->state
;
482 ret
= vmk80xx_write_packet(dev
, cmd
);
487 if (devpriv
->model
== VMK8061_MODEL
) {
488 tx_buf
[0] = VMK8061_CMD_RD_DO
;
489 ret
= vmk80xx_read_packet(dev
);
492 data
[1] = rx_buf
[reg
];
498 up(&devpriv
->limit_sem
);
500 return ret
? ret
: insn
->n
;
503 static int vmk80xx_cnt_insn_read(struct comedi_device
*dev
,
504 struct comedi_subdevice
*s
,
505 struct comedi_insn
*insn
,
508 struct vmk80xx_private
*devpriv
= dev
->private;
513 down(&devpriv
->limit_sem
);
514 chan
= CR_CHAN(insn
->chanspec
);
516 switch (devpriv
->model
) {
519 reg
[0] = VMK8055_CNT1_REG
;
521 reg
[0] = VMK8055_CNT2_REG
;
525 reg
[0] = VMK8061_CNT_REG
;
526 reg
[1] = VMK8061_CNT_REG
;
527 devpriv
->usb_tx_buf
[0] = VMK8061_CMD_RD_CNT
;
531 for (n
= 0; n
< insn
->n
; n
++) {
532 if (vmk80xx_read_packet(dev
))
535 if (devpriv
->model
== VMK8055_MODEL
)
536 data
[n
] = devpriv
->usb_rx_buf
[reg
[0]];
537 else /* VMK8061_MODEL */
538 data
[n
] = devpriv
->usb_rx_buf
[reg
[0] * (chan
+ 1) + 1]
539 + 256 * devpriv
->usb_rx_buf
[reg
[1] * 2 + 2];
542 up(&devpriv
->limit_sem
);
547 static int vmk80xx_cnt_insn_config(struct comedi_device
*dev
,
548 struct comedi_subdevice
*s
,
549 struct comedi_insn
*insn
,
552 struct vmk80xx_private
*devpriv
= dev
->private;
553 unsigned int chan
= CR_CHAN(insn
->chanspec
);
558 down(&devpriv
->limit_sem
);
560 case INSN_CONFIG_RESET
:
561 if (devpriv
->model
== VMK8055_MODEL
) {
563 cmd
= VMK8055_CMD_RST_CNT1
;
564 reg
= VMK8055_CNT1_REG
;
566 cmd
= VMK8055_CMD_RST_CNT2
;
567 reg
= VMK8055_CNT2_REG
;
569 devpriv
->usb_tx_buf
[reg
] = 0x00;
571 cmd
= VMK8061_CMD_RST_CNT
;
573 ret
= vmk80xx_write_packet(dev
, cmd
);
579 up(&devpriv
->limit_sem
);
581 return ret
? ret
: insn
->n
;
584 static int vmk80xx_cnt_insn_write(struct comedi_device
*dev
,
585 struct comedi_subdevice
*s
,
586 struct comedi_insn
*insn
,
589 struct vmk80xx_private
*devpriv
= dev
->private;
590 unsigned long debtime
;
596 down(&devpriv
->limit_sem
);
597 chan
= CR_CHAN(insn
->chanspec
);
600 cmd
= VMK8055_CMD_DEB1_TIME
;
602 cmd
= VMK8055_CMD_DEB2_TIME
;
604 for (n
= 0; n
< insn
->n
; n
++) {
609 /* TODO: Prevent overflows */
613 val
= int_sqrt(debtime
* 1000 / 115);
614 if (((val
+ 1) * val
) < debtime
* 1000 / 115)
617 devpriv
->usb_tx_buf
[6 + chan
] = val
;
619 if (vmk80xx_write_packet(dev
, cmd
))
623 up(&devpriv
->limit_sem
);
628 static int vmk80xx_pwm_insn_read(struct comedi_device
*dev
,
629 struct comedi_subdevice
*s
,
630 struct comedi_insn
*insn
,
633 struct vmk80xx_private
*devpriv
= dev
->private;
634 unsigned char *tx_buf
;
635 unsigned char *rx_buf
;
639 down(&devpriv
->limit_sem
);
641 tx_buf
= devpriv
->usb_tx_buf
;
642 rx_buf
= devpriv
->usb_rx_buf
;
644 reg
[0] = VMK8061_PWM_REG1
;
645 reg
[1] = VMK8061_PWM_REG2
;
647 tx_buf
[0] = VMK8061_CMD_RD_PWM
;
649 for (n
= 0; n
< insn
->n
; n
++) {
650 if (vmk80xx_read_packet(dev
))
653 data
[n
] = rx_buf
[reg
[0]] + 4 * rx_buf
[reg
[1]];
656 up(&devpriv
->limit_sem
);
661 static int vmk80xx_pwm_insn_write(struct comedi_device
*dev
,
662 struct comedi_subdevice
*s
,
663 struct comedi_insn
*insn
,
666 struct vmk80xx_private
*devpriv
= dev
->private;
667 unsigned char *tx_buf
;
672 down(&devpriv
->limit_sem
);
674 tx_buf
= devpriv
->usb_tx_buf
;
676 reg
[0] = VMK8061_PWM_REG1
;
677 reg
[1] = VMK8061_PWM_REG2
;
679 cmd
= VMK8061_CMD_OUT_PWM
;
682 * The followin piece of code was translated from the inline
683 * assembler code in the DLL source code.
686 * mov eax, k ; k is the value (data[n])
687 * and al, 03h ; al are the lower 8 bits of eax
688 * mov lo, al ; lo is the low part (tx_buf[reg[0]])
690 * shr eax, 2 ; right shift eax register by 2
691 * mov hi, al ; hi is the high part (tx_buf[reg[1]])
694 for (n
= 0; n
< insn
->n
; n
++) {
695 tx_buf
[reg
[0]] = (unsigned char)(data
[n
] & 0x03);
696 tx_buf
[reg
[1]] = (unsigned char)(data
[n
] >> 2) & 0xff;
698 if (vmk80xx_write_packet(dev
, cmd
))
702 up(&devpriv
->limit_sem
);
707 static int vmk80xx_find_usb_endpoints(struct comedi_device
*dev
)
709 struct vmk80xx_private
*devpriv
= dev
->private;
710 struct usb_interface
*intf
= comedi_to_usb_interface(dev
);
711 struct usb_host_interface
*iface_desc
= intf
->cur_altsetting
;
712 struct usb_endpoint_descriptor
*ep_desc
;
715 if (iface_desc
->desc
.bNumEndpoints
!= 2)
718 for (i
= 0; i
< iface_desc
->desc
.bNumEndpoints
; i
++) {
719 ep_desc
= &iface_desc
->endpoint
[i
].desc
;
721 if (usb_endpoint_is_int_in(ep_desc
) ||
722 usb_endpoint_is_bulk_in(ep_desc
)) {
724 devpriv
->ep_rx
= ep_desc
;
728 if (usb_endpoint_is_int_out(ep_desc
) ||
729 usb_endpoint_is_bulk_out(ep_desc
)) {
731 devpriv
->ep_tx
= ep_desc
;
736 if (!devpriv
->ep_rx
|| !devpriv
->ep_tx
)
742 static int vmk80xx_alloc_usb_buffers(struct comedi_device
*dev
)
744 struct vmk80xx_private
*devpriv
= dev
->private;
747 size
= le16_to_cpu(devpriv
->ep_rx
->wMaxPacketSize
);
748 devpriv
->usb_rx_buf
= kzalloc(size
, GFP_KERNEL
);
749 if (!devpriv
->usb_rx_buf
)
752 size
= le16_to_cpu(devpriv
->ep_tx
->wMaxPacketSize
);
753 devpriv
->usb_tx_buf
= kzalloc(size
, GFP_KERNEL
);
754 if (!devpriv
->usb_tx_buf
) {
755 kfree(devpriv
->usb_rx_buf
);
762 static int vmk80xx_init_subdevices(struct comedi_device
*dev
)
764 const struct vmk80xx_board
*boardinfo
= dev
->board_ptr
;
765 struct vmk80xx_private
*devpriv
= dev
->private;
766 struct comedi_subdevice
*s
;
770 down(&devpriv
->limit_sem
);
772 if (devpriv
->model
== VMK8055_MODEL
)
776 ret
= comedi_alloc_subdevices(dev
, n_subd
);
778 up(&devpriv
->limit_sem
);
782 /* Analog input subdevice */
783 s
= &dev
->subdevices
[0];
784 s
->type
= COMEDI_SUBD_AI
;
785 s
->subdev_flags
= SDF_READABLE
| SDF_GROUND
;
786 s
->n_chan
= boardinfo
->ai_nchans
;
787 s
->maxdata
= boardinfo
->ai_maxdata
;
788 s
->range_table
= boardinfo
->range
;
789 s
->insn_read
= vmk80xx_ai_insn_read
;
791 /* Analog output subdevice */
792 s
= &dev
->subdevices
[1];
793 s
->type
= COMEDI_SUBD_AO
;
794 s
->subdev_flags
= SDF_WRITABLE
| SDF_GROUND
;
795 s
->n_chan
= boardinfo
->ao_nchans
;
797 s
->range_table
= boardinfo
->range
;
798 s
->insn_write
= vmk80xx_ao_insn_write
;
799 if (devpriv
->model
== VMK8061_MODEL
) {
800 s
->subdev_flags
|= SDF_READABLE
;
801 s
->insn_read
= vmk80xx_ao_insn_read
;
804 /* Digital input subdevice */
805 s
= &dev
->subdevices
[2];
806 s
->type
= COMEDI_SUBD_DI
;
807 s
->subdev_flags
= SDF_READABLE
;
808 s
->n_chan
= boardinfo
->di_nchans
;
810 s
->range_table
= &range_digital
;
811 s
->insn_bits
= vmk80xx_di_insn_bits
;
813 /* Digital output subdevice */
814 s
= &dev
->subdevices
[3];
815 s
->type
= COMEDI_SUBD_DO
;
816 s
->subdev_flags
= SDF_WRITABLE
;
819 s
->range_table
= &range_digital
;
820 s
->insn_bits
= vmk80xx_do_insn_bits
;
822 /* Counter subdevice */
823 s
= &dev
->subdevices
[4];
824 s
->type
= COMEDI_SUBD_COUNTER
;
825 s
->subdev_flags
= SDF_READABLE
;
827 s
->maxdata
= boardinfo
->cnt_maxdata
;
828 s
->insn_read
= vmk80xx_cnt_insn_read
;
829 s
->insn_config
= vmk80xx_cnt_insn_config
;
830 if (devpriv
->model
== VMK8055_MODEL
) {
831 s
->subdev_flags
|= SDF_WRITABLE
;
832 s
->insn_write
= vmk80xx_cnt_insn_write
;
836 if (devpriv
->model
== VMK8061_MODEL
) {
837 s
= &dev
->subdevices
[5];
838 s
->type
= COMEDI_SUBD_PWM
;
839 s
->subdev_flags
= SDF_READABLE
| SDF_WRITABLE
;
840 s
->n_chan
= boardinfo
->pwm_nchans
;
841 s
->maxdata
= boardinfo
->pwm_maxdata
;
842 s
->insn_read
= vmk80xx_pwm_insn_read
;
843 s
->insn_write
= vmk80xx_pwm_insn_write
;
846 up(&devpriv
->limit_sem
);
851 static int vmk80xx_auto_attach(struct comedi_device
*dev
,
852 unsigned long context
)
854 struct usb_interface
*intf
= comedi_to_usb_interface(dev
);
855 const struct vmk80xx_board
*boardinfo
;
856 struct vmk80xx_private
*devpriv
;
859 boardinfo
= &vmk80xx_boardinfo
[context
];
860 dev
->board_ptr
= boardinfo
;
861 dev
->board_name
= boardinfo
->name
;
863 devpriv
= comedi_alloc_devpriv(dev
, sizeof(*devpriv
));
867 devpriv
->model
= boardinfo
->model
;
869 ret
= vmk80xx_find_usb_endpoints(dev
);
873 ret
= vmk80xx_alloc_usb_buffers(dev
);
877 sema_init(&devpriv
->limit_sem
, 8);
879 usb_set_intfdata(intf
, devpriv
);
881 if (devpriv
->model
== VMK8061_MODEL
) {
882 vmk80xx_read_eeprom(dev
, IC3_VERSION
);
883 dev_info(&intf
->dev
, "%s\n", devpriv
->fw
.ic3_vers
);
885 if (vmk80xx_check_data_link(dev
)) {
886 vmk80xx_read_eeprom(dev
, IC6_VERSION
);
887 dev_info(&intf
->dev
, "%s\n", devpriv
->fw
.ic6_vers
);
891 if (devpriv
->model
== VMK8055_MODEL
)
892 vmk80xx_reset_device(dev
);
894 return vmk80xx_init_subdevices(dev
);
897 static void vmk80xx_detach(struct comedi_device
*dev
)
899 struct usb_interface
*intf
= comedi_to_usb_interface(dev
);
900 struct vmk80xx_private
*devpriv
= dev
->private;
905 down(&devpriv
->limit_sem
);
907 usb_set_intfdata(intf
, NULL
);
909 kfree(devpriv
->usb_rx_buf
);
910 kfree(devpriv
->usb_tx_buf
);
912 up(&devpriv
->limit_sem
);
915 static struct comedi_driver vmk80xx_driver
= {
916 .module
= THIS_MODULE
,
917 .driver_name
= "vmk80xx",
918 .auto_attach
= vmk80xx_auto_attach
,
919 .detach
= vmk80xx_detach
,
922 static int vmk80xx_usb_probe(struct usb_interface
*intf
,
923 const struct usb_device_id
*id
)
925 return comedi_usb_auto_config(intf
, &vmk80xx_driver
, id
->driver_info
);
928 static const struct usb_device_id vmk80xx_usb_id_table
[] = {
929 { USB_DEVICE(0x10cf, 0x5500), .driver_info
= DEVICE_VMK8055
},
930 { USB_DEVICE(0x10cf, 0x5501), .driver_info
= DEVICE_VMK8055
},
931 { USB_DEVICE(0x10cf, 0x5502), .driver_info
= DEVICE_VMK8055
},
932 { USB_DEVICE(0x10cf, 0x5503), .driver_info
= DEVICE_VMK8055
},
933 { USB_DEVICE(0x10cf, 0x8061), .driver_info
= DEVICE_VMK8061
},
934 { USB_DEVICE(0x10cf, 0x8062), .driver_info
= DEVICE_VMK8061
},
935 { USB_DEVICE(0x10cf, 0x8063), .driver_info
= DEVICE_VMK8061
},
936 { USB_DEVICE(0x10cf, 0x8064), .driver_info
= DEVICE_VMK8061
},
937 { USB_DEVICE(0x10cf, 0x8065), .driver_info
= DEVICE_VMK8061
},
938 { USB_DEVICE(0x10cf, 0x8066), .driver_info
= DEVICE_VMK8061
},
939 { USB_DEVICE(0x10cf, 0x8067), .driver_info
= DEVICE_VMK8061
},
940 { USB_DEVICE(0x10cf, 0x8068), .driver_info
= DEVICE_VMK8061
},
943 MODULE_DEVICE_TABLE(usb
, vmk80xx_usb_id_table
);
945 static struct usb_driver vmk80xx_usb_driver
= {
947 .id_table
= vmk80xx_usb_id_table
,
948 .probe
= vmk80xx_usb_probe
,
949 .disconnect
= comedi_usb_auto_unconfig
,
951 module_comedi_usb_driver(vmk80xx_driver
, vmk80xx_usb_driver
);
953 MODULE_AUTHOR("Manuel Gebele <forensixs@gmx.de>");
954 MODULE_DESCRIPTION("Velleman USB Board Low-Level Driver");
955 MODULE_SUPPORTED_DEVICE("K8055/K8061 aka VM110/VM140");
956 MODULE_LICENSE("GPL");