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