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#include <linux/kernel.h>
41#include <linux/firmware.h>
42#include <linux/module.h>
43#include <linux/init.h>
44#include <linux/slab.h>
45#include <linux/input.h>
46#include <linux/usb.h>
47#include <linux/smp_lock.h>
48#include <linux/fcntl.h>
49#include <linux/compiler.h>
50#include "comedi_fc.h"
51#include "../comedidev.h"
52
53#define DRIVER_VERSION "v1.0"
54#define DRIVER_AUTHOR "Bernd Porr, BerndPorr@f2s.com"
55#define DRIVER_DESC "USB-DUXfast, BerndPorr@f2s.com"
56#define BOARDNAME "usbduxfast"
57
58
59
60
61#define EZTIMEOUT 30
62
63
64
65
66#define USBDUXFASTSUB_FIRMWARE 0xA0
67#define VENDOR_DIR_IN 0xC0
68#define VENDOR_DIR_OUT 0x40
69
70
71
72
73#define USBDUXFASTSUB_CPUCS 0xE600
74
75
76
77
78#define TB_LEN 0x2000
79
80
81
82
83#define BULKINEP 6
84
85
86
87
88#define CHANNELLISTEP 4
89
90
91
92
93#define NUMCHANNELS 32
94
95
96
97
98#define WAVESIZE 0x20
99
100
101
102
103#define SIZEADIN (sizeof(int16_t))
104
105
106
107
108#define SIZEINBUF 512
109
110
111
112
113#define SIZEINSNBUF 512
114
115
116
117
118#define SIZEOFDUXBUFFER 256
119
120
121
122
123#define NUMOFINBUFFERSHIGH 10
124
125
126
127
128#define NUMUSBDUXFAST 16
129
130
131
132
133#define N_SUBDEVICES 1
134
135
136
137
138#define SUBDEV_AD 0
139
140
141
142
143
144
145
146#define MIN_SAMPLING_PERIOD 9
147
148
149
150
151#define MAX_SAMPLING_PERIOD 500
152
153
154
155
156
157#define PACKETS_TO_IGNORE 4
158
159
160
161
162static const struct comedi_lrange range_usbduxfast_ai_range = {
163 2, {BIP_RANGE(0.75), BIP_RANGE(0.5)}
164};
165
166
167
168
169
170
171
172struct usbduxfastsub_s {
173 int attached;
174 int probed;
175 struct usb_device *usbdev;
176 struct urb *urbIn;
177 int8_t *transfer_buffer;
178 int16_t *insnBuffer;
179 int ifnum;
180 struct usb_interface *interface;
181 struct comedi_device *comedidev;
182
183 short int ai_cmd_running;
184 short int ai_continous;
185 long int ai_sample_count;
186 uint8_t *dux_commands;
187 int ignore;
188
189 struct semaphore sem;
190};
191
192
193
194
195
196
197
198
199
200
201static struct usbduxfastsub_s usbduxfastsub[NUMUSBDUXFAST];
202
203static DECLARE_MUTEX(start_stop_sem);
204
205
206
207
208#define SENDADCOMMANDS 0
209#define SENDINITEP6 1
210
211static int send_dux_commands(struct usbduxfastsub_s *udfs, int cmd_type)
212{
213 int tmp, nsent;
214
215 udfs->dux_commands[0] = cmd_type;
216
217#ifdef CONFIG_COMEDI_DEBUG
218 printk(KERN_DEBUG "comedi%d: usbduxfast: dux_commands: ",
219 udfs->comedidev->minor);
220 for (tmp = 0; tmp < SIZEOFDUXBUFFER; tmp++)
221 printk(" %02x", udfs->dux_commands[tmp]);
222 printk("\n");
223#endif
224
225 tmp = usb_bulk_msg(udfs->usbdev,
226 usb_sndbulkpipe(udfs->usbdev, CHANNELLISTEP),
227 udfs->dux_commands, SIZEOFDUXBUFFER, &nsent, 10000);
228 if (tmp < 0)
229 printk(KERN_ERR "comedi%d: could not transmit dux_commands to"
230 "the usb-device, err=%d\n", udfs->comedidev->minor, tmp);
231 return tmp;
232}
233
234
235
236
237
238static int usbduxfastsub_unlink_InURBs(struct usbduxfastsub_s *udfs)
239{
240 int j = 0;
241 int err = 0;
242
243 if (udfs && udfs->urbIn) {
244 udfs->ai_cmd_running = 0;
245
246 usb_kill_urb(udfs->urbIn);
247 j = 0;
248 }
249#ifdef CONFIG_COMEDI_DEBUG
250 printk(KERN_DEBUG "comedi: usbduxfast: unlinked InURB: res=%d\n", j);
251#endif
252 return err;
253}
254
255
256
257
258
259
260static int usbduxfast_ai_stop(struct usbduxfastsub_s *udfs, int do_unlink)
261{
262 int ret = 0;
263
264 if (!udfs) {
265 printk(KERN_ERR "comedi?: usbduxfast_ai_stop: udfs=NULL!\n");
266 return -EFAULT;
267 }
268#ifdef CONFIG_COMEDI_DEBUG
269 printk(KERN_DEBUG "comedi: usbduxfast_ai_stop\n");
270#endif
271
272 udfs->ai_cmd_running = 0;
273
274 if (do_unlink)
275 ret = usbduxfastsub_unlink_InURBs(udfs);
276
277 return ret;
278}
279
280
281
282
283
284static int usbduxfast_ai_cancel(struct comedi_device *dev,
285 struct comedi_subdevice *s)
286{
287 struct usbduxfastsub_s *udfs;
288 int ret;
289
290
291#ifdef CONFIG_COMEDI_DEBUG
292 printk(KERN_DEBUG "comedi: usbduxfast_ai_cancel\n");
293#endif
294 udfs = dev->private;
295 if (!udfs) {
296 printk(KERN_ERR "comedi: usbduxfast_ai_cancel: udfs=NULL\n");
297 return -EFAULT;
298 }
299 down(&udfs->sem);
300 if (!udfs->probed) {
301 up(&udfs->sem);
302 return -ENODEV;
303 }
304
305 ret = usbduxfast_ai_stop(udfs, 1);
306 up(&udfs->sem);
307
308 return ret;
309}
310
311
312
313
314
315static void usbduxfastsub_ai_Irq(struct urb *urb)
316{
317 int n, err;
318 struct usbduxfastsub_s *udfs;
319 struct comedi_device *this_comedidev;
320 struct comedi_subdevice *s;
321 uint16_t *p;
322
323
324 if (!urb) {
325 printk(KERN_ERR "comedi_: usbduxfast_: ao int-handler called "
326 "with urb=NULL!\n");
327 return;
328 }
329
330 this_comedidev = urb->context;
331 if (!this_comedidev) {
332 printk(KERN_ERR "comedi_: usbduxfast_: urb context is a NULL "
333 "pointer!\n");
334 return;
335 }
336
337 udfs = this_comedidev->private;
338 if (!udfs) {
339 printk(KERN_ERR "comedi_: usbduxfast_: private of comedi "
340 "subdev is a NULL pointer!\n");
341 return;
342 }
343
344 if (unlikely(!udfs->ai_cmd_running)) {
345
346
347
348
349
350 return;
351 }
352
353 if (unlikely(!udfs->attached)) {
354
355 return;
356 }
357
358 s = this_comedidev->subdevices + SUBDEV_AD;
359
360
361 switch (urb->status) {
362 case 0:
363 break;
364
365
366
367
368
369 case -ECONNRESET:
370 case -ENOENT:
371 case -ESHUTDOWN:
372 case -ECONNABORTED:
373
374 s->async->events |= COMEDI_CB_EOA;
375 s->async->events |= COMEDI_CB_ERROR;
376 comedi_event(udfs->comedidev, s);
377
378 usbduxfast_ai_stop(udfs, 0);
379 return;
380
381 default:
382 printk("comedi%d: usbduxfast: non-zero urb status received in "
383 "ai intr context: %d\n",
384 udfs->comedidev->minor, urb->status);
385 s->async->events |= COMEDI_CB_EOA;
386 s->async->events |= COMEDI_CB_ERROR;
387 comedi_event(udfs->comedidev, s);
388 usbduxfast_ai_stop(udfs, 0);
389 return;
390 }
391
392 p = urb->transfer_buffer;
393 if (!udfs->ignore) {
394 if (!udfs->ai_continous) {
395
396 n = urb->actual_length / sizeof(uint16_t);
397 if (unlikely(udfs->ai_sample_count < n)) {
398
399
400
401
402 cfc_write_array_to_buffer(s,
403 urb->transfer_buffer,
404 udfs->ai_sample_count
405 * sizeof(uint16_t));
406 usbduxfast_ai_stop(udfs, 0);
407
408 s->async->events |= COMEDI_CB_EOA;
409 comedi_event(udfs->comedidev, s);
410 return;
411 }
412 udfs->ai_sample_count -= n;
413 }
414
415 err = cfc_write_array_to_buffer(s, urb->transfer_buffer,
416 urb->actual_length);
417 if (unlikely(err == 0)) {
418
419 usbduxfast_ai_stop(udfs, 0);
420 return;
421 }
422
423
424 comedi_event(udfs->comedidev, s);
425
426 } else {
427
428 udfs->ignore--;
429 }
430
431
432
433
434
435 urb->dev = udfs->usbdev;
436 urb->status = 0;
437 err = usb_submit_urb(urb, GFP_ATOMIC);
438 if (err < 0) {
439 printk(KERN_ERR "comedi%d: usbduxfast: urb resubm failed: %d",
440 udfs->comedidev->minor, err);
441 s->async->events |= COMEDI_CB_EOA;
442 s->async->events |= COMEDI_CB_ERROR;
443 comedi_event(udfs->comedidev, s);
444 usbduxfast_ai_stop(udfs, 0);
445 }
446}
447
448static int usbduxfastsub_start(struct usbduxfastsub_s *udfs)
449{
450 int ret;
451 unsigned char local_transfer_buffer[16];
452
453
454 local_transfer_buffer[0] = 0;
455 ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), USBDUXFASTSUB_FIRMWARE,
456 VENDOR_DIR_OUT,
457 USBDUXFASTSUB_CPUCS,
458 0x0000,
459 local_transfer_buffer,
460 1,
461 EZTIMEOUT);
462 if (ret < 0) {
463 printk("comedi_: usbduxfast_: control msg failed (start)\n");
464 return ret;
465 }
466
467 return 0;
468}
469
470static int usbduxfastsub_stop(struct usbduxfastsub_s *udfs)
471{
472 int ret;
473 unsigned char local_transfer_buffer[16];
474
475
476 local_transfer_buffer[0] = 1;
477 ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), USBDUXFASTSUB_FIRMWARE,
478 VENDOR_DIR_OUT,
479 USBDUXFASTSUB_CPUCS,
480 0x0000,
481 local_transfer_buffer, 1,
482 EZTIMEOUT);
483 if (ret < 0) {
484 printk(KERN_ERR "comedi_: usbduxfast: control msg failed "
485 "(stop)\n");
486 return ret;
487 }
488
489 return 0;
490}
491
492static int usbduxfastsub_upload(struct usbduxfastsub_s *udfs,
493 unsigned char *local_transfer_buffer,
494 unsigned int startAddr, unsigned int len)
495{
496 int ret;
497
498#ifdef CONFIG_COMEDI_DEBUG
499 printk(KERN_DEBUG "comedi: usbduxfast: uploading %d bytes", len);
500 printk(KERN_DEBUG " to addr %d, first byte=%d.\n",
501 startAddr, local_transfer_buffer[0]);
502#endif
503 ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), USBDUXFASTSUB_FIRMWARE,
504 VENDOR_DIR_OUT,
505 startAddr,
506 0x0000,
507 local_transfer_buffer,
508 len,
509 EZTIMEOUT);
510
511#ifdef CONFIG_COMEDI_DEBUG
512 printk(KERN_DEBUG "comedi_: usbduxfast: result=%d\n", ret);
513#endif
514
515 if (ret < 0) {
516 printk(KERN_ERR "comedi_: usbduxfast: uppload failed\n");
517 return ret;
518 }
519
520 return 0;
521}
522
523int usbduxfastsub_submit_InURBs(struct usbduxfastsub_s *udfs)
524{
525 int ret;
526
527 if (!udfs)
528 return -EFAULT;
529
530 usb_fill_bulk_urb(udfs->urbIn, udfs->usbdev,
531 usb_rcvbulkpipe(udfs->usbdev, BULKINEP),
532 udfs->transfer_buffer,
533 SIZEINBUF, usbduxfastsub_ai_Irq, udfs->comedidev);
534
535#ifdef CONFIG_COMEDI_DEBUG
536 printk(KERN_DEBUG "comedi%d: usbduxfast: submitting in-urb: "
537 "0x%p,0x%p\n", udfs->comedidev->minor, udfs->urbIn->context,
538 udfs->urbIn->dev);
539#endif
540 ret = usb_submit_urb(udfs->urbIn, GFP_ATOMIC);
541 if (ret) {
542 printk(KERN_ERR "comedi_: usbduxfast: ai: usb_submit_urb error"
543 " %d\n", ret);
544 return ret;
545 }
546 return 0;
547}
548
549static int usbduxfast_ai_cmdtest(struct comedi_device *dev,
550 struct comedi_subdevice *s,
551 struct comedi_cmd *cmd)
552{
553 int err = 0, stop_mask = 0;
554 long int steps, tmp;
555 int minSamplPer;
556 struct usbduxfastsub_s *udfs = dev->private;
557
558 if (!udfs->probed)
559 return -ENODEV;
560
561#ifdef CONFIG_COMEDI_DEBUG
562 printk(KERN_DEBUG "comedi%d: usbduxfast_ai_cmdtest\n", dev->minor);
563 printk(KERN_DEBUG "comedi%d: usbduxfast: convert_arg=%u "
564 "scan_begin_arg=%u\n",
565 dev->minor, cmd->convert_arg, cmd->scan_begin_arg);
566#endif
567
568
569 tmp = cmd->start_src;
570 cmd->start_src &= TRIG_NOW | TRIG_EXT | TRIG_INT;
571 if (!cmd->start_src || tmp != cmd->start_src)
572 err++;
573
574 tmp = cmd->scan_begin_src;
575 cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT;
576 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
577 err++;
578
579 tmp = cmd->convert_src;
580 cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
581 if (!cmd->convert_src || tmp != cmd->convert_src)
582 err++;
583
584 tmp = cmd->scan_end_src;
585 cmd->scan_end_src &= TRIG_COUNT;
586 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
587 err++;
588
589 tmp = cmd->stop_src;
590 stop_mask = TRIG_COUNT | TRIG_NONE;
591 cmd->stop_src &= stop_mask;
592 if (!cmd->stop_src || tmp != cmd->stop_src)
593 err++;
594
595 if (err)
596 return 1;
597
598
599
600
601
602 if (cmd->start_src != TRIG_NOW &&
603 cmd->start_src != TRIG_EXT && cmd->start_src != TRIG_INT)
604 err++;
605 if (cmd->scan_begin_src != TRIG_TIMER &&
606 cmd->scan_begin_src != TRIG_FOLLOW &&
607 cmd->scan_begin_src != TRIG_EXT)
608 err++;
609 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
610 err++;
611 if (cmd->stop_src != TRIG_COUNT &&
612 cmd->stop_src != TRIG_EXT && cmd->stop_src != TRIG_NONE)
613 err++;
614
615
616 if (cmd->start_src == TRIG_EXT && cmd->stop_src == TRIG_EXT)
617 err++;
618
619 if (err)
620 return 2;
621
622
623
624 if (cmd->start_src == TRIG_NOW && cmd->start_arg != 0) {
625 cmd->start_arg = 0;
626 err++;
627 }
628
629 if (!cmd->chanlist_len)
630 err++;
631
632 if (cmd->scan_end_arg != cmd->chanlist_len) {
633 cmd->scan_end_arg = cmd->chanlist_len;
634 err++;
635 }
636
637 if (cmd->chanlist_len == 1)
638 minSamplPer = 1;
639 else
640 minSamplPer = MIN_SAMPLING_PERIOD;
641
642 if (cmd->convert_src == TRIG_TIMER) {
643 steps = cmd->convert_arg * 30;
644 if (steps < (minSamplPer * 1000))
645 steps = minSamplPer * 1000;
646
647 if (steps > (MAX_SAMPLING_PERIOD * 1000))
648 steps = MAX_SAMPLING_PERIOD * 1000;
649
650
651 tmp = steps / 30;
652 if (cmd->convert_arg != tmp) {
653 cmd->convert_arg = tmp;
654 err++;
655 }
656 }
657
658 if (cmd->scan_begin_src == TRIG_TIMER)
659 err++;
660
661
662 switch (cmd->stop_src) {
663 case TRIG_COUNT:
664 if (!cmd->stop_arg) {
665 cmd->stop_arg = 1;
666 err++;
667 }
668 break;
669 case TRIG_NONE:
670 if (cmd->stop_arg != 0) {
671 cmd->stop_arg = 0;
672 err++;
673 }
674 break;
675
676
677
678
679 default:
680 break;
681 }
682
683 if (err)
684 return 3;
685
686
687
688 return 0;
689
690}
691
692static int usbduxfast_ai_inttrig(struct comedi_device *dev,
693 struct comedi_subdevice *s,
694 unsigned int trignum)
695{
696 int ret;
697 struct usbduxfastsub_s *udfs = dev->private;
698
699 if (!udfs)
700 return -EFAULT;
701
702 down(&udfs->sem);
703 if (!udfs->probed) {
704 up(&udfs->sem);
705 return -ENODEV;
706 }
707#ifdef CONFIG_COMEDI_DEBUG
708 printk(KERN_DEBUG "comedi%d: usbduxfast_ai_inttrig\n", dev->minor);
709#endif
710
711 if (trignum != 0) {
712 printk(KERN_ERR "comedi%d: usbduxfast_ai_inttrig: invalid"
713 " trignum\n", dev->minor);
714 up(&udfs->sem);
715 return -EINVAL;
716 }
717 if (!udfs->ai_cmd_running) {
718 udfs->ai_cmd_running = 1;
719 ret = usbduxfastsub_submit_InURBs(udfs);
720 if (ret < 0) {
721 printk(KERN_ERR "comedi%d: usbduxfast_ai_inttrig: "
722 "urbSubmit: err=%d\n", dev->minor, ret);
723 udfs->ai_cmd_running = 0;
724 up(&udfs->sem);
725 return ret;
726 }
727 s->async->inttrig = NULL;
728 } else {
729 printk(KERN_ERR "comedi%d: ai_inttrig but acqu is already"
730 " running\n", dev->minor);
731 }
732 up(&udfs->sem);
733 return 1;
734}
735
736
737
738
739
740#define LENBASE (1+0x00)
741#define OPBASE (1+0x08)
742#define OUTBASE (1+0x10)
743#define LOGBASE (1+0x18)
744
745static int usbduxfast_ai_cmd(struct comedi_device *dev,
746 struct comedi_subdevice *s)
747{
748 struct comedi_cmd *cmd = &s->async->cmd;
749 unsigned int chan, gain, rngmask = 0xff;
750 int i, j, ret;
751 struct usbduxfastsub_s *udfs;
752 int result;
753 long steps, steps_tmp;
754
755#ifdef CONFIG_COMEDI_DEBUG
756 printk(KERN_DEBUG "comedi%d: usbduxfast_ai_cmd\n", dev->minor);
757#endif
758 udfs = dev->private;
759 if (!udfs)
760 return -EFAULT;
761
762 down(&udfs->sem);
763 if (!udfs->probed) {
764 up(&udfs->sem);
765 return -ENODEV;
766 }
767 if (udfs->ai_cmd_running) {
768 printk(KERN_ERR "comedi%d: ai_cmd not possible. Another ai_cmd"
769 " is running.\n", dev->minor);
770 up(&udfs->sem);
771 return -EBUSY;
772 }
773
774 s->async->cur_chan = 0;
775
776
777
778
779
780 udfs->ignore = PACKETS_TO_IGNORE;
781
782 if (cmd->chanlist_len > 0) {
783 gain = CR_RANGE(cmd->chanlist[0]);
784 for (i = 0; i < cmd->chanlist_len; ++i) {
785 chan = CR_CHAN(cmd->chanlist[i]);
786 if (chan != i) {
787 printk(KERN_ERR "comedi%d: cmd is accepting "
788 "only consecutive channels.\n",
789 dev->minor);
790 up(&udfs->sem);
791 return -EINVAL;
792 }
793 if ((gain != CR_RANGE(cmd->chanlist[i]))
794 && (cmd->chanlist_len > 3)) {
795 printk(KERN_ERR "comedi%d: the gain must be"
796 " the same for all channels.\n",
797 dev->minor);
798 up(&udfs->sem);
799 return -EINVAL;
800 }
801 if (i >= NUMCHANNELS) {
802 printk(KERN_ERR "comedi%d: channel list too"
803 " long\n", dev->minor);
804 break;
805 }
806 }
807 }
808 steps = 0;
809 if (cmd->scan_begin_src == TRIG_TIMER) {
810 printk(KERN_ERR "comedi%d: usbduxfast: "
811 "scan_begin_src==TRIG_TIMER not valid.\n", dev->minor);
812 up(&udfs->sem);
813 return -EINVAL;
814 }
815 if (cmd->convert_src == TRIG_TIMER)
816 steps = (cmd->convert_arg * 30) / 1000;
817
818 if ((steps < MIN_SAMPLING_PERIOD) && (cmd->chanlist_len != 1)) {
819 printk(KERN_ERR "comedi%d: usbduxfast: ai_cmd: steps=%ld, "
820 "scan_begin_arg=%d. Not properly tested by cmdtest?\n",
821 dev->minor, steps, cmd->scan_begin_arg);
822 up(&udfs->sem);
823 return -EINVAL;
824 }
825 if (steps > MAX_SAMPLING_PERIOD) {
826 printk(KERN_ERR "comedi%d: usbduxfast: ai_cmd: sampling rate "
827 "too low.\n", dev->minor);
828 up(&udfs->sem);
829 return -EINVAL;
830 }
831 if ((cmd->start_src == TRIG_EXT) && (cmd->chanlist_len != 1)
832 && (cmd->chanlist_len != 16)) {
833 printk(KERN_ERR "comedi%d: usbduxfast: ai_cmd: TRIG_EXT only"
834 " with 1 or 16 channels possible.\n", dev->minor);
835 up(&udfs->sem);
836 return -EINVAL;
837 }
838#ifdef CONFIG_COMEDI_DEBUG
839 printk(KERN_DEBUG "comedi%d: usbduxfast: steps=%ld, convert_arg=%u\n",
840 dev->minor, steps, cmd->convert_arg);
841#endif
842
843 switch (cmd->chanlist_len) {
844 case 1:
845
846
847
848
849 if (CR_RANGE(cmd->chanlist[0]) > 0)
850 rngmask = 0xff - 0x04;
851 else
852 rngmask = 0xff;
853
854
855
856
857
858
859
860 if (cmd->start_src == TRIG_EXT) {
861
862 udfs->dux_commands[LENBASE + 0] = 0x01;
863
864 udfs->dux_commands[OPBASE + 0] = 0x01;
865 udfs->dux_commands[OUTBASE + 0] = 0xFF & rngmask;
866
867 udfs->dux_commands[LOGBASE + 0] = 0x00;
868 } else {
869 udfs->dux_commands[LENBASE + 0] = 1;
870 udfs->dux_commands[OPBASE + 0] = 0;
871 udfs->dux_commands[OUTBASE + 0] = 0xFF & rngmask;
872 udfs->dux_commands[LOGBASE + 0] = 0;
873 }
874
875 if (steps < MIN_SAMPLING_PERIOD) {
876
877 if (steps <= 1) {
878
879
880
881
882
883
884
885 udfs->dux_commands[LENBASE + 1] = 0x89;
886
887 udfs->dux_commands[OPBASE + 1] = 0x03;
888 udfs->dux_commands[OUTBASE + 1] =
889 0xFF & rngmask;
890
891 udfs->dux_commands[LOGBASE + 1] = 0xFF;
892 } else {
893
894
895
896
897 udfs->dux_commands[LENBASE + 1] = steps - 1;
898
899 udfs->dux_commands[OPBASE + 1] = 0x02;
900 udfs->dux_commands[OUTBASE + 1] =
901 0xFF & rngmask;
902
903 udfs->dux_commands[LOGBASE + 1] = 0;
904
905 udfs->dux_commands[LENBASE + 2] = 0x09;
906
907 udfs->dux_commands[OPBASE + 2] = 0x01;
908 udfs->dux_commands[OUTBASE + 2] =
909 0xFF & rngmask;
910
911 udfs->dux_commands[LOGBASE + 2] = 0xFF;
912 }
913 } else {
914
915
916
917
918
919
920 steps = steps - 1;
921
922
923 udfs->dux_commands[LENBASE + 1] = steps / 2;
924 udfs->dux_commands[OPBASE + 1] = 0;
925 udfs->dux_commands[OUTBASE + 1] = 0xFF & rngmask;
926 udfs->dux_commands[LOGBASE + 1] = 0;
927
928
929 udfs->dux_commands[LENBASE + 2] = steps - steps / 2;
930 udfs->dux_commands[OPBASE + 2] = 0;
931 udfs->dux_commands[OUTBASE + 2] = 0xFF & rngmask;
932 udfs->dux_commands[LOGBASE + 2] = 0;
933
934
935
936
937 udfs->dux_commands[LENBASE + 3] = 0x09;
938
939 udfs->dux_commands[OPBASE + 3] = 0x03;
940 udfs->dux_commands[OUTBASE + 3] = 0xFF & rngmask;
941
942 udfs->dux_commands[LOGBASE + 3] = 0xFF;
943 }
944 break;
945
946 case 2:
947
948
949
950
951
952 if (CR_RANGE(cmd->chanlist[0]) > 0)
953 rngmask = 0xff - 0x04;
954 else
955 rngmask = 0xff;
956
957 udfs->dux_commands[LENBASE + 0] = 1;
958
959 udfs->dux_commands[OPBASE + 0] = 0x02;
960 udfs->dux_commands[OUTBASE + 0] = 0xFF & rngmask;
961 udfs->dux_commands[LOGBASE + 0] = 0;
962
963
964 steps_tmp = steps - 1;
965
966 if (CR_RANGE(cmd->chanlist[1]) > 0)
967 rngmask = 0xff - 0x04;
968 else
969 rngmask = 0xff;
970
971
972 udfs->dux_commands[LENBASE + 1] = steps_tmp / 2;
973 udfs->dux_commands[OPBASE + 1] = 0;
974
975 udfs->dux_commands[OUTBASE + 1] = 0xFE & rngmask;
976 udfs->dux_commands[LOGBASE + 1] = 0;
977
978
979 udfs->dux_commands[LENBASE + 2] = steps_tmp - steps_tmp / 2;
980 udfs->dux_commands[OPBASE + 2] = 0;
981 udfs->dux_commands[OUTBASE + 2] = 0xFF & rngmask;
982 udfs->dux_commands[LOGBASE + 2] = 0;
983
984 udfs->dux_commands[LENBASE + 3] = 1;
985
986 udfs->dux_commands[OPBASE + 3] = 0x02;
987 udfs->dux_commands[OUTBASE + 3] = 0xFF & rngmask;
988 udfs->dux_commands[LOGBASE + 3] = 0;
989
990
991
992
993
994 steps_tmp = steps - 2;
995
996 if (CR_RANGE(cmd->chanlist[0]) > 0)
997 rngmask = 0xff - 0x04;
998 else
999 rngmask = 0xff;
1000
1001
1002 udfs->dux_commands[LENBASE + 4] = steps_tmp / 2;
1003 udfs->dux_commands[OPBASE + 4] = 0;
1004
1005 udfs->dux_commands[OUTBASE + 4] = (0xFF - 0x02) & rngmask;
1006 udfs->dux_commands[LOGBASE + 4] = 0;
1007
1008
1009 udfs->dux_commands[LENBASE + 5] = steps_tmp - steps_tmp / 2;
1010 udfs->dux_commands[OPBASE + 5] = 0;
1011 udfs->dux_commands[OUTBASE + 5] = 0xFF & rngmask;
1012 udfs->dux_commands[LOGBASE + 5] = 0;
1013
1014 udfs->dux_commands[LENBASE + 6] = 1;
1015 udfs->dux_commands[OPBASE + 6] = 0;
1016 udfs->dux_commands[OUTBASE + 6] = 0xFF & rngmask;
1017 udfs->dux_commands[LOGBASE + 6] = 0;
1018 break;
1019
1020 case 3:
1021
1022
1023
1024 for (j = 0; j < 1; j++) {
1025 if (CR_RANGE(cmd->chanlist[j]) > 0)
1026 rngmask = 0xff - 0x04;
1027 else
1028 rngmask = 0xff;
1029
1030
1031
1032
1033 udfs->dux_commands[LENBASE + j * 2] = steps / 2;
1034
1035 udfs->dux_commands[OPBASE + j * 2] = 0x02;
1036
1037 udfs->dux_commands[OUTBASE + j * 2] = 0xFF & rngmask;
1038 udfs->dux_commands[LOGBASE + j * 2] = 0;
1039
1040 if (CR_RANGE(cmd->chanlist[j + 1]) > 0)
1041 rngmask = 0xff - 0x04;
1042 else
1043 rngmask = 0xff;
1044
1045
1046 udfs->dux_commands[LENBASE + j * 2 + 1] =
1047 steps - steps / 2;
1048
1049 udfs->dux_commands[OPBASE + j * 2 + 1] = 0;
1050
1051 udfs->dux_commands[OUTBASE + j * 2 + 1] =
1052 0xFE & rngmask;
1053 udfs->dux_commands[LOGBASE + j * 2 + 1] = 0;
1054 }
1055
1056
1057 steps_tmp = steps - 2;
1058
1059
1060 udfs->dux_commands[LENBASE + 4] = steps_tmp / 2;
1061
1062 udfs->dux_commands[OPBASE + 4] = 0x02;
1063 udfs->dux_commands[OUTBASE + 4] = 0xFF & rngmask;
1064 udfs->dux_commands[LOGBASE + 4] = 0;
1065
1066 if (CR_RANGE(cmd->chanlist[0]) > 0)
1067 rngmask = 0xff - 0x04;
1068 else
1069 rngmask = 0xff;
1070
1071
1072 udfs->dux_commands[LENBASE + 5] = steps_tmp - steps_tmp / 2;
1073
1074 udfs->dux_commands[OPBASE + 5] = 0;
1075
1076 udfs->dux_commands[OUTBASE + 5] = (0xFF - 0x02) & rngmask;
1077 udfs->dux_commands[LOGBASE + 5] = 0;
1078
1079 udfs->dux_commands[LENBASE + 6] = 1;
1080 udfs->dux_commands[OPBASE + 6] = 0;
1081 udfs->dux_commands[OUTBASE + 6] = 0xFF & rngmask;
1082 udfs->dux_commands[LOGBASE + 6] = 0;
1083
1084 case 16:
1085 if (CR_RANGE(cmd->chanlist[0]) > 0)
1086 rngmask = 0xff - 0x04;
1087 else
1088 rngmask = 0xff;
1089
1090 if (cmd->start_src == TRIG_EXT) {
1091
1092
1093
1094
1095
1096 udfs->dux_commands[LENBASE + 0] = 0x01;
1097
1098 udfs->dux_commands[OPBASE + 0] = 0x01;
1099
1100 udfs->dux_commands[OUTBASE + 0] =
1101 (0xFF - 0x02) & rngmask;
1102
1103 udfs->dux_commands[LOGBASE + 0] = 0x00;
1104 } else {
1105
1106
1107
1108
1109
1110 udfs->dux_commands[LENBASE + 0] = 255;
1111 udfs->dux_commands[OPBASE + 0] = 0;
1112
1113 udfs->dux_commands[OUTBASE + 0] =
1114 (0xFF - 0x02) & rngmask;
1115 udfs->dux_commands[LOGBASE + 0] = 0;
1116 }
1117
1118
1119 udfs->dux_commands[LENBASE + 1] = 1;
1120
1121 udfs->dux_commands[OPBASE + 1] = 0x02;
1122 udfs->dux_commands[OUTBASE + 1] = 0xFF & rngmask;
1123 udfs->dux_commands[LOGBASE + 1] = 0;
1124
1125
1126 steps = steps - 2;
1127
1128
1129 udfs->dux_commands[LENBASE + 2] = steps / 2;
1130 udfs->dux_commands[OPBASE + 2] = 0;
1131 udfs->dux_commands[OUTBASE + 2] = 0xFE & rngmask;
1132 udfs->dux_commands[LOGBASE + 2] = 0;
1133
1134
1135 udfs->dux_commands[LENBASE + 3] = steps - steps / 2;
1136 udfs->dux_commands[OPBASE + 3] = 0;
1137 udfs->dux_commands[OUTBASE + 3] = 0xFF & rngmask;
1138 udfs->dux_commands[LOGBASE + 3] = 0;
1139
1140
1141 udfs->dux_commands[LENBASE + 4] = 0x09;
1142
1143 udfs->dux_commands[OPBASE + 4] = 0x01;
1144 udfs->dux_commands[OUTBASE + 4] = 0xFF & rngmask;
1145
1146 udfs->dux_commands[LOGBASE + 4] = 0xFF;
1147
1148 break;
1149
1150 default:
1151 printk(KERN_ERR "comedi %d: unsupported combination of "
1152 "channels\n", dev->minor);
1153 up(&udfs->sem);
1154 return -EFAULT;
1155 }
1156
1157#ifdef CONFIG_COMEDI_DEBUG
1158 printk(KERN_DEBUG "comedi %d: sending commands to the usb device\n",
1159 dev->minor);
1160#endif
1161
1162 result = send_dux_commands(udfs, SENDADCOMMANDS);
1163 if (result < 0) {
1164 printk(KERN_ERR "comedi%d: adc command could not be submitted."
1165 "Aborting...\n", dev->minor);
1166 up(&udfs->sem);
1167 return result;
1168 }
1169 if (cmd->stop_src == TRIG_COUNT) {
1170 udfs->ai_sample_count = cmd->stop_arg * cmd->scan_end_arg;
1171 if (udfs->ai_sample_count < 1) {
1172 printk(KERN_ERR "comedi%d: "
1173 "(cmd->stop_arg)*(cmd->scan_end_arg)<1, "
1174 "aborting.\n", dev->minor);
1175 up(&udfs->sem);
1176 return -EFAULT;
1177 }
1178 udfs->ai_continous = 0;
1179 } else {
1180
1181 udfs->ai_continous = 1;
1182 udfs->ai_sample_count = 0;
1183 }
1184
1185 if ((cmd->start_src == TRIG_NOW) || (cmd->start_src == TRIG_EXT)) {
1186
1187 udfs->ai_cmd_running = 1;
1188 ret = usbduxfastsub_submit_InURBs(udfs);
1189 if (ret < 0) {
1190 udfs->ai_cmd_running = 0;
1191
1192 up(&udfs->sem);
1193 return ret;
1194 }
1195 s->async->inttrig = NULL;
1196 } else {
1197
1198
1199
1200
1201
1202 s->async->inttrig = usbduxfast_ai_inttrig;
1203 }
1204 up(&udfs->sem);
1205
1206 return 0;
1207}
1208
1209
1210
1211
1212static int usbduxfast_ai_insn_read(struct comedi_device *dev,
1213 struct comedi_subdevice *s,
1214 struct comedi_insn *insn, unsigned int *data)
1215{
1216 int i, j, n, actual_length;
1217 int chan, range, rngmask;
1218 int err;
1219 struct usbduxfastsub_s *udfs;
1220
1221 udfs = dev->private;
1222 if (!udfs) {
1223 printk(KERN_ERR "comedi%d: ai_insn_read: no usb dev.\n",
1224 dev->minor);
1225 return -ENODEV;
1226 }
1227#ifdef CONFIG_COMEDI_DEBUG
1228 printk(KERN_DEBUG "comedi%d: ai_insn_read, insn->n=%d, "
1229 "insn->subdev=%d\n", dev->minor, insn->n, insn->subdev);
1230#endif
1231 down(&udfs->sem);
1232 if (!udfs->probed) {
1233 up(&udfs->sem);
1234 return -ENODEV;
1235 }
1236 if (udfs->ai_cmd_running) {
1237 printk(KERN_ERR "comedi%d: ai_insn_read not possible. Async "
1238 "Command is running.\n", dev->minor);
1239 up(&udfs->sem);
1240 return -EBUSY;
1241 }
1242
1243 chan = CR_CHAN(insn->chanspec);
1244 range = CR_RANGE(insn->chanspec);
1245
1246
1247 if (range > 0)
1248 rngmask = 0xff - 0x04;
1249 else
1250 rngmask = 0xff;
1251
1252
1253 udfs->dux_commands[LENBASE + 0] = 1;
1254
1255 udfs->dux_commands[OPBASE + 0] = 0x02;
1256 udfs->dux_commands[OUTBASE + 0] = 0xFF & rngmask;
1257 udfs->dux_commands[LOGBASE + 0] = 0;
1258
1259
1260 udfs->dux_commands[LENBASE + 1] = 12;
1261 udfs->dux_commands[OPBASE + 1] = 0;
1262 udfs->dux_commands[OUTBASE + 1] = 0xFE & rngmask;
1263 udfs->dux_commands[LOGBASE + 1] = 0;
1264
1265 udfs->dux_commands[LENBASE + 2] = 1;
1266 udfs->dux_commands[OPBASE + 2] = 0;
1267 udfs->dux_commands[OUTBASE + 2] = 0xFE & rngmask;
1268 udfs->dux_commands[LOGBASE + 2] = 0;
1269
1270 udfs->dux_commands[LENBASE + 3] = 1;
1271 udfs->dux_commands[OPBASE + 3] = 0;
1272 udfs->dux_commands[OUTBASE + 3] = 0xFE & rngmask;
1273 udfs->dux_commands[LOGBASE + 3] = 0;
1274
1275 udfs->dux_commands[LENBASE + 4] = 1;
1276 udfs->dux_commands[OPBASE + 4] = 0;
1277 udfs->dux_commands[OUTBASE + 4] = 0xFE & rngmask;
1278 udfs->dux_commands[LOGBASE + 4] = 0;
1279
1280
1281 udfs->dux_commands[LENBASE + 5] = 12;
1282 udfs->dux_commands[OPBASE + 5] = 0;
1283 udfs->dux_commands[OUTBASE + 5] = 0xFF & rngmask;
1284 udfs->dux_commands[LOGBASE + 5] = 0;
1285
1286 udfs->dux_commands[LENBASE + 6] = 1;
1287 udfs->dux_commands[OPBASE + 6] = 0;
1288 udfs->dux_commands[OUTBASE + 6] = 0xFF & rngmask;
1289 udfs->dux_commands[LOGBASE + 0] = 0;
1290
1291#ifdef CONFIG_COMEDI_DEBUG
1292 printk(KERN_DEBUG "comedi %d: sending commands to the usb device\n",
1293 dev->minor);
1294#endif
1295
1296 err = send_dux_commands(udfs, SENDADCOMMANDS);
1297 if (err < 0) {
1298 printk(KERN_ERR "comedi%d: adc command could not be submitted."
1299 "Aborting...\n", dev->minor);
1300 up(&udfs->sem);
1301 return err;
1302 }
1303#ifdef CONFIG_COMEDI_DEBUG
1304 printk(KERN_DEBUG "comedi%d: usbduxfast: submitting in-urb: "
1305 "0x%p,0x%p\n", udfs->comedidev->minor, udfs->urbIn->context,
1306 udfs->urbIn->dev);
1307#endif
1308 for (i = 0; i < PACKETS_TO_IGNORE; i++) {
1309 err = usb_bulk_msg(udfs->usbdev,
1310 usb_rcvbulkpipe(udfs->usbdev, BULKINEP),
1311 udfs->transfer_buffer, SIZEINBUF,
1312 &actual_length, 10000);
1313 if (err < 0) {
1314 printk(KERN_ERR "comedi%d: insn timeout. No data.\n",
1315 dev->minor);
1316 up(&udfs->sem);
1317 return err;
1318 }
1319 }
1320
1321 for (i = 0; i < insn->n;) {
1322 err = usb_bulk_msg(udfs->usbdev,
1323 usb_rcvbulkpipe(udfs->usbdev, BULKINEP),
1324 udfs->transfer_buffer, SIZEINBUF,
1325 &actual_length, 10000);
1326 if (err < 0) {
1327 printk(KERN_ERR "comedi%d: insn data error: %d\n",
1328 dev->minor, err);
1329 up(&udfs->sem);
1330 return err;
1331 }
1332 n = actual_length / sizeof(uint16_t);
1333 if ((n % 16) != 0) {
1334 printk(KERN_ERR "comedi%d: insn data packet "
1335 "corrupted.\n", dev->minor);
1336 up(&udfs->sem);
1337 return -EINVAL;
1338 }
1339 for (j = chan; (j < n) && (i < insn->n); j = j + 16) {
1340 data[i] = ((uint16_t *) (udfs->transfer_buffer))[j];
1341 i++;
1342 }
1343 }
1344 up(&udfs->sem);
1345 return i;
1346}
1347
1348#define FIRMWARE_MAX_LEN 0x2000
1349
1350static int firmwareUpload(struct usbduxfastsub_s *usbduxfastsub,
1351 const u8 * firmwareBinary, int sizeFirmware)
1352{
1353 int ret;
1354 uint8_t *fwBuf;
1355
1356 if (!firmwareBinary)
1357 return 0;
1358
1359 if (sizeFirmware > FIRMWARE_MAX_LEN) {
1360 dev_err(&usbduxfastsub->interface->dev,
1361 "comedi_: usbduxfast firmware binary it too large for FX2.\n");
1362 return -ENOMEM;
1363 }
1364
1365
1366 fwBuf = kzalloc(sizeFirmware, GFP_KERNEL);
1367 if (!fwBuf) {
1368 dev_err(&usbduxfastsub->interface->dev,
1369 "comedi_: mem alloc for firmware failed\n");
1370 return -ENOMEM;
1371 }
1372 memcpy(fwBuf, firmwareBinary, sizeFirmware);
1373
1374 ret = usbduxfastsub_stop(usbduxfastsub);
1375 if (ret < 0) {
1376 dev_err(&usbduxfastsub->interface->dev,
1377 "comedi_: can not stop firmware\n");
1378 kfree(fwBuf);
1379 return ret;
1380 }
1381
1382 ret = usbduxfastsub_upload(usbduxfastsub, fwBuf, 0, sizeFirmware);
1383 if (ret < 0) {
1384 dev_err(&usbduxfastsub->interface->dev,
1385 "comedi_: firmware upload failed\n");
1386 kfree(fwBuf);
1387 return ret;
1388 }
1389 ret = usbduxfastsub_start(usbduxfastsub);
1390 if (ret < 0) {
1391 dev_err(&usbduxfastsub->interface->dev,
1392 "comedi_: can not start firmware\n");
1393 kfree(fwBuf);
1394 return ret;
1395 }
1396 kfree(fwBuf);
1397 return 0;
1398}
1399
1400static void tidy_up(struct usbduxfastsub_s *udfs)
1401{
1402#ifdef CONFIG_COMEDI_DEBUG
1403 printk(KERN_DEBUG "comedi_: usbduxfast: tiding up\n");
1404#endif
1405
1406 if (!udfs)
1407 return;
1408
1409
1410 if (udfs->interface)
1411 usb_set_intfdata(udfs->interface, NULL);
1412
1413 udfs->probed = 0;
1414
1415 if (udfs->urbIn) {
1416
1417 usb_kill_urb(udfs->urbIn);
1418
1419 kfree(udfs->transfer_buffer);
1420 udfs->transfer_buffer = NULL;
1421
1422 usb_free_urb(udfs->urbIn);
1423 udfs->urbIn = NULL;
1424 }
1425
1426 kfree(udfs->insnBuffer);
1427 udfs->insnBuffer = NULL;
1428
1429 kfree(udfs->dux_commands);
1430 udfs->dux_commands = NULL;
1431
1432 udfs->ai_cmd_running = 0;
1433}
1434
1435static void usbduxfast_firmware_request_complete_handler(const struct firmware
1436 *fw, void *context)
1437{
1438 struct usbduxfastsub_s *usbduxfastsub_tmp = context;
1439 struct usb_device *usbdev = usbduxfastsub_tmp->usbdev;
1440 int ret;
1441
1442 if (fw == NULL)
1443 return;
1444
1445
1446
1447
1448
1449 ret = firmwareUpload(usbduxfastsub_tmp, fw->data, fw->size);
1450
1451 if (ret) {
1452 dev_err(&usbdev->dev,
1453 "Could not upload firmware (err=%d)\n", ret);
1454 return;
1455 }
1456
1457 comedi_usb_auto_config(usbdev, BOARDNAME);
1458}
1459
1460
1461
1462
1463static int usbduxfastsub_probe(struct usb_interface *uinterf,
1464 const struct usb_device_id *id)
1465{
1466 struct usb_device *udev = interface_to_usbdev(uinterf);
1467 int i;
1468 int index;
1469 int ret;
1470
1471 if (udev->speed != USB_SPEED_HIGH) {
1472 printk(KERN_ERR "comedi_: usbduxfast_: This driver needs"
1473 "USB 2.0 to operate. Aborting...\n");
1474 return -ENODEV;
1475 }
1476#ifdef CONFIG_COMEDI_DEBUG
1477 printk(KERN_DEBUG "comedi_: usbduxfast_: finding a free structure for "
1478 "the usb-device\n");
1479#endif
1480 down(&start_stop_sem);
1481
1482 index = -1;
1483 for (i = 0; i < NUMUSBDUXFAST; i++) {
1484 if (!usbduxfastsub[i].probed) {
1485 index = i;
1486 break;
1487 }
1488 }
1489
1490
1491 if (index == -1) {
1492 printk(KERN_ERR "Too many usbduxfast-devices connected.\n");
1493 up(&start_stop_sem);
1494 return -EMFILE;
1495 }
1496#ifdef CONFIG_COMEDI_DEBUG
1497 printk(KERN_DEBUG "comedi_: usbduxfast: usbduxfastsub[%d] is ready to "
1498 "connect to comedi.\n", index);
1499#endif
1500
1501 init_MUTEX(&(usbduxfastsub[index].sem));
1502
1503 usbduxfastsub[index].usbdev = udev;
1504
1505
1506 usbduxfastsub[index].interface = uinterf;
1507
1508 usbduxfastsub[index].ifnum = uinterf->altsetting->desc.bInterfaceNumber;
1509
1510
1511
1512
1513 usb_set_intfdata(uinterf, &(usbduxfastsub[index]));
1514
1515#ifdef CONFIG_COMEDI_DEBUG
1516 printk(KERN_DEBUG "comedi_: usbduxfast: ifnum=%d\n",
1517 usbduxfastsub[index].ifnum);
1518#endif
1519
1520 usbduxfastsub[index].dux_commands = kmalloc(SIZEOFDUXBUFFER,
1521 GFP_KERNEL);
1522 if (!usbduxfastsub[index].dux_commands) {
1523 printk(KERN_ERR "comedi_: usbduxfast: error alloc space for "
1524 "dac commands\n");
1525 tidy_up(&(usbduxfastsub[index]));
1526 up(&start_stop_sem);
1527 return -ENOMEM;
1528 }
1529
1530 usbduxfastsub[index].insnBuffer = kmalloc(SIZEINSNBUF, GFP_KERNEL);
1531 if (!usbduxfastsub[index].insnBuffer) {
1532 printk(KERN_ERR "comedi_: usbduxfast: could not alloc space "
1533 "for insnBuffer\n");
1534 tidy_up(&(usbduxfastsub[index]));
1535 up(&start_stop_sem);
1536 return -ENOMEM;
1537 }
1538
1539 i = usb_set_interface(usbduxfastsub[index].usbdev,
1540 usbduxfastsub[index].ifnum, 1);
1541 if (i < 0) {
1542 printk(KERN_ERR "comedi_: usbduxfast%d: could not switch to "
1543 "alternate setting 1.\n", index);
1544 tidy_up(&(usbduxfastsub[index]));
1545 up(&start_stop_sem);
1546 return -ENODEV;
1547 }
1548 usbduxfastsub[index].urbIn = usb_alloc_urb(0, GFP_KERNEL);
1549 if (!usbduxfastsub[index].urbIn) {
1550 printk(KERN_ERR "comedi_: usbduxfast%d: Could not alloc."
1551 "urb\n", index);
1552 tidy_up(&(usbduxfastsub[index]));
1553 up(&start_stop_sem);
1554 return -ENOMEM;
1555 }
1556 usbduxfastsub[index].transfer_buffer = kmalloc(SIZEINBUF, GFP_KERNEL);
1557 if (!usbduxfastsub[index].transfer_buffer) {
1558 printk(KERN_ERR "comedi_: usbduxfast%d: could not alloc. "
1559 "transb.\n", index);
1560 tidy_up(&(usbduxfastsub[index]));
1561 up(&start_stop_sem);
1562 return -ENOMEM;
1563 }
1564
1565 usbduxfastsub[index].probed = 1;
1566 up(&start_stop_sem);
1567
1568 ret = request_firmware_nowait(THIS_MODULE,
1569 FW_ACTION_HOTPLUG,
1570 "usbduxfast_firmware.bin",
1571 &udev->dev,
1572 usbduxfastsub + index,
1573 usbduxfast_firmware_request_complete_handler);
1574
1575 if (ret) {
1576 dev_err(&udev->dev, "could not load firmware (err=%d)\n", ret);
1577 return ret;
1578 }
1579
1580 printk(KERN_INFO "comedi_: usbduxfast%d has been successfully "
1581 "initialized.\n", index);
1582
1583 return 0;
1584}
1585
1586static void usbduxfastsub_disconnect(struct usb_interface *intf)
1587{
1588 struct usbduxfastsub_s *udfs = usb_get_intfdata(intf);
1589 struct usb_device *udev = interface_to_usbdev(intf);
1590
1591 if (!udfs) {
1592 printk(KERN_ERR "comedi_: usbduxfast: disconnect called with "
1593 "null pointer.\n");
1594 return;
1595 }
1596 if (udfs->usbdev != udev) {
1597 printk(KERN_ERR "comedi_: usbduxfast: BUG! called with wrong "
1598 "ptr!!!\n");
1599 return;
1600 }
1601
1602 comedi_usb_auto_unconfig(udev);
1603
1604 down(&start_stop_sem);
1605 down(&udfs->sem);
1606 tidy_up(udfs);
1607 up(&udfs->sem);
1608 up(&start_stop_sem);
1609
1610#ifdef CONFIG_COMEDI_DEBUG
1611 printk(KERN_DEBUG "comedi_: usbduxfast: disconnected from the usb\n");
1612#endif
1613}
1614
1615
1616
1617
1618static int usbduxfast_attach(struct comedi_device *dev,
1619 struct comedi_devconfig *it)
1620{
1621 int ret;
1622 int index;
1623 int i;
1624 struct comedi_subdevice *s = NULL;
1625 dev->private = NULL;
1626
1627 down(&start_stop_sem);
1628
1629
1630
1631
1632 index = -1;
1633 for (i = 0; i < NUMUSBDUXFAST; i++) {
1634 if (usbduxfastsub[i].probed && !usbduxfastsub[i].attached) {
1635 index = i;
1636 break;
1637 }
1638 }
1639
1640 if (index < 0) {
1641 printk(KERN_ERR "comedi%d: usbduxfast: error: attach failed, "
1642 "no usbduxfast devs connected to the usb bus.\n",
1643 dev->minor);
1644 up(&start_stop_sem);
1645 return -ENODEV;
1646 }
1647
1648 down(&(usbduxfastsub[index].sem));
1649
1650 usbduxfastsub[index].comedidev = dev;
1651
1652
1653 if (comedi_aux_data(it->options, 0) &&
1654 it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
1655 firmwareUpload(&usbduxfastsub[index],
1656 comedi_aux_data(it->options, 0),
1657 it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]);
1658 }
1659
1660 dev->board_name = BOARDNAME;
1661
1662
1663 dev->n_subdevices = N_SUBDEVICES;
1664
1665
1666 ret = alloc_subdevices(dev, N_SUBDEVICES);
1667 if (ret < 0) {
1668 printk(KERN_ERR "comedi%d: usbduxfast: error alloc space for "
1669 "subdev\n", dev->minor);
1670 up(&(usbduxfastsub[index].sem));
1671 up(&start_stop_sem);
1672 return ret;
1673 }
1674
1675 printk(KERN_INFO "comedi%d: usbduxfast: usb-device %d is attached to "
1676 "comedi.\n", dev->minor, index);
1677
1678 dev->private = usbduxfastsub + index;
1679
1680 s = dev->subdevices + SUBDEV_AD;
1681
1682
1683
1684
1685 dev->read_subdev = s;
1686
1687 s->private = NULL;
1688
1689 s->type = COMEDI_SUBD_AI;
1690
1691 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
1692
1693 s->n_chan = 16;
1694
1695 s->len_chanlist = 16;
1696
1697 s->insn_read = usbduxfast_ai_insn_read;
1698 s->do_cmdtest = usbduxfast_ai_cmdtest;
1699 s->do_cmd = usbduxfast_ai_cmd;
1700 s->cancel = usbduxfast_ai_cancel;
1701
1702 s->maxdata = 0x1000;
1703
1704 s->range_table = &range_usbduxfast_ai_range;
1705
1706
1707 usbduxfastsub[index].attached = 1;
1708
1709 up(&(usbduxfastsub[index].sem));
1710 up(&start_stop_sem);
1711 printk(KERN_INFO "comedi%d: successfully attached to usbduxfast.\n",
1712 dev->minor);
1713
1714 return 0;
1715}
1716
1717static int usbduxfast_detach(struct comedi_device *dev)
1718{
1719 struct usbduxfastsub_s *udfs;
1720
1721 if (!dev) {
1722 printk(KERN_ERR "comedi?: usbduxfast: detach without dev "
1723 "variable...\n");
1724 return -EFAULT;
1725 }
1726#ifdef CONFIG_COMEDI_DEBUG
1727 printk(KERN_DEBUG "comedi%d: usbduxfast: detach usb device\n",
1728 dev->minor);
1729#endif
1730
1731 udfs = dev->private;
1732 if (!udfs) {
1733 printk(KERN_ERR "comedi?: usbduxfast: detach without ptr to "
1734 "usbduxfastsub[]\n");
1735 return -EFAULT;
1736 }
1737
1738 down(&udfs->sem);
1739 down(&start_stop_sem);
1740
1741
1742
1743
1744 dev->private = NULL;
1745 udfs->attached = 0;
1746 udfs->comedidev = NULL;
1747#ifdef CONFIG_COMEDI_DEBUG
1748 printk(KERN_DEBUG "comedi%d: usbduxfast: detach: successfully "
1749 "removed\n", dev->minor);
1750#endif
1751 up(&start_stop_sem);
1752 up(&udfs->sem);
1753 return 0;
1754}
1755
1756
1757
1758
1759static struct comedi_driver driver_usbduxfast = {
1760 .driver_name = "usbduxfast",
1761 .module = THIS_MODULE,
1762 .attach = usbduxfast_attach,
1763 .detach = usbduxfast_detach
1764};
1765
1766
1767
1768
1769static struct usb_device_id usbduxfastsub_table[] = {
1770
1771 {USB_DEVICE(0x13d8, 0x0010)},
1772 {USB_DEVICE(0x13d8, 0x0011)},
1773 {}
1774};
1775
1776MODULE_DEVICE_TABLE(usb, usbduxfastsub_table);
1777
1778
1779
1780
1781static struct usb_driver usbduxfastsub_driver = {
1782#ifdef COMEDI_HAVE_USB_DRIVER_OWNER
1783 .owner = THIS_MODULE,
1784#endif
1785 .name = BOARDNAME,
1786 .probe = usbduxfastsub_probe,
1787 .disconnect = usbduxfastsub_disconnect,
1788 .id_table = usbduxfastsub_table
1789};
1790
1791
1792
1793
1794
1795static int __init init_usbduxfast(void)
1796{
1797 printk(KERN_INFO
1798 KBUILD_MODNAME ": " DRIVER_VERSION ":" DRIVER_DESC "\n");
1799 usb_register(&usbduxfastsub_driver);
1800 comedi_driver_register(&driver_usbduxfast);
1801 return 0;
1802}
1803
1804
1805
1806
1807static void __exit exit_usbduxfast(void)
1808{
1809 comedi_driver_unregister(&driver_usbduxfast);
1810 usb_deregister(&usbduxfastsub_driver);
1811}
1812
1813module_init(init_usbduxfast);
1814module_exit(exit_usbduxfast);
1815
1816MODULE_AUTHOR(DRIVER_AUTHOR);
1817MODULE_DESCRIPTION(DRIVER_DESC);
1818MODULE_LICENSE("GPL");
1819