1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42#include <linux/kernel.h>
43#include <linux/module.h>
44#include <linux/mutex.h>
45#include <linux/errno.h>
46#include <linux/input.h>
47#include <linux/slab.h>
48#include <linux/poll.h>
49#include <linux/usb.h>
50#include <linux/uaccess.h>
51
52#include "../comedidev.h"
53
54enum {
55 DEVICE_VMK8055,
56 DEVICE_VMK8061
57};
58
59#define VMK8055_DI_REG 0x00
60#define VMK8055_DO_REG 0x01
61#define VMK8055_AO1_REG 0x02
62#define VMK8055_AO2_REG 0x03
63#define VMK8055_AI1_REG 0x02
64#define VMK8055_AI2_REG 0x03
65#define VMK8055_CNT1_REG 0x04
66#define VMK8055_CNT2_REG 0x06
67
68#define VMK8061_CH_REG 0x01
69#define VMK8061_DI_REG 0x01
70#define VMK8061_DO_REG 0x01
71#define VMK8061_PWM_REG1 0x01
72#define VMK8061_PWM_REG2 0x02
73#define VMK8061_CNT_REG 0x02
74#define VMK8061_AO_REG 0x02
75#define VMK8061_AI_REG1 0x02
76#define VMK8061_AI_REG2 0x03
77
78#define VMK8055_CMD_RST 0x00
79#define VMK8055_CMD_DEB1_TIME 0x01
80#define VMK8055_CMD_DEB2_TIME 0x02
81#define VMK8055_CMD_RST_CNT1 0x03
82#define VMK8055_CMD_RST_CNT2 0x04
83#define VMK8055_CMD_WRT_AD 0x05
84
85#define VMK8061_CMD_RD_AI 0x00
86#define VMK8061_CMR_RD_ALL_AI 0x01
87#define VMK8061_CMD_SET_AO 0x02
88#define VMK8061_CMD_SET_ALL_AO 0x03
89#define VMK8061_CMD_OUT_PWM 0x04
90#define VMK8061_CMD_RD_DI 0x05
91#define VMK8061_CMD_DO 0x06
92#define VMK8061_CMD_CLR_DO 0x07
93#define VMK8061_CMD_SET_DO 0x08
94#define VMK8061_CMD_RD_CNT 0x09
95#define VMK8061_CMD_RST_CNT 0x0a
96#define VMK8061_CMD_RD_VERSION 0x0b
97#define VMK8061_CMD_RD_JMP_STAT 0x0c
98#define VMK8061_CMD_RD_PWR_STAT 0x0d
99#define VMK8061_CMD_RD_DO 0x0e
100#define VMK8061_CMD_RD_AO 0x0f
101#define VMK8061_CMD_RD_PWM 0x10
102
103#define IC3_VERSION (1 << 0)
104#define IC6_VERSION (1 << 1)
105
106enum vmk80xx_model {
107 VMK8055_MODEL,
108 VMK8061_MODEL
109};
110
111struct firmware_version {
112 unsigned char ic3_vers[32];
113 unsigned char ic6_vers[32];
114};
115
116static const struct comedi_lrange vmk8061_range = {
117 2, {
118 UNI_RANGE(5),
119 UNI_RANGE(10)
120 }
121};
122
123struct vmk80xx_board {
124 const char *name;
125 enum vmk80xx_model model;
126 const struct comedi_lrange *range;
127 int ai_nchans;
128 unsigned int ai_maxdata;
129 int ao_nchans;
130 int di_nchans;
131 unsigned int cnt_maxdata;
132 int pwm_nchans;
133 unsigned int pwm_maxdata;
134};
135
136static const struct vmk80xx_board vmk80xx_boardinfo[] = {
137 [DEVICE_VMK8055] = {
138 .name = "K8055 (VM110)",
139 .model = VMK8055_MODEL,
140 .range = &range_unipolar5,
141 .ai_nchans = 2,
142 .ai_maxdata = 0x00ff,
143 .ao_nchans = 2,
144 .di_nchans = 6,
145 .cnt_maxdata = 0xffff,
146 },
147 [DEVICE_VMK8061] = {
148 .name = "K8061 (VM140)",
149 .model = VMK8061_MODEL,
150 .range = &vmk8061_range,
151 .ai_nchans = 8,
152 .ai_maxdata = 0x03ff,
153 .ao_nchans = 8,
154 .di_nchans = 8,
155 .cnt_maxdata = 0,
156 .pwm_nchans = 1,
157 .pwm_maxdata = 0x03ff,
158 },
159};
160
161struct vmk80xx_private {
162 struct usb_device *usb;
163 struct usb_interface *intf;
164 struct usb_endpoint_descriptor *ep_rx;
165 struct usb_endpoint_descriptor *ep_tx;
166 struct firmware_version fw;
167 struct semaphore limit_sem;
168 unsigned char *usb_rx_buf;
169 unsigned char *usb_tx_buf;
170 enum vmk80xx_model model;
171};
172
173static int vmk80xx_check_data_link(struct vmk80xx_private *devpriv)
174{
175 struct usb_device *usb = devpriv->usb;
176 unsigned int tx_pipe;
177 unsigned int rx_pipe;
178 unsigned char tx[1];
179 unsigned char rx[2];
180
181 tx_pipe = usb_sndbulkpipe(usb, 0x01);
182 rx_pipe = usb_rcvbulkpipe(usb, 0x81);
183
184 tx[0] = VMK8061_CMD_RD_PWR_STAT;
185
186
187
188
189
190
191 usb_bulk_msg(usb, tx_pipe, tx, 1, NULL, devpriv->ep_tx->bInterval);
192 usb_bulk_msg(usb, rx_pipe, rx, 2, NULL, HZ * 10);
193
194 return (int)rx[1];
195}
196
197static void vmk80xx_read_eeprom(struct vmk80xx_private *devpriv, int flag)
198{
199 struct usb_device *usb = devpriv->usb;
200 unsigned int tx_pipe;
201 unsigned int rx_pipe;
202 unsigned char tx[1];
203 unsigned char rx[64];
204 int cnt;
205
206 tx_pipe = usb_sndbulkpipe(usb, 0x01);
207 rx_pipe = usb_rcvbulkpipe(usb, 0x81);
208
209 tx[0] = VMK8061_CMD_RD_VERSION;
210
211
212
213
214
215 usb_bulk_msg(usb, tx_pipe, tx, 1, NULL, devpriv->ep_tx->bInterval);
216 usb_bulk_msg(usb, rx_pipe, rx, 64, &cnt, HZ * 10);
217
218 rx[cnt] = '\0';
219
220 if (flag & IC3_VERSION)
221 strncpy(devpriv->fw.ic3_vers, rx + 1, 24);
222 else
223 strncpy(devpriv->fw.ic6_vers, rx + 25, 24);
224}
225
226static void vmk80xx_do_bulk_msg(struct vmk80xx_private *devpriv)
227{
228 struct usb_device *usb = devpriv->usb;
229 __u8 tx_addr;
230 __u8 rx_addr;
231 unsigned int tx_pipe;
232 unsigned int rx_pipe;
233 size_t size;
234
235 tx_addr = devpriv->ep_tx->bEndpointAddress;
236 rx_addr = devpriv->ep_rx->bEndpointAddress;
237 tx_pipe = usb_sndbulkpipe(usb, tx_addr);
238 rx_pipe = usb_rcvbulkpipe(usb, rx_addr);
239
240
241
242
243
244 size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize);
245
246 usb_bulk_msg(usb, tx_pipe, devpriv->usb_tx_buf,
247 size, NULL, devpriv->ep_tx->bInterval);
248 usb_bulk_msg(usb, rx_pipe, devpriv->usb_rx_buf, size, NULL, HZ * 10);
249}
250
251static int vmk80xx_read_packet(struct vmk80xx_private *devpriv)
252{
253 struct usb_device *usb;
254 struct usb_endpoint_descriptor *ep;
255 unsigned int pipe;
256
257 if (!devpriv->intf)
258 return -ENODEV;
259
260 if (devpriv->model == VMK8061_MODEL) {
261 vmk80xx_do_bulk_msg(devpriv);
262 return 0;
263 }
264
265 usb = devpriv->usb;
266 ep = devpriv->ep_rx;
267 pipe = usb_rcvintpipe(usb, ep->bEndpointAddress);
268 return usb_interrupt_msg(usb, pipe, devpriv->usb_rx_buf,
269 le16_to_cpu(ep->wMaxPacketSize), NULL,
270 HZ * 10);
271}
272
273static int vmk80xx_write_packet(struct vmk80xx_private *devpriv, int cmd)
274{
275 struct usb_device *usb;
276 struct usb_endpoint_descriptor *ep;
277 unsigned int pipe;
278
279 if (!devpriv->intf)
280 return -ENODEV;
281
282 devpriv->usb_tx_buf[0] = cmd;
283
284 if (devpriv->model == VMK8061_MODEL) {
285 vmk80xx_do_bulk_msg(devpriv);
286 return 0;
287 }
288
289 usb = devpriv->usb;
290 ep = devpriv->ep_tx;
291 pipe = usb_sndintpipe(usb, ep->bEndpointAddress);
292 return usb_interrupt_msg(usb, pipe, devpriv->usb_tx_buf,
293 le16_to_cpu(ep->wMaxPacketSize), NULL,
294 HZ * 10);
295}
296
297static int vmk80xx_reset_device(struct vmk80xx_private *devpriv)
298{
299 size_t size;
300 int retval;
301
302 size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize);
303 memset(devpriv->usb_tx_buf, 0, size);
304 retval = vmk80xx_write_packet(devpriv, VMK8055_CMD_RST);
305 if (retval)
306 return retval;
307
308 return vmk80xx_write_packet(devpriv, VMK8055_CMD_WRT_AD);
309}
310
311static int vmk80xx_ai_insn_read(struct comedi_device *dev,
312 struct comedi_subdevice *s,
313 struct comedi_insn *insn,
314 unsigned int *data)
315{
316 struct vmk80xx_private *devpriv = dev->private;
317 int chan;
318 int reg[2];
319 int n;
320
321 down(&devpriv->limit_sem);
322 chan = CR_CHAN(insn->chanspec);
323
324 switch (devpriv->model) {
325 case VMK8055_MODEL:
326 if (!chan)
327 reg[0] = VMK8055_AI1_REG;
328 else
329 reg[0] = VMK8055_AI2_REG;
330 break;
331 case VMK8061_MODEL:
332 default:
333 reg[0] = VMK8061_AI_REG1;
334 reg[1] = VMK8061_AI_REG2;
335 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_AI;
336 devpriv->usb_tx_buf[VMK8061_CH_REG] = chan;
337 break;
338 }
339
340 for (n = 0; n < insn->n; n++) {
341 if (vmk80xx_read_packet(devpriv))
342 break;
343
344 if (devpriv->model == VMK8055_MODEL) {
345 data[n] = devpriv->usb_rx_buf[reg[0]];
346 continue;
347 }
348
349
350 data[n] = devpriv->usb_rx_buf[reg[0]] + 256 *
351 devpriv->usb_rx_buf[reg[1]];
352 }
353
354 up(&devpriv->limit_sem);
355
356 return n;
357}
358
359static int vmk80xx_ao_insn_write(struct comedi_device *dev,
360 struct comedi_subdevice *s,
361 struct comedi_insn *insn,
362 unsigned int *data)
363{
364 struct vmk80xx_private *devpriv = dev->private;
365 int chan;
366 int cmd;
367 int reg;
368 int n;
369
370 down(&devpriv->limit_sem);
371 chan = CR_CHAN(insn->chanspec);
372
373 switch (devpriv->model) {
374 case VMK8055_MODEL:
375 cmd = VMK8055_CMD_WRT_AD;
376 if (!chan)
377 reg = VMK8055_AO1_REG;
378 else
379 reg = VMK8055_AO2_REG;
380 break;
381 default:
382 cmd = VMK8061_CMD_SET_AO;
383 reg = VMK8061_AO_REG;
384 devpriv->usb_tx_buf[VMK8061_CH_REG] = chan;
385 break;
386 }
387
388 for (n = 0; n < insn->n; n++) {
389 devpriv->usb_tx_buf[reg] = data[n];
390
391 if (vmk80xx_write_packet(devpriv, cmd))
392 break;
393 }
394
395 up(&devpriv->limit_sem);
396
397 return n;
398}
399
400static int vmk80xx_ao_insn_read(struct comedi_device *dev,
401 struct comedi_subdevice *s,
402 struct comedi_insn *insn,
403 unsigned int *data)
404{
405 struct vmk80xx_private *devpriv = dev->private;
406 int chan;
407 int reg;
408 int n;
409
410 down(&devpriv->limit_sem);
411 chan = CR_CHAN(insn->chanspec);
412
413 reg = VMK8061_AO_REG - 1;
414
415 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_AO;
416
417 for (n = 0; n < insn->n; n++) {
418 if (vmk80xx_read_packet(devpriv))
419 break;
420
421 data[n] = devpriv->usb_rx_buf[reg + chan];
422 }
423
424 up(&devpriv->limit_sem);
425
426 return n;
427}
428
429static int vmk80xx_di_insn_bits(struct comedi_device *dev,
430 struct comedi_subdevice *s,
431 struct comedi_insn *insn,
432 unsigned int *data)
433{
434 struct vmk80xx_private *devpriv = dev->private;
435 unsigned char *rx_buf;
436 int reg;
437 int retval;
438
439 down(&devpriv->limit_sem);
440
441 rx_buf = devpriv->usb_rx_buf;
442
443 if (devpriv->model == VMK8061_MODEL) {
444 reg = VMK8061_DI_REG;
445 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_DI;
446 } else {
447 reg = VMK8055_DI_REG;
448 }
449
450 retval = vmk80xx_read_packet(devpriv);
451
452 if (!retval) {
453 if (devpriv->model == VMK8055_MODEL)
454 data[1] = (((rx_buf[reg] >> 4) & 0x03) |
455 ((rx_buf[reg] << 2) & 0x04) |
456 ((rx_buf[reg] >> 3) & 0x18));
457 else
458 data[1] = rx_buf[reg];
459
460 retval = 2;
461 }
462
463 up(&devpriv->limit_sem);
464
465 return retval;
466}
467
468static int vmk80xx_do_insn_bits(struct comedi_device *dev,
469 struct comedi_subdevice *s,
470 struct comedi_insn *insn,
471 unsigned int *data)
472{
473 struct vmk80xx_private *devpriv = dev->private;
474 unsigned char *rx_buf, *tx_buf;
475 int reg, cmd;
476 int retval;
477
478 if (devpriv->model == VMK8061_MODEL) {
479 reg = VMK8061_DO_REG;
480 cmd = VMK8061_CMD_DO;
481 } else {
482 reg = VMK8055_DO_REG;
483 cmd = VMK8055_CMD_WRT_AD;
484 }
485
486 down(&devpriv->limit_sem);
487
488 rx_buf = devpriv->usb_rx_buf;
489 tx_buf = devpriv->usb_tx_buf;
490
491 if (data[0]) {
492 tx_buf[reg] &= ~data[0];
493 tx_buf[reg] |= (data[0] & data[1]);
494
495 retval = vmk80xx_write_packet(devpriv, cmd);
496
497 if (retval)
498 goto out;
499 }
500
501 if (devpriv->model == VMK8061_MODEL) {
502 tx_buf[0] = VMK8061_CMD_RD_DO;
503
504 retval = vmk80xx_read_packet(devpriv);
505
506 if (!retval) {
507 data[1] = rx_buf[reg];
508 retval = 2;
509 }
510 } else {
511 data[1] = tx_buf[reg];
512 retval = 2;
513 }
514
515out:
516 up(&devpriv->limit_sem);
517
518 return retval;
519}
520
521static int vmk80xx_cnt_insn_read(struct comedi_device *dev,
522 struct comedi_subdevice *s,
523 struct comedi_insn *insn,
524 unsigned int *data)
525{
526 struct vmk80xx_private *devpriv = dev->private;
527 int chan;
528 int reg[2];
529 int n;
530
531 down(&devpriv->limit_sem);
532 chan = CR_CHAN(insn->chanspec);
533
534 switch (devpriv->model) {
535 case VMK8055_MODEL:
536 if (!chan)
537 reg[0] = VMK8055_CNT1_REG;
538 else
539 reg[0] = VMK8055_CNT2_REG;
540 break;
541 case VMK8061_MODEL:
542 default:
543 reg[0] = VMK8061_CNT_REG;
544 reg[1] = VMK8061_CNT_REG;
545 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_CNT;
546 break;
547 }
548
549 for (n = 0; n < insn->n; n++) {
550 if (vmk80xx_read_packet(devpriv))
551 break;
552
553 if (devpriv->model == VMK8055_MODEL)
554 data[n] = devpriv->usb_rx_buf[reg[0]];
555 else
556 data[n] = devpriv->usb_rx_buf[reg[0] * (chan + 1) + 1]
557 + 256 * devpriv->usb_rx_buf[reg[1] * 2 + 2];
558 }
559
560 up(&devpriv->limit_sem);
561
562 return n;
563}
564
565static int vmk80xx_cnt_insn_config(struct comedi_device *dev,
566 struct comedi_subdevice *s,
567 struct comedi_insn *insn,
568 unsigned int *data)
569{
570 struct vmk80xx_private *devpriv = dev->private;
571 unsigned int insn_cmd;
572 int chan;
573 int cmd;
574 int reg;
575 int n;
576
577 insn_cmd = data[0];
578 if (insn_cmd != INSN_CONFIG_RESET && insn_cmd != GPCT_RESET)
579 return -EINVAL;
580
581 down(&devpriv->limit_sem);
582
583 chan = CR_CHAN(insn->chanspec);
584
585 if (devpriv->model == VMK8055_MODEL) {
586 if (!chan) {
587 cmd = VMK8055_CMD_RST_CNT1;
588 reg = VMK8055_CNT1_REG;
589 } else {
590 cmd = VMK8055_CMD_RST_CNT2;
591 reg = VMK8055_CNT2_REG;
592 }
593
594 devpriv->usb_tx_buf[reg] = 0x00;
595 } else {
596 cmd = VMK8061_CMD_RST_CNT;
597 }
598
599 for (n = 0; n < insn->n; n++)
600 if (vmk80xx_write_packet(devpriv, cmd))
601 break;
602
603 up(&devpriv->limit_sem);
604
605 return n;
606}
607
608static int vmk80xx_cnt_insn_write(struct comedi_device *dev,
609 struct comedi_subdevice *s,
610 struct comedi_insn *insn,
611 unsigned int *data)
612{
613 struct vmk80xx_private *devpriv = dev->private;
614 unsigned long debtime;
615 unsigned long val;
616 int chan;
617 int cmd;
618 int n;
619
620 down(&devpriv->limit_sem);
621 chan = CR_CHAN(insn->chanspec);
622
623 if (!chan)
624 cmd = VMK8055_CMD_DEB1_TIME;
625 else
626 cmd = VMK8055_CMD_DEB2_TIME;
627
628 for (n = 0; n < insn->n; n++) {
629 debtime = data[n];
630 if (debtime == 0)
631 debtime = 1;
632
633
634 if (debtime > 7450)
635 debtime = 7450;
636
637 val = int_sqrt(debtime * 1000 / 115);
638 if (((val + 1) * val) < debtime * 1000 / 115)
639 val += 1;
640
641 devpriv->usb_tx_buf[6 + chan] = val;
642
643 if (vmk80xx_write_packet(devpriv, cmd))
644 break;
645 }
646
647 up(&devpriv->limit_sem);
648
649 return n;
650}
651
652static int vmk80xx_pwm_insn_read(struct comedi_device *dev,
653 struct comedi_subdevice *s,
654 struct comedi_insn *insn,
655 unsigned int *data)
656{
657 struct vmk80xx_private *devpriv = dev->private;
658 unsigned char *tx_buf;
659 unsigned char *rx_buf;
660 int reg[2];
661 int n;
662
663 down(&devpriv->limit_sem);
664
665 tx_buf = devpriv->usb_tx_buf;
666 rx_buf = devpriv->usb_rx_buf;
667
668 reg[0] = VMK8061_PWM_REG1;
669 reg[1] = VMK8061_PWM_REG2;
670
671 tx_buf[0] = VMK8061_CMD_RD_PWM;
672
673 for (n = 0; n < insn->n; n++) {
674 if (vmk80xx_read_packet(devpriv))
675 break;
676
677 data[n] = rx_buf[reg[0]] + 4 * rx_buf[reg[1]];
678 }
679
680 up(&devpriv->limit_sem);
681
682 return n;
683}
684
685static int vmk80xx_pwm_insn_write(struct comedi_device *dev,
686 struct comedi_subdevice *s,
687 struct comedi_insn *insn,
688 unsigned int *data)
689{
690 struct vmk80xx_private *devpriv = dev->private;
691 unsigned char *tx_buf;
692 int reg[2];
693 int cmd;
694 int n;
695
696 down(&devpriv->limit_sem);
697
698 tx_buf = devpriv->usb_tx_buf;
699
700 reg[0] = VMK8061_PWM_REG1;
701 reg[1] = VMK8061_PWM_REG2;
702
703 cmd = VMK8061_CMD_OUT_PWM;
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718 for (n = 0; n < insn->n; n++) {
719 tx_buf[reg[0]] = (unsigned char)(data[n] & 0x03);
720 tx_buf[reg[1]] = (unsigned char)(data[n] >> 2) & 0xff;
721
722 if (vmk80xx_write_packet(devpriv, cmd))
723 break;
724 }
725
726 up(&devpriv->limit_sem);
727
728 return n;
729}
730
731static int vmk80xx_find_usb_endpoints(struct comedi_device *dev)
732{
733 struct vmk80xx_private *devpriv = dev->private;
734 struct usb_interface *intf = devpriv->intf;
735 struct usb_host_interface *iface_desc = intf->cur_altsetting;
736 struct usb_endpoint_descriptor *ep_desc;
737 int i;
738
739 if (iface_desc->desc.bNumEndpoints != 2)
740 return -ENODEV;
741
742 for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
743 ep_desc = &iface_desc->endpoint[i].desc;
744
745 if (usb_endpoint_is_int_in(ep_desc) ||
746 usb_endpoint_is_bulk_in(ep_desc)) {
747 if (!devpriv->ep_rx)
748 devpriv->ep_rx = ep_desc;
749 continue;
750 }
751
752 if (usb_endpoint_is_int_out(ep_desc) ||
753 usb_endpoint_is_bulk_out(ep_desc)) {
754 if (!devpriv->ep_tx)
755 devpriv->ep_tx = ep_desc;
756 continue;
757 }
758 }
759
760 if (!devpriv->ep_rx || !devpriv->ep_tx)
761 return -ENODEV;
762
763 return 0;
764}
765
766static int vmk80xx_alloc_usb_buffers(struct comedi_device *dev)
767{
768 struct vmk80xx_private *devpriv = dev->private;
769 size_t size;
770
771 size = le16_to_cpu(devpriv->ep_rx->wMaxPacketSize);
772 devpriv->usb_rx_buf = kzalloc(size, GFP_KERNEL);
773 if (!devpriv->usb_rx_buf)
774 return -ENOMEM;
775
776 size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize);
777 devpriv->usb_tx_buf = kzalloc(size, GFP_KERNEL);
778 if (!devpriv->usb_tx_buf) {
779 kfree(devpriv->usb_rx_buf);
780 return -ENOMEM;
781 }
782
783 return 0;
784}
785
786static int vmk80xx_init_subdevices(struct comedi_device *dev)
787{
788 const struct vmk80xx_board *boardinfo = comedi_board(dev);
789 struct vmk80xx_private *devpriv = dev->private;
790 struct comedi_subdevice *s;
791 int n_subd;
792 int ret;
793
794 down(&devpriv->limit_sem);
795
796 if (devpriv->model == VMK8055_MODEL)
797 n_subd = 5;
798 else
799 n_subd = 6;
800 ret = comedi_alloc_subdevices(dev, n_subd);
801 if (ret) {
802 up(&devpriv->limit_sem);
803 return ret;
804 }
805
806
807 s = &dev->subdevices[0];
808 s->type = COMEDI_SUBD_AI;
809 s->subdev_flags = SDF_READABLE | SDF_GROUND;
810 s->n_chan = boardinfo->ai_nchans;
811 s->maxdata = boardinfo->ai_maxdata;
812 s->range_table = boardinfo->range;
813 s->insn_read = vmk80xx_ai_insn_read;
814
815
816 s = &dev->subdevices[1];
817 s->type = COMEDI_SUBD_AO;
818 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
819 s->n_chan = boardinfo->ao_nchans;
820 s->maxdata = 0x00ff;
821 s->range_table = boardinfo->range;
822 s->insn_write = vmk80xx_ao_insn_write;
823 if (devpriv->model == VMK8061_MODEL) {
824 s->subdev_flags |= SDF_READABLE;
825 s->insn_read = vmk80xx_ao_insn_read;
826 }
827
828
829 s = &dev->subdevices[2];
830 s->type = COMEDI_SUBD_DI;
831 s->subdev_flags = SDF_READABLE;
832 s->n_chan = boardinfo->di_nchans;
833 s->maxdata = 1;
834 s->range_table = &range_digital;
835 s->insn_bits = vmk80xx_di_insn_bits;
836
837
838 s = &dev->subdevices[3];
839 s->type = COMEDI_SUBD_DO;
840 s->subdev_flags = SDF_WRITEABLE;
841 s->n_chan = 8;
842 s->maxdata = 1;
843 s->range_table = &range_digital;
844 s->insn_bits = vmk80xx_do_insn_bits;
845
846
847 s = &dev->subdevices[4];
848 s->type = COMEDI_SUBD_COUNTER;
849 s->subdev_flags = SDF_READABLE;
850 s->n_chan = 2;
851 s->maxdata = boardinfo->cnt_maxdata;
852 s->insn_read = vmk80xx_cnt_insn_read;
853 s->insn_config = vmk80xx_cnt_insn_config;
854 if (devpriv->model == VMK8055_MODEL) {
855 s->subdev_flags |= SDF_WRITEABLE;
856 s->insn_write = vmk80xx_cnt_insn_write;
857 }
858
859
860 if (devpriv->model == VMK8061_MODEL) {
861 s = &dev->subdevices[5];
862 s->type = COMEDI_SUBD_PWM;
863 s->subdev_flags = SDF_READABLE | SDF_WRITEABLE;
864 s->n_chan = boardinfo->pwm_nchans;
865 s->maxdata = boardinfo->pwm_maxdata;
866 s->insn_read = vmk80xx_pwm_insn_read;
867 s->insn_write = vmk80xx_pwm_insn_write;
868 }
869
870 up(&devpriv->limit_sem);
871
872 return 0;
873}
874
875static int vmk80xx_auto_attach(struct comedi_device *dev,
876 unsigned long context)
877{
878 struct usb_interface *intf = comedi_to_usb_interface(dev);
879 const struct vmk80xx_board *boardinfo;
880 struct vmk80xx_private *devpriv;
881 int ret;
882
883 boardinfo = &vmk80xx_boardinfo[context];
884 dev->board_ptr = boardinfo;
885 dev->board_name = boardinfo->name;
886
887 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
888 if (!devpriv)
889 return -ENOMEM;
890 dev->private = devpriv;
891
892 devpriv->usb = interface_to_usbdev(intf);
893 devpriv->intf = intf;
894 devpriv->model = boardinfo->model;
895
896 ret = vmk80xx_find_usb_endpoints(dev);
897 if (ret)
898 return ret;
899
900 ret = vmk80xx_alloc_usb_buffers(dev);
901 if (ret)
902 return ret;
903
904 sema_init(&devpriv->limit_sem, 8);
905
906 usb_set_intfdata(intf, devpriv);
907
908 if (devpriv->model == VMK8061_MODEL) {
909 vmk80xx_read_eeprom(devpriv, IC3_VERSION);
910 dev_info(&intf->dev, "%s\n", devpriv->fw.ic3_vers);
911
912 if (vmk80xx_check_data_link(devpriv)) {
913 vmk80xx_read_eeprom(devpriv, IC6_VERSION);
914 dev_info(&intf->dev, "%s\n", devpriv->fw.ic6_vers);
915 }
916 }
917
918 if (devpriv->model == VMK8055_MODEL)
919 vmk80xx_reset_device(devpriv);
920
921 return vmk80xx_init_subdevices(dev);
922}
923
924static void vmk80xx_detach(struct comedi_device *dev)
925{
926 struct vmk80xx_private *devpriv = dev->private;
927
928 if (!devpriv)
929 return;
930
931 down(&devpriv->limit_sem);
932
933 usb_set_intfdata(devpriv->intf, NULL);
934
935 kfree(devpriv->usb_rx_buf);
936 kfree(devpriv->usb_tx_buf);
937
938 up(&devpriv->limit_sem);
939}
940
941static struct comedi_driver vmk80xx_driver = {
942 .module = THIS_MODULE,
943 .driver_name = "vmk80xx",
944 .auto_attach = vmk80xx_auto_attach,
945 .detach = vmk80xx_detach,
946};
947
948static int vmk80xx_usb_probe(struct usb_interface *intf,
949 const struct usb_device_id *id)
950{
951 return comedi_usb_auto_config(intf, &vmk80xx_driver, id->driver_info);
952}
953
954static const struct usb_device_id vmk80xx_usb_id_table[] = {
955 { USB_DEVICE(0x10cf, 0x5500), .driver_info = DEVICE_VMK8055 },
956 { USB_DEVICE(0x10cf, 0x5501), .driver_info = DEVICE_VMK8055 },
957 { USB_DEVICE(0x10cf, 0x5502), .driver_info = DEVICE_VMK8055 },
958 { USB_DEVICE(0x10cf, 0x5503), .driver_info = DEVICE_VMK8055 },
959 { USB_DEVICE(0x10cf, 0x8061), .driver_info = DEVICE_VMK8061 },
960 { USB_DEVICE(0x10cf, 0x8062), .driver_info = DEVICE_VMK8061 },
961 { USB_DEVICE(0x10cf, 0x8063), .driver_info = DEVICE_VMK8061 },
962 { USB_DEVICE(0x10cf, 0x8064), .driver_info = DEVICE_VMK8061 },
963 { USB_DEVICE(0x10cf, 0x8065), .driver_info = DEVICE_VMK8061 },
964 { USB_DEVICE(0x10cf, 0x8066), .driver_info = DEVICE_VMK8061 },
965 { USB_DEVICE(0x10cf, 0x8067), .driver_info = DEVICE_VMK8061 },
966 { USB_DEVICE(0x10cf, 0x8068), .driver_info = DEVICE_VMK8061 },
967 { }
968};
969MODULE_DEVICE_TABLE(usb, vmk80xx_usb_id_table);
970
971static struct usb_driver vmk80xx_usb_driver = {
972 .name = "vmk80xx",
973 .id_table = vmk80xx_usb_id_table,
974 .probe = vmk80xx_usb_probe,
975 .disconnect = comedi_usb_auto_unconfig,
976};
977module_comedi_usb_driver(vmk80xx_driver, vmk80xx_usb_driver);
978
979MODULE_AUTHOR("Manuel Gebele <forensixs@gmx.de>");
980MODULE_DESCRIPTION("Velleman USB Board Low-Level Driver");
981MODULE_SUPPORTED_DEVICE("K8055/K8061 aka VM110/VM140");
982MODULE_VERSION("0.8.01");
983MODULE_LICENSE("GPL");
984