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