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