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