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