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