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