Staging: comedi: dt9812: fix sparse warnings
[deliverable/linux.git] / drivers / staging / comedi / drivers / usbdux.c
CommitLineData
4bf21fa4
BP
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");
This page took 0.134102 seconds and 5 git commands to generate.