]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/staging/comedi/drivers/dt3000.c
Staging: windbond: camelCase should be fixed
[mirror_ubuntu-artful-kernel.git] / drivers / staging / comedi / drivers / dt3000.c
CommitLineData
9a21297d
DS
1/*
2 comedi/drivers/dt3000.c
3 Data Translation DT3000 series driver
4
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 1999 David A. Schleef <ds@schleef.org>
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: dt3000
25Description: Data Translation DT3000 series
26Author: ds
27Devices: [Data Translation] DT3001 (dt3000), DT3001-PGL, DT3002, DT3003,
28 DT3003-PGL, DT3004, DT3005, DT3004-200
29Updated: Mon, 14 Apr 2008 15:41:24 +0100
30Status: works
31
32Configuration Options:
33 [0] - PCI bus of device (optional)
34 [1] - PCI slot of device (optional)
35 If bus/slot is not specified, the first supported
36 PCI device found will be used.
37
38There is code to support AI commands, but it may not work.
39
40AO commands are not supported.
41*/
42
43/*
44 The DT3000 series is Data Translation's attempt to make a PCI
45 data acquisition board. The design of this series is very nice,
46 since each board has an on-board DSP (Texas Instruments TMS320C52).
47 However, a few details are a little annoying. The boards lack
48 bus-mastering DMA, which eliminates them from serious work.
49 They also are not capable of autocalibration, which is a common
50 feature in modern hardware. The default firmware is pretty bad,
51 making it nearly impossible to write an RT compatible driver.
52 It would make an interesting project to write a decent firmware
53 for these boards.
54
55 Data Translation originally wanted an NDA for the documentation
56 for the 3k series. However, if you ask nicely, they might send
57 you the docs without one, also.
58*/
59
60#define DEBUG 1
61
25436dc9 62#include <linux/interrupt.h>
9a21297d
DS
63#include "../comedidev.h"
64#include <linux/delay.h>
65
66#include "comedi_pci.h"
67
68#define PCI_VENDOR_ID_DT 0x1116
69
9ced1de6 70static const struct comedi_lrange range_dt3000_ai = { 4, {
0a85b6f0
MT
71 RANGE(-10, 10),
72 RANGE(-5, 5),
73 RANGE(-2.5, 2.5),
74 RANGE(-1.25, 1.25)
75 }
9a21297d 76};
0a85b6f0 77
9ced1de6 78static const struct comedi_lrange range_dt3000_ai_pgl = { 4, {
0a85b6f0
MT
79 RANGE(-10, 10),
80 RANGE(-1, 1),
81 RANGE(-0.1, 0.1),
82 RANGE(-0.02, 0.02)
83 }
9a21297d
DS
84};
85
c14e9208
BP
86struct dt3k_boardtype {
87
9a21297d
DS
88 const char *name;
89 unsigned int device_id;
90 int adchan;
91 int adbits;
92 int ai_speed;
9ced1de6 93 const struct comedi_lrange *adrange;
9a21297d
DS
94 int dachan;
95 int dabits;
c14e9208
BP
96};
97
c14e9208 98static const struct dt3k_boardtype dt3k_boardtypes[] = {
68c3dbff
BP
99 {.name = "dt3001",
100 .device_id = 0x22,
101 .adchan = 16,
102 .adbits = 12,
103 .adrange = &range_dt3000_ai,
104 .ai_speed = 3000,
105 .dachan = 2,
106 .dabits = 12,
0a85b6f0 107 },
68c3dbff
BP
108 {.name = "dt3001-pgl",
109 .device_id = 0x27,
110 .adchan = 16,
111 .adbits = 12,
112 .adrange = &range_dt3000_ai_pgl,
113 .ai_speed = 3000,
114 .dachan = 2,
115 .dabits = 12,
0a85b6f0 116 },
68c3dbff
BP
117 {.name = "dt3002",
118 .device_id = 0x23,
119 .adchan = 32,
120 .adbits = 12,
121 .adrange = &range_dt3000_ai,
122 .ai_speed = 3000,
123 .dachan = 0,
124 .dabits = 0,
0a85b6f0 125 },
68c3dbff
BP
126 {.name = "dt3003",
127 .device_id = 0x24,
128 .adchan = 64,
129 .adbits = 12,
130 .adrange = &range_dt3000_ai,
131 .ai_speed = 3000,
132 .dachan = 2,
133 .dabits = 12,
0a85b6f0 134 },
68c3dbff
BP
135 {.name = "dt3003-pgl",
136 .device_id = 0x28,
137 .adchan = 64,
138 .adbits = 12,
139 .adrange = &range_dt3000_ai_pgl,
140 .ai_speed = 3000,
141 .dachan = 2,
142 .dabits = 12,
0a85b6f0 143 },
68c3dbff
BP
144 {.name = "dt3004",
145 .device_id = 0x25,
146 .adchan = 16,
147 .adbits = 16,
148 .adrange = &range_dt3000_ai,
149 .ai_speed = 10000,
150 .dachan = 2,
151 .dabits = 12,
0a85b6f0
MT
152 },
153 {.name = "dt3005", /* a.k.a. 3004-200 */
68c3dbff
BP
154 .device_id = 0x26,
155 .adchan = 16,
156 .adbits = 16,
157 .adrange = &range_dt3000_ai,
158 .ai_speed = 5000,
159 .dachan = 2,
160 .dabits = 12,
0a85b6f0 161 },
9a21297d
DS
162};
163
c14e9208
BP
164#define n_dt3k_boards sizeof(dt3k_boardtypes)/sizeof(struct dt3k_boardtype)
165#define this_board ((const struct dt3k_boardtype *)dev->board_ptr)
9a21297d
DS
166
167static DEFINE_PCI_DEVICE_TABLE(dt3k_pci_table) = {
0a85b6f0
MT
168 {
169 PCI_VENDOR_ID_DT, 0x0022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
170 PCI_VENDOR_ID_DT, 0x0027, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
171 PCI_VENDOR_ID_DT, 0x0023, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
172 PCI_VENDOR_ID_DT, 0x0024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
173 PCI_VENDOR_ID_DT, 0x0028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
174 PCI_VENDOR_ID_DT, 0x0025, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
175 PCI_VENDOR_ID_DT, 0x0026, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
176 0}
9a21297d
DS
177};
178
179MODULE_DEVICE_TABLE(pci, dt3k_pci_table);
180
181#define DT3000_SIZE (4*0x1000)
182
183/* dual-ported RAM location definitions */
184
185#define DPR_DAC_buffer (4*0x000)
186#define DPR_ADC_buffer (4*0x800)
187#define DPR_Command (4*0xfd3)
188#define DPR_SubSys (4*0xfd3)
189#define DPR_Encode (4*0xfd4)
190#define DPR_Params(a) (4*(0xfd5+(a)))
191#define DPR_Tick_Reg_Lo (4*0xff5)
192#define DPR_Tick_Reg_Hi (4*0xff6)
193#define DPR_DA_Buf_Front (4*0xff7)
194#define DPR_DA_Buf_Rear (4*0xff8)
195#define DPR_AD_Buf_Front (4*0xff9)
196#define DPR_AD_Buf_Rear (4*0xffa)
197#define DPR_Int_Mask (4*0xffb)
198#define DPR_Intr_Flag (4*0xffc)
199#define DPR_Response_Mbx (4*0xffe)
200#define DPR_Command_Mbx (4*0xfff)
201
202#define AI_FIFO_DEPTH 2003
203#define AO_FIFO_DEPTH 2048
204
205/* command list */
206
207#define CMD_GETBRDINFO 0
208#define CMD_CONFIG 1
209#define CMD_GETCONFIG 2
210#define CMD_START 3
211#define CMD_STOP 4
212#define CMD_READSINGLE 5
213#define CMD_WRITESINGLE 6
214#define CMD_CALCCLOCK 7
215#define CMD_READEVENTS 8
216#define CMD_WRITECTCTRL 16
217#define CMD_READCTCTRL 17
218#define CMD_WRITECT 18
219#define CMD_READCT 19
220#define CMD_WRITEDATA 32
221#define CMD_READDATA 33
222#define CMD_WRITEIO 34
223#define CMD_READIO 35
224#define CMD_WRITECODE 36
225#define CMD_READCODE 37
226#define CMD_EXECUTE 38
227#define CMD_HALT 48
228
229#define SUBS_AI 0
230#define SUBS_AO 1
231#define SUBS_DIN 2
232#define SUBS_DOUT 3
233#define SUBS_MEM 4
234#define SUBS_CT 5
235
236/* interrupt flags */
237#define DT3000_CMDONE 0x80
238#define DT3000_CTDONE 0x40
239#define DT3000_DAHWERR 0x20
240#define DT3000_DASWERR 0x10
241#define DT3000_DAEMPTY 0x08
242#define DT3000_ADHWERR 0x04
243#define DT3000_ADSWERR 0x02
244#define DT3000_ADFULL 0x01
245
246#define DT3000_COMPLETION_MASK 0xff00
247#define DT3000_COMMAND_MASK 0x00ff
248#define DT3000_NOTPROCESSED 0x0000
249#define DT3000_NOERROR 0x5500
250#define DT3000_ERROR 0xaa00
251#define DT3000_NOTSUPPORTED 0xff00
252
253#define DT3000_EXTERNAL_CLOCK 1
254#define DT3000_RISING_EDGE 2
255
256#define TMODE_MASK 0x1c
257
258#define DT3000_AD_TRIG_INTERNAL (0<<2)
259#define DT3000_AD_TRIG_EXTERNAL (1<<2)
260#define DT3000_AD_RETRIG_INTERNAL (2<<2)
261#define DT3000_AD_RETRIG_EXTERNAL (3<<2)
262#define DT3000_AD_EXTRETRIG (4<<2)
263
264#define DT3000_CHANNEL_MODE_SE 0
265#define DT3000_CHANNEL_MODE_DI 1
266
b81c8035
BP
267struct dt3k_private {
268
9a21297d
DS
269 struct pci_dev *pci_dev;
270 resource_size_t phys_addr;
271 void *io_addr;
272 unsigned int lock;
790c5541 273 unsigned int ao_readback[2];
9a21297d
DS
274 unsigned int ai_front;
275 unsigned int ai_rear;
b81c8035
BP
276};
277
278#define devpriv ((struct dt3k_private *)dev->private)
9a21297d 279
0a85b6f0
MT
280static int dt3000_attach(struct comedi_device *dev,
281 struct comedi_devconfig *it);
da91b269 282static int dt3000_detach(struct comedi_device *dev);
139dfbdf 283static struct comedi_driver driver_dt3000 = {
68c3dbff
BP
284 .driver_name = "dt3000",
285 .module = THIS_MODULE,
286 .attach = dt3000_attach,
287 .detach = dt3000_detach,
9a21297d
DS
288};
289
290COMEDI_PCI_INITCLEANUP(driver_dt3000, dt3k_pci_table);
291
0a85b6f0
MT
292static void dt3k_ai_empty_fifo(struct comedi_device *dev,
293 struct comedi_subdevice *s);
9a21297d 294static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *arg,
0a85b6f0
MT
295 unsigned int round_mode);
296static int dt3k_ai_cancel(struct comedi_device *dev,
297 struct comedi_subdevice *s);
9a21297d
DS
298#ifdef DEBUG
299static void debug_intr_flags(unsigned int flags);
300#endif
301
302#define TIMEOUT 100
303
da91b269 304static int dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
9a21297d
DS
305{
306 int i;
307 unsigned int status = 0;
308
309 writew(cmd, devpriv->io_addr + DPR_Command_Mbx);
310
311 for (i = 0; i < TIMEOUT; i++) {
312 status = readw(devpriv->io_addr + DPR_Command_Mbx);
313 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED)
314 break;
5f74ea14 315 udelay(1);
9a21297d
DS
316 }
317 if ((status & DT3000_COMPLETION_MASK) == DT3000_NOERROR) {
318 return 0;
319 }
320
321 printk("dt3k_send_cmd() timeout/error status=0x%04x\n", status);
322
323 return -ETIME;
324}
325
0a85b6f0
MT
326static unsigned int dt3k_readsingle(struct comedi_device *dev,
327 unsigned int subsys, unsigned int chan,
328 unsigned int gain)
9a21297d
DS
329{
330 writew(subsys, devpriv->io_addr + DPR_SubSys);
331
332 writew(chan, devpriv->io_addr + DPR_Params(0));
333 writew(gain, devpriv->io_addr + DPR_Params(1));
334
335 dt3k_send_cmd(dev, CMD_READSINGLE);
336
337 return readw(devpriv->io_addr + DPR_Params(2));
338}
339
da91b269 340static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
0a85b6f0 341 unsigned int chan, unsigned int data)
9a21297d
DS
342{
343 writew(subsys, devpriv->io_addr + DPR_SubSys);
344
345 writew(chan, devpriv->io_addr + DPR_Params(0));
346 writew(0, devpriv->io_addr + DPR_Params(1));
347 writew(data, devpriv->io_addr + DPR_Params(2));
348
349 dt3k_send_cmd(dev, CMD_WRITESINGLE);
350}
351
352static int debug_n_ints = 0;
353
2696fb57
BP
354/* FIXME! Assumes shared interrupt is for this card. */
355/* What's this debug_n_ints stuff? Obviously needs some work... */
70265d24 356static irqreturn_t dt3k_interrupt(int irq, void *d)
9a21297d 357{
71b5f4f1 358 struct comedi_device *dev = d;
34c43922 359 struct comedi_subdevice *s;
9a21297d
DS
360 unsigned int status;
361
362 if (!dev->attached) {
363 return IRQ_NONE;
364 }
365
366 s = dev->subdevices + 0;
367 status = readw(devpriv->io_addr + DPR_Intr_Flag);
368#ifdef DEBUG
369 debug_intr_flags(status);
370#endif
371
372 if (status & DT3000_ADFULL) {
373 dt3k_ai_empty_fifo(dev, s);
374 s->async->events |= COMEDI_CB_BLOCK;
375 }
376
377 if (status & (DT3000_ADSWERR | DT3000_ADHWERR)) {
378 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
379 }
380
381 debug_n_ints++;
382 if (debug_n_ints >= 10) {
383 dt3k_ai_cancel(dev, s);
384 s->async->events |= COMEDI_CB_EOA;
385 }
386
387 comedi_event(dev, s);
388 return IRQ_HANDLED;
389}
390
391#ifdef DEBUG
392static char *intr_flags[] = {
393 "AdFull", "AdSwError", "AdHwError", "DaEmpty",
394 "DaSwError", "DaHwError", "CtDone", "CmDone",
395};
0a85b6f0 396
9a21297d
DS
397static void debug_intr_flags(unsigned int flags)
398{
399 int i;
400 printk("dt3k: intr_flags:");
401 for (i = 0; i < 8; i++) {
402 if (flags & (1 << i)) {
403 printk(" %s", intr_flags[i]);
404 }
405 }
406 printk("\n");
407}
408#endif
409
0a85b6f0
MT
410static void dt3k_ai_empty_fifo(struct comedi_device *dev,
411 struct comedi_subdevice *s)
9a21297d
DS
412{
413 int front;
414 int rear;
415 int count;
416 int i;
790c5541 417 short data;
9a21297d
DS
418
419 front = readw(devpriv->io_addr + DPR_AD_Buf_Front);
420 count = front - devpriv->ai_front;
421 if (count < 0)
422 count += AI_FIFO_DEPTH;
423
424 printk("reading %d samples\n", count);
425
426 rear = devpriv->ai_rear;
427
428 for (i = 0; i < count; i++) {
429 data = readw(devpriv->io_addr + DPR_ADC_buffer + rear);
430 comedi_buf_put(s->async, data);
431 rear++;
432 if (rear >= AI_FIFO_DEPTH)
433 rear = 0;
434 }
435
436 devpriv->ai_rear = rear;
437 writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear);
438}
439
0a85b6f0
MT
440static int dt3k_ai_cmdtest(struct comedi_device *dev,
441 struct comedi_subdevice *s, struct comedi_cmd *cmd)
9a21297d
DS
442{
443 int err = 0;
444 int tmp;
445
446 /* step 1: make sure trigger sources are trivially valid */
447
448 tmp = cmd->start_src;
449 cmd->start_src &= TRIG_NOW;
450 if (!cmd->start_src || tmp != cmd->start_src)
451 err++;
452
453 tmp = cmd->scan_begin_src;
454 cmd->scan_begin_src &= TRIG_TIMER;
455 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
456 err++;
457
458 tmp = cmd->convert_src;
459 cmd->convert_src &= TRIG_TIMER;
460 if (!cmd->convert_src || tmp != cmd->convert_src)
461 err++;
462
463 tmp = cmd->scan_end_src;
464 cmd->scan_end_src &= TRIG_COUNT;
465 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
466 err++;
467
468 tmp = cmd->stop_src;
469 cmd->stop_src &= TRIG_COUNT;
470 if (!cmd->stop_src || tmp != cmd->stop_src)
471 err++;
472
473 if (err)
474 return 1;
475
476 /* step 2: make sure trigger sources are unique and mutually compatible */
477
478 if (err)
479 return 2;
480
481 /* step 3: make sure arguments are trivially compatible */
482
483 if (cmd->start_arg != 0) {
484 cmd->start_arg = 0;
485 err++;
486 }
487
488 if (cmd->scan_begin_src == TRIG_TIMER) {
489 if (cmd->scan_begin_arg < this_board->ai_speed) {
490 cmd->scan_begin_arg = this_board->ai_speed;
491 err++;
492 }
493 if (cmd->scan_begin_arg > 100 * 16 * 65535) {
494 cmd->scan_begin_arg = 100 * 16 * 65535;
495 err++;
496 }
497 } else {
498 /* not supported */
499 }
500 if (cmd->convert_src == TRIG_TIMER) {
501 if (cmd->convert_arg < this_board->ai_speed) {
502 cmd->convert_arg = this_board->ai_speed;
503 err++;
504 }
505 if (cmd->convert_arg > 50 * 16 * 65535) {
506 cmd->convert_arg = 50 * 16 * 65535;
507 err++;
508 }
509 } else {
510 /* not supported */
511 }
512
513 if (cmd->scan_end_arg != cmd->chanlist_len) {
514 cmd->scan_end_arg = cmd->chanlist_len;
515 err++;
516 }
517 if (cmd->stop_src == TRIG_COUNT) {
518 if (cmd->stop_arg > 0x00ffffff) {
519 cmd->stop_arg = 0x00ffffff;
520 err++;
521 }
522 } else {
523 /* TRIG_NONE */
524 if (cmd->stop_arg != 0) {
525 cmd->stop_arg = 0;
526 err++;
527 }
528 }
529
530 if (err)
531 return 3;
532
533 /* step 4: fix up any arguments */
534
535 if (cmd->scan_begin_src == TRIG_TIMER) {
536 tmp = cmd->scan_begin_arg;
537 dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
0a85b6f0 538 cmd->flags & TRIG_ROUND_MASK);
9a21297d
DS
539 if (tmp != cmd->scan_begin_arg)
540 err++;
541 } else {
542 /* not supported */
543 }
544 if (cmd->convert_src == TRIG_TIMER) {
545 tmp = cmd->convert_arg;
546 dt3k_ns_to_timer(50, &cmd->convert_arg,
0a85b6f0 547 cmd->flags & TRIG_ROUND_MASK);
9a21297d
DS
548 if (tmp != cmd->convert_arg)
549 err++;
550 if (cmd->scan_begin_src == TRIG_TIMER &&
0a85b6f0
MT
551 cmd->scan_begin_arg <
552 cmd->convert_arg * cmd->scan_end_arg) {
9a21297d 553 cmd->scan_begin_arg =
0a85b6f0 554 cmd->convert_arg * cmd->scan_end_arg;
9a21297d
DS
555 err++;
556 }
557 } else {
558 /* not supported */
559 }
560
561 if (err)
562 return 4;
563
564 return 0;
565}
566
567static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
0a85b6f0 568 unsigned int round_mode)
9a21297d
DS
569{
570 int divider, base, prescale;
571
572 /* This function needs improvment */
573 /* Don't know if divider==0 works. */
574
575 for (prescale = 0; prescale < 16; prescale++) {
576 base = timer_base * (prescale + 1);
577 switch (round_mode) {
578 case TRIG_ROUND_NEAREST:
579 default:
580 divider = (*nanosec + base / 2) / base;
581 break;
582 case TRIG_ROUND_DOWN:
583 divider = (*nanosec) / base;
584 break;
585 case TRIG_ROUND_UP:
586 divider = (*nanosec) / base;
587 break;
588 }
589 if (divider < 65536) {
590 *nanosec = divider * base;
591 return (prescale << 16) | (divider);
592 }
593 }
594
595 prescale = 15;
596 base = timer_base * (1 << prescale);
597 divider = 65535;
598 *nanosec = divider * base;
599 return (prescale << 16) | (divider);
600}
601
da91b269 602static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
9a21297d 603{
ea6d0d4c 604 struct comedi_cmd *cmd = &s->async->cmd;
9a21297d
DS
605 int i;
606 unsigned int chan, range, aref;
607 unsigned int divider;
608 unsigned int tscandiv;
609 int ret;
610 unsigned int mode;
611
612 printk("dt3k_ai_cmd:\n");
613 for (i = 0; i < cmd->chanlist_len; i++) {
614 chan = CR_CHAN(cmd->chanlist[i]);
615 range = CR_RANGE(cmd->chanlist[i]);
616
617 writew((range << 6) | chan,
0a85b6f0 618 devpriv->io_addr + DPR_ADC_buffer + i);
9a21297d
DS
619 }
620 aref = CR_AREF(cmd->chanlist[0]);
621
622 writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0));
623 printk("param[0]=0x%04x\n", cmd->scan_end_arg);
624
625 if (cmd->convert_src == TRIG_TIMER) {
626 divider = dt3k_ns_to_timer(50, &cmd->convert_arg,
0a85b6f0 627 cmd->flags & TRIG_ROUND_MASK);
9a21297d
DS
628 writew((divider >> 16), devpriv->io_addr + DPR_Params(1));
629 printk("param[1]=0x%04x\n", divider >> 16);
630 writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2));
631 printk("param[2]=0x%04x\n", divider & 0xffff);
632 } else {
633 /* not supported */
634 }
635
636 if (cmd->scan_begin_src == TRIG_TIMER) {
637 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
0a85b6f0 638 cmd->flags & TRIG_ROUND_MASK);
9a21297d
DS
639 writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3));
640 printk("param[3]=0x%04x\n", tscandiv >> 16);
641 writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4));
642 printk("param[4]=0x%04x\n", tscandiv & 0xffff);
643 } else {
644 /* not supported */
645 }
646
647 mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
648 writew(mode, devpriv->io_addr + DPR_Params(5));
649 printk("param[5]=0x%04x\n", mode);
650 writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6));
651 printk("param[6]=0x%04x\n", aref == AREF_DIFF);
652
653 writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7));
654 printk("param[7]=0x%04x\n", AI_FIFO_DEPTH / 2);
655
656 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
657 ret = dt3k_send_cmd(dev, CMD_CONFIG);
658
659 writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
0a85b6f0 660 devpriv->io_addr + DPR_Int_Mask);
9a21297d
DS
661
662 debug_n_ints = 0;
663
664 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
665 ret = dt3k_send_cmd(dev, CMD_START);
666
667 return 0;
668}
669
da91b269 670static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
9a21297d
DS
671{
672 int ret;
673
674 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
675 ret = dt3k_send_cmd(dev, CMD_STOP);
676
677 writew(0, devpriv->io_addr + DPR_Int_Mask);
678
679 return 0;
680}
681
da91b269 682static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 683 struct comedi_insn *insn, unsigned int *data)
9a21297d
DS
684{
685 int i;
686 unsigned int chan, gain, aref;
687
688 chan = CR_CHAN(insn->chanspec);
689 gain = CR_RANGE(insn->chanspec);
690 /* XXX docs don't explain how to select aref */
691 aref = CR_AREF(insn->chanspec);
692
693 for (i = 0; i < insn->n; i++) {
694 data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
695 }
696
697 return i;
698}
699
da91b269 700static int dt3k_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 701 struct comedi_insn *insn, unsigned int *data)
9a21297d
DS
702{
703 int i;
704 unsigned int chan;
705
706 chan = CR_CHAN(insn->chanspec);
707 for (i = 0; i < insn->n; i++) {
708 dt3k_writesingle(dev, SUBS_AO, chan, data[i]);
709 devpriv->ao_readback[chan] = data[i];
710 }
711
712 return i;
713}
714
0a85b6f0
MT
715static int dt3k_ao_insn_read(struct comedi_device *dev,
716 struct comedi_subdevice *s,
717 struct comedi_insn *insn, unsigned int *data)
9a21297d
DS
718{
719 int i;
720 unsigned int chan;
721
722 chan = CR_CHAN(insn->chanspec);
723 for (i = 0; i < insn->n; i++) {
724 data[i] = devpriv->ao_readback[chan];
725 }
726
727 return i;
728}
729
da91b269 730static void dt3k_dio_config(struct comedi_device *dev, int bits)
9a21297d
DS
731{
732 /* XXX */
733 writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys);
734
735 writew(bits, devpriv->io_addr + DPR_Params(0));
736#if 0
737 /* don't know */
738 writew(0, devpriv->io_addr + DPR_Params(1));
739 writew(0, devpriv->io_addr + DPR_Params(2));
740#endif
741
742 dt3k_send_cmd(dev, CMD_CONFIG);
743}
744
0a85b6f0
MT
745static int dt3k_dio_insn_config(struct comedi_device *dev,
746 struct comedi_subdevice *s,
747 struct comedi_insn *insn, unsigned int *data)
9a21297d
DS
748{
749 int mask;
750
751 mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
752
753 switch (data[0]) {
754 case INSN_CONFIG_DIO_OUTPUT:
755 s->io_bits |= mask;
756 break;
757 case INSN_CONFIG_DIO_INPUT:
758 s->io_bits &= ~mask;
759 break;
760 case INSN_CONFIG_DIO_QUERY:
761 data[1] =
0a85b6f0
MT
762 (s->
763 io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
764 COMEDI_INPUT;
9a21297d
DS
765 return insn->n;
766 break;
767 default:
768 return -EINVAL;
769 break;
770 }
771 mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3);
772 dt3k_dio_config(dev, mask);
773
774 return insn->n;
775}
776
0a85b6f0
MT
777static int dt3k_dio_insn_bits(struct comedi_device *dev,
778 struct comedi_subdevice *s,
779 struct comedi_insn *insn, unsigned int *data)
9a21297d
DS
780{
781 if (insn->n != 2)
782 return -EINVAL;
783
784 if (data[0]) {
785 s->state &= ~data[0];
786 s->state |= data[1] & data[0];
787 dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
788 }
789 data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
790
791 return 2;
792}
793
0a85b6f0
MT
794static int dt3k_mem_insn_read(struct comedi_device *dev,
795 struct comedi_subdevice *s,
796 struct comedi_insn *insn, unsigned int *data)
9a21297d
DS
797{
798 unsigned int addr = CR_CHAN(insn->chanspec);
799 int i;
800
801 for (i = 0; i < insn->n; i++) {
802 writew(SUBS_MEM, devpriv->io_addr + DPR_SubSys);
803 writew(addr, devpriv->io_addr + DPR_Params(0));
804 writew(1, devpriv->io_addr + DPR_Params(1));
805
806 dt3k_send_cmd(dev, CMD_READCODE);
807
808 data[i] = readw(devpriv->io_addr + DPR_Params(2));
809 }
810
811 return i;
812}
813
da91b269 814static int dt_pci_probe(struct comedi_device *dev, int bus, int slot);
9a21297d 815
da91b269 816static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
9a21297d 817{
34c43922 818 struct comedi_subdevice *s;
9a21297d
DS
819 int bus, slot;
820 int ret = 0;
821
822 printk("dt3000:");
823 bus = it->options[0];
824 slot = it->options[1];
825
c3744138
BP
826 ret = alloc_private(dev, sizeof(struct dt3k_private));
827 if (ret < 0)
9a21297d
DS
828 return ret;
829
830 ret = dt_pci_probe(dev, bus, slot);
831 if (ret < 0)
832 return ret;
833 if (ret == 0) {
834 printk(" no DT board found\n");
835 return -ENODEV;
836 }
837
838 dev->board_name = this_board->name;
839
5f74ea14
GKH
840 if (request_irq(devpriv->pci_dev->irq, dt3k_interrupt, IRQF_SHARED,
841 "dt3000", dev)) {
9a21297d
DS
842 printk(" unable to allocate IRQ %u\n", devpriv->pci_dev->irq);
843 return -EINVAL;
844 }
845 dev->irq = devpriv->pci_dev->irq;
846
c3744138
BP
847 ret = alloc_subdevices(dev, 4);
848 if (ret < 0)
9a21297d
DS
849 return ret;
850
851 s = dev->subdevices;
852 dev->read_subdev = s;
853
854 /* ai subdevice */
855 s->type = COMEDI_SUBD_AI;
856 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
857 s->n_chan = this_board->adchan;
858 s->insn_read = dt3k_ai_insn;
859 s->maxdata = (1 << this_board->adbits) - 1;
860 s->len_chanlist = 512;
861 s->range_table = &range_dt3000_ai; /* XXX */
862 s->do_cmd = dt3k_ai_cmd;
863 s->do_cmdtest = dt3k_ai_cmdtest;
864 s->cancel = dt3k_ai_cancel;
865
866 s++;
867 /* ao subsystem */
868 s->type = COMEDI_SUBD_AO;
869 s->subdev_flags = SDF_WRITABLE;
870 s->n_chan = 2;
871 s->insn_read = dt3k_ao_insn_read;
872 s->insn_write = dt3k_ao_insn;
873 s->maxdata = (1 << this_board->dabits) - 1;
874 s->len_chanlist = 1;
875 s->range_table = &range_bipolar10;
876
877 s++;
878 /* dio subsystem */
879 s->type = COMEDI_SUBD_DIO;
880 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
881 s->n_chan = 8;
882 s->insn_config = dt3k_dio_insn_config;
883 s->insn_bits = dt3k_dio_insn_bits;
884 s->maxdata = 1;
885 s->len_chanlist = 8;
886 s->range_table = &range_digital;
887
888 s++;
889 /* mem subsystem */
890 s->type = COMEDI_SUBD_MEMORY;
891 s->subdev_flags = SDF_READABLE;
892 s->n_chan = 0x1000;
893 s->insn_read = dt3k_mem_insn_read;
894 s->maxdata = 0xff;
895 s->len_chanlist = 1;
896 s->range_table = &range_unknown;
897
898#if 0
899 s++;
900 /* proc subsystem */
901 s->type = COMEDI_SUBD_PROC;
902#endif
903
904 return 0;
905}
906
da91b269 907static int dt3000_detach(struct comedi_device *dev)
9a21297d
DS
908{
909 if (dev->irq)
5f74ea14 910 free_irq(dev->irq, dev);
9a21297d
DS
911
912 if (devpriv) {
913 if (devpriv->pci_dev) {
914 if (devpriv->phys_addr) {
915 comedi_pci_disable(devpriv->pci_dev);
916 }
917 pci_dev_put(devpriv->pci_dev);
918 }
919 if (devpriv->io_addr)
920 iounmap(devpriv->io_addr);
921 }
922 /* XXX */
923
924 return 0;
925}
926
927static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board);
da91b269 928static int setup_pci(struct comedi_device *dev);
9a21297d 929
da91b269 930static int dt_pci_probe(struct comedi_device *dev, int bus, int slot)
9a21297d
DS
931{
932 int board;
933 int ret;
934 struct pci_dev *pcidev;
935
936 pcidev = NULL;
937 while ((pcidev = dt_pci_find_device(pcidev, &board)) != NULL) {
938 if ((bus == 0 && slot == 0) ||
0a85b6f0
MT
939 (pcidev->bus->number == bus &&
940 PCI_SLOT(pcidev->devfn) == slot)) {
9a21297d
DS
941 break;
942 }
943 }
944 devpriv->pci_dev = pcidev;
945
946 if (board >= 0)
947 dev->board_ptr = dt3k_boardtypes + board;
948
949 if (!devpriv->pci_dev)
950 return 0;
951
c3744138
BP
952 ret = setup_pci(dev);
953 if (ret < 0)
9a21297d
DS
954 return ret;
955
956 return 1;
957}
958
da91b269 959static int setup_pci(struct comedi_device *dev)
9a21297d
DS
960{
961 resource_size_t addr;
962 int ret;
963
964 ret = comedi_pci_enable(devpriv->pci_dev, "dt3000");
965 if (ret < 0)
966 return ret;
967
968 addr = pci_resource_start(devpriv->pci_dev, 0);
969 devpriv->phys_addr = addr;
970 devpriv->io_addr = ioremap(devpriv->phys_addr, DT3000_SIZE);
971 if (!devpriv->io_addr)
972 return -ENOMEM;
973#if DEBUG
974 printk("0x%08llx mapped to %p, ",
0a85b6f0 975 (unsigned long long)devpriv->phys_addr, devpriv->io_addr);
9a21297d
DS
976#endif
977
978 return 0;
979}
980
981static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board)
982{
983 int i;
984
985 for (from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from);
0a85b6f0
MT
986 from != NULL;
987 from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from)) {
9a21297d
DS
988 for (i = 0; i < n_dt3k_boards; i++) {
989 if (from->device == dt3k_boardtypes[i].device_id) {
990 *board = i;
991 return from;
992 }
993 }
0a85b6f0
MT
994 printk
995 ("unknown Data Translation PCI device found with device_id=0x%04x\n",
996 from->device);
9a21297d
DS
997 }
998 *board = -1;
999 return from;
1000}