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