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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70#include <linux/kernel.h>
71#include <linux/module.h>
72#include <linux/slab.h>
73#include <linux/input.h>
74#include <linux/fcntl.h>
75#include <linux/compiler.h>
76
77#include "../comedi_usb.h"
78
79
80#define USBDUX_FIRMWARE "usbdux_firmware.bin"
81#define USBDUX_FIRMWARE_MAX_LEN 0x2000
82#define USBDUX_FIRMWARE_CMD 0xa0
83#define VENDOR_DIR_IN 0xc0
84#define VENDOR_DIR_OUT 0x40
85#define USBDUX_CPU_CS 0xe600
86
87
88#define USBDUX_CMD_MULT_AI 0
89#define USBDUX_CMD_AO 1
90#define USBDUX_CMD_DIO_CFG 2
91#define USBDUX_CMD_DIO_BITS 3
92#define USBDUX_CMD_SINGLE_AI 4
93#define USBDUX_CMD_TIMER_RD 5
94#define USBDUX_CMD_TIMER_WR 6
95#define USBDUX_CMD_PWM_ON 7
96#define USBDUX_CMD_PWM_OFF 8
97
98
99#define BULK_TIMEOUT 1000
100
101
102#define MIN_PWM_PERIOD ((long)(1E9 / 300))
103
104
105#define PWM_DEFAULT_PERIOD ((long)(1E9 / 100))
106
107
108#define SIZEADIN ((sizeof(u16)))
109
110
111
112
113
114#define SIZEINBUF (8 * SIZEADIN)
115
116
117#define SIZEINSNBUF 16
118
119
120#define SIZEDAOUT ((sizeof(u8) + sizeof(u16)))
121
122
123
124
125
126
127#define SIZEOUTBUF (8 * SIZEDAOUT)
128
129
130
131
132
133#define SIZEOFDUXBUFFER (8 * SIZEDAOUT + 2)
134
135
136#define NUMOFINBUFFERSFULL 5
137
138
139#define NUMOFOUTBUFFERSFULL 5
140
141
142
143#define NUMOFINBUFFERSHIGH 10
144
145
146
147#define NUMOFOUTBUFFERSHIGH 10
148
149
150#define RETRIES 10
151
152static const struct comedi_lrange range_usbdux_ai_range = {
153 4, {
154 BIP_RANGE(4.096),
155 BIP_RANGE(4.096 / 2),
156 UNI_RANGE(4.096),
157 UNI_RANGE(4.096 / 2)
158 }
159};
160
161static const struct comedi_lrange range_usbdux_ao_range = {
162 2, {
163 BIP_RANGE(4.096),
164 UNI_RANGE(4.096)
165 }
166};
167
168struct usbdux_private {
169
170 int n_ai_urbs;
171
172 int n_ao_urbs;
173
174 struct urb **ai_urbs;
175 struct urb **ao_urbs;
176
177 struct urb *pwm_urb;
178
179 unsigned int pwm_period;
180
181 u8 pwm_delay;
182
183 int pwm_buf_sz;
184
185 __le16 *in_buf;
186
187 __le16 *insn_buf;
188
189 unsigned int high_speed:1;
190 unsigned int ai_cmd_running:1;
191 unsigned int ao_cmd_running:1;
192 unsigned int pwm_cmd_running:1;
193
194
195 unsigned int ai_timer;
196 unsigned int ao_timer;
197
198 unsigned int ai_counter;
199 unsigned int ao_counter;
200
201 unsigned int ai_interval;
202
203 u8 *dux_commands;
204 struct mutex mut;
205};
206
207static void usbdux_unlink_urbs(struct urb **urbs, int num_urbs)
208{
209 int i;
210
211 for (i = 0; i < num_urbs; i++)
212 usb_kill_urb(urbs[i]);
213}
214
215static void usbdux_ai_stop(struct comedi_device *dev, int do_unlink)
216{
217 struct usbdux_private *devpriv = dev->private;
218
219 if (do_unlink && devpriv->ai_urbs)
220 usbdux_unlink_urbs(devpriv->ai_urbs, devpriv->n_ai_urbs);
221
222 devpriv->ai_cmd_running = 0;
223}
224
225static int usbdux_ai_cancel(struct comedi_device *dev,
226 struct comedi_subdevice *s)
227{
228 struct usbdux_private *devpriv = dev->private;
229
230
231 mutex_lock(&devpriv->mut);
232
233 usbdux_ai_stop(dev, devpriv->ai_cmd_running);
234 mutex_unlock(&devpriv->mut);
235
236 return 0;
237}
238
239static void usbduxsub_ai_handle_urb(struct comedi_device *dev,
240 struct comedi_subdevice *s,
241 struct urb *urb)
242{
243 struct usbdux_private *devpriv = dev->private;
244 struct comedi_async *async = s->async;
245 struct comedi_cmd *cmd = &async->cmd;
246 int ret;
247 int i;
248
249 devpriv->ai_counter--;
250 if (devpriv->ai_counter == 0) {
251 devpriv->ai_counter = devpriv->ai_timer;
252
253
254 for (i = 0; i < cmd->chanlist_len; i++) {
255 unsigned int range = CR_RANGE(cmd->chanlist[i]);
256 u16 val = le16_to_cpu(devpriv->in_buf[i]);
257
258
259 if (comedi_range_is_bipolar(s, range))
260 val = comedi_offset_munge(s, val);
261
262
263 if (!comedi_buf_write_samples(s, &val, 1))
264 return;
265 }
266
267 if (cmd->stop_src == TRIG_COUNT &&
268 async->scans_done >= cmd->stop_arg)
269 async->events |= COMEDI_CB_EOA;
270 }
271
272
273 if (!(async->events & COMEDI_CB_CANCEL_MASK)) {
274 urb->dev = comedi_to_usb_dev(dev);
275 ret = usb_submit_urb(urb, GFP_ATOMIC);
276 if (ret < 0) {
277 dev_err(dev->class_dev,
278 "urb resubmit failed in int-context! err=%d\n",
279 ret);
280 if (ret == -EL2NSYNC)
281 dev_err(dev->class_dev,
282 "buggy USB host controller or bug in IRQ handler!\n");
283 async->events |= COMEDI_CB_ERROR;
284 }
285 }
286}
287
288static void usbduxsub_ai_isoc_irq(struct urb *urb)
289{
290 struct comedi_device *dev = urb->context;
291 struct comedi_subdevice *s = dev->read_subdev;
292 struct comedi_async *async = s->async;
293 struct usbdux_private *devpriv = dev->private;
294
295
296 if (!devpriv->ai_cmd_running)
297 return;
298
299 switch (urb->status) {
300 case 0:
301
302 memcpy(devpriv->in_buf, urb->transfer_buffer, SIZEINBUF);
303 usbduxsub_ai_handle_urb(dev, s, urb);
304 break;
305
306 case -EILSEQ:
307
308
309
310
311
312 dev_dbg(dev->class_dev, "CRC error in ISO IN stream\n");
313 usbduxsub_ai_handle_urb(dev, s, urb);
314 break;
315
316 case -ECONNRESET:
317 case -ENOENT:
318 case -ESHUTDOWN:
319 case -ECONNABORTED:
320
321 async->events |= COMEDI_CB_ERROR;
322 break;
323
324 default:
325
326 dev_err(dev->class_dev,
327 "Non-zero urb status received in ai intr context: %d\n",
328 urb->status);
329 async->events |= COMEDI_CB_ERROR;
330 break;
331 }
332
333
334
335
336
337 if (async->events & COMEDI_CB_CANCEL_MASK)
338 usbdux_ai_stop(dev, 0);
339
340 comedi_event(dev, s);
341}
342
343static void usbdux_ao_stop(struct comedi_device *dev, int do_unlink)
344{
345 struct usbdux_private *devpriv = dev->private;
346
347 if (do_unlink && devpriv->ao_urbs)
348 usbdux_unlink_urbs(devpriv->ao_urbs, devpriv->n_ao_urbs);
349
350 devpriv->ao_cmd_running = 0;
351}
352
353static int usbdux_ao_cancel(struct comedi_device *dev,
354 struct comedi_subdevice *s)
355{
356 struct usbdux_private *devpriv = dev->private;
357
358
359 mutex_lock(&devpriv->mut);
360
361 usbdux_ao_stop(dev, devpriv->ao_cmd_running);
362 mutex_unlock(&devpriv->mut);
363
364 return 0;
365}
366
367static void usbduxsub_ao_handle_urb(struct comedi_device *dev,
368 struct comedi_subdevice *s,
369 struct urb *urb)
370{
371 struct usbdux_private *devpriv = dev->private;
372 struct comedi_async *async = s->async;
373 struct comedi_cmd *cmd = &async->cmd;
374 u8 *datap;
375 int ret;
376 int i;
377
378 devpriv->ao_counter--;
379 if (devpriv->ao_counter == 0) {
380 devpriv->ao_counter = devpriv->ao_timer;
381
382 if (cmd->stop_src == TRIG_COUNT &&
383 async->scans_done >= cmd->stop_arg) {
384 async->events |= COMEDI_CB_EOA;
385 return;
386 }
387
388
389 datap = urb->transfer_buffer;
390 *datap++ = cmd->chanlist_len;
391 for (i = 0; i < cmd->chanlist_len; i++) {
392 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
393 unsigned short val;
394
395 if (!comedi_buf_read_samples(s, &val, 1)) {
396 dev_err(dev->class_dev, "buffer underflow\n");
397 async->events |= COMEDI_CB_OVERFLOW;
398 return;
399 }
400
401
402 *datap++ = val & 0xff;
403 *datap++ = (val >> 8) & 0xff;
404 *datap++ = chan << 6;
405 s->readback[chan] = val;
406 }
407 }
408
409
410 if (!(async->events & COMEDI_CB_CANCEL_MASK)) {
411 urb->transfer_buffer_length = SIZEOUTBUF;
412 urb->dev = comedi_to_usb_dev(dev);
413 urb->status = 0;
414 if (devpriv->high_speed)
415 urb->interval = 8;
416 else
417 urb->interval = 1;
418 urb->number_of_packets = 1;
419 urb->iso_frame_desc[0].offset = 0;
420 urb->iso_frame_desc[0].length = SIZEOUTBUF;
421 urb->iso_frame_desc[0].status = 0;
422 ret = usb_submit_urb(urb, GFP_ATOMIC);
423 if (ret < 0) {
424 dev_err(dev->class_dev,
425 "ao urb resubm failed in int-cont. ret=%d",
426 ret);
427 if (ret == -EL2NSYNC)
428 dev_err(dev->class_dev,
429 "buggy USB host controller or bug in IRQ handling!\n");
430 async->events |= COMEDI_CB_ERROR;
431 }
432 }
433}
434
435static void usbduxsub_ao_isoc_irq(struct urb *urb)
436{
437 struct comedi_device *dev = urb->context;
438 struct comedi_subdevice *s = dev->write_subdev;
439 struct comedi_async *async = s->async;
440 struct usbdux_private *devpriv = dev->private;
441
442
443 if (!devpriv->ao_cmd_running)
444 return;
445
446 switch (urb->status) {
447 case 0:
448 usbduxsub_ao_handle_urb(dev, s, urb);
449 break;
450
451 case -ECONNRESET:
452 case -ENOENT:
453 case -ESHUTDOWN:
454 case -ECONNABORTED:
455
456 async->events |= COMEDI_CB_ERROR;
457 break;
458
459 default:
460
461 dev_err(dev->class_dev,
462 "Non-zero urb status received in ao intr context: %d\n",
463 urb->status);
464 async->events |= COMEDI_CB_ERROR;
465 break;
466 }
467
468
469
470
471
472 if (async->events & COMEDI_CB_CANCEL_MASK)
473 usbdux_ao_stop(dev, 0);
474
475 comedi_event(dev, s);
476}
477
478static int usbdux_submit_urbs(struct comedi_device *dev,
479 struct urb **urbs, int num_urbs,
480 int input_urb)
481{
482 struct usb_device *usb = comedi_to_usb_dev(dev);
483 struct usbdux_private *devpriv = dev->private;
484 struct urb *urb;
485 int ret;
486 int i;
487
488
489 for (i = 0; i < num_urbs; i++) {
490 urb = urbs[i];
491
492
493 if (input_urb)
494 urb->interval = devpriv->ai_interval;
495 urb->context = dev;
496 urb->dev = usb;
497 urb->status = 0;
498 urb->transfer_flags = URB_ISO_ASAP;
499
500 ret = usb_submit_urb(urb, GFP_ATOMIC);
501 if (ret)
502 return ret;
503 }
504 return 0;
505}
506
507static int usbdux_ai_cmdtest(struct comedi_device *dev,
508 struct comedi_subdevice *s, struct comedi_cmd *cmd)
509{
510 struct usbdux_private *devpriv = dev->private;
511 int err = 0;
512
513
514
515 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
516 err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
517 err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_NOW);
518 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
519 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
520
521 if (err)
522 return 1;
523
524
525
526 err |= comedi_check_trigger_is_unique(cmd->start_src);
527 err |= comedi_check_trigger_is_unique(cmd->stop_src);
528
529
530
531 if (err)
532 return 2;
533
534
535
536 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
537
538 if (cmd->scan_begin_src == TRIG_FOLLOW)
539 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
540
541 if (cmd->scan_begin_src == TRIG_TIMER) {
542
543 unsigned int arg = 1000000;
544 unsigned int min_arg = arg;
545
546 if (devpriv->high_speed) {
547
548
549
550
551
552
553 int i = 1;
554
555
556 while (i < cmd->chanlist_len)
557 i = i * 2;
558
559 arg /= 8;
560 min_arg = arg * i;
561 }
562 err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg,
563 min_arg);
564
565 arg = (cmd->scan_begin_arg / arg) * arg;
566 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
567 }
568
569 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
570 cmd->chanlist_len);
571
572 if (cmd->stop_src == TRIG_COUNT)
573 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
574 else
575 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
576
577 if (err)
578 return 3;
579
580 return 0;
581}
582
583
584
585
586
587static u8 create_adc_command(unsigned int chan, unsigned int range)
588{
589 u8 p = (range <= 1);
590 u8 r = ((range % 2) == 0);
591
592 return (chan << 4) | ((p == 1) << 2) | ((r == 1) << 3);
593}
594
595static int send_dux_commands(struct comedi_device *dev, unsigned int cmd_type)
596{
597 struct usb_device *usb = comedi_to_usb_dev(dev);
598 struct usbdux_private *devpriv = dev->private;
599 int nsent;
600
601 devpriv->dux_commands[0] = cmd_type;
602
603 return usb_bulk_msg(usb, usb_sndbulkpipe(usb, 1),
604 devpriv->dux_commands, SIZEOFDUXBUFFER,
605 &nsent, BULK_TIMEOUT);
606}
607
608static int receive_dux_commands(struct comedi_device *dev, unsigned int command)
609{
610 struct usb_device *usb = comedi_to_usb_dev(dev);
611 struct usbdux_private *devpriv = dev->private;
612 int ret;
613 int nrec;
614 int i;
615
616 for (i = 0; i < RETRIES; i++) {
617 ret = usb_bulk_msg(usb, usb_rcvbulkpipe(usb, 8),
618 devpriv->insn_buf, SIZEINSNBUF,
619 &nrec, BULK_TIMEOUT);
620 if (ret < 0)
621 return ret;
622 if (le16_to_cpu(devpriv->insn_buf[0]) == command)
623 return ret;
624 }
625
626 return -EFAULT;
627}
628
629static int usbdux_ai_inttrig(struct comedi_device *dev,
630 struct comedi_subdevice *s,
631 unsigned int trig_num)
632{
633 struct usbdux_private *devpriv = dev->private;
634 struct comedi_cmd *cmd = &s->async->cmd;
635 int ret;
636
637 if (trig_num != cmd->start_arg)
638 return -EINVAL;
639
640 mutex_lock(&devpriv->mut);
641
642 if (!devpriv->ai_cmd_running) {
643 devpriv->ai_cmd_running = 1;
644 ret = usbdux_submit_urbs(dev, devpriv->ai_urbs,
645 devpriv->n_ai_urbs, 1);
646 if (ret < 0) {
647 devpriv->ai_cmd_running = 0;
648 goto ai_trig_exit;
649 }
650 s->async->inttrig = NULL;
651 } else {
652 ret = -EBUSY;
653 }
654
655ai_trig_exit:
656 mutex_unlock(&devpriv->mut);
657 return ret;
658}
659
660static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
661{
662 struct usbdux_private *devpriv = dev->private;
663 struct comedi_cmd *cmd = &s->async->cmd;
664 int len = cmd->chanlist_len;
665 int ret = -EBUSY;
666 int i;
667
668
669 mutex_lock(&devpriv->mut);
670
671 if (devpriv->ai_cmd_running)
672 goto ai_cmd_exit;
673
674 devpriv->dux_commands[1] = len;
675 for (i = 0; i < len; ++i) {
676 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
677 unsigned int range = CR_RANGE(cmd->chanlist[i]);
678
679 devpriv->dux_commands[i + 2] = create_adc_command(chan, range);
680 }
681
682 ret = send_dux_commands(dev, USBDUX_CMD_MULT_AI);
683 if (ret < 0)
684 goto ai_cmd_exit;
685
686 if (devpriv->high_speed) {
687
688
689
690
691
692 devpriv->ai_interval = 1;
693
694 while (devpriv->ai_interval < len)
695 devpriv->ai_interval *= 2;
696
697 devpriv->ai_timer = cmd->scan_begin_arg /
698 (125000 * devpriv->ai_interval);
699 } else {
700
701 devpriv->ai_interval = 1;
702 devpriv->ai_timer = cmd->scan_begin_arg / 1000000;
703 }
704 if (devpriv->ai_timer < 1) {
705 ret = -EINVAL;
706 goto ai_cmd_exit;
707 }
708
709 devpriv->ai_counter = devpriv->ai_timer;
710
711 if (cmd->start_src == TRIG_NOW) {
712
713 devpriv->ai_cmd_running = 1;
714 ret = usbdux_submit_urbs(dev, devpriv->ai_urbs,
715 devpriv->n_ai_urbs, 1);
716 if (ret < 0) {
717 devpriv->ai_cmd_running = 0;
718
719 goto ai_cmd_exit;
720 }
721 s->async->inttrig = NULL;
722 } else {
723
724
725
726 s->async->inttrig = usbdux_ai_inttrig;
727 }
728
729ai_cmd_exit:
730 mutex_unlock(&devpriv->mut);
731
732 return ret;
733}
734
735
736static int usbdux_ai_insn_read(struct comedi_device *dev,
737 struct comedi_subdevice *s,
738 struct comedi_insn *insn,
739 unsigned int *data)
740{
741 struct usbdux_private *devpriv = dev->private;
742 unsigned int chan = CR_CHAN(insn->chanspec);
743 unsigned int range = CR_RANGE(insn->chanspec);
744 unsigned int val;
745 int ret = -EBUSY;
746 int i;
747
748 mutex_lock(&devpriv->mut);
749
750 if (devpriv->ai_cmd_running)
751 goto ai_read_exit;
752
753
754 devpriv->dux_commands[1] = create_adc_command(chan, range);
755
756
757 ret = send_dux_commands(dev, USBDUX_CMD_SINGLE_AI);
758 if (ret < 0)
759 goto ai_read_exit;
760
761 for (i = 0; i < insn->n; i++) {
762 ret = receive_dux_commands(dev, USBDUX_CMD_SINGLE_AI);
763 if (ret < 0)
764 goto ai_read_exit;
765
766 val = le16_to_cpu(devpriv->insn_buf[1]);
767
768
769 if (comedi_range_is_bipolar(s, range))
770 val = comedi_offset_munge(s, val);
771
772 data[i] = val;
773 }
774
775ai_read_exit:
776 mutex_unlock(&devpriv->mut);
777
778 return ret ? ret : insn->n;
779}
780
781static int usbdux_ao_insn_read(struct comedi_device *dev,
782 struct comedi_subdevice *s,
783 struct comedi_insn *insn,
784 unsigned int *data)
785{
786 struct usbdux_private *devpriv = dev->private;
787 int ret;
788
789 mutex_lock(&devpriv->mut);
790 ret = comedi_readback_insn_read(dev, s, insn, data);
791 mutex_unlock(&devpriv->mut);
792
793 return ret;
794}
795
796static int usbdux_ao_insn_write(struct comedi_device *dev,
797 struct comedi_subdevice *s,
798 struct comedi_insn *insn,
799 unsigned int *data)
800{
801 struct usbdux_private *devpriv = dev->private;
802 unsigned int chan = CR_CHAN(insn->chanspec);
803 __le16 *p = (__le16 *)&devpriv->dux_commands[2];
804 int ret = -EBUSY;
805 int i;
806
807 mutex_lock(&devpriv->mut);
808
809 if (devpriv->ao_cmd_running)
810 goto ao_write_exit;
811
812
813 devpriv->dux_commands[1] = 1;
814
815 devpriv->dux_commands[4] = chan << 6;
816
817 for (i = 0; i < insn->n; i++) {
818 unsigned int val = data[i];
819
820
821 *p = cpu_to_le16(val);
822
823 ret = send_dux_commands(dev, USBDUX_CMD_AO);
824 if (ret < 0)
825 goto ao_write_exit;
826
827 s->readback[chan] = val;
828 }
829
830ao_write_exit:
831 mutex_unlock(&devpriv->mut);
832
833 return ret ? ret : insn->n;
834}
835
836static int usbdux_ao_inttrig(struct comedi_device *dev,
837 struct comedi_subdevice *s,
838 unsigned int trig_num)
839{
840 struct usbdux_private *devpriv = dev->private;
841 struct comedi_cmd *cmd = &s->async->cmd;
842 int ret;
843
844 if (trig_num != cmd->start_arg)
845 return -EINVAL;
846
847 mutex_lock(&devpriv->mut);
848
849 if (!devpriv->ao_cmd_running) {
850 devpriv->ao_cmd_running = 1;
851 ret = usbdux_submit_urbs(dev, devpriv->ao_urbs,
852 devpriv->n_ao_urbs, 0);
853 if (ret < 0) {
854 devpriv->ao_cmd_running = 0;
855 goto ao_trig_exit;
856 }
857 s->async->inttrig = NULL;
858 } else {
859 ret = -EBUSY;
860 }
861
862ao_trig_exit:
863 mutex_unlock(&devpriv->mut);
864 return ret;
865}
866
867static int usbdux_ao_cmdtest(struct comedi_device *dev,
868 struct comedi_subdevice *s, struct comedi_cmd *cmd)
869{
870 int err = 0;
871 unsigned int flags;
872
873
874
875 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
876
877 if (0) {
878
879 flags = TRIG_FOLLOW;
880 } else {
881
882 flags = TRIG_TIMER;
883 }
884 err |= comedi_check_trigger_src(&cmd->scan_begin_src, flags);
885
886 if (0) {
887
888
889
890
891 flags = TRIG_TIMER;
892 } else {
893
894
895
896
897 flags = TRIG_NOW;
898 }
899 err |= comedi_check_trigger_src(&cmd->convert_src, flags);
900
901 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
902 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
903
904 if (err)
905 return 1;
906
907
908
909 err |= comedi_check_trigger_is_unique(cmd->start_src);
910 err |= comedi_check_trigger_is_unique(cmd->stop_src);
911
912
913
914 if (err)
915 return 2;
916
917
918
919 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
920
921 if (cmd->scan_begin_src == TRIG_FOLLOW)
922 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
923
924 if (cmd->scan_begin_src == TRIG_TIMER) {
925 err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg,
926 1000000);
927 }
928
929
930 if (cmd->convert_src == TRIG_TIMER)
931 err |= comedi_check_trigger_arg_min(&cmd->convert_arg, 125000);
932
933 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
934 cmd->chanlist_len);
935
936 if (cmd->stop_src == TRIG_COUNT)
937 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
938 else
939 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
940
941 if (err)
942 return 3;
943
944 return 0;
945}
946
947static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
948{
949 struct usbdux_private *devpriv = dev->private;
950 struct comedi_cmd *cmd = &s->async->cmd;
951 int ret = -EBUSY;
952
953 mutex_lock(&devpriv->mut);
954
955 if (devpriv->ao_cmd_running)
956 goto ao_cmd_exit;
957
958
959
960 if (0) {
961
962
963 devpriv->ao_timer = cmd->convert_arg / 125000;
964 } else {
965
966
967 devpriv->ao_timer = cmd->scan_begin_arg / 1000000;
968 if (devpriv->ao_timer < 1) {
969 ret = -EINVAL;
970 goto ao_cmd_exit;
971 }
972 }
973
974 devpriv->ao_counter = devpriv->ao_timer;
975
976 if (cmd->start_src == TRIG_NOW) {
977
978 devpriv->ao_cmd_running = 1;
979 ret = usbdux_submit_urbs(dev, devpriv->ao_urbs,
980 devpriv->n_ao_urbs, 0);
981 if (ret < 0) {
982 devpriv->ao_cmd_running = 0;
983
984 goto ao_cmd_exit;
985 }
986 s->async->inttrig = NULL;
987 } else {
988
989
990
991 s->async->inttrig = usbdux_ao_inttrig;
992 }
993
994ao_cmd_exit:
995 mutex_unlock(&devpriv->mut);
996
997 return ret;
998}
999
1000static int usbdux_dio_insn_config(struct comedi_device *dev,
1001 struct comedi_subdevice *s,
1002 struct comedi_insn *insn,
1003 unsigned int *data)
1004{
1005 int ret;
1006
1007 ret = comedi_dio_insn_config(dev, s, insn, data, 0);
1008 if (ret)
1009 return ret;
1010
1011
1012
1013
1014
1015 return insn->n;
1016}
1017
1018static int usbdux_dio_insn_bits(struct comedi_device *dev,
1019 struct comedi_subdevice *s,
1020 struct comedi_insn *insn,
1021 unsigned int *data)
1022{
1023 struct usbdux_private *devpriv = dev->private;
1024 int ret;
1025
1026 mutex_lock(&devpriv->mut);
1027
1028 comedi_dio_update_state(s, data);
1029
1030
1031 devpriv->dux_commands[1] = s->io_bits;
1032 devpriv->dux_commands[2] = s->state;
1033
1034
1035
1036
1037
1038 ret = send_dux_commands(dev, USBDUX_CMD_DIO_BITS);
1039 if (ret < 0)
1040 goto dio_exit;
1041 ret = receive_dux_commands(dev, USBDUX_CMD_DIO_BITS);
1042 if (ret < 0)
1043 goto dio_exit;
1044
1045 data[1] = le16_to_cpu(devpriv->insn_buf[1]);
1046
1047dio_exit:
1048 mutex_unlock(&devpriv->mut);
1049
1050 return ret ? ret : insn->n;
1051}
1052
1053static int usbdux_counter_read(struct comedi_device *dev,
1054 struct comedi_subdevice *s,
1055 struct comedi_insn *insn,
1056 unsigned int *data)
1057{
1058 struct usbdux_private *devpriv = dev->private;
1059 unsigned int chan = CR_CHAN(insn->chanspec);
1060 int ret = 0;
1061 int i;
1062
1063 mutex_lock(&devpriv->mut);
1064
1065 for (i = 0; i < insn->n; i++) {
1066 ret = send_dux_commands(dev, USBDUX_CMD_TIMER_RD);
1067 if (ret < 0)
1068 goto counter_read_exit;
1069 ret = receive_dux_commands(dev, USBDUX_CMD_TIMER_RD);
1070 if (ret < 0)
1071 goto counter_read_exit;
1072
1073 data[i] = le16_to_cpu(devpriv->insn_buf[chan + 1]);
1074 }
1075
1076counter_read_exit:
1077 mutex_unlock(&devpriv->mut);
1078
1079 return ret ? ret : insn->n;
1080}
1081
1082static int usbdux_counter_write(struct comedi_device *dev,
1083 struct comedi_subdevice *s,
1084 struct comedi_insn *insn,
1085 unsigned int *data)
1086{
1087 struct usbdux_private *devpriv = dev->private;
1088 unsigned int chan = CR_CHAN(insn->chanspec);
1089 __le16 *p = (__le16 *)&devpriv->dux_commands[2];
1090 int ret = 0;
1091 int i;
1092
1093 mutex_lock(&devpriv->mut);
1094
1095 devpriv->dux_commands[1] = chan;
1096
1097 for (i = 0; i < insn->n; i++) {
1098 *p = cpu_to_le16(data[i]);
1099
1100 ret = send_dux_commands(dev, USBDUX_CMD_TIMER_WR);
1101 if (ret < 0)
1102 break;
1103 }
1104
1105 mutex_unlock(&devpriv->mut);
1106
1107 return ret ? ret : insn->n;
1108}
1109
1110static int usbdux_counter_config(struct comedi_device *dev,
1111 struct comedi_subdevice *s,
1112 struct comedi_insn *insn, unsigned int *data)
1113{
1114
1115 return 2;
1116}
1117
1118static void usbduxsub_unlink_pwm_urbs(struct comedi_device *dev)
1119{
1120 struct usbdux_private *devpriv = dev->private;
1121
1122 usb_kill_urb(devpriv->pwm_urb);
1123}
1124
1125static void usbdux_pwm_stop(struct comedi_device *dev, int do_unlink)
1126{
1127 struct usbdux_private *devpriv = dev->private;
1128
1129 if (do_unlink)
1130 usbduxsub_unlink_pwm_urbs(dev);
1131
1132 devpriv->pwm_cmd_running = 0;
1133}
1134
1135static int usbdux_pwm_cancel(struct comedi_device *dev,
1136 struct comedi_subdevice *s)
1137{
1138 struct usbdux_private *devpriv = dev->private;
1139 int ret;
1140
1141 mutex_lock(&devpriv->mut);
1142
1143 usbdux_pwm_stop(dev, devpriv->pwm_cmd_running);
1144 ret = send_dux_commands(dev, USBDUX_CMD_PWM_OFF);
1145 mutex_unlock(&devpriv->mut);
1146
1147 return ret;
1148}
1149
1150static void usbduxsub_pwm_irq(struct urb *urb)
1151{
1152 struct comedi_device *dev = urb->context;
1153 struct usbdux_private *devpriv = dev->private;
1154 int ret;
1155
1156 switch (urb->status) {
1157 case 0:
1158
1159 break;
1160
1161 case -ECONNRESET:
1162 case -ENOENT:
1163 case -ESHUTDOWN:
1164 case -ECONNABORTED:
1165
1166
1167
1168
1169 if (devpriv->pwm_cmd_running)
1170 usbdux_pwm_stop(dev, 0);
1171
1172 return;
1173
1174 default:
1175
1176 if (devpriv->pwm_cmd_running) {
1177 dev_err(dev->class_dev,
1178 "Non-zero urb status received in pwm intr context: %d\n",
1179 urb->status);
1180 usbdux_pwm_stop(dev, 0);
1181 }
1182 return;
1183 }
1184
1185
1186 if (!devpriv->pwm_cmd_running)
1187 return;
1188
1189 urb->transfer_buffer_length = devpriv->pwm_buf_sz;
1190 urb->dev = comedi_to_usb_dev(dev);
1191 urb->status = 0;
1192 if (devpriv->pwm_cmd_running) {
1193 ret = usb_submit_urb(urb, GFP_ATOMIC);
1194 if (ret < 0) {
1195 dev_err(dev->class_dev,
1196 "pwm urb resubm failed in int-cont. ret=%d",
1197 ret);
1198 if (ret == -EL2NSYNC)
1199 dev_err(dev->class_dev,
1200 "buggy USB host controller or bug in IRQ handling!\n");
1201
1202
1203 usbdux_pwm_stop(dev, 0);
1204 }
1205 }
1206}
1207
1208static int usbduxsub_submit_pwm_urbs(struct comedi_device *dev)
1209{
1210 struct usb_device *usb = comedi_to_usb_dev(dev);
1211 struct usbdux_private *devpriv = dev->private;
1212 struct urb *urb = devpriv->pwm_urb;
1213
1214
1215 usb_fill_bulk_urb(urb, usb, usb_sndbulkpipe(usb, 4),
1216 urb->transfer_buffer,
1217 devpriv->pwm_buf_sz,
1218 usbduxsub_pwm_irq,
1219 dev);
1220
1221 return usb_submit_urb(urb, GFP_ATOMIC);
1222}
1223
1224static int usbdux_pwm_period(struct comedi_device *dev,
1225 struct comedi_subdevice *s,
1226 unsigned int period)
1227{
1228 struct usbdux_private *devpriv = dev->private;
1229 int fx2delay = 255;
1230
1231 if (period < MIN_PWM_PERIOD)
1232 return -EAGAIN;
1233
1234 fx2delay = (period / (6 * 512 * 1000 / 33)) - 6;
1235 if (fx2delay > 255)
1236 return -EAGAIN;
1237
1238 devpriv->pwm_delay = fx2delay;
1239 devpriv->pwm_period = period;
1240
1241 return 0;
1242}
1243
1244static int usbdux_pwm_start(struct comedi_device *dev,
1245 struct comedi_subdevice *s)
1246{
1247 struct usbdux_private *devpriv = dev->private;
1248 int ret = 0;
1249
1250 mutex_lock(&devpriv->mut);
1251
1252 if (devpriv->pwm_cmd_running)
1253 goto pwm_start_exit;
1254
1255 devpriv->dux_commands[1] = devpriv->pwm_delay;
1256 ret = send_dux_commands(dev, USBDUX_CMD_PWM_ON);
1257 if (ret < 0)
1258 goto pwm_start_exit;
1259
1260
1261 memset(devpriv->pwm_urb->transfer_buffer, 0, devpriv->pwm_buf_sz);
1262
1263 devpriv->pwm_cmd_running = 1;
1264 ret = usbduxsub_submit_pwm_urbs(dev);
1265 if (ret < 0)
1266 devpriv->pwm_cmd_running = 0;
1267
1268pwm_start_exit:
1269 mutex_unlock(&devpriv->mut);
1270
1271 return ret;
1272}
1273
1274static void usbdux_pwm_pattern(struct comedi_device *dev,
1275 struct comedi_subdevice *s,
1276 unsigned int chan,
1277 unsigned int value,
1278 unsigned int sign)
1279{
1280 struct usbdux_private *devpriv = dev->private;
1281 char pwm_mask = (1 << chan);
1282 char sgn_mask = (16 << chan);
1283 char *buf = (char *)(devpriv->pwm_urb->transfer_buffer);
1284 int szbuf = devpriv->pwm_buf_sz;
1285 int i;
1286
1287 for (i = 0; i < szbuf; i++) {
1288 char c = *buf;
1289
1290 c &= ~pwm_mask;
1291 if (i < value)
1292 c |= pwm_mask;
1293 if (!sign)
1294 c &= ~sgn_mask;
1295 else
1296 c |= sgn_mask;
1297 *buf++ = c;
1298 }
1299}
1300
1301static int usbdux_pwm_write(struct comedi_device *dev,
1302 struct comedi_subdevice *s,
1303 struct comedi_insn *insn,
1304 unsigned int *data)
1305{
1306 unsigned int chan = CR_CHAN(insn->chanspec);
1307
1308
1309
1310
1311
1312 if (insn->n != 1)
1313 return -EINVAL;
1314
1315
1316
1317
1318
1319 usbdux_pwm_pattern(dev, s, chan, data[0], 0);
1320
1321 return insn->n;
1322}
1323
1324static int usbdux_pwm_config(struct comedi_device *dev,
1325 struct comedi_subdevice *s,
1326 struct comedi_insn *insn,
1327 unsigned int *data)
1328{
1329 struct usbdux_private *devpriv = dev->private;
1330 unsigned int chan = CR_CHAN(insn->chanspec);
1331
1332 switch (data[0]) {
1333 case INSN_CONFIG_ARM:
1334
1335
1336
1337
1338 if (data[1] != 0)
1339 return -EINVAL;
1340 return usbdux_pwm_start(dev, s);
1341 case INSN_CONFIG_DISARM:
1342 return usbdux_pwm_cancel(dev, s);
1343 case INSN_CONFIG_GET_PWM_STATUS:
1344 data[1] = devpriv->pwm_cmd_running;
1345 return 0;
1346 case INSN_CONFIG_PWM_SET_PERIOD:
1347 return usbdux_pwm_period(dev, s, data[1]);
1348 case INSN_CONFIG_PWM_GET_PERIOD:
1349 data[1] = devpriv->pwm_period;
1350 return 0;
1351 case INSN_CONFIG_PWM_SET_H_BRIDGE:
1352
1353
1354
1355
1356 usbdux_pwm_pattern(dev, s, chan, data[1], (data[2] != 0));
1357 return 0;
1358 case INSN_CONFIG_PWM_GET_H_BRIDGE:
1359
1360 return -EINVAL;
1361 }
1362 return -EINVAL;
1363}
1364
1365static int usbdux_firmware_upload(struct comedi_device *dev,
1366 const u8 *data, size_t size,
1367 unsigned long context)
1368{
1369 struct usb_device *usb = comedi_to_usb_dev(dev);
1370 u8 *buf;
1371 u8 *tmp;
1372 int ret;
1373
1374 if (!data)
1375 return 0;
1376
1377 if (size > USBDUX_FIRMWARE_MAX_LEN) {
1378 dev_err(dev->class_dev,
1379 "usbdux firmware binary it too large for FX2.\n");
1380 return -ENOMEM;
1381 }
1382
1383
1384 buf = kmemdup(data, size, GFP_KERNEL);
1385 if (!buf)
1386 return -ENOMEM;
1387
1388
1389 tmp = kmalloc(1, GFP_KERNEL);
1390 if (!tmp) {
1391 kfree(buf);
1392 return -ENOMEM;
1393 }
1394
1395
1396 *tmp = 1;
1397 ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0),
1398 USBDUX_FIRMWARE_CMD,
1399 VENDOR_DIR_OUT,
1400 USBDUX_CPU_CS, 0x0000,
1401 tmp, 1,
1402 BULK_TIMEOUT);
1403 if (ret < 0) {
1404 dev_err(dev->class_dev, "can not stop firmware\n");
1405 goto done;
1406 }
1407
1408
1409 ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0),
1410 USBDUX_FIRMWARE_CMD,
1411 VENDOR_DIR_OUT,
1412 0, 0x0000,
1413 buf, size,
1414 BULK_TIMEOUT);
1415 if (ret < 0) {
1416 dev_err(dev->class_dev, "firmware upload failed\n");
1417 goto done;
1418 }
1419
1420
1421 *tmp = 0;
1422 ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0),
1423 USBDUX_FIRMWARE_CMD,
1424 VENDOR_DIR_OUT,
1425 USBDUX_CPU_CS, 0x0000,
1426 tmp, 1,
1427 BULK_TIMEOUT);
1428 if (ret < 0)
1429 dev_err(dev->class_dev, "can not start firmware\n");
1430
1431done:
1432 kfree(tmp);
1433 kfree(buf);
1434 return ret;
1435}
1436
1437static int usbdux_alloc_usb_buffers(struct comedi_device *dev)
1438{
1439 struct usb_device *usb = comedi_to_usb_dev(dev);
1440 struct usbdux_private *devpriv = dev->private;
1441 struct urb *urb;
1442 int i;
1443
1444 devpriv->dux_commands = kzalloc(SIZEOFDUXBUFFER, GFP_KERNEL);
1445 devpriv->in_buf = kzalloc(SIZEINBUF, GFP_KERNEL);
1446 devpriv->insn_buf = kzalloc(SIZEINSNBUF, GFP_KERNEL);
1447 devpriv->ai_urbs = kcalloc(devpriv->n_ai_urbs, sizeof(void *),
1448 GFP_KERNEL);
1449 devpriv->ao_urbs = kcalloc(devpriv->n_ao_urbs, sizeof(void *),
1450 GFP_KERNEL);
1451 if (!devpriv->dux_commands || !devpriv->in_buf || !devpriv->insn_buf ||
1452 !devpriv->ai_urbs || !devpriv->ao_urbs)
1453 return -ENOMEM;
1454
1455 for (i = 0; i < devpriv->n_ai_urbs; i++) {
1456
1457 urb = usb_alloc_urb(1, GFP_KERNEL);
1458 if (!urb)
1459 return -ENOMEM;
1460 devpriv->ai_urbs[i] = urb;
1461
1462 urb->dev = usb;
1463 urb->context = dev;
1464 urb->pipe = usb_rcvisocpipe(usb, 6);
1465 urb->transfer_flags = URB_ISO_ASAP;
1466 urb->transfer_buffer = kzalloc(SIZEINBUF, GFP_KERNEL);
1467 if (!urb->transfer_buffer)
1468 return -ENOMEM;
1469
1470 urb->complete = usbduxsub_ai_isoc_irq;
1471 urb->number_of_packets = 1;
1472 urb->transfer_buffer_length = SIZEINBUF;
1473 urb->iso_frame_desc[0].offset = 0;
1474 urb->iso_frame_desc[0].length = SIZEINBUF;
1475 }
1476
1477 for (i = 0; i < devpriv->n_ao_urbs; i++) {
1478
1479 urb = usb_alloc_urb(1, GFP_KERNEL);
1480 if (!urb)
1481 return -ENOMEM;
1482 devpriv->ao_urbs[i] = urb;
1483
1484 urb->dev = usb;
1485 urb->context = dev;
1486 urb->pipe = usb_sndisocpipe(usb, 2);
1487 urb->transfer_flags = URB_ISO_ASAP;
1488 urb->transfer_buffer = kzalloc(SIZEOUTBUF, GFP_KERNEL);
1489 if (!urb->transfer_buffer)
1490 return -ENOMEM;
1491
1492 urb->complete = usbduxsub_ao_isoc_irq;
1493 urb->number_of_packets = 1;
1494 urb->transfer_buffer_length = SIZEOUTBUF;
1495 urb->iso_frame_desc[0].offset = 0;
1496 urb->iso_frame_desc[0].length = SIZEOUTBUF;
1497 if (devpriv->high_speed)
1498 urb->interval = 8;
1499 else
1500 urb->interval = 1;
1501 }
1502
1503
1504 if (devpriv->pwm_buf_sz) {
1505 urb = usb_alloc_urb(0, GFP_KERNEL);
1506 if (!urb)
1507 return -ENOMEM;
1508 devpriv->pwm_urb = urb;
1509
1510
1511 urb->transfer_buffer = kzalloc(devpriv->pwm_buf_sz,
1512 GFP_KERNEL);
1513 if (!urb->transfer_buffer)
1514 return -ENOMEM;
1515 }
1516
1517 return 0;
1518}
1519
1520static void usbdux_free_usb_buffers(struct comedi_device *dev)
1521{
1522 struct usbdux_private *devpriv = dev->private;
1523 struct urb *urb;
1524 int i;
1525
1526 urb = devpriv->pwm_urb;
1527 if (urb) {
1528 kfree(urb->transfer_buffer);
1529 usb_free_urb(urb);
1530 }
1531 if (devpriv->ao_urbs) {
1532 for (i = 0; i < devpriv->n_ao_urbs; i++) {
1533 urb = devpriv->ao_urbs[i];
1534 if (urb) {
1535 kfree(urb->transfer_buffer);
1536 usb_free_urb(urb);
1537 }
1538 }
1539 kfree(devpriv->ao_urbs);
1540 }
1541 if (devpriv->ai_urbs) {
1542 for (i = 0; i < devpriv->n_ai_urbs; i++) {
1543 urb = devpriv->ai_urbs[i];
1544 if (urb) {
1545 kfree(urb->transfer_buffer);
1546 usb_free_urb(urb);
1547 }
1548 }
1549 kfree(devpriv->ai_urbs);
1550 }
1551 kfree(devpriv->insn_buf);
1552 kfree(devpriv->in_buf);
1553 kfree(devpriv->dux_commands);
1554}
1555
1556static int usbdux_auto_attach(struct comedi_device *dev,
1557 unsigned long context_unused)
1558{
1559 struct usb_interface *intf = comedi_to_usb_interface(dev);
1560 struct usb_device *usb = comedi_to_usb_dev(dev);
1561 struct usbdux_private *devpriv;
1562 struct comedi_subdevice *s;
1563 int ret;
1564
1565 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1566 if (!devpriv)
1567 return -ENOMEM;
1568
1569 mutex_init(&devpriv->mut);
1570
1571 usb_set_intfdata(intf, devpriv);
1572
1573 devpriv->high_speed = (usb->speed == USB_SPEED_HIGH);
1574 if (devpriv->high_speed) {
1575 devpriv->n_ai_urbs = NUMOFINBUFFERSHIGH;
1576 devpriv->n_ao_urbs = NUMOFOUTBUFFERSHIGH;
1577 devpriv->pwm_buf_sz = 512;
1578 } else {
1579 devpriv->n_ai_urbs = NUMOFINBUFFERSFULL;
1580 devpriv->n_ao_urbs = NUMOFOUTBUFFERSFULL;
1581 }
1582
1583 ret = usbdux_alloc_usb_buffers(dev);
1584 if (ret)
1585 return ret;
1586
1587
1588 ret = usb_set_interface(usb, intf->altsetting->desc.bInterfaceNumber,
1589 3);
1590 if (ret < 0) {
1591 dev_err(dev->class_dev,
1592 "could not set alternate setting 3 in high speed\n");
1593 return ret;
1594 }
1595
1596 ret = comedi_load_firmware(dev, &usb->dev, USBDUX_FIRMWARE,
1597 usbdux_firmware_upload, 0);
1598 if (ret < 0)
1599 return ret;
1600
1601 ret = comedi_alloc_subdevices(dev, (devpriv->high_speed) ? 5 : 4);
1602 if (ret)
1603 return ret;
1604
1605
1606 s = &dev->subdevices[0];
1607 dev->read_subdev = s;
1608 s->type = COMEDI_SUBD_AI;
1609 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
1610 s->n_chan = 8;
1611 s->maxdata = 0x0fff;
1612 s->len_chanlist = 8;
1613 s->range_table = &range_usbdux_ai_range;
1614 s->insn_read = usbdux_ai_insn_read;
1615 s->do_cmdtest = usbdux_ai_cmdtest;
1616 s->do_cmd = usbdux_ai_cmd;
1617 s->cancel = usbdux_ai_cancel;
1618
1619
1620 s = &dev->subdevices[1];
1621 dev->write_subdev = s;
1622 s->type = COMEDI_SUBD_AO;
1623 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
1624 s->n_chan = 4;
1625 s->maxdata = 0x0fff;
1626 s->len_chanlist = s->n_chan;
1627 s->range_table = &range_usbdux_ao_range;
1628 s->do_cmdtest = usbdux_ao_cmdtest;
1629 s->do_cmd = usbdux_ao_cmd;
1630 s->cancel = usbdux_ao_cancel;
1631 s->insn_read = usbdux_ao_insn_read;
1632 s->insn_write = usbdux_ao_insn_write;
1633
1634 ret = comedi_alloc_subdev_readback(s);
1635 if (ret)
1636 return ret;
1637
1638
1639 s = &dev->subdevices[2];
1640 s->type = COMEDI_SUBD_DIO;
1641 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1642 s->n_chan = 8;
1643 s->maxdata = 1;
1644 s->range_table = &range_digital;
1645 s->insn_bits = usbdux_dio_insn_bits;
1646 s->insn_config = usbdux_dio_insn_config;
1647
1648
1649 s = &dev->subdevices[3];
1650 s->type = COMEDI_SUBD_COUNTER;
1651 s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
1652 s->n_chan = 4;
1653 s->maxdata = 0xffff;
1654 s->insn_read = usbdux_counter_read;
1655 s->insn_write = usbdux_counter_write;
1656 s->insn_config = usbdux_counter_config;
1657
1658 if (devpriv->high_speed) {
1659
1660 s = &dev->subdevices[4];
1661 s->type = COMEDI_SUBD_PWM;
1662 s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE;
1663 s->n_chan = 8;
1664 s->maxdata = devpriv->pwm_buf_sz;
1665 s->insn_write = usbdux_pwm_write;
1666 s->insn_config = usbdux_pwm_config;
1667
1668 usbdux_pwm_period(dev, s, PWM_DEFAULT_PERIOD);
1669 }
1670
1671 return 0;
1672}
1673
1674static void usbdux_detach(struct comedi_device *dev)
1675{
1676 struct usb_interface *intf = comedi_to_usb_interface(dev);
1677 struct usbdux_private *devpriv = dev->private;
1678
1679 usb_set_intfdata(intf, NULL);
1680
1681 if (!devpriv)
1682 return;
1683
1684 mutex_lock(&devpriv->mut);
1685
1686
1687 usbdux_pwm_stop(dev, 1);
1688 usbdux_ao_stop(dev, 1);
1689 usbdux_ai_stop(dev, 1);
1690
1691 usbdux_free_usb_buffers(dev);
1692
1693 mutex_unlock(&devpriv->mut);
1694}
1695
1696static struct comedi_driver usbdux_driver = {
1697 .driver_name = "usbdux",
1698 .module = THIS_MODULE,
1699 .auto_attach = usbdux_auto_attach,
1700 .detach = usbdux_detach,
1701};
1702
1703static int usbdux_usb_probe(struct usb_interface *intf,
1704 const struct usb_device_id *id)
1705{
1706 return comedi_usb_auto_config(intf, &usbdux_driver, 0);
1707}
1708
1709static const struct usb_device_id usbdux_usb_table[] = {
1710 { USB_DEVICE(0x13d8, 0x0001) },
1711 { USB_DEVICE(0x13d8, 0x0002) },
1712 { }
1713};
1714MODULE_DEVICE_TABLE(usb, usbdux_usb_table);
1715
1716static struct usb_driver usbdux_usb_driver = {
1717 .name = "usbdux",
1718 .probe = usbdux_usb_probe,
1719 .disconnect = comedi_usb_auto_unconfig,
1720 .id_table = usbdux_usb_table,
1721};
1722module_comedi_usb_driver(usbdux_driver, usbdux_usb_driver);
1723
1724MODULE_AUTHOR("Bernd Porr, BerndPorr@f2s.com");
1725MODULE_DESCRIPTION("Stirling/ITL USB-DUX -- Bernd.Porr@f2s.com");
1726MODULE_LICENSE("GPL");
1727MODULE_FIRMWARE(USBDUX_FIRMWARE);
1728