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"
5 comedi/drivers/usbdux.c
6 Copyright (C) 2003-2007 Bernd Porr, Bernd.Porr@f2s.com
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.
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.
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.
25 Description: University of Stirling USB DAQ & INCITE Technology Limited
26 Devices: [ITL] USB-DUX (usbdux.o)
27 Author: Bernd Porr <BerndPorr@f2s.com>
30 Configuration 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.
35 Connection 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.
39 Please note that under USB2.0 the length of the channel list determines
40 the max sampling rate. If you sample only one channel you get 8kHz
41 sampling rate. If you sample two channels you get 4kHz and so on.
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.
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
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
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
81 // generates loads of debug info
82 #define NOISY_DUX_DEBUGBUG
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>
94 #include <linux/comedidev.h>
95 #include <linux/usb.h>
97 #define BOARDNAME "usbdux"
99 // timeout for the USB-transfer
102 // constants for "firmware" upload and download
103 #define USBDUXSUB_FIRMWARE 0xA0
104 #define VENDOR_DIR_IN 0xC0
105 #define VENDOR_DIR_OUT 0x40
107 // internal adresses of the 8051 processor
108 #define USBDUXSUB_CPUCS 0xE600
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
117 // max lenghth of the transfer-buffer for software upload
118 #define TB_LEN 0x2000
120 // Input endpoint number: ISO/IRQ
123 // Output endpoint number: ISO/IRQ
126 // This EP sends DUX commands to USBDUX
127 #define COMMAND_OUT_EP 1
129 // This EP receives the DUX commands from USBDUX
130 #define COMMAND_IN_EP 8
132 // Output endpoint for PWM
135 // 300Hz max frequ under PWM
136 #define MIN_PWM_PERIOD ((long)(1E9/300))
138 // Default PWM frequency
139 #define PWM_DEFAULT_PERIOD ((long)(1E9/100))
141 // Number of channels
142 #define NUMCHANNELS 8
144 // Size of one A/D value
145 #define SIZEADIN ((sizeof(int16_t)))
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))
152 #define SIZEINSNBUF 16
154 // Number of DA channels
155 #define NUMOUTCHANNELS 8
157 // size of one value for the D/A converter: channel and value
158 #define SIZEDAOUT ((sizeof(int8_t)+sizeof(int16_t)))
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))
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))
169 // Number of in-URBs which receive the data: min=2
170 #define NUMOFINBUFFERSFULL 5
172 // Number of out-URBs which send the data: min=2
173 #define NUMOFOUTBUFFERSFULL 5
175 // Number of in-URBs which receive the data: min=5
176 #define NUMOFINBUFFERSHIGH 10 // must have more buffers due to buggy USB ctr
178 // Number of out-URBs which send the data: min=5
179 #define NUMOFOUTBUFFERSHIGH 10 // must have more buffers due to buggy USB ctr
181 // Total number of usbdux devices
184 // Analogue in subdevice
187 // Analogue out subdevice
194 #define SUBDEV_COUNTER 3
196 // timer aka pwm output
199 // number of retries to get the right dux command
202 /////////////////////////////////////////////
204 static const comedi_lrange range_usbdux_ai_range = { 4, {
206 BIP_RANGE(4.096 / 2),
212 static const comedi_lrange range_usbdux_ao_range = { 2, {
219 * private structure of one subdevice
222 // This is the structure which holds all the data of this driver
223 // one sub device just now: A/D
227 // is it associated with a subdevice?
229 // pointer to the usb-device
230 struct usb_device *usbdev;
231 // actual number of in-buffers
233 // actual number of out-buffers
235 // ISO-transfer handling: buffers
238 // pwm-transfer handling
242 // PWM internal delay for the GPIF in the FX2
244 // size of the PWM buffer which holds the bit pattern
246 // input buffer for the ISO-transfer
248 // input buffer for single insn
250 // output buffer for single DA outputs
254 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
255 // interface structure in 2.6
256 struct usb_interface *interface;
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;
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
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;
282 int8_t *dac_commands;
284 int8_t *dux_commands;
285 struct semaphore sem;
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.
295 static usbduxsub_t usbduxsub[NUMUSBDUX];
297 static DECLARE_MUTEX(start_stop_sem);
299 // Stops the data acquision
300 // It should be safe to call this function from any context
301 static int usbduxsub_unlink_InURBs(usbduxsub_t * usbduxsub_tmp)
304 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8)
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]);
318 // We wait here until all transfers
319 // have been cancelled.
320 usb_kill_urb(usbduxsub_tmp->urbIn[i]);
323 #ifdef NOISY_DUX_DEBUGBUG
324 printk("comedi: usbdux: unlinked InURB %d, err=%d\n",
332 /* This will stop a running acquisition operation */
333 // Is called from within this driver from both the
334 // interrupt context and from comedi
335 static int usbdux_ai_stop(usbduxsub_t * this_usbduxsub, int do_unlink)
339 if (!this_usbduxsub) {
340 printk("comedi?: usbdux_ai_stop: this_usbduxsub=NULL!\n");
343 #ifdef NOISY_DUX_DEBUGBUG
344 printk("comedi: usbdux_ai_stop\n");
349 ret = usbduxsub_unlink_InURBs(this_usbduxsub);
352 this_usbduxsub->ai_cmd_running = 0;
357 // This will cancel a running acquisition operation.
358 // This is called by comedi but never from inside the
360 static int usbdux_ai_cancel(comedi_device * dev, comedi_subdevice * s)
362 usbduxsub_t *this_usbduxsub;
365 // force unlink of all urbs
366 #ifdef NOISY_DUX_DEBUGBUG
367 printk("comedi: usbdux_ai_cancel\n");
369 this_usbduxsub = dev->private;
370 if (!this_usbduxsub) {
371 printk("comedi: usbdux_ai_cancel: this_usbduxsub=NULL\n");
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);
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);
387 // interrupt service routine
388 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
389 static void usbduxsub_ai_IsocIrq(struct urb *urb)
391 static void usbduxsub_ai_IsocIrq(struct urb *urb PT_REGS_ARG)
395 usbduxsub_t *this_usbduxsub;
396 comedi_device *this_comedidev;
402 printk("comedi_: usbdux_: ao int-handler called with urb=NULL!\n");
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");
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");
417 // subdevice which is the AD converter
418 s = this_comedidev->subdevices + SUBDEV_AD;
420 // first we test if something unusual has just happened
421 switch (urb->status) {
423 // copy the result in the transfer buffer
424 memcpy(this_usbduxsub->inBuffer,
425 urb->transfer_buffer, SIZEINBUF);
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);
438 // happens after an unlink command
443 if (this_usbduxsub->ai_cmd_running) {
444 // we are still running a command
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);
454 // a real error on the bus
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);
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
477 urb->dev = this_usbduxsub->usbdev;
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");
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);
496 this_usbduxsub->ai_counter--;
497 if (likely(this_usbduxsub->ai_counter > 0)) {
500 // timer zero, transfer measurements to comedi
501 this_usbduxsub->ai_counter = this_usbduxsub->ai_timer;
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);
517 // get the data from the USB bus and hand it over
519 n = s->async->cmd.chanlist_len;
520 for (i = 0; i < n; i++) {
522 if (CR_RANGE(s->async->cmd.chanlist[i]) <= 1) {
525 le16_to_cpu(this_usbduxsub->
526 inBuffer[i]) ^ 0x800);
530 le16_to_cpu(this_usbduxsub->inBuffer[i]));
533 // tell comedi that data is there
534 comedi_event(this_usbduxsub->comedidev, s);
537 static int usbduxsub_unlink_OutURBs(usbduxsub_t * usbduxsub_tmp)
540 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8)
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]);
555 usb_kill_urb(usbduxsub_tmp->urbOut[i]);
558 #ifdef NOISY_DUX_DEBUGBUG
559 printk("comedi: usbdux: unlinked OutURB %d: res=%d\n",
567 /* This will cancel a running acquisition operation
570 static int usbdux_ao_stop(usbduxsub_t * this_usbduxsub, int do_unlink)
574 if (!this_usbduxsub) {
575 #ifdef NOISY_DUX_DEBUGBUG
576 printk("comedi?: usbdux_ao_stop: this_usbduxsub=NULL!\n");
580 #ifdef NOISY_DUX_DEBUGBUG
581 printk("comedi: usbdux_ao_cancel\n");
584 ret = usbduxsub_unlink_OutURBs(this_usbduxsub);
587 this_usbduxsub->ao_cmd_running = 0;
593 // is called by comedi
594 static int usbdux_ao_cancel(comedi_device * dev, comedi_subdevice * s)
596 usbduxsub_t *this_usbduxsub = dev->private;
599 if (!this_usbduxsub) {
600 printk("comedi: usbdux_ao_cancel: this_usbduxsub=NULL\n");
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);
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);
615 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
616 static void usbduxsub_ao_IsocIrq(struct urb *urb)
619 static void usbduxsub_ao_IsocIrq(struct urb *urb PT_REGS_ARG)
624 usbduxsub_t *this_usbduxsub;
625 comedi_device *this_comedidev;
629 printk("comedi_: usbdux_: ao urb handler called with NULL ptr.\n");
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");
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");
645 s = this_comedidev->subdevices + SUBDEV_DA;
647 switch (urb->status) {
652 // after an unlink command, unplug, ... etc
653 // no unlink needed here. Already shutting down.
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);
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);
678 // are we actually running?
679 if (!(this_usbduxsub->ao_cmd_running)) {
682 // normal operation: executing a command in this subdevice
683 this_usbduxsub->ao_counter--;
684 if (this_usbduxsub->ao_counter <= 0) {
686 this_usbduxsub->ao_counter = this_usbduxsub->ao_timer;
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
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++) {
706 if (i >= NUMOUTCHANNELS) {
710 datap = (&(((int8_t *) urb->transfer_buffer)[i * 3 + 1]));
711 // get the data from comedi
712 ret = comedi_buf_get(s->async, &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]);
719 printk("comedi: usbdux: buffer underflow\n");
720 s->async->events |= COMEDI_CB_EOA;
721 s->async->events |= COMEDI_CB_OVERFLOW;
723 // transmit data to comedi
724 s->async->events |= COMEDI_CB_BLOCK;
725 comedi_event(this_usbduxsub->comedidev, s);
728 urb->transfer_buffer_length = SIZEOUTBUF;
729 urb->dev = this_usbduxsub->usbdev;
731 if (this_usbduxsub->ao_cmd_running) {
732 if (this_usbduxsub->high_speed) {
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");
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);
760 static int usbduxsub_start(usbduxsub_t * usbduxsub)
763 uint8_t local_transfer_buffer[16];
765 if (usbduxsub->probed) {
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"
779 // address of the transfer buffer
780 local_transfer_buffer,
786 printk("comedi_: usbdux_: control msg failed (start)\n");
793 static int usbduxsub_stop(usbduxsub_t * usbduxsub)
797 uint8_t local_transfer_buffer[16];
798 if (usbduxsub->probed) {
800 local_transfer_buffer[0] = 1;
801 errcode = USB_CONTROL_MSG
803 usb_sndctrlpipe(usbduxsub->usbdev, 0),
804 // bRequest, "Firmware"
811 0x0000, local_transfer_buffer,
817 printk("comedi_: usbdux: control msg failed (stop)\n");
824 static int usbduxsub_upload(usbduxsub_t * usbduxsub,
825 uint8_t * local_transfer_buffer,
826 unsigned int startAddr, unsigned int len)
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]);
837 errcode = USB_CONTROL_MSG
839 usb_sndctrlpipe(usbduxsub->usbdev, 0),
840 // brequest, firmware
848 // our local safe buffer
849 local_transfer_buffer,
854 #ifdef NOISY_DUX_DEBUGBUG
855 printk("comedi_: usbdux: result=%d\n", errcode);
858 printk("comedi_: usbdux: uppload failed\n");
862 // no device on the bus for this index
868 int firmwareUpload(usbduxsub_t * usbduxsub,
869 uint8_t * firmwareBinary, int sizeFirmware)
873 if (!firmwareBinary) {
876 ret = usbduxsub_stop(usbduxsub);
878 printk("comedi_: usbdux: can not stop firmware\n");
881 ret = usbduxsub_upload(usbduxsub, firmwareBinary, 0, sizeFirmware);
883 printk("comedi_: usbdux: firmware upload failed\n");
886 ret = usbduxsub_start(usbduxsub);
888 printk("comedi_: usbdux: can not start firmware\n");
894 int usbduxsub_submit_InURBs(usbduxsub_t * usbduxsub)
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));
912 errFlag = USB_SUBMIT_URB(usbduxsub->urbIn[i]);
914 printk("comedi_: usbdux: ai: ");
915 printk("USB_SUBMIT_URB(%d)", i);
916 printk(" error %d\n", errFlag);
923 int usbduxsub_submit_OutURBs(usbduxsub_t * usbduxsub)
930 for (i = 0; i < usbduxsub->numOfOutBuffers; i++) {
931 #ifdef NOISY_DUX_DEBUGBUG
932 printk("comedi_: usbdux: submitting out-urb[%d]\n", i);
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]);
941 printk("comedi_: usbdux: ao: ");
942 printk("USB_SUBMIT_URB(%d)", i);
943 printk(" error %d\n", errFlag);
950 static int usbdux_ai_cmdtest(comedi_device * dev,
951 comedi_subdevice * s, comedi_cmd * cmd)
954 unsigned int tmpTimer;
955 usbduxsub_t *this_usbduxsub = dev->private;
956 if (!(this_usbduxsub->probed)) {
959 #ifdef NOISY_DUX_DEBUGBUG
960 printk("comedi%d: usbdux_ai_cmdtest\n", dev->minor);
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)
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)
976 // scanning is continous
977 tmp = cmd->convert_src;
978 cmd->convert_src &= TRIG_NOW;
979 if (!cmd->convert_src || tmp != cmd->convert_src)
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)
988 // trigger at the end of count events or not, stop condition or not
990 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
991 if (!cmd->stop_src || tmp != cmd->stop_src)
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)
1003 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
1009 /* step 3: make sure arguments are trivially compatible */
1011 if (cmd->start_arg != 0) {
1016 if (cmd->scan_begin_src == TRIG_FOLLOW) {
1017 /* internal trigger */
1018 if (cmd->scan_begin_arg != 0) {
1019 cmd->scan_begin_arg = 0;
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.
1031 // find a power of 2 for the number of channels
1032 while (i < (cmd->chanlist_len)) {
1035 if (cmd->scan_begin_arg < (1000000 / 8 * i)) {
1036 cmd->scan_begin_arg = 1000000 / 8 * i;
1039 // now calc the real sampling rate with all the rounding errors
1041 ((unsigned int)(cmd->scan_begin_arg / 125000)) *
1043 if (cmd->scan_begin_arg != tmpTimer) {
1044 cmd->scan_begin_arg = tmpTimer;
1047 } else { // full speed
1048 // 1kHz scans every USB frame
1049 if (cmd->scan_begin_arg < 1000000) {
1050 cmd->scan_begin_arg = 1000000;
1053 // calc the real sampling rate with the rounding errors
1055 ((unsigned int)(cmd->scan_begin_arg /
1056 1000000)) * 1000000;
1057 if (cmd->scan_begin_arg != tmpTimer) {
1058 cmd->scan_begin_arg = tmpTimer;
1063 // the same argument
1064 if (cmd->scan_end_arg != cmd->chanlist_len) {
1065 cmd->scan_end_arg = cmd->chanlist_len;
1069 if (cmd->stop_src == TRIG_COUNT) {
1070 /* any count is allowed */
1073 if (cmd->stop_arg != 0) {
1085 // creates the ADC command for the MAX1271
1086 // range is the range value from comedi
1087 static int8_t create_adc_command(unsigned int chan, int range)
1089 int8_t p = (range <= 1);
1090 int8_t r = ((range % 2) == 0);
1091 return (chan << 4) | ((p == 1) << 2) | ((r == 1) << 3);
1094 // bulk transfers to usbdux
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
1104 #define SENDPWMOFF 8
1106 static int send_dux_commands(usbduxsub_t * this_usbduxsub, int cmd_type)
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]);
1119 result = USB_BULK_MSG(this_usbduxsub->usbdev,
1120 usb_sndbulkpipe(this_usbduxsub->usbdev,
1122 this_usbduxsub->dux_commands, SIZEOFDUXBUFFER, &nsent, 10 * HZ);
1124 printk("comedi%d: could not transmit dux_command to the usb-device, err=%d\n", this_usbduxsub->comedidev->minor, result);
1129 static int receive_dux_commands(usbduxsub_t * this_usbduxsub, int command)
1131 int result = (-EFAULT);
1135 for (i = 0; i < RETRIES; i++) {
1136 result = USB_BULK_MSG(this_usbduxsub->usbdev,
1137 usb_rcvbulkpipe(this_usbduxsub->usbdev,
1139 this_usbduxsub->insnBuffer, SIZEINSNBUF, &nrec, 1 * HZ);
1141 printk("comedi%d: insn: USB error %d while receiving DUX command\n", this_usbduxsub->comedidev->minor, result);
1144 if (le16_to_cpu(this_usbduxsub->insnBuffer[0]) == command) {
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]));
1153 static int usbdux_ai_inttrig(comedi_device * dev,
1154 comedi_subdevice * s, unsigned int trignum)
1157 usbduxsub_t *this_usbduxsub = dev->private;
1158 if (!this_usbduxsub) {
1161 down(&this_usbduxsub->sem);
1162 if (!(this_usbduxsub->probed)) {
1163 up(&this_usbduxsub->sem);
1166 #ifdef NOISY_DUX_DEBUGBUG
1167 printk("comedi%d: usbdux_ai_inttrig\n", dev->minor);
1171 printk("comedi%d: usbdux_ai_inttrig: invalid trignum\n",
1173 up(&this_usbduxsub->sem);
1176 if (!(this_usbduxsub->ai_cmd_running)) {
1177 this_usbduxsub->ai_cmd_running = 1;
1178 ret = usbduxsub_submit_InURBs(this_usbduxsub);
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);
1185 s->async->inttrig = NULL;
1187 printk("comedi%d: ai_inttrig but acqu is already running\n",
1190 up(&this_usbduxsub->sem);
1194 static int usbdux_ai_cmd(comedi_device * dev, comedi_subdevice * s)
1196 comedi_cmd *cmd = &s->async->cmd;
1197 unsigned int chan, range;
1199 usbduxsub_t *this_usbduxsub = dev->private;
1202 #ifdef NOISY_DUX_DEBUGBUG
1203 printk("comedi%d: usbdux_ai_cmd\n", dev->minor);
1205 if (!this_usbduxsub) {
1208 // block other CPUs from starting an ai_cmd
1209 down(&this_usbduxsub->sem);
1211 if (!(this_usbduxsub->probed)) {
1212 up(&this_usbduxsub->sem);
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);
1220 // set current channel of the running aquisition to zero
1221 s->async->cur_chan = 0;
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);
1231 this_usbduxsub->dux_commands[i + 2] =
1232 create_adc_command(chan, range);
1235 #ifdef NOISY_DUX_DEBUGBUG
1236 printk("comedi %d: sending commands to the usb device: ", dev->minor);
1237 printk("size=%u\n", NUMCHANNELS);
1239 if ((result = send_dux_commands(this_usbduxsub, SENDADCOMMANDS)) < 0) {
1240 up(&this_usbduxsub->sem);
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;
1254 this_usbduxsub->ai_timer =
1255 cmd->scan_begin_arg / (125000 *
1256 (this_usbduxsub->ai_interval));
1258 // interval always 1ms
1259 this_usbduxsub->ai_interval = 1;
1260 this_usbduxsub->ai_timer = cmd->scan_begin_arg / 1000000;
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);
1267 this_usbduxsub->ai_counter = this_usbduxsub->ai_timer;
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;
1274 // continous aquisition
1275 this_usbduxsub->ai_continous = 1;
1276 this_usbduxsub->ai_sample_count = 0;
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);
1284 this_usbduxsub->ai_cmd_running = 0;
1285 // fixme: unlink here??
1286 up(&this_usbduxsub->sem);
1289 s->async->inttrig = NULL;
1292 // don't enable the acquision operation
1293 // wait for an internal signal
1294 s->async->inttrig = usbdux_ai_inttrig;
1296 up(&this_usbduxsub->sem);
1300 /* Mode 0 is used to get a single conversion on demand */
1301 static int usbdux_ai_insn_read(comedi_device * dev,
1302 comedi_subdevice * s, comedi_insn * insn, lsampl_t * data)
1308 usbduxsub_t *this_usbduxsub = dev->private;
1310 if (!this_usbduxsub) {
1311 printk("comedi%d: ai_insn_read: no usb dev.\n", dev->minor);
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);
1318 down(&this_usbduxsub->sem);
1319 if (!(this_usbduxsub->probed)) {
1320 up(&this_usbduxsub->sem);
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);
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);
1336 if ((err = send_dux_commands(this_usbduxsub, SENDSINGLEAD)) < 0) {
1337 up(&this_usbduxsub->sem);
1341 for (i = 0; i < insn->n; i++) {
1342 if ((err = receive_dux_commands(this_usbduxsub,
1343 SENDSINGLEAD)) < 0) {
1344 up(&this_usbduxsub->sem);
1347 one = le16_to_cpu(this_usbduxsub->insnBuffer[1]);
1348 if (CR_RANGE(insn->chanspec) <= 1) {
1353 up(&this_usbduxsub->sem);
1360 static int usbdux_ao_insn_read(comedi_device * dev, comedi_subdevice * s,
1361 comedi_insn * insn, lsampl_t * data)
1364 int chan = CR_CHAN(insn->chanspec);
1365 usbduxsub_t *this_usbduxsub = dev->private;
1367 if (!this_usbduxsub) {
1370 down(&this_usbduxsub->sem);
1371 if (!(this_usbduxsub->probed)) {
1372 up(&this_usbduxsub->sem);
1375 for (i = 0; i < insn->n; i++) {
1376 data[i] = this_usbduxsub->outBuffer[chan];
1378 up(&this_usbduxsub->sem);
1382 static int usbdux_ao_insn_write(comedi_device * dev, comedi_subdevice * s,
1383 comedi_insn * insn, lsampl_t * data)
1386 int chan = CR_CHAN(insn->chanspec);
1387 usbduxsub_t *this_usbduxsub = dev->private;
1389 #ifdef NOISY_DUX_DEBUGBUG
1390 printk("comedi%d: ao_insn_write\n", dev->minor);
1392 if (!this_usbduxsub) {
1395 down(&this_usbduxsub->sem);
1396 if (!(this_usbduxsub->probed)) {
1397 up(&this_usbduxsub->sem);
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);
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]);
1411 // number of channels: 1
1412 this_usbduxsub->dux_commands[1] = 1;
1414 *((int16_t *) (this_usbduxsub->dux_commands + 2)) =
1415 cpu_to_le16(data[i]);
1416 this_usbduxsub->outBuffer[chan] = data[i];
1418 this_usbduxsub->dux_commands[4] = (chan << 6);
1419 if ((err = send_dux_commands(this_usbduxsub,
1420 SENDDACOMMANDS)) < 0) {
1421 up(&this_usbduxsub->sem);
1425 up(&this_usbduxsub->sem);
1430 static int usbdux_ao_inttrig(comedi_device * dev, comedi_subdevice * s,
1431 unsigned int trignum)
1434 usbduxsub_t *this_usbduxsub = dev->private;
1436 if (!this_usbduxsub) {
1439 down(&this_usbduxsub->sem);
1440 if (!(this_usbduxsub->probed)) {
1441 up(&this_usbduxsub->sem);
1445 printk("comedi%d: usbdux_ao_inttrig: invalid trignum\n",
1449 if (!(this_usbduxsub->ao_cmd_running)) {
1450 this_usbduxsub->ao_cmd_running = 1;
1451 ret = usbduxsub_submit_OutURBs(this_usbduxsub);
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);
1458 s->async->inttrig = NULL;
1460 printk("comedi%d: ao_inttrig but acqu is already running.\n",
1463 up(&this_usbduxsub->sem);
1467 static int usbdux_ao_cmdtest(comedi_device * dev,
1468 comedi_subdevice * s, comedi_cmd * cmd)
1471 usbduxsub_t *this_usbduxsub = dev->private;
1473 if (!this_usbduxsub) {
1476 if (!(this_usbduxsub->probed)) {
1479 #ifdef NOISY_DUX_DEBUGBUG
1480 printk("comedi%d: usbdux_ao_cmdtest\n", dev->minor);
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)
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;
1498 // start a new scan (output at once) with a timer
1499 cmd->scan_begin_src &= TRIG_TIMER;
1501 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
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;
1511 // all conversion events happen simultaneously with a rate of 1kHz/n
1512 cmd->convert_src &= TRIG_NOW;
1514 if (!cmd->convert_src || tmp != cmd->convert_src)
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)
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)
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)
1538 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
1544 /* step 3: make sure arguments are trivially compatible */
1546 if (cmd->start_arg != 0) {
1551 if (cmd->scan_begin_src == TRIG_FOLLOW) {
1552 /* internal trigger */
1553 if (cmd->scan_begin_arg != 0) {
1554 cmd->scan_begin_arg = 0;
1559 if (cmd->scan_begin_src == TRIG_TIMER) {
1561 if (cmd->scan_begin_arg < 1000000) {
1562 cmd->scan_begin_arg = 1000000;
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;
1574 // the same argument
1575 if (cmd->scan_end_arg != cmd->chanlist_len) {
1576 cmd->scan_end_arg = cmd->chanlist_len;
1580 if (cmd->stop_src == TRIG_COUNT) {
1581 /* any count is allowed */
1584 if (cmd->stop_arg != 0) {
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);
1600 static int usbdux_ao_cmd(comedi_device * dev, comedi_subdevice * s)
1602 comedi_cmd *cmd = &s->async->cmd;
1603 unsigned int chan, gain;
1605 usbduxsub_t *this_usbduxsub = dev->private;
1607 if (!this_usbduxsub) {
1610 down(&this_usbduxsub->sem);
1611 if (!(this_usbduxsub->probed)) {
1612 up(&this_usbduxsub->sem);
1615 #ifdef NOISY_DUX_DEBUGBUG
1616 printk("comedi%d: usbdux_ao_cmd\n", dev->minor);
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);
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]);
1635 // we count in steps of 1ms (125us)
1636 // 125us mode not used yet
1637 if (0) { /* (this_usbduxsub->high_speed) */
1639 // timing of the conversion itself: every 125 us
1640 this_usbduxsub->ao_timer = cmd->convert_arg / 125000;
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);
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);
1656 this_usbduxsub->ao_counter = this_usbduxsub->ao_timer;
1658 if (cmd->stop_src == TRIG_COUNT) {
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);
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;
1671 this_usbduxsub->ao_continous = 0;
1673 // continous aquisition
1674 this_usbduxsub->ao_continous = 1;
1675 this_usbduxsub->ao_sample_count = 0;
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);
1683 this_usbduxsub->ao_cmd_running = 0;
1684 // fixme: unlink here??
1685 up(&this_usbduxsub->sem);
1688 s->async->inttrig = NULL;
1691 // submit the urbs later
1692 // wait for an internal signal
1693 s->async->inttrig = usbdux_ao_inttrig;
1696 up(&this_usbduxsub->sem);
1700 static int usbdux_dio_insn_config(comedi_device * dev,
1701 comedi_subdevice * s, comedi_insn * insn, lsampl_t * data)
1703 int chan = CR_CHAN(insn->chanspec);
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. */
1711 case INSN_CONFIG_DIO_OUTPUT:
1712 s->io_bits |= 1 << chan; /* 1 means Out */
1714 case INSN_CONFIG_DIO_INPUT:
1715 s->io_bits &= ~(1 << chan);
1717 case INSN_CONFIG_DIO_QUERY:
1720 io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
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.
1731 static int usbdux_dio_insn_bits(comedi_device * dev,
1732 comedi_subdevice * s, comedi_insn * insn, lsampl_t * data)
1735 usbduxsub_t *this_usbduxsub = dev->private;
1738 if (!this_usbduxsub) {
1745 down(&this_usbduxsub->sem);
1747 if (!(this_usbduxsub->probed)) {
1748 up(&this_usbduxsub->sem);
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;
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);
1765 if ((err = receive_dux_commands(this_usbduxsub,
1766 SENDDIOBITSCOMMAND)) < 0) {
1767 up(&this_usbduxsub->sem);
1771 data[1] = le16_to_cpu(this_usbduxsub->insnBuffer[1]);
1772 up(&this_usbduxsub->sem);
1776 // reads the 4 counters
1777 // only two are used just now
1778 static int usbdux_counter_read(comedi_device * dev, comedi_subdevice * s,
1779 comedi_insn * insn, lsampl_t * data)
1781 usbduxsub_t *this_usbduxsub = dev->private;
1782 int chan = insn->chanspec;
1785 if (!this_usbduxsub) {
1789 down(&this_usbduxsub->sem);
1791 if (!(this_usbduxsub->probed)) {
1792 up(&this_usbduxsub->sem);
1796 if ((err = send_dux_commands(this_usbduxsub, READCOUNTERCOMMAND)) < 0) {
1797 up(&this_usbduxsub->sem);
1801 if ((err = receive_dux_commands(this_usbduxsub,
1802 READCOUNTERCOMMAND)) < 0) {
1803 up(&this_usbduxsub->sem);
1807 data[0] = le16_to_cpu(this_usbduxsub->insnBuffer[chan + 1]);
1808 up(&this_usbduxsub->sem);
1812 static int usbdux_counter_write(comedi_device * dev, comedi_subdevice * s,
1813 comedi_insn * insn, lsampl_t * data)
1815 usbduxsub_t *this_usbduxsub = dev->private;
1818 if (!this_usbduxsub) {
1822 down(&this_usbduxsub->sem);
1824 if (!(this_usbduxsub->probed)) {
1825 up(&this_usbduxsub->sem);
1829 this_usbduxsub->dux_commands[1] = insn->chanspec;
1830 *((int16_t *) (this_usbduxsub->dux_commands + 2)) = cpu_to_le16(*data);
1832 if ((err = send_dux_commands(this_usbduxsub, WRITECOUNTERCOMMAND)) < 0) {
1833 up(&this_usbduxsub->sem);
1837 up(&this_usbduxsub->sem);
1842 static int usbdux_counter_config(comedi_device * dev, comedi_subdevice * s,
1843 comedi_insn * insn, lsampl_t * data)
1845 // nothing to do so far
1849 /////////////////////////////
1852 static int usbduxsub_unlink_PwmURBs(usbduxsub_t * usbduxsub_tmp)
1854 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8)
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);
1868 usb_kill_urb(usbduxsub_tmp->urbPwm);
1871 #ifdef NOISY_DUX_DEBUGBUG
1872 printk("comedi: usbdux: unlinked PwmURB: res=%d\n", err);
1878 /* This cancels a running acquisition operation
1881 static int usbdux_pwm_stop(usbduxsub_t * this_usbduxsub, int do_unlink)
1885 if (!this_usbduxsub) {
1886 #ifdef NOISY_DUX_DEBUGBUG
1887 printk("comedi?: usbdux_pwm_stop: this_usbduxsub=NULL!\n");
1891 #ifdef NOISY_DUX_DEBUGBUG
1892 printk("comedi: usbdux_pwm_cancel\n");
1895 ret = usbduxsub_unlink_PwmURBs(this_usbduxsub);
1898 this_usbduxsub->pwm_cmd_running = 0;
1904 // is called by comedi
1905 static int usbdux_pwm_cancel(comedi_device * dev, comedi_subdevice * s)
1907 usbduxsub_t *this_usbduxsub = dev->private;
1910 // unlink only if it is really running
1911 res = usbdux_pwm_stop(this_usbduxsub, this_usbduxsub->pwm_cmd_running);
1913 #ifdef NOISY_DUX_DEBUGBUG
1914 printk("comedi %d: sending pwm off command to the usb device.\n",
1917 if ((res = send_dux_commands(this_usbduxsub, SENDPWMOFF)) < 0) {
1924 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
1925 static void usbduxsub_pwm_irq(struct urb *urb)
1928 static void usbduxsub_pwm_irq(struct urb *urb, struct pt_regs *regs)
1932 usbduxsub_t *this_usbduxsub;
1933 comedi_device *this_comedidev;
1934 comedi_subdevice *s;
1936 // printk("PWM: IRQ\n");
1939 printk("comedi_: usbdux_: pwm urb handler called with NULL ptr.\n");
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");
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");
1955 s = this_comedidev->subdevices + SUBDEV_DA;
1957 switch (urb->status) {
1962 // after an unlink command, unplug, ... etc
1963 // no unlink needed here. Already shutting down.
1968 if (this_usbduxsub->pwm_cmd_running) {
1969 usbdux_pwm_stop(this_usbduxsub, 0);
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);
1982 // are we actually running?
1983 if (!(this_usbduxsub->pwm_cmd_running)) {
1987 urb->transfer_buffer_length = this_usbduxsub->sizePwmBuf;
1988 urb->dev = this_usbduxsub->usbdev;
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");
1999 // don't do an unlink here
2000 usbdux_pwm_stop(this_usbduxsub, 0);
2005 int usbduxsub_submit_PwmURBs(usbduxsub_t * usbduxsub)
2012 #ifdef NOISY_DUX_DEBUGBUG
2013 printk("comedi_: usbdux: submitting pwm-urb\n");
2015 // in case of a resubmission after an unlink...
2017 usb_fill_bulk_urb(usbduxsub->urbPwm,
2019 usb_sndbulkpipe(usbduxsub->usbdev, PWM_EP),
2020 usbduxsub->urbPwm->transfer_buffer,
2021 usbduxsub->sizePwmBuf, usbduxsub_pwm_irq, usbduxsub->comedidev);
2023 errFlag = USB_SUBMIT_URB(usbduxsub->urbPwm);
2025 printk("comedi_: usbdux: pwm: ");
2026 printk("USB_SUBMIT_URB");
2027 printk(" error %d\n", errFlag);
2033 static int usbdux_pwm_period(comedi_device * dev, comedi_subdevice * s,
2036 usbduxsub_t *this_usbduxsub = dev->private;
2038 if (period < MIN_PWM_PERIOD)
2040 printk("comedi%d: illegal period setting for pwm.\n", dev->minor);
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);
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);
2059 // is called from insn so there's no need to do all the sanity checks
2060 static int usbdux_pwm_start(comedi_device * dev, comedi_subdevice * s)
2063 usbduxsub_t *this_usbduxsub = dev->private;
2065 #ifdef NOISY_DUX_DEBUGBUG
2066 printk("comedi%d: usbdux_pwm_start\n", dev->minor);
2068 if (this_usbduxsub->pwm_cmd_running) {
2073 this_usbduxsub->dux_commands[1] = ((int8_t) this_usbduxsub->pwmDelay);
2074 if ((ret = send_dux_commands(this_usbduxsub, SENDPWMON)) < 0) {
2077 // initalise the buffer
2078 for (i = 0; i < this_usbduxsub->sizePwmBuf; i++) {
2079 ((char *)(this_usbduxsub->urbPwm->transfer_buffer))[i] = 0;
2082 this_usbduxsub->pwm_cmd_running = 1;
2083 ret = usbduxsub_submit_PwmURBs(this_usbduxsub);
2085 this_usbduxsub->pwm_cmd_running = 0;
2092 // generates the bit pattern for PWM with the optional sign bit
2093 static int usbdux_pwm_pattern(comedi_device * dev, comedi_subdevice * s,
2094 int channel, lsampl_t value, lsampl_t sign)
2096 usbduxsub_t *this_usbduxsub = dev->private;
2099 char pwm_mask,sgn_mask,c;
2101 if (!this_usbduxsub) {
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++) {
2115 c = c & (~pwm_mask);
2116 // set the bit as long as the index is lower than the value
2119 // set the optional sign bit for a relay
2122 c = c & (~sgn_mask);
2132 static int usbdux_pwm_write(comedi_device * dev, comedi_subdevice * s,
2133 comedi_insn * insn, lsampl_t * data)
2135 usbduxsub_t *this_usbduxsub = dev->private;
2137 if (!this_usbduxsub) {
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
2147 // the sign is set via a special INSN only, this gives us 8 bits for
2149 return usbdux_pwm_pattern(dev,s,
2150 CR_CHAN(insn->chanspec),
2152 0); // relay sign 0 by default
2156 static int usbdux_pwm_read(comedi_device * x1, comedi_subdevice * x2,
2157 comedi_insn * x3, lsampl_t * x4)
2163 // switches on/off PWM
2164 static int usbdux_pwm_config(comedi_device * dev, comedi_subdevice * s,
2165 comedi_insn * insn, lsampl_t * data)
2167 usbduxsub_t *this_usbduxsub = dev->private;
2169 case INSN_CONFIG_ARM:
2170 #ifdef NOISY_DUX_DEBUGBUG
2172 printk("comedi%d: pwm_insn_config: pwm on\n",
2175 // if not zero the PWM is limited to a certain time which is
2176 // not supported here
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",
2186 return usbdux_pwm_cancel(dev, s);
2187 case INSN_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;
2192 case INSN_CONFIG_PWM_SET_PERIOD:
2193 #ifdef NOISY_DUX_DEBUGBUG
2194 printk("comedi%d: pwm_insn_config: setting period\n",
2197 return usbdux_pwm_period(dev,s,data[1]);
2198 case INSN_CONFIG_PWM_GET_PERIOD:
2199 data[1] = this_usbduxsub->pwmPeriod;
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
2215 ///////////////////////////////////////////////////////////////////
2217 static void tidy_up(usbduxsub_t * usbduxsub_tmp)
2221 #ifdef CONFIG_COMEDI_DEBUG
2222 printk("comedi_: usbdux: tiding up\n");
2224 if (!usbduxsub_tmp) {
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);
2234 usbduxsub_tmp->probed = 0;
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);
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;
2246 if (usbduxsub_tmp->urbIn[i]) {
2247 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,8)
2248 usb_kill_urb(usbduxsub_tmp->urbIn[i]);
2250 usb_free_urb(usbduxsub_tmp->urbIn[i]);
2251 usbduxsub_tmp->urbIn[i] = NULL;
2254 kfree(usbduxsub_tmp->urbIn);
2255 usbduxsub_tmp->urbIn = NULL;
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);
2262 for (i = 0; i < usbduxsub_tmp->numOfOutBuffers; i++) {
2263 if (usbduxsub_tmp->urbOut[i]->transfer_buffer) {
2264 kfree(usbduxsub_tmp->urbOut[i]->
2266 usbduxsub_tmp->urbOut[i]->transfer_buffer =
2269 if (usbduxsub_tmp->urbOut[i]) {
2270 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,8)
2271 usb_kill_urb(usbduxsub_tmp->urbOut[i]);
2273 usb_free_urb(usbduxsub_tmp->urbOut[i]);
2274 usbduxsub_tmp->urbOut[i] = NULL;
2277 kfree(usbduxsub_tmp->urbOut);
2278 usbduxsub_tmp->urbOut = NULL;
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);
2285 if (usbduxsub_tmp->urbPwm->transfer_buffer) {
2286 kfree(usbduxsub_tmp->urbPwm->transfer_buffer);
2287 usbduxsub_tmp->urbPwm->transfer_buffer = NULL;
2289 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,8)
2290 usb_kill_urb(usbduxsub_tmp->urbPwm);
2292 usb_free_urb(usbduxsub_tmp->urbPwm);
2293 usbduxsub_tmp->urbPwm = NULL;
2295 if (usbduxsub_tmp->inBuffer) {
2296 kfree(usbduxsub_tmp->inBuffer);
2297 usbduxsub_tmp->inBuffer = NULL;
2299 if (usbduxsub_tmp->insnBuffer) {
2300 kfree(usbduxsub_tmp->insnBuffer);
2301 usbduxsub_tmp->insnBuffer = NULL;
2303 if (usbduxsub_tmp->inBuffer) {
2304 kfree(usbduxsub_tmp->inBuffer);
2305 usbduxsub_tmp->inBuffer = NULL;
2307 if (usbduxsub_tmp->dac_commands) {
2308 kfree(usbduxsub_tmp->dac_commands);
2309 usbduxsub_tmp->dac_commands = NULL;
2311 if (usbduxsub_tmp->dux_commands) {
2312 kfree(usbduxsub_tmp->dux_commands);
2313 usbduxsub_tmp->dux_commands = NULL;
2315 usbduxsub_tmp->ai_cmd_running = 0;
2316 usbduxsub_tmp->ao_cmd_running = 0;
2317 usbduxsub_tmp->pwm_cmd_running = 0;
2320 static unsigned hex2unsigned(char *h)
2324 hi = h[0] - 'A' + 0x0a;
2329 lo = h[1] - 'A' + 0x0a;
2333 return hi * 0x10 + lo;
2337 #define FIRMWARE_MAX_LEN 0x2000
2339 // taken from David Brownell's fxload and adjusted for this driver
2340 static int read_firmware(usbduxsub_t * usbduxsub, void *firmwarePtr, long size)
2343 unsigned char *fp = (char *)firmwarePtr;
2344 unsigned char *firmwareBinary = NULL;
2348 firmwareBinary = kzalloc(FIRMWARE_MAX_LEN, GFP_KERNEL);
2349 if (!firmwareBinary) {
2350 printk("comedi_: usbdux: mem alloc for firmware failed\n");
2362 while ((i < size) && (fp[i] != 13) && (fp[i] != 10)) {
2366 if (j >= sizeof(buf)) {
2367 printk("comedi_: usbdux: bogus firmware file!\n");
2371 // get rid of LF/CR/...
2372 while ((i < size) && ((fp[i] == 13) || (fp[i] == 10)
2378 //printk("comedi_: buf=%s\n",buf);
2380 /* EXTENSION: "# comment-till-end-of-line", for copyrights etc */
2384 if (buf[0] != ':') {
2385 printk("comedi_: usbdux: upload: not an ihex record: %s", buf);
2389 /* Read the length field (up to 16 bytes) */
2390 len = hex2unsigned(buf + 1);
2392 /* Read the target offset */
2393 off = (hex2unsigned(buf + 3) * 0x0100) + hex2unsigned(buf + 5);
2395 if ((off + len) > maxAddr) {
2396 maxAddr = off + len;
2399 if (maxAddr >= FIRMWARE_MAX_LEN) {
2400 printk("comedi_: usbdux: firmware upload goes beyond FX2 RAM boundaries.");
2403 //printk("comedi_: usbdux: off=%x, len=%x:",off,len);
2405 /* Read the record type */
2406 type = hex2unsigned(buf + 7);
2408 /* If this is an EOF record, then make it so. */
2414 printk("comedi_: usbdux: unsupported record type: %u\n",
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]);
2426 printk("comedi_: usbdux: unexpected end of hex file\n");
2431 res = firmwareUpload(usbduxsub, firmwareBinary, maxAddr + 1);
2432 kfree(firmwareBinary);
2436 // allocate memory for the urbs and initialise them
2437 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
2438 static void *usbduxsub_probe(struct usb_device *udev,
2439 unsigned int interfnum, const struct usb_device_id *id)
2442 static int usbduxsub_probe(struct usb_interface *uinterf,
2443 const struct usb_device_id *id)
2445 struct usb_device *udev = interface_to_usbdev(uinterf);
2450 #ifdef CONFIG_COMEDI_DEBUG
2451 printk("comedi_: usbdux_: finding a free structure for the usb-device\n");
2453 down(&start_stop_sem);
2454 // look for a free place in the usbdux array
2456 for (i = 0; i < NUMUSBDUX; i++) {
2457 if (!(usbduxsub[i].probed)) {
2465 printk("Too many usbdux-devices connected.\n");
2466 up(&start_stop_sem);
2467 return PROBE_ERR_RETURN(-EMFILE);
2469 #ifdef CONFIG_COMEDI_DEBUG
2470 printk("comedi_: usbdux: usbduxsub[%d] is ready to connect to comedi.\n", index);
2473 init_MUTEX(&(usbduxsub[index].sem));
2474 // save a pointer to the usb device
2475 usbduxsub[index].usbdev = udev;
2477 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
2478 // save the interface number
2479 usbduxsub[index].ifnum = interfnum;
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]));
2490 #ifdef CONFIG_COMEDI_DEBUG
2491 printk("comedi_: usbdux: ifnum=%d\n", usbduxsub[index].ifnum);
2493 // test if it is high speed (USB 2.0)
2494 usbduxsub[index].high_speed =
2495 (usbduxsub[index].usbdev->speed == USB_SPEED_HIGH);
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);
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);
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);
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);
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);
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);
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);
2546 if (usbduxsub[index].high_speed) {
2547 usbduxsub[index].numOfInBuffers = NUMOFINBUFFERSHIGH;
2549 usbduxsub[index].numOfInBuffers = NUMOFINBUFFERSFULL;
2551 usbduxsub[index].urbIn =
2552 kzalloc(sizeof(struct urb *) * usbduxsub[index].numOfInBuffers,
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);
2560 for (i = 0; i < usbduxsub[index].numOfInBuffers; i++) {
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",
2566 tidy_up(&(usbduxsub[index]));
2567 up(&start_stop_sem);
2568 return PROBE_ERR_RETURN(-ENOMEM);
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",
2582 tidy_up(&(usbduxsub[index]));
2583 up(&start_stop_sem);
2584 return PROBE_ERR_RETURN(-ENOMEM);
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;
2594 if (usbduxsub[index].high_speed) {
2595 usbduxsub[index].numOfOutBuffers = NUMOFOUTBUFFERSHIGH;
2597 usbduxsub[index].numOfOutBuffers = NUMOFOUTBUFFERSFULL;
2599 usbduxsub[index].urbOut =
2600 kzalloc(sizeof(struct urb *) * usbduxsub[index].numOfOutBuffers,
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);
2608 for (i = 0; i < usbduxsub[index].numOfOutBuffers; i++) {
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",
2614 tidy_up(&(usbduxsub[index]));
2615 up(&start_stop_sem);
2616 return PROBE_ERR_RETURN(-ENOMEM);
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",
2630 tidy_up(&(usbduxsub[index]));
2631 up(&start_stop_sem);
2632 return PROBE_ERR_RETURN(-ENOMEM);
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 =
2640 if (usbduxsub[index].high_speed) {
2642 usbduxsub[index].urbOut[i]->interval = 8;
2645 usbduxsub[index].urbOut[i]->interval = 1;
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",
2656 tidy_up(&(usbduxsub[index]));
2657 up(&start_stop_sem);
2658 return PROBE_ERR_RETURN(-ENOMEM);
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);
2669 usbduxsub[index].urbPwm = NULL;
2670 usbduxsub[index].sizePwmBuf = 0;
2673 usbduxsub[index].ai_cmd_running = 0;
2674 usbduxsub[index].ao_cmd_running = 0;
2675 usbduxsub[index].pwm_cmd_running = 0;
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]);
2689 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
2690 static void usbduxsub_disconnect(struct usb_device *udev, void *ptr)
2692 usbduxsub_t *usbduxsub_tmp = (usbduxsub_t *) ptr;
2694 static void usbduxsub_disconnect(struct usb_interface *intf)
2696 usbduxsub_t *usbduxsub_tmp = usb_get_intfdata(intf);
2697 struct usb_device *udev = interface_to_usbdev(intf);
2699 if (!usbduxsub_tmp) {
2700 printk("comedi_: usbdux: disconnect called with null pointer.\n");
2703 if (usbduxsub_tmp->usbdev != udev) {
2704 printk("comedi_: usbdux: BUG! called with wrong ptr!!!\n");
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");
2717 // is called when comedi-config is called
2718 static int usbdux_attach(comedi_device * dev, comedi_devconfig * it)
2723 comedi_subdevice *s = NULL;
2724 dev->private = NULL;
2726 down(&start_stop_sem);
2727 // find a valid device which has been detected by the probe function of the usb
2729 for (i = 0; i < NUMUSBDUX; i++) {
2730 if ((usbduxsub[i].probed) && (!usbduxsub[i].attached)) {
2737 printk("comedi%d: usbdux: error: attach failed, no usbdux devs connected to the usb bus.\n", dev->minor);
2738 up(&start_stop_sem);
2742 down(&(usbduxsub[index].sem));
2743 // pointer back to the corresponding comedi device
2744 usbduxsub[index].comedidev = dev;
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]);
2754 dev->board_name = BOARDNAME;
2756 /* set number of subdevices */
2757 if (usbduxsub[index].high_speed) {
2759 dev->n_subdevices = 5;
2762 dev->n_subdevices = 4;
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",
2769 up(&start_stop_sem);
2773 printk("comedi%d: usbdux: usb-device %d is attached to comedi.\n",
2775 // private structure is also simply the usb-structure
2776 dev->private = usbduxsub + index;
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
2788 s->type = COMEDI_SUBD_AI;
2789 // readable and ref is to ground
2790 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
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)
2802 // range table to convert to physical units
2803 s->range_table = (&range_usbdux_ai_range);
2807 s = dev->subdevices + SUBDEV_DA;
2809 s->type = COMEDI_SUBD_AO;
2811 dev->write_subdev = s;
2812 // the subdevice receives as private structure the
2816 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
2819 // length of the channellist
2820 s->len_chanlist = 4;
2821 // 12 bit resolution
2822 s->maxdata = 0x0fff;
2824 s->range_table = (&range_usbdux_ao_range);
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;
2833 s = dev->subdevices + SUBDEV_DIO;
2834 s->type = COMEDI_SUBD_DIO;
2835 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
2838 s->range_table = (&range_digital);
2839 s->insn_bits = usbdux_dio_insn_bits;
2840 s->insn_config = usbdux_dio_insn_config;
2845 s = dev->subdevices + SUBDEV_COUNTER;
2846 s->type = COMEDI_SUBD_COUNTER;
2847 s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
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;
2854 if (usbduxsub[index].high_speed) {
2856 s = dev->subdevices + SUBDEV_PWM;
2857 s->type = COMEDI_SUBD_PWM;
2858 s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE;
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);
2867 // finally decide that it's attached
2868 usbduxsub[index].attached = 1;
2870 up(&(usbduxsub[index].sem));
2872 up(&start_stop_sem);
2874 printk("comedi%d: attached to usbdux.\n", dev->minor);
2879 static int usbdux_detach(comedi_device * dev)
2881 usbduxsub_t *usbduxsub_tmp;
2883 #ifdef CONFIG_COMEDI_DEBUG
2884 printk("comedi%d: usbdux: detach usb device\n", dev->minor);
2888 printk("comedi?: usbdux: detach without dev variable...\n");
2892 usbduxsub_tmp = dev->private;
2893 if (!usbduxsub_tmp) {
2894 printk("comedi?: usbdux: detach without ptr to usbduxsub[]\n");
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);
2907 up(&usbduxsub_tmp->sem);
2911 /* main driver struct */
2912 static comedi_driver driver_usbdux = {
2913 driver_name:"usbdux",
2915 attach:usbdux_attach,
2916 detach:usbdux_detach,
2919 static void init_usb_devices(void)
2922 #ifdef CONFIG_COMEDI_DEBUG
2923 printk("comedi_: usbdux: setting all possible devs to invalid\n");
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));
2934 // Table with the USB-devices: just now only testing IDs
2935 static struct usb_device_id usbduxsub_table[] = {
2936 {USB_DEVICE(0x13d8, 0x0001),
2938 {USB_DEVICE(0x13d8, 0x0002)
2940 {} /* Terminating entry */
2943 MODULE_DEVICE_TABLE(usb, usbduxsub_table);
2945 // The usbduxsub-driver
2946 static struct usb_driver usbduxsub_driver = {
2947 #ifdef COMEDI_HAVE_USB_DRIVER_OWNER
2951 probe:usbduxsub_probe,
2952 disconnect:usbduxsub_disconnect,
2953 id_table:usbduxsub_table,
2956 // Can't use the nice macro as I have also to initialise the USB
2958 // registering the usb-system _and_ the comedi-driver
2959 static int init_usbdux(void)
2961 info(DRIVER_VERSION ":" DRIVER_DESC);
2963 usb_register(&usbduxsub_driver);
2964 comedi_driver_register(&driver_usbdux);
2968 // deregistering the comedi driver and the usb-subsystem
2969 static void exit_usbdux(void)
2971 comedi_driver_unregister(&driver_usbdux);
2972 usb_deregister(&usbduxsub_driver);
2975 module_init(init_usbdux);
2976 module_exit(exit_usbdux);
2978 MODULE_AUTHOR(DRIVER_AUTHOR);
2979 MODULE_DESCRIPTION(DRIVER_DESC);
2980 MODULE_LICENSE("GPL");