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