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