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
43
44
45
46
47
48
49
50
51
52
53
54
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>
64
65#include "../comedidev.h"
66
67enum {
68 DEVICE_VMK8055,
69 DEVICE_VMK8061
70};
71
72#define VMK8055_DI_REG 0x00
73#define VMK8055_DO_REG 0x01
74#define VMK8055_AO1_REG 0x02
75#define VMK8055_AO2_REG 0x03
76#define VMK8055_AI1_REG 0x02
77#define VMK8055_AI2_REG 0x03
78#define VMK8055_CNT1_REG 0x04
79#define VMK8055_CNT2_REG 0x06
80
81#define VMK8061_CH_REG 0x01
82#define VMK8061_DI_REG 0x01
83#define VMK8061_DO_REG 0x01
84#define VMK8061_PWM_REG1 0x01
85#define VMK8061_PWM_REG2 0x02
86#define VMK8061_CNT_REG 0x02
87#define VMK8061_AO_REG 0x02
88#define VMK8061_AI_REG1 0x02
89#define VMK8061_AI_REG2 0x03
90
91#define VMK8055_CMD_RST 0x00
92#define VMK8055_CMD_DEB1_TIME 0x01
93#define VMK8055_CMD_DEB2_TIME 0x02
94#define VMK8055_CMD_RST_CNT1 0x03
95#define VMK8055_CMD_RST_CNT2 0x04
96#define VMK8055_CMD_WRT_AD 0x05
97
98#define VMK8061_CMD_RD_AI 0x00
99#define VMK8061_CMR_RD_ALL_AI 0x01
100#define VMK8061_CMD_SET_AO 0x02
101#define VMK8061_CMD_SET_ALL_AO 0x03
102#define VMK8061_CMD_OUT_PWM 0x04
103#define VMK8061_CMD_RD_DI 0x05
104#define VMK8061_CMD_DO 0x06
105#define VMK8061_CMD_CLR_DO 0x07
106#define VMK8061_CMD_SET_DO 0x08
107#define VMK8061_CMD_RD_CNT 0x09
108#define VMK8061_CMD_RST_CNT 0x0a
109#define VMK8061_CMD_RD_VERSION 0x0b
110#define VMK8061_CMD_RD_JMP_STAT 0x0c
111#define VMK8061_CMD_RD_PWR_STAT 0x0d
112#define VMK8061_CMD_RD_DO 0x0e
113#define VMK8061_CMD_RD_AO 0x0f
114#define VMK8061_CMD_RD_PWM 0x10
115
116#define VMK80XX_MAX_BOARDS COMEDI_NUM_BOARD_MINORS
117
118#define TRANS_OUT_BUSY 1
119#define TRANS_IN_BUSY 2
120#define TRANS_IN_RUNNING 3
121
122#define IC3_VERSION (1 << 0)
123#define IC6_VERSION (1 << 1)
124
125#define URB_RCV_FLAG (1 << 0)
126#define URB_SND_FLAG (1 << 1)
127
128#ifdef CONFIG_COMEDI_DEBUG
129static int dbgcm = 1;
130#else
131static int dbgcm;
132#endif
133
134#define dbgcm(fmt, arg...) \
135do { \
136 if (dbgcm) \
137 printk(KERN_DEBUG fmt, ##arg); \
138} while (0)
139
140enum vmk80xx_model {
141 VMK8055_MODEL,
142 VMK8061_MODEL
143};
144
145struct firmware_version {
146 unsigned char ic3_vers[32];
147 unsigned char ic6_vers[32];
148};
149
150static const struct comedi_lrange vmk8055_range = {
151 1, {UNI_RANGE(5)}
152};
153
154static const struct comedi_lrange vmk8061_range = {
155 2, {UNI_RANGE(5), UNI_RANGE(10)}
156};
157
158struct vmk80xx_board {
159 const char *name;
160 enum vmk80xx_model model;
161 const struct comedi_lrange *range;
162 __u8 ai_chans;
163 __le16 ai_bits;
164 __u8 ao_chans;
165 __le16 ao_bits;
166 __u8 di_chans;
167 __le16 di_bits;
168 __u8 do_chans;
169 __le16 do_bits;
170 __u8 cnt_chans;
171 __le16 cnt_bits;
172 __u8 pwm_chans;
173 __le16 pwm_bits;
174};
175
176enum {
177 VMK80XX_SUBD_AI,
178 VMK80XX_SUBD_AO,
179 VMK80XX_SUBD_DI,
180 VMK80XX_SUBD_DO,
181 VMK80XX_SUBD_CNT,
182 VMK80XX_SUBD_PWM,
183};
184
185struct vmk80xx_usb {
186 struct usb_device *udev;
187 struct usb_interface *intf;
188 struct usb_endpoint_descriptor *ep_rx;
189 struct usb_endpoint_descriptor *ep_tx;
190 struct usb_anchor rx_anchor;
191 struct usb_anchor tx_anchor;
192 struct vmk80xx_board board;
193 struct firmware_version fw;
194 struct semaphore limit_sem;
195 wait_queue_head_t read_wait;
196 wait_queue_head_t write_wait;
197 unsigned char *usb_rx_buf;
198 unsigned char *usb_tx_buf;
199 unsigned long flags;
200 int probed;
201 int attached;
202 int count;
203};
204
205static struct vmk80xx_usb vmb[VMK80XX_MAX_BOARDS];
206
207static DEFINE_MUTEX(glb_mutex);
208
209static void vmk80xx_tx_callback(struct urb *urb)
210{
211 struct vmk80xx_usb *dev = urb->context;
212 int stat = urb->status;
213
214 if (stat && !(stat == -ENOENT
215 || stat == -ECONNRESET || stat == -ESHUTDOWN))
216 dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n",
217 __func__, stat);
218
219 if (!test_bit(TRANS_OUT_BUSY, &dev->flags))
220 return;
221
222 clear_bit(TRANS_OUT_BUSY, &dev->flags);
223
224 wake_up_interruptible(&dev->write_wait);
225}
226
227static void vmk80xx_rx_callback(struct urb *urb)
228{
229 struct vmk80xx_usb *dev = urb->context;
230 int stat = urb->status;
231
232 switch (stat) {
233 case 0:
234 break;
235 case -ENOENT:
236 case -ECONNRESET:
237 case -ESHUTDOWN:
238 break;
239 default:
240 dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n",
241 __func__, stat);
242 goto resubmit;
243 }
244
245 goto exit;
246resubmit:
247 if (test_bit(TRANS_IN_RUNNING, &dev->flags) && dev->intf) {
248 usb_anchor_urb(urb, &dev->rx_anchor);
249
250 if (!usb_submit_urb(urb, GFP_KERNEL))
251 goto exit;
252
253 dev_err(&urb->dev->dev,
254 "comedi#: vmk80xx: %s - submit urb failed\n",
255 __func__);
256
257 usb_unanchor_urb(urb);
258 }
259exit:
260 clear_bit(TRANS_IN_BUSY, &dev->flags);
261
262 wake_up_interruptible(&dev->read_wait);
263}
264
265static int vmk80xx_check_data_link(struct vmk80xx_usb *dev)
266{
267 unsigned int tx_pipe;
268 unsigned int rx_pipe;
269 unsigned char tx[1];
270 unsigned char rx[2];
271
272 tx_pipe = usb_sndbulkpipe(dev->udev, 0x01);
273 rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81);
274
275 tx[0] = VMK8061_CMD_RD_PWR_STAT;
276
277
278
279
280
281
282 usb_bulk_msg(dev->udev, tx_pipe, tx, 1, NULL, dev->ep_tx->bInterval);
283 usb_bulk_msg(dev->udev, rx_pipe, rx, 2, NULL, HZ * 10);
284
285 return (int)rx[1];
286}
287
288static void vmk80xx_read_eeprom(struct vmk80xx_usb *dev, int flag)
289{
290 unsigned int tx_pipe;
291 unsigned int rx_pipe;
292 unsigned char tx[1];
293 unsigned char rx[64];
294 int cnt;
295
296 tx_pipe = usb_sndbulkpipe(dev->udev, 0x01);
297 rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81);
298
299 tx[0] = VMK8061_CMD_RD_VERSION;
300
301
302
303
304
305 usb_bulk_msg(dev->udev, tx_pipe, tx, 1, NULL, dev->ep_tx->bInterval);
306 usb_bulk_msg(dev->udev, rx_pipe, rx, 64, &cnt, HZ * 10);
307
308 rx[cnt] = '\0';
309
310 if (flag & IC3_VERSION)
311 strncpy(dev->fw.ic3_vers, rx + 1, 24);
312 else
313 strncpy(dev->fw.ic6_vers, rx + 25, 24);
314}
315
316static int vmk80xx_reset_device(struct vmk80xx_usb *dev)
317{
318 struct urb *urb;
319 unsigned int tx_pipe;
320 int ival;
321 size_t size;
322
323 urb = usb_alloc_urb(0, GFP_KERNEL);
324 if (!urb)
325 return -ENOMEM;
326
327 tx_pipe = usb_sndintpipe(dev->udev, 0x01);
328
329 ival = dev->ep_tx->bInterval;
330 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
331
332 dev->usb_tx_buf[0] = VMK8055_CMD_RST;
333 dev->usb_tx_buf[1] = 0x00;
334 dev->usb_tx_buf[2] = 0x00;
335 dev->usb_tx_buf[3] = 0x00;
336 dev->usb_tx_buf[4] = 0x00;
337 dev->usb_tx_buf[5] = 0x00;
338 dev->usb_tx_buf[6] = 0x00;
339 dev->usb_tx_buf[7] = 0x00;
340
341 usb_fill_int_urb(urb, dev->udev, tx_pipe, dev->usb_tx_buf,
342 size, vmk80xx_tx_callback, dev, ival);
343
344 usb_anchor_urb(urb, &dev->tx_anchor);
345
346 return usb_submit_urb(urb, GFP_KERNEL);
347}
348
349static void vmk80xx_build_int_urb(struct urb *urb, int flag)
350{
351 struct vmk80xx_usb *dev = urb->context;
352 __u8 rx_addr;
353 __u8 tx_addr;
354 unsigned int pipe;
355 unsigned char *buf;
356 size_t size;
357 void (*callback) (struct urb *);
358 int ival;
359
360 if (flag & URB_RCV_FLAG) {
361 rx_addr = dev->ep_rx->bEndpointAddress;
362 pipe = usb_rcvintpipe(dev->udev, rx_addr);
363 buf = dev->usb_rx_buf;
364 size = le16_to_cpu(dev->ep_rx->wMaxPacketSize);
365 callback = vmk80xx_rx_callback;
366 ival = dev->ep_rx->bInterval;
367 } else {
368 tx_addr = dev->ep_tx->bEndpointAddress;
369 pipe = usb_sndintpipe(dev->udev, tx_addr);
370 buf = dev->usb_tx_buf;
371 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
372 callback = vmk80xx_tx_callback;
373 ival = dev->ep_tx->bInterval;
374 }
375
376 usb_fill_int_urb(urb, dev->udev, pipe, buf, size, callback, dev, ival);
377}
378
379static void vmk80xx_do_bulk_msg(struct vmk80xx_usb *dev)
380{
381 __u8 tx_addr;
382 __u8 rx_addr;
383 unsigned int tx_pipe;
384 unsigned int rx_pipe;
385 size_t size;
386
387 set_bit(TRANS_IN_BUSY, &dev->flags);
388 set_bit(TRANS_OUT_BUSY, &dev->flags);
389
390 tx_addr = dev->ep_tx->bEndpointAddress;
391 rx_addr = dev->ep_rx->bEndpointAddress;
392 tx_pipe = usb_sndbulkpipe(dev->udev, tx_addr);
393 rx_pipe = usb_rcvbulkpipe(dev->udev, rx_addr);
394
395
396
397
398
399 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
400
401 usb_bulk_msg(dev->udev, tx_pipe, dev->usb_tx_buf,
402 size, NULL, dev->ep_tx->bInterval);
403 usb_bulk_msg(dev->udev, rx_pipe, dev->usb_rx_buf, size, NULL, HZ * 10);
404
405 clear_bit(TRANS_OUT_BUSY, &dev->flags);
406 clear_bit(TRANS_IN_BUSY, &dev->flags);
407}
408
409static int vmk80xx_read_packet(struct vmk80xx_usb *dev)
410{
411 struct urb *urb;
412 int retval;
413
414 if (!dev->intf)
415 return -ENODEV;
416
417
418 if (test_bit(TRANS_IN_BUSY, &dev->flags))
419 if (wait_event_interruptible(dev->read_wait,
420 !test_bit(TRANS_IN_BUSY,
421 &dev->flags)))
422 return -ERESTART;
423
424 if (dev->board.model == VMK8061_MODEL) {
425 vmk80xx_do_bulk_msg(dev);
426
427 return 0;
428 }
429
430 urb = usb_alloc_urb(0, GFP_KERNEL);
431 if (!urb)
432 return -ENOMEM;
433
434 urb->context = dev;
435 vmk80xx_build_int_urb(urb, URB_RCV_FLAG);
436
437 set_bit(TRANS_IN_RUNNING, &dev->flags);
438 set_bit(TRANS_IN_BUSY, &dev->flags);
439
440 usb_anchor_urb(urb, &dev->rx_anchor);
441
442 retval = usb_submit_urb(urb, GFP_KERNEL);
443 if (!retval)
444 goto exit;
445
446 clear_bit(TRANS_IN_RUNNING, &dev->flags);
447 usb_unanchor_urb(urb);
448
449exit:
450 usb_free_urb(urb);
451
452 return retval;
453}
454
455static int vmk80xx_write_packet(struct vmk80xx_usb *dev, int cmd)
456{
457 struct urb *urb;
458 int retval;
459
460 if (!dev->intf)
461 return -ENODEV;
462
463 if (test_bit(TRANS_OUT_BUSY, &dev->flags))
464 if (wait_event_interruptible(dev->write_wait,
465 !test_bit(TRANS_OUT_BUSY,
466 &dev->flags)))
467 return -ERESTART;
468
469 if (dev->board.model == VMK8061_MODEL) {
470 dev->usb_tx_buf[0] = cmd;
471 vmk80xx_do_bulk_msg(dev);
472
473 return 0;
474 }
475
476 urb = usb_alloc_urb(0, GFP_KERNEL);
477 if (!urb)
478 return -ENOMEM;
479
480 urb->context = dev;
481 vmk80xx_build_int_urb(urb, URB_SND_FLAG);
482
483 set_bit(TRANS_OUT_BUSY, &dev->flags);
484
485 usb_anchor_urb(urb, &dev->tx_anchor);
486
487 dev->usb_tx_buf[0] = cmd;
488
489 retval = usb_submit_urb(urb, GFP_KERNEL);
490 if (!retval)
491 goto exit;
492
493 clear_bit(TRANS_OUT_BUSY, &dev->flags);
494 usb_unanchor_urb(urb);
495
496exit:
497 usb_free_urb(urb);
498
499 return retval;
500}
501
502#define DIR_IN 1
503#define DIR_OUT 2
504
505static int rudimentary_check(struct vmk80xx_usb *dev, int dir)
506{
507 if (!dev)
508 return -EFAULT;
509 if (!dev->probed)
510 return -ENODEV;
511 if (!dev->attached)
512 return -ENODEV;
513 if (dir & DIR_IN) {
514 if (test_bit(TRANS_IN_BUSY, &dev->flags))
515 return -EBUSY;
516 }
517 if (dir & DIR_OUT) {
518 if (test_bit(TRANS_OUT_BUSY, &dev->flags))
519 return -EBUSY;
520 }
521
522 return 0;
523}
524
525static int vmk80xx_ai_rinsn(struct comedi_device *cdev,
526 struct comedi_subdevice *s,
527 struct comedi_insn *insn, unsigned int *data)
528{
529 struct vmk80xx_usb *dev = cdev->private;
530 int chan;
531 int reg[2];
532 int n;
533
534 n = rudimentary_check(dev, DIR_IN);
535 if (n)
536 return n;
537
538 down(&dev->limit_sem);
539 chan = CR_CHAN(insn->chanspec);
540
541 switch (dev->board.model) {
542 case VMK8055_MODEL:
543 if (!chan)
544 reg[0] = VMK8055_AI1_REG;
545 else
546 reg[0] = VMK8055_AI2_REG;
547 break;
548 case VMK8061_MODEL:
549 default:
550 reg[0] = VMK8061_AI_REG1;
551 reg[1] = VMK8061_AI_REG2;
552 dev->usb_tx_buf[0] = VMK8061_CMD_RD_AI;
553 dev->usb_tx_buf[VMK8061_CH_REG] = chan;
554 break;
555 }
556
557 for (n = 0; n < insn->n; n++) {
558 if (vmk80xx_read_packet(dev))
559 break;
560
561 if (dev->board.model == VMK8055_MODEL) {
562 data[n] = dev->usb_rx_buf[reg[0]];
563 continue;
564 }
565
566
567 data[n] = dev->usb_rx_buf[reg[0]] + 256 *
568 dev->usb_rx_buf[reg[1]];
569 }
570
571 up(&dev->limit_sem);
572
573 return n;
574}
575
576static int vmk80xx_ao_winsn(struct comedi_device *cdev,
577 struct comedi_subdevice *s,
578 struct comedi_insn *insn, unsigned int *data)
579{
580 struct vmk80xx_usb *dev = cdev->private;
581 int chan;
582 int cmd;
583 int reg;
584 int n;
585
586 n = rudimentary_check(dev, DIR_OUT);
587 if (n)
588 return n;
589
590 down(&dev->limit_sem);
591 chan = CR_CHAN(insn->chanspec);
592
593 switch (dev->board.model) {
594 case VMK8055_MODEL:
595 cmd = VMK8055_CMD_WRT_AD;
596 if (!chan)
597 reg = VMK8055_AO1_REG;
598 else
599 reg = VMK8055_AO2_REG;
600 break;
601 default:
602 cmd = VMK8061_CMD_SET_AO;
603 reg = VMK8061_AO_REG;
604 dev->usb_tx_buf[VMK8061_CH_REG] = chan;
605 break;
606 }
607
608 for (n = 0; n < insn->n; n++) {
609 dev->usb_tx_buf[reg] = data[n];
610
611 if (vmk80xx_write_packet(dev, cmd))
612 break;
613 }
614
615 up(&dev->limit_sem);
616
617 return n;
618}
619
620static int vmk80xx_ao_rinsn(struct comedi_device *cdev,
621 struct comedi_subdevice *s,
622 struct comedi_insn *insn, unsigned int *data)
623{
624 struct vmk80xx_usb *dev = cdev->private;
625 int chan;
626 int reg;
627 int n;
628
629 n = rudimentary_check(dev, DIR_IN);
630 if (n)
631 return n;
632
633 down(&dev->limit_sem);
634 chan = CR_CHAN(insn->chanspec);
635
636 reg = VMK8061_AO_REG - 1;
637
638 dev->usb_tx_buf[0] = VMK8061_CMD_RD_AO;
639
640 for (n = 0; n < insn->n; n++) {
641 if (vmk80xx_read_packet(dev))
642 break;
643
644 data[n] = dev->usb_rx_buf[reg + chan];
645 }
646
647 up(&dev->limit_sem);
648
649 return n;
650}
651
652static int vmk80xx_di_bits(struct comedi_device *cdev,
653 struct comedi_subdevice *s,
654 struct comedi_insn *insn, unsigned int *data)
655{
656 struct vmk80xx_usb *dev = cdev->private;
657 unsigned char *rx_buf;
658 int reg;
659 int retval;
660
661 retval = rudimentary_check(dev, DIR_IN);
662 if (retval)
663 return retval;
664
665 down(&dev->limit_sem);
666
667 rx_buf = dev->usb_rx_buf;
668
669 if (dev->board.model == VMK8061_MODEL) {
670 reg = VMK8061_DI_REG;
671 dev->usb_tx_buf[0] = VMK8061_CMD_RD_DI;
672 } else {
673 reg = VMK8055_DI_REG;
674 }
675
676 retval = vmk80xx_read_packet(dev);
677
678 if (!retval) {
679 if (dev->board.model == VMK8055_MODEL)
680 data[1] = (((rx_buf[reg] >> 4) & 0x03) |
681 ((rx_buf[reg] << 2) & 0x04) |
682 ((rx_buf[reg] >> 3) & 0x18));
683 else
684 data[1] = rx_buf[reg];
685
686 retval = 2;
687 }
688
689 up(&dev->limit_sem);
690
691 return retval;
692}
693
694static int vmk80xx_di_rinsn(struct comedi_device *cdev,
695 struct comedi_subdevice *s,
696 struct comedi_insn *insn, unsigned int *data)
697{
698 struct vmk80xx_usb *dev = cdev->private;
699 int chan;
700 unsigned char *rx_buf;
701 int reg;
702 int inp;
703 int n;
704
705 n = rudimentary_check(dev, DIR_IN);
706 if (n)
707 return n;
708
709 down(&dev->limit_sem);
710 chan = CR_CHAN(insn->chanspec);
711
712 rx_buf = dev->usb_rx_buf;
713
714 if (dev->board.model == VMK8061_MODEL) {
715 reg = VMK8061_DI_REG;
716 dev->usb_tx_buf[0] = VMK8061_CMD_RD_DI;
717 } else {
718 reg = VMK8055_DI_REG;
719 }
720 for (n = 0; n < insn->n; n++) {
721 if (vmk80xx_read_packet(dev))
722 break;
723
724 if (dev->board.model == VMK8055_MODEL)
725 inp = (((rx_buf[reg] >> 4) & 0x03) |
726 ((rx_buf[reg] << 2) & 0x04) |
727 ((rx_buf[reg] >> 3) & 0x18));
728 else
729 inp = rx_buf[reg];
730
731 data[n] = (inp >> chan) & 1;
732 }
733
734 up(&dev->limit_sem);
735
736 return n;
737}
738
739static int vmk80xx_do_winsn(struct comedi_device *cdev,
740 struct comedi_subdevice *s,
741 struct comedi_insn *insn, unsigned int *data)
742{
743 struct vmk80xx_usb *dev = cdev->private;
744 int chan;
745 unsigned char *tx_buf;
746 int reg;
747 int cmd;
748 int n;
749
750 n = rudimentary_check(dev, DIR_OUT);
751 if (n)
752 return n;
753
754 down(&dev->limit_sem);
755 chan = CR_CHAN(insn->chanspec);
756
757 tx_buf = dev->usb_tx_buf;
758
759 for (n = 0; n < insn->n; n++) {
760 if (dev->board.model == VMK8055_MODEL) {
761 reg = VMK8055_DO_REG;
762 cmd = VMK8055_CMD_WRT_AD;
763 if (data[n] == 1)
764 tx_buf[reg] |= (1 << chan);
765 else
766 tx_buf[reg] ^= (1 << chan);
767 } else {
768 reg = VMK8061_DO_REG;
769 if (data[n] == 1) {
770 cmd = VMK8061_CMD_SET_DO;
771 tx_buf[reg] = 1 << chan;
772 } else {
773 cmd = VMK8061_CMD_CLR_DO;
774 tx_buf[reg] = 0xff - (1 << chan);
775 }
776 }
777
778 if (vmk80xx_write_packet(dev, cmd))
779 break;
780 }
781
782 up(&dev->limit_sem);
783
784 return n;
785}
786
787static int vmk80xx_do_rinsn(struct comedi_device *cdev,
788 struct comedi_subdevice *s,
789 struct comedi_insn *insn, unsigned int *data)
790{
791 struct vmk80xx_usb *dev = cdev->private;
792 int chan;
793 int reg;
794 int n;
795
796 n = rudimentary_check(dev, DIR_IN);
797 if (n)
798 return n;
799
800 down(&dev->limit_sem);
801 chan = CR_CHAN(insn->chanspec);
802
803 reg = VMK8061_DO_REG;
804
805 dev->usb_tx_buf[0] = VMK8061_CMD_RD_DO;
806
807 for (n = 0; n < insn->n; n++) {
808 if (vmk80xx_read_packet(dev))
809 break;
810
811 data[n] = (dev->usb_rx_buf[reg] >> chan) & 1;
812 }
813
814 up(&dev->limit_sem);
815
816 return n;
817}
818
819static int vmk80xx_do_bits(struct comedi_device *cdev,
820 struct comedi_subdevice *s,
821 struct comedi_insn *insn, unsigned int *data)
822{
823 struct vmk80xx_usb *dev = cdev->private;
824 unsigned char *rx_buf, *tx_buf;
825 int dir, reg, cmd;
826 int retval;
827
828 dir = 0;
829
830 if (data[0])
831 dir |= DIR_OUT;
832
833 if (dev->board.model == VMK8061_MODEL)
834 dir |= DIR_IN;
835
836 retval = rudimentary_check(dev, dir);
837 if (retval)
838 return retval;
839
840 down(&dev->limit_sem);
841
842 rx_buf = dev->usb_rx_buf;
843 tx_buf = dev->usb_tx_buf;
844
845 if (data[0]) {
846 if (dev->board.model == VMK8055_MODEL) {
847 reg = VMK8055_DO_REG;
848 cmd = VMK8055_CMD_WRT_AD;
849 } else {
850 reg = VMK8061_DO_REG;
851 cmd = VMK8061_CMD_DO;
852 }
853
854 tx_buf[reg] &= ~data[0];
855 tx_buf[reg] |= (data[0] & data[1]);
856
857 retval = vmk80xx_write_packet(dev, cmd);
858
859 if (retval)
860 goto out;
861 }
862
863 if (dev->board.model == VMK8061_MODEL) {
864 reg = VMK8061_DO_REG;
865 tx_buf[0] = VMK8061_CMD_RD_DO;
866
867 retval = vmk80xx_read_packet(dev);
868
869 if (!retval) {
870 data[1] = rx_buf[reg];
871 retval = 2;
872 }
873 } else {
874 data[1] = tx_buf[reg];
875 retval = 2;
876 }
877
878out:
879 up(&dev->limit_sem);
880
881 return retval;
882}
883
884static int vmk80xx_cnt_rinsn(struct comedi_device *cdev,
885 struct comedi_subdevice *s,
886 struct comedi_insn *insn, unsigned int *data)
887{
888 struct vmk80xx_usb *dev = cdev->private;
889 int chan;
890 int reg[2];
891 int n;
892
893 n = rudimentary_check(dev, DIR_IN);
894 if (n)
895 return n;
896
897 down(&dev->limit_sem);
898 chan = CR_CHAN(insn->chanspec);
899
900 switch (dev->board.model) {
901 case VMK8055_MODEL:
902 if (!chan)
903 reg[0] = VMK8055_CNT1_REG;
904 else
905 reg[0] = VMK8055_CNT2_REG;
906 break;
907 case VMK8061_MODEL:
908 default:
909 reg[0] = VMK8061_CNT_REG;
910 reg[1] = VMK8061_CNT_REG;
911 dev->usb_tx_buf[0] = VMK8061_CMD_RD_CNT;
912 break;
913 }
914
915 for (n = 0; n < insn->n; n++) {
916 if (vmk80xx_read_packet(dev))
917 break;
918
919 if (dev->board.model == VMK8055_MODEL)
920 data[n] = dev->usb_rx_buf[reg[0]];
921 else
922 data[n] = dev->usb_rx_buf[reg[0] * (chan + 1) + 1]
923 + 256 * dev->usb_rx_buf[reg[1] * 2 + 2];
924 }
925
926 up(&dev->limit_sem);
927
928 return n;
929}
930
931static int vmk80xx_cnt_cinsn(struct comedi_device *cdev,
932 struct comedi_subdevice *s,
933 struct comedi_insn *insn, unsigned int *data)
934{
935 struct vmk80xx_usb *dev = cdev->private;
936 unsigned int insn_cmd;
937 int chan;
938 int cmd;
939 int reg;
940 int n;
941
942 n = rudimentary_check(dev, DIR_OUT);
943 if (n)
944 return n;
945
946 insn_cmd = data[0];
947 if (insn_cmd != INSN_CONFIG_RESET && insn_cmd != GPCT_RESET)
948 return -EINVAL;
949
950 down(&dev->limit_sem);
951
952 chan = CR_CHAN(insn->chanspec);
953
954 if (dev->board.model == VMK8055_MODEL) {
955 if (!chan) {
956 cmd = VMK8055_CMD_RST_CNT1;
957 reg = VMK8055_CNT1_REG;
958 } else {
959 cmd = VMK8055_CMD_RST_CNT2;
960 reg = VMK8055_CNT2_REG;
961 }
962
963 dev->usb_tx_buf[reg] = 0x00;
964 } else {
965 cmd = VMK8061_CMD_RST_CNT;
966 }
967
968 for (n = 0; n < insn->n; n++)
969 if (vmk80xx_write_packet(dev, cmd))
970 break;
971
972 up(&dev->limit_sem);
973
974 return n;
975}
976
977static int vmk80xx_cnt_winsn(struct comedi_device *cdev,
978 struct comedi_subdevice *s,
979 struct comedi_insn *insn, unsigned int *data)
980{
981 struct vmk80xx_usb *dev = cdev->private;
982 unsigned long debtime;
983 unsigned long val;
984 int chan;
985 int cmd;
986 int n;
987
988 n = rudimentary_check(dev, DIR_OUT);
989 if (n)
990 return n;
991
992 down(&dev->limit_sem);
993 chan = CR_CHAN(insn->chanspec);
994
995 if (!chan)
996 cmd = VMK8055_CMD_DEB1_TIME;
997 else
998 cmd = VMK8055_CMD_DEB2_TIME;
999
1000 for (n = 0; n < insn->n; n++) {
1001 debtime = data[n];
1002 if (debtime == 0)
1003 debtime = 1;
1004
1005
1006 if (debtime > 7450)
1007 debtime = 7450;
1008
1009 val = int_sqrt(debtime * 1000 / 115);
1010 if (((val + 1) * val) < debtime * 1000 / 115)
1011 val += 1;
1012
1013 dev->usb_tx_buf[6 + chan] = val;
1014
1015 if (vmk80xx_write_packet(dev, cmd))
1016 break;
1017 }
1018
1019 up(&dev->limit_sem);
1020
1021 return n;
1022}
1023
1024static int vmk80xx_pwm_rinsn(struct comedi_device *cdev,
1025 struct comedi_subdevice *s,
1026 struct comedi_insn *insn, unsigned int *data)
1027{
1028 struct vmk80xx_usb *dev = cdev->private;
1029 int reg[2];
1030 int n;
1031
1032 n = rudimentary_check(dev, DIR_IN);
1033 if (n)
1034 return n;
1035
1036 down(&dev->limit_sem);
1037
1038 reg[0] = VMK8061_PWM_REG1;
1039 reg[1] = VMK8061_PWM_REG2;
1040
1041 dev->usb_tx_buf[0] = VMK8061_CMD_RD_PWM;
1042
1043 for (n = 0; n < insn->n; n++) {
1044 if (vmk80xx_read_packet(dev))
1045 break;
1046
1047 data[n] = dev->usb_rx_buf[reg[0]] + 4 * dev->usb_rx_buf[reg[1]];
1048 }
1049
1050 up(&dev->limit_sem);
1051
1052 return n;
1053}
1054
1055static int vmk80xx_pwm_winsn(struct comedi_device *cdev,
1056 struct comedi_subdevice *s,
1057 struct comedi_insn *insn, unsigned int *data)
1058{
1059 struct vmk80xx_usb *dev = cdev->private;
1060 unsigned char *tx_buf;
1061 int reg[2];
1062 int cmd;
1063 int n;
1064
1065 n = rudimentary_check(dev, DIR_OUT);
1066 if (n)
1067 return n;
1068
1069 down(&dev->limit_sem);
1070
1071 tx_buf = dev->usb_tx_buf;
1072
1073 reg[0] = VMK8061_PWM_REG1;
1074 reg[1] = VMK8061_PWM_REG2;
1075
1076 cmd = VMK8061_CMD_OUT_PWM;
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091 for (n = 0; n < insn->n; n++) {
1092 tx_buf[reg[0]] = (unsigned char)(data[n] & 0x03);
1093 tx_buf[reg[1]] = (unsigned char)(data[n] >> 2) & 0xff;
1094
1095 if (vmk80xx_write_packet(dev, cmd))
1096 break;
1097 }
1098
1099 up(&dev->limit_sem);
1100
1101 return n;
1102}
1103
1104static int vmk80xx_attach_common(struct comedi_device *cdev,
1105 struct vmk80xx_usb *dev)
1106{
1107 int n_subd;
1108 struct comedi_subdevice *s;
1109 int ret;
1110
1111 down(&dev->limit_sem);
1112 cdev->board_name = dev->board.name;
1113 cdev->private = dev;
1114 if (dev->board.model == VMK8055_MODEL)
1115 n_subd = 5;
1116 else
1117 n_subd = 6;
1118 ret = comedi_alloc_subdevices(cdev, n_subd);
1119 if (ret) {
1120 up(&dev->limit_sem);
1121 return ret;
1122 }
1123
1124 s = &cdev->subdevices[VMK80XX_SUBD_AI];
1125 s->type = COMEDI_SUBD_AI;
1126 s->subdev_flags = SDF_READABLE | SDF_GROUND;
1127 s->n_chan = dev->board.ai_chans;
1128 s->maxdata = (1 << dev->board.ai_bits) - 1;
1129 s->range_table = dev->board.range;
1130 s->insn_read = vmk80xx_ai_rinsn;
1131
1132 s = &cdev->subdevices[VMK80XX_SUBD_AO];
1133 s->type = COMEDI_SUBD_AO;
1134 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
1135 s->n_chan = dev->board.ao_chans;
1136 s->maxdata = (1 << dev->board.ao_bits) - 1;
1137 s->range_table = dev->board.range;
1138 s->insn_write = vmk80xx_ao_winsn;
1139 if (dev->board.model == VMK8061_MODEL) {
1140 s->subdev_flags |= SDF_READABLE;
1141 s->insn_read = vmk80xx_ao_rinsn;
1142 }
1143
1144 s = &cdev->subdevices[VMK80XX_SUBD_DI];
1145 s->type = COMEDI_SUBD_DI;
1146 s->subdev_flags = SDF_READABLE | SDF_GROUND;
1147 s->n_chan = dev->board.di_chans;
1148 s->maxdata = 1;
1149 s->insn_read = vmk80xx_di_rinsn;
1150 s->insn_bits = vmk80xx_di_bits;
1151
1152 s = &cdev->subdevices[VMK80XX_SUBD_DO];
1153 s->type = COMEDI_SUBD_DO;
1154 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
1155 s->n_chan = dev->board.do_chans;
1156 s->maxdata = 1;
1157 s->insn_write = vmk80xx_do_winsn;
1158 s->insn_bits = vmk80xx_do_bits;
1159 if (dev->board.model == VMK8061_MODEL) {
1160 s->subdev_flags |= SDF_READABLE;
1161 s->insn_read = vmk80xx_do_rinsn;
1162 }
1163
1164 s = &cdev->subdevices[VMK80XX_SUBD_CNT];
1165 s->type = COMEDI_SUBD_COUNTER;
1166 s->subdev_flags = SDF_READABLE;
1167 s->n_chan = dev->board.cnt_chans;
1168 s->insn_read = vmk80xx_cnt_rinsn;
1169 s->insn_config = vmk80xx_cnt_cinsn;
1170 if (dev->board.model == VMK8055_MODEL) {
1171 s->subdev_flags |= SDF_WRITEABLE;
1172 s->maxdata = (1 << dev->board.cnt_bits) - 1;
1173 s->insn_write = vmk80xx_cnt_winsn;
1174 }
1175
1176 if (dev->board.model == VMK8061_MODEL) {
1177 s = &cdev->subdevices[VMK80XX_SUBD_PWM];
1178 s->type = COMEDI_SUBD_PWM;
1179 s->subdev_flags = SDF_READABLE | SDF_WRITEABLE;
1180 s->n_chan = dev->board.pwm_chans;
1181 s->maxdata = (1 << dev->board.pwm_bits) - 1;
1182 s->insn_read = vmk80xx_pwm_rinsn;
1183 s->insn_write = vmk80xx_pwm_winsn;
1184 }
1185 dev->attached = 1;
1186 dev_info(cdev->class_dev, "vmk80xx: board #%d [%s] attached\n",
1187 dev->count, dev->board.name);
1188 up(&dev->limit_sem);
1189 return 0;
1190}
1191
1192
1193static int vmk80xx_attach(struct comedi_device *cdev,
1194 struct comedi_devconfig *it)
1195{
1196 int i;
1197 int ret;
1198
1199 mutex_lock(&glb_mutex);
1200 for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
1201 if (vmb[i].probed && !vmb[i].attached)
1202 break;
1203 if (i == VMK80XX_MAX_BOARDS)
1204 ret = -ENODEV;
1205 else
1206 ret = vmk80xx_attach_common(cdev, &vmb[i]);
1207 mutex_unlock(&glb_mutex);
1208 return ret;
1209}
1210
1211
1212static int vmk80xx_auto_attach(struct comedi_device *cdev,
1213 unsigned long context_unused)
1214{
1215 struct usb_interface *intf = comedi_to_usb_interface(cdev);
1216 int i;
1217 int ret;
1218
1219 mutex_lock(&glb_mutex);
1220 for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
1221 if (vmb[i].probed && vmb[i].intf == intf)
1222 break;
1223 if (i == VMK80XX_MAX_BOARDS)
1224 ret = -ENODEV;
1225 else if (vmb[i].attached)
1226 ret = -EBUSY;
1227 else
1228 ret = vmk80xx_attach_common(cdev, &vmb[i]);
1229 mutex_unlock(&glb_mutex);
1230 return ret;
1231}
1232
1233static void vmk80xx_detach(struct comedi_device *dev)
1234{
1235 struct vmk80xx_usb *usb = dev->private;
1236
1237 if (usb) {
1238 down(&usb->limit_sem);
1239 dev->private = NULL;
1240 usb->attached = 0;
1241 up(&usb->limit_sem);
1242 }
1243}
1244
1245static struct comedi_driver vmk80xx_driver = {
1246 .module = THIS_MODULE,
1247 .driver_name = "vmk80xx",
1248 .attach = vmk80xx_attach,
1249 .detach = vmk80xx_detach,
1250 .auto_attach = vmk80xx_auto_attach,
1251};
1252
1253static int vmk80xx_usb_probe(struct usb_interface *intf,
1254 const struct usb_device_id *id)
1255{
1256 int i;
1257 struct vmk80xx_usb *dev;
1258 struct usb_host_interface *iface_desc;
1259 struct usb_endpoint_descriptor *ep_desc;
1260 size_t size;
1261
1262 mutex_lock(&glb_mutex);
1263
1264 for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
1265 if (!vmb[i].probed)
1266 break;
1267
1268 if (i == VMK80XX_MAX_BOARDS) {
1269 mutex_unlock(&glb_mutex);
1270 return -EMFILE;
1271 }
1272
1273 dev = &vmb[i];
1274
1275 memset(dev, 0x00, sizeof(struct vmk80xx_usb));
1276 dev->count = i;
1277
1278 iface_desc = intf->cur_altsetting;
1279 if (iface_desc->desc.bNumEndpoints != 2)
1280 goto error;
1281
1282 for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
1283 ep_desc = &iface_desc->endpoint[i].desc;
1284
1285 if (usb_endpoint_is_int_in(ep_desc)) {
1286 dev->ep_rx = ep_desc;
1287 continue;
1288 }
1289
1290 if (usb_endpoint_is_int_out(ep_desc)) {
1291 dev->ep_tx = ep_desc;
1292 continue;
1293 }
1294
1295 if (usb_endpoint_is_bulk_in(ep_desc)) {
1296 dev->ep_rx = ep_desc;
1297 continue;
1298 }
1299
1300 if (usb_endpoint_is_bulk_out(ep_desc)) {
1301 dev->ep_tx = ep_desc;
1302 continue;
1303 }
1304 }
1305
1306 if (!dev->ep_rx || !dev->ep_tx)
1307 goto error;
1308
1309 size = le16_to_cpu(dev->ep_rx->wMaxPacketSize);
1310 dev->usb_rx_buf = kmalloc(size, GFP_KERNEL);
1311 if (!dev->usb_rx_buf) {
1312 mutex_unlock(&glb_mutex);
1313 return -ENOMEM;
1314 }
1315
1316 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize);
1317 dev->usb_tx_buf = kmalloc(size, GFP_KERNEL);
1318 if (!dev->usb_tx_buf) {
1319 kfree(dev->usb_rx_buf);
1320 mutex_unlock(&glb_mutex);
1321 return -ENOMEM;
1322 }
1323
1324 dev->udev = interface_to_usbdev(intf);
1325 dev->intf = intf;
1326
1327 sema_init(&dev->limit_sem, 8);
1328 init_waitqueue_head(&dev->read_wait);
1329 init_waitqueue_head(&dev->write_wait);
1330
1331 init_usb_anchor(&dev->rx_anchor);
1332 init_usb_anchor(&dev->tx_anchor);
1333
1334 usb_set_intfdata(intf, dev);
1335
1336 switch (id->driver_info) {
1337 case DEVICE_VMK8055:
1338 dev->board.name = "K8055 (VM110)";
1339 dev->board.model = VMK8055_MODEL;
1340 dev->board.range = &vmk8055_range;
1341 dev->board.ai_chans = 2;
1342 dev->board.ai_bits = 8;
1343 dev->board.ao_chans = 2;
1344 dev->board.ao_bits = 8;
1345 dev->board.di_chans = 5;
1346 dev->board.di_bits = 1;
1347 dev->board.do_chans = 8;
1348 dev->board.do_bits = 1;
1349 dev->board.cnt_chans = 2;
1350 dev->board.cnt_bits = 16;
1351 dev->board.pwm_chans = 0;
1352 dev->board.pwm_bits = 0;
1353 break;
1354 case DEVICE_VMK8061:
1355 dev->board.name = "K8061 (VM140)";
1356 dev->board.model = VMK8061_MODEL;
1357 dev->board.range = &vmk8061_range;
1358 dev->board.ai_chans = 8;
1359 dev->board.ai_bits = 10;
1360 dev->board.ao_chans = 8;
1361 dev->board.ao_bits = 8;
1362 dev->board.di_chans = 8;
1363 dev->board.di_bits = 1;
1364 dev->board.do_chans = 8;
1365 dev->board.do_bits = 1;
1366 dev->board.cnt_chans = 2;
1367 dev->board.cnt_bits = 0;
1368 dev->board.pwm_chans = 1;
1369 dev->board.pwm_bits = 10;
1370 break;
1371 }
1372
1373 if (dev->board.model == VMK8061_MODEL) {
1374 vmk80xx_read_eeprom(dev, IC3_VERSION);
1375 dev_info(&intf->dev, "%s\n", dev->fw.ic3_vers);
1376
1377 if (vmk80xx_check_data_link(dev)) {
1378 vmk80xx_read_eeprom(dev, IC6_VERSION);
1379 dev_info(&intf->dev, "%s\n", dev->fw.ic6_vers);
1380 } else {
1381 dbgcm("comedi#: vmk80xx: no conn. to CPU\n");
1382 }
1383 }
1384
1385 if (dev->board.model == VMK8055_MODEL)
1386 vmk80xx_reset_device(dev);
1387
1388 dev->probed = 1;
1389
1390 dev_info(&intf->dev, "board #%d [%s] now attached\n",
1391 dev->count, dev->board.name);
1392
1393 mutex_unlock(&glb_mutex);
1394
1395 comedi_usb_auto_config(intf, &vmk80xx_driver);
1396
1397 return 0;
1398error:
1399 mutex_unlock(&glb_mutex);
1400
1401 return -ENODEV;
1402}
1403
1404static void vmk80xx_usb_disconnect(struct usb_interface *intf)
1405{
1406 struct vmk80xx_usb *dev = usb_get_intfdata(intf);
1407
1408 if (!dev)
1409 return;
1410
1411 comedi_usb_auto_unconfig(intf);
1412
1413 mutex_lock(&glb_mutex);
1414 down(&dev->limit_sem);
1415
1416 dev->probed = 0;
1417 usb_set_intfdata(dev->intf, NULL);
1418
1419 usb_kill_anchored_urbs(&dev->rx_anchor);
1420 usb_kill_anchored_urbs(&dev->tx_anchor);
1421
1422 kfree(dev->usb_rx_buf);
1423 kfree(dev->usb_tx_buf);
1424
1425 dev_info(&intf->dev, "board #%d [%s] now detached\n",
1426 dev->count, dev->board.name);
1427
1428 up(&dev->limit_sem);
1429 mutex_unlock(&glb_mutex);
1430}
1431
1432static const struct usb_device_id vmk80xx_usb_id_table[] = {
1433 { USB_DEVICE(0x10cf, 0x5500), .driver_info = DEVICE_VMK8055 },
1434 { USB_DEVICE(0x10cf, 0x5501), .driver_info = DEVICE_VMK8055 },
1435 { USB_DEVICE(0x10cf, 0x5502), .driver_info = DEVICE_VMK8055 },
1436 { USB_DEVICE(0x10cf, 0x5503), .driver_info = DEVICE_VMK8055 },
1437 { USB_DEVICE(0x10cf, 0x8061), .driver_info = DEVICE_VMK8061 },
1438 { USB_DEVICE(0x10cf, 0x8062), .driver_info = DEVICE_VMK8061 },
1439 { USB_DEVICE(0x10cf, 0x8063), .driver_info = DEVICE_VMK8061 },
1440 { USB_DEVICE(0x10cf, 0x8064), .driver_info = DEVICE_VMK8061 },
1441 { USB_DEVICE(0x10cf, 0x8065), .driver_info = DEVICE_VMK8061 },
1442 { USB_DEVICE(0x10cf, 0x8066), .driver_info = DEVICE_VMK8061 },
1443 { USB_DEVICE(0x10cf, 0x8067), .driver_info = DEVICE_VMK8061 },
1444 { USB_DEVICE(0x10cf, 0x8068), .driver_info = DEVICE_VMK8061 },
1445 { }
1446};
1447MODULE_DEVICE_TABLE(usb, vmk80xx_usb_id_table);
1448
1449
1450
1451static struct usb_driver vmk80xx_usb_driver = {
1452 .name = "vmk80xx",
1453 .probe = vmk80xx_usb_probe,
1454 .disconnect = vmk80xx_usb_disconnect,
1455 .id_table = vmk80xx_usb_id_table,
1456};
1457module_comedi_usb_driver(vmk80xx_driver, vmk80xx_usb_driver);
1458
1459MODULE_AUTHOR("Manuel Gebele <forensixs@gmx.de>");
1460MODULE_DESCRIPTION("Velleman USB Board Low-Level Driver");
1461MODULE_SUPPORTED_DEVICE("K8055/K8061 aka VM110/VM140");
1462MODULE_VERSION("0.8.01");
1463MODULE_LICENSE("GPL");
1464