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