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