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