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