]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/staging/comedi/drivers/usbduxfast.c
Driver-Core: devtmpfs - set root directory mode to 0755
[net-next-2.6.git] / drivers / staging / comedi / drivers / usbduxfast.c
CommitLineData
f47c697d 1/*
4e8ad0dc
MK
2 * Copyright (C) 2004 Bernd Porr, Bernd.Porr@f2s.com
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
f47c697d
BP
18
19/*
20 * I must give credit here to Chris Baugher who
21 * wrote the driver for AT-MIO-16d. I used some parts of this
22 * driver. I also must give credits to David Brownell
23 * who supported me with the USB development.
24 *
25 * Bernd Porr
26 *
27 *
28 * Revision history:
29 * 0.9: Dropping the first data packet which seems to be from the last transfer.
30 * Buffer overflows in the FX2 are handed over to comedi.
31 * 0.92: Dropping now 4 packets. The quad buffer has to be emptied.
4e8ad0dc
MK
32 * Added insn command basically for testing. Sample rate is
33 * 1MHz/16ch=62.5kHz
f47c697d
BP
34 * 0.99: Ian Abbott pointed out a bug which has been corrected. Thanks!
35 * 0.99a: added external trigger.
6742c0af
BP
36 * 1.00: added firmware kernel request to the driver which fixed
37 * udev coldplug problem
f47c697d
BP
38 */
39
40#include <linux/kernel.h>
6742c0af 41#include <linux/firmware.h>
f47c697d
BP
42#include <linux/module.h>
43#include <linux/init.h>
44#include <linux/slab.h>
45#include <linux/input.h>
46#include <linux/usb.h>
47#include <linux/smp_lock.h>
48#include <linux/fcntl.h>
49#include <linux/compiler.h>
50#include "comedi_fc.h"
51#include "../comedidev.h"
f47c697d 52
6742c0af 53#define DRIVER_VERSION "v1.0"
4e8ad0dc
MK
54#define DRIVER_AUTHOR "Bernd Porr, BerndPorr@f2s.com"
55#define DRIVER_DESC "USB-DUXfast, BerndPorr@f2s.com"
f47c697d
BP
56#define BOARDNAME "usbduxfast"
57
4e8ad0dc
MK
58/*
59 * timeout for the USB-transfer
60 */
61#define EZTIMEOUT 30
f47c697d 62
4e8ad0dc
MK
63/*
64 * constants for "firmware" upload and download
65 */
66#define USBDUXFASTSUB_FIRMWARE 0xA0
67#define VENDOR_DIR_IN 0xC0
68#define VENDOR_DIR_OUT 0x40
f47c697d 69
4e8ad0dc
MK
70/*
71 * internal adresses of the 8051 processor
72 */
73#define USBDUXFASTSUB_CPUCS 0xE600
f47c697d 74
4e8ad0dc
MK
75/*
76 * max lenghth of the transfer-buffer for software upload
77 */
78#define TB_LEN 0x2000
f47c697d 79
4e8ad0dc
MK
80/*
81 * input endpoint number
82 */
83#define BULKINEP 6
f47c697d 84
4e8ad0dc
MK
85/*
86 * endpoint for the A/D channellist: bulk OUT
87 */
88#define CHANNELLISTEP 4
f47c697d 89
4e8ad0dc
MK
90/*
91 * number of channels
92 */
93#define NUMCHANNELS 32
f47c697d 94
4e8ad0dc
MK
95/*
96 * size of the waveform descriptor
97 */
98#define WAVESIZE 0x20
f47c697d 99
4e8ad0dc
MK
100/*
101 * size of one A/D value
102 */
103#define SIZEADIN (sizeof(int16_t))
f47c697d 104
4e8ad0dc
MK
105/*
106 * size of the input-buffer IN BYTES
107 */
108#define SIZEINBUF 512
f47c697d 109
4e8ad0dc
MK
110/*
111 * 16 bytes
112 */
113#define SIZEINSNBUF 512
f47c697d 114
4e8ad0dc
MK
115/*
116 * size of the buffer for the dux commands in bytes
117 */
118#define SIZEOFDUXBUFFER 256
f47c697d 119
4e8ad0dc
MK
120/*
121 * number of in-URBs which receive the data: min=5
122 */
123#define NUMOFINBUFFERSHIGH 10
f47c697d 124
4e8ad0dc
MK
125/*
126 * total number of usbduxfast devices
127 */
128#define NUMUSBDUXFAST 16
f47c697d 129
4e8ad0dc
MK
130/*
131 * number of subdevices
132 */
133#define N_SUBDEVICES 1
f47c697d 134
4e8ad0dc
MK
135/*
136 * analogue in subdevice
137 */
138#define SUBDEV_AD 0
f47c697d 139
4e8ad0dc
MK
140/*
141 * min delay steps for more than one channel
142 * basically when the mux gives up ;-)
143 *
144 * steps at 30MHz in the FX2
145 */
146#define MIN_SAMPLING_PERIOD 9
f47c697d 147
4e8ad0dc
MK
148/*
149 * max number of 1/30MHz delay steps
150 */
151#define MAX_SAMPLING_PERIOD 500
f47c697d 152
4e8ad0dc
MK
153/*
154 * number of received packets to ignore before we start handing data
155 * over to comedi, it's quad buffering and we have to ignore 4 packets
156 */
157#define PACKETS_TO_IGNORE 4
f47c697d 158
4e8ad0dc
MK
159/*
160 * comedi constants
161 */
9ced1de6 162static const struct comedi_lrange range_usbduxfast_ai_range = {
0a85b6f0 163 2, {BIP_RANGE(0.75), BIP_RANGE(0.5)}
f47c697d
BP
164};
165
166/*
167 * private structure of one subdevice
4e8ad0dc
MK
168 *
169 * this is the structure which holds all the data of this driver
170 * one sub device just now: A/D
f47c697d 171 */
4e8ad0dc 172struct usbduxfastsub_s {
0a85b6f0
MT
173 int attached; /* is attached? */
174 int probed; /* is it associated with a subdevice? */
4e8ad0dc 175 struct usb_device *usbdev; /* pointer to the usb-device */
0a85b6f0 176 struct urb *urbIn; /* BULK-transfer handling: urb */
f47c697d 177 int8_t *transfer_buffer;
0a85b6f0
MT
178 int16_t *insnBuffer; /* input buffer for single insn */
179 int ifnum; /* interface number */
4e8ad0dc 180 struct usb_interface *interface; /* interface structure */
71b5f4f1 181 struct comedi_device *comedidev; /* comedi device for the interrupt
0a85b6f0 182 context */
4e8ad0dc 183 short int ai_cmd_running; /* asynchronous command is running */
0a85b6f0 184 short int ai_continous; /* continous aquisition */
4e8ad0dc 185 long int ai_sample_count; /* number of samples to aquire */
0a85b6f0
MT
186 uint8_t *dux_commands; /* commands */
187 int ignore; /* counter which ignores the first
188 buffers */
f47c697d 189 struct semaphore sem;
4e8ad0dc 190};
f47c697d 191
4e8ad0dc
MK
192/*
193 * The pointer to the private usb-data of the driver
194 * is also the private data for the comedi-device.
195 * This has to be global as the usb subsystem needs
196 * global variables. The other reason is that this
197 * structure must be there _before_ any comedi
198 * command is issued. The usb subsystem must be
199 * initialised before comedi can access it.
200 */
201static struct usbduxfastsub_s usbduxfastsub[NUMUSBDUXFAST];
f47c697d
BP
202
203static DECLARE_MUTEX(start_stop_sem);
204
4e8ad0dc
MK
205/*
206 * bulk transfers to usbduxfast
207 */
f47c697d
BP
208#define SENDADCOMMANDS 0
209#define SENDINITEP6 1
210
4e8ad0dc 211static int send_dux_commands(struct usbduxfastsub_s *udfs, int cmd_type)
f47c697d 212{
0a3b8b64
MK
213 int tmp, nsent;
214
4e8ad0dc 215 udfs->dux_commands[0] = cmd_type;
0a3b8b64 216
f47c697d 217#ifdef CONFIG_COMEDI_DEBUG
0a3b8b64 218 printk(KERN_DEBUG "comedi%d: usbduxfast: dux_commands: ",
0a85b6f0 219 udfs->comedidev->minor);
0a3b8b64 220 for (tmp = 0; tmp < SIZEOFDUXBUFFER; tmp++)
4e8ad0dc 221 printk(" %02x", udfs->dux_commands[tmp]);
f47c697d
BP
222 printk("\n");
223#endif
0a3b8b64 224
4e8ad0dc
MK
225 tmp = usb_bulk_msg(udfs->usbdev,
226 usb_sndbulkpipe(udfs->usbdev, CHANNELLISTEP),
227 udfs->dux_commands, SIZEOFDUXBUFFER, &nsent, 10000);
0a3b8b64
MK
228 if (tmp < 0)
229 printk(KERN_ERR "comedi%d: could not transmit dux_commands to"
0a85b6f0 230 "the usb-device, err=%d\n", udfs->comedidev->minor, tmp);
0a3b8b64 231 return tmp;
f47c697d
BP
232}
233
4e8ad0dc
MK
234/*
235 * Stops the data acquision.
236 * It should be safe to call this function from any context.
237 */
238static int usbduxfastsub_unlink_InURBs(struct usbduxfastsub_s *udfs)
f47c697d
BP
239{
240 int j = 0;
241 int err = 0;
242
4e8ad0dc
MK
243 if (udfs && udfs->urbIn) {
244 udfs->ai_cmd_running = 0;
245 /* waits until a running transfer is over */
246 usb_kill_urb(udfs->urbIn);
f47c697d 247 j = 0;
f47c697d
BP
248 }
249#ifdef CONFIG_COMEDI_DEBUG
4e8ad0dc 250 printk(KERN_DEBUG "comedi: usbduxfast: unlinked InURB: res=%d\n", j);
f47c697d
BP
251#endif
252 return err;
253}
254
4e8ad0dc
MK
255/*
256 * This will stop a running acquisition operation.
257 * Is called from within this driver from both the
258 * interrupt context and from comedi.
259 */
0a85b6f0 260static int usbduxfast_ai_stop(struct usbduxfastsub_s *udfs, int do_unlink)
f47c697d
BP
261{
262 int ret = 0;
263
4e8ad0dc
MK
264 if (!udfs) {
265 printk(KERN_ERR "comedi?: usbduxfast_ai_stop: udfs=NULL!\n");
f47c697d
BP
266 return -EFAULT;
267 }
268#ifdef CONFIG_COMEDI_DEBUG
4e8ad0dc 269 printk(KERN_DEBUG "comedi: usbduxfast_ai_stop\n");
f47c697d
BP
270#endif
271
4e8ad0dc 272 udfs->ai_cmd_running = 0;
f47c697d 273
4e8ad0dc 274 if (do_unlink)
0a85b6f0 275 ret = usbduxfastsub_unlink_InURBs(udfs); /* stop aquistion */
f47c697d
BP
276
277 return ret;
278}
279
4e8ad0dc
MK
280/*
281 * This will cancel a running acquisition operation.
282 * This is called by comedi but never from inside the driver.
283 */
0a85b6f0
MT
284static int usbduxfast_ai_cancel(struct comedi_device *dev,
285 struct comedi_subdevice *s)
f47c697d 286{
4e8ad0dc
MK
287 struct usbduxfastsub_s *udfs;
288 int ret;
f47c697d 289
4e8ad0dc 290 /* force unlink of all urbs */
f47c697d 291#ifdef CONFIG_COMEDI_DEBUG
4e8ad0dc 292 printk(KERN_DEBUG "comedi: usbduxfast_ai_cancel\n");
f47c697d 293#endif
4e8ad0dc
MK
294 udfs = dev->private;
295 if (!udfs) {
296 printk(KERN_ERR "comedi: usbduxfast_ai_cancel: udfs=NULL\n");
f47c697d
BP
297 return -EFAULT;
298 }
4e8ad0dc
MK
299 down(&udfs->sem);
300 if (!udfs->probed) {
301 up(&udfs->sem);
f47c697d
BP
302 return -ENODEV;
303 }
4e8ad0dc
MK
304 /* unlink */
305 ret = usbduxfast_ai_stop(udfs, 1);
306 up(&udfs->sem);
f47c697d 307
4e8ad0dc 308 return ret;
f47c697d
BP
309}
310
4e8ad0dc
MK
311/*
312 * analogue IN
313 * interrupt service routine
314 */
70265d24 315static void usbduxfastsub_ai_Irq(struct urb *urb)
f47c697d
BP
316{
317 int n, err;
4e8ad0dc 318 struct usbduxfastsub_s *udfs;
71b5f4f1 319 struct comedi_device *this_comedidev;
34c43922 320 struct comedi_subdevice *s;
f47c697d
BP
321 uint16_t *p;
322
4e8ad0dc 323 /* sanity checks - is the urb there? */
f47c697d 324 if (!urb) {
4e8ad0dc
MK
325 printk(KERN_ERR "comedi_: usbduxfast_: ao int-handler called "
326 "with urb=NULL!\n");
f47c697d
BP
327 return;
328 }
4e8ad0dc 329 /* the context variable points to the subdevice */
f47c697d
BP
330 this_comedidev = urb->context;
331 if (!this_comedidev) {
4e8ad0dc
MK
332 printk(KERN_ERR "comedi_: usbduxfast_: urb context is a NULL "
333 "pointer!\n");
f47c697d
BP
334 return;
335 }
4e8ad0dc
MK
336 /* the private structure of the subdevice is usbduxfastsub_s */
337 udfs = this_comedidev->private;
338 if (!udfs) {
339 printk(KERN_ERR "comedi_: usbduxfast_: private of comedi "
340 "subdev is a NULL pointer!\n");
f47c697d
BP
341 return;
342 }
4e8ad0dc
MK
343 /* are we running a command? */
344 if (unlikely(!udfs->ai_cmd_running)) {
345 /*
346 * not running a command
347 * do not continue execution if no asynchronous command
348 * is running in particular not resubmit
349 */
f47c697d
BP
350 return;
351 }
352
4e8ad0dc
MK
353 if (unlikely(!udfs->attached)) {
354 /* no comedi device there */
f47c697d
BP
355 return;
356 }
4e8ad0dc 357 /* subdevice which is the AD converter */
f47c697d
BP
358 s = this_comedidev->subdevices + SUBDEV_AD;
359
4e8ad0dc 360 /* first we test if something unusual has just happened */
f47c697d
BP
361 switch (urb->status) {
362 case 0:
363 break;
364
4e8ad0dc
MK
365 /*
366 * happens after an unlink command or when the device
367 * is plugged out
368 */
f47c697d
BP
369 case -ECONNRESET:
370 case -ENOENT:
371 case -ESHUTDOWN:
372 case -ECONNABORTED:
4e8ad0dc 373 /* tell this comedi */
f47c697d
BP
374 s->async->events |= COMEDI_CB_EOA;
375 s->async->events |= COMEDI_CB_ERROR;
4e8ad0dc
MK
376 comedi_event(udfs->comedidev, s);
377 /* stop the transfer w/o unlink */
378 usbduxfast_ai_stop(udfs, 0);
f47c697d
BP
379 return;
380
381 default:
4e8ad0dc
MK
382 printk("comedi%d: usbduxfast: non-zero urb status received in "
383 "ai intr context: %d\n",
384 udfs->comedidev->minor, urb->status);
f47c697d
BP
385 s->async->events |= COMEDI_CB_EOA;
386 s->async->events |= COMEDI_CB_ERROR;
4e8ad0dc
MK
387 comedi_event(udfs->comedidev, s);
388 usbduxfast_ai_stop(udfs, 0);
f47c697d
BP
389 return;
390 }
391
392 p = urb->transfer_buffer;
4e8ad0dc
MK
393 if (!udfs->ignore) {
394 if (!udfs->ai_continous) {
395 /* not continous, fixed number of samples */
f47c697d 396 n = urb->actual_length / sizeof(uint16_t);
4e8ad0dc
MK
397 if (unlikely(udfs->ai_sample_count < n)) {
398 /*
399 * we have send only a fraction of the bytes
400 * received
401 */
f47c697d 402 cfc_write_array_to_buffer(s,
0a85b6f0
MT
403 urb->transfer_buffer,
404 udfs->ai_sample_count
405 * sizeof(uint16_t));
4e8ad0dc 406 usbduxfast_ai_stop(udfs, 0);
efe8d60a 407 /* tell comedi that the acquistion is over */
f47c697d 408 s->async->events |= COMEDI_CB_EOA;
4e8ad0dc 409 comedi_event(udfs->comedidev, s);
f47c697d
BP
410 return;
411 }
4e8ad0dc 412 udfs->ai_sample_count -= n;
f47c697d 413 }
4e8ad0dc 414 /* write the full buffer to comedi */
efe8d60a
BP
415 err = cfc_write_array_to_buffer(s, urb->transfer_buffer,
416 urb->actual_length);
417 if (unlikely(err == 0)) {
418 /* buffer overflow */
419 usbduxfast_ai_stop(udfs, 0);
420 return;
421 }
f47c697d 422
4e8ad0dc
MK
423 /* tell comedi that data is there */
424 comedi_event(udfs->comedidev, s);
f47c697d
BP
425
426 } else {
4e8ad0dc
MK
427 /* ignore this packet */
428 udfs->ignore--;
f47c697d
BP
429 }
430
4e8ad0dc
MK
431 /*
432 * command is still running
433 * resubmit urb for BULK transfer
434 */
435 urb->dev = udfs->usbdev;
f47c697d 436 urb->status = 0;
88676359
GKH
437 err = usb_submit_urb(urb, GFP_ATOMIC);
438 if (err < 0) {
4e8ad0dc 439 printk(KERN_ERR "comedi%d: usbduxfast: urb resubm failed: %d",
0a85b6f0 440 udfs->comedidev->minor, err);
f47c697d
BP
441 s->async->events |= COMEDI_CB_EOA;
442 s->async->events |= COMEDI_CB_ERROR;
4e8ad0dc
MK
443 comedi_event(udfs->comedidev, s);
444 usbduxfast_ai_stop(udfs, 0);
f47c697d
BP
445 }
446}
447
4e8ad0dc 448static int usbduxfastsub_start(struct usbduxfastsub_s *udfs)
f47c697d 449{
4e8ad0dc 450 int ret;
f47c697d
BP
451 unsigned char local_transfer_buffer[16];
452
4e8ad0dc
MK
453 /* 7f92 to zero */
454 local_transfer_buffer[0] = 0;
0a85b6f0
MT
455 ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), USBDUXFASTSUB_FIRMWARE, /* bRequest, "Firmware" */
456 VENDOR_DIR_OUT, /* bmRequestType */
457 USBDUXFASTSUB_CPUCS, /* Value */
458 0x0000, /* Index */
459 local_transfer_buffer, /* address of the transfer buffer */
460 1, /* Length */
461 EZTIMEOUT); /* Timeout */
4e8ad0dc
MK
462 if (ret < 0) {
463 printk("comedi_: usbduxfast_: control msg failed (start)\n");
464 return ret;
f47c697d 465 }
4e8ad0dc 466
f47c697d
BP
467 return 0;
468}
469
4e8ad0dc 470static int usbduxfastsub_stop(struct usbduxfastsub_s *udfs)
f47c697d 471{
4e8ad0dc 472 int ret;
f47c697d 473 unsigned char local_transfer_buffer[16];
4e8ad0dc 474
4e8ad0dc
MK
475 /* 7f92 to one */
476 local_transfer_buffer[0] = 1;
0a85b6f0
MT
477 ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), USBDUXFASTSUB_FIRMWARE, /* bRequest, "Firmware" */
478 VENDOR_DIR_OUT, /* bmRequestType */
479 USBDUXFASTSUB_CPUCS, /* Value */
480 0x0000, /* Index */
481 local_transfer_buffer, 1, /* Length */
482 EZTIMEOUT); /* Timeout */
4e8ad0dc
MK
483 if (ret < 0) {
484 printk(KERN_ERR "comedi_: usbduxfast: control msg failed "
485 "(stop)\n");
486 return ret;
f47c697d 487 }
4e8ad0dc 488
f47c697d
BP
489 return 0;
490}
491
4e8ad0dc 492static int usbduxfastsub_upload(struct usbduxfastsub_s *udfs,
0a85b6f0
MT
493 unsigned char *local_transfer_buffer,
494 unsigned int startAddr, unsigned int len)
f47c697d 495{
4e8ad0dc
MK
496 int ret;
497
f47c697d 498#ifdef CONFIG_COMEDI_DEBUG
d52a63bf 499 printk(KERN_DEBUG "comedi: usbduxfast: uploading %d bytes", len);
4e8ad0dc 500 printk(KERN_DEBUG " to addr %d, first byte=%d.\n",
0a85b6f0 501 startAddr, local_transfer_buffer[0]);
f47c697d 502#endif
0a85b6f0
MT
503 ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), USBDUXFASTSUB_FIRMWARE, /* brequest, firmware */
504 VENDOR_DIR_OUT, /* bmRequestType */
505 startAddr, /* value */
506 0x0000, /* index */
507 local_transfer_buffer, /* our local safe buffer */
508 len, /* length */
509 EZTIMEOUT); /* timeout */
4e8ad0dc 510
f47c697d 511#ifdef CONFIG_COMEDI_DEBUG
4e8ad0dc 512 printk(KERN_DEBUG "comedi_: usbduxfast: result=%d\n", ret);
f47c697d 513#endif
4e8ad0dc
MK
514
515 if (ret < 0) {
516 printk(KERN_ERR "comedi_: usbduxfast: uppload failed\n");
517 return ret;
f47c697d 518 }
4e8ad0dc 519
f47c697d
BP
520 return 0;
521}
522
4e8ad0dc 523int usbduxfastsub_submit_InURBs(struct usbduxfastsub_s *udfs)
f47c697d 524{
4e8ad0dc 525 int ret;
f47c697d 526
4e8ad0dc 527 if (!udfs)
f47c697d 528 return -EFAULT;
4e8ad0dc
MK
529
530 usb_fill_bulk_urb(udfs->urbIn, udfs->usbdev,
531 usb_rcvbulkpipe(udfs->usbdev, BULKINEP),
532 udfs->transfer_buffer,
533 SIZEINBUF, usbduxfastsub_ai_Irq, udfs->comedidev);
f47c697d
BP
534
535#ifdef CONFIG_COMEDI_DEBUG
4e8ad0dc
MK
536 printk(KERN_DEBUG "comedi%d: usbduxfast: submitting in-urb: "
537 "0x%p,0x%p\n", udfs->comedidev->minor, udfs->urbIn->context,
0a85b6f0 538 udfs->urbIn->dev);
f47c697d 539#endif
4e8ad0dc
MK
540 ret = usb_submit_urb(udfs->urbIn, GFP_ATOMIC);
541 if (ret) {
542 printk(KERN_ERR "comedi_: usbduxfast: ai: usb_submit_urb error"
543 " %d\n", ret);
544 return ret;
f47c697d
BP
545 }
546 return 0;
547}
548
71b5f4f1 549static int usbduxfast_ai_cmdtest(struct comedi_device *dev,
0a85b6f0
MT
550 struct comedi_subdevice *s,
551 struct comedi_cmd *cmd)
f47c697d
BP
552{
553 int err = 0, stop_mask = 0;
4e8ad0dc 554 long int steps, tmp;
f47c697d 555 int minSamplPer;
4e8ad0dc
MK
556 struct usbduxfastsub_s *udfs = dev->private;
557
558 if (!udfs->probed)
f47c697d 559 return -ENODEV;
4e8ad0dc 560
f47c697d 561#ifdef CONFIG_COMEDI_DEBUG
4e8ad0dc
MK
562 printk(KERN_DEBUG "comedi%d: usbduxfast_ai_cmdtest\n", dev->minor);
563 printk(KERN_DEBUG "comedi%d: usbduxfast: convert_arg=%u "
564 "scan_begin_arg=%u\n",
565 dev->minor, cmd->convert_arg, cmd->scan_begin_arg);
f47c697d
BP
566#endif
567 /* step 1: make sure trigger sources are trivially valid */
568
569 tmp = cmd->start_src;
570 cmd->start_src &= TRIG_NOW | TRIG_EXT | TRIG_INT;
571 if (!cmd->start_src || tmp != cmd->start_src)
572 err++;
573
574 tmp = cmd->scan_begin_src;
575 cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT;
576 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
577 err++;
578
579 tmp = cmd->convert_src;
580 cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
581 if (!cmd->convert_src || tmp != cmd->convert_src)
582 err++;
583
584 tmp = cmd->scan_end_src;
585 cmd->scan_end_src &= TRIG_COUNT;
586 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
587 err++;
588
589 tmp = cmd->stop_src;
590 stop_mask = TRIG_COUNT | TRIG_NONE;
591 cmd->stop_src &= stop_mask;
592 if (!cmd->stop_src || tmp != cmd->stop_src)
593 err++;
594
595 if (err)
596 return 1;
597
4e8ad0dc
MK
598 /*
599 * step 2: make sure trigger sources are unique and mutually compatible
600 */
f47c697d
BP
601
602 if (cmd->start_src != TRIG_NOW &&
0a85b6f0 603 cmd->start_src != TRIG_EXT && cmd->start_src != TRIG_INT)
f47c697d
BP
604 err++;
605 if (cmd->scan_begin_src != TRIG_TIMER &&
0a85b6f0
MT
606 cmd->scan_begin_src != TRIG_FOLLOW &&
607 cmd->scan_begin_src != TRIG_EXT)
f47c697d
BP
608 err++;
609 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
610 err++;
611 if (cmd->stop_src != TRIG_COUNT &&
0a85b6f0 612 cmd->stop_src != TRIG_EXT && cmd->stop_src != TRIG_NONE)
f47c697d
BP
613 err++;
614
4e8ad0dc 615 /* can't have external stop and start triggers at once */
f47c697d
BP
616 if (cmd->start_src == TRIG_EXT && cmd->stop_src == TRIG_EXT)
617 err++;
618
619 if (err)
620 return 2;
621
622 /* step 3: make sure arguments are trivially compatible */
623
624 if (cmd->start_src == TRIG_NOW && cmd->start_arg != 0) {
625 cmd->start_arg = 0;
626 err++;
627 }
628
4e8ad0dc 629 if (!cmd->chanlist_len)
f47c697d 630 err++;
4e8ad0dc 631
f47c697d
BP
632 if (cmd->scan_end_arg != cmd->chanlist_len) {
633 cmd->scan_end_arg = cmd->chanlist_len;
634 err++;
635 }
636
4e8ad0dc 637 if (cmd->chanlist_len == 1)
f47c697d 638 minSamplPer = 1;
4e8ad0dc 639 else
f47c697d 640 minSamplPer = MIN_SAMPLING_PERIOD;
f47c697d
BP
641
642 if (cmd->convert_src == TRIG_TIMER) {
643 steps = cmd->convert_arg * 30;
4e8ad0dc 644 if (steps < (minSamplPer * 1000))
f47c697d 645 steps = minSamplPer * 1000;
4e8ad0dc
MK
646
647 if (steps > (MAX_SAMPLING_PERIOD * 1000))
f47c697d 648 steps = MAX_SAMPLING_PERIOD * 1000;
4e8ad0dc
MK
649
650 /* calc arg again */
f47c697d
BP
651 tmp = steps / 30;
652 if (cmd->convert_arg != tmp) {
653 cmd->convert_arg = tmp;
654 err++;
655 }
656 }
657
4e8ad0dc 658 if (cmd->scan_begin_src == TRIG_TIMER)
f47c697d 659 err++;
4e8ad0dc
MK
660
661 /* stop source */
f47c697d
BP
662 switch (cmd->stop_src) {
663 case TRIG_COUNT:
664 if (!cmd->stop_arg) {
665 cmd->stop_arg = 1;
666 err++;
667 }
668 break;
669 case TRIG_NONE:
670 if (cmd->stop_arg != 0) {
671 cmd->stop_arg = 0;
672 err++;
673 }
674 break;
4e8ad0dc
MK
675 /*
676 * TRIG_EXT doesn't care since it doesn't trigger
677 * off a numbered channel
678 */
f47c697d
BP
679 default:
680 break;
681 }
682
683 if (err)
684 return 3;
685
686 /* step 4: fix up any arguments */
687
688 return 0;
689
690}
691
71b5f4f1 692static int usbduxfast_ai_inttrig(struct comedi_device *dev,
0a85b6f0
MT
693 struct comedi_subdevice *s,
694 unsigned int trignum)
f47c697d
BP
695{
696 int ret;
4e8ad0dc
MK
697 struct usbduxfastsub_s *udfs = dev->private;
698
699 if (!udfs)
f47c697d 700 return -EFAULT;
4e8ad0dc
MK
701
702 down(&udfs->sem);
703 if (!udfs->probed) {
704 up(&udfs->sem);
f47c697d
BP
705 return -ENODEV;
706 }
707#ifdef CONFIG_COMEDI_DEBUG
4e8ad0dc 708 printk(KERN_DEBUG "comedi%d: usbduxfast_ai_inttrig\n", dev->minor);
f47c697d
BP
709#endif
710
711 if (trignum != 0) {
4e8ad0dc
MK
712 printk(KERN_ERR "comedi%d: usbduxfast_ai_inttrig: invalid"
713 " trignum\n", dev->minor);
714 up(&udfs->sem);
f47c697d
BP
715 return -EINVAL;
716 }
4e8ad0dc
MK
717 if (!udfs->ai_cmd_running) {
718 udfs->ai_cmd_running = 1;
719 ret = usbduxfastsub_submit_InURBs(udfs);
f47c697d 720 if (ret < 0) {
4e8ad0dc
MK
721 printk(KERN_ERR "comedi%d: usbduxfast_ai_inttrig: "
722 "urbSubmit: err=%d\n", dev->minor, ret);
723 udfs->ai_cmd_running = 0;
724 up(&udfs->sem);
f47c697d
BP
725 return ret;
726 }
727 s->async->inttrig = NULL;
728 } else {
4e8ad0dc
MK
729 printk(KERN_ERR "comedi%d: ai_inttrig but acqu is already"
730 " running\n", dev->minor);
f47c697d 731 }
4e8ad0dc 732 up(&udfs->sem);
f47c697d
BP
733 return 1;
734}
735
4e8ad0dc
MK
736/*
737 * offsets for the GPIF bytes
738 * the first byte is the command byte
739 */
740#define LENBASE (1+0x00)
741#define OPBASE (1+0x08)
742#define OUTBASE (1+0x10)
743#define LOGBASE (1+0x18)
f47c697d 744
0a85b6f0
MT
745static int usbduxfast_ai_cmd(struct comedi_device *dev,
746 struct comedi_subdevice *s)
f47c697d 747{
ea6d0d4c 748 struct comedi_cmd *cmd = &s->async->cmd;
f47c697d
BP
749 unsigned int chan, gain, rngmask = 0xff;
750 int i, j, ret;
4e8ad0dc 751 struct usbduxfastsub_s *udfs;
f47c697d
BP
752 int result;
753 long steps, steps_tmp;
754
755#ifdef CONFIG_COMEDI_DEBUG
4e8ad0dc 756 printk(KERN_DEBUG "comedi%d: usbduxfast_ai_cmd\n", dev->minor);
f47c697d 757#endif
4e8ad0dc
MK
758 udfs = dev->private;
759 if (!udfs)
f47c697d 760 return -EFAULT;
4e8ad0dc
MK
761
762 down(&udfs->sem);
763 if (!udfs->probed) {
764 up(&udfs->sem);
f47c697d
BP
765 return -ENODEV;
766 }
4e8ad0dc
MK
767 if (udfs->ai_cmd_running) {
768 printk(KERN_ERR "comedi%d: ai_cmd not possible. Another ai_cmd"
769 " is running.\n", dev->minor);
770 up(&udfs->sem);
f47c697d
BP
771 return -EBUSY;
772 }
4e8ad0dc 773 /* set current channel of the running aquisition to zero */
f47c697d
BP
774 s->async->cur_chan = 0;
775
4e8ad0dc
MK
776 /*
777 * ignore the first buffers from the device if there
778 * is an error condition
779 */
780 udfs->ignore = PACKETS_TO_IGNORE;
f47c697d
BP
781
782 if (cmd->chanlist_len > 0) {
783 gain = CR_RANGE(cmd->chanlist[0]);
784 for (i = 0; i < cmd->chanlist_len; ++i) {
785 chan = CR_CHAN(cmd->chanlist[i]);
786 if (chan != i) {
4e8ad0dc
MK
787 printk(KERN_ERR "comedi%d: cmd is accepting "
788 "only consecutive channels.\n",
789 dev->minor);
790 up(&udfs->sem);
f47c697d
BP
791 return -EINVAL;
792 }
793 if ((gain != CR_RANGE(cmd->chanlist[i]))
0a85b6f0 794 && (cmd->chanlist_len > 3)) {
4e8ad0dc
MK
795 printk(KERN_ERR "comedi%d: the gain must be"
796 " the same for all channels.\n",
797 dev->minor);
798 up(&udfs->sem);
f47c697d
BP
799 return -EINVAL;
800 }
801 if (i >= NUMCHANNELS) {
4e8ad0dc
MK
802 printk(KERN_ERR "comedi%d: channel list too"
803 " long\n", dev->minor);
f47c697d
BP
804 break;
805 }
806 }
807 }
808 steps = 0;
809 if (cmd->scan_begin_src == TRIG_TIMER) {
4e8ad0dc
MK
810 printk(KERN_ERR "comedi%d: usbduxfast: "
811 "scan_begin_src==TRIG_TIMER not valid.\n", dev->minor);
812 up(&udfs->sem);
f47c697d
BP
813 return -EINVAL;
814 }
4e8ad0dc 815 if (cmd->convert_src == TRIG_TIMER)
f47c697d 816 steps = (cmd->convert_arg * 30) / 1000;
4e8ad0dc 817
f47c697d 818 if ((steps < MIN_SAMPLING_PERIOD) && (cmd->chanlist_len != 1)) {
4e8ad0dc
MK
819 printk(KERN_ERR "comedi%d: usbduxfast: ai_cmd: steps=%ld, "
820 "scan_begin_arg=%d. Not properly tested by cmdtest?\n",
821 dev->minor, steps, cmd->scan_begin_arg);
822 up(&udfs->sem);
f47c697d
BP
823 return -EINVAL;
824 }
825 if (steps > MAX_SAMPLING_PERIOD) {
4e8ad0dc
MK
826 printk(KERN_ERR "comedi%d: usbduxfast: ai_cmd: sampling rate "
827 "too low.\n", dev->minor);
828 up(&udfs->sem);
f47c697d
BP
829 return -EINVAL;
830 }
831 if ((cmd->start_src == TRIG_EXT) && (cmd->chanlist_len != 1)
0a85b6f0 832 && (cmd->chanlist_len != 16)) {
4e8ad0dc
MK
833 printk(KERN_ERR "comedi%d: usbduxfast: ai_cmd: TRIG_EXT only"
834 " with 1 or 16 channels possible.\n", dev->minor);
835 up(&udfs->sem);
f47c697d
BP
836 return -EINVAL;
837 }
838#ifdef CONFIG_COMEDI_DEBUG
4e8ad0dc
MK
839 printk(KERN_DEBUG "comedi%d: usbduxfast: steps=%ld, convert_arg=%u\n",
840 dev->minor, steps, cmd->convert_arg);
f47c697d
BP
841#endif
842
843 switch (cmd->chanlist_len) {
f47c697d 844 case 1:
4e8ad0dc
MK
845 /*
846 * one channel
847 */
848
f47c697d
BP
849 if (CR_RANGE(cmd->chanlist[0]) > 0)
850 rngmask = 0xff - 0x04;
851 else
852 rngmask = 0xff;
853
4e8ad0dc
MK
854 /*
855 * for external trigger: looping in this state until
856 * the RDY0 pin becomes zero
857 */
858
859 /* we loop here until ready has been set */
860 if (cmd->start_src == TRIG_EXT) {
861 /* branch back to state 0 */
0a85b6f0 862 udfs->dux_commands[LENBASE + 0] = 0x01;
4e8ad0dc 863 /* deceision state w/o data */
0a85b6f0
MT
864 udfs->dux_commands[OPBASE + 0] = 0x01;
865 udfs->dux_commands[OUTBASE + 0] = 0xFF & rngmask;
4e8ad0dc 866 /* RDY0 = 0 */
0a85b6f0 867 udfs->dux_commands[LOGBASE + 0] = 0x00;
4e8ad0dc 868 } else { /* we just proceed to state 1 */
0a85b6f0
MT
869 udfs->dux_commands[LENBASE + 0] = 1;
870 udfs->dux_commands[OPBASE + 0] = 0;
871 udfs->dux_commands[OUTBASE + 0] = 0xFF & rngmask;
872 udfs->dux_commands[LOGBASE + 0] = 0;
f47c697d
BP
873 }
874
875 if (steps < MIN_SAMPLING_PERIOD) {
4e8ad0dc 876 /* for fast single channel aqu without mux */
f47c697d 877 if (steps <= 1) {
4e8ad0dc
MK
878 /*
879 * we just stay here at state 1 and rexecute
880 * the same state this gives us 30MHz sampling
881 * rate
882 */
883
884 /* branch back to state 1 */
0a85b6f0 885 udfs->dux_commands[LENBASE + 1] = 0x89;
4e8ad0dc 886 /* deceision state with data */
0a85b6f0
MT
887 udfs->dux_commands[OPBASE + 1] = 0x03;
888 udfs->dux_commands[OUTBASE + 1] =
889 0xFF & rngmask;
4e8ad0dc 890 /* doesn't matter */
0a85b6f0 891 udfs->dux_commands[LOGBASE + 1] = 0xFF;
f47c697d 892 } else {
4e8ad0dc
MK
893 /*
894 * we loop through two states: data and delay
895 * max rate is 15MHz
896 */
0a85b6f0 897 udfs->dux_commands[LENBASE + 1] = steps - 1;
4e8ad0dc 898 /* data */
0a85b6f0
MT
899 udfs->dux_commands[OPBASE + 1] = 0x02;
900 udfs->dux_commands[OUTBASE + 1] =
901 0xFF & rngmask;
4e8ad0dc 902 /* doesn't matter */
0a85b6f0 903 udfs->dux_commands[LOGBASE + 1] = 0;
4e8ad0dc 904 /* branch back to state 1 */
0a85b6f0 905 udfs->dux_commands[LENBASE + 2] = 0x09;
4e8ad0dc 906 /* deceision state w/o data */
0a85b6f0
MT
907 udfs->dux_commands[OPBASE + 2] = 0x01;
908 udfs->dux_commands[OUTBASE + 2] =
909 0xFF & rngmask;
4e8ad0dc 910 /* doesn't matter */
0a85b6f0 911 udfs->dux_commands[LOGBASE + 2] = 0xFF;
f47c697d
BP
912 }
913 } else {
4e8ad0dc
MK
914 /*
915 * we loop through 3 states: 2x delay and 1x data
916 * this gives a min sampling rate of 60kHz
917 */
f47c697d 918
4e8ad0dc 919 /* we have 1 state with duration 1 */
f47c697d
BP
920 steps = steps - 1;
921
4e8ad0dc 922 /* do the first part of the delay */
0a85b6f0
MT
923 udfs->dux_commands[LENBASE + 1] = steps / 2;
924 udfs->dux_commands[OPBASE + 1] = 0;
925 udfs->dux_commands[OUTBASE + 1] = 0xFF & rngmask;
926 udfs->dux_commands[LOGBASE + 1] = 0;
4e8ad0dc
MK
927
928 /* and the second part */
0a85b6f0
MT
929 udfs->dux_commands[LENBASE + 2] = steps - steps / 2;
930 udfs->dux_commands[OPBASE + 2] = 0;
931 udfs->dux_commands[OUTBASE + 2] = 0xFF & rngmask;
932 udfs->dux_commands[LOGBASE + 2] = 0;
4e8ad0dc
MK
933
934 /* get the data and branch back */
935
936 /* branch back to state 1 */
0a85b6f0 937 udfs->dux_commands[LENBASE + 3] = 0x09;
4e8ad0dc 938 /* deceision state w data */
0a85b6f0
MT
939 udfs->dux_commands[OPBASE + 3] = 0x03;
940 udfs->dux_commands[OUTBASE + 3] = 0xFF & rngmask;
4e8ad0dc 941 /* doesn't matter */
0a85b6f0 942 udfs->dux_commands[LOGBASE + 3] = 0xFF;
f47c697d
BP
943 }
944 break;
945
946 case 2:
4e8ad0dc
MK
947 /*
948 * two channels
949 * commit data to the FIFO
950 */
951
f47c697d
BP
952 if (CR_RANGE(cmd->chanlist[0]) > 0)
953 rngmask = 0xff - 0x04;
954 else
955 rngmask = 0xff;
f47c697d 956
0a85b6f0 957 udfs->dux_commands[LENBASE + 0] = 1;
4e8ad0dc 958 /* data */
0a85b6f0
MT
959 udfs->dux_commands[OPBASE + 0] = 0x02;
960 udfs->dux_commands[OUTBASE + 0] = 0xFF & rngmask;
961 udfs->dux_commands[LOGBASE + 0] = 0;
4e8ad0dc
MK
962
963 /* we have 1 state with duration 1: state 0 */
f47c697d
BP
964 steps_tmp = steps - 1;
965
966 if (CR_RANGE(cmd->chanlist[1]) > 0)
967 rngmask = 0xff - 0x04;
968 else
969 rngmask = 0xff;
4e8ad0dc
MK
970
971 /* do the first part of the delay */
0a85b6f0
MT
972 udfs->dux_commands[LENBASE + 1] = steps_tmp / 2;
973 udfs->dux_commands[OPBASE + 1] = 0;
4e8ad0dc 974 /* count */
0a85b6f0
MT
975 udfs->dux_commands[OUTBASE + 1] = 0xFE & rngmask;
976 udfs->dux_commands[LOGBASE + 1] = 0;
4e8ad0dc
MK
977
978 /* and the second part */
0a85b6f0
MT
979 udfs->dux_commands[LENBASE + 2] = steps_tmp - steps_tmp / 2;
980 udfs->dux_commands[OPBASE + 2] = 0;
981 udfs->dux_commands[OUTBASE + 2] = 0xFF & rngmask;
982 udfs->dux_commands[LOGBASE + 2] = 0;
4e8ad0dc 983
0a85b6f0 984 udfs->dux_commands[LENBASE + 3] = 1;
4e8ad0dc 985 /* data */
0a85b6f0
MT
986 udfs->dux_commands[OPBASE + 3] = 0x02;
987 udfs->dux_commands[OUTBASE + 3] = 0xFF & rngmask;
988 udfs->dux_commands[LOGBASE + 3] = 0;
4e8ad0dc
MK
989
990 /*
991 * we have 2 states with duration 1: step 6 and
992 * the IDLE state
993 */
f47c697d
BP
994 steps_tmp = steps - 2;
995
996 if (CR_RANGE(cmd->chanlist[0]) > 0)
997 rngmask = 0xff - 0x04;
998 else
999 rngmask = 0xff;
4e8ad0dc
MK
1000
1001 /* do the first part of the delay */
0a85b6f0
MT
1002 udfs->dux_commands[LENBASE + 4] = steps_tmp / 2;
1003 udfs->dux_commands[OPBASE + 4] = 0;
4e8ad0dc 1004 /* reset */
0a85b6f0
MT
1005 udfs->dux_commands[OUTBASE + 4] = (0xFF - 0x02) & rngmask;
1006 udfs->dux_commands[LOGBASE + 4] = 0;
4e8ad0dc
MK
1007
1008 /* and the second part */
0a85b6f0
MT
1009 udfs->dux_commands[LENBASE + 5] = steps_tmp - steps_tmp / 2;
1010 udfs->dux_commands[OPBASE + 5] = 0;
1011 udfs->dux_commands[OUTBASE + 5] = 0xFF & rngmask;
1012 udfs->dux_commands[LOGBASE + 5] = 0;
1013
1014 udfs->dux_commands[LENBASE + 6] = 1;
1015 udfs->dux_commands[OPBASE + 6] = 0;
1016 udfs->dux_commands[OUTBASE + 6] = 0xFF & rngmask;
1017 udfs->dux_commands[LOGBASE + 6] = 0;
f47c697d
BP
1018 break;
1019
1020 case 3:
4e8ad0dc
MK
1021 /*
1022 * three channels
1023 */
f47c697d
BP
1024 for (j = 0; j < 1; j++) {
1025 if (CR_RANGE(cmd->chanlist[j]) > 0)
1026 rngmask = 0xff - 0x04;
1027 else
1028 rngmask = 0xff;
4e8ad0dc
MK
1029 /*
1030 * commit data to the FIFO and do the first part
1031 * of the delay
1032 */
0a85b6f0 1033 udfs->dux_commands[LENBASE + j * 2] = steps / 2;
4e8ad0dc 1034 /* data */
0a85b6f0 1035 udfs->dux_commands[OPBASE + j * 2] = 0x02;
4e8ad0dc 1036 /* no change */
0a85b6f0
MT
1037 udfs->dux_commands[OUTBASE + j * 2] = 0xFF & rngmask;
1038 udfs->dux_commands[LOGBASE + j * 2] = 0;
f47c697d
BP
1039
1040 if (CR_RANGE(cmd->chanlist[j + 1]) > 0)
1041 rngmask = 0xff - 0x04;
1042 else
1043 rngmask = 0xff;
4e8ad0dc
MK
1044
1045 /* do the second part of the delay */
0a85b6f0
MT
1046 udfs->dux_commands[LENBASE + j * 2 + 1] =
1047 steps - steps / 2;
4e8ad0dc 1048 /* no data */
0a85b6f0 1049 udfs->dux_commands[OPBASE + j * 2 + 1] = 0;
4e8ad0dc 1050 /* count */
0a85b6f0
MT
1051 udfs->dux_commands[OUTBASE + j * 2 + 1] =
1052 0xFE & rngmask;
1053 udfs->dux_commands[LOGBASE + j * 2 + 1] = 0;
f47c697d
BP
1054 }
1055
4e8ad0dc 1056 /* 2 steps with duration 1: the idele step and step 6: */
f47c697d 1057 steps_tmp = steps - 2;
4e8ad0dc
MK
1058
1059 /* commit data to the FIFO and do the first part of the delay */
0a85b6f0 1060 udfs->dux_commands[LENBASE + 4] = steps_tmp / 2;
4e8ad0dc 1061 /* data */
0a85b6f0
MT
1062 udfs->dux_commands[OPBASE + 4] = 0x02;
1063 udfs->dux_commands[OUTBASE + 4] = 0xFF & rngmask;
1064 udfs->dux_commands[LOGBASE + 4] = 0;
f47c697d
BP
1065
1066 if (CR_RANGE(cmd->chanlist[0]) > 0)
1067 rngmask = 0xff - 0x04;
1068 else
1069 rngmask = 0xff;
4e8ad0dc
MK
1070
1071 /* do the second part of the delay */
0a85b6f0 1072 udfs->dux_commands[LENBASE + 5] = steps_tmp - steps_tmp / 2;
4e8ad0dc 1073 /* no data */
0a85b6f0 1074 udfs->dux_commands[OPBASE + 5] = 0;
4e8ad0dc 1075 /* reset */
0a85b6f0
MT
1076 udfs->dux_commands[OUTBASE + 5] = (0xFF - 0x02) & rngmask;
1077 udfs->dux_commands[LOGBASE + 5] = 0;
4e8ad0dc 1078
0a85b6f0
MT
1079 udfs->dux_commands[LENBASE + 6] = 1;
1080 udfs->dux_commands[OPBASE + 6] = 0;
1081 udfs->dux_commands[OUTBASE + 6] = 0xFF & rngmask;
1082 udfs->dux_commands[LOGBASE + 6] = 0;
f47c697d
BP
1083
1084 case 16:
1085 if (CR_RANGE(cmd->chanlist[0]) > 0)
1086 rngmask = 0xff - 0x04;
1087 else
1088 rngmask = 0xff;
4e8ad0dc
MK
1089
1090 if (cmd->start_src == TRIG_EXT) {
1091 /*
1092 * we loop here until ready has been set
1093 */
1094
1095 /* branch back to state 0 */
0a85b6f0 1096 udfs->dux_commands[LENBASE + 0] = 0x01;
4e8ad0dc 1097 /* deceision state w/o data */
0a85b6f0 1098 udfs->dux_commands[OPBASE + 0] = 0x01;
4e8ad0dc 1099 /* reset */
0a85b6f0
MT
1100 udfs->dux_commands[OUTBASE + 0] =
1101 (0xFF - 0x02) & rngmask;
4e8ad0dc 1102 /* RDY0 = 0 */
0a85b6f0 1103 udfs->dux_commands[LOGBASE + 0] = 0x00;
4e8ad0dc
MK
1104 } else {
1105 /*
1106 * we just proceed to state 1
1107 */
1108
1109 /* 30us reset pulse */
0a85b6f0
MT
1110 udfs->dux_commands[LENBASE + 0] = 255;
1111 udfs->dux_commands[OPBASE + 0] = 0;
4e8ad0dc 1112 /* reset */
0a85b6f0
MT
1113 udfs->dux_commands[OUTBASE + 0] =
1114 (0xFF - 0x02) & rngmask;
1115 udfs->dux_commands[LOGBASE + 0] = 0;
f47c697d
BP
1116 }
1117
4e8ad0dc 1118 /* commit data to the FIFO */
0a85b6f0 1119 udfs->dux_commands[LENBASE + 1] = 1;
4e8ad0dc 1120 /* data */
0a85b6f0
MT
1121 udfs->dux_commands[OPBASE + 1] = 0x02;
1122 udfs->dux_commands[OUTBASE + 1] = 0xFF & rngmask;
1123 udfs->dux_commands[LOGBASE + 1] = 0;
f47c697d 1124
4e8ad0dc 1125 /* we have 2 states with duration 1 */
f47c697d
BP
1126 steps = steps - 2;
1127
4e8ad0dc 1128 /* do the first part of the delay */
0a85b6f0
MT
1129 udfs->dux_commands[LENBASE + 2] = steps / 2;
1130 udfs->dux_commands[OPBASE + 2] = 0;
1131 udfs->dux_commands[OUTBASE + 2] = 0xFE & rngmask;
1132 udfs->dux_commands[LOGBASE + 2] = 0;
4e8ad0dc
MK
1133
1134 /* and the second part */
0a85b6f0
MT
1135 udfs->dux_commands[LENBASE + 3] = steps - steps / 2;
1136 udfs->dux_commands[OPBASE + 3] = 0;
1137 udfs->dux_commands[OUTBASE + 3] = 0xFF & rngmask;
1138 udfs->dux_commands[LOGBASE + 3] = 0;
4e8ad0dc
MK
1139
1140 /* branch back to state 1 */
0a85b6f0 1141 udfs->dux_commands[LENBASE + 4] = 0x09;
4e8ad0dc 1142 /* deceision state w/o data */
0a85b6f0
MT
1143 udfs->dux_commands[OPBASE + 4] = 0x01;
1144 udfs->dux_commands[OUTBASE + 4] = 0xFF & rngmask;
4e8ad0dc 1145 /* doesn't matter */
0a85b6f0 1146 udfs->dux_commands[LOGBASE + 4] = 0xFF;
f47c697d
BP
1147
1148 break;
1149
1150 default:
4e8ad0dc
MK
1151 printk(KERN_ERR "comedi %d: unsupported combination of "
1152 "channels\n", dev->minor);
1153 up(&udfs->sem);
f47c697d
BP
1154 return -EFAULT;
1155 }
1156
1157#ifdef CONFIG_COMEDI_DEBUG
4e8ad0dc
MK
1158 printk(KERN_DEBUG "comedi %d: sending commands to the usb device\n",
1159 dev->minor);
f47c697d 1160#endif
4e8ad0dc
MK
1161 /* 0 means that the AD commands are sent */
1162 result = send_dux_commands(udfs, SENDADCOMMANDS);
f47c697d 1163 if (result < 0) {
4e8ad0dc
MK
1164 printk(KERN_ERR "comedi%d: adc command could not be submitted."
1165 "Aborting...\n", dev->minor);
1166 up(&udfs->sem);
f47c697d
BP
1167 return result;
1168 }
1169 if (cmd->stop_src == TRIG_COUNT) {
0a85b6f0 1170 udfs->ai_sample_count = cmd->stop_arg * cmd->scan_end_arg;
4e8ad0dc
MK
1171 if (udfs->ai_sample_count < 1) {
1172 printk(KERN_ERR "comedi%d: "
1173 "(cmd->stop_arg)*(cmd->scan_end_arg)<1, "
1174 "aborting.\n", dev->minor);
1175 up(&udfs->sem);
f47c697d
BP
1176 return -EFAULT;
1177 }
4e8ad0dc 1178 udfs->ai_continous = 0;
f47c697d 1179 } else {
4e8ad0dc
MK
1180 /* continous aquisition */
1181 udfs->ai_continous = 1;
1182 udfs->ai_sample_count = 0;
f47c697d
BP
1183 }
1184
1185 if ((cmd->start_src == TRIG_NOW) || (cmd->start_src == TRIG_EXT)) {
4e8ad0dc
MK
1186 /* enable this acquisition operation */
1187 udfs->ai_cmd_running = 1;
1188 ret = usbduxfastsub_submit_InURBs(udfs);
f47c697d 1189 if (ret < 0) {
4e8ad0dc
MK
1190 udfs->ai_cmd_running = 0;
1191 /* fixme: unlink here?? */
1192 up(&udfs->sem);
f47c697d
BP
1193 return ret;
1194 }
1195 s->async->inttrig = NULL;
1196 } else {
4e8ad0dc
MK
1197 /*
1198 * TRIG_INT
1199 * don't enable the acquision operation
1200 * wait for an internal signal
1201 */
f47c697d
BP
1202 s->async->inttrig = usbduxfast_ai_inttrig;
1203 }
4e8ad0dc 1204 up(&udfs->sem);
f47c697d
BP
1205
1206 return 0;
1207}
1208
4e8ad0dc
MK
1209/*
1210 * Mode 0 is used to get a single conversion on demand.
1211 */
71b5f4f1 1212static int usbduxfast_ai_insn_read(struct comedi_device *dev,
0a85b6f0
MT
1213 struct comedi_subdevice *s,
1214 struct comedi_insn *insn, unsigned int *data)
f47c697d
BP
1215{
1216 int i, j, n, actual_length;
1217 int chan, range, rngmask;
1218 int err;
4e8ad0dc 1219 struct usbduxfastsub_s *udfs;
f47c697d 1220
4e8ad0dc
MK
1221 udfs = dev->private;
1222 if (!udfs) {
1223 printk(KERN_ERR "comedi%d: ai_insn_read: no usb dev.\n",
1224 dev->minor);
f47c697d
BP
1225 return -ENODEV;
1226 }
1227#ifdef CONFIG_COMEDI_DEBUG
4e8ad0dc
MK
1228 printk(KERN_DEBUG "comedi%d: ai_insn_read, insn->n=%d, "
1229 "insn->subdev=%d\n", dev->minor, insn->n, insn->subdev);
f47c697d 1230#endif
4e8ad0dc
MK
1231 down(&udfs->sem);
1232 if (!udfs->probed) {
1233 up(&udfs->sem);
f47c697d
BP
1234 return -ENODEV;
1235 }
4e8ad0dc
MK
1236 if (udfs->ai_cmd_running) {
1237 printk(KERN_ERR "comedi%d: ai_insn_read not possible. Async "
1238 "Command is running.\n", dev->minor);
1239 up(&udfs->sem);
f47c697d
BP
1240 return -EBUSY;
1241 }
4e8ad0dc 1242 /* sample one channel */
f47c697d
BP
1243 chan = CR_CHAN(insn->chanspec);
1244 range = CR_RANGE(insn->chanspec);
4e8ad0dc 1245 /* set command for the first channel */
f47c697d
BP
1246
1247 if (range > 0)
1248 rngmask = 0xff - 0x04;
1249 else
1250 rngmask = 0xff;
4e8ad0dc
MK
1251
1252 /* commit data to the FIFO */
0a85b6f0 1253 udfs->dux_commands[LENBASE + 0] = 1;
4e8ad0dc 1254 /* data */
0a85b6f0
MT
1255 udfs->dux_commands[OPBASE + 0] = 0x02;
1256 udfs->dux_commands[OUTBASE + 0] = 0xFF & rngmask;
1257 udfs->dux_commands[LOGBASE + 0] = 0;
4e8ad0dc
MK
1258
1259 /* do the first part of the delay */
0a85b6f0
MT
1260 udfs->dux_commands[LENBASE + 1] = 12;
1261 udfs->dux_commands[OPBASE + 1] = 0;
1262 udfs->dux_commands[OUTBASE + 1] = 0xFE & rngmask;
1263 udfs->dux_commands[LOGBASE + 1] = 0;
1264
1265 udfs->dux_commands[LENBASE + 2] = 1;
1266 udfs->dux_commands[OPBASE + 2] = 0;
1267 udfs->dux_commands[OUTBASE + 2] = 0xFE & rngmask;
1268 udfs->dux_commands[LOGBASE + 2] = 0;
1269
1270 udfs->dux_commands[LENBASE + 3] = 1;
1271 udfs->dux_commands[OPBASE + 3] = 0;
1272 udfs->dux_commands[OUTBASE + 3] = 0xFE & rngmask;
1273 udfs->dux_commands[LOGBASE + 3] = 0;
1274
1275 udfs->dux_commands[LENBASE + 4] = 1;
1276 udfs->dux_commands[OPBASE + 4] = 0;
1277 udfs->dux_commands[OUTBASE + 4] = 0xFE & rngmask;
1278 udfs->dux_commands[LOGBASE + 4] = 0;
4e8ad0dc
MK
1279
1280 /* second part */
0a85b6f0
MT
1281 udfs->dux_commands[LENBASE + 5] = 12;
1282 udfs->dux_commands[OPBASE + 5] = 0;
1283 udfs->dux_commands[OUTBASE + 5] = 0xFF & rngmask;
1284 udfs->dux_commands[LOGBASE + 5] = 0;
4e8ad0dc 1285
0a85b6f0
MT
1286 udfs->dux_commands[LENBASE + 6] = 1;
1287 udfs->dux_commands[OPBASE + 6] = 0;
1288 udfs->dux_commands[OUTBASE + 6] = 0xFF & rngmask;
1289 udfs->dux_commands[LOGBASE + 0] = 0;
f47c697d
BP
1290
1291#ifdef CONFIG_COMEDI_DEBUG
4e8ad0dc
MK
1292 printk(KERN_DEBUG "comedi %d: sending commands to the usb device\n",
1293 dev->minor);
f47c697d 1294#endif
4e8ad0dc
MK
1295 /* 0 means that the AD commands are sent */
1296 err = send_dux_commands(udfs, SENDADCOMMANDS);
f47c697d 1297 if (err < 0) {
4e8ad0dc
MK
1298 printk(KERN_ERR "comedi%d: adc command could not be submitted."
1299 "Aborting...\n", dev->minor);
1300 up(&udfs->sem);
f47c697d
BP
1301 return err;
1302 }
1303#ifdef CONFIG_COMEDI_DEBUG
4e8ad0dc
MK
1304 printk(KERN_DEBUG "comedi%d: usbduxfast: submitting in-urb: "
1305 "0x%p,0x%p\n", udfs->comedidev->minor, udfs->urbIn->context,
1306 udfs->urbIn->dev);
f47c697d
BP
1307#endif
1308 for (i = 0; i < PACKETS_TO_IGNORE; i++) {
4e8ad0dc
MK
1309 err = usb_bulk_msg(udfs->usbdev,
1310 usb_rcvbulkpipe(udfs->usbdev, BULKINEP),
1311 udfs->transfer_buffer, SIZEINBUF,
88676359 1312 &actual_length, 10000);
f47c697d 1313 if (err < 0) {
4e8ad0dc 1314 printk(KERN_ERR "comedi%d: insn timeout. No data.\n",
0a85b6f0 1315 dev->minor);
4e8ad0dc 1316 up(&udfs->sem);
f47c697d
BP
1317 return err;
1318 }
1319 }
4e8ad0dc 1320 /* data points */
f47c697d 1321 for (i = 0; i < insn->n;) {
4e8ad0dc
MK
1322 err = usb_bulk_msg(udfs->usbdev,
1323 usb_rcvbulkpipe(udfs->usbdev, BULKINEP),
1324 udfs->transfer_buffer, SIZEINBUF,
88676359 1325 &actual_length, 10000);
f47c697d 1326 if (err < 0) {
4e8ad0dc 1327 printk(KERN_ERR "comedi%d: insn data error: %d\n",
0a85b6f0 1328 dev->minor, err);
4e8ad0dc 1329 up(&udfs->sem);
f47c697d
BP
1330 return err;
1331 }
1332 n = actual_length / sizeof(uint16_t);
1333 if ((n % 16) != 0) {
4e8ad0dc
MK
1334 printk(KERN_ERR "comedi%d: insn data packet "
1335 "corrupted.\n", dev->minor);
1336 up(&udfs->sem);
f47c697d
BP
1337 return -EINVAL;
1338 }
1339 for (j = chan; (j < n) && (i < insn->n); j = j + 16) {
4e8ad0dc 1340 data[i] = ((uint16_t *) (udfs->transfer_buffer))[j];
f47c697d
BP
1341 i++;
1342 }
1343 }
4e8ad0dc 1344 up(&udfs->sem);
f47c697d
BP
1345 return i;
1346}
1347
f47c697d
BP
1348#define FIRMWARE_MAX_LEN 0x2000
1349
81874ff7 1350static int firmwareUpload(struct usbduxfastsub_s *usbduxfastsub,
0a85b6f0 1351 const u8 * firmwareBinary, int sizeFirmware)
f47c697d 1352{
81874ff7
BP
1353 int ret;
1354 uint8_t *fwBuf;
f47c697d 1355
81874ff7
BP
1356 if (!firmwareBinary)
1357 return 0;
f47c697d 1358
0a85b6f0 1359 if (sizeFirmware > FIRMWARE_MAX_LEN) {
81874ff7
BP
1360 dev_err(&usbduxfastsub->interface->dev,
1361 "comedi_: usbduxfast firmware binary it too large for FX2.\n");
1362 return -ENOMEM;
1363 }
4e8ad0dc 1364
81874ff7
BP
1365 /* we generate a local buffer for the firmware */
1366 fwBuf = kzalloc(sizeFirmware, GFP_KERNEL);
1367 if (!fwBuf) {
1368 dev_err(&usbduxfastsub->interface->dev,
1369 "comedi_: mem alloc for firmware failed\n");
1370 return -ENOMEM;
1371 }
0a85b6f0 1372 memcpy(fwBuf, firmwareBinary, sizeFirmware);
f47c697d 1373
81874ff7
BP
1374 ret = usbduxfastsub_stop(usbduxfastsub);
1375 if (ret < 0) {
1376 dev_err(&usbduxfastsub->interface->dev,
1377 "comedi_: can not stop firmware\n");
1378 kfree(fwBuf);
1379 return ret;
1380 }
f47c697d 1381
81874ff7
BP
1382 ret = usbduxfastsub_upload(usbduxfastsub, fwBuf, 0, sizeFirmware);
1383 if (ret < 0) {
1384 dev_err(&usbduxfastsub->interface->dev,
1385 "comedi_: firmware upload failed\n");
1386 kfree(fwBuf);
1387 return ret;
f47c697d 1388 }
81874ff7
BP
1389 ret = usbduxfastsub_start(usbduxfastsub);
1390 if (ret < 0) {
1391 dev_err(&usbduxfastsub->interface->dev,
1392 "comedi_: can not start firmware\n");
1393 kfree(fwBuf);
1394 return ret;
1395 }
1396 kfree(fwBuf);
1397 return 0;
f47c697d
BP
1398}
1399
4e8ad0dc 1400static void tidy_up(struct usbduxfastsub_s *udfs)
f47c697d
BP
1401{
1402#ifdef CONFIG_COMEDI_DEBUG
4e8ad0dc 1403 printk(KERN_DEBUG "comedi_: usbduxfast: tiding up\n");
f47c697d 1404#endif
4e8ad0dc
MK
1405
1406 if (!udfs)
f47c697d 1407 return;
6fffdb35 1408
4e8ad0dc
MK
1409 /* shows the usb subsystem that the driver is down */
1410 if (udfs->interface)
1411 usb_set_intfdata(udfs->interface, NULL);
f47c697d 1412
4e8ad0dc 1413 udfs->probed = 0;
f47c697d 1414
4e8ad0dc
MK
1415 if (udfs->urbIn) {
1416 /* waits until a running transfer is over */
1417 usb_kill_urb(udfs->urbIn);
1418
1419 kfree(udfs->transfer_buffer);
1420 udfs->transfer_buffer = NULL;
1421
1422 usb_free_urb(udfs->urbIn);
1423 udfs->urbIn = NULL;
f47c697d 1424 }
4e8ad0dc
MK
1425
1426 kfree(udfs->insnBuffer);
1427 udfs->insnBuffer = NULL;
1428
1429 kfree(udfs->dux_commands);
1430 udfs->dux_commands = NULL;
1431
1432 udfs->ai_cmd_running = 0;
f47c697d
BP
1433}
1434
0a85b6f0
MT
1435static void usbduxfast_firmware_request_complete_handler(const struct firmware
1436 *fw, void *context)
6742c0af
BP
1437{
1438 struct usbduxfastsub_s *usbduxfastsub_tmp = context;
1439 struct usb_device *usbdev = usbduxfastsub_tmp->usbdev;
1440 int ret;
1441
1442 if (fw == NULL)
1443 return;
1444
1445 /*
1446 * we need to upload the firmware here because fw will be
1447 * freed once we've left this function
1448 */
81874ff7 1449 ret = firmwareUpload(usbduxfastsub_tmp, fw->data, fw->size);
6742c0af
BP
1450
1451 if (ret) {
1452 dev_err(&usbdev->dev,
0a85b6f0 1453 "Could not upload firmware (err=%d)\n", ret);
6742c0af
BP
1454 return;
1455 }
1456
1457 comedi_usb_auto_config(usbdev, BOARDNAME);
1458}
1459
4e8ad0dc
MK
1460/*
1461 * allocate memory for the urbs and initialise them
1462 */
f47c697d 1463static int usbduxfastsub_probe(struct usb_interface *uinterf,
0a85b6f0 1464 const struct usb_device_id *id)
f47c697d
BP
1465{
1466 struct usb_device *udev = interface_to_usbdev(uinterf);
f47c697d
BP
1467 int i;
1468 int index;
6742c0af 1469 int ret;
f47c697d
BP
1470
1471 if (udev->speed != USB_SPEED_HIGH) {
4e8ad0dc
MK
1472 printk(KERN_ERR "comedi_: usbduxfast_: This driver needs"
1473 "USB 2.0 to operate. Aborting...\n");
88676359 1474 return -ENODEV;
f47c697d
BP
1475 }
1476#ifdef CONFIG_COMEDI_DEBUG
4e8ad0dc
MK
1477 printk(KERN_DEBUG "comedi_: usbduxfast_: finding a free structure for "
1478 "the usb-device\n");
f47c697d
BP
1479#endif
1480 down(&start_stop_sem);
4e8ad0dc 1481 /* look for a free place in the usbduxfast array */
f47c697d
BP
1482 index = -1;
1483 for (i = 0; i < NUMUSBDUXFAST; i++) {
4e8ad0dc 1484 if (!usbduxfastsub[i].probed) {
f47c697d
BP
1485 index = i;
1486 break;
1487 }
1488 }
1489
4e8ad0dc 1490 /* no more space */
f47c697d 1491 if (index == -1) {
4e8ad0dc 1492 printk(KERN_ERR "Too many usbduxfast-devices connected.\n");
f47c697d 1493 up(&start_stop_sem);
88676359 1494 return -EMFILE;
f47c697d
BP
1495 }
1496#ifdef CONFIG_COMEDI_DEBUG
4e8ad0dc
MK
1497 printk(KERN_DEBUG "comedi_: usbduxfast: usbduxfastsub[%d] is ready to "
1498 "connect to comedi.\n", index);
f47c697d
BP
1499#endif
1500
1501 init_MUTEX(&(usbduxfastsub[index].sem));
4e8ad0dc 1502 /* save a pointer to the usb device */
f47c697d
BP
1503 usbduxfastsub[index].usbdev = udev;
1504
4e8ad0dc 1505 /* save the interface itself */
f47c697d 1506 usbduxfastsub[index].interface = uinterf;
4e8ad0dc 1507 /* get the interface number from the interface */
f47c697d 1508 usbduxfastsub[index].ifnum = uinterf->altsetting->desc.bInterfaceNumber;
4e8ad0dc
MK
1509 /*
1510 * hand the private data over to the usb subsystem
1511 * will be needed for disconnect
1512 */
f47c697d 1513 usb_set_intfdata(uinterf, &(usbduxfastsub[index]));
f47c697d
BP
1514
1515#ifdef CONFIG_COMEDI_DEBUG
4e8ad0dc
MK
1516 printk(KERN_DEBUG "comedi_: usbduxfast: ifnum=%d\n",
1517 usbduxfastsub[index].ifnum);
f47c697d 1518#endif
4e8ad0dc 1519 /* create space for the commands going to the usb device */
f47c697d 1520 usbduxfastsub[index].dux_commands = kmalloc(SIZEOFDUXBUFFER,
4e8ad0dc 1521 GFP_KERNEL);
f47c697d 1522 if (!usbduxfastsub[index].dux_commands) {
4e8ad0dc
MK
1523 printk(KERN_ERR "comedi_: usbduxfast: error alloc space for "
1524 "dac commands\n");
f47c697d
BP
1525 tidy_up(&(usbduxfastsub[index]));
1526 up(&start_stop_sem);
88676359 1527 return -ENOMEM;
f47c697d 1528 }
4e8ad0dc 1529 /* create space of the instruction buffer */
f47c697d 1530 usbduxfastsub[index].insnBuffer = kmalloc(SIZEINSNBUF, GFP_KERNEL);
4e8ad0dc
MK
1531 if (!usbduxfastsub[index].insnBuffer) {
1532 printk(KERN_ERR "comedi_: usbduxfast: could not alloc space "
1533 "for insnBuffer\n");
f47c697d
BP
1534 tidy_up(&(usbduxfastsub[index]));
1535 up(&start_stop_sem);
88676359 1536 return -ENOMEM;
f47c697d 1537 }
4e8ad0dc 1538 /* setting to alternate setting 1: enabling bulk ep */
f47c697d 1539 i = usb_set_interface(usbduxfastsub[index].usbdev,
0a85b6f0 1540 usbduxfastsub[index].ifnum, 1);
f47c697d 1541 if (i < 0) {
4e8ad0dc
MK
1542 printk(KERN_ERR "comedi_: usbduxfast%d: could not switch to "
1543 "alternate setting 1.\n", index);
f47c697d
BP
1544 tidy_up(&(usbduxfastsub[index]));
1545 up(&start_stop_sem);
88676359 1546 return -ENODEV;
f47c697d 1547 }
88676359 1548 usbduxfastsub[index].urbIn = usb_alloc_urb(0, GFP_KERNEL);
4e8ad0dc
MK
1549 if (!usbduxfastsub[index].urbIn) {
1550 printk(KERN_ERR "comedi_: usbduxfast%d: Could not alloc."
1551 "urb\n", index);
f47c697d
BP
1552 tidy_up(&(usbduxfastsub[index]));
1553 up(&start_stop_sem);
88676359 1554 return -ENOMEM;
f47c697d
BP
1555 }
1556 usbduxfastsub[index].transfer_buffer = kmalloc(SIZEINBUF, GFP_KERNEL);
4e8ad0dc
MK
1557 if (!usbduxfastsub[index].transfer_buffer) {
1558 printk(KERN_ERR "comedi_: usbduxfast%d: could not alloc. "
1559 "transb.\n", index);
f47c697d
BP
1560 tidy_up(&(usbduxfastsub[index]));
1561 up(&start_stop_sem);
88676359 1562 return -ENOMEM;
f47c697d 1563 }
4e8ad0dc 1564 /* we've reached the bottom of the function */
f47c697d
BP
1565 usbduxfastsub[index].probed = 1;
1566 up(&start_stop_sem);
6742c0af
BP
1567
1568 ret = request_firmware_nowait(THIS_MODULE,
1569 FW_ACTION_HOTPLUG,
81874ff7 1570 "usbduxfast_firmware.bin",
6742c0af
BP
1571 &udev->dev,
1572 usbduxfastsub + index,
1573 usbduxfast_firmware_request_complete_handler);
1574
1575 if (ret) {
0a85b6f0 1576 dev_err(&udev->dev, "could not load firmware (err=%d)\n", ret);
6742c0af
BP
1577 return ret;
1578 }
1579
4e8ad0dc
MK
1580 printk(KERN_INFO "comedi_: usbduxfast%d has been successfully "
1581 "initialized.\n", index);
1582 /* success */
f47c697d 1583 return 0;
f47c697d
BP
1584}
1585
f47c697d
BP
1586static void usbduxfastsub_disconnect(struct usb_interface *intf)
1587{
4e8ad0dc 1588 struct usbduxfastsub_s *udfs = usb_get_intfdata(intf);
f47c697d 1589 struct usb_device *udev = interface_to_usbdev(intf);
6fffdb35 1590
4e8ad0dc
MK
1591 if (!udfs) {
1592 printk(KERN_ERR "comedi_: usbduxfast: disconnect called with "
1593 "null pointer.\n");
f47c697d
BP
1594 return;
1595 }
4e8ad0dc
MK
1596 if (udfs->usbdev != udev) {
1597 printk(KERN_ERR "comedi_: usbduxfast: BUG! called with wrong "
1598 "ptr!!!\n");
f47c697d
BP
1599 return;
1600 }
6742c0af
BP
1601
1602 comedi_usb_auto_unconfig(udev);
1603
f47c697d 1604 down(&start_stop_sem);
4e8ad0dc
MK
1605 down(&udfs->sem);
1606 tidy_up(udfs);
1607 up(&udfs->sem);
f47c697d 1608 up(&start_stop_sem);
4e8ad0dc 1609
f47c697d 1610#ifdef CONFIG_COMEDI_DEBUG
4e8ad0dc 1611 printk(KERN_DEBUG "comedi_: usbduxfast: disconnected from the usb\n");
f47c697d
BP
1612#endif
1613}
1614
4e8ad0dc
MK
1615/*
1616 * is called when comedi-config is called
1617 */
0a85b6f0
MT
1618static int usbduxfast_attach(struct comedi_device *dev,
1619 struct comedi_devconfig *it)
f47c697d
BP
1620{
1621 int ret;
1622 int index;
1623 int i;
34c43922 1624 struct comedi_subdevice *s = NULL;
f47c697d
BP
1625 dev->private = NULL;
1626
1627 down(&start_stop_sem);
4e8ad0dc
MK
1628 /*
1629 * find a valid device which has been detected by the
1630 * probe function of the usb
1631 */
f47c697d
BP
1632 index = -1;
1633 for (i = 0; i < NUMUSBDUXFAST; i++) {
4e8ad0dc 1634 if (usbduxfastsub[i].probed && !usbduxfastsub[i].attached) {
f47c697d
BP
1635 index = i;
1636 break;
1637 }
1638 }
1639
1640 if (index < 0) {
4e8ad0dc
MK
1641 printk(KERN_ERR "comedi%d: usbduxfast: error: attach failed, "
1642 "no usbduxfast devs connected to the usb bus.\n",
1643 dev->minor);
f47c697d
BP
1644 up(&start_stop_sem);
1645 return -ENODEV;
1646 }
1647
1648 down(&(usbduxfastsub[index].sem));
4e8ad0dc 1649 /* pointer back to the corresponding comedi device */
f47c697d
BP
1650 usbduxfastsub[index].comedidev = dev;
1651
4e8ad0dc 1652 /* trying to upload the firmware into the chip */
f47c697d 1653 if (comedi_aux_data(it->options, 0) &&
6742c0af 1654 it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
81874ff7
BP
1655 firmwareUpload(&usbduxfastsub[index],
1656 comedi_aux_data(it->options, 0),
1657 it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]);
f47c697d
BP
1658 }
1659
1660 dev->board_name = BOARDNAME;
1661
1662 /* set number of subdevices */
1663 dev->n_subdevices = N_SUBDEVICES;
1664
4e8ad0dc
MK
1665 /* allocate space for the subdevices */
1666 ret = alloc_subdevices(dev, N_SUBDEVICES);
1667 if (ret < 0) {
1668 printk(KERN_ERR "comedi%d: usbduxfast: error alloc space for "
1669 "subdev\n", dev->minor);
e57795a1 1670 up(&(usbduxfastsub[index].sem));
f47c697d
BP
1671 up(&start_stop_sem);
1672 return ret;
1673 }
1674
4e8ad0dc
MK
1675 printk(KERN_INFO "comedi%d: usbduxfast: usb-device %d is attached to "
1676 "comedi.\n", dev->minor, index);
1677 /* private structure is also simply the usb-structure */
f47c697d 1678 dev->private = usbduxfastsub + index;
4e8ad0dc 1679 /* the first subdevice is the A/D converter */
f47c697d 1680 s = dev->subdevices + SUBDEV_AD;
4e8ad0dc
MK
1681 /*
1682 * the URBs get the comedi subdevice which is responsible for reading
1683 * this is the subdevice which reads data
1684 */
f47c697d 1685 dev->read_subdev = s;
4e8ad0dc 1686 /* the subdevice receives as private structure the usb-structure */
f47c697d 1687 s->private = NULL;
4e8ad0dc 1688 /* analog input */
f47c697d 1689 s->type = COMEDI_SUBD_AI;
4e8ad0dc 1690 /* readable and ref is to ground */
f47c697d 1691 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
4e8ad0dc 1692 /* 16 channels */
f47c697d 1693 s->n_chan = 16;
4e8ad0dc 1694 /* length of the channellist */
f47c697d 1695 s->len_chanlist = 16;
4e8ad0dc 1696 /* callback functions */
f47c697d
BP
1697 s->insn_read = usbduxfast_ai_insn_read;
1698 s->do_cmdtest = usbduxfast_ai_cmdtest;
1699 s->do_cmd = usbduxfast_ai_cmd;
1700 s->cancel = usbduxfast_ai_cancel;
4e8ad0dc 1701 /* max value from the A/D converter (12bit+1 bit for overflow) */
f47c697d 1702 s->maxdata = 0x1000;
4e8ad0dc 1703 /* range table to convert to physical units */
f47c697d
BP
1704 s->range_table = &range_usbduxfast_ai_range;
1705
4e8ad0dc 1706 /* finally decide that it's attached */
f47c697d
BP
1707 usbduxfastsub[index].attached = 1;
1708
1709 up(&(usbduxfastsub[index].sem));
f47c697d 1710 up(&start_stop_sem);
4e8ad0dc
MK
1711 printk(KERN_INFO "comedi%d: successfully attached to usbduxfast.\n",
1712 dev->minor);
f47c697d
BP
1713
1714 return 0;
1715}
1716
71b5f4f1 1717static int usbduxfast_detach(struct comedi_device *dev)
f47c697d 1718{
4e8ad0dc 1719 struct usbduxfastsub_s *udfs;
f47c697d 1720
f47c697d 1721 if (!dev) {
4e8ad0dc
MK
1722 printk(KERN_ERR "comedi?: usbduxfast: detach without dev "
1723 "variable...\n");
f47c697d
BP
1724 return -EFAULT;
1725 }
98ccdc56 1726#ifdef CONFIG_COMEDI_DEBUG
4e8ad0dc
MK
1727 printk(KERN_DEBUG "comedi%d: usbduxfast: detach usb device\n",
1728 dev->minor);
98ccdc56
JL
1729#endif
1730
4e8ad0dc
MK
1731 udfs = dev->private;
1732 if (!udfs) {
1733 printk(KERN_ERR "comedi?: usbduxfast: detach without ptr to "
1734 "usbduxfastsub[]\n");
f47c697d
BP
1735 return -EFAULT;
1736 }
1737
4e8ad0dc 1738 down(&udfs->sem);
f47c697d 1739 down(&start_stop_sem);
4e8ad0dc
MK
1740 /*
1741 * Don't allow detach to free the private structure
1742 * It's one entry of of usbduxfastsub[]
1743 */
f47c697d 1744 dev->private = NULL;
4e8ad0dc
MK
1745 udfs->attached = 0;
1746 udfs->comedidev = NULL;
f47c697d 1747#ifdef CONFIG_COMEDI_DEBUG
4e8ad0dc
MK
1748 printk(KERN_DEBUG "comedi%d: usbduxfast: detach: successfully "
1749 "removed\n", dev->minor);
f47c697d
BP
1750#endif
1751 up(&start_stop_sem);
4e8ad0dc 1752 up(&udfs->sem);
f47c697d
BP
1753 return 0;
1754}
1755
4e8ad0dc
MK
1756/*
1757 * main driver struct
1758 */
139dfbdf 1759static struct comedi_driver driver_usbduxfast = {
0a85b6f0
MT
1760 .driver_name = "usbduxfast",
1761 .module = THIS_MODULE,
1762 .attach = usbduxfast_attach,
1763 .detach = usbduxfast_detach
f47c697d
BP
1764};
1765
4e8ad0dc
MK
1766/*
1767 * Table with the USB-devices: just now only testing IDs
1768 */
f47c697d 1769static struct usb_device_id usbduxfastsub_table[] = {
4e8ad0dc 1770 /* { USB_DEVICE(0x4b4, 0x8613) }, testing */
0a85b6f0
MT
1771 {USB_DEVICE(0x13d8, 0x0010)}, /* real ID */
1772 {USB_DEVICE(0x13d8, 0x0011)}, /* real ID */
1773 {} /* Terminating entry */
f47c697d
BP
1774};
1775
1776MODULE_DEVICE_TABLE(usb, usbduxfastsub_table);
1777
4e8ad0dc
MK
1778/*
1779 * The usbduxfastsub-driver
1780 */
f47c697d
BP
1781static struct usb_driver usbduxfastsub_driver = {
1782#ifdef COMEDI_HAVE_USB_DRIVER_OWNER
0a85b6f0 1783 .owner = THIS_MODULE,
f47c697d 1784#endif
0a85b6f0
MT
1785 .name = BOARDNAME,
1786 .probe = usbduxfastsub_probe,
1787 .disconnect = usbduxfastsub_disconnect,
1788 .id_table = usbduxfastsub_table
f47c697d
BP
1789};
1790
4e8ad0dc
MK
1791/*
1792 * Can't use the nice macro as I have also to initialise the USB subsystem:
1793 * registering the usb-system _and_ the comedi-driver
1794 */
7dcb582c 1795static int __init init_usbduxfast(void)
f47c697d 1796{
4e8ad0dc
MK
1797 printk(KERN_INFO
1798 KBUILD_MODNAME ": " DRIVER_VERSION ":" DRIVER_DESC "\n");
f47c697d
BP
1799 usb_register(&usbduxfastsub_driver);
1800 comedi_driver_register(&driver_usbduxfast);
1801 return 0;
1802}
1803
4e8ad0dc
MK
1804/*
1805 * deregistering the comedi driver and the usb-subsystem
1806 */
7dcb582c 1807static void __exit exit_usbduxfast(void)
f47c697d
BP
1808{
1809 comedi_driver_unregister(&driver_usbduxfast);
1810 usb_deregister(&usbduxfastsub_driver);
1811}
1812
1813module_init(init_usbduxfast);
1814module_exit(exit_usbduxfast);
1815
1816MODULE_AUTHOR(DRIVER_AUTHOR);
1817MODULE_DESCRIPTION(DRIVER_DESC);
1818MODULE_LICENSE("GPL");