usbdux.c revision 4bf21fa4dabaa8803906c6548496fcf12b15b10f
1#define DRIVER_VERSION "v2.1"
2#define DRIVER_AUTHOR "Bernd Porr, BerndPorr@f2s.com"
3#define DRIVER_DESC "Stirling/ITL USB-DUX -- Bernd.Porr@f2s.com"
4/*
5   comedi/drivers/usbdux.c
6   Copyright (C) 2003-2007 Bernd Porr, Bernd.Porr@f2s.com
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 */
23/*
24Driver: usbdux
25Description: University of Stirling USB DAQ & INCITE Technology Limited
26Devices: [ITL] USB-DUX (usbdux.o)
27Author: Bernd Porr <BerndPorr@f2s.com>
28Updated: 25 Nov 2007
29Status: Testing
30Configuration options:
31  You have to upload firmware with the -i option. The
32  firmware is usually installed under /usr/share/usb or
33  /usr/local/share/usb or /lib/firmware.
34
35Connection scheme for the counter at the digital port:
36  0=/CLK0, 1=UP/DOWN0, 2=RESET0, 4=/CLK1, 5=UP/DOWN1, 6=RESET1.
37  The sampling rate of the counter is approximately 500Hz.
38
39Please note that under USB2.0 the length of the channel list determines
40the max sampling rate. If you sample only one channel you get 8kHz
41sampling rate. If you sample two channels you get 4kHz and so on.
42*/
43/*
44 * I must give credit here to Chris Baugher who
45 * wrote the driver for AT-MIO-16d. I used some parts of this
46 * driver. I also must give credits to David Brownell
47 * who supported me with the USB development.
48 *
49 * Bernd Porr
50 *
51 *
52 * Revision history:
53 * 0.94: D/A output should work now with any channel list combinations
54 * 0.95: .owner commented out for kernel vers below 2.4.19
55 *       sanity checks in ai/ao_cmd
56 * 0.96: trying to get it working with 2.6, moved all memory alloc to comedi's attach final USB IDs
57 *       moved memory allocation completely to the corresponding comedi functions
58 *       firmware upload is by fxload and no longer by comedi (due to enumeration)
59 * 0.97: USB IDs received, adjusted table
60 * 0.98: SMP, locking, memroy alloc: moved all usb memory alloc
61 *       to the usb subsystem and moved all comedi related memory
62 *       alloc to comedi.
63 *       | kernel | registration | usbdux-usb | usbdux-comedi | comedi |
64 * 0.99: USB 2.0: changed protocol to isochronous transfer
65 *                IRQ transfer is too buggy and too risky in 2.0
66 *                for the high speed ISO transfer is now a working version available
67 * 0.99b: Increased the iso transfer buffer for high sp.to 10 buffers. Some VIA
68 *        chipsets miss out IRQs. Deeper buffering is needed.
69 * 1.00: full USB 2.0 support for the A/D converter. Now: max 8kHz sampling rate.
70 *       Firmware vers 1.00 is needed for this.
71 *       Two 16 bit up/down/reset counter with a sampling rate of 1kHz
72 *       And loads of cleaning up, in particular streamlining the
73 *       bulk transfers.
74 * 1.1:  moved EP4 transfers to EP1 to make space for a PWM output on EP4
75 * 1.2:  added PWM suport via EP4
76 * 2.0:  PWM seems to be stable and is not interfering with the other functions
77 * 2.1:  changed PWM API
78 *
79 */
80
81// generates loads of debug info
82// #define NOISY_DUX_DEBUGBUG
83
84#include <linux/kernel.h>
85#include <linux/module.h>
86#include <linux/init.h>
87#include <linux/slab.h>
88#include <linux/input.h>
89#include <linux/usb.h>
90#include <linux/smp_lock.h>
91#include <linux/fcntl.h>
92#include <linux/compiler.h>
93
94#include "../comedidev.h"
95#include "../usb.h"
96
97#define BOARDNAME "usbdux"
98
99// timeout for the USB-transfer
100#define EZTIMEOUT 30
101
102// constants for "firmware" upload and download
103#define USBDUXSUB_FIRMWARE 0xA0
104#define VENDOR_DIR_IN  0xC0
105#define VENDOR_DIR_OUT 0x40
106
107// internal adresses of the 8051 processor
108#define USBDUXSUB_CPUCS 0xE600
109
110// the minor device number, major is 180
111// only for debugging purposes and to
112// upload special firmware (programming the
113// eeprom etc) which is not compatible with
114// the comedi framwork
115#define USBDUXSUB_MINOR 32
116
117// max lenghth of the transfer-buffer for software upload
118#define TB_LEN 0x2000
119
120// Input endpoint number: ISO/IRQ
121#define ISOINEP           6
122
123// Output endpoint number: ISO/IRQ
124#define ISOOUTEP          2
125
126// This EP sends DUX commands to USBDUX
127#define COMMAND_OUT_EP     1
128
129// This EP receives the DUX commands from USBDUX
130#define COMMAND_IN_EP        8
131
132// Output endpoint for PWM
133#define PWM_EP         4
134
135// 300Hz max frequ under PWM
136#define MIN_PWM_PERIOD  ((long)(1E9/300))
137
138// Default PWM frequency
139#define PWM_DEFAULT_PERIOD ((long)(1E9/100))
140
141// Number of channels
142#define NUMCHANNELS       8
143
144// Size of one A/D value
145#define SIZEADIN          ((sizeof(int16_t)))
146
147// Size of the input-buffer IN BYTES
148// Always multiple of 8 for 8 microframes which is needed in the highspeed mode
149#define SIZEINBUF         ((8*SIZEADIN))
150
151// 16 bytes.
152#define SIZEINSNBUF       16
153
154// Number of DA channels
155#define NUMOUTCHANNELS    8
156
157// size of one value for the D/A converter: channel and value
158#define SIZEDAOUT          ((sizeof(int8_t)+sizeof(int16_t)))
159
160// Size of the output-buffer in bytes
161// Actually only the first 4 triplets are used but for the
162// high speed mode we need to pad it to 8 (microframes).
163#define SIZEOUTBUF         ((8*SIZEDAOUT))
164
165// Size of the buffer for the dux commands: just now max size is determined
166// by the analogue out + command byte + panic bytes...
167#define SIZEOFDUXBUFFER    ((8*SIZEDAOUT+2))
168
169// Number of in-URBs which receive the data: min=2
170#define NUMOFINBUFFERSFULL     5
171
172// Number of out-URBs which send the data: min=2
173#define NUMOFOUTBUFFERSFULL    5
174
175// Number of in-URBs which receive the data: min=5
176#define NUMOFINBUFFERSHIGH     10	// must have more buffers due to buggy USB ctr
177
178// Number of out-URBs which send the data: min=5
179#define NUMOFOUTBUFFERSHIGH    10	// must have more buffers due to buggy USB ctr
180
181// Total number of usbdux devices
182#define NUMUSBDUX             16
183
184// Analogue in subdevice
185#define SUBDEV_AD             0
186
187// Analogue out subdevice
188#define SUBDEV_DA             1
189
190// Digital I/O
191#define SUBDEV_DIO            2
192
193// counter
194#define SUBDEV_COUNTER        3
195
196// timer aka pwm output
197#define SUBDEV_PWM            4
198
199// number of retries to get the right dux command
200#define RETRIES 10
201
202/////////////////////////////////////////////
203// comedi constants
204static const comedi_lrange range_usbdux_ai_range = { 4, {
205			BIP_RANGE(4.096),
206			BIP_RANGE(4.096 / 2),
207			UNI_RANGE(4.096),
208			UNI_RANGE(4.096 / 2)
209	}
210};
211
212static const comedi_lrange range_usbdux_ao_range = { 2, {
213			BIP_RANGE(4.096),
214			UNI_RANGE(4.096),
215	}
216};
217
218/*
219 * private structure of one subdevice
220 */
221
222// This is the structure which holds all the data of this driver
223// one sub device just now: A/D
224typedef struct {
225	// attached?
226	int attached;
227	// is it associated with a subdevice?
228	int probed;
229	// pointer to the usb-device
230	struct usb_device *usbdev;
231	// actual number of in-buffers
232	int numOfInBuffers;
233	// actual number of out-buffers
234	int numOfOutBuffers;
235	// ISO-transfer handling: buffers
236	struct urb **urbIn;
237	struct urb **urbOut;
238	// pwm-transfer handling
239	struct urb *urbPwm;
240	// PWM period
241	lsampl_t pwmPeriod;
242	// PWM internal delay for the GPIF in the FX2
243	int8_t pwmDelay;
244	// size of the PWM buffer which holds the bit pattern
245	int sizePwmBuf;
246	// input buffer for the ISO-transfer
247	int16_t *inBuffer;
248	// input buffer for single insn
249	int16_t *insnBuffer;
250	// output buffer for single DA outputs
251	int16_t *outBuffer;
252	// interface number
253	int ifnum;
254#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
255	// interface structure in 2.6
256	struct usb_interface *interface;
257#endif
258	// comedi device for the interrupt context
259	comedi_device *comedidev;
260	// is it USB_SPEED_HIGH or not?
261	short int high_speed;
262	// asynchronous command is running
263	short int ai_cmd_running;
264	short int ao_cmd_running;
265	// pwm is running
266	short int pwm_cmd_running;
267	// continous aquisition
268	short int ai_continous;
269	short int ao_continous;
270	// number of samples to aquire
271	int ai_sample_count;
272	int ao_sample_count;
273	// time between samples in units of the timer
274	unsigned int ai_timer;
275	unsigned int ao_timer;
276	// counter between aquisitions
277	unsigned int ai_counter;
278	unsigned int ao_counter;
279	// interval in frames/uframes
280	unsigned int ai_interval;
281	// D/A commands
282	int8_t *dac_commands;
283	// commands
284	int8_t *dux_commands;
285	struct semaphore sem;
286} usbduxsub_t;
287
288// The pointer to the private usb-data of the driver
289// is also the private data for the comedi-device.
290// This has to be global as the usb subsystem needs
291// global variables. The other reason is that this
292// structure must be there _before_ any comedi
293// command is issued. The usb subsystem must be
294// initialised before comedi can access it.
295static usbduxsub_t usbduxsub[NUMUSBDUX];
296
297static DECLARE_MUTEX(start_stop_sem);
298
299// Stops the data acquision
300// It should be safe to call this function from any context
301static int usbduxsub_unlink_InURBs(usbduxsub_t * usbduxsub_tmp)
302{
303	int i = 0;
304#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8)
305	int j = 0;
306#endif
307	int err = 0;
308
309	if (usbduxsub_tmp && usbduxsub_tmp->urbIn) {
310		for (i = 0; i < usbduxsub_tmp->numOfInBuffers; i++) {
311			if (usbduxsub_tmp->urbIn[i]) {
312#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8)
313				j = usb_unlink_urb(usbduxsub_tmp->urbIn[i]);
314				if (j < 0) {
315					err = j;
316				}
317#else
318				// We wait here until all transfers
319				// have been cancelled.
320				usb_kill_urb(usbduxsub_tmp->urbIn[i]);
321#endif
322			}
323#ifdef NOISY_DUX_DEBUGBUG
324			printk("comedi: usbdux: unlinked InURB %d, err=%d\n",
325				i, err);
326#endif
327		}
328	}
329	return err;
330}
331
332/* This will stop a running acquisition operation */
333// Is called from within this driver from both the
334// interrupt context and from comedi
335static int usbdux_ai_stop(usbduxsub_t * this_usbduxsub, int do_unlink)
336{
337	int ret = 0;
338
339	if (!this_usbduxsub) {
340		printk("comedi?: usbdux_ai_stop: this_usbduxsub=NULL!\n");
341		return -EFAULT;
342	}
343#ifdef NOISY_DUX_DEBUGBUG
344	printk("comedi: usbdux_ai_stop\n");
345#endif
346
347	if (do_unlink) {
348		// stop aquistion
349		ret = usbduxsub_unlink_InURBs(this_usbduxsub);
350	}
351
352	this_usbduxsub->ai_cmd_running = 0;
353
354	return ret;
355}
356
357// This will cancel a running acquisition operation.
358// This is called by comedi but never from inside the
359// driver.
360static int usbdux_ai_cancel(comedi_device * dev, comedi_subdevice * s)
361{
362	usbduxsub_t *this_usbduxsub;
363	int res = 0;
364
365	// force unlink of all urbs
366#ifdef NOISY_DUX_DEBUGBUG
367	printk("comedi: usbdux_ai_cancel\n");
368#endif
369	this_usbduxsub = dev->private;
370	if (!this_usbduxsub) {
371		printk("comedi: usbdux_ai_cancel: this_usbduxsub=NULL\n");
372		return -EFAULT;
373	}
374	// prevent other CPUs from submitting new commands just now
375	down(&this_usbduxsub->sem);
376	if (!(this_usbduxsub->probed)) {
377		up(&this_usbduxsub->sem);
378		return -ENODEV;
379	}
380	// unlink only if the urb really has been submitted
381	res = usbdux_ai_stop(this_usbduxsub, this_usbduxsub->ai_cmd_running);
382	up(&this_usbduxsub->sem);
383	return res;
384}
385
386// analogue IN
387// interrupt service routine
388#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
389static void usbduxsub_ai_IsocIrq(struct urb *urb)
390#else
391static void usbduxsub_ai_IsocIrq(struct urb *urb PT_REGS_ARG)
392#endif
393{
394	int i, err, n;
395	usbduxsub_t *this_usbduxsub;
396	comedi_device *this_comedidev;
397	comedi_subdevice *s;
398
399	// sanity checks
400	// is the urb there?
401	if (!urb) {
402		printk("comedi_: usbdux_: ao int-handler called with urb=NULL!\n");
403		return;
404	}
405	// the context variable points to the subdevice
406	this_comedidev = urb->context;
407	if (unlikely(!this_comedidev)) {
408		printk("comedi_: usbdux_: BUG! urb context is a NULL pointer!\n");
409		return;
410	}
411	// the private structure of the subdevice is usbduxsub_t
412	this_usbduxsub = this_comedidev->private;
413	if (unlikely(!this_usbduxsub)) {
414		printk("comedi_: usbdux_: BUG! private of comedi subdev is a NULL pointer!\n");
415		return;
416	}
417	// subdevice which is the AD converter
418	s = this_comedidev->subdevices + SUBDEV_AD;
419
420	// first we test if something unusual has just happened
421	switch (urb->status) {
422	case 0:
423		// copy the result in the transfer buffer
424		memcpy(this_usbduxsub->inBuffer,
425			urb->transfer_buffer, SIZEINBUF);
426		break;
427	case -EILSEQ:
428		// error in the ISOchronous data
429		// we don't copy the data into the transfer buffer
430		// and recycle the last data byte
431#ifdef CONFIG_COMEDI_DEBUG
432		printk("comedi%d: usbdux: CRC error in ISO IN stream.\n",
433			this_usbduxsub->comedidev->minor);
434#endif
435
436		break;
437
438		// happens after an unlink command
439	case -ECONNRESET:
440	case -ENOENT:
441	case -ESHUTDOWN:
442	case -ECONNABORTED:
443		if (this_usbduxsub->ai_cmd_running) {
444			// we are still running a command
445			// tell this comedi
446			s->async->events |= COMEDI_CB_EOA;
447			s->async->events |= COMEDI_CB_ERROR;
448			comedi_event(this_usbduxsub->comedidev, s);
449			// stop the transfer w/o unlink
450			usbdux_ai_stop(this_usbduxsub, 0);
451		}
452		return;
453
454		// a real error on the bus
455	default:
456		// pass error to comedi if we are really running a command
457		if (this_usbduxsub->ai_cmd_running) {
458			printk("Non-zero urb status received in ai intr context: %d\n", urb->status);
459			s->async->events |= COMEDI_CB_EOA;
460			s->async->events |= COMEDI_CB_ERROR;
461			comedi_event(this_usbduxsub->comedidev, s);
462			// don't do an unlink here
463			usbdux_ai_stop(this_usbduxsub, 0);
464		}
465		return;
466	}
467
468	// at this point we are reasonably sure that nothing dodgy has happened
469	// are we running a command?
470	if (unlikely((!(this_usbduxsub->ai_cmd_running)))) {
471		// not running a command
472		// do not continue execution if no asynchronous command is running
473		// in particular not resubmit
474		return;
475	}
476
477	urb->dev = this_usbduxsub->usbdev;
478
479	// resubmit the urb
480	err = USB_SUBMIT_URB(urb);
481	if (unlikely(err < 0)) {
482		printk("comedi_: usbdux_: urb resubmit failed in int-context! err=%d ", err);
483		if (err == -EL2NSYNC) {
484			printk("--> buggy USB host controller or bug in IRQ handler!\n");
485		} else {
486			printk("\n");
487		}
488		s->async->events |= COMEDI_CB_EOA;
489		s->async->events |= COMEDI_CB_ERROR;
490		comedi_event(this_usbduxsub->comedidev, s);
491		// don't do an unlink here
492		usbdux_ai_stop(this_usbduxsub, 0);
493		return;
494	}
495
496	this_usbduxsub->ai_counter--;
497	if (likely(this_usbduxsub->ai_counter > 0)) {
498		return;
499	}
500	// timer zero, transfer measurements to comedi
501	this_usbduxsub->ai_counter = this_usbduxsub->ai_timer;
502
503	// test, if we transmit only a fixed number of samples
504	if (!(this_usbduxsub->ai_continous)) {
505		// not continous, fixed number of samples
506		this_usbduxsub->ai_sample_count--;
507		// all samples received?
508		if (this_usbduxsub->ai_sample_count < 0) {
509			// prevent a resubmit next time
510			usbdux_ai_stop(this_usbduxsub, 0);
511			// say comedi that the acquistion is over
512			s->async->events |= COMEDI_CB_EOA;
513			comedi_event(this_usbduxsub->comedidev, s);
514			return;
515		}
516	}
517	// get the data from the USB bus and hand it over
518	// to comedi
519	n = s->async->cmd.chanlist_len;
520	for (i = 0; i < n; i++) {
521		// transfer data
522		if (CR_RANGE(s->async->cmd.chanlist[i]) <= 1) {
523			comedi_buf_put
524				(s->async,
525				le16_to_cpu(this_usbduxsub->
526					inBuffer[i]) ^ 0x800);
527		} else {
528			comedi_buf_put
529				(s->async,
530				le16_to_cpu(this_usbduxsub->inBuffer[i]));
531		}
532	}
533	// tell comedi that data is there
534	comedi_event(this_usbduxsub->comedidev, s);
535}
536
537static int usbduxsub_unlink_OutURBs(usbduxsub_t * usbduxsub_tmp)
538{
539	int i = 0;
540#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8)
541	int j = 0;
542#endif
543
544	int err = 0;
545
546	if (usbduxsub_tmp && usbduxsub_tmp->urbOut) {
547		for (i = 0; i < usbduxsub_tmp->numOfOutBuffers; i++) {
548			if (usbduxsub_tmp->urbOut[i]) {
549#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8)
550				j = usb_unlink_urb(usbduxsub_tmp->urbOut[i]);
551				if (j < err) {
552					err = j;
553				}
554#else
555				usb_kill_urb(usbduxsub_tmp->urbOut[i]);
556#endif
557			}
558#ifdef NOISY_DUX_DEBUGBUG
559			printk("comedi: usbdux: unlinked OutURB %d: res=%d\n",
560				i, err);
561#endif
562		}
563	}
564	return err;
565}
566
567/* This will cancel a running acquisition operation
568 * in any context.
569 */
570static int usbdux_ao_stop(usbduxsub_t * this_usbduxsub, int do_unlink)
571{
572	int ret = 0;
573
574	if (!this_usbduxsub) {
575#ifdef NOISY_DUX_DEBUGBUG
576		printk("comedi?: usbdux_ao_stop: this_usbduxsub=NULL!\n");
577#endif
578		return -EFAULT;
579	}
580#ifdef NOISY_DUX_DEBUGBUG
581	printk("comedi: usbdux_ao_cancel\n");
582#endif
583	if (do_unlink) {
584		ret = usbduxsub_unlink_OutURBs(this_usbduxsub);
585	}
586
587	this_usbduxsub->ao_cmd_running = 0;
588
589	return ret;
590}
591
592// force unlink
593// is called by comedi
594static int usbdux_ao_cancel(comedi_device * dev, comedi_subdevice * s)
595{
596	usbduxsub_t *this_usbduxsub = dev->private;
597	int res = 0;
598
599	if (!this_usbduxsub) {
600		printk("comedi: usbdux_ao_cancel: this_usbduxsub=NULL\n");
601		return -EFAULT;
602	}
603	// prevent other CPUs from submitting a command just now
604	down(&this_usbduxsub->sem);
605	if (!(this_usbduxsub->probed)) {
606		up(&this_usbduxsub->sem);
607		return -ENODEV;
608	}
609	// unlink only if it is really running
610	res = usbdux_ao_stop(this_usbduxsub, this_usbduxsub->ao_cmd_running);
611	up(&this_usbduxsub->sem);
612	return res;
613}
614
615#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
616static void usbduxsub_ao_IsocIrq(struct urb *urb)
617{
618#else
619static void usbduxsub_ao_IsocIrq(struct urb *urb PT_REGS_ARG)
620{
621#endif
622	int i, ret;
623	int8_t *datap;
624	usbduxsub_t *this_usbduxsub;
625	comedi_device *this_comedidev;
626	comedi_subdevice *s;
627
628	if (!urb) {
629		printk("comedi_: usbdux_: ao urb handler called with NULL ptr.\n");
630		return;
631	}
632	// the context variable points to the subdevice
633	this_comedidev = urb->context;
634	if (!this_comedidev) {
635		printk("comedi_: usbdux_: ao urb int-context is a NULL pointer.\n");
636		return;
637	}
638	// the private structure of the subdevice is usbduxsub_t
639	this_usbduxsub = this_comedidev->private;
640	if (!this_usbduxsub) {
641		printk("comedi_: usbdux_: private data structure of ao subdev is NULL p.\n");
642		return;
643	}
644
645	s = this_comedidev->subdevices + SUBDEV_DA;
646
647	switch (urb->status) {
648	case 0:
649		/* success */
650		break;
651
652		// after an unlink command, unplug, ... etc
653		// no unlink needed here. Already shutting down.
654	case -ECONNRESET:
655	case -ENOENT:
656	case -ESHUTDOWN:
657	case -ECONNABORTED:
658		if (this_usbduxsub->ao_cmd_running) {
659			s->async->events |= COMEDI_CB_EOA;
660			comedi_event(this_usbduxsub->comedidev, s);
661			usbdux_ao_stop(this_usbduxsub, 0);
662		}
663		return;
664
665		// a real error
666	default:
667		if (this_usbduxsub->ao_cmd_running) {
668			printk("comedi_: usbdux_: Non-zero urb status received in ao intr context: %d\n", urb->status);
669			s->async->events |= COMEDI_CB_ERROR;
670			s->async->events |= COMEDI_CB_EOA;
671			comedi_event(this_usbduxsub->comedidev, s);
672			// we do an unlink if we are in the high speed mode
673			usbdux_ao_stop(this_usbduxsub, 0);
674		}
675		return;
676	}
677
678	// are we actually running?
679	if (!(this_usbduxsub->ao_cmd_running)) {
680		return;
681	}
682	// normal operation: executing a command in this subdevice
683	this_usbduxsub->ao_counter--;
684	if (this_usbduxsub->ao_counter <= 0) {
685		// timer zero
686		this_usbduxsub->ao_counter = this_usbduxsub->ao_timer;
687
688		// handle non continous aquisition
689		if (!(this_usbduxsub->ao_continous)) {
690			// fixed number of samples
691			this_usbduxsub->ao_sample_count--;
692			if (this_usbduxsub->ao_sample_count < 0) {
693				// all samples transmitted
694				usbdux_ao_stop(this_usbduxsub, 0);
695				s->async->events |= COMEDI_CB_EOA;
696				comedi_event(this_usbduxsub->comedidev, s);
697				// no resubmit of the urb
698				return;
699			}
700		}
701		// transmit data to the USB bus
702		((uint8_t *) (urb->transfer_buffer))[0] =
703			s->async->cmd.chanlist_len;
704		for (i = 0; i < s->async->cmd.chanlist_len; i++) {
705			sampl_t temp;
706			if (i >= NUMOUTCHANNELS) {
707				break;
708			}
709			// pointer to the DA
710			datap = (&(((int8_t *) urb->transfer_buffer)[i * 3 + 1]));
711			// get the data from comedi
712			ret = comedi_buf_get(s->async, &temp);
713			datap[0] = temp;
714			datap[1] = temp >> 8;
715			datap[2] = this_usbduxsub->dac_commands[i];
716			// printk("data[0]=%x, data[1]=%x, data[2]=%x\n",
717			// datap[0],datap[1],datap[2]);
718			if (ret < 0) {
719				printk("comedi: usbdux: buffer underflow\n");
720				s->async->events |= COMEDI_CB_EOA;
721				s->async->events |= COMEDI_CB_OVERFLOW;
722			}
723			// transmit data to comedi
724			s->async->events |= COMEDI_CB_BLOCK;
725			comedi_event(this_usbduxsub->comedidev, s);
726		}
727	}
728	urb->transfer_buffer_length = SIZEOUTBUF;
729	urb->dev = this_usbduxsub->usbdev;
730	urb->status = 0;
731	if (this_usbduxsub->ao_cmd_running) {
732		if (this_usbduxsub->high_speed) {
733			// uframes
734			urb->interval = 8;
735		} else {
736			// frames
737			urb->interval = 1;
738		}
739		urb->number_of_packets = 1;
740		urb->iso_frame_desc[0].offset = 0;
741		urb->iso_frame_desc[0].length = SIZEOUTBUF;
742		urb->iso_frame_desc[0].status = 0;
743		if ((ret = USB_SUBMIT_URB(urb)) < 0) {
744			printk("comedi_: usbdux_: ao urb resubm failed in int-cont.");
745			printk("ret=%d", ret);
746			if (ret == EL2NSYNC) {
747				printk("--> buggy USB host controller or bug in IRQ handling!\n");
748			} else {
749				printk("\n");
750			}
751			s->async->events |= COMEDI_CB_EOA;
752			s->async->events |= COMEDI_CB_ERROR;
753			comedi_event(this_usbduxsub->comedidev, s);
754			// don't do an unlink here
755			usbdux_ao_stop(this_usbduxsub, 0);
756		}
757	}
758}
759
760static int usbduxsub_start(usbduxsub_t * usbduxsub)
761{
762	int errcode = 0;
763	uint8_t local_transfer_buffer[16];
764
765	if (usbduxsub->probed) {
766		// 7f92 to zero
767		local_transfer_buffer[0] = 0;
768		errcode = USB_CONTROL_MSG(usbduxsub->usbdev,
769			// create a pipe for a control transfer
770			usb_sndctrlpipe(usbduxsub->usbdev, 0),
771			// bRequest, "Firmware"
772			USBDUXSUB_FIRMWARE,
773			// bmRequestType
774			VENDOR_DIR_OUT,
775			// Value
776			USBDUXSUB_CPUCS,
777			// Index
778			0x0000,
779			// address of the transfer buffer
780			local_transfer_buffer,
781			// Length
782			1,
783			// Timeout
784			EZTIMEOUT);
785		if (errcode < 0) {
786			printk("comedi_: usbdux_: control msg failed (start)\n");
787			return errcode;
788		}
789	}
790	return 0;
791}
792
793static int usbduxsub_stop(usbduxsub_t * usbduxsub)
794{
795	int errcode = 0;
796
797	uint8_t local_transfer_buffer[16];
798	if (usbduxsub->probed) {
799		// 7f92 to one
800		local_transfer_buffer[0] = 1;
801		errcode = USB_CONTROL_MSG
802			(usbduxsub->usbdev,
803			usb_sndctrlpipe(usbduxsub->usbdev, 0),
804			// bRequest, "Firmware"
805			USBDUXSUB_FIRMWARE,
806			// bmRequestType
807			VENDOR_DIR_OUT,
808			// Value
809			USBDUXSUB_CPUCS,
810			// Index
811			0x0000, local_transfer_buffer,
812			// Length
813			1,
814			// Timeout
815			EZTIMEOUT);
816		if (errcode < 0) {
817			printk("comedi_: usbdux: control msg failed (stop)\n");
818			return errcode;
819		}
820	}
821	return 0;
822}
823
824static int usbduxsub_upload(usbduxsub_t * usbduxsub,
825	uint8_t * local_transfer_buffer,
826	unsigned int startAddr, unsigned int len)
827{
828	int errcode;
829
830	if (usbduxsub->probed) {
831#ifdef CONFIG_COMEDI_DEBUG
832		printk("comedi%d: usbdux: uploading %d bytes",
833			usbduxsub->comedidev->minor, len);
834		printk(" to addr %d, first byte=%d.\n",
835			startAddr, local_transfer_buffer[0]);
836#endif
837		errcode = USB_CONTROL_MSG
838			(usbduxsub->usbdev,
839			usb_sndctrlpipe(usbduxsub->usbdev, 0),
840			// brequest, firmware
841			USBDUXSUB_FIRMWARE,
842			// bmRequestType
843			VENDOR_DIR_OUT,
844			// value
845			startAddr,
846			// index
847			0x0000,
848			// our local safe buffer
849			local_transfer_buffer,
850			// length
851			len,
852			// timeout
853			EZTIMEOUT);
854#ifdef NOISY_DUX_DEBUGBUG
855		printk("comedi_: usbdux: result=%d\n", errcode);
856#endif
857		if (errcode < 0) {
858			printk("comedi_: usbdux: uppload failed\n");
859			return errcode;
860		}
861	} else {
862		// no device on the bus for this index
863		return -EFAULT;
864	}
865	return 0;
866}
867
868int firmwareUpload(usbduxsub_t * usbduxsub,
869	uint8_t * firmwareBinary, int sizeFirmware)
870{
871	int ret;
872
873	if (!firmwareBinary) {
874		return 0;
875	}
876	ret = usbduxsub_stop(usbduxsub);
877	if (ret < 0) {
878		printk("comedi_: usbdux: can not stop firmware\n");
879		return ret;
880	}
881	ret = usbduxsub_upload(usbduxsub, firmwareBinary, 0, sizeFirmware);
882	if (ret < 0) {
883		printk("comedi_: usbdux: firmware upload failed\n");
884		return ret;
885	}
886	ret = usbduxsub_start(usbduxsub);
887	if (ret < 0) {
888		printk("comedi_: usbdux: can not start firmware\n");
889		return ret;
890	}
891	return 0;
892}
893
894int usbduxsub_submit_InURBs(usbduxsub_t * usbduxsub)
895{
896	int i, errFlag;
897
898	if (!usbduxsub) {
899		return -EFAULT;
900	}
901	/* Submit all URBs and start the transfer on the bus */
902	for (i = 0; i < usbduxsub->numOfInBuffers; i++) {
903		// in case of a resubmission after an unlink...
904		usbduxsub->urbIn[i]->interval = usbduxsub->ai_interval;
905		usbduxsub->urbIn[i]->context = usbduxsub->comedidev;
906		usbduxsub->urbIn[i]->dev = usbduxsub->usbdev;
907		usbduxsub->urbIn[i]->status = 0;
908		usbduxsub->urbIn[i]->transfer_flags = URB_ISO_ASAP;
909#ifdef NOISY_DUX_DEBUGBUG
910		printk("comedi%d: usbdux: submitting in-urb[%d]: %p,%p intv=%d\n", usbduxsub->comedidev->minor, i, (usbduxsub->urbIn[i]->context), (usbduxsub->urbIn[i]->dev), (usbduxsub->urbIn[i]->interval));
911#endif
912		errFlag = USB_SUBMIT_URB(usbduxsub->urbIn[i]);
913		if (errFlag) {
914			printk("comedi_: usbdux: ai: ");
915			printk("USB_SUBMIT_URB(%d)", i);
916			printk(" error %d\n", errFlag);
917			return errFlag;
918		}
919	}
920	return 0;
921}
922
923int usbduxsub_submit_OutURBs(usbduxsub_t * usbduxsub)
924{
925	int i, errFlag;
926
927	if (!usbduxsub) {
928		return -EFAULT;
929	}
930	for (i = 0; i < usbduxsub->numOfOutBuffers; i++) {
931#ifdef NOISY_DUX_DEBUGBUG
932		printk("comedi_: usbdux: submitting out-urb[%d]\n", i);
933#endif
934		// in case of a resubmission after an unlink...
935		usbduxsub->urbOut[i]->context = usbduxsub->comedidev;
936		usbduxsub->urbOut[i]->dev = usbduxsub->usbdev;
937		usbduxsub->urbOut[i]->status = 0;
938		usbduxsub->urbOut[i]->transfer_flags = URB_ISO_ASAP;
939		errFlag = USB_SUBMIT_URB(usbduxsub->urbOut[i]);
940		if (errFlag) {
941			printk("comedi_: usbdux: ao: ");
942			printk("USB_SUBMIT_URB(%d)", i);
943			printk(" error %d\n", errFlag);
944			return errFlag;
945		}
946	}
947	return 0;
948}
949
950static int usbdux_ai_cmdtest(comedi_device * dev,
951	comedi_subdevice * s, comedi_cmd * cmd)
952{
953	int err = 0, tmp, i;
954	unsigned int tmpTimer;
955	usbduxsub_t *this_usbduxsub = dev->private;
956	if (!(this_usbduxsub->probed)) {
957		return -ENODEV;
958	}
959#ifdef NOISY_DUX_DEBUGBUG
960	printk("comedi%d: usbdux_ai_cmdtest\n", dev->minor);
961#endif
962	/* make sure triggers are valid */
963	// Only immediate triggers are allowed
964	tmp = cmd->start_src;
965	cmd->start_src &= TRIG_NOW | TRIG_INT;
966	if (!cmd->start_src || tmp != cmd->start_src)
967		err++;
968
969	// trigger should happen timed
970	tmp = cmd->scan_begin_src;
971	// start a new _scan_ with a timer
972	cmd->scan_begin_src &= TRIG_TIMER;
973	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
974		err++;
975
976	// scanning is continous
977	tmp = cmd->convert_src;
978	cmd->convert_src &= TRIG_NOW;
979	if (!cmd->convert_src || tmp != cmd->convert_src)
980		err++;
981
982	// issue a trigger when scan is finished and start a new scan
983	tmp = cmd->scan_end_src;
984	cmd->scan_end_src &= TRIG_COUNT;
985	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
986		err++;
987
988	// trigger at the end of count events or not, stop condition or not
989	tmp = cmd->stop_src;
990	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
991	if (!cmd->stop_src || tmp != cmd->stop_src)
992		err++;
993
994	if (err)
995		return 1;
996
997	/* step 2: make sure trigger sources are unique and mutually compatible */
998	/* note that mutual compatiblity is not an issue here */
999	if (cmd->scan_begin_src != TRIG_FOLLOW &&
1000		cmd->scan_begin_src != TRIG_EXT &&
1001		cmd->scan_begin_src != TRIG_TIMER)
1002		err++;
1003	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
1004		err++;
1005
1006	if (err)
1007		return 2;
1008
1009	/* step 3: make sure arguments are trivially compatible */
1010
1011	if (cmd->start_arg != 0) {
1012		cmd->start_arg = 0;
1013		err++;
1014	}
1015
1016	if (cmd->scan_begin_src == TRIG_FOLLOW) {
1017		/* internal trigger */
1018		if (cmd->scan_begin_arg != 0) {
1019			cmd->scan_begin_arg = 0;
1020			err++;
1021		}
1022	}
1023
1024	if (cmd->scan_begin_src == TRIG_TIMER) {
1025		if (this_usbduxsub->high_speed) {
1026			// In high speed mode microframes are possible.
1027			// However, during one microframe we can roughly
1028			// sample one channel. Thus, the more channels
1029			// are in the channel list the more time we need.
1030			i = 1;
1031			// find a power of 2 for the number of channels
1032			while (i < (cmd->chanlist_len)) {
1033				i = i * 2;
1034			}
1035			if (cmd->scan_begin_arg < (1000000 / 8 * i)) {
1036				cmd->scan_begin_arg = 1000000 / 8 * i;
1037				err++;
1038			}
1039			// now calc the real sampling rate with all the rounding errors
1040			tmpTimer =
1041				((unsigned int)(cmd->scan_begin_arg / 125000)) *
1042				125000;
1043			if (cmd->scan_begin_arg != tmpTimer) {
1044				cmd->scan_begin_arg = tmpTimer;
1045				err++;
1046			}
1047		} else {	// full speed
1048			// 1kHz scans every USB frame
1049			if (cmd->scan_begin_arg < 1000000) {
1050				cmd->scan_begin_arg = 1000000;
1051				err++;
1052			}
1053			// calc the real sampling rate with the rounding errors
1054			tmpTimer =
1055				((unsigned int)(cmd->scan_begin_arg /
1056					1000000)) * 1000000;
1057			if (cmd->scan_begin_arg != tmpTimer) {
1058				cmd->scan_begin_arg = tmpTimer;
1059				err++;
1060			}
1061		}
1062	}
1063	// the same argument
1064	if (cmd->scan_end_arg != cmd->chanlist_len) {
1065		cmd->scan_end_arg = cmd->chanlist_len;
1066		err++;
1067	}
1068
1069	if (cmd->stop_src == TRIG_COUNT) {
1070		/* any count is allowed */
1071	} else {
1072		/* TRIG_NONE */
1073		if (cmd->stop_arg != 0) {
1074			cmd->stop_arg = 0;
1075			err++;
1076		}
1077	}
1078
1079	if (err)
1080		return 3;
1081
1082	return 0;
1083}
1084
1085// creates the ADC command for the MAX1271
1086// range is the range value from comedi
1087static int8_t create_adc_command(unsigned int chan, int range)
1088{
1089	int8_t p = (range <= 1);
1090	int8_t r = ((range % 2) == 0);
1091	return (chan << 4) | ((p == 1) << 2) | ((r == 1) << 3);
1092}
1093
1094// bulk transfers to usbdux
1095
1096#define SENDADCOMMANDS            0
1097#define SENDDACOMMANDS            1
1098#define SENDDIOCONFIGCOMMAND      2
1099#define SENDDIOBITSCOMMAND        3
1100#define SENDSINGLEAD              4
1101#define READCOUNTERCOMMAND        5
1102#define WRITECOUNTERCOMMAND       6
1103#define SENDPWMON                 7
1104#define SENDPWMOFF                8
1105
1106static int send_dux_commands(usbduxsub_t * this_usbduxsub, int cmd_type)
1107{
1108	int result, nsent;
1109
1110	this_usbduxsub->dux_commands[0] = cmd_type;
1111#ifdef NOISY_DUX_DEBUGBUG
1112	printk("comedi%d: usbdux: dux_commands: ",
1113		this_usbduxsub->comedidev->minor);
1114	for (result = 0; result < SIZEOFDUXBUFFER; result++) {
1115		printk(" %02x", this_usbduxsub->dux_commands[result]);
1116	}
1117	printk("\n");
1118#endif
1119	result = USB_BULK_MSG(this_usbduxsub->usbdev,
1120		usb_sndbulkpipe(this_usbduxsub->usbdev,
1121			COMMAND_OUT_EP),
1122		this_usbduxsub->dux_commands, SIZEOFDUXBUFFER, &nsent, 10 * HZ);
1123	if (result < 0) {
1124		printk("comedi%d: could not transmit dux_command to the usb-device, err=%d\n", this_usbduxsub->comedidev->minor, result);
1125	}
1126	return result;
1127}
1128
1129static int receive_dux_commands(usbduxsub_t * this_usbduxsub, int command)
1130{
1131	int result = (-EFAULT);
1132	int nrec;
1133	int i;
1134
1135	for (i = 0; i < RETRIES; i++) {
1136		result = USB_BULK_MSG(this_usbduxsub->usbdev,
1137			usb_rcvbulkpipe(this_usbduxsub->usbdev,
1138				COMMAND_IN_EP),
1139			this_usbduxsub->insnBuffer, SIZEINSNBUF, &nrec, 1 * HZ);
1140		if (result < 0) {
1141			printk("comedi%d: insn: USB error %d while receiving DUX command\n", this_usbduxsub->comedidev->minor, result);
1142			return result;
1143		}
1144		if (le16_to_cpu(this_usbduxsub->insnBuffer[0]) == command) {
1145			return result;
1146		}
1147	}
1148	// this is only reached if the data has been requested a couple of times
1149	printk("comedi%d: insn: wrong data returned from firmware: want cmd %d, got cmd %d.\n", this_usbduxsub->comedidev->minor, command, le16_to_cpu(this_usbduxsub->insnBuffer[0]));
1150	return -EFAULT;
1151}
1152
1153static int usbdux_ai_inttrig(comedi_device * dev,
1154	comedi_subdevice * s, unsigned int trignum)
1155{
1156	int ret;
1157	usbduxsub_t *this_usbduxsub = dev->private;
1158	if (!this_usbduxsub) {
1159		return -EFAULT;
1160	}
1161	down(&this_usbduxsub->sem);
1162	if (!(this_usbduxsub->probed)) {
1163		up(&this_usbduxsub->sem);
1164		return -ENODEV;
1165	}
1166#ifdef NOISY_DUX_DEBUGBUG
1167	printk("comedi%d: usbdux_ai_inttrig\n", dev->minor);
1168#endif
1169
1170	if (trignum != 0) {
1171		printk("comedi%d: usbdux_ai_inttrig: invalid trignum\n",
1172			dev->minor);
1173		up(&this_usbduxsub->sem);
1174		return -EINVAL;
1175	}
1176	if (!(this_usbduxsub->ai_cmd_running)) {
1177		this_usbduxsub->ai_cmd_running = 1;
1178		ret = usbduxsub_submit_InURBs(this_usbduxsub);
1179		if (ret < 0) {
1180			printk("comedi%d: usbdux_ai_inttrig: urbSubmit: err=%d\n", dev->minor, ret);
1181			this_usbduxsub->ai_cmd_running = 0;
1182			up(&this_usbduxsub->sem);
1183			return ret;
1184		}
1185		s->async->inttrig = NULL;
1186	} else {
1187		printk("comedi%d: ai_inttrig but acqu is already running\n",
1188			dev->minor);
1189	}
1190	up(&this_usbduxsub->sem);
1191	return 1;
1192}
1193
1194static int usbdux_ai_cmd(comedi_device * dev, comedi_subdevice * s)
1195{
1196	comedi_cmd *cmd = &s->async->cmd;
1197	unsigned int chan, range;
1198	int i, ret;
1199	usbduxsub_t *this_usbduxsub = dev->private;
1200	int result;
1201
1202#ifdef NOISY_DUX_DEBUGBUG
1203	printk("comedi%d: usbdux_ai_cmd\n", dev->minor);
1204#endif
1205	if (!this_usbduxsub) {
1206		return -EFAULT;
1207	}
1208	// block other CPUs from starting an ai_cmd
1209	down(&this_usbduxsub->sem);
1210
1211	if (!(this_usbduxsub->probed)) {
1212		up(&this_usbduxsub->sem);
1213		return -ENODEV;
1214	}
1215	if (this_usbduxsub->ai_cmd_running) {
1216		printk("comedi%d: ai_cmd not possible. Another ai_cmd is running.\n", dev->minor);
1217		up(&this_usbduxsub->sem);
1218		return -EBUSY;
1219	}
1220	// set current channel of the running aquisition to zero
1221	s->async->cur_chan = 0;
1222
1223	this_usbduxsub->dux_commands[1] = cmd->chanlist_len;
1224	for (i = 0; i < cmd->chanlist_len; ++i) {
1225		chan = CR_CHAN(cmd->chanlist[i]);
1226		range = CR_RANGE(cmd->chanlist[i]);
1227		if (i >= NUMCHANNELS) {
1228			printk("comedi%d: channel list too long\n", dev->minor);
1229			break;
1230		}
1231		this_usbduxsub->dux_commands[i + 2] =
1232			create_adc_command(chan, range);
1233	}
1234
1235#ifdef NOISY_DUX_DEBUGBUG
1236	printk("comedi %d: sending commands to the usb device: ", dev->minor);
1237	printk("size=%u\n", NUMCHANNELS);
1238#endif
1239	if ((result = send_dux_commands(this_usbduxsub, SENDADCOMMANDS)) < 0) {
1240		up(&this_usbduxsub->sem);
1241		return result;
1242	}
1243
1244	if (this_usbduxsub->high_speed) {
1245		// every channel gets a time window of 125us. Thus, if we
1246		// sample all 8 channels we need 1ms. If we sample only
1247		// one channel we need only 125us
1248		this_usbduxsub->ai_interval = 1;
1249		// find a power of 2 for the interval
1250		while ((this_usbduxsub->ai_interval) < (cmd->chanlist_len)) {
1251			this_usbduxsub->ai_interval =
1252				(this_usbduxsub->ai_interval) * 2;
1253		}
1254		this_usbduxsub->ai_timer =
1255			cmd->scan_begin_arg / (125000 *
1256			(this_usbduxsub->ai_interval));
1257	} else {
1258		// interval always 1ms
1259		this_usbduxsub->ai_interval = 1;
1260		this_usbduxsub->ai_timer = cmd->scan_begin_arg / 1000000;
1261	}
1262	if (this_usbduxsub->ai_timer < 1) {
1263		printk("comedi%d: usbdux: ai_cmd: timer=%d, scan_begin_arg=%d. Not properly tested by cmdtest?\n", dev->minor, this_usbduxsub->ai_timer, cmd->scan_begin_arg);
1264		up(&this_usbduxsub->sem);
1265		return -EINVAL;
1266	}
1267	this_usbduxsub->ai_counter = this_usbduxsub->ai_timer;
1268
1269	if (cmd->stop_src == TRIG_COUNT) {
1270		// data arrives as one packet
1271		this_usbduxsub->ai_sample_count = cmd->stop_arg;
1272		this_usbduxsub->ai_continous = 0;
1273	} else {
1274		// continous aquisition
1275		this_usbduxsub->ai_continous = 1;
1276		this_usbduxsub->ai_sample_count = 0;
1277	}
1278
1279	if (cmd->start_src == TRIG_NOW) {
1280		// enable this acquisition operation
1281		this_usbduxsub->ai_cmd_running = 1;
1282		ret = usbduxsub_submit_InURBs(this_usbduxsub);
1283		if (ret < 0) {
1284			this_usbduxsub->ai_cmd_running = 0;
1285			// fixme: unlink here??
1286			up(&this_usbduxsub->sem);
1287			return ret;
1288		}
1289		s->async->inttrig = NULL;
1290	} else {
1291		/* TRIG_INT */
1292		// don't enable the acquision operation
1293		// wait for an internal signal
1294		s->async->inttrig = usbdux_ai_inttrig;
1295	}
1296	up(&this_usbduxsub->sem);
1297	return 0;
1298}
1299
1300/* Mode 0 is used to get a single conversion on demand */
1301static int usbdux_ai_insn_read(comedi_device * dev,
1302	comedi_subdevice * s, comedi_insn * insn, lsampl_t * data)
1303{
1304	int i;
1305	lsampl_t one = 0;
1306	int chan, range;
1307	int err;
1308	usbduxsub_t *this_usbduxsub = dev->private;
1309
1310	if (!this_usbduxsub) {
1311		printk("comedi%d: ai_insn_read: no usb dev.\n", dev->minor);
1312		return 0;
1313	}
1314#ifdef NOISY_DUX_DEBUGBUG
1315	printk("comedi%d: ai_insn_read, insn->n=%d, insn->subdev=%d\n",
1316		dev->minor, insn->n, insn->subdev);
1317#endif
1318	down(&this_usbduxsub->sem);
1319	if (!(this_usbduxsub->probed)) {
1320		up(&this_usbduxsub->sem);
1321		return -ENODEV;
1322	}
1323	if (this_usbduxsub->ai_cmd_running) {
1324		printk("comedi%d: ai_insn_read not possible. Async Command is running.\n", dev->minor);
1325		up(&this_usbduxsub->sem);
1326		return 0;
1327	}
1328
1329	// sample one channel
1330	chan = CR_CHAN(insn->chanspec);
1331	range = CR_RANGE(insn->chanspec);
1332	// set command for the first channel
1333	this_usbduxsub->dux_commands[1] = create_adc_command(chan, range);
1334
1335	// adc commands
1336	if ((err = send_dux_commands(this_usbduxsub, SENDSINGLEAD)) < 0) {
1337		up(&this_usbduxsub->sem);
1338		return err;
1339	}
1340
1341	for (i = 0; i < insn->n; i++) {
1342		if ((err = receive_dux_commands(this_usbduxsub,
1343					SENDSINGLEAD)) < 0) {
1344			up(&this_usbduxsub->sem);
1345			return 0;
1346		}
1347		one = le16_to_cpu(this_usbduxsub->insnBuffer[1]);
1348		if (CR_RANGE(insn->chanspec) <= 1) {
1349			one = one ^ 0x800;
1350		}
1351		data[i] = one;
1352	}
1353	up(&this_usbduxsub->sem);
1354	return i;
1355}
1356
1357//////////////////
1358// analog out
1359
1360static int usbdux_ao_insn_read(comedi_device * dev, comedi_subdevice * s,
1361	comedi_insn * insn, lsampl_t * data)
1362{
1363	int i;
1364	int chan = CR_CHAN(insn->chanspec);
1365	usbduxsub_t *this_usbduxsub = dev->private;
1366
1367	if (!this_usbduxsub) {
1368		return -EFAULT;
1369	}
1370	down(&this_usbduxsub->sem);
1371	if (!(this_usbduxsub->probed)) {
1372		up(&this_usbduxsub->sem);
1373		return -ENODEV;
1374	}
1375	for (i = 0; i < insn->n; i++) {
1376		data[i] = this_usbduxsub->outBuffer[chan];
1377	}
1378	up(&this_usbduxsub->sem);
1379	return i;
1380}
1381
1382static int usbdux_ao_insn_write(comedi_device * dev, comedi_subdevice * s,
1383	comedi_insn * insn, lsampl_t * data)
1384{
1385	int i, err;
1386	int chan = CR_CHAN(insn->chanspec);
1387	usbduxsub_t *this_usbduxsub = dev->private;
1388
1389#ifdef NOISY_DUX_DEBUGBUG
1390	printk("comedi%d: ao_insn_write\n", dev->minor);
1391#endif
1392	if (!this_usbduxsub) {
1393		return -EFAULT;
1394	}
1395	down(&this_usbduxsub->sem);
1396	if (!(this_usbduxsub->probed)) {
1397		up(&this_usbduxsub->sem);
1398		return -ENODEV;
1399	}
1400	if (this_usbduxsub->ao_cmd_running) {
1401		printk("comedi%d: ao_insn_write: ERROR: asynchronous ao_cmd is running\n", dev->minor);
1402		up(&this_usbduxsub->sem);
1403		return 0;
1404	}
1405
1406	for (i = 0; i < insn->n; i++) {
1407#ifdef NOISY_DUX_DEBUGBUG
1408		printk("comedi%d: ao_insn_write: data[chan=%d,i=%d]=%d\n",
1409			dev->minor, chan, i, data[i]);
1410#endif
1411		// number of channels: 1
1412		this_usbduxsub->dux_commands[1] = 1;
1413		// one 16 bit value
1414		*((int16_t *) (this_usbduxsub->dux_commands + 2)) =
1415			cpu_to_le16(data[i]);
1416		this_usbduxsub->outBuffer[chan] = data[i];
1417		// channel number
1418		this_usbduxsub->dux_commands[4] = (chan << 6);
1419		if ((err = send_dux_commands(this_usbduxsub,
1420					SENDDACOMMANDS)) < 0) {
1421			up(&this_usbduxsub->sem);
1422			return err;
1423		}
1424	}
1425	up(&this_usbduxsub->sem);
1426
1427	return i;
1428}
1429
1430static int usbdux_ao_inttrig(comedi_device * dev, comedi_subdevice * s,
1431	unsigned int trignum)
1432{
1433	int ret;
1434	usbduxsub_t *this_usbduxsub = dev->private;
1435
1436	if (!this_usbduxsub) {
1437		return -EFAULT;
1438	}
1439	down(&this_usbduxsub->sem);
1440	if (!(this_usbduxsub->probed)) {
1441		up(&this_usbduxsub->sem);
1442		return -ENODEV;
1443	}
1444	if (trignum != 0) {
1445		printk("comedi%d: usbdux_ao_inttrig: invalid trignum\n",
1446			dev->minor);
1447		return -EINVAL;
1448	}
1449	if (!(this_usbduxsub->ao_cmd_running)) {
1450		this_usbduxsub->ao_cmd_running = 1;
1451		ret = usbduxsub_submit_OutURBs(this_usbduxsub);
1452		if (ret < 0) {
1453			printk("comedi%d: usbdux_ao_inttrig: submitURB: err=%d\n", dev->minor, ret);
1454			this_usbduxsub->ao_cmd_running = 0;
1455			up(&this_usbduxsub->sem);
1456			return ret;
1457		}
1458		s->async->inttrig = NULL;
1459	} else {
1460		printk("comedi%d: ao_inttrig but acqu is already running.\n",
1461			dev->minor);
1462	}
1463	up(&this_usbduxsub->sem);
1464	return 1;
1465}
1466
1467static int usbdux_ao_cmdtest(comedi_device * dev,
1468	comedi_subdevice * s, comedi_cmd * cmd)
1469{
1470	int err = 0, tmp;
1471	usbduxsub_t *this_usbduxsub = dev->private;
1472
1473	if (!this_usbduxsub) {
1474		return -EFAULT;
1475	}
1476	if (!(this_usbduxsub->probed)) {
1477		return -ENODEV;
1478	}
1479#ifdef NOISY_DUX_DEBUGBUG
1480	printk("comedi%d: usbdux_ao_cmdtest\n", dev->minor);
1481#endif
1482	/* make sure triggers are valid */
1483	// Only immediate triggers are allowed
1484	tmp = cmd->start_src;
1485	cmd->start_src &= TRIG_NOW | TRIG_INT;
1486	if (!cmd->start_src || tmp != cmd->start_src)
1487		err++;
1488
1489	// trigger should happen timed
1490	tmp = cmd->scan_begin_src;
1491	// just now we scan also in the high speed mode every frame
1492	// this is due to ehci driver limitations
1493	if (0) {		/* (this_usbduxsub->high_speed) */
1494		// start immidiately a new scan
1495		// the sampling rate is set by the coversion rate
1496		cmd->scan_begin_src &= TRIG_FOLLOW;
1497	} else {
1498		// start a new scan (output at once) with a timer
1499		cmd->scan_begin_src &= TRIG_TIMER;
1500	}
1501	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1502		err++;
1503
1504	// scanning is continous
1505	tmp = cmd->convert_src;
1506	// we always output at 1kHz just now all channels at once
1507	if (0) {		/* (this_usbduxsub->high_speed) */
1508		// in usb-2.0 only one conversion it tranmitted but with 8kHz/n
1509		cmd->convert_src &= TRIG_TIMER;
1510	} else {
1511		// all conversion events happen simultaneously with a rate of 1kHz/n
1512		cmd->convert_src &= TRIG_NOW;
1513	}
1514	if (!cmd->convert_src || tmp != cmd->convert_src)
1515		err++;
1516
1517	// issue a trigger when scan is finished and start a new scan
1518	tmp = cmd->scan_end_src;
1519	cmd->scan_end_src &= TRIG_COUNT;
1520	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1521		err++;
1522
1523	// trigger at the end of count events or not, stop condition or not
1524	tmp = cmd->stop_src;
1525	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
1526	if (!cmd->stop_src || tmp != cmd->stop_src)
1527		err++;
1528
1529	if (err)
1530		return 1;
1531
1532	/* step 2: make sure trigger sources are unique and mutually compatible */
1533	/* note that mutual compatiblity is not an issue here */
1534	if (cmd->scan_begin_src != TRIG_FOLLOW &&
1535		cmd->scan_begin_src != TRIG_EXT &&
1536		cmd->scan_begin_src != TRIG_TIMER)
1537		err++;
1538	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
1539		err++;
1540
1541	if (err)
1542		return 2;
1543
1544	/* step 3: make sure arguments are trivially compatible */
1545
1546	if (cmd->start_arg != 0) {
1547		cmd->start_arg = 0;
1548		err++;
1549	}
1550
1551	if (cmd->scan_begin_src == TRIG_FOLLOW) {
1552		/* internal trigger */
1553		if (cmd->scan_begin_arg != 0) {
1554			cmd->scan_begin_arg = 0;
1555			err++;
1556		}
1557	}
1558
1559	if (cmd->scan_begin_src == TRIG_TIMER) {
1560		/* timer */
1561		if (cmd->scan_begin_arg < 1000000) {
1562			cmd->scan_begin_arg = 1000000;
1563			err++;
1564		}
1565	}
1566	// not used now, is for later use
1567	if (cmd->convert_src == TRIG_TIMER) {
1568		if (cmd->convert_arg < 125000) {
1569			cmd->convert_arg = 125000;
1570			err++;
1571		}
1572	}
1573
1574	// the same argument
1575	if (cmd->scan_end_arg != cmd->chanlist_len) {
1576		cmd->scan_end_arg = cmd->chanlist_len;
1577		err++;
1578	}
1579
1580	if (cmd->stop_src == TRIG_COUNT) {
1581		/* any count is allowed */
1582	} else {
1583		/* TRIG_NONE */
1584		if (cmd->stop_arg != 0) {
1585			cmd->stop_arg = 0;
1586			err++;
1587		}
1588	}
1589
1590#ifdef NOISY_DUX_DEBUGBUG
1591	printk("comedi%d: err=%d, scan_begin_src=%d, scan_begin_arg=%d, convert_src=%d, convert_arg=%d\n", dev->minor, err, cmd->scan_begin_src, cmd->scan_begin_arg, cmd->convert_src, cmd->convert_arg);
1592#endif
1593
1594	if (err)
1595		return 3;
1596
1597	return 0;
1598}
1599
1600static int usbdux_ao_cmd(comedi_device * dev, comedi_subdevice * s)
1601{
1602	comedi_cmd *cmd = &s->async->cmd;
1603	unsigned int chan, gain;
1604	int i, ret;
1605	usbduxsub_t *this_usbduxsub = dev->private;
1606
1607	if (!this_usbduxsub) {
1608		return -EFAULT;
1609	}
1610	down(&this_usbduxsub->sem);
1611	if (!(this_usbduxsub->probed)) {
1612		up(&this_usbduxsub->sem);
1613		return -ENODEV;
1614	}
1615#ifdef NOISY_DUX_DEBUGBUG
1616	printk("comedi%d: usbdux_ao_cmd\n", dev->minor);
1617#endif
1618
1619	// set current channel of the running aquisition to zero
1620	s->async->cur_chan = 0;
1621	for (i = 0; i < cmd->chanlist_len; ++i) {
1622		chan = CR_CHAN(cmd->chanlist[i]);
1623		gain = CR_RANGE(cmd->chanlist[i]);
1624		if (i >= NUMOUTCHANNELS) {
1625			printk("comedi%d: usbdux_ao_cmd: channel list too long\n", dev->minor);
1626			break;
1627		}
1628		this_usbduxsub->dac_commands[i] = (chan << 6);
1629#ifdef NOISY_DUX_DEBUGBUG
1630		printk("comedi%d: dac command for ch %d is %x\n",
1631			dev->minor, i, this_usbduxsub->dac_commands[i]);
1632#endif
1633	}
1634
1635	// we count in steps of 1ms (125us)
1636	// 125us mode not used yet
1637	if (0) {		/* (this_usbduxsub->high_speed) */
1638		// 125us
1639		// timing of the conversion itself: every 125 us
1640		this_usbduxsub->ao_timer = cmd->convert_arg / 125000;
1641	} else {
1642		// 1ms
1643		// timing of the scan: we get all channels at once
1644		this_usbduxsub->ao_timer = cmd->scan_begin_arg / 1000000;
1645#ifdef NOISY_DUX_DEBUGBUG
1646		printk("comedi%d: usbdux: scan_begin_src=%d, scan_begin_arg=%d, convert_src=%d, convert_arg=%d\n", dev->minor, cmd->scan_begin_src, cmd->scan_begin_arg, cmd->convert_src, cmd->convert_arg);
1647		printk("comedi%d: usbdux: ao_timer=%d (ms)\n",
1648			dev->minor, this_usbduxsub->ao_timer);
1649#endif
1650		if (this_usbduxsub->ao_timer < 1) {
1651			printk("comedi%d: usbdux: ao_timer=%d,  scan_begin_arg=%d. Not properly tested by cmdtest?\n", dev->minor, this_usbduxsub->ao_timer, cmd->scan_begin_arg);
1652			up(&this_usbduxsub->sem);
1653			return -EINVAL;
1654		}
1655	}
1656	this_usbduxsub->ao_counter = this_usbduxsub->ao_timer;
1657
1658	if (cmd->stop_src == TRIG_COUNT) {
1659		// not continous
1660		// counter
1661		// high speed also scans everything at once
1662		if (0) {	/* (this_usbduxsub->high_speed) */
1663			this_usbduxsub->ao_sample_count =
1664				(cmd->stop_arg) * (cmd->scan_end_arg);
1665		} else {
1666			// there's no scan as the scan has been
1667			// perf inside the FX2
1668			// data arrives as one packet
1669			this_usbduxsub->ao_sample_count = cmd->stop_arg;
1670		}
1671		this_usbduxsub->ao_continous = 0;
1672	} else {
1673		// continous aquisition
1674		this_usbduxsub->ao_continous = 1;
1675		this_usbduxsub->ao_sample_count = 0;
1676	}
1677
1678	if (cmd->start_src == TRIG_NOW) {
1679		// enable this acquisition operation
1680		this_usbduxsub->ao_cmd_running = 1;
1681		ret = usbduxsub_submit_OutURBs(this_usbduxsub);
1682		if (ret < 0) {
1683			this_usbduxsub->ao_cmd_running = 0;
1684			// fixme: unlink here??
1685			up(&this_usbduxsub->sem);
1686			return ret;
1687		}
1688		s->async->inttrig = NULL;
1689	} else {
1690		/* TRIG_INT */
1691		// submit the urbs later
1692		// wait for an internal signal
1693		s->async->inttrig = usbdux_ao_inttrig;
1694	}
1695
1696	up(&this_usbduxsub->sem);
1697	return 0;
1698}
1699
1700static int usbdux_dio_insn_config(comedi_device * dev,
1701	comedi_subdevice * s, comedi_insn * insn, lsampl_t * data)
1702{
1703	int chan = CR_CHAN(insn->chanspec);
1704
1705	/* The input or output configuration of each digital line is
1706	 * configured by a special insn_config instruction.  chanspec
1707	 * contains the channel to be changed, and data[0] contains the
1708	 * value COMEDI_INPUT or COMEDI_OUTPUT. */
1709
1710	switch (data[0]) {
1711	case INSN_CONFIG_DIO_OUTPUT:
1712		s->io_bits |= 1 << chan;	/* 1 means Out */
1713		break;
1714	case INSN_CONFIG_DIO_INPUT:
1715		s->io_bits &= ~(1 << chan);
1716		break;
1717	case INSN_CONFIG_DIO_QUERY:
1718		data[1] =
1719			(s->
1720			io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
1721		break;
1722	default:
1723		return -EINVAL;
1724		break;
1725	}
1726	// we don't tell the firmware here as it would take 8 frames
1727	// to submit the information. We do it in the insn_bits.
1728	return insn->n;
1729}
1730
1731static int usbdux_dio_insn_bits(comedi_device * dev,
1732	comedi_subdevice * s, comedi_insn * insn, lsampl_t * data)
1733{
1734
1735	usbduxsub_t *this_usbduxsub = dev->private;
1736	int err;
1737
1738	if (!this_usbduxsub) {
1739		return -EFAULT;
1740	}
1741
1742	if (insn->n != 2)
1743		return -EINVAL;
1744
1745	down(&this_usbduxsub->sem);
1746
1747	if (!(this_usbduxsub->probed)) {
1748		up(&this_usbduxsub->sem);
1749		return -ENODEV;
1750	}
1751
1752	/* The insn data is a mask in data[0] and the new data
1753	 * in data[1], each channel cooresponding to a bit. */
1754	s->state &= ~data[0];
1755	s->state |= data[0] & data[1];
1756	this_usbduxsub->dux_commands[1] = s->io_bits;
1757	this_usbduxsub->dux_commands[2] = s->state;
1758
1759	// This command also tells the firmware to return
1760	// the digital input lines
1761	if ((err = send_dux_commands(this_usbduxsub, SENDDIOBITSCOMMAND)) < 0) {
1762		up(&this_usbduxsub->sem);
1763		return err;
1764	}
1765	if ((err = receive_dux_commands(this_usbduxsub,
1766				SENDDIOBITSCOMMAND)) < 0) {
1767		up(&this_usbduxsub->sem);
1768		return err;
1769	}
1770
1771	data[1] = le16_to_cpu(this_usbduxsub->insnBuffer[1]);
1772	up(&this_usbduxsub->sem);
1773	return 2;
1774}
1775
1776// reads the 4 counters
1777// only two are used just now
1778static int usbdux_counter_read(comedi_device * dev, comedi_subdevice * s,
1779	comedi_insn * insn, lsampl_t * data)
1780{
1781	usbduxsub_t *this_usbduxsub = dev->private;
1782	int chan = insn->chanspec;
1783	int err;
1784
1785	if (!this_usbduxsub) {
1786		return -EFAULT;
1787	}
1788
1789	down(&this_usbduxsub->sem);
1790
1791	if (!(this_usbduxsub->probed)) {
1792		up(&this_usbduxsub->sem);
1793		return -ENODEV;
1794	}
1795
1796	if ((err = send_dux_commands(this_usbduxsub, READCOUNTERCOMMAND)) < 0) {
1797		up(&this_usbduxsub->sem);
1798		return err;
1799	}
1800
1801	if ((err = receive_dux_commands(this_usbduxsub,
1802				READCOUNTERCOMMAND)) < 0) {
1803		up(&this_usbduxsub->sem);
1804		return err;
1805	}
1806
1807	data[0] = le16_to_cpu(this_usbduxsub->insnBuffer[chan + 1]);
1808	up(&this_usbduxsub->sem);
1809	return 1;
1810}
1811
1812static int usbdux_counter_write(comedi_device * dev, comedi_subdevice * s,
1813	comedi_insn * insn, lsampl_t * data)
1814{
1815	usbduxsub_t *this_usbduxsub = dev->private;
1816	int err;
1817
1818	if (!this_usbduxsub) {
1819		return -EFAULT;
1820	}
1821
1822	down(&this_usbduxsub->sem);
1823
1824	if (!(this_usbduxsub->probed)) {
1825		up(&this_usbduxsub->sem);
1826		return -ENODEV;
1827	}
1828
1829	this_usbduxsub->dux_commands[1] = insn->chanspec;
1830	*((int16_t *) (this_usbduxsub->dux_commands + 2)) = cpu_to_le16(*data);
1831
1832	if ((err = send_dux_commands(this_usbduxsub, WRITECOUNTERCOMMAND)) < 0) {
1833		up(&this_usbduxsub->sem);
1834		return err;
1835	}
1836
1837	up(&this_usbduxsub->sem);
1838
1839	return 1;
1840}
1841
1842static int usbdux_counter_config(comedi_device * dev, comedi_subdevice * s,
1843	comedi_insn * insn, lsampl_t * data)
1844{
1845	// nothing to do so far
1846	return 2;
1847}
1848
1849/////////////////////////////
1850// PWM
1851
1852static int usbduxsub_unlink_PwmURBs(usbduxsub_t * usbduxsub_tmp)
1853{
1854#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8)
1855	int j = 0;
1856#endif
1857
1858	int err = 0;
1859
1860	if (usbduxsub_tmp && usbduxsub_tmp->urbPwm) {
1861		if (usbduxsub_tmp->urbPwm) {
1862#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8)
1863			j = usb_unlink_urb(usbduxsub_tmp->urbPwm);
1864			if (j < err) {
1865				err = j;
1866			}
1867#else
1868			usb_kill_urb(usbduxsub_tmp->urbPwm);
1869#endif
1870		}
1871#ifdef NOISY_DUX_DEBUGBUG
1872		printk("comedi: usbdux: unlinked PwmURB: res=%d\n", err);
1873#endif
1874	}
1875	return err;
1876}
1877
1878/* This cancels a running acquisition operation
1879 * in any context.
1880 */
1881static int usbdux_pwm_stop(usbduxsub_t * this_usbduxsub, int do_unlink)
1882{
1883	int ret = 0;
1884
1885	if (!this_usbduxsub) {
1886#ifdef NOISY_DUX_DEBUGBUG
1887		printk("comedi?: usbdux_pwm_stop: this_usbduxsub=NULL!\n");
1888#endif
1889		return -EFAULT;
1890	}
1891#ifdef NOISY_DUX_DEBUGBUG
1892	printk("comedi: usbdux_pwm_cancel\n");
1893#endif
1894	if (do_unlink) {
1895		ret = usbduxsub_unlink_PwmURBs(this_usbduxsub);
1896	}
1897
1898	this_usbduxsub->pwm_cmd_running = 0;
1899
1900	return ret;
1901}
1902
1903// force unlink
1904// is called by comedi
1905static int usbdux_pwm_cancel(comedi_device * dev, comedi_subdevice * s)
1906{
1907	usbduxsub_t *this_usbduxsub = dev->private;
1908	int res = 0;
1909
1910	// unlink only if it is really running
1911	res = usbdux_pwm_stop(this_usbduxsub, this_usbduxsub->pwm_cmd_running);
1912
1913#ifdef NOISY_DUX_DEBUGBUG
1914	printk("comedi %d: sending pwm off command to the usb device.\n",
1915		dev->minor);
1916#endif
1917	if ((res = send_dux_commands(this_usbduxsub, SENDPWMOFF)) < 0) {
1918		return res;
1919	}
1920
1921	return res;
1922}
1923
1924#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
1925static void usbduxsub_pwm_irq(struct urb *urb)
1926{
1927#else
1928static void usbduxsub_pwm_irq(struct urb *urb, struct pt_regs *regs)
1929{
1930#endif
1931	int ret;
1932	usbduxsub_t *this_usbduxsub;
1933	comedi_device *this_comedidev;
1934	comedi_subdevice *s;
1935
1936	// printk("PWM: IRQ\n");
1937
1938	if (!urb) {
1939		printk("comedi_: usbdux_: pwm urb handler called with NULL ptr.\n");
1940		return;
1941	}
1942	// the context variable points to the subdevice
1943	this_comedidev = urb->context;
1944	if (!this_comedidev) {
1945		printk("comedi_: usbdux_: pwm urb int-context is a NULL pointer.\n");
1946		return;
1947	}
1948	// the private structure of the subdevice is usbduxsub_t
1949	this_usbduxsub = this_comedidev->private;
1950	if (!this_usbduxsub) {
1951		printk("comedi_: usbdux_: private data structure of pwm subdev is NULL p.\n");
1952		return;
1953	}
1954
1955	s = this_comedidev->subdevices + SUBDEV_DA;
1956
1957	switch (urb->status) {
1958	case 0:
1959		/* success */
1960		break;
1961
1962		// after an unlink command, unplug, ... etc
1963		// no unlink needed here. Already shutting down.
1964	case -ECONNRESET:
1965	case -ENOENT:
1966	case -ESHUTDOWN:
1967	case -ECONNABORTED:
1968		if (this_usbduxsub->pwm_cmd_running) {
1969			usbdux_pwm_stop(this_usbduxsub, 0);
1970		}
1971		return;
1972
1973		// a real error
1974	default:
1975		if (this_usbduxsub->pwm_cmd_running) {
1976			printk("comedi_: usbdux_: Non-zero urb status received in pwm intr context: %d\n", urb->status);
1977			usbdux_pwm_stop(this_usbduxsub, 0);
1978		}
1979		return;
1980	}
1981
1982	// are we actually running?
1983	if (!(this_usbduxsub->pwm_cmd_running)) {
1984		return;
1985	}
1986
1987	urb->transfer_buffer_length = this_usbduxsub->sizePwmBuf;
1988	urb->dev = this_usbduxsub->usbdev;
1989	urb->status = 0;
1990	if (this_usbduxsub->pwm_cmd_running) {
1991		if ((ret = USB_SUBMIT_URB(urb)) < 0) {
1992			printk("comedi_: usbdux_: pwm urb resubm failed in int-cont.");
1993			printk("ret=%d", ret);
1994			if (ret == EL2NSYNC) {
1995				printk("--> buggy USB host controller or bug in IRQ handling!\n");
1996			} else {
1997				printk("\n");
1998			}
1999			// don't do an unlink here
2000			usbdux_pwm_stop(this_usbduxsub, 0);
2001		}
2002	}
2003}
2004
2005int usbduxsub_submit_PwmURBs(usbduxsub_t * usbduxsub)
2006{
2007	int errFlag;
2008
2009	if (!usbduxsub) {
2010		return -EFAULT;
2011	}
2012#ifdef NOISY_DUX_DEBUGBUG
2013	printk("comedi_: usbdux: submitting pwm-urb\n");
2014#endif
2015	// in case of a resubmission after an unlink...
2016
2017	usb_fill_bulk_urb(usbduxsub->urbPwm,
2018		usbduxsub->usbdev,
2019		usb_sndbulkpipe(usbduxsub->usbdev, PWM_EP),
2020		usbduxsub->urbPwm->transfer_buffer,
2021		usbduxsub->sizePwmBuf, usbduxsub_pwm_irq, usbduxsub->comedidev);
2022
2023	errFlag = USB_SUBMIT_URB(usbduxsub->urbPwm);
2024	if (errFlag) {
2025		printk("comedi_: usbdux: pwm: ");
2026		printk("USB_SUBMIT_URB");
2027		printk(" error %d\n", errFlag);
2028		return errFlag;
2029	}
2030	return 0;
2031}
2032
2033static int usbdux_pwm_period(comedi_device * dev, comedi_subdevice * s,
2034			     lsampl_t period)
2035{
2036	usbduxsub_t *this_usbduxsub = dev->private;
2037	int fx2delay=255;
2038	if (period < MIN_PWM_PERIOD)
2039	{
2040		printk("comedi%d: illegal period setting for pwm.\n", dev->minor);
2041		return -EAGAIN;
2042	} else {
2043		fx2delay = period / ((int)(6*512*(1.0/0.033))) - 6;
2044		if (fx2delay > 255) {
2045			printk("comedi%d: period %d for pwm is too low.\n",
2046			       dev->minor, period);
2047			return -EAGAIN;
2048		}
2049	}
2050	this_usbduxsub->pwmDelay=fx2delay;
2051	this_usbduxsub->pwmPeriod=period;
2052#ifdef NOISY_DUX_DEBUGBUG
2053	printk("usbdux_pwm_period: frequ=%d, period=%d\n",period,fx2delay);
2054#endif
2055	return 0;
2056}
2057
2058
2059// is called from insn so there's no need to do all the sanity checks
2060static int usbdux_pwm_start(comedi_device * dev, comedi_subdevice * s)
2061{
2062	int ret, i;
2063	usbduxsub_t *this_usbduxsub = dev->private;
2064
2065#ifdef NOISY_DUX_DEBUGBUG
2066	printk("comedi%d: usbdux_pwm_start\n", dev->minor);
2067#endif
2068	if (this_usbduxsub->pwm_cmd_running) {
2069		// already running
2070		return 0;
2071	}
2072
2073	this_usbduxsub->dux_commands[1] = ((int8_t) this_usbduxsub->pwmDelay);
2074	if ((ret = send_dux_commands(this_usbduxsub, SENDPWMON)) < 0) {
2075		return ret;
2076	}
2077	// initalise the buffer
2078	for (i = 0; i < this_usbduxsub->sizePwmBuf; i++) {
2079		((char *)(this_usbduxsub->urbPwm->transfer_buffer))[i] = 0;
2080	}
2081
2082	this_usbduxsub->pwm_cmd_running = 1;
2083	ret = usbduxsub_submit_PwmURBs(this_usbduxsub);
2084	if (ret < 0) {
2085		this_usbduxsub->pwm_cmd_running = 0;
2086		return ret;
2087	}
2088	return 0;
2089}
2090
2091
2092// generates the bit pattern for PWM with the optional sign bit
2093static int usbdux_pwm_pattern(comedi_device * dev, comedi_subdevice * s,
2094			      int channel, lsampl_t value, lsampl_t sign)
2095{
2096	usbduxsub_t *this_usbduxsub = dev->private;
2097	int i, szbuf;
2098	char *pBuf;
2099	char pwm_mask,sgn_mask,c;
2100
2101	if (!this_usbduxsub) {
2102		return -EFAULT;
2103	}
2104	// this is the DIO bit which carries the PWM data
2105	pwm_mask = (1 << channel);
2106	// this is the DIO bit which carries the optional direction bit
2107	sgn_mask = (16 << channel);
2108	// this is the buffer which will be filled with the with bit
2109	// pattern for one period
2110	szbuf = this_usbduxsub->sizePwmBuf;
2111	pBuf = (char *)(this_usbduxsub->urbPwm->transfer_buffer);
2112	for (i = 0; i < szbuf; i++) {
2113		c = *pBuf;
2114		// reset bits
2115		c = c & (~pwm_mask);
2116		// set the bit as long as the index is lower than the value
2117		if (i < value)
2118			c = c | pwm_mask;
2119		// set the optional sign bit for a relay
2120		if (!sign) {
2121			// positive value
2122			c = c & (~sgn_mask);
2123		} else {
2124			// negative value
2125			c = c | sgn_mask;
2126		}
2127		*(pBuf++) = c;
2128	}
2129	return 1;
2130}
2131
2132static int usbdux_pwm_write(comedi_device * dev, comedi_subdevice * s,
2133			    comedi_insn * insn, lsampl_t * data)
2134{
2135	usbduxsub_t *this_usbduxsub = dev->private;
2136
2137	if (!this_usbduxsub) {
2138		return -EFAULT;
2139	}
2140
2141	if ((insn->n)!=1) {
2142		// doesn't make sense to have more than one value here
2143		// because it would just overwrite the PWM buffer a couple of times
2144		return -EINVAL;
2145	}
2146
2147	// the sign is set via a special INSN only, this gives us 8 bits for
2148	// normal operation
2149	return usbdux_pwm_pattern(dev,s,
2150				  CR_CHAN(insn->chanspec),
2151				  data[0],
2152				  0); // relay sign 0 by default
2153}
2154
2155
2156static int usbdux_pwm_read(comedi_device * x1, comedi_subdevice * x2,
2157	comedi_insn * x3, lsampl_t * x4)
2158{
2159	// not needed
2160	return -EINVAL;
2161};
2162
2163// switches on/off PWM
2164static int usbdux_pwm_config(comedi_device * dev, comedi_subdevice * s,
2165	comedi_insn * insn, lsampl_t * data)
2166{
2167	usbduxsub_t *this_usbduxsub = dev->private;
2168	switch (data[0]) {
2169	case INSN_CONFIG_ARM:
2170#ifdef NOISY_DUX_DEBUGBUG
2171		// switch it on
2172		printk("comedi%d: pwm_insn_config: pwm on\n",
2173		       dev->minor);
2174#endif
2175		// if not zero the PWM is limited to a certain time which is
2176		// not supported here
2177		if (data[1]!=0) {
2178			return -EINVAL;
2179		}
2180		return usbdux_pwm_start(dev, s);
2181	case INSN_CONFIG_DISARM:
2182#ifdef NOISY_DUX_DEBUGBUG
2183		printk("comedi%d: pwm_insn_config: pwm off\n",
2184		       dev->minor);
2185#endif
2186		return usbdux_pwm_cancel(dev, s);
2187	case INSN_CONFIG_GET_PWM_STATUS:
2188		// to check if the USB transmission has failed or in case
2189		// PWM was limited to n cycles to check if it has terminated
2190		data[1] = this_usbduxsub->pwm_cmd_running;
2191		return 0;
2192	case INSN_CONFIG_PWM_SET_PERIOD:
2193#ifdef NOISY_DUX_DEBUGBUG
2194		printk("comedi%d: pwm_insn_config: setting period\n",
2195		       dev->minor);
2196#endif
2197		return usbdux_pwm_period(dev,s,data[1]);
2198	case INSN_CONFIG_PWM_GET_PERIOD:
2199		data[1] = this_usbduxsub->pwmPeriod;
2200		return 0;
2201	case INSN_CONFIG_PWM_SET_H_BRIDGE:
2202		// value in the first byte and the sign in the second for a relay
2203		return usbdux_pwm_pattern(dev, s,
2204					  CR_CHAN(insn->chanspec), // the channel number
2205					  data[1], // actual PWM data
2206					  (data[2]!=0)); // just a sign
2207	case INSN_CONFIG_PWM_GET_H_BRIDGE:
2208		// values are not kept in this driver, nothing to return here
2209		return -EINVAL;
2210	}
2211	return -EINVAL;
2212}
2213
2214// end of PWM
2215///////////////////////////////////////////////////////////////////
2216
2217static void tidy_up(usbduxsub_t * usbduxsub_tmp)
2218{
2219	int i;
2220
2221#ifdef CONFIG_COMEDI_DEBUG
2222	printk("comedi_: usbdux: tiding up\n");
2223#endif
2224	if (!usbduxsub_tmp) {
2225		return;
2226	}
2227#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
2228	// shows the usb subsystem that the driver is down
2229	if (usbduxsub_tmp->interface) {
2230		usb_set_intfdata(usbduxsub_tmp->interface, NULL);
2231	}
2232#endif
2233
2234	usbduxsub_tmp->probed = 0;
2235
2236	if (usbduxsub_tmp->urbIn) {
2237		if (usbduxsub_tmp->ai_cmd_running) {
2238			usbduxsub_tmp->ai_cmd_running = 0;
2239			usbduxsub_unlink_InURBs(usbduxsub_tmp);
2240		}
2241		for (i = 0; i < usbduxsub_tmp->numOfInBuffers; i++) {
2242			if (usbduxsub_tmp->urbIn[i]->transfer_buffer) {
2243				kfree(usbduxsub_tmp->urbIn[i]->transfer_buffer);
2244				usbduxsub_tmp->urbIn[i]->transfer_buffer = NULL;
2245			}
2246			if (usbduxsub_tmp->urbIn[i]) {
2247#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,8)
2248				usb_kill_urb(usbduxsub_tmp->urbIn[i]);
2249#endif
2250				usb_free_urb(usbduxsub_tmp->urbIn[i]);
2251				usbduxsub_tmp->urbIn[i] = NULL;
2252			}
2253		}
2254		kfree(usbduxsub_tmp->urbIn);
2255		usbduxsub_tmp->urbIn = NULL;
2256	}
2257	if (usbduxsub_tmp->urbOut) {
2258		if (usbduxsub_tmp->ao_cmd_running) {
2259			usbduxsub_tmp->ao_cmd_running = 0;
2260			usbduxsub_unlink_OutURBs(usbduxsub_tmp);
2261		}
2262		for (i = 0; i < usbduxsub_tmp->numOfOutBuffers; i++) {
2263			if (usbduxsub_tmp->urbOut[i]->transfer_buffer) {
2264				kfree(usbduxsub_tmp->urbOut[i]->
2265					transfer_buffer);
2266				usbduxsub_tmp->urbOut[i]->transfer_buffer =
2267					NULL;
2268			}
2269			if (usbduxsub_tmp->urbOut[i]) {
2270#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,8)
2271				usb_kill_urb(usbduxsub_tmp->urbOut[i]);
2272#endif
2273				usb_free_urb(usbduxsub_tmp->urbOut[i]);
2274				usbduxsub_tmp->urbOut[i] = NULL;
2275			}
2276		}
2277		kfree(usbduxsub_tmp->urbOut);
2278		usbduxsub_tmp->urbOut = NULL;
2279	}
2280	if (usbduxsub_tmp->urbPwm) {
2281		if (usbduxsub_tmp->pwm_cmd_running) {
2282			usbduxsub_tmp->pwm_cmd_running = 0;
2283			usbduxsub_unlink_PwmURBs(usbduxsub_tmp);
2284		}
2285		if (usbduxsub_tmp->urbPwm->transfer_buffer) {
2286			kfree(usbduxsub_tmp->urbPwm->transfer_buffer);
2287			usbduxsub_tmp->urbPwm->transfer_buffer = NULL;
2288		}
2289#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,8)
2290		usb_kill_urb(usbduxsub_tmp->urbPwm);
2291#endif
2292		usb_free_urb(usbduxsub_tmp->urbPwm);
2293		usbduxsub_tmp->urbPwm = NULL;
2294	}
2295	if (usbduxsub_tmp->inBuffer) {
2296		kfree(usbduxsub_tmp->inBuffer);
2297		usbduxsub_tmp->inBuffer = NULL;
2298	}
2299	if (usbduxsub_tmp->insnBuffer) {
2300		kfree(usbduxsub_tmp->insnBuffer);
2301		usbduxsub_tmp->insnBuffer = NULL;
2302	}
2303	if (usbduxsub_tmp->inBuffer) {
2304		kfree(usbduxsub_tmp->inBuffer);
2305		usbduxsub_tmp->inBuffer = NULL;
2306	}
2307	if (usbduxsub_tmp->dac_commands) {
2308		kfree(usbduxsub_tmp->dac_commands);
2309		usbduxsub_tmp->dac_commands = NULL;
2310	}
2311	if (usbduxsub_tmp->dux_commands) {
2312		kfree(usbduxsub_tmp->dux_commands);
2313		usbduxsub_tmp->dux_commands = NULL;
2314	}
2315	usbduxsub_tmp->ai_cmd_running = 0;
2316	usbduxsub_tmp->ao_cmd_running = 0;
2317	usbduxsub_tmp->pwm_cmd_running = 0;
2318}
2319
2320static unsigned hex2unsigned(char *h)
2321{
2322	unsigned hi, lo;
2323	if (h[0] > '9') {
2324		hi = h[0] - 'A' + 0x0a;
2325	} else {
2326		hi = h[0] - '0';
2327	}
2328	if (h[1] > '9') {
2329		lo = h[1] - 'A' + 0x0a;
2330	} else {
2331		lo = h[1] - '0';
2332	}
2333	return hi * 0x10 + lo;
2334}
2335
2336// for FX2
2337#define FIRMWARE_MAX_LEN 0x2000
2338
2339// taken from David Brownell's fxload and adjusted for this driver
2340static int read_firmware(usbduxsub_t * usbduxsub, void *firmwarePtr, long size)
2341{
2342	int i = 0;
2343	unsigned char *fp = (char *)firmwarePtr;
2344	unsigned char *firmwareBinary = NULL;
2345	int res = 0;
2346	int maxAddr = 0;
2347
2348	firmwareBinary = kzalloc(FIRMWARE_MAX_LEN, GFP_KERNEL);
2349	if (!firmwareBinary) {
2350		printk("comedi_: usbdux: mem alloc for firmware failed\n");
2351		return -ENOMEM;
2352	}
2353
2354	for (;;) {
2355		char buf[256], *cp;
2356		char type;
2357		int len;
2358		int idx, off;
2359		int j = 0;
2360
2361		// get one line
2362		while ((i < size) && (fp[i] != 13) && (fp[i] != 10)) {
2363			buf[j] = fp[i];
2364			i++;
2365			j++;
2366			if (j >= sizeof(buf)) {
2367				printk("comedi_: usbdux: bogus firmware file!\n");
2368				return -1;
2369			}
2370		}
2371		// get rid of LF/CR/...
2372		while ((i < size) && ((fp[i] == 13) || (fp[i] == 10)
2373				|| (fp[i] == 0))) {
2374			i++;
2375		}
2376
2377		buf[j] = 0;
2378		//printk("comedi_: buf=%s\n",buf);
2379
2380		/* EXTENSION: "# comment-till-end-of-line", for copyrights etc */
2381		if (buf[0] == '#')
2382			continue;
2383
2384		if (buf[0] != ':') {
2385			printk("comedi_: usbdux: upload: not an ihex record: %s", buf);
2386			return -EFAULT;
2387		}
2388
2389		/* Read the length field (up to 16 bytes) */
2390		len = hex2unsigned(buf + 1);
2391
2392		/* Read the target offset */
2393		off = (hex2unsigned(buf + 3) * 0x0100) + hex2unsigned(buf + 5);
2394
2395		if ((off + len) > maxAddr) {
2396			maxAddr = off + len;
2397		}
2398
2399		if (maxAddr >= FIRMWARE_MAX_LEN) {
2400			printk("comedi_: usbdux: firmware upload goes beyond FX2 RAM boundaries.");
2401			return -EFAULT;
2402		}
2403		//printk("comedi_: usbdux: off=%x, len=%x:",off,len);
2404
2405		/* Read the record type */
2406		type = hex2unsigned(buf + 7);
2407
2408		/* If this is an EOF record, then make it so. */
2409		if (type == 1) {
2410			break;
2411		}
2412
2413		if (type != 0) {
2414			printk("comedi_: usbdux: unsupported record type: %u\n",
2415				type);
2416			return -EFAULT;
2417		}
2418
2419		for (idx = 0, cp = buf + 9; idx < len; idx += 1, cp += 2) {
2420			firmwareBinary[idx + off] = hex2unsigned(cp);
2421			//printk("%02x ",firmwareBinary[idx+off]);
2422		}
2423		//printk("\n");
2424
2425		if (i >= size) {
2426			printk("comedi_: usbdux: unexpected end of hex file\n");
2427			break;
2428		}
2429
2430	}
2431	res = firmwareUpload(usbduxsub, firmwareBinary, maxAddr + 1);
2432	kfree(firmwareBinary);
2433	return res;
2434}
2435
2436// allocate memory for the urbs and initialise them
2437#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
2438static void *usbduxsub_probe(struct usb_device *udev,
2439	unsigned int interfnum, const struct usb_device_id *id)
2440{
2441#else
2442static int usbduxsub_probe(struct usb_interface *uinterf,
2443	const struct usb_device_id *id)
2444{
2445	struct usb_device *udev = interface_to_usbdev(uinterf);
2446#endif
2447	int i;
2448	int index;
2449
2450#ifdef CONFIG_COMEDI_DEBUG
2451	printk("comedi_: usbdux_: finding a free structure for the usb-device\n");
2452#endif
2453	down(&start_stop_sem);
2454	// look for a free place in the usbdux array
2455	index = -1;
2456	for (i = 0; i < NUMUSBDUX; i++) {
2457		if (!(usbduxsub[i].probed)) {
2458			index = i;
2459			break;
2460		}
2461	}
2462
2463	// no more space
2464	if (index == -1) {
2465		printk("Too many usbdux-devices connected.\n");
2466		up(&start_stop_sem);
2467		return PROBE_ERR_RETURN(-EMFILE);
2468	}
2469#ifdef CONFIG_COMEDI_DEBUG
2470	printk("comedi_: usbdux: usbduxsub[%d] is ready to connect to comedi.\n", index);
2471#endif
2472
2473	init_MUTEX(&(usbduxsub[index].sem));
2474	// save a pointer to the usb device
2475	usbduxsub[index].usbdev = udev;
2476
2477#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
2478	// save the interface number
2479	usbduxsub[index].ifnum = interfnum;
2480#else
2481	// 2.6: save the interface itself
2482	usbduxsub[index].interface = uinterf;
2483	// get the interface number from the interface
2484	usbduxsub[index].ifnum = uinterf->altsetting->desc.bInterfaceNumber;
2485	// hand the private data over to the usb subsystem
2486	// will be needed for disconnect
2487	usb_set_intfdata(uinterf, &(usbduxsub[index]));
2488#endif
2489
2490#ifdef CONFIG_COMEDI_DEBUG
2491	printk("comedi_: usbdux: ifnum=%d\n", usbduxsub[index].ifnum);
2492#endif
2493	// test if it is high speed (USB 2.0)
2494	usbduxsub[index].high_speed =
2495		(usbduxsub[index].usbdev->speed == USB_SPEED_HIGH);
2496
2497	// create space for the commands of the DA converter
2498	usbduxsub[index].dac_commands = kzalloc(NUMOUTCHANNELS, GFP_KERNEL);
2499	if (!usbduxsub[index].dac_commands) {
2500		printk("comedi_: usbdux: error alloc space for dac commands\n");
2501		tidy_up(&(usbduxsub[index]));
2502		up(&start_stop_sem);
2503		return PROBE_ERR_RETURN(-ENOMEM);
2504	}
2505	// create space for the commands going to the usb device
2506	usbduxsub[index].dux_commands = kzalloc(SIZEOFDUXBUFFER, GFP_KERNEL);
2507	if (!usbduxsub[index].dux_commands) {
2508		printk("comedi_: usbdux: error alloc space for dac commands\n");
2509		tidy_up(&(usbduxsub[index]));
2510		up(&start_stop_sem);
2511		return PROBE_ERR_RETURN(-ENOMEM);
2512	}
2513	// create space for the in buffer and set it to zero
2514	usbduxsub[index].inBuffer = kzalloc(SIZEINBUF, GFP_KERNEL);
2515	if (!(usbduxsub[index].inBuffer)) {
2516		printk("comedi_: usbdux: could not alloc space for inBuffer\n");
2517		tidy_up(&(usbduxsub[index]));
2518		up(&start_stop_sem);
2519		return PROBE_ERR_RETURN(-ENOMEM);
2520	}
2521	// create space of the instruction buffer
2522	usbduxsub[index].insnBuffer = kzalloc(SIZEINSNBUF, GFP_KERNEL);
2523	if (!(usbduxsub[index].insnBuffer)) {
2524		printk("comedi_: usbdux: could not alloc space for insnBuffer\n");
2525		tidy_up(&(usbduxsub[index]));
2526		up(&start_stop_sem);
2527		return PROBE_ERR_RETURN(-ENOMEM);
2528	}
2529	// create space for the outbuffer
2530	usbduxsub[index].outBuffer = kzalloc(SIZEOUTBUF, GFP_KERNEL);
2531	if (!(usbduxsub[index].outBuffer)) {
2532		printk("comedi_: usbdux: could not alloc space for outBuffer\n");
2533		tidy_up(&(usbduxsub[index]));
2534		up(&start_stop_sem);
2535		return PROBE_ERR_RETURN(-ENOMEM);
2536	}
2537	// setting to alternate setting 3: enabling iso ep and bulk ep.
2538	i = usb_set_interface(usbduxsub[index].usbdev,
2539		usbduxsub[index].ifnum, 3);
2540	if (i < 0) {
2541		printk("comedi_: usbdux%d: could not set alternate setting 3 in high speed.\n", index);
2542		tidy_up(&(usbduxsub[index]));
2543		up(&start_stop_sem);
2544		return PROBE_ERR_RETURN(-ENODEV);
2545	}
2546	if (usbduxsub[index].high_speed) {
2547		usbduxsub[index].numOfInBuffers = NUMOFINBUFFERSHIGH;
2548	} else {
2549		usbduxsub[index].numOfInBuffers = NUMOFINBUFFERSFULL;
2550	}
2551	usbduxsub[index].urbIn =
2552		kzalloc(sizeof(struct urb *) * usbduxsub[index].numOfInBuffers,
2553		GFP_KERNEL);
2554	if (!(usbduxsub[index].urbIn)) {
2555		printk("comedi_: usbdux: Could not alloc. urbIn array\n");
2556		tidy_up(&(usbduxsub[index]));
2557		up(&start_stop_sem);
2558		return PROBE_ERR_RETURN(-ENOMEM);
2559	}
2560	for (i = 0; i < usbduxsub[index].numOfInBuffers; i++) {
2561		// one frame: 1ms
2562		usbduxsub[index].urbIn[i] = USB_ALLOC_URB(1);
2563		if (usbduxsub[index].urbIn[i] == NULL) {
2564			printk("comedi_: usbdux%d: Could not alloc. urb(%d)\n",
2565				index, i);
2566			tidy_up(&(usbduxsub[index]));
2567			up(&start_stop_sem);
2568			return PROBE_ERR_RETURN(-ENOMEM);
2569		}
2570		usbduxsub[index].urbIn[i]->dev = usbduxsub[index].usbdev;
2571		// will be filled later with a pointer to the comedi-device
2572		// and ONLY then the urb should be submitted
2573		usbduxsub[index].urbIn[i]->context = NULL;
2574		usbduxsub[index].urbIn[i]->pipe =
2575			usb_rcvisocpipe(usbduxsub[index].usbdev, ISOINEP);
2576		usbduxsub[index].urbIn[i]->transfer_flags = URB_ISO_ASAP;
2577		usbduxsub[index].urbIn[i]->transfer_buffer =
2578			kzalloc(SIZEINBUF, GFP_KERNEL);
2579		if (!(usbduxsub[index].urbIn[i]->transfer_buffer)) {
2580			printk("comedi_: usbdux%d: could not alloc. transb.\n",
2581				index);
2582			tidy_up(&(usbduxsub[index]));
2583			up(&start_stop_sem);
2584			return PROBE_ERR_RETURN(-ENOMEM);
2585		}
2586		usbduxsub[index].urbIn[i]->complete = usbduxsub_ai_IsocIrq;
2587		usbduxsub[index].urbIn[i]->number_of_packets = 1;
2588		usbduxsub[index].urbIn[i]->transfer_buffer_length = SIZEINBUF;
2589		usbduxsub[index].urbIn[i]->iso_frame_desc[0].offset = 0;
2590		usbduxsub[index].urbIn[i]->iso_frame_desc[0].length = SIZEINBUF;
2591	}
2592
2593	// out
2594	if (usbduxsub[index].high_speed) {
2595		usbduxsub[index].numOfOutBuffers = NUMOFOUTBUFFERSHIGH;
2596	} else {
2597		usbduxsub[index].numOfOutBuffers = NUMOFOUTBUFFERSFULL;
2598	}
2599	usbduxsub[index].urbOut =
2600		kzalloc(sizeof(struct urb *) * usbduxsub[index].numOfOutBuffers,
2601		GFP_KERNEL);
2602	if (!(usbduxsub[index].urbOut)) {
2603		printk("comedi_: usbdux: Could not alloc. urbOut array\n");
2604		tidy_up(&(usbduxsub[index]));
2605		up(&start_stop_sem);
2606		return PROBE_ERR_RETURN(-ENOMEM);
2607	}
2608	for (i = 0; i < usbduxsub[index].numOfOutBuffers; i++) {
2609		// one frame: 1ms
2610		usbduxsub[index].urbOut[i] = USB_ALLOC_URB(1);
2611		if (usbduxsub[index].urbOut[i] == NULL) {
2612			printk("comedi_: usbdux%d: Could not alloc. urb(%d)\n",
2613				index, i);
2614			tidy_up(&(usbduxsub[index]));
2615			up(&start_stop_sem);
2616			return PROBE_ERR_RETURN(-ENOMEM);
2617		}
2618		usbduxsub[index].urbOut[i]->dev = usbduxsub[index].usbdev;
2619		// will be filled later with a pointer to the comedi-device
2620		// and ONLY then the urb should be submitted
2621		usbduxsub[index].urbOut[i]->context = NULL;
2622		usbduxsub[index].urbOut[i]->pipe =
2623			usb_sndisocpipe(usbduxsub[index].usbdev, ISOOUTEP);
2624		usbduxsub[index].urbOut[i]->transfer_flags = URB_ISO_ASAP;
2625		usbduxsub[index].urbOut[i]->transfer_buffer =
2626			kzalloc(SIZEOUTBUF, GFP_KERNEL);
2627		if (!(usbduxsub[index].urbOut[i]->transfer_buffer)) {
2628			printk("comedi_: usbdux%d: could not alloc. transb.\n",
2629				index);
2630			tidy_up(&(usbduxsub[index]));
2631			up(&start_stop_sem);
2632			return PROBE_ERR_RETURN(-ENOMEM);
2633		}
2634		usbduxsub[index].urbOut[i]->complete = usbduxsub_ao_IsocIrq;
2635		usbduxsub[index].urbOut[i]->number_of_packets = 1;
2636		usbduxsub[index].urbOut[i]->transfer_buffer_length = SIZEOUTBUF;
2637		usbduxsub[index].urbOut[i]->iso_frame_desc[0].offset = 0;
2638		usbduxsub[index].urbOut[i]->iso_frame_desc[0].length =
2639			SIZEOUTBUF;
2640		if (usbduxsub[index].high_speed) {
2641			// uframes
2642			usbduxsub[index].urbOut[i]->interval = 8;
2643		} else {
2644			// frames
2645			usbduxsub[index].urbOut[i]->interval = 1;
2646		}
2647	}
2648
2649	// pwm
2650	if (usbduxsub[index].high_speed) {
2651		usbduxsub[index].sizePwmBuf = 512;	// max bulk ep size in high speed
2652		usbduxsub[index].urbPwm = USB_ALLOC_URB(0);
2653		if (usbduxsub[index].urbPwm == NULL) {
2654			printk("comedi_: usbdux%d: Could not alloc. pwm urb\n",
2655				index);
2656			tidy_up(&(usbduxsub[index]));
2657			up(&start_stop_sem);
2658			return PROBE_ERR_RETURN(-ENOMEM);
2659		}
2660		usbduxsub[index].urbPwm->transfer_buffer =
2661			kzalloc(usbduxsub[index].sizePwmBuf, GFP_KERNEL);
2662		if (!(usbduxsub[index].urbPwm->transfer_buffer)) {
2663			printk("comedi_: usbdux%d: could not alloc. transb. for pwm\n", index);
2664			tidy_up(&(usbduxsub[index]));
2665			up(&start_stop_sem);
2666			return PROBE_ERR_RETURN(-ENOMEM);
2667		}
2668	} else {
2669		usbduxsub[index].urbPwm = NULL;
2670		usbduxsub[index].sizePwmBuf = 0;
2671	}
2672
2673	usbduxsub[index].ai_cmd_running = 0;
2674	usbduxsub[index].ao_cmd_running = 0;
2675	usbduxsub[index].pwm_cmd_running = 0;
2676
2677	// we've reached the bottom of the function
2678	usbduxsub[index].probed = 1;
2679	up(&start_stop_sem);
2680	printk("comedi_: usbdux%d has been successfully initialised.\n", index);
2681#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
2682	return (void *)(&usbduxsub[index]);
2683#else
2684	// success
2685	return 0;
2686#endif
2687}
2688
2689#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
2690static void usbduxsub_disconnect(struct usb_device *udev, void *ptr)
2691{
2692	usbduxsub_t *usbduxsub_tmp = (usbduxsub_t *) ptr;
2693#else
2694static void usbduxsub_disconnect(struct usb_interface *intf)
2695{
2696	usbduxsub_t *usbduxsub_tmp = usb_get_intfdata(intf);
2697	struct usb_device *udev = interface_to_usbdev(intf);
2698#endif
2699	if (!usbduxsub_tmp) {
2700		printk("comedi_: usbdux: disconnect called with null pointer.\n");
2701		return;
2702	}
2703	if (usbduxsub_tmp->usbdev != udev) {
2704		printk("comedi_: usbdux: BUG! called with wrong ptr!!!\n");
2705		return;
2706	}
2707	down(&start_stop_sem);
2708	down(&usbduxsub_tmp->sem);
2709	tidy_up(usbduxsub_tmp);
2710	up(&usbduxsub_tmp->sem);
2711	up(&start_stop_sem);
2712#ifdef CONFIG_COMEDI_DEBUG
2713	printk("comedi_: usbdux: disconnected from the usb\n");
2714#endif
2715}
2716
2717// is called when comedi-config is called
2718static int usbdux_attach(comedi_device * dev, comedi_devconfig * it)
2719{
2720	int ret;
2721	int index;
2722	int i;
2723	comedi_subdevice *s = NULL;
2724	dev->private = NULL;
2725
2726	down(&start_stop_sem);
2727	// find a valid device which has been detected by the probe function of the usb
2728	index = -1;
2729	for (i = 0; i < NUMUSBDUX; i++) {
2730		if ((usbduxsub[i].probed) && (!usbduxsub[i].attached)) {
2731			index = i;
2732			break;
2733		}
2734	}
2735
2736	if (index < 0) {
2737		printk("comedi%d: usbdux: error: attach failed, no usbdux devs connected to the usb bus.\n", dev->minor);
2738		up(&start_stop_sem);
2739		return -ENODEV;
2740	}
2741
2742	down(&(usbduxsub[index].sem));
2743	// pointer back to the corresponding comedi device
2744	usbduxsub[index].comedidev = dev;
2745
2746	// trying to upload the firmware into the chip
2747	if (comedi_aux_data(it->options, 0) &&
2748		it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
2749		read_firmware(usbduxsub + index,
2750			comedi_aux_data(it->options, 0),
2751			it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]);
2752	}
2753
2754	dev->board_name = BOARDNAME;
2755
2756	/* set number of subdevices */
2757	if (usbduxsub[index].high_speed) {
2758		// with pwm
2759		dev->n_subdevices = 5;
2760	} else {
2761		// without pwm
2762		dev->n_subdevices = 4;
2763	}
2764
2765	// allocate space for the subdevices
2766	if ((ret = alloc_subdevices(dev, dev->n_subdevices)) < 0) {
2767		printk("comedi%d: usbdux: error alloc space for subdev\n",
2768			dev->minor);
2769		up(&start_stop_sem);
2770		return ret;
2771	}
2772
2773	printk("comedi%d: usbdux: usb-device %d is attached to comedi.\n",
2774		dev->minor, index);
2775	// private structure is also simply the usb-structure
2776	dev->private = usbduxsub + index;
2777
2778	// the first subdevice is the A/D converter
2779	s = dev->subdevices + SUBDEV_AD;
2780	// the URBs get the comedi subdevice
2781	// which is responsible for reading
2782	// this is the subdevice which reads data
2783	dev->read_subdev = s;
2784	// the subdevice receives as private structure the
2785	// usb-structure
2786	s->private = NULL;
2787	// analog input
2788	s->type = COMEDI_SUBD_AI;
2789	// readable and ref is to ground
2790	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
2791	// 8 channels
2792	s->n_chan = 8;
2793	// length of the channellist
2794	s->len_chanlist = 8;
2795	// callback functions
2796	s->insn_read = usbdux_ai_insn_read;
2797	s->do_cmdtest = usbdux_ai_cmdtest;
2798	s->do_cmd = usbdux_ai_cmd;
2799	s->cancel = usbdux_ai_cancel;
2800	// max value from the A/D converter (12bit)
2801	s->maxdata = 0xfff;
2802	// range table to convert to physical units
2803	s->range_table = (&range_usbdux_ai_range);
2804	//
2805
2806	// analog out
2807	s = dev->subdevices + SUBDEV_DA;
2808	// analog out
2809	s->type = COMEDI_SUBD_AO;
2810	// backward pointer
2811	dev->write_subdev = s;
2812	// the subdevice receives as private structure the
2813	// usb-structure
2814	s->private = NULL;
2815	// are writable
2816	s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
2817	// 4 channels
2818	s->n_chan = 4;
2819	// length of the channellist
2820	s->len_chanlist = 4;
2821	// 12 bit resolution
2822	s->maxdata = 0x0fff;
2823	// bipolar range
2824	s->range_table = (&range_usbdux_ao_range);
2825	// callback
2826	s->do_cmdtest = usbdux_ao_cmdtest;
2827	s->do_cmd = usbdux_ao_cmd;
2828	s->cancel = usbdux_ao_cancel;
2829	s->insn_read = usbdux_ao_insn_read;
2830	s->insn_write = usbdux_ao_insn_write;
2831
2832	// digital I/O
2833	s = dev->subdevices + SUBDEV_DIO;
2834	s->type = COMEDI_SUBD_DIO;
2835	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
2836	s->n_chan = 8;
2837	s->maxdata = 1;
2838	s->range_table = (&range_digital);
2839	s->insn_bits = usbdux_dio_insn_bits;
2840	s->insn_config = usbdux_dio_insn_config;
2841	// we don't use it
2842	s->private = NULL;
2843
2844	//counter
2845	s = dev->subdevices + SUBDEV_COUNTER;
2846	s->type = COMEDI_SUBD_COUNTER;
2847	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
2848	s->n_chan = 4;
2849	s->maxdata = 0xFFFF;
2850	s->insn_read = usbdux_counter_read;
2851	s->insn_write = usbdux_counter_write;
2852	s->insn_config = usbdux_counter_config;
2853
2854	if (usbduxsub[index].high_speed) {
2855		//timer / pwm
2856		s = dev->subdevices + SUBDEV_PWM;
2857		s->type = COMEDI_SUBD_PWM;
2858		s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE;
2859		s->n_chan = 8;
2860		// this defines the max duty cycle resolution
2861		s->maxdata = usbduxsub[index].sizePwmBuf;
2862		s->insn_write = usbdux_pwm_write;
2863		s->insn_read = usbdux_pwm_read;
2864		s->insn_config = usbdux_pwm_config;
2865		usbdux_pwm_period(dev, s, PWM_DEFAULT_PERIOD);
2866	}
2867	// finally decide that it's attached
2868	usbduxsub[index].attached = 1;
2869
2870	up(&(usbduxsub[index].sem));
2871
2872	up(&start_stop_sem);
2873
2874	printk("comedi%d: attached to usbdux.\n", dev->minor);
2875
2876	return 0;
2877}
2878
2879static int usbdux_detach(comedi_device * dev)
2880{
2881	usbduxsub_t *usbduxsub_tmp;
2882
2883#ifdef CONFIG_COMEDI_DEBUG
2884	printk("comedi%d: usbdux: detach usb device\n", dev->minor);
2885#endif
2886
2887	if (!dev) {
2888		printk("comedi?: usbdux: detach without dev variable...\n");
2889		return -EFAULT;
2890	}
2891
2892	usbduxsub_tmp = dev->private;
2893	if (!usbduxsub_tmp) {
2894		printk("comedi?: usbdux: detach without ptr to usbduxsub[]\n");
2895		return -EFAULT;
2896	}
2897
2898	down(&usbduxsub_tmp->sem);
2899	// Don't allow detach to free the private structure
2900	// It's one entry of of usbduxsub[]
2901	dev->private = NULL;
2902	usbduxsub_tmp->attached = 0;
2903	usbduxsub_tmp->comedidev = NULL;
2904#ifdef CONFIG_COMEDI_DEBUG
2905	printk("comedi%d: usbdux: detach: successfully removed\n", dev->minor);
2906#endif
2907	up(&usbduxsub_tmp->sem);
2908	return 0;
2909}
2910
2911/* main driver struct */
2912static comedi_driver driver_usbdux = {
2913      driver_name:"usbdux",
2914      module:THIS_MODULE,
2915      attach:usbdux_attach,
2916      detach:usbdux_detach,
2917};
2918
2919static void init_usb_devices(void)
2920{
2921	int index;
2922#ifdef CONFIG_COMEDI_DEBUG
2923	printk("comedi_: usbdux: setting all possible devs to invalid\n");
2924#endif
2925	// all devices entries are invalid to begin with
2926	// they will become valid by the probe function
2927	// and then finally by the attach-function
2928	for (index = 0; index < NUMUSBDUX; index++) {
2929		memset(&(usbduxsub[index]), 0x00, sizeof(usbduxsub[index]));
2930		init_MUTEX(&(usbduxsub[index].sem));
2931	}
2932}
2933
2934// Table with the USB-devices: just now only testing IDs
2935static struct usb_device_id usbduxsub_table[] = {
2936	{USB_DEVICE(0x13d8, 0x0001),
2937		},
2938	{USB_DEVICE(0x13d8, 0x0002)
2939		},
2940	{}			/* Terminating entry */
2941};
2942
2943MODULE_DEVICE_TABLE(usb, usbduxsub_table);
2944
2945// The usbduxsub-driver
2946static struct usb_driver usbduxsub_driver = {
2947#ifdef COMEDI_HAVE_USB_DRIVER_OWNER
2948      owner:THIS_MODULE,
2949#endif
2950      name:BOARDNAME,
2951      probe:usbduxsub_probe,
2952      disconnect:usbduxsub_disconnect,
2953      id_table:usbduxsub_table,
2954};
2955
2956// Can't use the nice macro as I have also to initialise the USB
2957// subsystem:
2958// registering the usb-system _and_ the comedi-driver
2959static int init_usbdux(void)
2960{
2961	printk(KERN_INFO KBUILD_MODNAME ": "
2962	       DRIVER_VERSION ":" DRIVER_DESC "\n");
2963	init_usb_devices();
2964	usb_register(&usbduxsub_driver);
2965	comedi_driver_register(&driver_usbdux);
2966	return 0;
2967}
2968
2969// deregistering the comedi driver and the usb-subsystem
2970static void exit_usbdux(void)
2971{
2972	comedi_driver_unregister(&driver_usbdux);
2973	usb_deregister(&usbduxsub_driver);
2974}
2975
2976module_init(init_usbdux);
2977module_exit(exit_usbdux);
2978
2979MODULE_AUTHOR(DRIVER_AUTHOR);
2980MODULE_DESCRIPTION(DRIVER_DESC);
2981MODULE_LICENSE("GPL");
2982