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