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
82
83
84
85
86
87
88
89#include <linux/kernel.h>
90#include <linux/module.h>
91#include <linux/init.h>
92#include <linux/slab.h>
93#include <linux/input.h>
94#include <linux/usb.h>
95#include <linux/fcntl.h>
96#include <linux/compiler.h>
97#include <linux/firmware.h>
98
99#include "../comedidev.h"
100
101#include "comedi_fc.h"
102
103
104#define BULK_TIMEOUT 1000
105
106
107#define FIRMWARE "usbdux_firmware.bin"
108#define USBDUXSUB_FIRMWARE 0xA0
109#define VENDOR_DIR_IN 0xC0
110#define VENDOR_DIR_OUT 0x40
111
112
113#define USBDUXSUB_CPUCS 0xE600
114
115
116
117
118
119
120#define USBDUXSUB_MINOR 32
121
122
123#define TB_LEN 0x2000
124
125
126#define ISOINEP 6
127
128
129#define ISOOUTEP 2
130
131
132#define COMMAND_OUT_EP 1
133
134
135#define COMMAND_IN_EP 8
136
137
138#define PWM_EP 4
139
140
141#define MIN_PWM_PERIOD ((long)(1E9/300))
142
143
144#define PWM_DEFAULT_PERIOD ((long)(1E9/100))
145
146
147#define NUMCHANNELS 8
148
149
150#define SIZEADIN ((sizeof(int16_t)))
151
152
153
154
155
156#define SIZEINBUF ((8*SIZEADIN))
157
158
159#define SIZEINSNBUF 16
160
161
162#define NUMOUTCHANNELS 8
163
164
165#define SIZEDAOUT ((sizeof(int8_t)+sizeof(int16_t)))
166
167
168
169
170
171
172#define SIZEOUTBUF ((8*SIZEDAOUT))
173
174
175
176
177
178#define SIZEOFDUXBUFFER ((8*SIZEDAOUT+2))
179
180
181#define NUMOFINBUFFERSFULL 5
182
183
184#define NUMOFOUTBUFFERSFULL 5
185
186
187
188#define NUMOFINBUFFERSHIGH 10
189
190
191
192#define NUMOFOUTBUFFERSHIGH 10
193
194
195#define NUMUSBDUX 16
196
197
198#define SUBDEV_AD 0
199
200
201#define SUBDEV_DA 1
202
203
204#define SUBDEV_DIO 2
205
206
207#define SUBDEV_COUNTER 3
208
209
210#define SUBDEV_PWM 4
211
212
213#define RETRIES 10
214
215
216
217static const struct comedi_lrange range_usbdux_ai_range = { 4, {
218 BIP_RANGE
219 (4.096),
220 BIP_RANGE(4.096
221 / 2),
222 UNI_RANGE
223 (4.096),
224 UNI_RANGE(4.096
225 / 2)
226 }
227};
228
229static const struct comedi_lrange range_usbdux_ao_range = { 2, {
230 BIP_RANGE
231 (4.096),
232 UNI_RANGE
233 (4.096),
234 }
235};
236
237
238
239
240
241
242
243
244
245struct usbduxsub {
246
247 int attached;
248
249 int probed;
250
251 struct usb_device *usbdev;
252
253 int num_in_buffers;
254
255 int num_out_buffers;
256
257 struct urb **urb_in;
258 struct urb **urb_out;
259
260 struct urb *urb_pwm;
261
262 unsigned int pwm_period;
263
264 int8_t pwn_delay;
265
266 int size_pwm_buf;
267
268 int16_t *in_buffer;
269
270 int16_t *insn_buffer;
271
272 int16_t *out_buffer;
273
274 int ifnum;
275
276 struct usb_interface *interface;
277
278 struct comedi_device *comedidev;
279
280 short int high_speed;
281
282 short int ai_cmd_running;
283 short int ao_cmd_running;
284
285 short int pwm_cmd_running;
286
287 short int ai_continous;
288 short int ao_continous;
289
290 int ai_sample_count;
291 int ao_sample_count;
292
293 unsigned int ai_timer;
294 unsigned int ao_timer;
295
296 unsigned int ai_counter;
297 unsigned int ao_counter;
298
299 unsigned int ai_interval;
300
301 int8_t *dac_commands;
302
303 int8_t *dux_commands;
304 struct semaphore sem;
305};
306
307
308
309
310
311
312
313
314static struct usbduxsub usbduxsub[NUMUSBDUX];
315
316static DEFINE_SEMAPHORE(start_stop_sem);
317
318
319
320
321
322static int usbduxsub_unlink_inurbs(struct usbduxsub *usbduxsub_tmp)
323{
324 int i = 0;
325 int err = 0;
326
327 if (usbduxsub_tmp && usbduxsub_tmp->urb_in) {
328 for (i = 0; i < usbduxsub_tmp->num_in_buffers; i++) {
329 if (usbduxsub_tmp->urb_in[i]) {
330
331
332 usb_kill_urb(usbduxsub_tmp->urb_in[i]);
333 }
334 dev_dbg(&usbduxsub_tmp->interface->dev,
335 "comedi: usbdux: unlinked InURB %d, err=%d\n",
336 i, err);
337 }
338 }
339 return err;
340}
341
342
343
344
345
346
347static int usbdux_ai_stop(struct usbduxsub *this_usbduxsub, int do_unlink)
348{
349 int ret = 0;
350
351 if (!this_usbduxsub) {
352 pr_err("comedi?: usbdux_ai_stop: this_usbduxsub=NULL!\n");
353 return -EFAULT;
354 }
355 dev_dbg(&this_usbduxsub->interface->dev, "comedi: usbdux_ai_stop\n");
356
357 if (do_unlink) {
358
359 ret = usbduxsub_unlink_inurbs(this_usbduxsub);
360 }
361
362 this_usbduxsub->ai_cmd_running = 0;
363
364 return ret;
365}
366
367
368
369
370
371static int usbdux_ai_cancel(struct comedi_device *dev,
372 struct comedi_subdevice *s)
373{
374 struct usbduxsub *this_usbduxsub;
375 int res = 0;
376
377
378 this_usbduxsub = dev->private;
379 if (!this_usbduxsub)
380 return -EFAULT;
381
382 dev_dbg(&this_usbduxsub->interface->dev, "comedi: usbdux_ai_cancel\n");
383
384
385 down(&this_usbduxsub->sem);
386 if (!(this_usbduxsub->probed)) {
387 up(&this_usbduxsub->sem);
388 return -ENODEV;
389 }
390
391 res = usbdux_ai_stop(this_usbduxsub, this_usbduxsub->ai_cmd_running);
392 up(&this_usbduxsub->sem);
393 return res;
394}
395
396
397static void usbduxsub_ai_isoc_irq(struct urb *urb)
398{
399 int i, err, n;
400 struct usbduxsub *this_usbduxsub;
401 struct comedi_device *this_comedidev;
402 struct comedi_subdevice *s;
403
404
405 this_comedidev = urb->context;
406
407 this_usbduxsub = this_comedidev->private;
408
409 s = &this_comedidev->subdevices[SUBDEV_AD];
410
411
412 switch (urb->status) {
413 case 0:
414
415 memcpy(this_usbduxsub->in_buffer,
416 urb->transfer_buffer, SIZEINBUF);
417 break;
418 case -EILSEQ:
419
420
421
422 dev_dbg(&urb->dev->dev,
423 "comedi%d: usbdux: CRC error in ISO IN stream.\n",
424 this_usbduxsub->comedidev->minor);
425
426 break;
427
428 case -ECONNRESET:
429 case -ENOENT:
430 case -ESHUTDOWN:
431 case -ECONNABORTED:
432
433 if (this_usbduxsub->ai_cmd_running) {
434
435
436 s->async->events |= COMEDI_CB_EOA;
437 s->async->events |= COMEDI_CB_ERROR;
438 comedi_event(this_usbduxsub->comedidev, s);
439
440 usbdux_ai_stop(this_usbduxsub, 0);
441 }
442 return;
443
444 default:
445
446
447 if (this_usbduxsub->ai_cmd_running) {
448 dev_err(&urb->dev->dev,
449 "Non-zero urb status received in ai intr "
450 "context: %d\n", urb->status);
451 s->async->events |= COMEDI_CB_EOA;
452 s->async->events |= COMEDI_CB_ERROR;
453 comedi_event(this_usbduxsub->comedidev, s);
454
455 usbdux_ai_stop(this_usbduxsub, 0);
456 }
457 return;
458 }
459
460
461
462
463
464 if (unlikely((!(this_usbduxsub->ai_cmd_running)))) {
465
466
467
468
469 return;
470 }
471
472 urb->dev = this_usbduxsub->usbdev;
473
474
475 err = usb_submit_urb(urb, GFP_ATOMIC);
476 if (unlikely(err < 0)) {
477 dev_err(&urb->dev->dev,
478 "comedi_: urb resubmit failed in int-context! err=%d\n",
479 err);
480 if (err == -EL2NSYNC)
481 dev_err(&urb->dev->dev,
482 "buggy USB host controller or bug in IRQ "
483 "handler!\n");
484 s->async->events |= COMEDI_CB_EOA;
485 s->async->events |= COMEDI_CB_ERROR;
486 comedi_event(this_usbduxsub->comedidev, s);
487
488 usbdux_ai_stop(this_usbduxsub, 0);
489 return;
490 }
491
492 this_usbduxsub->ai_counter--;
493 if (likely(this_usbduxsub->ai_counter > 0))
494 return;
495
496
497 this_usbduxsub->ai_counter = this_usbduxsub->ai_timer;
498
499
500 if (!(this_usbduxsub->ai_continous)) {
501
502 this_usbduxsub->ai_sample_count--;
503
504 if (this_usbduxsub->ai_sample_count < 0) {
505
506 usbdux_ai_stop(this_usbduxsub, 0);
507
508 s->async->events |= COMEDI_CB_EOA;
509 comedi_event(this_usbduxsub->comedidev, s);
510 return;
511 }
512 }
513
514 n = s->async->cmd.chanlist_len;
515 for (i = 0; i < n; i++) {
516
517 if (CR_RANGE(s->async->cmd.chanlist[i]) <= 1) {
518 err = comedi_buf_put
519 (s->async,
520 le16_to_cpu(this_usbduxsub->in_buffer[i]) ^ 0x800);
521 } else {
522 err = comedi_buf_put
523 (s->async,
524 le16_to_cpu(this_usbduxsub->in_buffer[i]));
525 }
526 if (unlikely(err == 0)) {
527
528 usbdux_ai_stop(this_usbduxsub, 0);
529 return;
530 }
531 }
532
533 s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS;
534 comedi_event(this_usbduxsub->comedidev, s);
535}
536
537static int usbduxsub_unlink_outurbs(struct usbduxsub *usbduxsub_tmp)
538{
539 int i = 0;
540 int err = 0;
541
542 if (usbduxsub_tmp && usbduxsub_tmp->urb_out) {
543 for (i = 0; i < usbduxsub_tmp->num_out_buffers; i++) {
544 if (usbduxsub_tmp->urb_out[i])
545 usb_kill_urb(usbduxsub_tmp->urb_out[i]);
546
547 dev_dbg(&usbduxsub_tmp->interface->dev,
548 "comedi: usbdux: unlinked OutURB %d: res=%d\n",
549 i, err);
550 }
551 }
552 return err;
553}
554
555
556
557
558static int usbdux_ao_stop(struct usbduxsub *this_usbduxsub, int do_unlink)
559{
560 int ret = 0;
561
562 if (!this_usbduxsub)
563 return -EFAULT;
564 dev_dbg(&this_usbduxsub->interface->dev, "comedi: usbdux_ao_cancel\n");
565
566 if (do_unlink)
567 ret = usbduxsub_unlink_outurbs(this_usbduxsub);
568
569 this_usbduxsub->ao_cmd_running = 0;
570
571 return ret;
572}
573
574
575static int usbdux_ao_cancel(struct comedi_device *dev,
576 struct comedi_subdevice *s)
577{
578 struct usbduxsub *this_usbduxsub = dev->private;
579 int res = 0;
580
581 if (!this_usbduxsub)
582 return -EFAULT;
583
584
585 down(&this_usbduxsub->sem);
586 if (!(this_usbduxsub->probed)) {
587 up(&this_usbduxsub->sem);
588 return -ENODEV;
589 }
590
591 res = usbdux_ao_stop(this_usbduxsub, this_usbduxsub->ao_cmd_running);
592 up(&this_usbduxsub->sem);
593 return res;
594}
595
596static void usbduxsub_ao_isoc_irq(struct urb *urb)
597{
598 int i, ret;
599 int8_t *datap;
600 struct usbduxsub *this_usbduxsub;
601 struct comedi_device *this_comedidev;
602 struct comedi_subdevice *s;
603
604
605 this_comedidev = urb->context;
606
607 this_usbduxsub = this_comedidev->private;
608
609 s = &this_comedidev->subdevices[SUBDEV_DA];
610
611 switch (urb->status) {
612 case 0:
613
614 break;
615
616 case -ECONNRESET:
617 case -ENOENT:
618 case -ESHUTDOWN:
619 case -ECONNABORTED:
620
621
622 if (this_usbduxsub->ao_cmd_running) {
623 s->async->events |= COMEDI_CB_EOA;
624 comedi_event(this_usbduxsub->comedidev, s);
625 usbdux_ao_stop(this_usbduxsub, 0);
626 }
627 return;
628
629 default:
630
631 if (this_usbduxsub->ao_cmd_running) {
632 dev_err(&urb->dev->dev,
633 "comedi_: Non-zero urb status received in ao "
634 "intr context: %d\n", urb->status);
635 s->async->events |= COMEDI_CB_ERROR;
636 s->async->events |= COMEDI_CB_EOA;
637 comedi_event(this_usbduxsub->comedidev, s);
638
639 usbdux_ao_stop(this_usbduxsub, 0);
640 }
641 return;
642 }
643
644
645 if (!(this_usbduxsub->ao_cmd_running))
646 return;
647
648
649 this_usbduxsub->ao_counter--;
650 if ((int)this_usbduxsub->ao_counter <= 0) {
651
652 this_usbduxsub->ao_counter = this_usbduxsub->ao_timer;
653
654
655 if (!(this_usbduxsub->ao_continous)) {
656
657 this_usbduxsub->ao_sample_count--;
658 if (this_usbduxsub->ao_sample_count < 0) {
659
660 usbdux_ao_stop(this_usbduxsub, 0);
661 s->async->events |= COMEDI_CB_EOA;
662 comedi_event(this_usbduxsub->comedidev, s);
663
664 return;
665 }
666 }
667
668 ((uint8_t *) (urb->transfer_buffer))[0] =
669 s->async->cmd.chanlist_len;
670 for (i = 0; i < s->async->cmd.chanlist_len; i++) {
671 short temp;
672 if (i >= NUMOUTCHANNELS)
673 break;
674
675
676 datap =
677 (&(((int8_t *) urb->transfer_buffer)[i * 3 + 1]));
678
679 ret = comedi_buf_get(s->async, &temp);
680 datap[0] = temp;
681 datap[1] = temp >> 8;
682 datap[2] = this_usbduxsub->dac_commands[i];
683
684
685 if (ret < 0) {
686 dev_err(&urb->dev->dev,
687 "comedi: buffer underflow\n");
688 s->async->events |= COMEDI_CB_EOA;
689 s->async->events |= COMEDI_CB_OVERFLOW;
690 }
691
692 s->async->events |= COMEDI_CB_BLOCK;
693 comedi_event(this_usbduxsub->comedidev, s);
694 }
695 }
696 urb->transfer_buffer_length = SIZEOUTBUF;
697 urb->dev = this_usbduxsub->usbdev;
698 urb->status = 0;
699 if (this_usbduxsub->ao_cmd_running) {
700 if (this_usbduxsub->high_speed) {
701
702 urb->interval = 8;
703 } else {
704
705 urb->interval = 1;
706 }
707 urb->number_of_packets = 1;
708 urb->iso_frame_desc[0].offset = 0;
709 urb->iso_frame_desc[0].length = SIZEOUTBUF;
710 urb->iso_frame_desc[0].status = 0;
711 ret = usb_submit_urb(urb, GFP_ATOMIC);
712 if (ret < 0) {
713 dev_err(&urb->dev->dev,
714 "comedi_: ao urb resubm failed in int-cont. "
715 "ret=%d", ret);
716 if (ret == EL2NSYNC)
717 dev_err(&urb->dev->dev,
718 "buggy USB host controller or bug in "
719 "IRQ handling!\n");
720
721 s->async->events |= COMEDI_CB_EOA;
722 s->async->events |= COMEDI_CB_ERROR;
723 comedi_event(this_usbduxsub->comedidev, s);
724
725 usbdux_ao_stop(this_usbduxsub, 0);
726 }
727 }
728}
729
730static int usbduxsub_start(struct usbduxsub *usbduxsub)
731{
732 int errcode = 0;
733 uint8_t *local_transfer_buffer;
734
735 local_transfer_buffer = kmalloc(1, GFP_KERNEL);
736 if (!local_transfer_buffer)
737 return -ENOMEM;
738
739
740 *local_transfer_buffer = 0;
741 errcode = usb_control_msg(usbduxsub->usbdev,
742
743 usb_sndctrlpipe(usbduxsub->usbdev, 0),
744
745 USBDUXSUB_FIRMWARE,
746
747 VENDOR_DIR_OUT,
748
749 USBDUXSUB_CPUCS,
750
751 0x0000,
752
753 local_transfer_buffer,
754
755 1,
756
757 BULK_TIMEOUT);
758 if (errcode < 0)
759 dev_err(&usbduxsub->interface->dev,
760 "comedi_: control msg failed (start)\n");
761
762 kfree(local_transfer_buffer);
763 return errcode;
764}
765
766static int usbduxsub_stop(struct usbduxsub *usbduxsub)
767{
768 int errcode = 0;
769 uint8_t *local_transfer_buffer;
770
771 local_transfer_buffer = kmalloc(1, GFP_KERNEL);
772 if (!local_transfer_buffer)
773 return -ENOMEM;
774
775
776 *local_transfer_buffer = 1;
777 errcode = usb_control_msg(usbduxsub->usbdev,
778 usb_sndctrlpipe(usbduxsub->usbdev, 0),
779
780 USBDUXSUB_FIRMWARE,
781
782 VENDOR_DIR_OUT,
783
784 USBDUXSUB_CPUCS,
785
786 0x0000, local_transfer_buffer,
787
788 1,
789
790 BULK_TIMEOUT);
791 if (errcode < 0)
792 dev_err(&usbduxsub->interface->dev,
793 "comedi_: control msg failed (stop)\n");
794
795 kfree(local_transfer_buffer);
796 return errcode;
797}
798
799static int usbduxsub_upload(struct usbduxsub *usbduxsub,
800 uint8_t *local_transfer_buffer,
801 unsigned int start_addr, unsigned int len)
802{
803 int errcode;
804
805 errcode = usb_control_msg(usbduxsub->usbdev,
806 usb_sndctrlpipe(usbduxsub->usbdev, 0),
807
808 USBDUXSUB_FIRMWARE,
809
810 VENDOR_DIR_OUT,
811
812 start_addr,
813
814 0x0000,
815
816 local_transfer_buffer,
817
818 len,
819
820 BULK_TIMEOUT);
821 dev_dbg(&usbduxsub->interface->dev, "comedi_: result=%d\n", errcode);
822 if (errcode < 0) {
823 dev_err(&usbduxsub->interface->dev, "comedi_: upload failed\n");
824 return errcode;
825 }
826 return 0;
827}
828
829#define FIRMWARE_MAX_LEN 0x2000
830
831static int firmware_upload(struct usbduxsub *usbduxsub,
832 const u8 *firmware_binary, int size_firmware)
833{
834 int ret;
835 uint8_t *fw_buf;
836
837 if (!firmware_binary)
838 return 0;
839
840 if (size_firmware > FIRMWARE_MAX_LEN) {
841 dev_err(&usbduxsub->interface->dev,
842 "usbdux firmware binary it too large for FX2.\n");
843 return -ENOMEM;
844 }
845
846
847 fw_buf = kmemdup(firmware_binary, size_firmware, GFP_KERNEL);
848 if (!fw_buf) {
849 dev_err(&usbduxsub->interface->dev,
850 "comedi_: mem alloc for firmware failed\n");
851 return -ENOMEM;
852 }
853
854 ret = usbduxsub_stop(usbduxsub);
855 if (ret < 0) {
856 dev_err(&usbduxsub->interface->dev,
857 "comedi_: can not stop firmware\n");
858 kfree(fw_buf);
859 return ret;
860 }
861
862 ret = usbduxsub_upload(usbduxsub, fw_buf, 0, size_firmware);
863 if (ret < 0) {
864 dev_err(&usbduxsub->interface->dev,
865 "comedi_: firmware upload failed\n");
866 kfree(fw_buf);
867 return ret;
868 }
869 ret = usbduxsub_start(usbduxsub);
870 if (ret < 0) {
871 dev_err(&usbduxsub->interface->dev,
872 "comedi_: can not start firmware\n");
873 kfree(fw_buf);
874 return ret;
875 }
876 kfree(fw_buf);
877 return 0;
878}
879
880static int usbduxsub_submit_inurbs(struct usbduxsub *usbduxsub)
881{
882 int i, err_flag;
883
884 if (!usbduxsub)
885 return -EFAULT;
886
887
888 for (i = 0; i < usbduxsub->num_in_buffers; i++) {
889
890 usbduxsub->urb_in[i]->interval = usbduxsub->ai_interval;
891 usbduxsub->urb_in[i]->context = usbduxsub->comedidev;
892 usbduxsub->urb_in[i]->dev = usbduxsub->usbdev;
893 usbduxsub->urb_in[i]->status = 0;
894 usbduxsub->urb_in[i]->transfer_flags = URB_ISO_ASAP;
895 dev_dbg(&usbduxsub->interface->dev,
896 "comedi%d: submitting in-urb[%d]: %p,%p intv=%d\n",
897 usbduxsub->comedidev->minor, i,
898 (usbduxsub->urb_in[i]->context),
899 (usbduxsub->urb_in[i]->dev),
900 (usbduxsub->urb_in[i]->interval));
901 err_flag = usb_submit_urb(usbduxsub->urb_in[i], GFP_ATOMIC);
902 if (err_flag) {
903 dev_err(&usbduxsub->interface->dev,
904 "comedi_: ai: usb_submit_urb(%d) error %d\n",
905 i, err_flag);
906 return err_flag;
907 }
908 }
909 return 0;
910}
911
912static int usbduxsub_submit_outurbs(struct usbduxsub *usbduxsub)
913{
914 int i, err_flag;
915
916 if (!usbduxsub)
917 return -EFAULT;
918
919 for (i = 0; i < usbduxsub->num_out_buffers; i++) {
920 dev_dbg(&usbduxsub->interface->dev,
921 "comedi_: submitting out-urb[%d]\n", i);
922
923 usbduxsub->urb_out[i]->context = usbduxsub->comedidev;
924 usbduxsub->urb_out[i]->dev = usbduxsub->usbdev;
925 usbduxsub->urb_out[i]->status = 0;
926 usbduxsub->urb_out[i]->transfer_flags = URB_ISO_ASAP;
927 err_flag = usb_submit_urb(usbduxsub->urb_out[i], GFP_ATOMIC);
928 if (err_flag) {
929 dev_err(&usbduxsub->interface->dev,
930 "comedi_: ao: usb_submit_urb(%d) error %d\n",
931 i, err_flag);
932 return err_flag;
933 }
934 }
935 return 0;
936}
937
938static int usbdux_ai_cmdtest(struct comedi_device *dev,
939 struct comedi_subdevice *s, struct comedi_cmd *cmd)
940{
941 struct usbduxsub *this_usbduxsub = dev->private;
942 int err = 0, i;
943 unsigned int tmp_timer;
944
945 if (!(this_usbduxsub->probed))
946 return -ENODEV;
947
948
949
950 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
951 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
952 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
953 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
954 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
955
956 if (err)
957 return 1;
958
959
960
961 err |= cfc_check_trigger_is_unique(cmd->start_src);
962 err |= cfc_check_trigger_is_unique(cmd->stop_src);
963
964
965
966 if (err)
967 return 2;
968
969
970
971 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
972
973 if (cmd->scan_begin_src == TRIG_FOLLOW)
974 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
975
976 if (cmd->scan_begin_src == TRIG_TIMER) {
977 if (this_usbduxsub->high_speed) {
978
979
980
981
982
983
984 i = 1;
985
986 while (i < (cmd->chanlist_len))
987 i = i * 2;
988
989 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
990 1000000 / 8 * i);
991
992
993 tmp_timer =
994 ((unsigned int)(cmd->scan_begin_arg / 125000)) *
995 125000;
996 } else {
997
998
999 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
1000 1000000);
1001
1002
1003
1004 tmp_timer = ((unsigned int)(cmd->scan_begin_arg /
1005 1000000)) * 1000000;
1006 }
1007 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg,
1008 tmp_timer);
1009 }
1010
1011 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
1012
1013 if (cmd->stop_src == TRIG_COUNT) {
1014
1015 } else {
1016
1017 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
1018 }
1019
1020 if (err)
1021 return 3;
1022
1023 return 0;
1024}
1025
1026
1027
1028
1029
1030static int8_t create_adc_command(unsigned int chan, int range)
1031{
1032 int8_t p = (range <= 1);
1033 int8_t r = ((range % 2) == 0);
1034 return (chan << 4) | ((p == 1) << 2) | ((r == 1) << 3);
1035}
1036
1037
1038
1039#define SENDADCOMMANDS 0
1040#define SENDDACOMMANDS 1
1041#define SENDDIOCONFIGCOMMAND 2
1042#define SENDDIOBITSCOMMAND 3
1043#define SENDSINGLEAD 4
1044#define READCOUNTERCOMMAND 5
1045#define WRITECOUNTERCOMMAND 6
1046#define SENDPWMON 7
1047#define SENDPWMOFF 8
1048
1049static int send_dux_commands(struct usbduxsub *this_usbduxsub, int cmd_type)
1050{
1051 int result, nsent;
1052
1053 this_usbduxsub->dux_commands[0] = cmd_type;
1054#ifdef NOISY_DUX_DEBUGBUG
1055 printk(KERN_DEBUG "comedi%d: usbdux: dux_commands: ",
1056 this_usbduxsub->comedidev->minor);
1057 for (result = 0; result < SIZEOFDUXBUFFER; result++)
1058 printk(" %02x", this_usbduxsub->dux_commands[result]);
1059 printk("\n");
1060#endif
1061 result = usb_bulk_msg(this_usbduxsub->usbdev,
1062 usb_sndbulkpipe(this_usbduxsub->usbdev,
1063 COMMAND_OUT_EP),
1064 this_usbduxsub->dux_commands, SIZEOFDUXBUFFER,
1065 &nsent, BULK_TIMEOUT);
1066 if (result < 0)
1067 dev_err(&this_usbduxsub->interface->dev, "comedi%d: "
1068 "could not transmit dux_command to the usb-device, "
1069 "err=%d\n", this_usbduxsub->comedidev->minor, result);
1070
1071 return result;
1072}
1073
1074static int receive_dux_commands(struct usbduxsub *this_usbduxsub, int command)
1075{
1076 int result = (-EFAULT);
1077 int nrec;
1078 int i;
1079
1080 for (i = 0; i < RETRIES; i++) {
1081 result = usb_bulk_msg(this_usbduxsub->usbdev,
1082 usb_rcvbulkpipe(this_usbduxsub->usbdev,
1083 COMMAND_IN_EP),
1084 this_usbduxsub->insn_buffer, SIZEINSNBUF,
1085 &nrec, BULK_TIMEOUT);
1086 if (result < 0) {
1087 dev_err(&this_usbduxsub->interface->dev, "comedi%d: "
1088 "insn: USB error %d while receiving DUX command"
1089 "\n", this_usbduxsub->comedidev->minor, result);
1090 return result;
1091 }
1092 if (le16_to_cpu(this_usbduxsub->insn_buffer[0]) == command)
1093 return result;
1094 }
1095
1096
1097 dev_err(&this_usbduxsub->interface->dev, "comedi%d: insn: "
1098 "wrong data returned from firmware: want cmd %d, got cmd %d.\n",
1099 this_usbduxsub->comedidev->minor, command,
1100 le16_to_cpu(this_usbduxsub->insn_buffer[0]));
1101 return -EFAULT;
1102}
1103
1104static int usbdux_ai_inttrig(struct comedi_device *dev,
1105 struct comedi_subdevice *s, unsigned int trignum)
1106{
1107 int ret;
1108 struct usbduxsub *this_usbduxsub = dev->private;
1109 if (!this_usbduxsub)
1110 return -EFAULT;
1111
1112 down(&this_usbduxsub->sem);
1113 if (!(this_usbduxsub->probed)) {
1114 up(&this_usbduxsub->sem);
1115 return -ENODEV;
1116 }
1117 dev_dbg(&this_usbduxsub->interface->dev,
1118 "comedi%d: usbdux_ai_inttrig\n", dev->minor);
1119
1120 if (trignum != 0) {
1121 dev_err(&this_usbduxsub->interface->dev,
1122 "comedi%d: usbdux_ai_inttrig: invalid trignum\n",
1123 dev->minor);
1124 up(&this_usbduxsub->sem);
1125 return -EINVAL;
1126 }
1127 if (!(this_usbduxsub->ai_cmd_running)) {
1128 this_usbduxsub->ai_cmd_running = 1;
1129 ret = usbduxsub_submit_inurbs(this_usbduxsub);
1130 if (ret < 0) {
1131 dev_err(&this_usbduxsub->interface->dev,
1132 "comedi%d: usbdux_ai_inttrig: "
1133 "urbSubmit: err=%d\n", dev->minor, ret);
1134 this_usbduxsub->ai_cmd_running = 0;
1135 up(&this_usbduxsub->sem);
1136 return ret;
1137 }
1138 s->async->inttrig = NULL;
1139 } else {
1140 dev_err(&this_usbduxsub->interface->dev,
1141 "comedi%d: ai_inttrig but acqu is already running\n",
1142 dev->minor);
1143 }
1144 up(&this_usbduxsub->sem);
1145 return 1;
1146}
1147
1148static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1149{
1150 struct comedi_cmd *cmd = &s->async->cmd;
1151 unsigned int chan, range;
1152 int i, ret;
1153 struct usbduxsub *this_usbduxsub = dev->private;
1154 int result;
1155
1156 if (!this_usbduxsub)
1157 return -EFAULT;
1158
1159 dev_dbg(&this_usbduxsub->interface->dev,
1160 "comedi%d: usbdux_ai_cmd\n", dev->minor);
1161
1162
1163 down(&this_usbduxsub->sem);
1164
1165 if (!(this_usbduxsub->probed)) {
1166 up(&this_usbduxsub->sem);
1167 return -ENODEV;
1168 }
1169 if (this_usbduxsub->ai_cmd_running) {
1170 dev_err(&this_usbduxsub->interface->dev, "comedi%d: "
1171 "ai_cmd not possible. Another ai_cmd is running.\n",
1172 dev->minor);
1173 up(&this_usbduxsub->sem);
1174 return -EBUSY;
1175 }
1176
1177 s->async->cur_chan = 0;
1178
1179 this_usbduxsub->dux_commands[1] = cmd->chanlist_len;
1180 for (i = 0; i < cmd->chanlist_len; ++i) {
1181 chan = CR_CHAN(cmd->chanlist[i]);
1182 range = CR_RANGE(cmd->chanlist[i]);
1183 if (i >= NUMCHANNELS) {
1184 dev_err(&this_usbduxsub->interface->dev,
1185 "comedi%d: channel list too long\n",
1186 dev->minor);
1187 break;
1188 }
1189 this_usbduxsub->dux_commands[i + 2] =
1190 create_adc_command(chan, range);
1191 }
1192
1193 dev_dbg(&this_usbduxsub->interface->dev,
1194 "comedi %d: sending commands to the usb device: size=%u\n",
1195 dev->minor, NUMCHANNELS);
1196
1197 result = send_dux_commands(this_usbduxsub, SENDADCOMMANDS);
1198 if (result < 0) {
1199 up(&this_usbduxsub->sem);
1200 return result;
1201 }
1202
1203 if (this_usbduxsub->high_speed) {
1204
1205
1206
1207
1208
1209 this_usbduxsub->ai_interval = 1;
1210
1211 while ((this_usbduxsub->ai_interval) < (cmd->chanlist_len)) {
1212 this_usbduxsub->ai_interval =
1213 (this_usbduxsub->ai_interval) * 2;
1214 }
1215 this_usbduxsub->ai_timer = cmd->scan_begin_arg / (125000 *
1216 (this_usbduxsub->
1217 ai_interval));
1218 } else {
1219
1220 this_usbduxsub->ai_interval = 1;
1221 this_usbduxsub->ai_timer = cmd->scan_begin_arg / 1000000;
1222 }
1223 if (this_usbduxsub->ai_timer < 1) {
1224 dev_err(&this_usbduxsub->interface->dev, "comedi%d: ai_cmd: "
1225 "timer=%d, scan_begin_arg=%d. "
1226 "Not properly tested by cmdtest?\n", dev->minor,
1227 this_usbduxsub->ai_timer, cmd->scan_begin_arg);
1228 up(&this_usbduxsub->sem);
1229 return -EINVAL;
1230 }
1231 this_usbduxsub->ai_counter = this_usbduxsub->ai_timer;
1232
1233 if (cmd->stop_src == TRIG_COUNT) {
1234
1235 this_usbduxsub->ai_sample_count = cmd->stop_arg;
1236 this_usbduxsub->ai_continous = 0;
1237 } else {
1238
1239 this_usbduxsub->ai_continous = 1;
1240 this_usbduxsub->ai_sample_count = 0;
1241 }
1242
1243 if (cmd->start_src == TRIG_NOW) {
1244
1245 this_usbduxsub->ai_cmd_running = 1;
1246 ret = usbduxsub_submit_inurbs(this_usbduxsub);
1247 if (ret < 0) {
1248 this_usbduxsub->ai_cmd_running = 0;
1249
1250 up(&this_usbduxsub->sem);
1251 return ret;
1252 }
1253 s->async->inttrig = NULL;
1254 } else {
1255
1256
1257
1258 s->async->inttrig = usbdux_ai_inttrig;
1259 }
1260 up(&this_usbduxsub->sem);
1261 return 0;
1262}
1263
1264
1265static int usbdux_ai_insn_read(struct comedi_device *dev,
1266 struct comedi_subdevice *s,
1267 struct comedi_insn *insn, unsigned int *data)
1268{
1269 int i;
1270 unsigned int one = 0;
1271 int chan, range;
1272 int err;
1273 struct usbduxsub *this_usbduxsub = dev->private;
1274
1275 if (!this_usbduxsub)
1276 return 0;
1277
1278 dev_dbg(&this_usbduxsub->interface->dev,
1279 "comedi%d: ai_insn_read, insn->n=%d, insn->subdev=%d\n",
1280 dev->minor, insn->n, insn->subdev);
1281
1282 down(&this_usbduxsub->sem);
1283 if (!(this_usbduxsub->probed)) {
1284 up(&this_usbduxsub->sem);
1285 return -ENODEV;
1286 }
1287 if (this_usbduxsub->ai_cmd_running) {
1288 dev_err(&this_usbduxsub->interface->dev,
1289 "comedi%d: ai_insn_read not possible. "
1290 "Async Command is running.\n", dev->minor);
1291 up(&this_usbduxsub->sem);
1292 return 0;
1293 }
1294
1295
1296 chan = CR_CHAN(insn->chanspec);
1297 range = CR_RANGE(insn->chanspec);
1298
1299 this_usbduxsub->dux_commands[1] = create_adc_command(chan, range);
1300
1301
1302 err = send_dux_commands(this_usbduxsub, SENDSINGLEAD);
1303 if (err < 0) {
1304 up(&this_usbduxsub->sem);
1305 return err;
1306 }
1307
1308 for (i = 0; i < insn->n; i++) {
1309 err = receive_dux_commands(this_usbduxsub, SENDSINGLEAD);
1310 if (err < 0) {
1311 up(&this_usbduxsub->sem);
1312 return 0;
1313 }
1314 one = le16_to_cpu(this_usbduxsub->insn_buffer[1]);
1315 if (CR_RANGE(insn->chanspec) <= 1)
1316 one = one ^ 0x800;
1317
1318 data[i] = one;
1319 }
1320 up(&this_usbduxsub->sem);
1321 return i;
1322}
1323
1324
1325
1326
1327static int usbdux_ao_insn_read(struct comedi_device *dev,
1328 struct comedi_subdevice *s,
1329 struct comedi_insn *insn, unsigned int *data)
1330{
1331 int i;
1332 int chan = CR_CHAN(insn->chanspec);
1333 struct usbduxsub *this_usbduxsub = dev->private;
1334
1335 if (!this_usbduxsub)
1336 return -EFAULT;
1337
1338 down(&this_usbduxsub->sem);
1339 if (!(this_usbduxsub->probed)) {
1340 up(&this_usbduxsub->sem);
1341 return -ENODEV;
1342 }
1343 for (i = 0; i < insn->n; i++)
1344 data[i] = this_usbduxsub->out_buffer[chan];
1345
1346 up(&this_usbduxsub->sem);
1347 return i;
1348}
1349
1350static int usbdux_ao_insn_write(struct comedi_device *dev,
1351 struct comedi_subdevice *s,
1352 struct comedi_insn *insn, unsigned int *data)
1353{
1354 int i, err;
1355 int chan = CR_CHAN(insn->chanspec);
1356 struct usbduxsub *this_usbduxsub = dev->private;
1357
1358 if (!this_usbduxsub)
1359 return -EFAULT;
1360
1361 dev_dbg(&this_usbduxsub->interface->dev,
1362 "comedi%d: ao_insn_write\n", dev->minor);
1363
1364 down(&this_usbduxsub->sem);
1365 if (!(this_usbduxsub->probed)) {
1366 up(&this_usbduxsub->sem);
1367 return -ENODEV;
1368 }
1369 if (this_usbduxsub->ao_cmd_running) {
1370 dev_err(&this_usbduxsub->interface->dev,
1371 "comedi%d: ao_insn_write: "
1372 "ERROR: asynchronous ao_cmd is running\n", dev->minor);
1373 up(&this_usbduxsub->sem);
1374 return 0;
1375 }
1376
1377 for (i = 0; i < insn->n; i++) {
1378 dev_dbg(&this_usbduxsub->interface->dev,
1379 "comedi%d: ao_insn_write: data[chan=%d,i=%d]=%d\n",
1380 dev->minor, chan, i, data[i]);
1381
1382
1383 this_usbduxsub->dux_commands[1] = 1;
1384
1385 *((int16_t *) (this_usbduxsub->dux_commands + 2)) =
1386 cpu_to_le16(data[i]);
1387 this_usbduxsub->out_buffer[chan] = data[i];
1388
1389 this_usbduxsub->dux_commands[4] = (chan << 6);
1390 err = send_dux_commands(this_usbduxsub, SENDDACOMMANDS);
1391 if (err < 0) {
1392 up(&this_usbduxsub->sem);
1393 return err;
1394 }
1395 }
1396 up(&this_usbduxsub->sem);
1397
1398 return i;
1399}
1400
1401static int usbdux_ao_inttrig(struct comedi_device *dev,
1402 struct comedi_subdevice *s, unsigned int trignum)
1403{
1404 int ret;
1405 struct usbduxsub *this_usbduxsub = dev->private;
1406
1407 if (!this_usbduxsub)
1408 return -EFAULT;
1409
1410 down(&this_usbduxsub->sem);
1411 if (!(this_usbduxsub->probed)) {
1412 up(&this_usbduxsub->sem);
1413 return -ENODEV;
1414 }
1415 if (trignum != 0) {
1416 dev_err(&this_usbduxsub->interface->dev,
1417 "comedi%d: usbdux_ao_inttrig: invalid trignum\n",
1418 dev->minor);
1419 up(&this_usbduxsub->sem);
1420 return -EINVAL;
1421 }
1422 if (!(this_usbduxsub->ao_cmd_running)) {
1423 this_usbduxsub->ao_cmd_running = 1;
1424 ret = usbduxsub_submit_outurbs(this_usbduxsub);
1425 if (ret < 0) {
1426 dev_err(&this_usbduxsub->interface->dev,
1427 "comedi%d: usbdux_ao_inttrig: submitURB: "
1428 "err=%d\n", dev->minor, ret);
1429 this_usbduxsub->ao_cmd_running = 0;
1430 up(&this_usbduxsub->sem);
1431 return ret;
1432 }
1433 s->async->inttrig = NULL;
1434 } else {
1435 dev_err(&this_usbduxsub->interface->dev,
1436 "comedi%d: ao_inttrig but acqu is already running.\n",
1437 dev->minor);
1438 }
1439 up(&this_usbduxsub->sem);
1440 return 1;
1441}
1442
1443static int usbdux_ao_cmdtest(struct comedi_device *dev,
1444 struct comedi_subdevice *s, struct comedi_cmd *cmd)
1445{
1446 struct usbduxsub *this_usbduxsub = dev->private;
1447 int err = 0;
1448 unsigned int flags;
1449
1450 if (!this_usbduxsub)
1451 return -EFAULT;
1452
1453 if (!(this_usbduxsub->probed))
1454 return -ENODEV;
1455
1456
1457
1458 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
1459
1460 if (0) {
1461
1462 flags = TRIG_FOLLOW;
1463 } else {
1464
1465 flags = TRIG_TIMER;
1466 }
1467 err |= cfc_check_trigger_src(&cmd->scan_begin_src, flags);
1468
1469 if (0) {
1470
1471
1472
1473
1474 flags = TRIG_TIMER;
1475 } else {
1476
1477
1478
1479
1480 flags = TRIG_NOW;
1481 }
1482 err |= cfc_check_trigger_src(&cmd->convert_src, flags);
1483
1484 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
1485 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
1486
1487 if (err)
1488 return 1;
1489
1490
1491
1492 err |= cfc_check_trigger_is_unique(cmd->start_src);
1493 err |= cfc_check_trigger_is_unique(cmd->stop_src);
1494
1495
1496
1497 if (err)
1498 return 2;
1499
1500
1501
1502 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
1503
1504 if (cmd->scan_begin_src == TRIG_FOLLOW)
1505 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
1506
1507 if (cmd->scan_begin_src == TRIG_TIMER)
1508 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
1509 1000000);
1510
1511
1512 if (cmd->convert_src == TRIG_TIMER)
1513 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 125000);
1514
1515 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
1516
1517 if (cmd->stop_src == TRIG_COUNT) {
1518
1519 } else {
1520
1521 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
1522 }
1523
1524 if (err)
1525 return 3;
1526
1527 return 0;
1528}
1529
1530static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1531{
1532 struct comedi_cmd *cmd = &s->async->cmd;
1533 unsigned int chan, gain;
1534 int i, ret;
1535 struct usbduxsub *this_usbduxsub = dev->private;
1536
1537 if (!this_usbduxsub)
1538 return -EFAULT;
1539
1540 down(&this_usbduxsub->sem);
1541 if (!(this_usbduxsub->probed)) {
1542 up(&this_usbduxsub->sem);
1543 return -ENODEV;
1544 }
1545 dev_dbg(&this_usbduxsub->interface->dev,
1546 "comedi%d: %s\n", dev->minor, __func__);
1547
1548
1549 s->async->cur_chan = 0;
1550 for (i = 0; i < cmd->chanlist_len; ++i) {
1551 chan = CR_CHAN(cmd->chanlist[i]);
1552 gain = CR_RANGE(cmd->chanlist[i]);
1553 if (i >= NUMOUTCHANNELS) {
1554 dev_err(&this_usbduxsub->interface->dev,
1555 "comedi%d: %s: channel list too long\n",
1556 dev->minor, __func__);
1557 break;
1558 }
1559 this_usbduxsub->dac_commands[i] = (chan << 6);
1560 dev_dbg(&this_usbduxsub->interface->dev,
1561 "comedi%d: dac command for ch %d is %x\n",
1562 dev->minor, i, this_usbduxsub->dac_commands[i]);
1563 }
1564
1565
1566
1567 if (0) {
1568
1569
1570 this_usbduxsub->ao_timer = cmd->convert_arg / 125000;
1571 } else {
1572
1573
1574 this_usbduxsub->ao_timer = cmd->scan_begin_arg / 1000000;
1575 dev_dbg(&this_usbduxsub->interface->dev,
1576 "comedi%d: scan_begin_src=%d, scan_begin_arg=%d, "
1577 "convert_src=%d, convert_arg=%d\n", dev->minor,
1578 cmd->scan_begin_src, cmd->scan_begin_arg,
1579 cmd->convert_src, cmd->convert_arg);
1580 dev_dbg(&this_usbduxsub->interface->dev,
1581 "comedi%d: ao_timer=%d (ms)\n",
1582 dev->minor, this_usbduxsub->ao_timer);
1583 if (this_usbduxsub->ao_timer < 1) {
1584 dev_err(&this_usbduxsub->interface->dev,
1585 "comedi%d: usbdux: ao_timer=%d, "
1586 "scan_begin_arg=%d. "
1587 "Not properly tested by cmdtest?\n",
1588 dev->minor, this_usbduxsub->ao_timer,
1589 cmd->scan_begin_arg);
1590 up(&this_usbduxsub->sem);
1591 return -EINVAL;
1592 }
1593 }
1594 this_usbduxsub->ao_counter = this_usbduxsub->ao_timer;
1595
1596 if (cmd->stop_src == TRIG_COUNT) {
1597
1598
1599
1600 if (0) {
1601 this_usbduxsub->ao_sample_count =
1602 (cmd->stop_arg) * (cmd->scan_end_arg);
1603 } else {
1604
1605
1606
1607 this_usbduxsub->ao_sample_count = cmd->stop_arg;
1608 }
1609 this_usbduxsub->ao_continous = 0;
1610 } else {
1611
1612 this_usbduxsub->ao_continous = 1;
1613 this_usbduxsub->ao_sample_count = 0;
1614 }
1615
1616 if (cmd->start_src == TRIG_NOW) {
1617
1618 this_usbduxsub->ao_cmd_running = 1;
1619 ret = usbduxsub_submit_outurbs(this_usbduxsub);
1620 if (ret < 0) {
1621 this_usbduxsub->ao_cmd_running = 0;
1622
1623 up(&this_usbduxsub->sem);
1624 return ret;
1625 }
1626 s->async->inttrig = NULL;
1627 } else {
1628
1629
1630
1631 s->async->inttrig = usbdux_ao_inttrig;
1632 }
1633
1634 up(&this_usbduxsub->sem);
1635 return 0;
1636}
1637
1638static int usbdux_dio_insn_config(struct comedi_device *dev,
1639 struct comedi_subdevice *s,
1640 struct comedi_insn *insn, unsigned int *data)
1641{
1642 int chan = CR_CHAN(insn->chanspec);
1643
1644
1645
1646
1647
1648
1649 switch (data[0]) {
1650 case INSN_CONFIG_DIO_OUTPUT:
1651 s->io_bits |= 1 << chan;
1652 break;
1653 case INSN_CONFIG_DIO_INPUT:
1654 s->io_bits &= ~(1 << chan);
1655 break;
1656 case INSN_CONFIG_DIO_QUERY:
1657 data[1] =
1658 (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
1659 break;
1660 default:
1661 return -EINVAL;
1662 break;
1663 }
1664
1665
1666 return insn->n;
1667}
1668
1669static int usbdux_dio_insn_bits(struct comedi_device *dev,
1670 struct comedi_subdevice *s,
1671 struct comedi_insn *insn, unsigned int *data)
1672{
1673
1674 struct usbduxsub *this_usbduxsub = dev->private;
1675 int err;
1676
1677 if (!this_usbduxsub)
1678 return -EFAULT;
1679
1680 down(&this_usbduxsub->sem);
1681
1682 if (!(this_usbduxsub->probed)) {
1683 up(&this_usbduxsub->sem);
1684 return -ENODEV;
1685 }
1686
1687
1688
1689 s->state &= ~data[0];
1690 s->state |= data[0] & data[1];
1691 this_usbduxsub->dux_commands[1] = s->io_bits;
1692 this_usbduxsub->dux_commands[2] = s->state;
1693
1694
1695
1696 err = send_dux_commands(this_usbduxsub, SENDDIOBITSCOMMAND);
1697 if (err < 0) {
1698 up(&this_usbduxsub->sem);
1699 return err;
1700 }
1701 err = receive_dux_commands(this_usbduxsub, SENDDIOBITSCOMMAND);
1702 if (err < 0) {
1703 up(&this_usbduxsub->sem);
1704 return err;
1705 }
1706
1707 data[1] = le16_to_cpu(this_usbduxsub->insn_buffer[1]);
1708 up(&this_usbduxsub->sem);
1709 return insn->n;
1710}
1711
1712
1713static int usbdux_counter_read(struct comedi_device *dev,
1714 struct comedi_subdevice *s,
1715 struct comedi_insn *insn, unsigned int *data)
1716{
1717 struct usbduxsub *this_usbduxsub = dev->private;
1718 int chan = insn->chanspec;
1719 int err;
1720
1721 if (!this_usbduxsub)
1722 return -EFAULT;
1723
1724 down(&this_usbduxsub->sem);
1725
1726 if (!(this_usbduxsub->probed)) {
1727 up(&this_usbduxsub->sem);
1728 return -ENODEV;
1729 }
1730
1731 err = send_dux_commands(this_usbduxsub, READCOUNTERCOMMAND);
1732 if (err < 0) {
1733 up(&this_usbduxsub->sem);
1734 return err;
1735 }
1736
1737 err = receive_dux_commands(this_usbduxsub, READCOUNTERCOMMAND);
1738 if (err < 0) {
1739 up(&this_usbduxsub->sem);
1740 return err;
1741 }
1742
1743 data[0] = le16_to_cpu(this_usbduxsub->insn_buffer[chan + 1]);
1744 up(&this_usbduxsub->sem);
1745 return 1;
1746}
1747
1748static int usbdux_counter_write(struct comedi_device *dev,
1749 struct comedi_subdevice *s,
1750 struct comedi_insn *insn, unsigned int *data)
1751{
1752 struct usbduxsub *this_usbduxsub = dev->private;
1753 int err;
1754
1755 if (!this_usbduxsub)
1756 return -EFAULT;
1757
1758 down(&this_usbduxsub->sem);
1759
1760 if (!(this_usbduxsub->probed)) {
1761 up(&this_usbduxsub->sem);
1762 return -ENODEV;
1763 }
1764
1765 this_usbduxsub->dux_commands[1] = insn->chanspec;
1766 *((int16_t *) (this_usbduxsub->dux_commands + 2)) = cpu_to_le16(*data);
1767
1768 err = send_dux_commands(this_usbduxsub, WRITECOUNTERCOMMAND);
1769 if (err < 0) {
1770 up(&this_usbduxsub->sem);
1771 return err;
1772 }
1773
1774 up(&this_usbduxsub->sem);
1775
1776 return 1;
1777}
1778
1779static int usbdux_counter_config(struct comedi_device *dev,
1780 struct comedi_subdevice *s,
1781 struct comedi_insn *insn, unsigned int *data)
1782{
1783
1784 return 2;
1785}
1786
1787
1788
1789
1790static int usbduxsub_unlink_pwm_urbs(struct usbduxsub *usbduxsub_tmp)
1791{
1792 int err = 0;
1793
1794 if (usbduxsub_tmp && usbduxsub_tmp->urb_pwm) {
1795 if (usbduxsub_tmp->urb_pwm)
1796 usb_kill_urb(usbduxsub_tmp->urb_pwm);
1797 dev_dbg(&usbduxsub_tmp->interface->dev,
1798 "comedi: unlinked PwmURB: res=%d\n", err);
1799 }
1800 return err;
1801}
1802
1803
1804
1805
1806static int usbdux_pwm_stop(struct usbduxsub *this_usbduxsub, int do_unlink)
1807{
1808 int ret = 0;
1809
1810 if (!this_usbduxsub)
1811 return -EFAULT;
1812
1813 dev_dbg(&this_usbduxsub->interface->dev, "comedi: %s\n", __func__);
1814 if (do_unlink)
1815 ret = usbduxsub_unlink_pwm_urbs(this_usbduxsub);
1816
1817 this_usbduxsub->pwm_cmd_running = 0;
1818
1819 return ret;
1820}
1821
1822
1823static int usbdux_pwm_cancel(struct comedi_device *dev,
1824 struct comedi_subdevice *s)
1825{
1826 struct usbduxsub *this_usbduxsub = dev->private;
1827 int res = 0;
1828
1829
1830 res = usbdux_pwm_stop(this_usbduxsub, this_usbduxsub->pwm_cmd_running);
1831
1832 dev_dbg(&this_usbduxsub->interface->dev,
1833 "comedi %d: sending pwm off command to the usb device.\n",
1834 dev->minor);
1835
1836 return send_dux_commands(this_usbduxsub, SENDPWMOFF);
1837}
1838
1839static void usbduxsub_pwm_irq(struct urb *urb)
1840{
1841 int ret;
1842 struct usbduxsub *this_usbduxsub;
1843 struct comedi_device *this_comedidev;
1844 struct comedi_subdevice *s;
1845
1846
1847
1848
1849 this_comedidev = urb->context;
1850
1851 this_usbduxsub = this_comedidev->private;
1852
1853 s = &this_comedidev->subdevices[SUBDEV_DA];
1854
1855 switch (urb->status) {
1856 case 0:
1857
1858 break;
1859
1860 case -ECONNRESET:
1861 case -ENOENT:
1862 case -ESHUTDOWN:
1863 case -ECONNABORTED:
1864
1865
1866
1867
1868 if (this_usbduxsub->pwm_cmd_running)
1869 usbdux_pwm_stop(this_usbduxsub, 0);
1870
1871 return;
1872
1873 default:
1874
1875 if (this_usbduxsub->pwm_cmd_running) {
1876 dev_err(&this_usbduxsub->interface->dev,
1877 "comedi_: Non-zero urb status received in "
1878 "pwm intr context: %d\n", urb->status);
1879 usbdux_pwm_stop(this_usbduxsub, 0);
1880 }
1881 return;
1882 }
1883
1884
1885 if (!(this_usbduxsub->pwm_cmd_running))
1886 return;
1887
1888 urb->transfer_buffer_length = this_usbduxsub->size_pwm_buf;
1889 urb->dev = this_usbduxsub->usbdev;
1890 urb->status = 0;
1891 if (this_usbduxsub->pwm_cmd_running) {
1892 ret = usb_submit_urb(urb, GFP_ATOMIC);
1893 if (ret < 0) {
1894 dev_err(&this_usbduxsub->interface->dev,
1895 "comedi_: pwm urb resubm failed in int-cont. "
1896 "ret=%d", ret);
1897 if (ret == EL2NSYNC)
1898 dev_err(&this_usbduxsub->interface->dev,
1899 "buggy USB host controller or bug in "
1900 "IRQ handling!\n");
1901
1902
1903 usbdux_pwm_stop(this_usbduxsub, 0);
1904 }
1905 }
1906}
1907
1908static int usbduxsub_submit_pwm_urbs(struct usbduxsub *usbduxsub)
1909{
1910 int err_flag;
1911
1912 if (!usbduxsub)
1913 return -EFAULT;
1914
1915 dev_dbg(&usbduxsub->interface->dev, "comedi_: submitting pwm-urb\n");
1916
1917
1918 usb_fill_bulk_urb(usbduxsub->urb_pwm,
1919 usbduxsub->usbdev,
1920 usb_sndbulkpipe(usbduxsub->usbdev, PWM_EP),
1921 usbduxsub->urb_pwm->transfer_buffer,
1922 usbduxsub->size_pwm_buf, usbduxsub_pwm_irq,
1923 usbduxsub->comedidev);
1924
1925 err_flag = usb_submit_urb(usbduxsub->urb_pwm, GFP_ATOMIC);
1926 if (err_flag) {
1927 dev_err(&usbduxsub->interface->dev,
1928 "comedi_: usbdux: pwm: usb_submit_urb error %d\n",
1929 err_flag);
1930 return err_flag;
1931 }
1932 return 0;
1933}
1934
1935static int usbdux_pwm_period(struct comedi_device *dev,
1936 struct comedi_subdevice *s, unsigned int period)
1937{
1938 struct usbduxsub *this_usbduxsub = dev->private;
1939 int fx2delay = 255;
1940
1941 if (period < MIN_PWM_PERIOD) {
1942 dev_err(&this_usbduxsub->interface->dev,
1943 "comedi%d: illegal period setting for pwm.\n",
1944 dev->minor);
1945 return -EAGAIN;
1946 } else {
1947 fx2delay = period / ((int)(6 * 512 * (1.0 / 0.033))) - 6;
1948 if (fx2delay > 255) {
1949 dev_err(&this_usbduxsub->interface->dev,
1950 "comedi%d: period %d for pwm is too low.\n",
1951 dev->minor, period);
1952 return -EAGAIN;
1953 }
1954 }
1955 this_usbduxsub->pwn_delay = fx2delay;
1956 this_usbduxsub->pwm_period = period;
1957 dev_dbg(&this_usbduxsub->interface->dev, "%s: frequ=%d, period=%d\n",
1958 __func__, period, fx2delay);
1959 return 0;
1960}
1961
1962
1963static int usbdux_pwm_start(struct comedi_device *dev,
1964 struct comedi_subdevice *s)
1965{
1966 int ret, i;
1967 struct usbduxsub *this_usbduxsub = dev->private;
1968
1969 dev_dbg(&this_usbduxsub->interface->dev, "comedi%d: %s\n",
1970 dev->minor, __func__);
1971
1972 if (this_usbduxsub->pwm_cmd_running) {
1973
1974 return 0;
1975 }
1976
1977 this_usbduxsub->dux_commands[1] = ((int8_t) this_usbduxsub->pwn_delay);
1978 ret = send_dux_commands(this_usbduxsub, SENDPWMON);
1979 if (ret < 0)
1980 return ret;
1981
1982
1983 for (i = 0; i < this_usbduxsub->size_pwm_buf; i++)
1984 ((char *)(this_usbduxsub->urb_pwm->transfer_buffer))[i] = 0;
1985
1986 this_usbduxsub->pwm_cmd_running = 1;
1987 ret = usbduxsub_submit_pwm_urbs(this_usbduxsub);
1988 if (ret < 0) {
1989 this_usbduxsub->pwm_cmd_running = 0;
1990 return ret;
1991 }
1992 return 0;
1993}
1994
1995
1996static int usbdux_pwm_pattern(struct comedi_device *dev,
1997 struct comedi_subdevice *s, int channel,
1998 unsigned int value, unsigned int sign)
1999{
2000 struct usbduxsub *this_usbduxsub = dev->private;
2001 int i, szbuf;
2002 char *p_buf;
2003 char pwm_mask;
2004 char sgn_mask;
2005 char c;
2006
2007 if (!this_usbduxsub)
2008 return -EFAULT;
2009
2010
2011 pwm_mask = (1 << channel);
2012
2013 sgn_mask = (16 << channel);
2014
2015
2016 szbuf = this_usbduxsub->size_pwm_buf;
2017 p_buf = (char *)(this_usbduxsub->urb_pwm->transfer_buffer);
2018 for (i = 0; i < szbuf; i++) {
2019 c = *p_buf;
2020
2021 c = c & (~pwm_mask);
2022
2023 if (i < value)
2024 c = c | pwm_mask;
2025
2026 if (!sign) {
2027
2028 c = c & (~sgn_mask);
2029 } else {
2030
2031 c = c | sgn_mask;
2032 }
2033 *(p_buf++) = c;
2034 }
2035 return 1;
2036}
2037
2038static int usbdux_pwm_write(struct comedi_device *dev,
2039 struct comedi_subdevice *s,
2040 struct comedi_insn *insn, unsigned int *data)
2041{
2042 struct usbduxsub *this_usbduxsub = dev->private;
2043
2044 if (!this_usbduxsub)
2045 return -EFAULT;
2046
2047 if ((insn->n) != 1) {
2048
2049
2050
2051
2052 return -EINVAL;
2053 }
2054
2055
2056
2057
2058
2059
2060 return usbdux_pwm_pattern(dev, s, CR_CHAN(insn->chanspec), data[0], 0);
2061}
2062
2063static int usbdux_pwm_read(struct comedi_device *x1,
2064 struct comedi_subdevice *x2, struct comedi_insn *x3,
2065 unsigned int *x4)
2066{
2067
2068 return -EINVAL;
2069};
2070
2071
2072static int usbdux_pwm_config(struct comedi_device *dev,
2073 struct comedi_subdevice *s,
2074 struct comedi_insn *insn, unsigned int *data)
2075{
2076 struct usbduxsub *this_usbduxsub = dev->private;
2077 switch (data[0]) {
2078 case INSN_CONFIG_ARM:
2079
2080 dev_dbg(&this_usbduxsub->interface->dev,
2081 "comedi%d: %s: pwm on\n", dev->minor, __func__);
2082
2083
2084
2085
2086 if (data[1] != 0)
2087 return -EINVAL;
2088 return usbdux_pwm_start(dev, s);
2089 case INSN_CONFIG_DISARM:
2090 dev_dbg(&this_usbduxsub->interface->dev,
2091 "comedi%d: %s: pwm off\n", dev->minor, __func__);
2092 return usbdux_pwm_cancel(dev, s);
2093 case INSN_CONFIG_GET_PWM_STATUS:
2094
2095
2096
2097
2098 data[1] = this_usbduxsub->pwm_cmd_running;
2099 return 0;
2100 case INSN_CONFIG_PWM_SET_PERIOD:
2101 dev_dbg(&this_usbduxsub->interface->dev,
2102 "comedi%d: %s: setting period\n", dev->minor, __func__);
2103 return usbdux_pwm_period(dev, s, data[1]);
2104 case INSN_CONFIG_PWM_GET_PERIOD:
2105 data[1] = this_usbduxsub->pwm_period;
2106 return 0;
2107 case INSN_CONFIG_PWM_SET_H_BRIDGE:
2108
2109
2110 return usbdux_pwm_pattern(dev, s,
2111
2112 CR_CHAN(insn->chanspec),
2113
2114 data[1],
2115
2116 (data[2] != 0));
2117 case INSN_CONFIG_PWM_GET_H_BRIDGE:
2118
2119 return -EINVAL;
2120 }
2121 return -EINVAL;
2122}
2123
2124
2125
2126
2127static void tidy_up(struct usbduxsub *usbduxsub_tmp)
2128{
2129 int i;
2130
2131 if (!usbduxsub_tmp)
2132 return;
2133 dev_dbg(&usbduxsub_tmp->interface->dev, "comedi_: tiding up\n");
2134
2135
2136 if (usbduxsub_tmp->interface)
2137 usb_set_intfdata(usbduxsub_tmp->interface, NULL);
2138
2139 usbduxsub_tmp->probed = 0;
2140
2141 if (usbduxsub_tmp->urb_in) {
2142 if (usbduxsub_tmp->ai_cmd_running) {
2143 usbduxsub_tmp->ai_cmd_running = 0;
2144 usbduxsub_unlink_inurbs(usbduxsub_tmp);
2145 }
2146 for (i = 0; i < usbduxsub_tmp->num_in_buffers; i++) {
2147 kfree(usbduxsub_tmp->urb_in[i]->transfer_buffer);
2148 usbduxsub_tmp->urb_in[i]->transfer_buffer = NULL;
2149 usb_kill_urb(usbduxsub_tmp->urb_in[i]);
2150 usb_free_urb(usbduxsub_tmp->urb_in[i]);
2151 usbduxsub_tmp->urb_in[i] = NULL;
2152 }
2153 kfree(usbduxsub_tmp->urb_in);
2154 usbduxsub_tmp->urb_in = NULL;
2155 }
2156 if (usbduxsub_tmp->urb_out) {
2157 if (usbduxsub_tmp->ao_cmd_running) {
2158 usbduxsub_tmp->ao_cmd_running = 0;
2159 usbduxsub_unlink_outurbs(usbduxsub_tmp);
2160 }
2161 for (i = 0; i < usbduxsub_tmp->num_out_buffers; i++) {
2162 kfree(usbduxsub_tmp->urb_out[i]->transfer_buffer);
2163 usbduxsub_tmp->urb_out[i]->transfer_buffer = NULL;
2164 if (usbduxsub_tmp->urb_out[i]) {
2165 usb_kill_urb(usbduxsub_tmp->urb_out[i]);
2166 usb_free_urb(usbduxsub_tmp->urb_out[i]);
2167 usbduxsub_tmp->urb_out[i] = NULL;
2168 }
2169 }
2170 kfree(usbduxsub_tmp->urb_out);
2171 usbduxsub_tmp->urb_out = NULL;
2172 }
2173 if (usbduxsub_tmp->urb_pwm) {
2174 if (usbduxsub_tmp->pwm_cmd_running) {
2175 usbduxsub_tmp->pwm_cmd_running = 0;
2176 usbduxsub_unlink_pwm_urbs(usbduxsub_tmp);
2177 }
2178 kfree(usbduxsub_tmp->urb_pwm->transfer_buffer);
2179 usbduxsub_tmp->urb_pwm->transfer_buffer = NULL;
2180 usb_kill_urb(usbduxsub_tmp->urb_pwm);
2181 usb_free_urb(usbduxsub_tmp->urb_pwm);
2182 usbduxsub_tmp->urb_pwm = NULL;
2183 }
2184 kfree(usbduxsub_tmp->in_buffer);
2185 usbduxsub_tmp->in_buffer = NULL;
2186 kfree(usbduxsub_tmp->insn_buffer);
2187 usbduxsub_tmp->insn_buffer = NULL;
2188 kfree(usbduxsub_tmp->out_buffer);
2189 usbduxsub_tmp->out_buffer = NULL;
2190 kfree(usbduxsub_tmp->dac_commands);
2191 usbduxsub_tmp->dac_commands = NULL;
2192 kfree(usbduxsub_tmp->dux_commands);
2193 usbduxsub_tmp->dux_commands = NULL;
2194 usbduxsub_tmp->ai_cmd_running = 0;
2195 usbduxsub_tmp->ao_cmd_running = 0;
2196 usbduxsub_tmp->pwm_cmd_running = 0;
2197}
2198
2199static int usbdux_attach_common(struct comedi_device *dev,
2200 struct usbduxsub *udev)
2201{
2202 int ret;
2203 struct comedi_subdevice *s = NULL;
2204 int n_subdevs;
2205
2206 down(&udev->sem);
2207
2208 udev->comedidev = dev;
2209
2210
2211 if (udev->high_speed) {
2212
2213 n_subdevs = 5;
2214 } else {
2215
2216 n_subdevs = 4;
2217 }
2218
2219 ret = comedi_alloc_subdevices(dev, n_subdevs);
2220 if (ret) {
2221 up(&udev->sem);
2222 return ret;
2223 }
2224
2225
2226 dev->private = udev;
2227
2228
2229 s = &dev->subdevices[SUBDEV_AD];
2230
2231
2232
2233 dev->read_subdev = s;
2234
2235
2236 s->private = NULL;
2237
2238 s->type = COMEDI_SUBD_AI;
2239
2240 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
2241
2242 s->n_chan = 8;
2243
2244 s->len_chanlist = 8;
2245
2246 s->insn_read = usbdux_ai_insn_read;
2247 s->do_cmdtest = usbdux_ai_cmdtest;
2248 s->do_cmd = usbdux_ai_cmd;
2249 s->cancel = usbdux_ai_cancel;
2250
2251 s->maxdata = 0xfff;
2252
2253 s->range_table = (&range_usbdux_ai_range);
2254
2255
2256 s = &dev->subdevices[SUBDEV_DA];
2257
2258 s->type = COMEDI_SUBD_AO;
2259
2260 dev->write_subdev = s;
2261
2262
2263 s->private = NULL;
2264
2265 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
2266
2267 s->n_chan = 4;
2268
2269 s->len_chanlist = 4;
2270
2271 s->maxdata = 0x0fff;
2272
2273 s->range_table = (&range_usbdux_ao_range);
2274
2275 s->do_cmdtest = usbdux_ao_cmdtest;
2276 s->do_cmd = usbdux_ao_cmd;
2277 s->cancel = usbdux_ao_cancel;
2278 s->insn_read = usbdux_ao_insn_read;
2279 s->insn_write = usbdux_ao_insn_write;
2280
2281
2282 s = &dev->subdevices[SUBDEV_DIO];
2283 s->type = COMEDI_SUBD_DIO;
2284 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
2285 s->n_chan = 8;
2286 s->maxdata = 1;
2287 s->range_table = (&range_digital);
2288 s->insn_bits = usbdux_dio_insn_bits;
2289 s->insn_config = usbdux_dio_insn_config;
2290
2291 s->private = NULL;
2292
2293
2294 s = &dev->subdevices[SUBDEV_COUNTER];
2295 s->type = COMEDI_SUBD_COUNTER;
2296 s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
2297 s->n_chan = 4;
2298 s->maxdata = 0xFFFF;
2299 s->insn_read = usbdux_counter_read;
2300 s->insn_write = usbdux_counter_write;
2301 s->insn_config = usbdux_counter_config;
2302
2303 if (udev->high_speed) {
2304
2305 s = &dev->subdevices[SUBDEV_PWM];
2306 s->type = COMEDI_SUBD_PWM;
2307 s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE;
2308 s->n_chan = 8;
2309
2310 s->maxdata = udev->size_pwm_buf;
2311 s->insn_write = usbdux_pwm_write;
2312 s->insn_read = usbdux_pwm_read;
2313 s->insn_config = usbdux_pwm_config;
2314 usbdux_pwm_period(dev, s, PWM_DEFAULT_PERIOD);
2315 }
2316
2317 udev->attached = 1;
2318
2319 up(&udev->sem);
2320
2321 dev_info(&udev->interface->dev, "comedi%d: attached to usbdux.\n",
2322 dev->minor);
2323
2324 return 0;
2325}
2326
2327static int usbdux_auto_attach(struct comedi_device *dev,
2328 unsigned long context_unused)
2329{
2330 struct usb_interface *uinterf = comedi_to_usb_interface(dev);
2331 int ret;
2332 struct usbduxsub *this_usbduxsub;
2333
2334 dev->private = NULL;
2335
2336 down(&start_stop_sem);
2337 this_usbduxsub = usb_get_intfdata(uinterf);
2338 if (!this_usbduxsub || !this_usbduxsub->probed) {
2339 dev_err(dev->class_dev,
2340 "usbdux: error: auto_attach failed, not connected\n");
2341 ret = -ENODEV;
2342 } else if (this_usbduxsub->attached) {
2343 dev_err(dev->class_dev,
2344 "error: auto_attach failed, already attached\n");
2345 ret = -ENODEV;
2346 } else
2347 ret = usbdux_attach_common(dev, this_usbduxsub);
2348 up(&start_stop_sem);
2349 return ret;
2350}
2351
2352static void usbdux_detach(struct comedi_device *dev)
2353{
2354 struct usbduxsub *usb = dev->private;
2355
2356 if (usb) {
2357 down(&usb->sem);
2358 dev->private = NULL;
2359 usb->attached = 0;
2360 usb->comedidev = NULL;
2361 up(&usb->sem);
2362 }
2363}
2364
2365static struct comedi_driver usbdux_driver = {
2366 .driver_name = "usbdux",
2367 .module = THIS_MODULE,
2368 .auto_attach = usbdux_auto_attach,
2369 .detach = usbdux_detach,
2370};
2371
2372static void usbdux_firmware_request_complete_handler(const struct firmware *fw,
2373 void *context)
2374{
2375 struct usbduxsub *usbduxsub_tmp = context;
2376 struct usb_interface *uinterf = usbduxsub_tmp->interface;
2377 int ret;
2378
2379 if (fw == NULL) {
2380 dev_err(&uinterf->dev,
2381 "Firmware complete handler without firmware!\n");
2382 return;
2383 }
2384
2385
2386
2387
2388
2389 ret = firmware_upload(usbduxsub_tmp, fw->data, fw->size);
2390
2391 if (ret) {
2392 dev_err(&uinterf->dev,
2393 "Could not upload firmware (err=%d)\n", ret);
2394 goto out;
2395 }
2396 comedi_usb_auto_config(uinterf, &usbdux_driver, 0);
2397 out:
2398 release_firmware(fw);
2399}
2400
2401static int usbdux_usb_probe(struct usb_interface *uinterf,
2402 const struct usb_device_id *id)
2403{
2404 struct usb_device *udev = interface_to_usbdev(uinterf);
2405 struct device *dev = &uinterf->dev;
2406 int i;
2407 int index;
2408 int ret;
2409
2410 dev_dbg(dev, "comedi_: usbdux_: "
2411 "finding a free structure for the usb-device\n");
2412
2413 down(&start_stop_sem);
2414
2415 index = -1;
2416 for (i = 0; i < NUMUSBDUX; i++) {
2417 if (!(usbduxsub[i].probed)) {
2418 index = i;
2419 break;
2420 }
2421 }
2422
2423
2424 if (index == -1) {
2425 dev_err(dev, "Too many usbdux-devices connected.\n");
2426 up(&start_stop_sem);
2427 return -EMFILE;
2428 }
2429 dev_dbg(dev, "comedi_: usbdux: "
2430 "usbduxsub[%d] is ready to connect to comedi.\n", index);
2431
2432 sema_init(&(usbduxsub[index].sem), 1);
2433
2434 usbduxsub[index].usbdev = udev;
2435
2436
2437 usbduxsub[index].interface = uinterf;
2438
2439 usbduxsub[index].ifnum = uinterf->altsetting->desc.bInterfaceNumber;
2440
2441
2442 usb_set_intfdata(uinterf, &(usbduxsub[index]));
2443
2444 dev_dbg(dev, "comedi_: usbdux: ifnum=%d\n", usbduxsub[index].ifnum);
2445
2446
2447 usbduxsub[index].high_speed =
2448 (usbduxsub[index].usbdev->speed == USB_SPEED_HIGH);
2449
2450
2451 usbduxsub[index].dac_commands = kzalloc(NUMOUTCHANNELS, GFP_KERNEL);
2452 if (!usbduxsub[index].dac_commands) {
2453 tidy_up(&(usbduxsub[index]));
2454 up(&start_stop_sem);
2455 return -ENOMEM;
2456 }
2457
2458 usbduxsub[index].dux_commands = kzalloc(SIZEOFDUXBUFFER, GFP_KERNEL);
2459 if (!usbduxsub[index].dux_commands) {
2460 tidy_up(&(usbduxsub[index]));
2461 up(&start_stop_sem);
2462 return -ENOMEM;
2463 }
2464
2465 usbduxsub[index].in_buffer = kzalloc(SIZEINBUF, GFP_KERNEL);
2466 if (!(usbduxsub[index].in_buffer)) {
2467 tidy_up(&(usbduxsub[index]));
2468 up(&start_stop_sem);
2469 return -ENOMEM;
2470 }
2471
2472 usbduxsub[index].insn_buffer = kzalloc(SIZEINSNBUF, GFP_KERNEL);
2473 if (!(usbduxsub[index].insn_buffer)) {
2474 tidy_up(&(usbduxsub[index]));
2475 up(&start_stop_sem);
2476 return -ENOMEM;
2477 }
2478
2479 usbduxsub[index].out_buffer = kzalloc(SIZEOUTBUF, GFP_KERNEL);
2480 if (!(usbduxsub[index].out_buffer)) {
2481 tidy_up(&(usbduxsub[index]));
2482 up(&start_stop_sem);
2483 return -ENOMEM;
2484 }
2485
2486 i = usb_set_interface(usbduxsub[index].usbdev,
2487 usbduxsub[index].ifnum, 3);
2488 if (i < 0) {
2489 dev_err(dev, "comedi_: usbdux%d: "
2490 "could not set alternate setting 3 in high speed.\n",
2491 index);
2492 tidy_up(&(usbduxsub[index]));
2493 up(&start_stop_sem);
2494 return -ENODEV;
2495 }
2496 if (usbduxsub[index].high_speed)
2497 usbduxsub[index].num_in_buffers = NUMOFINBUFFERSHIGH;
2498 else
2499 usbduxsub[index].num_in_buffers = NUMOFINBUFFERSFULL;
2500
2501 usbduxsub[index].urb_in =
2502 kcalloc(usbduxsub[index].num_in_buffers, sizeof(struct urb *),
2503 GFP_KERNEL);
2504 if (!(usbduxsub[index].urb_in)) {
2505 tidy_up(&(usbduxsub[index]));
2506 up(&start_stop_sem);
2507 return -ENOMEM;
2508 }
2509 for (i = 0; i < usbduxsub[index].num_in_buffers; i++) {
2510
2511 usbduxsub[index].urb_in[i] = usb_alloc_urb(1, GFP_KERNEL);
2512 if (usbduxsub[index].urb_in[i] == NULL) {
2513 dev_err(dev, "comedi_: usbdux%d: "
2514 "Could not alloc. urb(%d)\n", index, i);
2515 tidy_up(&(usbduxsub[index]));
2516 up(&start_stop_sem);
2517 return -ENOMEM;
2518 }
2519 usbduxsub[index].urb_in[i]->dev = usbduxsub[index].usbdev;
2520
2521
2522 usbduxsub[index].urb_in[i]->context = NULL;
2523 usbduxsub[index].urb_in[i]->pipe =
2524 usb_rcvisocpipe(usbduxsub[index].usbdev, ISOINEP);
2525 usbduxsub[index].urb_in[i]->transfer_flags = URB_ISO_ASAP;
2526 usbduxsub[index].urb_in[i]->transfer_buffer =
2527 kzalloc(SIZEINBUF, GFP_KERNEL);
2528 if (!(usbduxsub[index].urb_in[i]->transfer_buffer)) {
2529 tidy_up(&(usbduxsub[index]));
2530 up(&start_stop_sem);
2531 return -ENOMEM;
2532 }
2533 usbduxsub[index].urb_in[i]->complete = usbduxsub_ai_isoc_irq;
2534 usbduxsub[index].urb_in[i]->number_of_packets = 1;
2535 usbduxsub[index].urb_in[i]->transfer_buffer_length = SIZEINBUF;
2536 usbduxsub[index].urb_in[i]->iso_frame_desc[0].offset = 0;
2537 usbduxsub[index].urb_in[i]->iso_frame_desc[0].length = SIZEINBUF;
2538 }
2539
2540
2541 if (usbduxsub[index].high_speed)
2542 usbduxsub[index].num_out_buffers = NUMOFOUTBUFFERSHIGH;
2543 else
2544 usbduxsub[index].num_out_buffers = NUMOFOUTBUFFERSFULL;
2545
2546 usbduxsub[index].urb_out =
2547 kcalloc(usbduxsub[index].num_out_buffers, sizeof(struct urb *),
2548 GFP_KERNEL);
2549 if (!(usbduxsub[index].urb_out)) {
2550 tidy_up(&(usbduxsub[index]));
2551 up(&start_stop_sem);
2552 return -ENOMEM;
2553 }
2554 for (i = 0; i < usbduxsub[index].num_out_buffers; i++) {
2555
2556 usbduxsub[index].urb_out[i] = usb_alloc_urb(1, GFP_KERNEL);
2557 if (usbduxsub[index].urb_out[i] == NULL) {
2558 dev_err(dev, "comedi_: usbdux%d: "
2559 "Could not alloc. urb(%d)\n", index, i);
2560 tidy_up(&(usbduxsub[index]));
2561 up(&start_stop_sem);
2562 return -ENOMEM;
2563 }
2564 usbduxsub[index].urb_out[i]->dev = usbduxsub[index].usbdev;
2565
2566
2567 usbduxsub[index].urb_out[i]->context = NULL;
2568 usbduxsub[index].urb_out[i]->pipe =
2569 usb_sndisocpipe(usbduxsub[index].usbdev, ISOOUTEP);
2570 usbduxsub[index].urb_out[i]->transfer_flags = URB_ISO_ASAP;
2571 usbduxsub[index].urb_out[i]->transfer_buffer =
2572 kzalloc(SIZEOUTBUF, GFP_KERNEL);
2573 if (!(usbduxsub[index].urb_out[i]->transfer_buffer)) {
2574 tidy_up(&(usbduxsub[index]));
2575 up(&start_stop_sem);
2576 return -ENOMEM;
2577 }
2578 usbduxsub[index].urb_out[i]->complete = usbduxsub_ao_isoc_irq;
2579 usbduxsub[index].urb_out[i]->number_of_packets = 1;
2580 usbduxsub[index].urb_out[i]->transfer_buffer_length = SIZEOUTBUF;
2581 usbduxsub[index].urb_out[i]->iso_frame_desc[0].offset = 0;
2582 usbduxsub[index].urb_out[i]->iso_frame_desc[0].length =
2583 SIZEOUTBUF;
2584 if (usbduxsub[index].high_speed) {
2585
2586 usbduxsub[index].urb_out[i]->interval = 8;
2587 } else {
2588
2589 usbduxsub[index].urb_out[i]->interval = 1;
2590 }
2591 }
2592
2593
2594 if (usbduxsub[index].high_speed) {
2595
2596 usbduxsub[index].size_pwm_buf = 512;
2597 usbduxsub[index].urb_pwm = usb_alloc_urb(0, GFP_KERNEL);
2598 if (usbduxsub[index].urb_pwm == NULL) {
2599 dev_err(dev, "comedi_: usbdux%d: "
2600 "Could not alloc. pwm urb\n", index);
2601 tidy_up(&(usbduxsub[index]));
2602 up(&start_stop_sem);
2603 return -ENOMEM;
2604 }
2605 usbduxsub[index].urb_pwm->transfer_buffer =
2606 kzalloc(usbduxsub[index].size_pwm_buf, GFP_KERNEL);
2607 if (!(usbduxsub[index].urb_pwm->transfer_buffer)) {
2608 tidy_up(&(usbduxsub[index]));
2609 up(&start_stop_sem);
2610 return -ENOMEM;
2611 }
2612 } else {
2613 usbduxsub[index].urb_pwm = NULL;
2614 usbduxsub[index].size_pwm_buf = 0;
2615 }
2616
2617 usbduxsub[index].ai_cmd_running = 0;
2618 usbduxsub[index].ao_cmd_running = 0;
2619 usbduxsub[index].pwm_cmd_running = 0;
2620
2621
2622 usbduxsub[index].probed = 1;
2623 up(&start_stop_sem);
2624
2625 ret = request_firmware_nowait(THIS_MODULE,
2626 FW_ACTION_HOTPLUG,
2627 FIRMWARE,
2628 &udev->dev,
2629 GFP_KERNEL,
2630 usbduxsub + index,
2631 usbdux_firmware_request_complete_handler);
2632
2633 if (ret) {
2634 dev_err(dev, "Could not load firmware (err=%d)\n", ret);
2635 return ret;
2636 }
2637
2638 dev_info(dev, "comedi_: usbdux%d "
2639 "has been successfully initialised.\n", index);
2640
2641 return 0;
2642}
2643
2644static void usbdux_usb_disconnect(struct usb_interface *intf)
2645{
2646 struct usbduxsub *usbduxsub_tmp = usb_get_intfdata(intf);
2647 struct usb_device *udev = interface_to_usbdev(intf);
2648
2649 if (!usbduxsub_tmp) {
2650 dev_err(&intf->dev,
2651 "comedi_: disconnect called with null pointer.\n");
2652 return;
2653 }
2654 if (usbduxsub_tmp->usbdev != udev) {
2655 dev_err(&intf->dev, "comedi_: BUG! called with wrong ptr!!!\n");
2656 return;
2657 }
2658 comedi_usb_auto_unconfig(intf);
2659 down(&start_stop_sem);
2660 down(&usbduxsub_tmp->sem);
2661 tidy_up(usbduxsub_tmp);
2662 up(&usbduxsub_tmp->sem);
2663 up(&start_stop_sem);
2664 dev_dbg(&intf->dev, "comedi_: disconnected from the usb\n");
2665}
2666
2667static const struct usb_device_id usbdux_usb_table[] = {
2668 { USB_DEVICE(0x13d8, 0x0001) },
2669 { USB_DEVICE(0x13d8, 0x0002) },
2670 { }
2671};
2672
2673MODULE_DEVICE_TABLE(usb, usbdux_usb_table);
2674
2675static struct usb_driver usbdux_usb_driver = {
2676 .name = "usbdux",
2677 .probe = usbdux_usb_probe,
2678 .disconnect = usbdux_usb_disconnect,
2679 .id_table = usbdux_usb_table,
2680};
2681module_comedi_usb_driver(usbdux_driver, usbdux_usb_driver);
2682
2683MODULE_AUTHOR("Bernd Porr, BerndPorr@f2s.com");
2684MODULE_DESCRIPTION("Stirling/ITL USB-DUX -- Bernd.Porr@f2s.com");
2685MODULE_LICENSE("GPL");
2686MODULE_FIRMWARE(FIRMWARE);
2687