This source file includes following definitions.
- usbduxfast_send_cmd
- usbduxfast_cmd_data
- usbduxfast_ai_stop
- usbduxfast_ai_cancel
- usbduxfast_ai_handle_urb
- usbduxfast_ai_interrupt
- usbduxfast_submit_urb
- usbduxfast_ai_check_chanlist
- usbduxfast_ai_cmdtest
- usbduxfast_ai_inttrig
- usbduxfast_ai_cmd
- usbduxfast_ai_insn_read
- usbduxfast_upload_firmware
- usbduxfast_auto_attach
- usbduxfast_detach
- usbduxfast_usb_probe
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 #include <linux/kernel.h>
38 #include <linux/module.h>
39 #include <linux/slab.h>
40 #include <linux/input.h>
41 #include <linux/fcntl.h>
42 #include <linux/compiler.h>
43 #include "../comedi_usb.h"
44
45
46
47
48 #define EZTIMEOUT 30
49
50
51
52
53 #define FIRMWARE "usbduxfast_firmware.bin"
54 #define FIRMWARE_MAX_LEN 0x2000
55 #define USBDUXFASTSUB_FIRMWARE 0xA0
56 #define VENDOR_DIR_IN 0xC0
57 #define VENDOR_DIR_OUT 0x40
58
59
60
61
62 #define USBDUXFASTSUB_CPUCS 0xE600
63
64
65
66
67 #define TB_LEN 0x2000
68
69
70
71
72 #define BULKINEP 6
73
74
75
76
77 #define CHANNELLISTEP 4
78
79
80
81
82 #define NUMCHANNELS 32
83
84
85
86
87 #define WAVESIZE 0x20
88
89
90
91
92 #define SIZEADIN (sizeof(s16))
93
94
95
96
97 #define SIZEINBUF 512
98
99
100
101
102 #define SIZEINSNBUF 512
103
104
105
106
107 #define SIZEOFDUXBUF 256
108
109
110
111
112 #define NUMOFINBUFFERSHIGH 10
113
114
115
116
117
118
119
120 #define MIN_SAMPLING_PERIOD 9
121
122
123
124
125 #define MAX_SAMPLING_PERIOD 500
126
127
128
129
130
131 #define PACKETS_TO_IGNORE 4
132
133
134
135
136 static const struct comedi_lrange range_usbduxfast_ai_range = {
137 2, {
138 BIP_RANGE(0.75),
139 BIP_RANGE(0.5)
140 }
141 };
142
143
144
145
146
147
148
149 struct usbduxfast_private {
150 struct urb *urb;
151 u8 *duxbuf;
152 s8 *inbuf;
153 short int ai_cmd_running;
154 int ignore;
155 struct mutex mut;
156 };
157
158
159
160
161 #define SENDADCOMMANDS 0
162 #define SENDINITEP6 1
163
164 static int usbduxfast_send_cmd(struct comedi_device *dev, int cmd_type)
165 {
166 struct usb_device *usb = comedi_to_usb_dev(dev);
167 struct usbduxfast_private *devpriv = dev->private;
168 int nsent;
169 int ret;
170
171 devpriv->duxbuf[0] = cmd_type;
172
173 ret = usb_bulk_msg(usb, usb_sndbulkpipe(usb, CHANNELLISTEP),
174 devpriv->duxbuf, SIZEOFDUXBUF,
175 &nsent, 10000);
176 if (ret < 0)
177 dev_err(dev->class_dev,
178 "could not transmit command to the usb-device, err=%d\n",
179 ret);
180 return ret;
181 }
182
183 static void usbduxfast_cmd_data(struct comedi_device *dev, int index,
184 u8 len, u8 op, u8 out, u8 log)
185 {
186 struct usbduxfast_private *devpriv = dev->private;
187
188
189 devpriv->duxbuf[1 + 0x00 + index] = len;
190 devpriv->duxbuf[1 + 0x08 + index] = op;
191 devpriv->duxbuf[1 + 0x10 + index] = out;
192 devpriv->duxbuf[1 + 0x18 + index] = log;
193 }
194
195 static int usbduxfast_ai_stop(struct comedi_device *dev, int do_unlink)
196 {
197 struct usbduxfast_private *devpriv = dev->private;
198
199
200 devpriv->ai_cmd_running = 0;
201
202 if (do_unlink && devpriv->urb) {
203
204 usb_kill_urb(devpriv->urb);
205 }
206
207 return 0;
208 }
209
210 static int usbduxfast_ai_cancel(struct comedi_device *dev,
211 struct comedi_subdevice *s)
212 {
213 struct usbduxfast_private *devpriv = dev->private;
214 int ret;
215
216 mutex_lock(&devpriv->mut);
217 ret = usbduxfast_ai_stop(dev, 1);
218 mutex_unlock(&devpriv->mut);
219
220 return ret;
221 }
222
223 static void usbduxfast_ai_handle_urb(struct comedi_device *dev,
224 struct comedi_subdevice *s,
225 struct urb *urb)
226 {
227 struct usbduxfast_private *devpriv = dev->private;
228 struct comedi_async *async = s->async;
229 struct comedi_cmd *cmd = &async->cmd;
230 int ret;
231
232 if (devpriv->ignore) {
233 devpriv->ignore--;
234 } else {
235 unsigned int nsamples;
236
237 nsamples = comedi_bytes_to_samples(s, urb->actual_length);
238 nsamples = comedi_nsamples_left(s, nsamples);
239 comedi_buf_write_samples(s, urb->transfer_buffer, nsamples);
240
241 if (cmd->stop_src == TRIG_COUNT &&
242 async->scans_done >= cmd->stop_arg)
243 async->events |= COMEDI_CB_EOA;
244 }
245
246
247 if (!(async->events & COMEDI_CB_CANCEL_MASK)) {
248 urb->dev = comedi_to_usb_dev(dev);
249 urb->status = 0;
250 ret = usb_submit_urb(urb, GFP_ATOMIC);
251 if (ret < 0) {
252 dev_err(dev->class_dev, "urb resubm failed: %d", ret);
253 async->events |= COMEDI_CB_ERROR;
254 }
255 }
256 }
257
258 static void usbduxfast_ai_interrupt(struct urb *urb)
259 {
260 struct comedi_device *dev = urb->context;
261 struct comedi_subdevice *s = dev->read_subdev;
262 struct comedi_async *async = s->async;
263 struct usbduxfast_private *devpriv = dev->private;
264
265
266 if (!devpriv->ai_cmd_running)
267 return;
268
269 switch (urb->status) {
270 case 0:
271 usbduxfast_ai_handle_urb(dev, s, urb);
272 break;
273
274 case -ECONNRESET:
275 case -ENOENT:
276 case -ESHUTDOWN:
277 case -ECONNABORTED:
278
279 async->events |= COMEDI_CB_ERROR;
280 break;
281
282 default:
283
284 dev_err(dev->class_dev,
285 "non-zero urb status received in ai intr context: %d\n",
286 urb->status);
287 async->events |= COMEDI_CB_ERROR;
288 break;
289 }
290
291
292
293
294
295 if (async->events & COMEDI_CB_CANCEL_MASK)
296 usbduxfast_ai_stop(dev, 0);
297
298 comedi_event(dev, s);
299 }
300
301 static int usbduxfast_submit_urb(struct comedi_device *dev)
302 {
303 struct usb_device *usb = comedi_to_usb_dev(dev);
304 struct usbduxfast_private *devpriv = dev->private;
305 int ret;
306
307 usb_fill_bulk_urb(devpriv->urb, usb, usb_rcvbulkpipe(usb, BULKINEP),
308 devpriv->inbuf, SIZEINBUF,
309 usbduxfast_ai_interrupt, dev);
310
311 ret = usb_submit_urb(devpriv->urb, GFP_ATOMIC);
312 if (ret) {
313 dev_err(dev->class_dev, "usb_submit_urb error %d\n", ret);
314 return ret;
315 }
316 return 0;
317 }
318
319 static int usbduxfast_ai_check_chanlist(struct comedi_device *dev,
320 struct comedi_subdevice *s,
321 struct comedi_cmd *cmd)
322 {
323 unsigned int gain0 = CR_RANGE(cmd->chanlist[0]);
324 int i;
325
326 if (cmd->chanlist_len > 3 && cmd->chanlist_len != 16) {
327 dev_err(dev->class_dev, "unsupported combination of channels\n");
328 return -EINVAL;
329 }
330
331 for (i = 0; i < cmd->chanlist_len; ++i) {
332 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
333 unsigned int gain = CR_RANGE(cmd->chanlist[i]);
334
335 if (chan != i) {
336 dev_err(dev->class_dev,
337 "channels are not consecutive\n");
338 return -EINVAL;
339 }
340 if (gain != gain0 && cmd->chanlist_len > 3) {
341 dev_err(dev->class_dev,
342 "gain must be the same for all channels\n");
343 return -EINVAL;
344 }
345 }
346 return 0;
347 }
348
349 static int usbduxfast_ai_cmdtest(struct comedi_device *dev,
350 struct comedi_subdevice *s,
351 struct comedi_cmd *cmd)
352 {
353 int err = 0;
354 int err2 = 0;
355 unsigned int steps;
356 unsigned int arg;
357
358
359
360 err |= comedi_check_trigger_src(&cmd->start_src,
361 TRIG_NOW | TRIG_EXT | TRIG_INT);
362 err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
363 err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
364 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
365 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
366
367 if (err)
368 return 1;
369
370
371
372 err |= comedi_check_trigger_is_unique(cmd->start_src);
373 err |= comedi_check_trigger_is_unique(cmd->stop_src);
374
375
376
377 if (err)
378 return 2;
379
380
381
382 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
383
384 if (!cmd->chanlist_len)
385 err |= -EINVAL;
386
387
388 if (cmd->start_src == TRIG_EXT &&
389 cmd->chanlist_len != 1 && cmd->chanlist_len != 16)
390 err |= -EINVAL;
391
392 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
393 cmd->chanlist_len);
394
395
396
397
398
399
400
401
402 steps = (cmd->convert_arg * 30) / 1000;
403 if (cmd->chanlist_len != 1)
404 err2 |= comedi_check_trigger_arg_min(&steps,
405 MIN_SAMPLING_PERIOD);
406 else
407 err2 |= comedi_check_trigger_arg_min(&steps, 1);
408 err2 |= comedi_check_trigger_arg_max(&steps, MAX_SAMPLING_PERIOD);
409 if (err2) {
410 err |= err2;
411 arg = (steps * 1000) / 30;
412 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
413 }
414
415 if (cmd->stop_src == TRIG_COUNT)
416 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
417 else
418 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
419
420 if (err)
421 return 3;
422
423
424
425
426 if (cmd->chanlist && cmd->chanlist_len > 0)
427 err |= usbduxfast_ai_check_chanlist(dev, s, cmd);
428 if (err)
429 return 5;
430
431 return 0;
432 }
433
434 static int usbduxfast_ai_inttrig(struct comedi_device *dev,
435 struct comedi_subdevice *s,
436 unsigned int trig_num)
437 {
438 struct usbduxfast_private *devpriv = dev->private;
439 struct comedi_cmd *cmd = &s->async->cmd;
440 int ret;
441
442 if (trig_num != cmd->start_arg)
443 return -EINVAL;
444
445 mutex_lock(&devpriv->mut);
446
447 if (!devpriv->ai_cmd_running) {
448 devpriv->ai_cmd_running = 1;
449 ret = usbduxfast_submit_urb(dev);
450 if (ret < 0) {
451 dev_err(dev->class_dev, "urbSubmit: err=%d\n", ret);
452 devpriv->ai_cmd_running = 0;
453 mutex_unlock(&devpriv->mut);
454 return ret;
455 }
456 s->async->inttrig = NULL;
457 } else {
458 dev_err(dev->class_dev, "ai is already running\n");
459 }
460 mutex_unlock(&devpriv->mut);
461 return 1;
462 }
463
464 static int usbduxfast_ai_cmd(struct comedi_device *dev,
465 struct comedi_subdevice *s)
466 {
467 struct usbduxfast_private *devpriv = dev->private;
468 struct comedi_cmd *cmd = &s->async->cmd;
469 unsigned int rngmask = 0xff;
470 int j, ret;
471 long steps, steps_tmp;
472
473 mutex_lock(&devpriv->mut);
474 if (devpriv->ai_cmd_running) {
475 ret = -EBUSY;
476 goto cmd_exit;
477 }
478
479
480
481
482
483 devpriv->ignore = PACKETS_TO_IGNORE;
484
485 steps = (cmd->convert_arg * 30) / 1000;
486
487 switch (cmd->chanlist_len) {
488 case 1:
489
490
491
492
493 if (CR_RANGE(cmd->chanlist[0]) > 0)
494 rngmask = 0xff - 0x04;
495 else
496 rngmask = 0xff;
497
498
499
500
501
502
503
504 if (cmd->start_src == TRIG_EXT) {
505
506
507
508 usbduxfast_cmd_data(dev, 0, 0x01, 0x01, rngmask, 0x00);
509 } else {
510 usbduxfast_cmd_data(dev, 0, 0x01, 0x00, rngmask, 0x00);
511 }
512
513 if (steps < MIN_SAMPLING_PERIOD) {
514
515 if (steps <= 1) {
516
517
518
519
520
521
522
523
524
525 usbduxfast_cmd_data(dev, 1,
526 0x89, 0x03, rngmask, 0xff);
527 } else {
528
529
530
531
532
533
534 usbduxfast_cmd_data(dev, 1, steps - 1,
535 0x02, rngmask, 0x00);
536
537
538
539
540 usbduxfast_cmd_data(dev, 2,
541 0x09, 0x01, rngmask, 0xff);
542 }
543 } else {
544
545
546
547
548
549
550 steps = steps - 1;
551
552
553 usbduxfast_cmd_data(dev, 1,
554 steps / 2, 0x00, rngmask, 0x00);
555
556
557 usbduxfast_cmd_data(dev, 2, steps - steps / 2,
558 0x00, rngmask, 0x00);
559
560
561
562
563
564
565 usbduxfast_cmd_data(dev, 3,
566 0x09, 0x03, rngmask, 0xff);
567 }
568 break;
569
570 case 2:
571
572
573
574
575
576 if (CR_RANGE(cmd->chanlist[0]) > 0)
577 rngmask = 0xff - 0x04;
578 else
579 rngmask = 0xff;
580
581
582 usbduxfast_cmd_data(dev, 0, 0x01, 0x02, rngmask, 0x00);
583
584
585 steps_tmp = steps - 1;
586
587 if (CR_RANGE(cmd->chanlist[1]) > 0)
588 rngmask = 0xff - 0x04;
589 else
590 rngmask = 0xff;
591
592
593
594 usbduxfast_cmd_data(dev, 1, steps_tmp / 2,
595 0x00, 0xfe & rngmask, 0x00);
596
597
598 usbduxfast_cmd_data(dev, 2, steps_tmp - steps_tmp / 2,
599 0x00, rngmask, 0x00);
600
601
602 usbduxfast_cmd_data(dev, 3, 0x01, 0x02, rngmask, 0x00);
603
604
605
606
607
608 steps_tmp = steps - 2;
609
610 if (CR_RANGE(cmd->chanlist[0]) > 0)
611 rngmask = 0xff - 0x04;
612 else
613 rngmask = 0xff;
614
615
616
617 usbduxfast_cmd_data(dev, 4, steps_tmp / 2,
618 0x00, (0xff - 0x02) & rngmask, 0x00);
619
620
621 usbduxfast_cmd_data(dev, 5, steps_tmp - steps_tmp / 2,
622 0x00, rngmask, 0x00);
623
624 usbduxfast_cmd_data(dev, 6, 0x01, 0x00, rngmask, 0x00);
625 break;
626
627 case 3:
628
629
630
631 for (j = 0; j < 1; j++) {
632 int index = j * 2;
633
634 if (CR_RANGE(cmd->chanlist[j]) > 0)
635 rngmask = 0xff - 0x04;
636 else
637 rngmask = 0xff;
638
639
640
641
642
643
644 usbduxfast_cmd_data(dev, index, steps / 2,
645 0x02, rngmask, 0x00);
646
647 if (CR_RANGE(cmd->chanlist[j + 1]) > 0)
648 rngmask = 0xff - 0x04;
649 else
650 rngmask = 0xff;
651
652
653
654
655 usbduxfast_cmd_data(dev, index + 1, steps - steps / 2,
656 0x00, 0xfe & rngmask, 0x00);
657 }
658
659
660 steps_tmp = steps - 2;
661
662
663
664 usbduxfast_cmd_data(dev, 4, steps_tmp / 2,
665 0x02, rngmask, 0x00);
666
667 if (CR_RANGE(cmd->chanlist[0]) > 0)
668 rngmask = 0xff - 0x04;
669 else
670 rngmask = 0xff;
671
672
673
674
675 usbduxfast_cmd_data(dev, 5, steps_tmp - steps_tmp / 2,
676 0x00, (0xff - 0x02) & rngmask, 0x00);
677
678 usbduxfast_cmd_data(dev, 6, 0x01, 0x00, rngmask, 0x00);
679 break;
680
681 case 16:
682 if (CR_RANGE(cmd->chanlist[0]) > 0)
683 rngmask = 0xff - 0x04;
684 else
685 rngmask = 0xff;
686
687 if (cmd->start_src == TRIG_EXT) {
688
689
690
691
692
693
694
695
696 usbduxfast_cmd_data(dev, 0, 0x01, 0x01,
697 (0xff - 0x02) & rngmask, 0x00);
698 } else {
699
700
701
702
703
704
705 usbduxfast_cmd_data(dev, 0, 0xff, 0x00,
706 (0xff - 0x02) & rngmask, 0x00);
707 }
708
709
710
711 usbduxfast_cmd_data(dev, 1, 0x01, 0x02, rngmask, 0x00);
712
713
714 steps = steps - 2;
715
716
717 usbduxfast_cmd_data(dev, 2, steps / 2,
718 0x00, 0xfe & rngmask, 0x00);
719
720
721 usbduxfast_cmd_data(dev, 3, steps - steps / 2,
722 0x00, rngmask, 0x00);
723
724
725
726
727 usbduxfast_cmd_data(dev, 4, 0x09, 0x01, rngmask, 0xff);
728
729 break;
730 }
731
732
733 ret = usbduxfast_send_cmd(dev, SENDADCOMMANDS);
734 if (ret < 0)
735 goto cmd_exit;
736
737 if ((cmd->start_src == TRIG_NOW) || (cmd->start_src == TRIG_EXT)) {
738
739 devpriv->ai_cmd_running = 1;
740 ret = usbduxfast_submit_urb(dev);
741 if (ret < 0) {
742 devpriv->ai_cmd_running = 0;
743
744 goto cmd_exit;
745 }
746 s->async->inttrig = NULL;
747 } else {
748 s->async->inttrig = usbduxfast_ai_inttrig;
749 }
750
751 cmd_exit:
752 mutex_unlock(&devpriv->mut);
753
754 return ret;
755 }
756
757
758
759
760 static int usbduxfast_ai_insn_read(struct comedi_device *dev,
761 struct comedi_subdevice *s,
762 struct comedi_insn *insn,
763 unsigned int *data)
764 {
765 struct usb_device *usb = comedi_to_usb_dev(dev);
766 struct usbduxfast_private *devpriv = dev->private;
767 unsigned int chan = CR_CHAN(insn->chanspec);
768 unsigned int range = CR_RANGE(insn->chanspec);
769 u8 rngmask = range ? (0xff - 0x04) : 0xff;
770 int i, j, n, actual_length;
771 int ret;
772
773 mutex_lock(&devpriv->mut);
774
775 if (devpriv->ai_cmd_running) {
776 dev_err(dev->class_dev,
777 "ai_insn_read not possible, async cmd is running\n");
778 mutex_unlock(&devpriv->mut);
779 return -EBUSY;
780 }
781
782
783
784
785
786 usbduxfast_cmd_data(dev, 0, 0x01, 0x02, rngmask, 0x00);
787
788
789 usbduxfast_cmd_data(dev, 1, 0x0c, 0x00, 0xfe & rngmask, 0x00);
790 usbduxfast_cmd_data(dev, 2, 0x01, 0x00, 0xfe & rngmask, 0x00);
791 usbduxfast_cmd_data(dev, 3, 0x01, 0x00, 0xfe & rngmask, 0x00);
792 usbduxfast_cmd_data(dev, 4, 0x01, 0x00, 0xfe & rngmask, 0x00);
793
794
795 usbduxfast_cmd_data(dev, 5, 0x0c, 0x00, rngmask, 0x00);
796 usbduxfast_cmd_data(dev, 6, 0x01, 0x00, rngmask, 0x00);
797
798 ret = usbduxfast_send_cmd(dev, SENDADCOMMANDS);
799 if (ret < 0) {
800 mutex_unlock(&devpriv->mut);
801 return ret;
802 }
803
804 for (i = 0; i < PACKETS_TO_IGNORE; i++) {
805 ret = usb_bulk_msg(usb, usb_rcvbulkpipe(usb, BULKINEP),
806 devpriv->inbuf, SIZEINBUF,
807 &actual_length, 10000);
808 if (ret < 0) {
809 dev_err(dev->class_dev, "insn timeout, no data\n");
810 mutex_unlock(&devpriv->mut);
811 return ret;
812 }
813 }
814
815 for (i = 0; i < insn->n;) {
816 ret = usb_bulk_msg(usb, usb_rcvbulkpipe(usb, BULKINEP),
817 devpriv->inbuf, SIZEINBUF,
818 &actual_length, 10000);
819 if (ret < 0) {
820 dev_err(dev->class_dev, "insn data error: %d\n", ret);
821 mutex_unlock(&devpriv->mut);
822 return ret;
823 }
824 n = actual_length / sizeof(u16);
825 if ((n % 16) != 0) {
826 dev_err(dev->class_dev, "insn data packet corrupted\n");
827 mutex_unlock(&devpriv->mut);
828 return -EINVAL;
829 }
830 for (j = chan; (j < n) && (i < insn->n); j = j + 16) {
831 data[i] = ((u16 *)(devpriv->inbuf))[j];
832 i++;
833 }
834 }
835
836 mutex_unlock(&devpriv->mut);
837
838 return insn->n;
839 }
840
841 static int usbduxfast_upload_firmware(struct comedi_device *dev,
842 const u8 *data, size_t size,
843 unsigned long context)
844 {
845 struct usb_device *usb = comedi_to_usb_dev(dev);
846 u8 *buf;
847 unsigned char *tmp;
848 int ret;
849
850 if (!data)
851 return 0;
852
853 if (size > FIRMWARE_MAX_LEN) {
854 dev_err(dev->class_dev, "firmware binary too large for FX2\n");
855 return -ENOMEM;
856 }
857
858
859 buf = kmemdup(data, size, GFP_KERNEL);
860 if (!buf)
861 return -ENOMEM;
862
863
864 tmp = kmalloc(1, GFP_KERNEL);
865 if (!tmp) {
866 kfree(buf);
867 return -ENOMEM;
868 }
869
870
871 *tmp = 1;
872 ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0),
873 USBDUXFASTSUB_FIRMWARE,
874 VENDOR_DIR_OUT,
875 USBDUXFASTSUB_CPUCS, 0x0000,
876 tmp, 1,
877 EZTIMEOUT);
878 if (ret < 0) {
879 dev_err(dev->class_dev, "can not stop firmware\n");
880 goto done;
881 }
882
883
884 ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0),
885 USBDUXFASTSUB_FIRMWARE,
886 VENDOR_DIR_OUT,
887 0, 0x0000,
888 buf, size,
889 EZTIMEOUT);
890 if (ret < 0) {
891 dev_err(dev->class_dev, "firmware upload failed\n");
892 goto done;
893 }
894
895
896 *tmp = 0;
897 ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0),
898 USBDUXFASTSUB_FIRMWARE,
899 VENDOR_DIR_OUT,
900 USBDUXFASTSUB_CPUCS, 0x0000,
901 tmp, 1,
902 EZTIMEOUT);
903 if (ret < 0)
904 dev_err(dev->class_dev, "can not start firmware\n");
905
906 done:
907 kfree(tmp);
908 kfree(buf);
909 return ret;
910 }
911
912 static int usbduxfast_auto_attach(struct comedi_device *dev,
913 unsigned long context_unused)
914 {
915 struct usb_interface *intf = comedi_to_usb_interface(dev);
916 struct usb_device *usb = comedi_to_usb_dev(dev);
917 struct usbduxfast_private *devpriv;
918 struct comedi_subdevice *s;
919 int ret;
920
921 if (usb->speed != USB_SPEED_HIGH) {
922 dev_err(dev->class_dev,
923 "This driver needs USB 2.0 to operate. Aborting...\n");
924 return -ENODEV;
925 }
926
927 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
928 if (!devpriv)
929 return -ENOMEM;
930
931 mutex_init(&devpriv->mut);
932 usb_set_intfdata(intf, devpriv);
933
934 devpriv->duxbuf = kmalloc(SIZEOFDUXBUF, GFP_KERNEL);
935 if (!devpriv->duxbuf)
936 return -ENOMEM;
937
938 ret = usb_set_interface(usb,
939 intf->altsetting->desc.bInterfaceNumber, 1);
940 if (ret < 0) {
941 dev_err(dev->class_dev,
942 "could not switch to alternate setting 1\n");
943 return -ENODEV;
944 }
945
946 devpriv->urb = usb_alloc_urb(0, GFP_KERNEL);
947 if (!devpriv->urb)
948 return -ENOMEM;
949
950 devpriv->inbuf = kmalloc(SIZEINBUF, GFP_KERNEL);
951 if (!devpriv->inbuf)
952 return -ENOMEM;
953
954 ret = comedi_load_firmware(dev, &usb->dev, FIRMWARE,
955 usbduxfast_upload_firmware, 0);
956 if (ret)
957 return ret;
958
959 ret = comedi_alloc_subdevices(dev, 1);
960 if (ret)
961 return ret;
962
963
964 s = &dev->subdevices[0];
965 dev->read_subdev = s;
966 s->type = COMEDI_SUBD_AI;
967 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
968 s->n_chan = 16;
969 s->maxdata = 0x1000;
970 s->range_table = &range_usbduxfast_ai_range;
971 s->insn_read = usbduxfast_ai_insn_read;
972 s->len_chanlist = s->n_chan;
973 s->do_cmdtest = usbduxfast_ai_cmdtest;
974 s->do_cmd = usbduxfast_ai_cmd;
975 s->cancel = usbduxfast_ai_cancel;
976
977 return 0;
978 }
979
980 static void usbduxfast_detach(struct comedi_device *dev)
981 {
982 struct usb_interface *intf = comedi_to_usb_interface(dev);
983 struct usbduxfast_private *devpriv = dev->private;
984
985 if (!devpriv)
986 return;
987
988 mutex_lock(&devpriv->mut);
989
990 usb_set_intfdata(intf, NULL);
991
992 if (devpriv->urb) {
993
994 usb_kill_urb(devpriv->urb);
995
996 kfree(devpriv->inbuf);
997 usb_free_urb(devpriv->urb);
998 }
999
1000 kfree(devpriv->duxbuf);
1001
1002 mutex_unlock(&devpriv->mut);
1003
1004 mutex_destroy(&devpriv->mut);
1005 }
1006
1007 static struct comedi_driver usbduxfast_driver = {
1008 .driver_name = "usbduxfast",
1009 .module = THIS_MODULE,
1010 .auto_attach = usbduxfast_auto_attach,
1011 .detach = usbduxfast_detach,
1012 };
1013
1014 static int usbduxfast_usb_probe(struct usb_interface *intf,
1015 const struct usb_device_id *id)
1016 {
1017 return comedi_usb_auto_config(intf, &usbduxfast_driver, 0);
1018 }
1019
1020 static const struct usb_device_id usbduxfast_usb_table[] = {
1021
1022 { USB_DEVICE(0x13d8, 0x0010) },
1023 { USB_DEVICE(0x13d8, 0x0011) },
1024 { }
1025 };
1026 MODULE_DEVICE_TABLE(usb, usbduxfast_usb_table);
1027
1028 static struct usb_driver usbduxfast_usb_driver = {
1029 .name = "usbduxfast",
1030 .probe = usbduxfast_usb_probe,
1031 .disconnect = comedi_usb_auto_unconfig,
1032 .id_table = usbduxfast_usb_table,
1033 };
1034 module_comedi_usb_driver(usbduxfast_driver, usbduxfast_usb_driver);
1035
1036 MODULE_AUTHOR("Bernd Porr, BerndPorr@f2s.com");
1037 MODULE_DESCRIPTION("USB-DUXfast, BerndPorr@f2s.com");
1038 MODULE_LICENSE("GPL");
1039 MODULE_FIRMWARE(FIRMWARE);