Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[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>
98#include <linux/smp_lock.h>
99#include <linux/fcntl.h>
100#include <linux/compiler.h>
6742c0af 101#include <linux/firmware.h>
4bf21fa4
BP
102
103#include "../comedidev.h"
4bf21fa4
BP
104
105#define BOARDNAME "usbdux"
106
ea25371a
BP
107/* timeout for the USB-transfer in ms*/
108#define BULK_TIMEOUT 1000
4bf21fa4 109
e54fb9c1 110/* constants for "firmware" upload and download */
4bf21fa4
BP
111#define USBDUXSUB_FIRMWARE 0xA0
112#define VENDOR_DIR_IN 0xC0
113#define VENDOR_DIR_OUT 0x40
114
e54fb9c1 115/* internal adresses of the 8051 processor */
4bf21fa4
BP
116#define USBDUXSUB_CPUCS 0xE600
117
e54fb9c1
GKH
118/*
119 * the minor device number, major is 180 only for debugging purposes and to
120 * upload special firmware (programming the eeprom etc) which is not compatible
121 * with the comedi framwork
122 */
4bf21fa4
BP
123#define USBDUXSUB_MINOR 32
124
e54fb9c1 125/* max lenghth of the transfer-buffer for software upload */
4bf21fa4
BP
126#define TB_LEN 0x2000
127
e54fb9c1 128/* Input endpoint number: ISO/IRQ */
4bf21fa4
BP
129#define ISOINEP 6
130
e54fb9c1 131/* Output endpoint number: ISO/IRQ */
4bf21fa4
BP
132#define ISOOUTEP 2
133
e54fb9c1 134/* This EP sends DUX commands to USBDUX */
4bf21fa4
BP
135#define COMMAND_OUT_EP 1
136
e54fb9c1 137/* This EP receives the DUX commands from USBDUX */
4bf21fa4
BP
138#define COMMAND_IN_EP 8
139
e54fb9c1 140/* Output endpoint for PWM */
4bf21fa4
BP
141#define PWM_EP 4
142
e54fb9c1 143/* 300Hz max frequ under PWM */
4bf21fa4
BP
144#define MIN_PWM_PERIOD ((long)(1E9/300))
145
e54fb9c1 146/* Default PWM frequency */
4bf21fa4
BP
147#define PWM_DEFAULT_PERIOD ((long)(1E9/100))
148
e54fb9c1 149/* Number of channels */
4bf21fa4
BP
150#define NUMCHANNELS 8
151
e54fb9c1 152/* Size of one A/D value */
4bf21fa4
BP
153#define SIZEADIN ((sizeof(int16_t)))
154
4274ea02
GKH
155/*
156 * Size of the input-buffer IN BYTES
157 * Always multiple of 8 for 8 microframes which is needed in the highspeed mode
158 */
4bf21fa4
BP
159#define SIZEINBUF ((8*SIZEADIN))
160
e54fb9c1 161/* 16 bytes. */
4bf21fa4
BP
162#define SIZEINSNBUF 16
163
e54fb9c1 164/* Number of DA channels */
4bf21fa4
BP
165#define NUMOUTCHANNELS 8
166
e54fb9c1 167/* size of one value for the D/A converter: channel and value */
4bf21fa4
BP
168#define SIZEDAOUT ((sizeof(int8_t)+sizeof(int16_t)))
169
e54fb9c1
GKH
170/*
171 * Size of the output-buffer in bytes
172 * Actually only the first 4 triplets are used but for the
173 * high speed mode we need to pad it to 8 (microframes).
174 */
4bf21fa4
BP
175#define SIZEOUTBUF ((8*SIZEDAOUT))
176
e54fb9c1
GKH
177/*
178 * Size of the buffer for the dux commands: just now max size is determined
179 * by the analogue out + command byte + panic bytes...
180 */
4bf21fa4
BP
181#define SIZEOFDUXBUFFER ((8*SIZEDAOUT+2))
182
e54fb9c1 183/* Number of in-URBs which receive the data: min=2 */
4bf21fa4
BP
184#define NUMOFINBUFFERSFULL 5
185
e54fb9c1 186/* Number of out-URBs which send the data: min=2 */
4bf21fa4
BP
187#define NUMOFOUTBUFFERSFULL 5
188
e54fb9c1
GKH
189/* Number of in-URBs which receive the data: min=5 */
190/* must have more buffers due to buggy USB ctr */
191#define NUMOFINBUFFERSHIGH 10
4bf21fa4 192
e54fb9c1
GKH
193/* Number of out-URBs which send the data: min=5 */
194/* must have more buffers due to buggy USB ctr */
195#define NUMOFOUTBUFFERSHIGH 10
4bf21fa4 196
e54fb9c1 197/* Total number of usbdux devices */
4bf21fa4
BP
198#define NUMUSBDUX 16
199
e54fb9c1 200/* Analogue in subdevice */
4bf21fa4
BP
201#define SUBDEV_AD 0
202
e54fb9c1 203/* Analogue out subdevice */
4bf21fa4
BP
204#define SUBDEV_DA 1
205
e54fb9c1 206/* Digital I/O */
4bf21fa4
BP
207#define SUBDEV_DIO 2
208
e54fb9c1 209/* counter */
4bf21fa4
BP
210#define SUBDEV_COUNTER 3
211
e54fb9c1 212/* timer aka pwm output */
4bf21fa4
BP
213#define SUBDEV_PWM 4
214
e54fb9c1 215/* number of retries to get the right dux command */
4bf21fa4
BP
216#define RETRIES 10
217
e54fb9c1
GKH
218/**************************************************/
219/* comedi constants */
9ced1de6 220static const struct comedi_lrange range_usbdux_ai_range = { 4, {
0a85b6f0
MT
221 BIP_RANGE
222 (4.096),
223 BIP_RANGE(4.096
224 / 2),
225 UNI_RANGE
226 (4.096),
227 UNI_RANGE(4.096
228 / 2)
229 }
4bf21fa4
BP
230};
231
9ced1de6 232static const struct comedi_lrange range_usbdux_ao_range = { 2, {
0a85b6f0
MT
233 BIP_RANGE
234 (4.096),
235 UNI_RANGE
236 (4.096),
237 }
4bf21fa4
BP
238};
239
240/*
241 * private structure of one subdevice
242 */
243
e54fb9c1
GKH
244/*
245 * This is the structure which holds all the data of
246 * this driver one sub device just now: A/D
247 */
cc92fca7 248struct usbduxsub {
e54fb9c1 249 /* attached? */
4bf21fa4 250 int attached;
e54fb9c1 251 /* is it associated with a subdevice? */
4bf21fa4 252 int probed;
e54fb9c1 253 /* pointer to the usb-device */
4bf21fa4 254 struct usb_device *usbdev;
e54fb9c1 255 /* actual number of in-buffers */
4bf21fa4 256 int numOfInBuffers;
e54fb9c1 257 /* actual number of out-buffers */
4bf21fa4 258 int numOfOutBuffers;
e54fb9c1 259 /* ISO-transfer handling: buffers */
4bf21fa4
BP
260 struct urb **urbIn;
261 struct urb **urbOut;
e54fb9c1 262 /* pwm-transfer handling */
4bf21fa4 263 struct urb *urbPwm;
e54fb9c1 264 /* PWM period */
790c5541 265 unsigned int pwmPeriod;
e54fb9c1 266 /* PWM internal delay for the GPIF in the FX2 */
4bf21fa4 267 int8_t pwmDelay;
e54fb9c1 268 /* size of the PWM buffer which holds the bit pattern */
4bf21fa4 269 int sizePwmBuf;
e54fb9c1 270 /* input buffer for the ISO-transfer */
4bf21fa4 271 int16_t *inBuffer;
e54fb9c1 272 /* input buffer for single insn */
4bf21fa4 273 int16_t *insnBuffer;
e54fb9c1 274 /* output buffer for single DA outputs */
4bf21fa4 275 int16_t *outBuffer;
e54fb9c1 276 /* interface number */
4bf21fa4 277 int ifnum;
e54fb9c1 278 /* interface structure in 2.6 */
4bf21fa4 279 struct usb_interface *interface;
e54fb9c1 280 /* comedi device for the interrupt context */
71b5f4f1 281 struct comedi_device *comedidev;
e54fb9c1 282 /* is it USB_SPEED_HIGH or not? */
4bf21fa4 283 short int high_speed;
e54fb9c1 284 /* asynchronous command is running */
4bf21fa4
BP
285 short int ai_cmd_running;
286 short int ao_cmd_running;
e54fb9c1 287 /* pwm is running */
4bf21fa4 288 short int pwm_cmd_running;
e54fb9c1 289 /* continous aquisition */
4bf21fa4
BP
290 short int ai_continous;
291 short int ao_continous;
e54fb9c1 292 /* number of samples to aquire */
4bf21fa4
BP
293 int ai_sample_count;
294 int ao_sample_count;
e54fb9c1 295 /* time between samples in units of the timer */
4bf21fa4
BP
296 unsigned int ai_timer;
297 unsigned int ao_timer;
e54fb9c1 298 /* counter between aquisitions */
4bf21fa4
BP
299 unsigned int ai_counter;
300 unsigned int ao_counter;
e54fb9c1 301 /* interval in frames/uframes */
4bf21fa4 302 unsigned int ai_interval;
e54fb9c1 303 /* D/A commands */
4bf21fa4 304 int8_t *dac_commands;
e54fb9c1 305 /* commands */
4bf21fa4
BP
306 int8_t *dux_commands;
307 struct semaphore sem;
cc92fca7 308};
4bf21fa4 309
e54fb9c1
GKH
310/*
311 * The pointer to the private usb-data of the driver is also the private data
312 * for the comedi-device. This has to be global as the usb subsystem needs
313 * global variables. The other reason is that this structure must be there
314 * _before_ any comedi command is issued. The usb subsystem must be initialised
315 * before comedi can access it.
316 */
cc92fca7 317static struct usbduxsub usbduxsub[NUMUSBDUX];
4bf21fa4
BP
318
319static DECLARE_MUTEX(start_stop_sem);
320
e54fb9c1
GKH
321/*
322 * Stops the data acquision
323 * It should be safe to call this function from any context
324 */
cc92fca7 325static int usbduxsub_unlink_InURBs(struct usbduxsub *usbduxsub_tmp)
4bf21fa4
BP
326{
327 int i = 0;
4bf21fa4
BP
328 int err = 0;
329
330 if (usbduxsub_tmp && usbduxsub_tmp->urbIn) {
331 for (i = 0; i < usbduxsub_tmp->numOfInBuffers; i++) {
332 if (usbduxsub_tmp->urbIn[i]) {
e54fb9c1
GKH
333 /* We wait here until all transfers have been
334 * cancelled. */
4bf21fa4 335 usb_kill_urb(usbduxsub_tmp->urbIn[i]);
4bf21fa4 336 }
c0e0c26e
GKH
337 dev_dbg(&usbduxsub_tmp->interface->dev,
338 "comedi: usbdux: unlinked InURB %d, err=%d\n",
4bf21fa4 339 i, err);
4bf21fa4
BP
340 }
341 }
342 return err;
343}
344
8fa07567
GKH
345/*
346 * This will stop a running acquisition operation
347 * Is called from within this driver from both the
348 * interrupt context and from comedi
349 */
cc92fca7 350static int usbdux_ai_stop(struct usbduxsub *this_usbduxsub, int do_unlink)
4bf21fa4
BP
351{
352 int ret = 0;
353
354 if (!this_usbduxsub) {
c0e0c26e
GKH
355 dev_err(&this_usbduxsub->interface->dev,
356 "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)) {
e54fb9c1 505 /* not continous, 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
BP
653 this_usbduxsub->ao_counter--;
654 if (this_usbduxsub->ao_counter <= 0) {
e54fb9c1 655 /* timer zero */
4bf21fa4
BP
656 this_usbduxsub->ao_counter = this_usbduxsub->ao_timer;
657
e54fb9c1 658 /* handle non continous aquisition */
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,
0a85b6f0 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,
0a85b6f0 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
BP
838 dev_err(&usbduxsub->interface->dev,
839 "comedi_: usbdux firmware binary it too large for FX2.\n");
840 return -ENOMEM;
841 }
842
843 /* we generate a local buffer for the firmware */
844 fwBuf = kzalloc(sizeFirmware, GFP_KERNEL);
845 if (!fwBuf) {
846 dev_err(&usbduxsub->interface->dev,
847 "comedi_: mem alloc for firmware failed\n");
848 return -ENOMEM;
849 }
0a85b6f0 850 memcpy(fwBuf, firmwareBinary, sizeFirmware);
81874ff7 851
4bf21fa4
BP
852 ret = usbduxsub_stop(usbduxsub);
853 if (ret < 0) {
c0e0c26e
GKH
854 dev_err(&usbduxsub->interface->dev,
855 "comedi_: can not stop firmware\n");
81874ff7 856 kfree(fwBuf);
4bf21fa4
BP
857 return ret;
858 }
81874ff7
BP
859
860 ret = usbduxsub_upload(usbduxsub, fwBuf, 0, sizeFirmware);
4bf21fa4 861 if (ret < 0) {
c0e0c26e
GKH
862 dev_err(&usbduxsub->interface->dev,
863 "comedi_: firmware upload failed\n");
81874ff7 864 kfree(fwBuf);
4bf21fa4
BP
865 return ret;
866 }
867 ret = usbduxsub_start(usbduxsub);
868 if (ret < 0) {
c0e0c26e
GKH
869 dev_err(&usbduxsub->interface->dev,
870 "comedi_: can not start firmware\n");
81874ff7 871 kfree(fwBuf);
4bf21fa4
BP
872 return ret;
873 }
81874ff7 874 kfree(fwBuf);
4bf21fa4
BP
875 return 0;
876}
877
cc92fca7 878static int usbduxsub_submit_InURBs(struct usbduxsub *usbduxsub)
4bf21fa4
BP
879{
880 int i, errFlag;
881
8fa07567 882 if (!usbduxsub)
4bf21fa4 883 return -EFAULT;
8fa07567 884
4bf21fa4
BP
885 /* Submit all URBs and start the transfer on the bus */
886 for (i = 0; i < usbduxsub->numOfInBuffers; i++) {
8fa07567 887 /* in case of a resubmission after an unlink... */
4bf21fa4
BP
888 usbduxsub->urbIn[i]->interval = usbduxsub->ai_interval;
889 usbduxsub->urbIn[i]->context = usbduxsub->comedidev;
890 usbduxsub->urbIn[i]->dev = usbduxsub->usbdev;
891 usbduxsub->urbIn[i]->status = 0;
892 usbduxsub->urbIn[i]->transfer_flags = URB_ISO_ASAP;
c0e0c26e
GKH
893 dev_dbg(&usbduxsub->interface->dev,
894 "comedi%d: submitting in-urb[%d]: %p,%p intv=%d\n",
895 usbduxsub->comedidev->minor, i,
896 (usbduxsub->urbIn[i]->context),
897 (usbduxsub->urbIn[i]->dev),
898 (usbduxsub->urbIn[i]->interval));
4aa3a823 899 errFlag = usb_submit_urb(usbduxsub->urbIn[i], GFP_ATOMIC);
4bf21fa4 900 if (errFlag) {
c0e0c26e 901 dev_err(&usbduxsub->interface->dev,
4aa3a823 902 "comedi_: ai: usb_submit_urb(%d) error %d\n",
c0e0c26e 903 i, errFlag);
4bf21fa4
BP
904 return errFlag;
905 }
906 }
907 return 0;
908}
909
cc92fca7 910static int usbduxsub_submit_OutURBs(struct usbduxsub *usbduxsub)
4bf21fa4
BP
911{
912 int i, errFlag;
913
4274ea02 914 if (!usbduxsub)
4bf21fa4 915 return -EFAULT;
4274ea02 916
4bf21fa4 917 for (i = 0; i < usbduxsub->numOfOutBuffers; i++) {
c0e0c26e
GKH
918 dev_dbg(&usbduxsub->interface->dev,
919 "comedi_: submitting out-urb[%d]\n", i);
e54fb9c1 920 /* in case of a resubmission after an unlink... */
4bf21fa4
BP
921 usbduxsub->urbOut[i]->context = usbduxsub->comedidev;
922 usbduxsub->urbOut[i]->dev = usbduxsub->usbdev;
923 usbduxsub->urbOut[i]->status = 0;
924 usbduxsub->urbOut[i]->transfer_flags = URB_ISO_ASAP;
4aa3a823 925 errFlag = usb_submit_urb(usbduxsub->urbOut[i], GFP_ATOMIC);
4bf21fa4 926 if (errFlag) {
c0e0c26e 927 dev_err(&usbduxsub->interface->dev,
4aa3a823 928 "comedi_: ao: usb_submit_urb(%d) error %d\n",
c0e0c26e 929 i, errFlag);
4bf21fa4
BP
930 return errFlag;
931 }
932 }
933 return 0;
934}
935
0a85b6f0
MT
936static int usbdux_ai_cmdtest(struct comedi_device *dev,
937 struct comedi_subdevice *s, struct comedi_cmd *cmd)
4bf21fa4
BP
938{
939 int err = 0, tmp, i;
940 unsigned int tmpTimer;
cc92fca7 941 struct usbduxsub *this_usbduxsub = dev->private;
4274ea02
GKH
942
943 if (!(this_usbduxsub->probed))
4bf21fa4 944 return -ENODEV;
4274ea02 945
c0e0c26e
GKH
946 dev_dbg(&this_usbduxsub->interface->dev,
947 "comedi%d: usbdux_ai_cmdtest\n", dev->minor);
948
4bf21fa4 949 /* make sure triggers are valid */
e54fb9c1 950 /* Only immediate triggers are allowed */
4bf21fa4
BP
951 tmp = cmd->start_src;
952 cmd->start_src &= TRIG_NOW | TRIG_INT;
953 if (!cmd->start_src || tmp != cmd->start_src)
954 err++;
955
e54fb9c1 956 /* trigger should happen timed */
4bf21fa4 957 tmp = cmd->scan_begin_src;
e54fb9c1 958 /* start a new _scan_ with a timer */
4bf21fa4
BP
959 cmd->scan_begin_src &= TRIG_TIMER;
960 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
961 err++;
962
e54fb9c1 963 /* scanning is continous */
4bf21fa4
BP
964 tmp = cmd->convert_src;
965 cmd->convert_src &= TRIG_NOW;
966 if (!cmd->convert_src || tmp != cmd->convert_src)
967 err++;
968
e54fb9c1 969 /* issue a trigger when scan is finished and start a new scan */
4bf21fa4
BP
970 tmp = cmd->scan_end_src;
971 cmd->scan_end_src &= TRIG_COUNT;
972 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
973 err++;
974
e54fb9c1 975 /* trigger at the end of count events or not, stop condition or not */
4bf21fa4
BP
976 tmp = cmd->stop_src;
977 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
978 if (!cmd->stop_src || tmp != cmd->stop_src)
979 err++;
980
981 if (err)
982 return 1;
983
4274ea02
GKH
984 /*
985 * step 2: make sure trigger sources are unique and mutually compatible
828684f9 986 * note that mutual compatibility is not an issue here
4274ea02 987 */
4bf21fa4 988 if (cmd->scan_begin_src != TRIG_FOLLOW &&
0a85b6f0
MT
989 cmd->scan_begin_src != TRIG_EXT &&
990 cmd->scan_begin_src != TRIG_TIMER)
4bf21fa4
BP
991 err++;
992 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
993 err++;
994
995 if (err)
996 return 2;
997
998 /* step 3: make sure arguments are trivially compatible */
4bf21fa4
BP
999 if (cmd->start_arg != 0) {
1000 cmd->start_arg = 0;
1001 err++;
1002 }
1003
1004 if (cmd->scan_begin_src == TRIG_FOLLOW) {
1005 /* internal trigger */
1006 if (cmd->scan_begin_arg != 0) {
1007 cmd->scan_begin_arg = 0;
1008 err++;
1009 }
1010 }
1011
1012 if (cmd->scan_begin_src == TRIG_TIMER) {
1013 if (this_usbduxsub->high_speed) {
e54fb9c1
GKH
1014 /*
1015 * In high speed mode microframes are possible.
1016 * However, during one microframe we can roughly
1017 * sample one channel. Thus, the more channels
1018 * are in the channel list the more time we need.
1019 */
4bf21fa4 1020 i = 1;
e54fb9c1 1021 /* find a power of 2 for the number of channels */
4274ea02 1022 while (i < (cmd->chanlist_len))
4bf21fa4 1023 i = i * 2;
4274ea02 1024
4bf21fa4
BP
1025 if (cmd->scan_begin_arg < (1000000 / 8 * i)) {
1026 cmd->scan_begin_arg = 1000000 / 8 * i;
1027 err++;
1028 }
e54fb9c1
GKH
1029 /* now calc the real sampling rate with all the
1030 * rounding errors */
4bf21fa4 1031 tmpTimer =
0a85b6f0
MT
1032 ((unsigned int)(cmd->scan_begin_arg / 125000)) *
1033 125000;
4bf21fa4
BP
1034 if (cmd->scan_begin_arg != tmpTimer) {
1035 cmd->scan_begin_arg = tmpTimer;
1036 err++;
1037 }
e54fb9c1
GKH
1038 } else {
1039 /* full speed */
1040 /* 1kHz scans every USB frame */
4bf21fa4
BP
1041 if (cmd->scan_begin_arg < 1000000) {
1042 cmd->scan_begin_arg = 1000000;
1043 err++;
1044 }
4274ea02
GKH
1045 /*
1046 * calc the real sampling rate with the rounding errors
1047 */
1048 tmpTimer = ((unsigned int)(cmd->scan_begin_arg /
0a85b6f0 1049 1000000)) * 1000000;
4bf21fa4
BP
1050 if (cmd->scan_begin_arg != tmpTimer) {
1051 cmd->scan_begin_arg = tmpTimer;
1052 err++;
1053 }
1054 }
1055 }
e54fb9c1 1056 /* the same argument */
4bf21fa4
BP
1057 if (cmd->scan_end_arg != cmd->chanlist_len) {
1058 cmd->scan_end_arg = cmd->chanlist_len;
1059 err++;
1060 }
1061
1062 if (cmd->stop_src == TRIG_COUNT) {
1063 /* any count is allowed */
1064 } else {
1065 /* TRIG_NONE */
1066 if (cmd->stop_arg != 0) {
1067 cmd->stop_arg = 0;
1068 err++;
1069 }
1070 }
1071
1072 if (err)
1073 return 3;
1074
1075 return 0;
1076}
1077
e54fb9c1
GKH
1078/*
1079 * creates the ADC command for the MAX1271
1080 * range is the range value from comedi
1081 */
4bf21fa4
BP
1082static int8_t create_adc_command(unsigned int chan, int range)
1083{
1084 int8_t p = (range <= 1);
1085 int8_t r = ((range % 2) == 0);
1086 return (chan << 4) | ((p == 1) << 2) | ((r == 1) << 3);
1087}
1088
e54fb9c1 1089/* bulk transfers to usbdux */
4bf21fa4
BP
1090
1091#define SENDADCOMMANDS 0
1092#define SENDDACOMMANDS 1
1093#define SENDDIOCONFIGCOMMAND 2
1094#define SENDDIOBITSCOMMAND 3
1095#define SENDSINGLEAD 4
1096#define READCOUNTERCOMMAND 5
1097#define WRITECOUNTERCOMMAND 6
1098#define SENDPWMON 7
1099#define SENDPWMOFF 8
1100
cc92fca7 1101static int send_dux_commands(struct usbduxsub *this_usbduxsub, int cmd_type)
4bf21fa4
BP
1102{
1103 int result, nsent;
1104
1105 this_usbduxsub->dux_commands[0] = cmd_type;
1106#ifdef NOISY_DUX_DEBUGBUG
c0e0c26e 1107 printk(KERN_DEBUG "comedi%d: usbdux: dux_commands: ",
0a85b6f0 1108 this_usbduxsub->comedidev->minor);
4274ea02 1109 for (result = 0; result < SIZEOFDUXBUFFER; result++)
4bf21fa4 1110 printk(" %02x", this_usbduxsub->dux_commands[result]);
4bf21fa4
BP
1111 printk("\n");
1112#endif
4aa3a823
GKH
1113 result = usb_bulk_msg(this_usbduxsub->usbdev,
1114 usb_sndbulkpipe(this_usbduxsub->usbdev,
1115 COMMAND_OUT_EP),
1116 this_usbduxsub->dux_commands, SIZEOFDUXBUFFER,
ea25371a 1117 &nsent, BULK_TIMEOUT);
8fa07567 1118 if (result < 0)
c0e0c26e
GKH
1119 dev_err(&this_usbduxsub->interface->dev, "comedi%d: "
1120 "could not transmit dux_command to the usb-device, "
1121 "err=%d\n", this_usbduxsub->comedidev->minor, result);
8fa07567 1122
4bf21fa4
BP
1123 return result;
1124}
1125
cc92fca7 1126static int receive_dux_commands(struct usbduxsub *this_usbduxsub, int command)
4bf21fa4
BP
1127{
1128 int result = (-EFAULT);
1129 int nrec;
1130 int i;
1131
1132 for (i = 0; i < RETRIES; i++) {
4aa3a823
GKH
1133 result = usb_bulk_msg(this_usbduxsub->usbdev,
1134 usb_rcvbulkpipe(this_usbduxsub->usbdev,
1135 COMMAND_IN_EP),
1136 this_usbduxsub->insnBuffer, SIZEINSNBUF,
ea25371a 1137 &nrec, BULK_TIMEOUT);
4bf21fa4 1138 if (result < 0) {
c0e0c26e
GKH
1139 dev_err(&this_usbduxsub->interface->dev, "comedi%d: "
1140 "insn: USB error %d while receiving DUX command"
1141 "\n", this_usbduxsub->comedidev->minor, result);
4bf21fa4
BP
1142 return result;
1143 }
4274ea02 1144 if (le16_to_cpu(this_usbduxsub->insnBuffer[0]) == command)
4bf21fa4 1145 return result;
4bf21fa4 1146 }
4274ea02
GKH
1147 /* this is only reached if the data has been requested a couple of
1148 * times */
c0e0c26e
GKH
1149 dev_err(&this_usbduxsub->interface->dev, "comedi%d: insn: "
1150 "wrong data returned from firmware: want cmd %d, got cmd %d.\n",
1151 this_usbduxsub->comedidev->minor, command,
1152 le16_to_cpu(this_usbduxsub->insnBuffer[0]));
4bf21fa4
BP
1153 return -EFAULT;
1154}
1155
0a85b6f0
MT
1156static int usbdux_ai_inttrig(struct comedi_device *dev,
1157 struct comedi_subdevice *s, unsigned int trignum)
4bf21fa4
BP
1158{
1159 int ret;
cc92fca7 1160 struct usbduxsub *this_usbduxsub = dev->private;
4274ea02 1161 if (!this_usbduxsub)
4bf21fa4 1162 return -EFAULT;
4274ea02 1163
4bf21fa4
BP
1164 down(&this_usbduxsub->sem);
1165 if (!(this_usbduxsub->probed)) {
1166 up(&this_usbduxsub->sem);
1167 return -ENODEV;
1168 }
c0e0c26e
GKH
1169 dev_dbg(&this_usbduxsub->interface->dev,
1170 "comedi%d: usbdux_ai_inttrig\n", dev->minor);
4bf21fa4
BP
1171
1172 if (trignum != 0) {
c0e0c26e
GKH
1173 dev_err(&this_usbduxsub->interface->dev,
1174 "comedi%d: usbdux_ai_inttrig: invalid trignum\n",
4bf21fa4
BP
1175 dev->minor);
1176 up(&this_usbduxsub->sem);
1177 return -EINVAL;
1178 }
1179 if (!(this_usbduxsub->ai_cmd_running)) {
1180 this_usbduxsub->ai_cmd_running = 1;
1181 ret = usbduxsub_submit_InURBs(this_usbduxsub);
1182 if (ret < 0) {
c0e0c26e
GKH
1183 dev_err(&this_usbduxsub->interface->dev,
1184 "comedi%d: usbdux_ai_inttrig: "
1185 "urbSubmit: err=%d\n", dev->minor, ret);
4bf21fa4
BP
1186 this_usbduxsub->ai_cmd_running = 0;
1187 up(&this_usbduxsub->sem);
1188 return ret;
1189 }
1190 s->async->inttrig = NULL;
1191 } else {
c0e0c26e
GKH
1192 dev_err(&this_usbduxsub->interface->dev,
1193 "comedi%d: ai_inttrig but acqu is already running\n",
4bf21fa4
BP
1194 dev->minor);
1195 }
1196 up(&this_usbduxsub->sem);
1197 return 1;
1198}
1199
34c43922 1200static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
4bf21fa4 1201{
ea6d0d4c 1202 struct comedi_cmd *cmd = &s->async->cmd;
4bf21fa4
BP
1203 unsigned int chan, range;
1204 int i, ret;
cc92fca7 1205 struct usbduxsub *this_usbduxsub = dev->private;
4bf21fa4
BP
1206 int result;
1207
8fa07567 1208 if (!this_usbduxsub)
4bf21fa4 1209 return -EFAULT;
8fa07567 1210
c0e0c26e
GKH
1211 dev_dbg(&this_usbduxsub->interface->dev,
1212 "comedi%d: usbdux_ai_cmd\n", dev->minor);
1213
8fa07567 1214 /* block other CPUs from starting an ai_cmd */
4bf21fa4
BP
1215 down(&this_usbduxsub->sem);
1216
1217 if (!(this_usbduxsub->probed)) {
1218 up(&this_usbduxsub->sem);
1219 return -ENODEV;
1220 }
1221 if (this_usbduxsub->ai_cmd_running) {
c0e0c26e
GKH
1222 dev_err(&this_usbduxsub->interface->dev, "comedi%d: "
1223 "ai_cmd not possible. Another ai_cmd is running.\n",
1224 dev->minor);
4bf21fa4
BP
1225 up(&this_usbduxsub->sem);
1226 return -EBUSY;
1227 }
8fa07567 1228 /* set current channel of the running aquisition to zero */
4bf21fa4
BP
1229 s->async->cur_chan = 0;
1230
1231 this_usbduxsub->dux_commands[1] = cmd->chanlist_len;
1232 for (i = 0; i < cmd->chanlist_len; ++i) {
1233 chan = CR_CHAN(cmd->chanlist[i]);
1234 range = CR_RANGE(cmd->chanlist[i]);
1235 if (i >= NUMCHANNELS) {
c0e0c26e
GKH
1236 dev_err(&this_usbduxsub->interface->dev,
1237 "comedi%d: channel list too long\n",
1238 dev->minor);
4bf21fa4
BP
1239 break;
1240 }
1241 this_usbduxsub->dux_commands[i + 2] =
0a85b6f0 1242 create_adc_command(chan, range);
4bf21fa4
BP
1243 }
1244
c0e0c26e
GKH
1245 dev_dbg(&this_usbduxsub->interface->dev,
1246 "comedi %d: sending commands to the usb device: size=%u\n",
1247 dev->minor, NUMCHANNELS);
1248
4274ea02
GKH
1249 result = send_dux_commands(this_usbduxsub, SENDADCOMMANDS);
1250 if (result < 0) {
4bf21fa4
BP
1251 up(&this_usbduxsub->sem);
1252 return result;
1253 }
1254
1255 if (this_usbduxsub->high_speed) {
8fa07567
GKH
1256 /*
1257 * every channel gets a time window of 125us. Thus, if we
1258 * sample all 8 channels we need 1ms. If we sample only one
1259 * channel we need only 125us
1260 */
4bf21fa4 1261 this_usbduxsub->ai_interval = 1;
8fa07567 1262 /* find a power of 2 for the interval */
4bf21fa4
BP
1263 while ((this_usbduxsub->ai_interval) < (cmd->chanlist_len)) {
1264 this_usbduxsub->ai_interval =
0a85b6f0 1265 (this_usbduxsub->ai_interval) * 2;
4bf21fa4 1266 }
8fa07567 1267 this_usbduxsub->ai_timer = cmd->scan_begin_arg / (125000 *
0a85b6f0
MT
1268 (this_usbduxsub->
1269 ai_interval));
4bf21fa4 1270 } else {
8fa07567 1271 /* interval always 1ms */
4bf21fa4
BP
1272 this_usbduxsub->ai_interval = 1;
1273 this_usbduxsub->ai_timer = cmd->scan_begin_arg / 1000000;
1274 }
1275 if (this_usbduxsub->ai_timer < 1) {
c0e0c26e
GKH
1276 dev_err(&this_usbduxsub->interface->dev, "comedi%d: ai_cmd: "
1277 "timer=%d, scan_begin_arg=%d. "
1278 "Not properly tested by cmdtest?\n", dev->minor,
1279 this_usbduxsub->ai_timer, cmd->scan_begin_arg);
4bf21fa4
BP
1280 up(&this_usbduxsub->sem);
1281 return -EINVAL;
1282 }
1283 this_usbduxsub->ai_counter = this_usbduxsub->ai_timer;
1284
1285 if (cmd->stop_src == TRIG_COUNT) {
e54fb9c1 1286 /* data arrives as one packet */
4bf21fa4
BP
1287 this_usbduxsub->ai_sample_count = cmd->stop_arg;
1288 this_usbduxsub->ai_continous = 0;
1289 } else {
e54fb9c1 1290 /* continous aquisition */
4bf21fa4
BP
1291 this_usbduxsub->ai_continous = 1;
1292 this_usbduxsub->ai_sample_count = 0;
1293 }
1294
1295 if (cmd->start_src == TRIG_NOW) {
e54fb9c1 1296 /* enable this acquisition operation */
4bf21fa4
BP
1297 this_usbduxsub->ai_cmd_running = 1;
1298 ret = usbduxsub_submit_InURBs(this_usbduxsub);
1299 if (ret < 0) {
1300 this_usbduxsub->ai_cmd_running = 0;
e54fb9c1 1301 /* fixme: unlink here?? */
4bf21fa4
BP
1302 up(&this_usbduxsub->sem);
1303 return ret;
1304 }
1305 s->async->inttrig = NULL;
1306 } else {
1307 /* TRIG_INT */
e54fb9c1
GKH
1308 /* don't enable the acquision operation */
1309 /* wait for an internal signal */
4bf21fa4
BP
1310 s->async->inttrig = usbdux_ai_inttrig;
1311 }
1312 up(&this_usbduxsub->sem);
1313 return 0;
1314}
1315
1316/* Mode 0 is used to get a single conversion on demand */
0a85b6f0
MT
1317static int usbdux_ai_insn_read(struct comedi_device *dev,
1318 struct comedi_subdevice *s,
90035c08 1319 struct comedi_insn *insn, unsigned int *data)
4bf21fa4
BP
1320{
1321 int i;
790c5541 1322 unsigned int one = 0;
4bf21fa4
BP
1323 int chan, range;
1324 int err;
cc92fca7 1325 struct usbduxsub *this_usbduxsub = dev->private;
4bf21fa4 1326
c0e0c26e 1327 if (!this_usbduxsub)
4bf21fa4 1328 return 0;
c0e0c26e
GKH
1329
1330 dev_dbg(&this_usbduxsub->interface->dev,
1331 "comedi%d: ai_insn_read, insn->n=%d, insn->subdev=%d\n",
4bf21fa4 1332 dev->minor, insn->n, insn->subdev);
c0e0c26e 1333
4bf21fa4
BP
1334 down(&this_usbduxsub->sem);
1335 if (!(this_usbduxsub->probed)) {
1336 up(&this_usbduxsub->sem);
1337 return -ENODEV;
1338 }
1339 if (this_usbduxsub->ai_cmd_running) {
c0e0c26e
GKH
1340 dev_err(&this_usbduxsub->interface->dev,
1341 "comedi%d: ai_insn_read not possible. "
1342 "Async Command is running.\n", dev->minor);
4bf21fa4
BP
1343 up(&this_usbduxsub->sem);
1344 return 0;
1345 }
1346
e54fb9c1 1347 /* sample one channel */
4bf21fa4
BP
1348 chan = CR_CHAN(insn->chanspec);
1349 range = CR_RANGE(insn->chanspec);
e54fb9c1 1350 /* set command for the first channel */
4bf21fa4
BP
1351 this_usbduxsub->dux_commands[1] = create_adc_command(chan, range);
1352
e54fb9c1 1353 /* adc commands */
4274ea02
GKH
1354 err = send_dux_commands(this_usbduxsub, SENDSINGLEAD);
1355 if (err < 0) {
4bf21fa4
BP
1356 up(&this_usbduxsub->sem);
1357 return err;
1358 }
1359
1360 for (i = 0; i < insn->n; i++) {
4274ea02
GKH
1361 err = receive_dux_commands(this_usbduxsub, SENDSINGLEAD);
1362 if (err < 0) {
4bf21fa4
BP
1363 up(&this_usbduxsub->sem);
1364 return 0;
1365 }
1366 one = le16_to_cpu(this_usbduxsub->insnBuffer[1]);
8fa07567 1367 if (CR_RANGE(insn->chanspec) <= 1)
4bf21fa4 1368 one = one ^ 0x800;
8fa07567 1369
4bf21fa4
BP
1370 data[i] = one;
1371 }
1372 up(&this_usbduxsub->sem);
1373 return i;
1374}
1375
e54fb9c1
GKH
1376/************************************/
1377/* analog out */
4bf21fa4 1378
0a85b6f0
MT
1379static int usbdux_ao_insn_read(struct comedi_device *dev,
1380 struct comedi_subdevice *s,
90035c08 1381 struct comedi_insn *insn, unsigned int *data)
4bf21fa4
BP
1382{
1383 int i;
1384 int chan = CR_CHAN(insn->chanspec);
cc92fca7 1385 struct usbduxsub *this_usbduxsub = dev->private;
4bf21fa4 1386
8fa07567 1387 if (!this_usbduxsub)
4bf21fa4 1388 return -EFAULT;
8fa07567 1389
4bf21fa4
BP
1390 down(&this_usbduxsub->sem);
1391 if (!(this_usbduxsub->probed)) {
1392 up(&this_usbduxsub->sem);
1393 return -ENODEV;
1394 }
8fa07567 1395 for (i = 0; i < insn->n; i++)
4bf21fa4 1396 data[i] = this_usbduxsub->outBuffer[chan];
8fa07567 1397
4bf21fa4
BP
1398 up(&this_usbduxsub->sem);
1399 return i;
1400}
1401
0a85b6f0
MT
1402static int usbdux_ao_insn_write(struct comedi_device *dev,
1403 struct comedi_subdevice *s,
90035c08 1404 struct comedi_insn *insn, unsigned int *data)
4bf21fa4
BP
1405{
1406 int i, err;
1407 int chan = CR_CHAN(insn->chanspec);
cc92fca7 1408 struct usbduxsub *this_usbduxsub = dev->private;
4bf21fa4 1409
8fa07567 1410 if (!this_usbduxsub)
4bf21fa4 1411 return -EFAULT;
8fa07567 1412
c0e0c26e
GKH
1413 dev_dbg(&this_usbduxsub->interface->dev,
1414 "comedi%d: ao_insn_write\n", dev->minor);
1415
4bf21fa4
BP
1416 down(&this_usbduxsub->sem);
1417 if (!(this_usbduxsub->probed)) {
1418 up(&this_usbduxsub->sem);
1419 return -ENODEV;
1420 }
1421 if (this_usbduxsub->ao_cmd_running) {
c0e0c26e
GKH
1422 dev_err(&this_usbduxsub->interface->dev,
1423 "comedi%d: ao_insn_write: "
1424 "ERROR: asynchronous ao_cmd is running\n", dev->minor);
4bf21fa4
BP
1425 up(&this_usbduxsub->sem);
1426 return 0;
1427 }
1428
1429 for (i = 0; i < insn->n; i++) {
c0e0c26e
GKH
1430 dev_dbg(&this_usbduxsub->interface->dev,
1431 "comedi%d: ao_insn_write: data[chan=%d,i=%d]=%d\n",
4bf21fa4 1432 dev->minor, chan, i, data[i]);
c0e0c26e 1433
e54fb9c1 1434 /* number of channels: 1 */
4bf21fa4 1435 this_usbduxsub->dux_commands[1] = 1;
e54fb9c1 1436 /* one 16 bit value */
4bf21fa4 1437 *((int16_t *) (this_usbduxsub->dux_commands + 2)) =
0a85b6f0 1438 cpu_to_le16(data[i]);
4bf21fa4 1439 this_usbduxsub->outBuffer[chan] = data[i];
e54fb9c1 1440 /* channel number */
4bf21fa4 1441 this_usbduxsub->dux_commands[4] = (chan << 6);
4274ea02
GKH
1442 err = send_dux_commands(this_usbduxsub, SENDDACOMMANDS);
1443 if (err < 0) {
4bf21fa4
BP
1444 up(&this_usbduxsub->sem);
1445 return err;
1446 }
1447 }
1448 up(&this_usbduxsub->sem);
1449
1450 return i;
1451}
1452
0a85b6f0
MT
1453static int usbdux_ao_inttrig(struct comedi_device *dev,
1454 struct comedi_subdevice *s, unsigned int trignum)
4bf21fa4
BP
1455{
1456 int ret;
cc92fca7 1457 struct usbduxsub *this_usbduxsub = dev->private;
4bf21fa4 1458
8fa07567 1459 if (!this_usbduxsub)
4bf21fa4 1460 return -EFAULT;
8fa07567 1461
4bf21fa4
BP
1462 down(&this_usbduxsub->sem);
1463 if (!(this_usbduxsub->probed)) {
1464 up(&this_usbduxsub->sem);
1465 return -ENODEV;
1466 }
1467 if (trignum != 0) {
c0e0c26e
GKH
1468 dev_err(&this_usbduxsub->interface->dev,
1469 "comedi%d: usbdux_ao_inttrig: invalid trignum\n",
4bf21fa4
BP
1470 dev->minor);
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) */
e54fb9c1
GKH
1521 /* start immidiately a new scan */
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
e54fb9c1 1531 /* scanning is continous */
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
GKH
1535 /*
1536 * in usb-2.0 only one conversion it tranmitted but with 8kHz/n
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
e54fb9c1 1651 /* set current channel of the running aquisition 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) {
e54fb9c1
GKH
1700 /* not continous */
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 {
e54fb9c1 1714 /* continous aquisition */
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 if (insn->n != 2)
1784 return -EINVAL;
1785
1786 down(&this_usbduxsub->sem);
1787
1788 if (!(this_usbduxsub->probed)) {
1789 up(&this_usbduxsub->sem);
1790 return -ENODEV;
1791 }
1792
1793 /* The insn data is a mask in data[0] and the new data
1794 * in data[1], each channel cooresponding to a bit. */
1795 s->state &= ~data[0];
1796 s->state |= data[0] & data[1];
1797 this_usbduxsub->dux_commands[1] = s->io_bits;
1798 this_usbduxsub->dux_commands[2] = s->state;
1799
e54fb9c1
GKH
1800 /* This command also tells the firmware to return */
1801 /* the digital input lines */
4274ea02
GKH
1802 err = send_dux_commands(this_usbduxsub, SENDDIOBITSCOMMAND);
1803 if (err < 0) {
4bf21fa4
BP
1804 up(&this_usbduxsub->sem);
1805 return err;
1806 }
4274ea02
GKH
1807 err = receive_dux_commands(this_usbduxsub, SENDDIOBITSCOMMAND);
1808 if (err < 0) {
4bf21fa4
BP
1809 up(&this_usbduxsub->sem);
1810 return err;
1811 }
1812
1813 data[1] = le16_to_cpu(this_usbduxsub->insnBuffer[1]);
1814 up(&this_usbduxsub->sem);
1815 return 2;
1816}
1817
8fa07567 1818/* reads the 4 counters, only two are used just now */
0a85b6f0
MT
1819static int usbdux_counter_read(struct comedi_device *dev,
1820 struct comedi_subdevice *s,
90035c08 1821 struct comedi_insn *insn, unsigned int *data)
4bf21fa4 1822{
cc92fca7 1823 struct usbduxsub *this_usbduxsub = dev->private;
4bf21fa4
BP
1824 int chan = insn->chanspec;
1825 int err;
1826
8fa07567 1827 if (!this_usbduxsub)
4bf21fa4 1828 return -EFAULT;
4bf21fa4
BP
1829
1830 down(&this_usbduxsub->sem);
1831
1832 if (!(this_usbduxsub->probed)) {
1833 up(&this_usbduxsub->sem);
1834 return -ENODEV;
1835 }
1836
4274ea02
GKH
1837 err = send_dux_commands(this_usbduxsub, READCOUNTERCOMMAND);
1838 if (err < 0) {
4bf21fa4
BP
1839 up(&this_usbduxsub->sem);
1840 return err;
1841 }
1842
4274ea02
GKH
1843 err = receive_dux_commands(this_usbduxsub, READCOUNTERCOMMAND);
1844 if (err < 0) {
4bf21fa4
BP
1845 up(&this_usbduxsub->sem);
1846 return err;
1847 }
1848
1849 data[0] = le16_to_cpu(this_usbduxsub->insnBuffer[chan + 1]);
1850 up(&this_usbduxsub->sem);
1851 return 1;
1852}
1853
0a85b6f0
MT
1854static int usbdux_counter_write(struct comedi_device *dev,
1855 struct comedi_subdevice *s,
90035c08 1856 struct comedi_insn *insn, unsigned int *data)
4bf21fa4 1857{
cc92fca7 1858 struct usbduxsub *this_usbduxsub = dev->private;
4bf21fa4
BP
1859 int err;
1860
8fa07567 1861 if (!this_usbduxsub)
4bf21fa4 1862 return -EFAULT;
4bf21fa4
BP
1863
1864 down(&this_usbduxsub->sem);
1865
1866 if (!(this_usbduxsub->probed)) {
1867 up(&this_usbduxsub->sem);
1868 return -ENODEV;
1869 }
1870
1871 this_usbduxsub->dux_commands[1] = insn->chanspec;
1872 *((int16_t *) (this_usbduxsub->dux_commands + 2)) = cpu_to_le16(*data);
1873
4274ea02
GKH
1874 err = send_dux_commands(this_usbduxsub, WRITECOUNTERCOMMAND);
1875 if (err < 0) {
4bf21fa4
BP
1876 up(&this_usbduxsub->sem);
1877 return err;
1878 }
1879
1880 up(&this_usbduxsub->sem);
1881
1882 return 1;
1883}
1884
0a85b6f0
MT
1885static int usbdux_counter_config(struct comedi_device *dev,
1886 struct comedi_subdevice *s,
90035c08 1887 struct comedi_insn *insn, unsigned int *data)
4bf21fa4 1888{
e54fb9c1 1889 /* nothing to do so far */
4bf21fa4
BP
1890 return 2;
1891}
1892
e54fb9c1
GKH
1893/***********************************/
1894/* PWM */
4bf21fa4 1895
cc92fca7 1896static int usbduxsub_unlink_PwmURBs(struct usbduxsub *usbduxsub_tmp)
4bf21fa4 1897{
4bf21fa4
BP
1898 int err = 0;
1899
1900 if (usbduxsub_tmp && usbduxsub_tmp->urbPwm) {
4398ecfa 1901 if (usbduxsub_tmp->urbPwm)
4bf21fa4 1902 usb_kill_urb(usbduxsub_tmp->urbPwm);
c0e0c26e
GKH
1903 dev_dbg(&usbduxsub_tmp->interface->dev,
1904 "comedi: unlinked PwmURB: res=%d\n", err);
4bf21fa4
BP
1905 }
1906 return err;
1907}
1908
1909/* This cancels a running acquisition operation
1910 * in any context.
1911 */
cc92fca7 1912static int usbdux_pwm_stop(struct usbduxsub *this_usbduxsub, int do_unlink)
4bf21fa4
BP
1913{
1914 int ret = 0;
1915
c0e0c26e 1916 if (!this_usbduxsub)
4bf21fa4 1917 return -EFAULT;
c0e0c26e
GKH
1918
1919 dev_dbg(&this_usbduxsub->interface->dev, "comedi: %s\n", __func__);
8fa07567 1920 if (do_unlink)
4bf21fa4 1921 ret = usbduxsub_unlink_PwmURBs(this_usbduxsub);
8fa07567 1922
4bf21fa4
BP
1923 this_usbduxsub->pwm_cmd_running = 0;
1924
1925 return ret;
1926}
1927
8fa07567 1928/* force unlink - is called by comedi */
0a85b6f0
MT
1929static int usbdux_pwm_cancel(struct comedi_device *dev,
1930 struct comedi_subdevice *s)
4bf21fa4 1931{
cc92fca7 1932 struct usbduxsub *this_usbduxsub = dev->private;
4bf21fa4
BP
1933 int res = 0;
1934
8fa07567 1935 /* unlink only if it is really running */
4bf21fa4
BP
1936 res = usbdux_pwm_stop(this_usbduxsub, this_usbduxsub->pwm_cmd_running);
1937
c0e0c26e
GKH
1938 dev_dbg(&this_usbduxsub->interface->dev,
1939 "comedi %d: sending pwm off command to the usb device.\n",
4bf21fa4 1940 dev->minor);
4274ea02
GKH
1941 res = send_dux_commands(this_usbduxsub, SENDPWMOFF);
1942 if (res < 0)
4bf21fa4 1943 return res;
4bf21fa4
BP
1944
1945 return res;
1946}
1947
4bf21fa4
BP
1948static void usbduxsub_pwm_irq(struct urb *urb)
1949{
4bf21fa4 1950 int ret;
cc92fca7 1951 struct usbduxsub *this_usbduxsub;
71b5f4f1 1952 struct comedi_device *this_comedidev;
34c43922 1953 struct comedi_subdevice *s;
4bf21fa4 1954
c0e0c26e 1955 /* printk(KERN_DEBUG "PWM: IRQ\n"); */
4bf21fa4 1956
e54fb9c1 1957 /* the context variable points to the subdevice */
4bf21fa4 1958 this_comedidev = urb->context;
cc92fca7 1959 /* the private structure of the subdevice is struct usbduxsub */
4bf21fa4 1960 this_usbduxsub = this_comedidev->private;
4bf21fa4
BP
1961
1962 s = this_comedidev->subdevices + SUBDEV_DA;
1963
1964 switch (urb->status) {
1965 case 0:
1966 /* success */
1967 break;
1968
4bf21fa4
BP
1969 case -ECONNRESET:
1970 case -ENOENT:
1971 case -ESHUTDOWN:
1972 case -ECONNABORTED:
8fa07567
GKH
1973 /*
1974 * after an unlink command, unplug, ... etc
1975 * no unlink needed here. Already shutting down.
1976 */
1977 if (this_usbduxsub->pwm_cmd_running)
4bf21fa4 1978 usbdux_pwm_stop(this_usbduxsub, 0);
8fa07567 1979
4bf21fa4
BP
1980 return;
1981
4bf21fa4 1982 default:
8fa07567 1983 /* a real error */
4bf21fa4 1984 if (this_usbduxsub->pwm_cmd_running) {
c0e0c26e
GKH
1985 dev_err(&this_usbduxsub->interface->dev,
1986 "comedi_: Non-zero urb status received in "
1987 "pwm intr context: %d\n", urb->status);
4bf21fa4
BP
1988 usbdux_pwm_stop(this_usbduxsub, 0);
1989 }
1990 return;
1991 }
1992
8fa07567
GKH
1993 /* are we actually running? */
1994 if (!(this_usbduxsub->pwm_cmd_running))
4bf21fa4 1995 return;
4bf21fa4
BP
1996
1997 urb->transfer_buffer_length = this_usbduxsub->sizePwmBuf;
1998 urb->dev = this_usbduxsub->usbdev;
1999 urb->status = 0;
2000 if (this_usbduxsub->pwm_cmd_running) {
4aa3a823 2001 ret = usb_submit_urb(urb, GFP_ATOMIC);
4274ea02 2002 if (ret < 0) {
c0e0c26e
GKH
2003 dev_err(&this_usbduxsub->interface->dev,
2004 "comedi_: pwm urb resubm failed in int-cont. "
2005 "ret=%d", ret);
8fa07567 2006 if (ret == EL2NSYNC)
c0e0c26e
GKH
2007 dev_err(&this_usbduxsub->interface->dev,
2008 "buggy USB host controller or bug in "
2009 "IRQ handling!\n");
8fa07567
GKH
2010
2011 /* don't do an unlink here */
4bf21fa4
BP
2012 usbdux_pwm_stop(this_usbduxsub, 0);
2013 }
2014 }
2015}
2016
cc92fca7 2017static int usbduxsub_submit_PwmURBs(struct usbduxsub *usbduxsub)
4bf21fa4
BP
2018{
2019 int errFlag;
2020
8fa07567 2021 if (!usbduxsub)
4bf21fa4 2022 return -EFAULT;
8fa07567 2023
c0e0c26e 2024 dev_dbg(&usbduxsub->interface->dev, "comedi_: submitting pwm-urb\n");
4bf21fa4 2025
c0e0c26e 2026 /* in case of a resubmission after an unlink... */
4bf21fa4 2027 usb_fill_bulk_urb(usbduxsub->urbPwm,
0a85b6f0
MT
2028 usbduxsub->usbdev,
2029 usb_sndbulkpipe(usbduxsub->usbdev, PWM_EP),
2030 usbduxsub->urbPwm->transfer_buffer,
2031 usbduxsub->sizePwmBuf, usbduxsub_pwm_irq,
2032 usbduxsub->comedidev);
4bf21fa4 2033
4aa3a823 2034 errFlag = usb_submit_urb(usbduxsub->urbPwm, GFP_ATOMIC);
4bf21fa4 2035 if (errFlag) {
c0e0c26e 2036 dev_err(&usbduxsub->interface->dev,
4aa3a823 2037 "comedi_: usbdux: pwm: usb_submit_urb error %d\n",
c0e0c26e 2038 errFlag);
4bf21fa4
BP
2039 return errFlag;
2040 }
2041 return 0;
2042}
2043
0a85b6f0
MT
2044static int usbdux_pwm_period(struct comedi_device *dev,
2045 struct comedi_subdevice *s, unsigned int period)
4bf21fa4 2046{
cc92fca7 2047 struct usbduxsub *this_usbduxsub = dev->private;
8fa07567
GKH
2048 int fx2delay = 255;
2049
2050 if (period < MIN_PWM_PERIOD) {
c0e0c26e
GKH
2051 dev_err(&this_usbduxsub->interface->dev,
2052 "comedi%d: illegal period setting for pwm.\n",
2053 dev->minor);
4bf21fa4
BP
2054 return -EAGAIN;
2055 } else {
0a85b6f0 2056 fx2delay = period / ((int)(6 * 512 * (1.0 / 0.033))) - 6;
4bf21fa4 2057 if (fx2delay > 255) {
c0e0c26e
GKH
2058 dev_err(&this_usbduxsub->interface->dev,
2059 "comedi%d: period %d for pwm is too low.\n",
0a85b6f0 2060 dev->minor, period);
4bf21fa4
BP
2061 return -EAGAIN;
2062 }
2063 }
8fa07567
GKH
2064 this_usbduxsub->pwmDelay = fx2delay;
2065 this_usbduxsub->pwmPeriod = period;
c0e0c26e
GKH
2066 dev_dbg(&this_usbduxsub->interface->dev, "%s: frequ=%d, period=%d\n",
2067 __func__, period, fx2delay);
4bf21fa4
BP
2068 return 0;
2069}
2070
e54fb9c1 2071/* is called from insn so there's no need to do all the sanity checks */
0a85b6f0
MT
2072static int usbdux_pwm_start(struct comedi_device *dev,
2073 struct comedi_subdevice *s)
4bf21fa4
BP
2074{
2075 int ret, i;
cc92fca7 2076 struct usbduxsub *this_usbduxsub = dev->private;
4bf21fa4 2077
c0e0c26e
GKH
2078 dev_dbg(&this_usbduxsub->interface->dev, "comedi%d: %s\n",
2079 dev->minor, __func__);
2080
4bf21fa4 2081 if (this_usbduxsub->pwm_cmd_running) {
e54fb9c1 2082 /* already running */
4bf21fa4
BP
2083 return 0;
2084 }
2085
2086 this_usbduxsub->dux_commands[1] = ((int8_t) this_usbduxsub->pwmDelay);
4274ea02
GKH
2087 ret = send_dux_commands(this_usbduxsub, SENDPWMON);
2088 if (ret < 0)
4bf21fa4 2089 return ret;
4274ea02 2090
e54fb9c1 2091 /* initalise the buffer */
4274ea02 2092 for (i = 0; i < this_usbduxsub->sizePwmBuf; i++)
4bf21fa4 2093 ((char *)(this_usbduxsub->urbPwm->transfer_buffer))[i] = 0;
4bf21fa4
BP
2094
2095 this_usbduxsub->pwm_cmd_running = 1;
2096 ret = usbduxsub_submit_PwmURBs(this_usbduxsub);
2097 if (ret < 0) {
2098 this_usbduxsub->pwm_cmd_running = 0;
2099 return ret;
2100 }
2101 return 0;
2102}
2103
e54fb9c1 2104/* generates the bit pattern for PWM with the optional sign bit */
0a85b6f0
MT
2105static int usbdux_pwm_pattern(struct comedi_device *dev,
2106 struct comedi_subdevice *s, int channel,
2107 unsigned int value, unsigned int sign)
4bf21fa4 2108{
cc92fca7 2109 struct usbduxsub *this_usbduxsub = dev->private;
4bf21fa4
BP
2110 int i, szbuf;
2111 char *pBuf;
4274ea02
GKH
2112 char pwm_mask;
2113 char sgn_mask;
2114 char c;
4bf21fa4 2115
4274ea02 2116 if (!this_usbduxsub)
4bf21fa4 2117 return -EFAULT;
4274ea02 2118
e54fb9c1 2119 /* this is the DIO bit which carries the PWM data */
4bf21fa4 2120 pwm_mask = (1 << channel);
e54fb9c1 2121 /* this is the DIO bit which carries the optional direction bit */
4bf21fa4 2122 sgn_mask = (16 << channel);
e54fb9c1
GKH
2123 /* this is the buffer which will be filled with the with bit */
2124 /* pattern for one period */
4bf21fa4
BP
2125 szbuf = this_usbduxsub->sizePwmBuf;
2126 pBuf = (char *)(this_usbduxsub->urbPwm->transfer_buffer);
2127 for (i = 0; i < szbuf; i++) {
2128 c = *pBuf;
e54fb9c1 2129 /* reset bits */
4bf21fa4 2130 c = c & (~pwm_mask);
e54fb9c1 2131 /* set the bit as long as the index is lower than the value */
4bf21fa4
BP
2132 if (i < value)
2133 c = c | pwm_mask;
e54fb9c1 2134 /* set the optional sign bit for a relay */
4bf21fa4 2135 if (!sign) {
e54fb9c1 2136 /* positive value */
4bf21fa4
BP
2137 c = c & (~sgn_mask);
2138 } else {
e54fb9c1 2139 /* negative value */
4bf21fa4
BP
2140 c = c | sgn_mask;
2141 }
2142 *(pBuf++) = c;
2143 }
2144 return 1;
2145}
2146
0a85b6f0
MT
2147static int usbdux_pwm_write(struct comedi_device *dev,
2148 struct comedi_subdevice *s,
90035c08 2149 struct comedi_insn *insn, unsigned int *data)
4bf21fa4 2150{
cc92fca7 2151 struct usbduxsub *this_usbduxsub = dev->private;
4bf21fa4 2152
4274ea02 2153 if (!this_usbduxsub)
4bf21fa4 2154 return -EFAULT;
4bf21fa4 2155
4274ea02
GKH
2156 if ((insn->n) != 1) {
2157 /*
2158 * doesn't make sense to have more than one value here because
2159 * it would just overwrite the PWM buffer a couple of times
2160 */
4bf21fa4
BP
2161 return -EINVAL;
2162 }
2163
4274ea02
GKH
2164 /*
2165 * the sign is set via a special INSN only, this gives us 8 bits for
2166 * normal operation
2167 * relay sign 0 by default
2168 */
0a85b6f0 2169 return usbdux_pwm_pattern(dev, s, CR_CHAN(insn->chanspec), data[0], 0);
4bf21fa4
BP
2170}
2171
0a85b6f0
MT
2172static int usbdux_pwm_read(struct comedi_device *x1,
2173 struct comedi_subdevice *x2, struct comedi_insn *x3,
2174 unsigned int *x4)
4bf21fa4 2175{
8fa07567 2176 /* not needed */
4bf21fa4
BP
2177 return -EINVAL;
2178};
2179
8fa07567 2180/* switches on/off PWM */
0a85b6f0
MT
2181static int usbdux_pwm_config(struct comedi_device *dev,
2182 struct comedi_subdevice *s,
90035c08 2183 struct comedi_insn *insn, unsigned int *data)
4bf21fa4 2184{
cc92fca7 2185 struct usbduxsub *this_usbduxsub = dev->private;
4bf21fa4
BP
2186 switch (data[0]) {
2187 case INSN_CONFIG_ARM:
8fa07567 2188 /* switch it on */
c0e0c26e
GKH
2189 dev_dbg(&this_usbduxsub->interface->dev,
2190 "comedi%d: %s: pwm on\n", dev->minor, __func__);
8fa07567
GKH
2191 /*
2192 * if not zero the PWM is limited to a certain time which is
2193 * not supported here
2194 */
2195 if (data[1] != 0)
4bf21fa4 2196 return -EINVAL;
4bf21fa4
BP
2197 return usbdux_pwm_start(dev, s);
2198 case INSN_CONFIG_DISARM:
c0e0c26e
GKH
2199 dev_dbg(&this_usbduxsub->interface->dev,
2200 "comedi%d: %s: pwm off\n", dev->minor, __func__);
4bf21fa4
BP
2201 return usbdux_pwm_cancel(dev, s);
2202 case INSN_CONFIG_GET_PWM_STATUS:
8fa07567
GKH
2203 /*
2204 * to check if the USB transmission has failed or in case PWM
2205 * was limited to n cycles to check if it has terminated
2206 */
4bf21fa4
BP
2207 data[1] = this_usbduxsub->pwm_cmd_running;
2208 return 0;
2209 case INSN_CONFIG_PWM_SET_PERIOD:
c0e0c26e
GKH
2210 dev_dbg(&this_usbduxsub->interface->dev,
2211 "comedi%d: %s: setting period\n", dev->minor, __func__);
8fa07567 2212 return usbdux_pwm_period(dev, s, data[1]);
4bf21fa4
BP
2213 case INSN_CONFIG_PWM_GET_PERIOD:
2214 data[1] = this_usbduxsub->pwmPeriod;
2215 return 0;
2216 case INSN_CONFIG_PWM_SET_H_BRIDGE:
8fa07567
GKH
2217 /* value in the first byte and the sign in the second for a
2218 relay */
4bf21fa4 2219 return usbdux_pwm_pattern(dev, s,
8fa07567
GKH
2220 /* the channel number */
2221 CR_CHAN(insn->chanspec),
2222 /* actual PWM data */
2223 data[1],
2224 /* just a sign */
2225 (data[2] != 0));
4bf21fa4 2226 case INSN_CONFIG_PWM_GET_H_BRIDGE:
8fa07567 2227 /* values are not kept in this driver, nothing to return here */
4bf21fa4
BP
2228 return -EINVAL;
2229 }
2230 return -EINVAL;
2231}
2232
8fa07567
GKH
2233/* end of PWM */
2234/*****************************************************************/
4bf21fa4 2235
cc92fca7 2236static void tidy_up(struct usbduxsub *usbduxsub_tmp)
4bf21fa4
BP
2237{
2238 int i;
2239
8fa07567 2240 if (!usbduxsub_tmp)
4bf21fa4 2241 return;
c0e0c26e 2242 dev_dbg(&usbduxsub_tmp->interface->dev, "comedi_: tiding up\n");
8fa07567
GKH
2243
2244 /* shows the usb subsystem that the driver is down */
4398ecfa 2245 if (usbduxsub_tmp->interface)
4bf21fa4 2246 usb_set_intfdata(usbduxsub_tmp->interface, NULL);
4bf21fa4
BP
2247
2248 usbduxsub_tmp->probed = 0;
2249
2250 if (usbduxsub_tmp->urbIn) {
2251 if (usbduxsub_tmp->ai_cmd_running) {
2252 usbduxsub_tmp->ai_cmd_running = 0;
2253 usbduxsub_unlink_InURBs(usbduxsub_tmp);
2254 }
2255 for (i = 0; i < usbduxsub_tmp->numOfInBuffers; i++) {
4274ea02
GKH
2256 kfree(usbduxsub_tmp->urbIn[i]->transfer_buffer);
2257 usbduxsub_tmp->urbIn[i]->transfer_buffer = NULL;
2258 usb_kill_urb(usbduxsub_tmp->urbIn[i]);
2259 usb_free_urb(usbduxsub_tmp->urbIn[i]);
2260 usbduxsub_tmp->urbIn[i] = NULL;
4bf21fa4
BP
2261 }
2262 kfree(usbduxsub_tmp->urbIn);
2263 usbduxsub_tmp->urbIn = NULL;
2264 }
2265 if (usbduxsub_tmp->urbOut) {
2266 if (usbduxsub_tmp->ao_cmd_running) {
2267 usbduxsub_tmp->ao_cmd_running = 0;
2268 usbduxsub_unlink_OutURBs(usbduxsub_tmp);
2269 }
2270 for (i = 0; i < usbduxsub_tmp->numOfOutBuffers; i++) {
2271 if (usbduxsub_tmp->urbOut[i]->transfer_buffer) {
0a85b6f0
MT
2272 kfree(usbduxsub_tmp->
2273 urbOut[i]->transfer_buffer);
4bf21fa4 2274 usbduxsub_tmp->urbOut[i]->transfer_buffer =
0a85b6f0 2275 NULL;
4bf21fa4
BP
2276 }
2277 if (usbduxsub_tmp->urbOut[i]) {
4bf21fa4 2278 usb_kill_urb(usbduxsub_tmp->urbOut[i]);
4bf21fa4
BP
2279 usb_free_urb(usbduxsub_tmp->urbOut[i]);
2280 usbduxsub_tmp->urbOut[i] = NULL;
2281 }
2282 }
2283 kfree(usbduxsub_tmp->urbOut);
2284 usbduxsub_tmp->urbOut = NULL;
2285 }
2286 if (usbduxsub_tmp->urbPwm) {
2287 if (usbduxsub_tmp->pwm_cmd_running) {
2288 usbduxsub_tmp->pwm_cmd_running = 0;
2289 usbduxsub_unlink_PwmURBs(usbduxsub_tmp);
2290 }
8fa07567
GKH
2291 kfree(usbduxsub_tmp->urbPwm->transfer_buffer);
2292 usbduxsub_tmp->urbPwm->transfer_buffer = NULL;
4bf21fa4 2293 usb_kill_urb(usbduxsub_tmp->urbPwm);
4bf21fa4
BP
2294 usb_free_urb(usbduxsub_tmp->urbPwm);
2295 usbduxsub_tmp->urbPwm = NULL;
2296 }
8fa07567
GKH
2297 kfree(usbduxsub_tmp->inBuffer);
2298 usbduxsub_tmp->inBuffer = NULL;
2299 kfree(usbduxsub_tmp->insnBuffer);
2300 usbduxsub_tmp->insnBuffer = NULL;
2301 kfree(usbduxsub_tmp->inBuffer);
2302 usbduxsub_tmp->inBuffer = NULL;
2303 kfree(usbduxsub_tmp->dac_commands);
2304 usbduxsub_tmp->dac_commands = NULL;
2305 kfree(usbduxsub_tmp->dux_commands);
2306 usbduxsub_tmp->dux_commands = NULL;
4bf21fa4
BP
2307 usbduxsub_tmp->ai_cmd_running = 0;
2308 usbduxsub_tmp->ao_cmd_running = 0;
2309 usbduxsub_tmp->pwm_cmd_running = 0;
2310}
2311
6742c0af
BP
2312static void usbdux_firmware_request_complete_handler(const struct firmware *fw,
2313 void *context)
2314{
2315 struct usbduxsub *usbduxsub_tmp = context;
2316 struct usb_device *usbdev = usbduxsub_tmp->usbdev;
2317 int ret;
2318
2319 if (fw == NULL) {
2320 dev_err(&usbdev->dev,
2321 "Firmware complete handler without firmware!\n");
2322 return;
2323 }
2324
2325 /*
2326 * we need to upload the firmware here because fw will be
2327 * freed once we've left this function
2328 */
81874ff7 2329 ret = firmwareUpload(usbduxsub_tmp, fw->data, fw->size);
6742c0af
BP
2330
2331 if (ret) {
2332 dev_err(&usbdev->dev,
0a85b6f0 2333 "Could not upload firmware (err=%d)\n", ret);
9ebfbd45 2334 goto out;
6742c0af
BP
2335 }
2336 comedi_usb_auto_config(usbdev, BOARDNAME);
9ebfbd45
JB
2337 out:
2338 release_firmware(fw);
6742c0af
BP
2339}
2340
e54fb9c1 2341/* allocate memory for the urbs and initialise them */
4bf21fa4 2342static int usbduxsub_probe(struct usb_interface *uinterf,
c0e0c26e 2343 const struct usb_device_id *id)
4bf21fa4
BP
2344{
2345 struct usb_device *udev = interface_to_usbdev(uinterf);
c0e0c26e 2346 struct device *dev = &uinterf->dev;
4bf21fa4
BP
2347 int i;
2348 int index;
6742c0af 2349 int ret;
4bf21fa4 2350
c0e0c26e
GKH
2351 dev_dbg(dev, "comedi_: usbdux_: "
2352 "finding a free structure for the usb-device\n");
2353
4bf21fa4 2354 down(&start_stop_sem);
e54fb9c1 2355 /* look for a free place in the usbdux array */
4bf21fa4
BP
2356 index = -1;
2357 for (i = 0; i < NUMUSBDUX; i++) {
2358 if (!(usbduxsub[i].probed)) {
2359 index = i;
2360 break;
2361 }
2362 }
2363
e54fb9c1 2364 /* no more space */
4bf21fa4 2365 if (index == -1) {
c0e0c26e 2366 dev_err(dev, "Too many usbdux-devices connected.\n");
4bf21fa4 2367 up(&start_stop_sem);
4aa3a823 2368 return -EMFILE;
4bf21fa4 2369 }
c0e0c26e
GKH
2370 dev_dbg(dev, "comedi_: usbdux: "
2371 "usbduxsub[%d] is ready to connect to comedi.\n", index);
4bf21fa4
BP
2372
2373 init_MUTEX(&(usbduxsub[index].sem));
e54fb9c1 2374 /* save a pointer to the usb device */
4bf21fa4
BP
2375 usbduxsub[index].usbdev = udev;
2376
e54fb9c1 2377 /* 2.6: save the interface itself */
4bf21fa4 2378 usbduxsub[index].interface = uinterf;
e54fb9c1 2379 /* get the interface number from the interface */
4bf21fa4 2380 usbduxsub[index].ifnum = uinterf->altsetting->desc.bInterfaceNumber;
e54fb9c1
GKH
2381 /* hand the private data over to the usb subsystem */
2382 /* will be needed for disconnect */
4bf21fa4 2383 usb_set_intfdata(uinterf, &(usbduxsub[index]));
4bf21fa4 2384
c0e0c26e
GKH
2385 dev_dbg(dev, "comedi_: usbdux: ifnum=%d\n", usbduxsub[index].ifnum);
2386
e54fb9c1 2387 /* test if it is high speed (USB 2.0) */
4bf21fa4 2388 usbduxsub[index].high_speed =
0a85b6f0 2389 (usbduxsub[index].usbdev->speed == USB_SPEED_HIGH);
4bf21fa4 2390
e54fb9c1 2391 /* create space for the commands of the DA converter */
4bf21fa4
BP
2392 usbduxsub[index].dac_commands = kzalloc(NUMOUTCHANNELS, GFP_KERNEL);
2393 if (!usbduxsub[index].dac_commands) {
c0e0c26e
GKH
2394 dev_err(dev, "comedi_: usbdux: "
2395 "error alloc space for dac commands\n");
4bf21fa4
BP
2396 tidy_up(&(usbduxsub[index]));
2397 up(&start_stop_sem);
4aa3a823 2398 return -ENOMEM;
4bf21fa4 2399 }
e54fb9c1 2400 /* create space for the commands going to the usb device */
4bf21fa4
BP
2401 usbduxsub[index].dux_commands = kzalloc(SIZEOFDUXBUFFER, GFP_KERNEL);
2402 if (!usbduxsub[index].dux_commands) {
c0e0c26e
GKH
2403 dev_err(dev, "comedi_: usbdux: "
2404 "error alloc space for dac commands\n");
4bf21fa4
BP
2405 tidy_up(&(usbduxsub[index]));
2406 up(&start_stop_sem);
4aa3a823 2407 return -ENOMEM;
4bf21fa4 2408 }
e54fb9c1 2409 /* create space for the in buffer and set it to zero */
4bf21fa4
BP
2410 usbduxsub[index].inBuffer = kzalloc(SIZEINBUF, GFP_KERNEL);
2411 if (!(usbduxsub[index].inBuffer)) {
c0e0c26e
GKH
2412 dev_err(dev, "comedi_: usbdux: "
2413 "could not alloc space for inBuffer\n");
4bf21fa4
BP
2414 tidy_up(&(usbduxsub[index]));
2415 up(&start_stop_sem);
4aa3a823 2416 return -ENOMEM;
4bf21fa4 2417 }
e54fb9c1 2418 /* create space of the instruction buffer */
4bf21fa4
BP
2419 usbduxsub[index].insnBuffer = kzalloc(SIZEINSNBUF, GFP_KERNEL);
2420 if (!(usbduxsub[index].insnBuffer)) {
c0e0c26e
GKH
2421 dev_err(dev, "comedi_: usbdux: "
2422 "could not alloc space for insnBuffer\n");
4bf21fa4
BP
2423 tidy_up(&(usbduxsub[index]));
2424 up(&start_stop_sem);
4aa3a823 2425 return -ENOMEM;
4bf21fa4 2426 }
e54fb9c1 2427 /* create space for the outbuffer */
4bf21fa4
BP
2428 usbduxsub[index].outBuffer = kzalloc(SIZEOUTBUF, GFP_KERNEL);
2429 if (!(usbduxsub[index].outBuffer)) {
c0e0c26e
GKH
2430 dev_err(dev, "comedi_: usbdux: "
2431 "could not alloc space for outBuffer\n");
4bf21fa4
BP
2432 tidy_up(&(usbduxsub[index]));
2433 up(&start_stop_sem);
4aa3a823 2434 return -ENOMEM;
4bf21fa4 2435 }
8fa07567 2436 /* setting to alternate setting 3: enabling iso ep and bulk ep. */
4bf21fa4 2437 i = usb_set_interface(usbduxsub[index].usbdev,
8fa07567 2438 usbduxsub[index].ifnum, 3);
4bf21fa4 2439 if (i < 0) {
c0e0c26e
GKH
2440 dev_err(dev, "comedi_: usbdux%d: "
2441 "could not set alternate setting 3 in high speed.\n",
2442 index);
4bf21fa4
BP
2443 tidy_up(&(usbduxsub[index]));
2444 up(&start_stop_sem);
4aa3a823 2445 return -ENODEV;
4bf21fa4 2446 }
8fa07567 2447 if (usbduxsub[index].high_speed)
4bf21fa4 2448 usbduxsub[index].numOfInBuffers = NUMOFINBUFFERSHIGH;
8fa07567 2449 else
4bf21fa4 2450 usbduxsub[index].numOfInBuffers = NUMOFINBUFFERSFULL;
8fa07567 2451
4bf21fa4 2452 usbduxsub[index].urbIn =
0a85b6f0
MT
2453 kzalloc(sizeof(struct urb *) * usbduxsub[index].numOfInBuffers,
2454 GFP_KERNEL);
4bf21fa4 2455 if (!(usbduxsub[index].urbIn)) {
c0e0c26e 2456 dev_err(dev, "comedi_: usbdux: Could not alloc. urbIn array\n");
4bf21fa4
BP
2457 tidy_up(&(usbduxsub[index]));
2458 up(&start_stop_sem);
4aa3a823 2459 return -ENOMEM;
4bf21fa4
BP
2460 }
2461 for (i = 0; i < usbduxsub[index].numOfInBuffers; i++) {
e54fb9c1 2462 /* one frame: 1ms */
4aa3a823 2463 usbduxsub[index].urbIn[i] = usb_alloc_urb(1, GFP_KERNEL);
4bf21fa4 2464 if (usbduxsub[index].urbIn[i] == NULL) {
c0e0c26e
GKH
2465 dev_err(dev, "comedi_: usbdux%d: "
2466 "Could not alloc. urb(%d)\n", index, i);
4bf21fa4
BP
2467 tidy_up(&(usbduxsub[index]));
2468 up(&start_stop_sem);
4aa3a823 2469 return -ENOMEM;
4bf21fa4
BP
2470 }
2471 usbduxsub[index].urbIn[i]->dev = usbduxsub[index].usbdev;
e54fb9c1
GKH
2472 /* will be filled later with a pointer to the comedi-device */
2473 /* and ONLY then the urb should be submitted */
4bf21fa4
BP
2474 usbduxsub[index].urbIn[i]->context = NULL;
2475 usbduxsub[index].urbIn[i]->pipe =
0a85b6f0 2476 usb_rcvisocpipe(usbduxsub[index].usbdev, ISOINEP);
4bf21fa4
BP
2477 usbduxsub[index].urbIn[i]->transfer_flags = URB_ISO_ASAP;
2478 usbduxsub[index].urbIn[i]->transfer_buffer =
0a85b6f0 2479 kzalloc(SIZEINBUF, GFP_KERNEL);
4bf21fa4 2480 if (!(usbduxsub[index].urbIn[i]->transfer_buffer)) {
c0e0c26e
GKH
2481 dev_err(dev, "comedi_: usbdux%d: "
2482 "could not alloc. transb.\n", index);
4bf21fa4
BP
2483 tidy_up(&(usbduxsub[index]));
2484 up(&start_stop_sem);
4aa3a823 2485 return -ENOMEM;
4bf21fa4
BP
2486 }
2487 usbduxsub[index].urbIn[i]->complete = usbduxsub_ai_IsocIrq;
2488 usbduxsub[index].urbIn[i]->number_of_packets = 1;
2489 usbduxsub[index].urbIn[i]->transfer_buffer_length = SIZEINBUF;
2490 usbduxsub[index].urbIn[i]->iso_frame_desc[0].offset = 0;
2491 usbduxsub[index].urbIn[i]->iso_frame_desc[0].length = SIZEINBUF;
2492 }
2493
8fa07567
GKH
2494 /* out */
2495 if (usbduxsub[index].high_speed)
4bf21fa4 2496 usbduxsub[index].numOfOutBuffers = NUMOFOUTBUFFERSHIGH;
8fa07567 2497 else
4bf21fa4 2498 usbduxsub[index].numOfOutBuffers = NUMOFOUTBUFFERSFULL;
8fa07567 2499
4bf21fa4 2500 usbduxsub[index].urbOut =
0a85b6f0
MT
2501 kzalloc(sizeof(struct urb *) * usbduxsub[index].numOfOutBuffers,
2502 GFP_KERNEL);
4bf21fa4 2503 if (!(usbduxsub[index].urbOut)) {
c0e0c26e
GKH
2504 dev_err(dev, "comedi_: usbdux: "
2505 "Could not alloc. urbOut array\n");
4bf21fa4
BP
2506 tidy_up(&(usbduxsub[index]));
2507 up(&start_stop_sem);
4aa3a823 2508 return -ENOMEM;
4bf21fa4
BP
2509 }
2510 for (i = 0; i < usbduxsub[index].numOfOutBuffers; i++) {
e54fb9c1 2511 /* one frame: 1ms */
4aa3a823 2512 usbduxsub[index].urbOut[i] = usb_alloc_urb(1, GFP_KERNEL);
4bf21fa4 2513 if (usbduxsub[index].urbOut[i] == NULL) {
c0e0c26e
GKH
2514 dev_err(dev, "comedi_: usbdux%d: "
2515 "Could not alloc. urb(%d)\n", index, i);
4bf21fa4
BP
2516 tidy_up(&(usbduxsub[index]));
2517 up(&start_stop_sem);
4aa3a823 2518 return -ENOMEM;
4bf21fa4
BP
2519 }
2520 usbduxsub[index].urbOut[i]->dev = usbduxsub[index].usbdev;
e54fb9c1
GKH
2521 /* will be filled later with a pointer to the comedi-device */
2522 /* and ONLY then the urb should be submitted */
4bf21fa4
BP
2523 usbduxsub[index].urbOut[i]->context = NULL;
2524 usbduxsub[index].urbOut[i]->pipe =
0a85b6f0 2525 usb_sndisocpipe(usbduxsub[index].usbdev, ISOOUTEP);
4bf21fa4
BP
2526 usbduxsub[index].urbOut[i]->transfer_flags = URB_ISO_ASAP;
2527 usbduxsub[index].urbOut[i]->transfer_buffer =
0a85b6f0 2528 kzalloc(SIZEOUTBUF, GFP_KERNEL);
4bf21fa4 2529 if (!(usbduxsub[index].urbOut[i]->transfer_buffer)) {
c0e0c26e
GKH
2530 dev_err(dev, "comedi_: usbdux%d: "
2531 "could not alloc. transb.\n", index);
4bf21fa4
BP
2532 tidy_up(&(usbduxsub[index]));
2533 up(&start_stop_sem);
4aa3a823 2534 return -ENOMEM;
4bf21fa4
BP
2535 }
2536 usbduxsub[index].urbOut[i]->complete = usbduxsub_ao_IsocIrq;
2537 usbduxsub[index].urbOut[i]->number_of_packets = 1;
2538 usbduxsub[index].urbOut[i]->transfer_buffer_length = SIZEOUTBUF;
2539 usbduxsub[index].urbOut[i]->iso_frame_desc[0].offset = 0;
2540 usbduxsub[index].urbOut[i]->iso_frame_desc[0].length =
0a85b6f0 2541 SIZEOUTBUF;
4bf21fa4 2542 if (usbduxsub[index].high_speed) {
e54fb9c1 2543 /* uframes */
4bf21fa4
BP
2544 usbduxsub[index].urbOut[i]->interval = 8;
2545 } else {
e54fb9c1 2546 /* frames */
4bf21fa4
BP
2547 usbduxsub[index].urbOut[i]->interval = 1;
2548 }
2549 }
2550
e54fb9c1 2551 /* pwm */
4bf21fa4 2552 if (usbduxsub[index].high_speed) {
4274ea02
GKH
2553 /* max bulk ep size in high speed */
2554 usbduxsub[index].sizePwmBuf = 512;
4aa3a823 2555 usbduxsub[index].urbPwm = usb_alloc_urb(0, GFP_KERNEL);
4bf21fa4 2556 if (usbduxsub[index].urbPwm == NULL) {
c0e0c26e
GKH
2557 dev_err(dev, "comedi_: usbdux%d: "
2558 "Could not alloc. pwm urb\n", index);
4bf21fa4
BP
2559 tidy_up(&(usbduxsub[index]));
2560 up(&start_stop_sem);
4aa3a823 2561 return -ENOMEM;
4bf21fa4
BP
2562 }
2563 usbduxsub[index].urbPwm->transfer_buffer =
0a85b6f0 2564 kzalloc(usbduxsub[index].sizePwmBuf, GFP_KERNEL);
4bf21fa4 2565 if (!(usbduxsub[index].urbPwm->transfer_buffer)) {
c0e0c26e
GKH
2566 dev_err(dev, "comedi_: usbdux%d: "
2567 "could not alloc. transb. for pwm\n", index);
4bf21fa4
BP
2568 tidy_up(&(usbduxsub[index]));
2569 up(&start_stop_sem);
4aa3a823 2570 return -ENOMEM;
4bf21fa4
BP
2571 }
2572 } else {
2573 usbduxsub[index].urbPwm = NULL;
2574 usbduxsub[index].sizePwmBuf = 0;
2575 }
2576
2577 usbduxsub[index].ai_cmd_running = 0;
2578 usbduxsub[index].ao_cmd_running = 0;
2579 usbduxsub[index].pwm_cmd_running = 0;
2580
e54fb9c1 2581 /* we've reached the bottom of the function */
4bf21fa4
BP
2582 usbduxsub[index].probed = 1;
2583 up(&start_stop_sem);
6742c0af
BP
2584
2585 ret = request_firmware_nowait(THIS_MODULE,
2586 FW_ACTION_HOTPLUG,
81874ff7 2587 "usbdux_firmware.bin",
6742c0af 2588 &udev->dev,
9ebfbd45 2589 GFP_KERNEL,
6742c0af
BP
2590 usbduxsub + index,
2591 usbdux_firmware_request_complete_handler);
2592
2593 if (ret) {
2594 dev_err(dev, "Could not load firmware (err=%d)\n", ret);
2595 return ret;
2596 }
2597
c0e0c26e
GKH
2598 dev_info(dev, "comedi_: usbdux%d "
2599 "has been successfully initialised.\n", index);
e54fb9c1 2600 /* success */
4bf21fa4 2601 return 0;
4bf21fa4
BP
2602}
2603
4bf21fa4
BP
2604static void usbduxsub_disconnect(struct usb_interface *intf)
2605{
cc92fca7 2606 struct usbduxsub *usbduxsub_tmp = usb_get_intfdata(intf);
4bf21fa4 2607 struct usb_device *udev = interface_to_usbdev(intf);
4398ecfa 2608
4bf21fa4 2609 if (!usbduxsub_tmp) {
c0e0c26e
GKH
2610 dev_err(&intf->dev,
2611 "comedi_: disconnect called with null pointer.\n");
4bf21fa4
BP
2612 return;
2613 }
2614 if (usbduxsub_tmp->usbdev != udev) {
0a85b6f0 2615 dev_err(&intf->dev, "comedi_: BUG! called with wrong ptr!!!\n");
4bf21fa4
BP
2616 return;
2617 }
6742c0af 2618 comedi_usb_auto_unconfig(udev);
4bf21fa4
BP
2619 down(&start_stop_sem);
2620 down(&usbduxsub_tmp->sem);
2621 tidy_up(usbduxsub_tmp);
2622 up(&usbduxsub_tmp->sem);
2623 up(&start_stop_sem);
c0e0c26e 2624 dev_dbg(&intf->dev, "comedi_: disconnected from the usb\n");
4bf21fa4
BP
2625}
2626
8fa07567 2627/* is called when comedi-config is called */
0707bb04 2628static int usbdux_attach(struct comedi_device *dev, struct comedi_devconfig *it)
4bf21fa4
BP
2629{
2630 int ret;
2631 int index;
2632 int i;
cc92fca7 2633 struct usbduxsub *udev;
c0e0c26e 2634
34c43922 2635 struct comedi_subdevice *s = NULL;
4bf21fa4
BP
2636 dev->private = NULL;
2637
2638 down(&start_stop_sem);
4274ea02
GKH
2639 /* find a valid device which has been detected by the probe function of
2640 * the usb */
4bf21fa4
BP
2641 index = -1;
2642 for (i = 0; i < NUMUSBDUX; i++) {
2643 if ((usbduxsub[i].probed) && (!usbduxsub[i].attached)) {
2644 index = i;
2645 break;
2646 }
2647 }
2648
2649 if (index < 0) {
c0e0c26e
GKH
2650 printk(KERN_ERR "comedi%d: usbdux: error: attach failed, no "
2651 "usbdux devs connected to the usb bus.\n", dev->minor);
4bf21fa4
BP
2652 up(&start_stop_sem);
2653 return -ENODEV;
2654 }
2655
c0e0c26e
GKH
2656 udev = &usbduxsub[index];
2657 down(&udev->sem);
e54fb9c1 2658 /* pointer back to the corresponding comedi device */
c0e0c26e 2659 udev->comedidev = dev;
4bf21fa4 2660
e54fb9c1 2661 /* trying to upload the firmware into the chip */
4bf21fa4 2662 if (comedi_aux_data(it->options, 0) &&
0a85b6f0 2663 it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
81874ff7
BP
2664 firmwareUpload(udev, comedi_aux_data(it->options, 0),
2665 it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]);
4bf21fa4
BP
2666 }
2667
2668 dev->board_name = BOARDNAME;
2669
2670 /* set number of subdevices */
c0e0c26e 2671 if (udev->high_speed) {
e54fb9c1 2672 /* with pwm */
4bf21fa4
BP
2673 dev->n_subdevices = 5;
2674 } else {
e54fb9c1 2675 /* without pwm */
4bf21fa4
BP
2676 dev->n_subdevices = 4;
2677 }
2678
e54fb9c1 2679 /* allocate space for the subdevices */
4274ea02
GKH
2680 ret = alloc_subdevices(dev, dev->n_subdevices);
2681 if (ret < 0) {
c0e0c26e
GKH
2682 dev_err(&udev->interface->dev,
2683 "comedi%d: error alloc space for subdev\n", dev->minor);
4bf21fa4
BP
2684 up(&start_stop_sem);
2685 return ret;
2686 }
2687
c0e0c26e 2688 dev_info(&udev->interface->dev,
0a85b6f0
MT
2689 "comedi%d: usb-device %d is attached to comedi.\n",
2690 dev->minor, index);
e54fb9c1 2691 /* private structure is also simply the usb-structure */
c0e0c26e 2692 dev->private = udev;
4bf21fa4 2693
e54fb9c1 2694 /* the first subdevice is the A/D converter */
4bf21fa4 2695 s = dev->subdevices + SUBDEV_AD;
e54fb9c1
GKH
2696 /* the URBs get the comedi subdevice */
2697 /* which is responsible for reading */
2698 /* this is the subdevice which reads data */
4bf21fa4 2699 dev->read_subdev = s;
e54fb9c1
GKH
2700 /* the subdevice receives as private structure the */
2701 /* usb-structure */
4bf21fa4 2702 s->private = NULL;
e54fb9c1 2703 /* analog input */
4bf21fa4 2704 s->type = COMEDI_SUBD_AI;
e54fb9c1 2705 /* readable and ref is to ground */
4bf21fa4 2706 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
e54fb9c1 2707 /* 8 channels */
4bf21fa4 2708 s->n_chan = 8;
e54fb9c1 2709 /* length of the channellist */
4bf21fa4 2710 s->len_chanlist = 8;
e54fb9c1 2711 /* callback functions */
4bf21fa4
BP
2712 s->insn_read = usbdux_ai_insn_read;
2713 s->do_cmdtest = usbdux_ai_cmdtest;
2714 s->do_cmd = usbdux_ai_cmd;
2715 s->cancel = usbdux_ai_cancel;
e54fb9c1 2716 /* max value from the A/D converter (12bit) */
4bf21fa4 2717 s->maxdata = 0xfff;
e54fb9c1 2718 /* range table to convert to physical units */
4bf21fa4 2719 s->range_table = (&range_usbdux_ai_range);
4bf21fa4 2720
e54fb9c1 2721 /* analog out */
4bf21fa4 2722 s = dev->subdevices + SUBDEV_DA;
e54fb9c1 2723 /* analog out */
4bf21fa4 2724 s->type = COMEDI_SUBD_AO;
e54fb9c1 2725 /* backward pointer */
4bf21fa4 2726 dev->write_subdev = s;
e54fb9c1
GKH
2727 /* the subdevice receives as private structure the */
2728 /* usb-structure */
4bf21fa4 2729 s->private = NULL;
e54fb9c1 2730 /* are writable */
4bf21fa4 2731 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
e54fb9c1 2732 /* 4 channels */
4bf21fa4 2733 s->n_chan = 4;
e54fb9c1 2734 /* length of the channellist */
4bf21fa4 2735 s->len_chanlist = 4;
e54fb9c1 2736 /* 12 bit resolution */
4bf21fa4 2737 s->maxdata = 0x0fff;
e54fb9c1 2738 /* bipolar range */
4bf21fa4 2739 s->range_table = (&range_usbdux_ao_range);
e54fb9c1 2740 /* callback */
4bf21fa4
BP
2741 s->do_cmdtest = usbdux_ao_cmdtest;
2742 s->do_cmd = usbdux_ao_cmd;
2743 s->cancel = usbdux_ao_cancel;
2744 s->insn_read = usbdux_ao_insn_read;
2745 s->insn_write = usbdux_ao_insn_write;
2746
e54fb9c1 2747 /* digital I/O */
4bf21fa4
BP
2748 s = dev->subdevices + SUBDEV_DIO;
2749 s->type = COMEDI_SUBD_DIO;
2750 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
2751 s->n_chan = 8;
2752 s->maxdata = 1;
2753 s->range_table = (&range_digital);
2754 s->insn_bits = usbdux_dio_insn_bits;
2755 s->insn_config = usbdux_dio_insn_config;
e54fb9c1 2756 /* we don't use it */
4bf21fa4
BP
2757 s->private = NULL;
2758
e54fb9c1 2759 /* counter */
4bf21fa4
BP
2760 s = dev->subdevices + SUBDEV_COUNTER;
2761 s->type = COMEDI_SUBD_COUNTER;
2762 s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
2763 s->n_chan = 4;
2764 s->maxdata = 0xFFFF;
2765 s->insn_read = usbdux_counter_read;
2766 s->insn_write = usbdux_counter_write;
2767 s->insn_config = usbdux_counter_config;
2768
c0e0c26e 2769 if (udev->high_speed) {
e54fb9c1 2770 /* timer / pwm */
4bf21fa4
BP
2771 s = dev->subdevices + SUBDEV_PWM;
2772 s->type = COMEDI_SUBD_PWM;
2773 s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE;
2774 s->n_chan = 8;
e54fb9c1 2775 /* this defines the max duty cycle resolution */
c0e0c26e 2776 s->maxdata = udev->sizePwmBuf;
4bf21fa4
BP
2777 s->insn_write = usbdux_pwm_write;
2778 s->insn_read = usbdux_pwm_read;
2779 s->insn_config = usbdux_pwm_config;
2780 usbdux_pwm_period(dev, s, PWM_DEFAULT_PERIOD);
2781 }
e54fb9c1 2782 /* finally decide that it's attached */
c0e0c26e 2783 udev->attached = 1;
4bf21fa4 2784
c0e0c26e 2785 up(&udev->sem);
4bf21fa4
BP
2786
2787 up(&start_stop_sem);
2788
c0e0c26e
GKH
2789 dev_info(&udev->interface->dev, "comedi%d: attached to usbdux.\n",
2790 dev->minor);
4bf21fa4
BP
2791
2792 return 0;
2793}
2794
71b5f4f1 2795static int usbdux_detach(struct comedi_device *dev)
4bf21fa4 2796{
cc92fca7 2797 struct usbduxsub *usbduxsub_tmp;
4bf21fa4 2798
4bf21fa4 2799 if (!dev) {
c0e0c26e 2800 printk(KERN_ERR
0a85b6f0 2801 "comedi?: usbdux: detach without dev variable...\n");
4bf21fa4
BP
2802 return -EFAULT;
2803 }
2804
2805 usbduxsub_tmp = dev->private;
2806 if (!usbduxsub_tmp) {
c0e0c26e 2807 printk(KERN_ERR
0a85b6f0 2808 "comedi?: usbdux: detach without ptr to usbduxsub[]\n");
4bf21fa4
BP
2809 return -EFAULT;
2810 }
2811
c0e0c26e
GKH
2812 dev_dbg(&usbduxsub_tmp->interface->dev, "comedi%d: detach usb device\n",
2813 dev->minor);
2814
4bf21fa4 2815 down(&usbduxsub_tmp->sem);
e54fb9c1
GKH
2816 /* Don't allow detach to free the private structure */
2817 /* It's one entry of of usbduxsub[] */
4bf21fa4
BP
2818 dev->private = NULL;
2819 usbduxsub_tmp->attached = 0;
2820 usbduxsub_tmp->comedidev = NULL;
c0e0c26e
GKH
2821 dev_dbg(&usbduxsub_tmp->interface->dev,
2822 "comedi%d: detach: successfully removed\n", dev->minor);
4bf21fa4
BP
2823 up(&usbduxsub_tmp->sem);
2824 return 0;
2825}
2826
2827/* main driver struct */
139dfbdf 2828static struct comedi_driver driver_usbdux = {
0a85b6f0
MT
2829 .driver_name = "usbdux",
2830 .module = THIS_MODULE,
2831 .attach = usbdux_attach,
2832 .detach = usbdux_detach,
4bf21fa4
BP
2833};
2834
8fa07567 2835/* Table with the USB-devices: just now only testing IDs */
4bf21fa4 2836static struct usb_device_id usbduxsub_table[] = {
0a85b6f0
MT
2837 {USB_DEVICE(0x13d8, 0x0001)},
2838 {USB_DEVICE(0x13d8, 0x0002)},
4bf21fa4
BP
2839 {} /* Terminating entry */
2840};
2841
2842MODULE_DEVICE_TABLE(usb, usbduxsub_table);
2843
8fa07567 2844/* The usbduxsub-driver */
4bf21fa4 2845static struct usb_driver usbduxsub_driver = {
0a85b6f0
MT
2846 .name = BOARDNAME,
2847 .probe = usbduxsub_probe,
2848 .disconnect = usbduxsub_disconnect,
2849 .id_table = usbduxsub_table,
4bf21fa4
BP
2850};
2851
e54fb9c1
GKH
2852/* Can't use the nice macro as I have also to initialise the USB */
2853/* subsystem: */
2854/* registering the usb-system _and_ the comedi-driver */
1b9fb14e 2855static int __init init_usbdux(void)
4bf21fa4
BP
2856{
2857 printk(KERN_INFO KBUILD_MODNAME ": "
2858 DRIVER_VERSION ":" DRIVER_DESC "\n");
4bf21fa4
BP
2859 usb_register(&usbduxsub_driver);
2860 comedi_driver_register(&driver_usbdux);
2861 return 0;
2862}
2863
e54fb9c1 2864/* deregistering the comedi driver and the usb-subsystem */
1b9fb14e 2865static void __exit exit_usbdux(void)
4bf21fa4
BP
2866{
2867 comedi_driver_unregister(&driver_usbdux);
2868 usb_deregister(&usbduxsub_driver);
2869}
2870
2871module_init(init_usbdux);
2872module_exit(exit_usbdux);
2873
2874MODULE_AUTHOR(DRIVER_AUTHOR);
2875MODULE_DESCRIPTION(DRIVER_DESC);
2876MODULE_LICENSE("GPL");