3ad3a08c3c20e47eb34c256760967683b8a0cade
[pandora-kernel.git] / drivers / staging / comedi / drivers / usbduxfast.c
1 #define DRIVER_VERSION "v0.99a"
2 #define DRIVER_AUTHOR "Bernd Porr, BerndPorr@f2s.com"
3 #define DRIVER_DESC "USB-DUXfast, BerndPorr@f2s.com"
4 /*
5    comedi/drivers/usbduxfast.c
6    Copyright (C) 2004 Bernd Porr, Bernd.Porr@f2s.com
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 /*
24 Driver: usbduxfast
25 Description: ITL USB-DUXfast
26 Devices: [ITL] USB-DUX (usbduxfast.o)
27 Author: Bernd Porr <BerndPorr@f2s.com>
28 Updated: 04 Dec 2006
29 Status: testing
30 */
31
32 /*
33  * I must give credit here to Chris Baugher who
34  * wrote the driver for AT-MIO-16d. I used some parts of this
35  * driver. I also must give credits to David Brownell
36  * who supported me with the USB development.
37  *
38  * Bernd Porr
39  *
40  *
41  * Revision history:
42  * 0.9: Dropping the first data packet which seems to be from the last transfer.
43  *      Buffer overflows in the FX2 are handed over to comedi.
44  * 0.92: Dropping now 4 packets. The quad buffer has to be emptied.
45  *       Added insn command basically for testing. Sample rate is 1MHz/16ch=62.5kHz
46  * 0.99: Ian Abbott pointed out a bug which has been corrected. Thanks!
47  * 0.99a: added external trigger.
48  */
49
50 #include <linux/kernel.h>
51 #include <linux/module.h>
52 #include <linux/init.h>
53 #include <linux/slab.h>
54 #include <linux/input.h>
55 #include <linux/usb.h>
56 #include <linux/smp_lock.h>
57 #include <linux/fcntl.h>
58 #include <linux/compiler.h>
59 #include "comedi_fc.h"
60 #include "../comedidev.h"
61
62 // (un)comment this if you want to have debug info.
63 //#define CONFIG_COMEDI_DEBUG
64 #undef  CONFIG_COMEDI_DEBUG
65
66 #define BOARDNAME "usbduxfast"
67
68 // timeout for the USB-transfer
69 #define EZTIMEOUT 30
70
71 // constants for "firmware" upload and download
72 #define USBDUXFASTSUB_FIRMWARE 0xA0
73 #define VENDOR_DIR_IN  0xC0
74 #define VENDOR_DIR_OUT 0x40
75
76 // internal adresses of the 8051 processor
77 #define USBDUXFASTSUB_CPUCS 0xE600
78
79 // max lenghth of the transfer-buffer for software upload
80 #define TB_LEN 0x2000
81
82 // Input endpoint number
83 #define BULKINEP           6
84
85 // Endpoint for the A/D channellist: bulk OUT
86 #define CHANNELLISTEP     4
87
88 // Number of channels
89 #define NUMCHANNELS       32
90
91 // size of the waveform descriptor
92 #define WAVESIZE          0x20
93
94 // Size of one A/D value
95 #define SIZEADIN          ((sizeof(int16_t)))
96
97 // Size of the input-buffer IN BYTES
98 #define SIZEINBUF         512
99
100 // 16 bytes.
101 #define SIZEINSNBUF       512
102
103 // Size of the buffer for the dux commands
104 #define SIZEOFDUXBUFFER    256  // bytes
105
106 // Number of in-URBs which receive the data: min=5
107 #define NUMOFINBUFFERSHIGH     10
108
109 // Total number of usbduxfast devices
110 #define NUMUSBDUXFAST             16
111
112 // Number of subdevices
113 #define N_SUBDEVICES          1
114
115 // Analogue in subdevice
116 #define SUBDEV_AD             0
117
118 // min delay steps for more than one channel
119 // basically when the mux gives up. ;-)
120 #define MIN_SAMPLING_PERIOD 9   // steps at 30MHz in the FX2
121
122 // Max number of 1/30MHz delay steps:
123 #define MAX_SAMPLING_PERIOD 500
124
125 // Number of received packets to ignore before we start handing data over to comedi.
126 // It's quad buffering and we have to ignore 4 packets.
127 #define PACKETS_TO_IGNORE 4
128
129 /////////////////////////////////////////////
130 // comedi constants
131 static const comedi_lrange range_usbduxfast_ai_range = { 2, {
132                         BIP_RANGE(0.75),
133                         BIP_RANGE(0.5),
134         }
135 };
136
137 /*
138  * private structure of one subdevice
139  */
140
141 // This is the structure which holds all the data of this driver
142 // one sub device just now: A/D
143 typedef struct {
144         // attached?
145         int attached;
146         // is it associated with a subdevice?
147         int probed;
148         // pointer to the usb-device
149         struct usb_device *usbdev;
150         // BULK-transfer handling: urb
151         struct urb *urbIn;
152         int8_t *transfer_buffer;
153         // input buffer for single insn
154         int16_t *insnBuffer;
155         // interface number
156         int ifnum;
157 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
158         // interface structure in 2.6
159         struct usb_interface *interface;
160 #endif
161         // comedi device for the interrupt context
162         comedi_device *comedidev;
163         // asynchronous command is running
164         short int ai_cmd_running;
165         // continous aquisition
166         short int ai_continous;
167         // number of samples to aquire
168         long int ai_sample_count;
169         // commands
170         uint8_t *dux_commands;
171         // counter which ignores the first buffers
172         int ignore;
173         struct semaphore sem;
174 } usbduxfastsub_t;
175
176 // The pointer to the private usb-data of the driver
177 // is also the private data for the comedi-device.
178 // This has to be global as the usb subsystem needs
179 // global variables. The other reason is that this
180 // structure must be there _before_ any comedi
181 // command is issued. The usb subsystem must be
182 // initialised before comedi can access it.
183 static usbduxfastsub_t usbduxfastsub[NUMUSBDUXFAST];
184
185 static DECLARE_MUTEX(start_stop_sem);
186
187 // bulk transfers to usbduxfast
188
189 #define SENDADCOMMANDS            0
190 #define SENDINITEP6               1
191
192 static int send_dux_commands(usbduxfastsub_t * this_usbduxfastsub, int cmd_type)
193 {
194         int result, nsent;
195         this_usbduxfastsub->dux_commands[0] = cmd_type;
196 #ifdef CONFIG_COMEDI_DEBUG
197         int i;
198         printk("comedi%d: usbduxfast: dux_commands: ",
199                 this_usbduxfastsub->comedidev->minor);
200         for (i = 0; i < SIZEOFDUXBUFFER; i++) {
201                 printk(" %02x", this_usbduxfastsub->dux_commands[i]);
202         }
203         printk("\n");
204 #endif
205         result = usb_bulk_msg(this_usbduxfastsub->usbdev,
206                               usb_sndbulkpipe(this_usbduxfastsub->usbdev,
207                                               CHANNELLISTEP),
208                               this_usbduxfastsub->dux_commands, SIZEOFDUXBUFFER,
209                               &nsent, 10000);
210         if (result < 0) {
211                 printk("comedi%d: could not transmit dux_commands to the usb-device, err=%d\n", this_usbduxfastsub->comedidev->minor, result);
212         }
213         return result;
214 }
215
216 // Stops the data acquision
217 // It should be safe to call this function from any context
218 static int usbduxfastsub_unlink_InURBs(usbduxfastsub_t * usbduxfastsub_tmp)
219 {
220         int j = 0;
221         int err = 0;
222
223         if (usbduxfastsub_tmp && usbduxfastsub_tmp->urbIn) {
224                 usbduxfastsub_tmp->ai_cmd_running = 0;
225 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8)
226                 j = usb_unlink_urb(usbduxfastsub_tmp->urbIn);
227                 if (j < 0) {
228                         err = j;
229                 }
230 #else
231                 // waits until a running transfer is over
232                 usb_kill_urb(usbduxfastsub_tmp->urbIn);
233                 j = 0;
234 #endif
235         }
236 #ifdef CONFIG_COMEDI_DEBUG
237         printk("comedi: usbduxfast: unlinked InURB: res=%d\n", j);
238 #endif
239         return err;
240 }
241
242 /* This will stop a running acquisition operation */
243 // Is called from within this driver from both the
244 // interrupt context and from comedi
245 static int usbduxfast_ai_stop(usbduxfastsub_t * this_usbduxfastsub,
246         int do_unlink)
247 {
248         int ret = 0;
249
250         if (!this_usbduxfastsub) {
251                 printk("comedi?: usbduxfast_ai_stop: this_usbduxfastsub=NULL!\n");
252                 return -EFAULT;
253         }
254 #ifdef CONFIG_COMEDI_DEBUG
255         printk("comedi: usbduxfast_ai_stop\n");
256 #endif
257
258         this_usbduxfastsub->ai_cmd_running = 0;
259
260         if (do_unlink) {
261                 // stop aquistion
262                 ret = usbduxfastsub_unlink_InURBs(this_usbduxfastsub);
263         }
264
265         return ret;
266 }
267
268 // This will cancel a running acquisition operation.
269 // This is called by comedi but never from inside the
270 // driver.
271 static int usbduxfast_ai_cancel(comedi_device * dev, comedi_subdevice * s)
272 {
273         usbduxfastsub_t *this_usbduxfastsub;
274         int res = 0;
275
276         // force unlink of all urbs
277 #ifdef CONFIG_COMEDI_DEBUG
278         printk("comedi: usbduxfast_ai_cancel\n");
279 #endif
280         this_usbduxfastsub = dev->private;
281         if (!this_usbduxfastsub) {
282                 printk("comedi: usbduxfast_ai_cancel: this_usbduxfastsub=NULL\n");
283                 return -EFAULT;
284         }
285         down(&this_usbduxfastsub->sem);
286         if (!(this_usbduxfastsub->probed)) {
287                 up(&this_usbduxfastsub->sem);
288                 return -ENODEV;
289         }
290         // unlink
291         res = usbduxfast_ai_stop(this_usbduxfastsub, 1);
292         up(&this_usbduxfastsub->sem);
293
294         return res;
295 }
296
297 // analogue IN
298 // interrupt service routine
299 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
300 static void usbduxfastsub_ai_Irq(struct urb *urb)
301 #else
302 static void usbduxfastsub_ai_Irq(struct urb *urb PT_REGS_ARG)
303 #endif
304 {
305         int n, err;
306         usbduxfastsub_t *this_usbduxfastsub;
307         comedi_device *this_comedidev;
308         comedi_subdevice *s;
309         uint16_t *p;
310
311         // sanity checks
312         // is the urb there?
313         if (!urb) {
314                 printk("comedi_: usbduxfast_: ao int-handler called with urb=NULL!\n");
315                 return;
316         }
317         // the context variable points to the subdevice
318         this_comedidev = urb->context;
319         if (!this_comedidev) {
320                 printk("comedi_: usbduxfast_: urb context is a NULL pointer!\n");
321                 return;
322         }
323         // the private structure of the subdevice is usbduxfastsub_t
324         this_usbduxfastsub = this_comedidev->private;
325         if (!this_usbduxfastsub) {
326                 printk("comedi_: usbduxfast_: private of comedi subdev is a NULL pointer!\n");
327                 return;
328         }
329         // are we running a command?
330         if (unlikely(!(this_usbduxfastsub->ai_cmd_running))) {
331                 // not running a command
332                 // do not continue execution if no asynchronous command is running
333                 // in particular not resubmit
334                 return;
335         }
336
337         if (unlikely(!(this_usbduxfastsub->attached))) {
338                 // no comedi device there
339                 return;
340         }
341         // subdevice which is the AD converter
342         s = this_comedidev->subdevices + SUBDEV_AD;
343
344         // first we test if something unusual has just happened
345         switch (urb->status) {
346         case 0:
347                 break;
348
349                 // happens after an unlink command or when the device is plugged out
350         case -ECONNRESET:
351         case -ENOENT:
352         case -ESHUTDOWN:
353         case -ECONNABORTED:
354                 // tell this comedi
355                 s->async->events |= COMEDI_CB_EOA;
356                 s->async->events |= COMEDI_CB_ERROR;
357                 comedi_event(this_usbduxfastsub->comedidev, s);
358                 // stop the transfer w/o unlink
359                 usbduxfast_ai_stop(this_usbduxfastsub, 0);
360                 return;
361
362         default:
363                 printk("comedi%d: usbduxfast: non-zero urb status received in ai intr context: %d\n", this_usbduxfastsub->comedidev->minor, urb->status);
364                 s->async->events |= COMEDI_CB_EOA;
365                 s->async->events |= COMEDI_CB_ERROR;
366                 comedi_event(this_usbduxfastsub->comedidev, s);
367                 usbduxfast_ai_stop(this_usbduxfastsub, 0);
368                 return;
369         }
370
371         p = urb->transfer_buffer;
372         if (!this_usbduxfastsub->ignore) {
373                 if (!(this_usbduxfastsub->ai_continous)) {
374                         // not continous, fixed number of samples
375                         n = urb->actual_length / sizeof(uint16_t);
376                         if (unlikely(this_usbduxfastsub->ai_sample_count < n)) {
377                                 // we have send only a fraction of the bytes received
378                                 cfc_write_array_to_buffer(s,
379                                         urb->transfer_buffer,
380                                         this_usbduxfastsub->ai_sample_count *
381                                         sizeof(uint16_t));
382                                 usbduxfast_ai_stop(this_usbduxfastsub, 0);
383                                 // say comedi that the acquistion is over
384                                 s->async->events |= COMEDI_CB_EOA;
385                                 comedi_event(this_usbduxfastsub->comedidev, s);
386                                 return;
387                         }
388                         this_usbduxfastsub->ai_sample_count -= n;
389                 }
390                 // write the full buffer to comedi
391                 cfc_write_array_to_buffer(s,
392                         urb->transfer_buffer, urb->actual_length);
393
394                 // tell comedi that data is there
395                 comedi_event(this_usbduxfastsub->comedidev, s);
396
397         } else {
398                 // ignore this packet
399                 this_usbduxfastsub->ignore--;
400         }
401
402         // command is still running
403         // resubmit urb for BULK transfer
404         urb->dev = this_usbduxfastsub->usbdev;
405         urb->status = 0;
406         err = usb_submit_urb(urb, GFP_ATOMIC);
407         if (err < 0) {
408                 printk("comedi%d: usbduxfast: urb resubm failed: %d",
409                         this_usbduxfastsub->comedidev->minor, err);
410                 s->async->events |= COMEDI_CB_EOA;
411                 s->async->events |= COMEDI_CB_ERROR;
412                 comedi_event(this_usbduxfastsub->comedidev, s);
413                 usbduxfast_ai_stop(this_usbduxfastsub, 0);
414         }
415 }
416
417 static int usbduxfastsub_start(usbduxfastsub_t * usbduxfastsub)
418 {
419         int errcode = 0;
420         unsigned char local_transfer_buffer[16];
421
422         if (usbduxfastsub->probed) {
423                 // 7f92 to zero
424                 local_transfer_buffer[0] = 0;
425                 errcode = usb_control_msg(usbduxfastsub->usbdev,
426                         // create a pipe for a control transfer
427                         usb_sndctrlpipe(usbduxfastsub->usbdev, 0),
428                         // bRequest, "Firmware"
429                         USBDUXFASTSUB_FIRMWARE,
430                         // bmRequestType
431                         VENDOR_DIR_OUT,
432                         // Value
433                         USBDUXFASTSUB_CPUCS,
434                         // Index
435                         0x0000,
436                         // address of the transfer buffer
437                         local_transfer_buffer,
438                         // Length
439                         1,
440                         // Timeout
441                         EZTIMEOUT);
442                 if (errcode < 0) {
443                         printk("comedi_: usbduxfast_: control msg failed (start)\n");
444                         return errcode;
445                 }
446         }
447         return 0;
448 }
449
450 static int usbduxfastsub_stop(usbduxfastsub_t * usbduxfastsub)
451 {
452         int errcode = 0;
453
454         unsigned char local_transfer_buffer[16];
455         if (usbduxfastsub->probed) {
456                 // 7f92 to one
457                 local_transfer_buffer[0] = 1;
458                 errcode = usb_control_msg(usbduxfastsub->usbdev,
459                         usb_sndctrlpipe(usbduxfastsub->usbdev, 0),
460                         // bRequest, "Firmware"
461                         USBDUXFASTSUB_FIRMWARE,
462                         // bmRequestType
463                         VENDOR_DIR_OUT,
464                         // Value
465                         USBDUXFASTSUB_CPUCS,
466                         // Index
467                         0x0000, local_transfer_buffer,
468                         // Length
469                         1,
470                         // Timeout
471                         EZTIMEOUT);
472                 if (errcode < 0) {
473                         printk("comedi_: usbduxfast: control msg failed (stop)\n");
474                         return errcode;
475                 }
476         }
477         return 0;
478 }
479
480 static int usbduxfastsub_upload(usbduxfastsub_t * usbduxfastsub,
481         unsigned char *local_transfer_buffer,
482         unsigned int startAddr, unsigned int len)
483 {
484         int errcode;
485
486         if (usbduxfastsub->probed) {
487 #ifdef CONFIG_COMEDI_DEBUG
488                 printk("comedi%d: usbduxfast: uploading %d bytes",
489                         usbduxfastsub->comedidev->minor, len);
490                 printk(" to addr %d, first byte=%d.\n",
491                         startAddr, local_transfer_buffer[0]);
492 #endif
493                 errcode = usb_control_msg(usbduxfastsub->usbdev,
494                         usb_sndctrlpipe(usbduxfastsub->usbdev, 0),
495                         // brequest, firmware
496                         USBDUXFASTSUB_FIRMWARE,
497                         // bmRequestType
498                         VENDOR_DIR_OUT,
499                         // value
500                         startAddr,
501                         // index
502                         0x0000,
503                         // our local safe buffer
504                         local_transfer_buffer,
505                         // length
506                         len,
507                         // timeout
508                         EZTIMEOUT);
509 #ifdef CONFIG_COMEDI_DEBUG
510                 printk("comedi_: usbduxfast: result=%d\n", errcode);
511 #endif
512                 if (errcode < 0) {
513                         printk("comedi_: usbduxfast: uppload failed\n");
514                         return errcode;
515                 }
516         } else {
517                 // no device on the bus for this index
518                 return -EFAULT;
519         }
520         return 0;
521 }
522
523 int firmwareUpload(usbduxfastsub_t * usbduxfastsub,
524         unsigned char *firmwareBinary, int sizeFirmware)
525 {
526         int ret;
527
528         if (!firmwareBinary) {
529                 return 0;
530         }
531         ret = usbduxfastsub_stop(usbduxfastsub);
532         if (ret < 0) {
533                 printk("comedi_: usbduxfast: can not stop firmware\n");
534                 return ret;
535         }
536         ret = usbduxfastsub_upload(usbduxfastsub,
537                 firmwareBinary, 0, sizeFirmware);
538         if (ret < 0) {
539                 printk("comedi_: usbduxfast: firmware upload failed\n");
540                 return ret;
541         }
542         ret = usbduxfastsub_start(usbduxfastsub);
543         if (ret < 0) {
544                 printk("comedi_: usbduxfast: can not start firmware\n");
545                 return ret;
546         }
547         return 0;
548 }
549
550 int usbduxfastsub_submit_InURBs(usbduxfastsub_t * usbduxfastsub)
551 {
552         int errFlag;
553
554         if (!usbduxfastsub) {
555                 return -EFAULT;
556         }
557         usb_fill_bulk_urb(usbduxfastsub->urbIn,
558                 usbduxfastsub->usbdev,
559                 usb_rcvbulkpipe(usbduxfastsub->usbdev, BULKINEP),
560                 usbduxfastsub->transfer_buffer,
561                 SIZEINBUF, usbduxfastsub_ai_Irq, usbduxfastsub->comedidev);
562
563 #ifdef CONFIG_COMEDI_DEBUG
564         printk("comedi%d: usbduxfast: submitting in-urb: %x,%x\n",
565                 usbduxfastsub->comedidev->minor,
566                 (int)(usbduxfastsub->urbIn->context),
567                 (int)(usbduxfastsub->urbIn->dev));
568 #endif
569         errFlag = usb_submit_urb(usbduxfastsub->urbIn, GFP_ATOMIC);
570         if (errFlag) {
571                 printk("comedi_: usbduxfast: ai: usb_submit_urb error %d\n",
572                         errFlag);
573                 return errFlag;
574         }
575         return 0;
576 }
577
578 static int usbduxfast_ai_cmdtest(comedi_device * dev,
579         comedi_subdevice * s, comedi_cmd * cmd)
580 {
581         int err = 0, stop_mask = 0;
582         long int steps, tmp = 0;
583         int minSamplPer;
584         usbduxfastsub_t *this_usbduxfastsub = dev->private;
585         if (!(this_usbduxfastsub->probed)) {
586                 return -ENODEV;
587         }
588 #ifdef CONFIG_COMEDI_DEBUG
589         printk("comedi%d: usbduxfast_ai_cmdtest\n", dev->minor);
590         printk("comedi%d: usbduxfast: convert_arg=%u scan_begin_arg=%u\n",
591                 dev->minor, cmd->convert_arg, cmd->scan_begin_arg);
592 #endif
593         /* step 1: make sure trigger sources are trivially valid */
594
595         tmp = cmd->start_src;
596         cmd->start_src &= TRIG_NOW | TRIG_EXT | TRIG_INT;
597         if (!cmd->start_src || tmp != cmd->start_src)
598                 err++;
599
600         tmp = cmd->scan_begin_src;
601         cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT;
602         if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
603                 err++;
604
605         tmp = cmd->convert_src;
606         cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
607         if (!cmd->convert_src || tmp != cmd->convert_src)
608                 err++;
609
610         tmp = cmd->scan_end_src;
611         cmd->scan_end_src &= TRIG_COUNT;
612         if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
613                 err++;
614
615         tmp = cmd->stop_src;
616         stop_mask = TRIG_COUNT | TRIG_NONE;
617         cmd->stop_src &= stop_mask;
618         if (!cmd->stop_src || tmp != cmd->stop_src)
619                 err++;
620
621         if (err)
622                 return 1;
623
624         /* step 2: make sure trigger sources are unique and mutually compatible */
625
626         if (cmd->start_src != TRIG_NOW &&
627                 cmd->start_src != TRIG_EXT && cmd->start_src != TRIG_INT)
628                 err++;
629         if (cmd->scan_begin_src != TRIG_TIMER &&
630                 cmd->scan_begin_src != TRIG_FOLLOW &&
631                 cmd->scan_begin_src != TRIG_EXT)
632                 err++;
633         if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
634                 err++;
635         if (cmd->stop_src != TRIG_COUNT &&
636                 cmd->stop_src != TRIG_EXT && cmd->stop_src != TRIG_NONE)
637                 err++;
638
639         // can't have external stop and start triggers at once
640         if (cmd->start_src == TRIG_EXT && cmd->stop_src == TRIG_EXT)
641                 err++;
642
643         if (err)
644                 return 2;
645
646         /* step 3: make sure arguments are trivially compatible */
647
648         if (cmd->start_src == TRIG_NOW && cmd->start_arg != 0) {
649                 cmd->start_arg = 0;
650                 err++;
651         }
652
653         if (!cmd->chanlist_len) {
654                 err++;
655         }
656         if (cmd->scan_end_arg != cmd->chanlist_len) {
657                 cmd->scan_end_arg = cmd->chanlist_len;
658                 err++;
659         }
660
661         if (cmd->chanlist_len == 1) {
662                 minSamplPer = 1;
663         } else {
664                 minSamplPer = MIN_SAMPLING_PERIOD;
665         }
666
667         if (cmd->convert_src == TRIG_TIMER) {
668                 steps = cmd->convert_arg * 30;
669                 if (steps < (minSamplPer * 1000)) {
670                         steps = minSamplPer * 1000;
671                 }
672                 if (steps > (MAX_SAMPLING_PERIOD * 1000)) {
673                         steps = MAX_SAMPLING_PERIOD * 1000;
674                 }
675                 // calc arg again
676                 tmp = steps / 30;
677                 if (cmd->convert_arg != tmp) {
678                         cmd->convert_arg = tmp;
679                         err++;
680                 }
681         }
682
683         if (cmd->scan_begin_src == TRIG_TIMER) {
684                 err++;
685         }
686         // stop source
687         switch (cmd->stop_src) {
688         case TRIG_COUNT:
689                 if (!cmd->stop_arg) {
690                         cmd->stop_arg = 1;
691                         err++;
692                 }
693                 break;
694         case TRIG_NONE:
695                 if (cmd->stop_arg != 0) {
696                         cmd->stop_arg = 0;
697                         err++;
698                 }
699                 break;
700                 // TRIG_EXT doesn't care since it doesn't trigger off a numbered channel
701         default:
702                 break;
703         }
704
705         if (err)
706                 return 3;
707
708         /* step 4: fix up any arguments */
709
710         return 0;
711
712 }
713
714 static int usbduxfast_ai_inttrig(comedi_device * dev,
715         comedi_subdevice * s, unsigned int trignum)
716 {
717         int ret;
718         usbduxfastsub_t *this_usbduxfastsub = dev->private;
719         if (!this_usbduxfastsub) {
720                 return -EFAULT;
721         }
722         down(&this_usbduxfastsub->sem);
723         if (!(this_usbduxfastsub->probed)) {
724                 up(&this_usbduxfastsub->sem);
725                 return -ENODEV;
726         }
727 #ifdef CONFIG_COMEDI_DEBUG
728         printk("comedi%d: usbduxfast_ai_inttrig\n", dev->minor);
729 #endif
730
731         if (trignum != 0) {
732                 printk("comedi%d: usbduxfast_ai_inttrig: invalid trignum\n",
733                         dev->minor);
734                 up(&this_usbduxfastsub->sem);
735                 return -EINVAL;
736         }
737         if (!(this_usbduxfastsub->ai_cmd_running)) {
738                 this_usbduxfastsub->ai_cmd_running = 1;
739                 ret = usbduxfastsub_submit_InURBs(this_usbduxfastsub);
740                 if (ret < 0) {
741                         printk("comedi%d: usbduxfast_ai_inttrig: urbSubmit: err=%d\n", dev->minor, ret);
742                         this_usbduxfastsub->ai_cmd_running = 0;
743                         up(&this_usbduxfastsub->sem);
744                         return ret;
745                 }
746                 s->async->inttrig = NULL;
747         } else {
748                 printk("comedi%d: ai_inttrig but acqu is already running\n",
749                         dev->minor);
750         }
751         up(&this_usbduxfastsub->sem);
752         return 1;
753 }
754
755 // offsets for the GPIF bytes
756 // the first byte is the command byte
757 #define LENBASE 1+0x00
758 #define OPBASE  1+0x08
759 #define OUTBASE 1+0x10
760 #define LOGBASE 1+0x18
761
762 static int usbduxfast_ai_cmd(comedi_device * dev, comedi_subdevice * s)
763 {
764         comedi_cmd *cmd = &s->async->cmd;
765         unsigned int chan, gain, rngmask = 0xff;
766         int i, j, ret;
767         usbduxfastsub_t *this_usbduxfastsub = dev->private;
768         int result;
769         long steps, steps_tmp;
770
771 #ifdef CONFIG_COMEDI_DEBUG
772         printk("comedi%d: usbduxfast_ai_cmd\n", dev->minor);
773 #endif
774         if (!this_usbduxfastsub) {
775                 return -EFAULT;
776         }
777         down(&this_usbduxfastsub->sem);
778         if (!(this_usbduxfastsub->probed)) {
779                 up(&this_usbduxfastsub->sem);
780                 return -ENODEV;
781         }
782         if (this_usbduxfastsub->ai_cmd_running) {
783                 printk("comedi%d: ai_cmd not possible. Another ai_cmd is running.\n", dev->minor);
784                 up(&this_usbduxfastsub->sem);
785                 return -EBUSY;
786         }
787         // set current channel of the running aquisition to zero
788         s->async->cur_chan = 0;
789
790         // ignore the first buffers from the device if there is an error condition
791         this_usbduxfastsub->ignore = PACKETS_TO_IGNORE;
792
793         if (cmd->chanlist_len > 0) {
794                 gain = CR_RANGE(cmd->chanlist[0]);
795                 for (i = 0; i < cmd->chanlist_len; ++i) {
796                         chan = CR_CHAN(cmd->chanlist[i]);
797                         if (chan != i) {
798                                 printk("comedi%d: cmd is accepting only consecutive channels.\n", dev->minor);
799                                 up(&this_usbduxfastsub->sem);
800                                 return -EINVAL;
801                         }
802                         if ((gain != CR_RANGE(cmd->chanlist[i]))
803                                 && (cmd->chanlist_len > 3)) {
804                                 printk("comedi%d: the gain must be the same for all channels.\n", dev->minor);
805                                 up(&this_usbduxfastsub->sem);
806                                 return -EINVAL;
807                         }
808                         if (i >= NUMCHANNELS) {
809                                 printk("comedi%d: channel list too long\n",
810                                         dev->minor);
811                                 break;
812                         }
813                 }
814         }
815         steps = 0;
816         if (cmd->scan_begin_src == TRIG_TIMER) {
817                 printk("comedi%d: usbduxfast: scan_begin_src==TRIG_TIMER not valid.\n", dev->minor);
818                 up(&this_usbduxfastsub->sem);
819                 return -EINVAL;
820         }
821         if (cmd->convert_src == TRIG_TIMER) {
822                 steps = (cmd->convert_arg * 30) / 1000;
823         }
824         if ((steps < MIN_SAMPLING_PERIOD) && (cmd->chanlist_len != 1)) {
825                 printk("comedi%d: usbduxfast: ai_cmd: steps=%ld, scan_begin_arg=%d. Not properly tested by cmdtest?\n", dev->minor, steps, cmd->scan_begin_arg);
826                 up(&this_usbduxfastsub->sem);
827                 return -EINVAL;
828         }
829         if (steps > MAX_SAMPLING_PERIOD) {
830                 printk("comedi%d: usbduxfast: ai_cmd: sampling rate too low.\n",
831                         dev->minor);
832                 up(&this_usbduxfastsub->sem);
833                 return -EINVAL;
834         }
835         if ((cmd->start_src == TRIG_EXT) && (cmd->chanlist_len != 1)
836                 && (cmd->chanlist_len != 16)) {
837                 printk("comedi%d: usbduxfast: ai_cmd: TRIG_EXT only with 1 or 16 channels possible.\n", dev->minor);
838                 up(&this_usbduxfastsub->sem);
839                 return -EINVAL;
840         }
841 #ifdef CONFIG_COMEDI_DEBUG
842         printk("comedi%d: usbduxfast: steps=%ld, convert_arg=%u, ai_timer=%u\n",
843                 dev->minor,
844                 steps, cmd->convert_arg, this_usbduxfastsub->ai_timer);
845 #endif
846
847         switch (cmd->chanlist_len) {
848                 // one channel
849         case 1:
850                 if (CR_RANGE(cmd->chanlist[0]) > 0)
851                         rngmask = 0xff - 0x04;
852                 else
853                         rngmask = 0xff;
854
855                 // for external trigger: looping in this state until the RDY0 pin
856                 // becomes zero
857                 if (cmd->start_src == TRIG_EXT) {       // we loop here until ready has been set
858                         this_usbduxfastsub->dux_commands[LENBASE + 0] = 0x01;   // branch back to state 0
859                         this_usbduxfastsub->dux_commands[OPBASE + 0] = 0x01;    // deceision state w/o data
860                         this_usbduxfastsub->dux_commands[OUTBASE + 0] =
861                                 0xFF & rngmask;
862                         this_usbduxfastsub->dux_commands[LOGBASE + 0] = 0x00;   // RDY0 = 0
863                 } else {        // we just proceed to state 1
864                         this_usbduxfastsub->dux_commands[LENBASE + 0] = 1;
865                         this_usbduxfastsub->dux_commands[OPBASE + 0] = 0;
866                         this_usbduxfastsub->dux_commands[OUTBASE + 0] =
867                                 0xFF & rngmask;
868                         this_usbduxfastsub->dux_commands[LOGBASE + 0] = 0;
869                 }
870
871                 if (steps < MIN_SAMPLING_PERIOD) {
872                         // for fast single channel aqu without mux
873                         if (steps <= 1) {
874                                 // we just stay here at state 1 and rexecute the same state
875                                 // this gives us 30MHz sampling rate
876                                 this_usbduxfastsub->dux_commands[LENBASE + 1] = 0x89;   // branch back to state 1
877                                 this_usbduxfastsub->dux_commands[OPBASE + 1] = 0x03;    // deceision state with data
878                                 this_usbduxfastsub->dux_commands[OUTBASE + 1] =
879                                         0xFF & rngmask;
880                                 this_usbduxfastsub->dux_commands[LOGBASE + 1] = 0xFF;   // doesn't matter
881                         } else {
882                                 // we loop through two states: data and delay: max rate is 15Mhz
883                                 this_usbduxfastsub->dux_commands[LENBASE + 1] =
884                                         steps - 1;
885                                 this_usbduxfastsub->dux_commands[OPBASE + 1] = 0x02;    // data
886                                 this_usbduxfastsub->dux_commands[OUTBASE + 1] =
887                                         0xFF & rngmask;
888                                 this_usbduxfastsub->dux_commands[LOGBASE + 1] = 0;      // doesn't matter
889
890                                 this_usbduxfastsub->dux_commands[LENBASE + 2] = 0x09;   // branch back to state 1
891                                 this_usbduxfastsub->dux_commands[OPBASE + 2] = 0x01;    // deceision state w/o data
892                                 this_usbduxfastsub->dux_commands[OUTBASE + 2] =
893                                         0xFF & rngmask;
894                                 this_usbduxfastsub->dux_commands[LOGBASE + 2] = 0xFF;   // doesn't matter
895                         }
896                 } else {
897                         // we loop through 3 states: 2x delay and 1x data. This gives a min
898                         // sampling rate of 60kHz.
899
900                         // we have 1 state with duration 1
901                         steps = steps - 1;
902
903                         // do the first part of the delay
904                         this_usbduxfastsub->dux_commands[LENBASE + 1] =
905                                 steps / 2;
906                         this_usbduxfastsub->dux_commands[OPBASE + 1] = 0;
907                         this_usbduxfastsub->dux_commands[OUTBASE + 1] =
908                                 0xFF & rngmask;
909                         this_usbduxfastsub->dux_commands[LOGBASE + 1] = 0;
910
911                         // and the second part
912                         this_usbduxfastsub->dux_commands[LENBASE + 2] =
913                                 steps - steps / 2;
914                         this_usbduxfastsub->dux_commands[OPBASE + 2] = 0;
915                         this_usbduxfastsub->dux_commands[OUTBASE + 2] =
916                                 0xFF & rngmask;
917                         this_usbduxfastsub->dux_commands[LOGBASE + 2] = 0;
918
919                         // get the data and branch back
920                         this_usbduxfastsub->dux_commands[LENBASE + 3] = 0x09;   // branch back to state 1
921                         this_usbduxfastsub->dux_commands[OPBASE + 3] = 0x03;    // deceision state w data
922                         this_usbduxfastsub->dux_commands[OUTBASE + 3] =
923                                 0xFF & rngmask;
924                         this_usbduxfastsub->dux_commands[LOGBASE + 3] = 0xFF;   // doesn't matter
925                 }
926                 break;
927
928         case 2:
929                 // two channels
930                 // commit data to the FIFO
931                 if (CR_RANGE(cmd->chanlist[0]) > 0)
932                         rngmask = 0xff - 0x04;
933                 else
934                         rngmask = 0xff;
935                 this_usbduxfastsub->dux_commands[LENBASE + 0] = 1;
936                 this_usbduxfastsub->dux_commands[OPBASE + 0] = 0x02;    // data
937                 this_usbduxfastsub->dux_commands[OUTBASE + 0] = 0xFF & rngmask;
938                 this_usbduxfastsub->dux_commands[LOGBASE + 0] = 0;
939
940                 // we have 1 state with duration 1: state 0
941                 steps_tmp = steps - 1;
942
943                 if (CR_RANGE(cmd->chanlist[1]) > 0)
944                         rngmask = 0xff - 0x04;
945                 else
946                         rngmask = 0xff;
947                 // do the first part of the delay
948                 this_usbduxfastsub->dux_commands[LENBASE + 1] = steps_tmp / 2;
949                 this_usbduxfastsub->dux_commands[OPBASE + 1] = 0;
950                 this_usbduxfastsub->dux_commands[OUTBASE + 1] = 0xFE & rngmask; //count
951                 this_usbduxfastsub->dux_commands[LOGBASE + 1] = 0;
952
953                 // and the second part
954                 this_usbduxfastsub->dux_commands[LENBASE + 2] =
955                         steps_tmp - steps_tmp / 2;
956                 this_usbduxfastsub->dux_commands[OPBASE + 2] = 0;
957                 this_usbduxfastsub->dux_commands[OUTBASE + 2] = 0xFF & rngmask;
958                 this_usbduxfastsub->dux_commands[LOGBASE + 2] = 0;
959
960                 this_usbduxfastsub->dux_commands[LENBASE + 3] = 1;
961                 this_usbduxfastsub->dux_commands[OPBASE + 3] = 0x02;    // data
962                 this_usbduxfastsub->dux_commands[OUTBASE + 3] = 0xFF & rngmask;
963                 this_usbduxfastsub->dux_commands[LOGBASE + 3] = 0;
964
965                 // we have 2 states with duration 1: step 6 and the IDLE state
966                 steps_tmp = steps - 2;
967
968                 if (CR_RANGE(cmd->chanlist[0]) > 0)
969                         rngmask = 0xff - 0x04;
970                 else
971                         rngmask = 0xff;
972                 // do the first part of the delay
973                 this_usbduxfastsub->dux_commands[LENBASE + 4] = steps_tmp / 2;
974                 this_usbduxfastsub->dux_commands[OPBASE + 4] = 0;
975                 this_usbduxfastsub->dux_commands[OUTBASE + 4] = (0xFF - 0x02) & rngmask;        //reset
976                 this_usbduxfastsub->dux_commands[LOGBASE + 4] = 0;
977
978                 // and the second part
979                 this_usbduxfastsub->dux_commands[LENBASE + 5] =
980                         steps_tmp - steps_tmp / 2;
981                 this_usbduxfastsub->dux_commands[OPBASE + 5] = 0;
982                 this_usbduxfastsub->dux_commands[OUTBASE + 5] = 0xFF & rngmask;
983                 this_usbduxfastsub->dux_commands[LOGBASE + 5] = 0;
984
985                 this_usbduxfastsub->dux_commands[LENBASE + 6] = 1;
986                 this_usbduxfastsub->dux_commands[OPBASE + 6] = 0;
987                 this_usbduxfastsub->dux_commands[OUTBASE + 6] = 0xFF & rngmask;
988                 this_usbduxfastsub->dux_commands[LOGBASE + 6] = 0;
989                 break;
990
991         case 3:
992                 // three channels
993                 for (j = 0; j < 1; j++) {
994                         if (CR_RANGE(cmd->chanlist[j]) > 0)
995                                 rngmask = 0xff - 0x04;
996                         else
997                                 rngmask = 0xff;
998                         // commit data to the FIFO and do the first part of the delay
999                         this_usbduxfastsub->dux_commands[LENBASE + j * 2] =
1000                                 steps / 2;
1001                         this_usbduxfastsub->dux_commands[OPBASE + j * 2] = 0x02;        // data
1002                         this_usbduxfastsub->dux_commands[OUTBASE + j * 2] = 0xFF & rngmask;     // no change
1003                         this_usbduxfastsub->dux_commands[LOGBASE + j * 2] = 0;
1004
1005                         if (CR_RANGE(cmd->chanlist[j + 1]) > 0)
1006                                 rngmask = 0xff - 0x04;
1007                         else
1008                                 rngmask = 0xff;
1009                         // do the second part of the delay
1010                         this_usbduxfastsub->dux_commands[LENBASE + j * 2 + 1] =
1011                                 steps - steps / 2;
1012                         this_usbduxfastsub->dux_commands[OPBASE + j * 2 + 1] = 0;       // no data
1013                         this_usbduxfastsub->dux_commands[OUTBASE + j * 2 + 1] = 0xFE & rngmask; //count
1014                         this_usbduxfastsub->dux_commands[LOGBASE + j * 2 + 1] =
1015                                 0;
1016                 }
1017
1018                 // 2 steps with duration 1: the idele step and step 6:
1019                 steps_tmp = steps - 2;
1020                 // commit data to the FIFO and do the first part of the delay
1021                 this_usbduxfastsub->dux_commands[LENBASE + 4] = steps_tmp / 2;
1022                 this_usbduxfastsub->dux_commands[OPBASE + 4] = 0x02;    // data
1023                 this_usbduxfastsub->dux_commands[OUTBASE + 4] = 0xFF & rngmask; // no change
1024                 this_usbduxfastsub->dux_commands[LOGBASE + 4] = 0;
1025
1026                 if (CR_RANGE(cmd->chanlist[0]) > 0)
1027                         rngmask = 0xff - 0x04;
1028                 else
1029                         rngmask = 0xff;
1030                 // do the second part of the delay
1031                 this_usbduxfastsub->dux_commands[LENBASE + 5] =
1032                         steps_tmp - steps_tmp / 2;
1033                 this_usbduxfastsub->dux_commands[OPBASE + 5] = 0;       // no data
1034                 this_usbduxfastsub->dux_commands[OUTBASE + 5] = (0xFF - 0x02) & rngmask;        // reset
1035                 this_usbduxfastsub->dux_commands[LOGBASE + 5] = 0;
1036
1037                 this_usbduxfastsub->dux_commands[LENBASE + 6] = 1;
1038                 this_usbduxfastsub->dux_commands[OPBASE + 6] = 0;
1039                 this_usbduxfastsub->dux_commands[OUTBASE + 6] = 0xFF & rngmask;
1040                 this_usbduxfastsub->dux_commands[LOGBASE + 6] = 0;
1041
1042         case 16:
1043                 if (CR_RANGE(cmd->chanlist[0]) > 0)
1044                         rngmask = 0xff - 0x04;
1045                 else
1046                         rngmask = 0xff;
1047                 if (cmd->start_src == TRIG_EXT) {       // we loop here until ready has been set
1048                         this_usbduxfastsub->dux_commands[LENBASE + 0] = 0x01;   // branch back to state 0
1049                         this_usbduxfastsub->dux_commands[OPBASE + 0] = 0x01;    // deceision state w/o data
1050                         this_usbduxfastsub->dux_commands[OUTBASE + 0] = (0xFF - 0x02) & rngmask;        // reset
1051                         this_usbduxfastsub->dux_commands[LOGBASE + 0] = 0x00;   // RDY0 = 0
1052                 } else {        // we just proceed to state 1
1053                         this_usbduxfastsub->dux_commands[LENBASE + 0] = 255;    // 30us reset pulse
1054                         this_usbduxfastsub->dux_commands[OPBASE + 0] = 0;
1055                         this_usbduxfastsub->dux_commands[OUTBASE + 0] = (0xFF - 0x02) & rngmask;        // reset
1056                         this_usbduxfastsub->dux_commands[LOGBASE + 0] = 0;
1057                 }
1058
1059                 // commit data to the FIFO
1060                 this_usbduxfastsub->dux_commands[LENBASE + 1] = 1;
1061                 this_usbduxfastsub->dux_commands[OPBASE + 1] = 0x02;    // data
1062                 this_usbduxfastsub->dux_commands[OUTBASE + 1] = 0xFF & rngmask;
1063                 this_usbduxfastsub->dux_commands[LOGBASE + 1] = 0;
1064
1065                 // we have 2 states with duration 1
1066                 steps = steps - 2;
1067
1068                 // do the first part of the delay
1069                 this_usbduxfastsub->dux_commands[LENBASE + 2] = steps / 2;
1070                 this_usbduxfastsub->dux_commands[OPBASE + 2] = 0;
1071                 this_usbduxfastsub->dux_commands[OUTBASE + 2] = 0xFE & rngmask;
1072                 this_usbduxfastsub->dux_commands[LOGBASE + 2] = 0;
1073
1074                 // and the second part
1075                 this_usbduxfastsub->dux_commands[LENBASE + 3] =
1076                         steps - steps / 2;
1077                 this_usbduxfastsub->dux_commands[OPBASE + 3] = 0;
1078                 this_usbduxfastsub->dux_commands[OUTBASE + 3] = 0xFF & rngmask;
1079                 this_usbduxfastsub->dux_commands[LOGBASE + 3] = 0;
1080
1081                 this_usbduxfastsub->dux_commands[LENBASE + 4] = 0x09;   // branch back to state 1
1082                 this_usbduxfastsub->dux_commands[OPBASE + 4] = 0x01;    // deceision state w/o data
1083                 this_usbduxfastsub->dux_commands[OUTBASE + 4] = 0xFF & rngmask;
1084                 this_usbduxfastsub->dux_commands[LOGBASE + 4] = 0xFF;   // doesn't matter
1085
1086                 break;
1087
1088         default:
1089                 printk("comedi %d: unsupported combination of channels\n",
1090                         dev->minor);
1091                 up(&this_usbduxfastsub->sem);
1092                 return -EFAULT;
1093         }
1094
1095 #ifdef CONFIG_COMEDI_DEBUG
1096         printk("comedi %d: sending commands to the usb device\n", dev->minor);
1097 #endif
1098         // 0 means that the AD commands are sent
1099         result = send_dux_commands(this_usbduxfastsub, SENDADCOMMANDS);
1100         if (result < 0) {
1101                 printk("comedi%d: adc command could not be submitted. Aborting...\n", dev->minor);
1102                 up(&this_usbduxfastsub->sem);
1103                 return result;
1104         }
1105         if (cmd->stop_src == TRIG_COUNT) {
1106                 this_usbduxfastsub->ai_sample_count =
1107                         (cmd->stop_arg) * (cmd->scan_end_arg);
1108                 if (usbduxfastsub->ai_sample_count < 1) {
1109                         printk("comedi%d: (cmd->stop_arg)*(cmd->scan_end_arg)<1, aborting.\n", dev->minor);
1110                         up(&this_usbduxfastsub->sem);
1111                         return -EFAULT;
1112                 }
1113                 this_usbduxfastsub->ai_continous = 0;
1114         } else {
1115                 // continous aquisition
1116                 this_usbduxfastsub->ai_continous = 1;
1117                 this_usbduxfastsub->ai_sample_count = 0;
1118         }
1119
1120         if ((cmd->start_src == TRIG_NOW) || (cmd->start_src == TRIG_EXT)) {
1121                 // enable this acquisition operation
1122                 this_usbduxfastsub->ai_cmd_running = 1;
1123                 ret = usbduxfastsub_submit_InURBs(this_usbduxfastsub);
1124                 if (ret < 0) {
1125                         this_usbduxfastsub->ai_cmd_running = 0;
1126                         // fixme: unlink here??
1127                         up(&this_usbduxfastsub->sem);
1128                         return ret;
1129                 }
1130                 s->async->inttrig = NULL;
1131         } else {
1132                 /* TRIG_INT */
1133                 // don't enable the acquision operation
1134                 // wait for an internal signal
1135                 s->async->inttrig = usbduxfast_ai_inttrig;
1136         }
1137         up(&this_usbduxfastsub->sem);
1138
1139         return 0;
1140 }
1141
1142 /* Mode 0 is used to get a single conversion on demand */
1143 static int usbduxfast_ai_insn_read(comedi_device * dev,
1144         comedi_subdevice * s, comedi_insn * insn, lsampl_t * data)
1145 {
1146         int i, j, n, actual_length;
1147         int chan, range, rngmask;
1148         int err;
1149         usbduxfastsub_t *usbduxfastsub = dev->private;
1150
1151         if (!usbduxfastsub) {
1152                 printk("comedi%d: ai_insn_read: no usb dev.\n", dev->minor);
1153                 return -ENODEV;
1154         }
1155 #ifdef CONFIG_COMEDI_DEBUG
1156         printk("comedi%d: ai_insn_read, insn->n=%d, insn->subdev=%d\n",
1157                 dev->minor, insn->n, insn->subdev);
1158 #endif
1159         down(&usbduxfastsub->sem);
1160         if (!(usbduxfastsub->probed)) {
1161                 up(&usbduxfastsub->sem);
1162                 return -ENODEV;
1163         }
1164         if (usbduxfastsub->ai_cmd_running) {
1165                 printk("comedi%d: ai_insn_read not possible. Async Command is running.\n", dev->minor);
1166                 up(&usbduxfastsub->sem);
1167                 return -EBUSY;
1168         }
1169         // sample one channel
1170         chan = CR_CHAN(insn->chanspec);
1171         range = CR_RANGE(insn->chanspec);
1172         // set command for the first channel
1173
1174         if (range > 0)
1175                 rngmask = 0xff - 0x04;
1176         else
1177                 rngmask = 0xff;
1178         // commit data to the FIFO
1179         usbduxfastsub->dux_commands[LENBASE + 0] = 1;
1180         usbduxfastsub->dux_commands[OPBASE + 0] = 0x02; // data
1181         usbduxfastsub->dux_commands[OUTBASE + 0] = 0xFF & rngmask;
1182         usbduxfastsub->dux_commands[LOGBASE + 0] = 0;
1183
1184         // do the first part of the delay
1185         usbduxfastsub->dux_commands[LENBASE + 1] = 12;
1186         usbduxfastsub->dux_commands[OPBASE + 1] = 0;
1187         usbduxfastsub->dux_commands[OUTBASE + 1] = 0xFE & rngmask;
1188         usbduxfastsub->dux_commands[LOGBASE + 1] = 0;
1189
1190         usbduxfastsub->dux_commands[LENBASE + 2] = 1;
1191         usbduxfastsub->dux_commands[OPBASE + 2] = 0;
1192         usbduxfastsub->dux_commands[OUTBASE + 2] = 0xFE & rngmask;
1193         usbduxfastsub->dux_commands[LOGBASE + 2] = 0;
1194
1195         usbduxfastsub->dux_commands[LENBASE + 3] = 1;
1196         usbduxfastsub->dux_commands[OPBASE + 3] = 0;
1197         usbduxfastsub->dux_commands[OUTBASE + 3] = 0xFE & rngmask;
1198         usbduxfastsub->dux_commands[LOGBASE + 3] = 0;
1199
1200         usbduxfastsub->dux_commands[LENBASE + 4] = 1;
1201         usbduxfastsub->dux_commands[OPBASE + 4] = 0;
1202         usbduxfastsub->dux_commands[OUTBASE + 4] = 0xFE & rngmask;
1203         usbduxfastsub->dux_commands[LOGBASE + 4] = 0;
1204
1205         // second part
1206         usbduxfastsub->dux_commands[LENBASE + 5] = 12;
1207         usbduxfastsub->dux_commands[OPBASE + 5] = 0;
1208         usbduxfastsub->dux_commands[OUTBASE + 5] = 0xFF & rngmask;
1209         usbduxfastsub->dux_commands[LOGBASE + 5] = 0;
1210
1211         usbduxfastsub->dux_commands[LENBASE + 6] = 1;
1212         usbduxfastsub->dux_commands[OPBASE + 6] = 0;
1213         usbduxfastsub->dux_commands[OUTBASE + 6] = 0xFF & rngmask;
1214         usbduxfastsub->dux_commands[LOGBASE + 0] = 0;
1215
1216 #ifdef CONFIG_COMEDI_DEBUG
1217         printk("comedi %d: sending commands to the usb device\n", dev->minor);
1218 #endif
1219         // 0 means that the AD commands are sent
1220         err = send_dux_commands(usbduxfastsub, SENDADCOMMANDS);
1221         if (err < 0) {
1222                 printk("comedi%d: adc command could not be submitted. Aborting...\n", dev->minor);
1223                 up(&usbduxfastsub->sem);
1224                 return err;
1225         }
1226 #ifdef CONFIG_COMEDI_DEBUG
1227         printk("comedi%d: usbduxfast: submitting in-urb: %x,%x\n",
1228                 usbduxfastsub->comedidev->minor,
1229                 (int)(usbduxfastsub->urbIn->context),
1230                 (int)(usbduxfastsub->urbIn->dev));
1231 #endif
1232         for (i = 0; i < PACKETS_TO_IGNORE; i++) {
1233                 err = usb_bulk_msg(usbduxfastsub->usbdev,
1234                                    usb_rcvbulkpipe(usbduxfastsub->usbdev,
1235                                                    BULKINEP),
1236                                    usbduxfastsub->transfer_buffer, SIZEINBUF,
1237                                    &actual_length, 10000);
1238                 if (err < 0) {
1239                         printk("comedi%d: insn timeout. No data.\n",
1240                                 dev->minor);
1241                         up(&usbduxfastsub->sem);
1242                         return err;
1243                 }
1244         }
1245         // data points
1246         for (i = 0; i < insn->n;) {
1247                 err = usb_bulk_msg(usbduxfastsub->usbdev,
1248                                    usb_rcvbulkpipe(usbduxfastsub->usbdev,
1249                                                    BULKINEP),
1250                                    usbduxfastsub->transfer_buffer, SIZEINBUF,
1251                                    &actual_length, 10000);
1252                 if (err < 0) {
1253                         printk("comedi%d: insn data error: %d\n",
1254                                 dev->minor, err);
1255                         up(&usbduxfastsub->sem);
1256                         return err;
1257                 }
1258                 n = actual_length / sizeof(uint16_t);
1259                 if ((n % 16) != 0) {
1260                         printk("comedi%d: insn data packet corrupted.\n",
1261                                 dev->minor);
1262                         up(&usbduxfastsub->sem);
1263                         return -EINVAL;
1264                 }
1265                 for (j = chan; (j < n) && (i < insn->n); j = j + 16) {
1266                         data[i] =
1267                                 ((uint16_t *) (usbduxfastsub->
1268                                         transfer_buffer))[j];
1269                         i++;
1270                 }
1271         }
1272         up(&usbduxfastsub->sem);
1273         return i;
1274 }
1275
1276 static unsigned hex2unsigned(char *h)
1277 {
1278         unsigned hi, lo;
1279         if (h[0] > '9') {
1280                 hi = h[0] - 'A' + 0x0a;
1281         } else {
1282                 hi = h[0] - '0';
1283         }
1284         if (h[1] > '9') {
1285                 lo = h[1] - 'A' + 0x0a;
1286         } else {
1287                 lo = h[1] - '0';
1288         }
1289         return hi * 0x10 + lo;
1290 }
1291
1292 // for FX2
1293 #define FIRMWARE_MAX_LEN 0x2000
1294
1295 // taken from David Brownell's fxload and adjusted for this driver
1296 static int read_firmware(usbduxfastsub_t * usbduxfastsub, void *firmwarePtr,
1297         long size)
1298 {
1299         int i = 0;
1300         unsigned char *fp = (char *)firmwarePtr;
1301         unsigned char *firmwareBinary;
1302         int res = 0;
1303         int maxAddr = 0;
1304
1305         firmwareBinary = kmalloc(FIRMWARE_MAX_LEN, GFP_KERNEL);
1306         if (!firmwareBinary) {
1307                 printk("comedi_: usbduxfast: mem alloc for firmware failed\n");
1308                 return -ENOMEM;
1309         }
1310
1311         for (;;) {
1312                 char buf[256], *cp;
1313                 char type;
1314                 int len;
1315                 int idx, off;
1316                 int j = 0;
1317
1318                 // get one line
1319                 while ((i < size) && (fp[i] != 13) && (fp[i] != 10)) {
1320                         buf[j] = fp[i];
1321                         i++;
1322                         j++;
1323                         if (j >= sizeof(buf)) {
1324                                 printk("comedi_: usbduxfast: bogus firmware file!\n");
1325                                 kfree(firmwareBinary);
1326                                 return -1;
1327                         }
1328                 }
1329                 // get rid of LF/CR/...
1330                 while ((i < size) && ((fp[i] == 13) || (fp[i] == 10)
1331                                 || (fp[i] == 0))) {
1332                         i++;
1333                 }
1334
1335                 buf[j] = 0;
1336                 //printk("comedi_: buf=%s\n",buf);
1337
1338                 /* EXTENSION: "# comment-till-end-of-line", for copyrights etc */
1339                 if (buf[0] == '#')
1340                         continue;
1341
1342                 if (buf[0] != ':') {
1343                         printk("comedi_: usbduxfast: upload: not an ihex record: %s", buf);
1344                         kfree(firmwareBinary);
1345                         return -EFAULT;
1346                 }
1347
1348                 /* Read the length field (up to 16 bytes) */
1349                 len = hex2unsigned(buf + 1);
1350
1351                 /* Read the target offset */
1352                 off = (hex2unsigned(buf + 3) * 0x0100) + hex2unsigned(buf + 5);
1353
1354                 if ((off + len) > maxAddr) {
1355                         maxAddr = off + len;
1356                 }
1357
1358                 if (maxAddr >= FIRMWARE_MAX_LEN) {
1359                         printk("comedi_: usbduxfast: firmware upload goes beyond FX2 RAM boundaries.");
1360                         kfree(firmwareBinary);
1361                         return -EFAULT;
1362                 }
1363                 //printk("comedi_: usbduxfast: off=%x, len=%x:",off,len);
1364
1365                 /* Read the record type */
1366                 type = hex2unsigned(buf + 7);
1367
1368                 /* If this is an EOF record, then make it so. */
1369                 if (type == 1) {
1370                         break;
1371                 }
1372
1373                 if (type != 0) {
1374                         printk("comedi_: usbduxfast: unsupported record type: %u\n", type);
1375                         kfree(firmwareBinary);
1376                         return -EFAULT;
1377                 }
1378
1379                 for (idx = 0, cp = buf + 9; idx < len; idx += 1, cp += 2) {
1380                         firmwareBinary[idx + off] = hex2unsigned(cp);
1381                         //printk("%02x ",firmwareBinary[idx+off]);
1382                 }
1383                 //printk("\n");
1384
1385                 if (i >= size) {
1386                         printk("comedi_: usbduxfast: unexpected end of hex file\n");
1387                         break;
1388                 }
1389
1390         }
1391         res = firmwareUpload(usbduxfastsub, firmwareBinary, maxAddr + 1);
1392         kfree(firmwareBinary);
1393         return res;
1394 }
1395
1396 static void tidy_up(usbduxfastsub_t * usbduxfastsub_tmp)
1397 {
1398 #ifdef CONFIG_COMEDI_DEBUG
1399         printk("comedi_: usbduxfast: tiding up\n");
1400 #endif
1401         if (!usbduxfastsub_tmp) {
1402                 return;
1403         }
1404 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
1405         // shows the usb subsystem that the driver is down
1406         if (usbduxfastsub_tmp->interface) {
1407                 usb_set_intfdata(usbduxfastsub_tmp->interface, NULL);
1408         }
1409 #endif
1410
1411         usbduxfastsub_tmp->probed = 0;
1412
1413         if (usbduxfastsub_tmp->urbIn) {
1414 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,8)
1415                 // waits until a running transfer is over
1416                 // thus, under 2.4 hotplugging while a command
1417                 // is running is not safe
1418                 usb_kill_urb(usbduxfastsub_tmp->urbIn);
1419 #endif
1420                 if (usbduxfastsub_tmp->transfer_buffer) {
1421                         kfree(usbduxfastsub_tmp->transfer_buffer);
1422                         usbduxfastsub_tmp->transfer_buffer = NULL;
1423                 }
1424                 usb_free_urb(usbduxfastsub_tmp->urbIn);
1425                 usbduxfastsub_tmp->urbIn = NULL;
1426         }
1427         if (usbduxfastsub_tmp->insnBuffer) {
1428                 kfree(usbduxfastsub_tmp->insnBuffer);
1429                 usbduxfastsub_tmp->insnBuffer = NULL;
1430         }
1431         if (usbduxfastsub_tmp->dux_commands) {
1432                 kfree(usbduxfastsub_tmp->dux_commands);
1433                 usbduxfastsub_tmp->dux_commands = NULL;
1434         }
1435         usbduxfastsub_tmp->ai_cmd_running = 0;
1436 }
1437
1438 // allocate memory for the urbs and initialise them
1439 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
1440 static void *usbduxfastsub_probe(struct usb_device *udev,
1441         unsigned int interfnum, const struct usb_device_id *id)
1442 {
1443 #else
1444 static int usbduxfastsub_probe(struct usb_interface *uinterf,
1445         const struct usb_device_id *id)
1446 {
1447         struct usb_device *udev = interface_to_usbdev(uinterf);
1448 #endif
1449         int i;
1450         int index;
1451
1452         if (udev->speed != USB_SPEED_HIGH) {
1453                 printk("comedi_: usbduxfast_: This driver needs USB 2.0 to operate. Aborting...\n");
1454                 return -ENODEV;
1455         }
1456 #ifdef CONFIG_COMEDI_DEBUG
1457         printk("comedi_: usbduxfast_: finding a free structure for the usb-device\n");
1458 #endif
1459         down(&start_stop_sem);
1460         // look for a free place in the usbduxfast array
1461         index = -1;
1462         for (i = 0; i < NUMUSBDUXFAST; i++) {
1463                 if (!(usbduxfastsub[i].probed)) {
1464                         index = i;
1465                         break;
1466                 }
1467         }
1468
1469         // no more space
1470         if (index == -1) {
1471                 printk("Too many usbduxfast-devices connected.\n");
1472                 up(&start_stop_sem);
1473                 return -EMFILE;
1474         }
1475 #ifdef CONFIG_COMEDI_DEBUG
1476         printk("comedi_: usbduxfast: usbduxfastsub[%d] is ready to connect to comedi.\n", index);
1477 #endif
1478
1479         init_MUTEX(&(usbduxfastsub[index].sem));
1480         // save a pointer to the usb device
1481         usbduxfastsub[index].usbdev = udev;
1482
1483 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
1484         // save the interface number
1485         usbduxfastsub[index].ifnum = interfnum;
1486 #else
1487         // 2.6: save the interface itself
1488         usbduxfastsub[index].interface = uinterf;
1489         // get the interface number from the interface
1490         usbduxfastsub[index].ifnum = uinterf->altsetting->desc.bInterfaceNumber;
1491         // hand the private data over to the usb subsystem
1492         // will be needed for disconnect
1493         usb_set_intfdata(uinterf, &(usbduxfastsub[index]));
1494 #endif
1495
1496 #ifdef CONFIG_COMEDI_DEBUG
1497         printk("comedi_: usbduxfast: ifnum=%d\n", usbduxfastsub[index].ifnum);
1498 #endif
1499         // create space for the commands going to the usb device
1500         usbduxfastsub[index].dux_commands = kmalloc(SIZEOFDUXBUFFER,
1501                 GFP_KERNEL);
1502         if (!usbduxfastsub[index].dux_commands) {
1503                 printk("comedi_: usbduxfast: error alloc space for dac commands\n");
1504                 tidy_up(&(usbduxfastsub[index]));
1505                 up(&start_stop_sem);
1506                 return -ENOMEM;
1507         }
1508         // create space of the instruction buffer
1509         usbduxfastsub[index].insnBuffer = kmalloc(SIZEINSNBUF, GFP_KERNEL);
1510         if (!(usbduxfastsub[index].insnBuffer)) {
1511                 printk("comedi_: usbduxfast: could not alloc space for insnBuffer\n");
1512                 tidy_up(&(usbduxfastsub[index]));
1513                 up(&start_stop_sem);
1514                 return -ENOMEM;
1515         }
1516         // setting to alternate setting 1: enabling bulk ep
1517         i = usb_set_interface(usbduxfastsub[index].usbdev,
1518                 usbduxfastsub[index].ifnum, 1);
1519         if (i < 0) {
1520                 printk("comedi_: usbduxfast%d: could not switch to alternate setting 1.\n", index);
1521                 tidy_up(&(usbduxfastsub[index]));
1522                 up(&start_stop_sem);
1523                 return -ENODEV;
1524         }
1525         usbduxfastsub[index].urbIn = usb_alloc_urb(0, GFP_KERNEL);
1526         if (usbduxfastsub[index].urbIn == NULL) {
1527                 printk("comedi_: usbduxfast%d: Could not alloc. urb\n", index);
1528                 tidy_up(&(usbduxfastsub[index]));
1529                 up(&start_stop_sem);
1530                 return -ENOMEM;
1531         }
1532         usbduxfastsub[index].transfer_buffer = kmalloc(SIZEINBUF, GFP_KERNEL);
1533         if (!(usbduxfastsub[index].transfer_buffer)) {
1534                 printk("comedi_: usbduxfast%d: could not alloc. transb.\n",
1535                         index);
1536                 tidy_up(&(usbduxfastsub[index]));
1537                 up(&start_stop_sem);
1538                 return -ENOMEM;
1539         }
1540         // we've reached the bottom of the function
1541         usbduxfastsub[index].probed = 1;
1542         up(&start_stop_sem);
1543         printk("comedi_: usbduxfast%d has been successfully initialized.\n",
1544                 index);
1545 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
1546         return (void *)(&usbduxfastsub[index]);
1547 #else
1548         // success
1549         return 0;
1550 #endif
1551 }
1552
1553 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
1554 static void usbduxfastsub_disconnect(struct usb_device *udev, void *ptr)
1555 {
1556         usbduxfastsub_t *usbduxfastsub_tmp = (usbduxfastsub_t *) ptr;
1557 #else
1558 static void usbduxfastsub_disconnect(struct usb_interface *intf)
1559 {
1560         usbduxfastsub_t *usbduxfastsub_tmp = usb_get_intfdata(intf);
1561         struct usb_device *udev = interface_to_usbdev(intf);
1562 #endif
1563         if (!usbduxfastsub_tmp) {
1564                 printk("comedi_: usbduxfast: disconnect called with null pointer.\n");
1565                 return;
1566         }
1567         if (usbduxfastsub_tmp->usbdev != udev) {
1568                 printk("comedi_: usbduxfast: BUG! called with wrong ptr!!!\n");
1569                 return;
1570         }
1571         down(&start_stop_sem);
1572         down(&usbduxfastsub_tmp->sem);
1573         tidy_up(usbduxfastsub_tmp);
1574         up(&usbduxfastsub_tmp->sem);
1575         up(&start_stop_sem);
1576 #ifdef CONFIG_COMEDI_DEBUG
1577         printk("comedi_: usbduxfast: disconnected from the usb\n");
1578 #endif
1579 }
1580
1581 // is called when comedi-config is called
1582 static int usbduxfast_attach(comedi_device * dev, comedi_devconfig * it)
1583 {
1584         int ret;
1585         int index;
1586         int i;
1587         comedi_subdevice *s = NULL;
1588         dev->private = NULL;
1589
1590         down(&start_stop_sem);
1591         // find a valid device which has been detected by the probe function of the usb
1592         index = -1;
1593         for (i = 0; i < NUMUSBDUXFAST; i++) {
1594                 if ((usbduxfastsub[i].probed) && (!usbduxfastsub[i].attached)) {
1595                         index = i;
1596                         break;
1597                 }
1598         }
1599
1600         if (index < 0) {
1601                 printk("comedi%d: usbduxfast: error: attach failed, no usbduxfast devs connected to the usb bus.\n", dev->minor);
1602                 up(&start_stop_sem);
1603                 return -ENODEV;
1604         }
1605
1606         down(&(usbduxfastsub[index].sem));
1607         // pointer back to the corresponding comedi device
1608         usbduxfastsub[index].comedidev = dev;
1609
1610         // trying to upload the firmware into the chip
1611         if (comedi_aux_data(it->options, 0) &&
1612                 it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
1613                 read_firmware(usbduxfastsub,
1614                         comedi_aux_data(it->options, 0),
1615                         it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]);
1616         }
1617
1618         dev->board_name = BOARDNAME;
1619
1620         /* set number of subdevices */
1621         dev->n_subdevices = N_SUBDEVICES;
1622
1623         // allocate space for the subdevices
1624         if ((ret = alloc_subdevices(dev, N_SUBDEVICES)) < 0) {
1625                 printk("comedi%d: usbduxfast: error alloc space for subdev\n",
1626                         dev->minor);
1627                 up(&start_stop_sem);
1628                 return ret;
1629         }
1630
1631         printk("comedi%d: usbduxfast: usb-device %d is attached to comedi.\n",
1632                 dev->minor, index);
1633         // private structure is also simply the usb-structure
1634         dev->private = usbduxfastsub + index;
1635         // the first subdevice is the A/D converter
1636         s = dev->subdevices + SUBDEV_AD;
1637         // the URBs get the comedi subdevice
1638         // which is responsible for reading
1639         // this is the subdevice which reads data
1640         dev->read_subdev = s;
1641         // the subdevice receives as private structure the
1642         // usb-structure
1643         s->private = NULL;
1644         // analog input
1645         s->type = COMEDI_SUBD_AI;
1646         // readable and ref is to ground
1647         s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
1648         // 16 channels
1649         s->n_chan = 16;
1650         // length of the channellist
1651         s->len_chanlist = 16;
1652         // callback functions
1653         s->insn_read = usbduxfast_ai_insn_read;
1654         s->do_cmdtest = usbduxfast_ai_cmdtest;
1655         s->do_cmd = usbduxfast_ai_cmd;
1656         s->cancel = usbduxfast_ai_cancel;
1657         // max value from the A/D converter (12bit+1 bit for overflow)
1658         s->maxdata = 0x1000;
1659         // range table to convert to physical units
1660         s->range_table = &range_usbduxfast_ai_range;
1661
1662         // finally decide that it's attached
1663         usbduxfastsub[index].attached = 1;
1664
1665         up(&(usbduxfastsub[index].sem));
1666
1667         up(&start_stop_sem);
1668
1669         printk("comedi%d: successfully attached to usbduxfast.\n", dev->minor);
1670
1671         return 0;
1672 }
1673
1674 static int usbduxfast_detach(comedi_device * dev)
1675 {
1676         usbduxfastsub_t *usbduxfastsub_tmp;
1677
1678 #ifdef CONFIG_COMEDI_DEBUG
1679         printk("comedi%d: usbduxfast: detach usb device\n", dev->minor);
1680 #endif
1681
1682         if (!dev) {
1683                 printk("comedi?: usbduxfast: detach without dev variable...\n");
1684                 return -EFAULT;
1685         }
1686
1687         usbduxfastsub_tmp = dev->private;
1688         if (!usbduxfastsub_tmp) {
1689                 printk("comedi?: usbduxfast: detach without ptr to usbduxfastsub[]\n");
1690                 return -EFAULT;
1691         }
1692
1693         down(&usbduxfastsub_tmp->sem);
1694         down(&start_stop_sem);
1695         // Don't allow detach to free the private structure
1696         // It's one entry of of usbduxfastsub[]
1697         dev->private = NULL;
1698         usbduxfastsub_tmp->attached = 0;
1699         usbduxfastsub_tmp->comedidev = NULL;
1700 #ifdef CONFIG_COMEDI_DEBUG
1701         printk("comedi%d: usbduxfast: detach: successfully removed\n",
1702                 dev->minor);
1703 #endif
1704         up(&start_stop_sem);
1705         up(&usbduxfastsub_tmp->sem);
1706         return 0;
1707 }
1708
1709 /* main driver struct */
1710 static comedi_driver driver_usbduxfast = {
1711       driver_name:"usbduxfast",
1712       module:THIS_MODULE,
1713       attach:usbduxfast_attach,
1714       detach:usbduxfast_detach,
1715 };
1716
1717 static void init_usb_devices(void)
1718 {
1719         int index;
1720 #ifdef CONFIG_COMEDI_DEBUG
1721         printk("comedi_: usbduxfast: setting all possible devs to invalid\n");
1722 #endif
1723         // all devices entries are invalid to begin with
1724         // they will become valid by the probe function
1725         // and then finally by the attach-function
1726         for (index = 0; index < NUMUSBDUXFAST; index++) {
1727                 memset(&(usbduxfastsub[index]), 0x00,
1728                         sizeof(usbduxfastsub[index]));
1729                 init_MUTEX(&(usbduxfastsub[index].sem));
1730         }
1731 }
1732
1733 // Table with the USB-devices: just now only testing IDs
1734 static struct usb_device_id usbduxfastsub_table[] = {
1735         //        { USB_DEVICE(0x4b4, 0x8613), //testing
1736         //        },
1737         {USB_DEVICE(0x13d8, 0x0010)     //real ID
1738                 },
1739         {USB_DEVICE(0x13d8, 0x0011)     //real ID
1740                 },
1741         {}                      /* Terminating entry */
1742 };
1743
1744 MODULE_DEVICE_TABLE(usb, usbduxfastsub_table);
1745
1746 // The usbduxfastsub-driver
1747 static struct usb_driver usbduxfastsub_driver = {
1748 #ifdef COMEDI_HAVE_USB_DRIVER_OWNER
1749       owner:THIS_MODULE,
1750 #endif
1751       name:BOARDNAME,
1752       probe:usbduxfastsub_probe,
1753       disconnect:usbduxfastsub_disconnect,
1754       id_table:usbduxfastsub_table,
1755 };
1756
1757 // Can't use the nice macro as I have also to initialise the USB
1758 // subsystem:
1759 // registering the usb-system _and_ the comedi-driver
1760 static int init_usbduxfast(void)
1761 {
1762         printk(KERN_INFO KBUILD_MODNAME ": "
1763                DRIVER_VERSION ":" DRIVER_DESC "\n");
1764         init_usb_devices();
1765         usb_register(&usbduxfastsub_driver);
1766         comedi_driver_register(&driver_usbduxfast);
1767         return 0;
1768 }
1769
1770 // deregistering the comedi driver and the usb-subsystem
1771 static void exit_usbduxfast(void)
1772 {
1773         comedi_driver_unregister(&driver_usbduxfast);
1774         usb_deregister(&usbduxfastsub_driver);
1775 }
1776
1777 module_init(init_usbduxfast);
1778 module_exit(exit_usbduxfast);
1779
1780 MODULE_AUTHOR(DRIVER_AUTHOR);
1781 MODULE_DESCRIPTION(DRIVER_DESC);
1782 MODULE_LICENSE("GPL");