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