GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / drivers / staging / comedi / drivers / dt3000.c
blob9996168c82f5bbfd34f3344d2be4593187f9ed35
1 /*
2 comedi/drivers/dt3000.c
3 Data Translation DT3000 series driver
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 1999 David A. Schleef <ds@schleef.org>
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.
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.
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.
24 Driver: dt3000
25 Description: Data Translation DT3000 series
26 Author: ds
27 Devices: [Data Translation] DT3001 (dt3000), DT3001-PGL, DT3002, DT3003,
28 DT3003-PGL, DT3004, DT3005, DT3004-200
29 Updated: Mon, 14 Apr 2008 15:41:24 +0100
30 Status: works
32 Configuration 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.
38 There is code to support AI commands, but it may not work.
40 AO commands are not supported.
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.
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.
60 #define DEBUG 1
62 #include <linux/interrupt.h>
63 #include "../comedidev.h"
64 #include <linux/delay.h>
66 #include "comedi_pci.h"
68 #define PCI_VENDOR_ID_DT 0x1116
70 static const struct comedi_lrange range_dt3000_ai = { 4, {
71 RANGE(-10, 10),
72 RANGE(-5, 5),
73 RANGE(-2.5, 2.5),
74 RANGE(-1.25, 1.25)
78 static const struct comedi_lrange range_dt3000_ai_pgl = { 4, {
79 RANGE(-10, 10),
80 RANGE(-1, 1),
81 RANGE(-0.1, 0.1),
82 RANGE(-0.02, 0.02)
86 struct dt3k_boardtype {
88 const char *name;
89 unsigned int device_id;
90 int adchan;
91 int adbits;
92 int ai_speed;
93 const struct comedi_lrange *adrange;
94 int dachan;
95 int dabits;
98 static const struct dt3k_boardtype dt3k_boardtypes[] = {
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,
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,
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,
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,
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,
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,
153 {.name = "dt3005", /* a.k.a. 3004-200 */
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,
164 #define n_dt3k_boards sizeof(dt3k_boardtypes)/sizeof(struct dt3k_boardtype)
165 #define this_board ((const struct dt3k_boardtype *)dev->board_ptr)
167 static DEFINE_PCI_DEVICE_TABLE(dt3k_pci_table) = {
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}, {
179 MODULE_DEVICE_TABLE(pci, dt3k_pci_table);
181 #define DT3000_SIZE (4*0x1000)
183 /* dual-ported RAM location definitions */
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)
202 #define AI_FIFO_DEPTH 2003
203 #define AO_FIFO_DEPTH 2048
205 /* command list */
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
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
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
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
253 #define DT3000_EXTERNAL_CLOCK 1
254 #define DT3000_RISING_EDGE 2
256 #define TMODE_MASK 0x1c
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)
264 #define DT3000_CHANNEL_MODE_SE 0
265 #define DT3000_CHANNEL_MODE_DI 1
267 struct dt3k_private {
269 struct pci_dev *pci_dev;
270 resource_size_t phys_addr;
271 void *io_addr;
272 unsigned int lock;
273 unsigned int ao_readback[2];
274 unsigned int ai_front;
275 unsigned int ai_rear;
278 #define devpriv ((struct dt3k_private *)dev->private)
280 static int dt3000_attach(struct comedi_device *dev,
281 struct comedi_devconfig *it);
282 static int dt3000_detach(struct comedi_device *dev);
283 static struct comedi_driver driver_dt3000 = {
284 .driver_name = "dt3000",
285 .module = THIS_MODULE,
286 .attach = dt3000_attach,
287 .detach = dt3000_detach,
290 static int __devinit driver_dt3000_pci_probe(struct pci_dev *dev,
291 const struct pci_device_id *ent)
293 return comedi_pci_auto_config(dev, driver_dt3000.driver_name);
296 static void __devexit driver_dt3000_pci_remove(struct pci_dev *dev)
298 comedi_pci_auto_unconfig(dev);
301 static struct pci_driver driver_dt3000_pci_driver = {
302 .id_table = dt3k_pci_table,
303 .probe = &driver_dt3000_pci_probe,
304 .remove = __devexit_p(&driver_dt3000_pci_remove)
307 static int __init driver_dt3000_init_module(void)
309 int retval;
311 retval = comedi_driver_register(&driver_dt3000);
312 if (retval < 0)
313 return retval;
315 driver_dt3000_pci_driver.name = (char *)driver_dt3000.driver_name;
316 return pci_register_driver(&driver_dt3000_pci_driver);
319 static void __exit driver_dt3000_cleanup_module(void)
321 pci_unregister_driver(&driver_dt3000_pci_driver);
322 comedi_driver_unregister(&driver_dt3000);
325 module_init(driver_dt3000_init_module);
326 module_exit(driver_dt3000_cleanup_module);
328 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
329 struct comedi_subdevice *s);
330 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *arg,
331 unsigned int round_mode);
332 static int dt3k_ai_cancel(struct comedi_device *dev,
333 struct comedi_subdevice *s);
334 #ifdef DEBUG
335 static void debug_intr_flags(unsigned int flags);
336 #endif
338 #define TIMEOUT 100
340 static int dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
342 int i;
343 unsigned int status = 0;
345 writew(cmd, devpriv->io_addr + DPR_Command_Mbx);
347 for (i = 0; i < TIMEOUT; i++) {
348 status = readw(devpriv->io_addr + DPR_Command_Mbx);
349 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED)
350 break;
351 udelay(1);
353 if ((status & DT3000_COMPLETION_MASK) == DT3000_NOERROR)
354 return 0;
356 printk("dt3k_send_cmd() timeout/error status=0x%04x\n", status);
358 return -ETIME;
361 static unsigned int dt3k_readsingle(struct comedi_device *dev,
362 unsigned int subsys, unsigned int chan,
363 unsigned int gain)
365 writew(subsys, devpriv->io_addr + DPR_SubSys);
367 writew(chan, devpriv->io_addr + DPR_Params(0));
368 writew(gain, devpriv->io_addr + DPR_Params(1));
370 dt3k_send_cmd(dev, CMD_READSINGLE);
372 return readw(devpriv->io_addr + DPR_Params(2));
375 static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
376 unsigned int chan, unsigned int data)
378 writew(subsys, devpriv->io_addr + DPR_SubSys);
380 writew(chan, devpriv->io_addr + DPR_Params(0));
381 writew(0, devpriv->io_addr + DPR_Params(1));
382 writew(data, devpriv->io_addr + DPR_Params(2));
384 dt3k_send_cmd(dev, CMD_WRITESINGLE);
387 static int debug_n_ints = 0;
389 /* What's this debug_n_ints stuff? Obviously needs some work... */
390 static irqreturn_t dt3k_interrupt(int irq, void *d)
392 struct comedi_device *dev = d;
393 struct comedi_subdevice *s;
394 unsigned int status;
396 if (!dev->attached)
397 return IRQ_NONE;
399 s = dev->subdevices + 0;
400 status = readw(devpriv->io_addr + DPR_Intr_Flag);
401 #ifdef DEBUG
402 debug_intr_flags(status);
403 #endif
405 if (status & DT3000_ADFULL) {
406 dt3k_ai_empty_fifo(dev, s);
407 s->async->events |= COMEDI_CB_BLOCK;
410 if (status & (DT3000_ADSWERR | DT3000_ADHWERR))
411 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
413 debug_n_ints++;
414 if (debug_n_ints >= 10) {
415 dt3k_ai_cancel(dev, s);
416 s->async->events |= COMEDI_CB_EOA;
419 comedi_event(dev, s);
420 return IRQ_HANDLED;
423 #ifdef DEBUG
424 static char *intr_flags[] = {
425 "AdFull", "AdSwError", "AdHwError", "DaEmpty",
426 "DaSwError", "DaHwError", "CtDone", "CmDone",
429 static void debug_intr_flags(unsigned int flags)
431 int i;
432 printk("dt3k: intr_flags:");
433 for (i = 0; i < 8; i++) {
434 if (flags & (1 << i))
435 printk(" %s", intr_flags[i]);
437 printk("\n");
439 #endif
441 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
442 struct comedi_subdevice *s)
444 int front;
445 int rear;
446 int count;
447 int i;
448 short data;
450 front = readw(devpriv->io_addr + DPR_AD_Buf_Front);
451 count = front - devpriv->ai_front;
452 if (count < 0)
453 count += AI_FIFO_DEPTH;
455 printk("reading %d samples\n", count);
457 rear = devpriv->ai_rear;
459 for (i = 0; i < count; i++) {
460 data = readw(devpriv->io_addr + DPR_ADC_buffer + rear);
461 comedi_buf_put(s->async, data);
462 rear++;
463 if (rear >= AI_FIFO_DEPTH)
464 rear = 0;
467 devpriv->ai_rear = rear;
468 writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear);
471 static int dt3k_ai_cmdtest(struct comedi_device *dev,
472 struct comedi_subdevice *s, struct comedi_cmd *cmd)
474 int err = 0;
475 int tmp;
477 /* step 1: make sure trigger sources are trivially valid */
479 tmp = cmd->start_src;
480 cmd->start_src &= TRIG_NOW;
481 if (!cmd->start_src || tmp != cmd->start_src)
482 err++;
484 tmp = cmd->scan_begin_src;
485 cmd->scan_begin_src &= TRIG_TIMER;
486 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
487 err++;
489 tmp = cmd->convert_src;
490 cmd->convert_src &= TRIG_TIMER;
491 if (!cmd->convert_src || tmp != cmd->convert_src)
492 err++;
494 tmp = cmd->scan_end_src;
495 cmd->scan_end_src &= TRIG_COUNT;
496 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
497 err++;
499 tmp = cmd->stop_src;
500 cmd->stop_src &= TRIG_COUNT;
501 if (!cmd->stop_src || tmp != cmd->stop_src)
502 err++;
504 if (err)
505 return 1;
507 /* step 2: make sure trigger sources are unique and mutually compatible */
509 if (err)
510 return 2;
512 /* step 3: make sure arguments are trivially compatible */
514 if (cmd->start_arg != 0) {
515 cmd->start_arg = 0;
516 err++;
519 if (cmd->scan_begin_src == TRIG_TIMER) {
520 if (cmd->scan_begin_arg < this_board->ai_speed) {
521 cmd->scan_begin_arg = this_board->ai_speed;
522 err++;
524 if (cmd->scan_begin_arg > 100 * 16 * 65535) {
525 cmd->scan_begin_arg = 100 * 16 * 65535;
526 err++;
528 } else {
529 /* not supported */
531 if (cmd->convert_src == TRIG_TIMER) {
532 if (cmd->convert_arg < this_board->ai_speed) {
533 cmd->convert_arg = this_board->ai_speed;
534 err++;
536 if (cmd->convert_arg > 50 * 16 * 65535) {
537 cmd->convert_arg = 50 * 16 * 65535;
538 err++;
540 } else {
541 /* not supported */
544 if (cmd->scan_end_arg != cmd->chanlist_len) {
545 cmd->scan_end_arg = cmd->chanlist_len;
546 err++;
548 if (cmd->stop_src == TRIG_COUNT) {
549 if (cmd->stop_arg > 0x00ffffff) {
550 cmd->stop_arg = 0x00ffffff;
551 err++;
553 } else {
554 /* TRIG_NONE */
555 if (cmd->stop_arg != 0) {
556 cmd->stop_arg = 0;
557 err++;
561 if (err)
562 return 3;
564 /* step 4: fix up any arguments */
566 if (cmd->scan_begin_src == TRIG_TIMER) {
567 tmp = cmd->scan_begin_arg;
568 dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
569 cmd->flags & TRIG_ROUND_MASK);
570 if (tmp != cmd->scan_begin_arg)
571 err++;
572 } else {
573 /* not supported */
575 if (cmd->convert_src == TRIG_TIMER) {
576 tmp = cmd->convert_arg;
577 dt3k_ns_to_timer(50, &cmd->convert_arg,
578 cmd->flags & TRIG_ROUND_MASK);
579 if (tmp != cmd->convert_arg)
580 err++;
581 if (cmd->scan_begin_src == TRIG_TIMER &&
582 cmd->scan_begin_arg <
583 cmd->convert_arg * cmd->scan_end_arg) {
584 cmd->scan_begin_arg =
585 cmd->convert_arg * cmd->scan_end_arg;
586 err++;
588 } else {
589 /* not supported */
592 if (err)
593 return 4;
595 return 0;
598 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
599 unsigned int round_mode)
601 int divider, base, prescale;
603 /* This function needs improvment */
604 /* Don't know if divider==0 works. */
606 for (prescale = 0; prescale < 16; prescale++) {
607 base = timer_base * (prescale + 1);
608 switch (round_mode) {
609 case TRIG_ROUND_NEAREST:
610 default:
611 divider = (*nanosec + base / 2) / base;
612 break;
613 case TRIG_ROUND_DOWN:
614 divider = (*nanosec) / base;
615 break;
616 case TRIG_ROUND_UP:
617 divider = (*nanosec) / base;
618 break;
620 if (divider < 65536) {
621 *nanosec = divider * base;
622 return (prescale << 16) | (divider);
626 prescale = 15;
627 base = timer_base * (1 << prescale);
628 divider = 65535;
629 *nanosec = divider * base;
630 return (prescale << 16) | (divider);
633 static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
635 struct comedi_cmd *cmd = &s->async->cmd;
636 int i;
637 unsigned int chan, range, aref;
638 unsigned int divider;
639 unsigned int tscandiv;
640 int ret;
641 unsigned int mode;
643 printk("dt3k_ai_cmd:\n");
644 for (i = 0; i < cmd->chanlist_len; i++) {
645 chan = CR_CHAN(cmd->chanlist[i]);
646 range = CR_RANGE(cmd->chanlist[i]);
648 writew((range << 6) | chan,
649 devpriv->io_addr + DPR_ADC_buffer + i);
651 aref = CR_AREF(cmd->chanlist[0]);
653 writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0));
654 printk("param[0]=0x%04x\n", cmd->scan_end_arg);
656 if (cmd->convert_src == TRIG_TIMER) {
657 divider = dt3k_ns_to_timer(50, &cmd->convert_arg,
658 cmd->flags & TRIG_ROUND_MASK);
659 writew((divider >> 16), devpriv->io_addr + DPR_Params(1));
660 printk("param[1]=0x%04x\n", divider >> 16);
661 writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2));
662 printk("param[2]=0x%04x\n", divider & 0xffff);
663 } else {
664 /* not supported */
667 if (cmd->scan_begin_src == TRIG_TIMER) {
668 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
669 cmd->flags & TRIG_ROUND_MASK);
670 writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3));
671 printk("param[3]=0x%04x\n", tscandiv >> 16);
672 writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4));
673 printk("param[4]=0x%04x\n", tscandiv & 0xffff);
674 } else {
675 /* not supported */
678 mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
679 writew(mode, devpriv->io_addr + DPR_Params(5));
680 printk("param[5]=0x%04x\n", mode);
681 writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6));
682 printk("param[6]=0x%04x\n", aref == AREF_DIFF);
684 writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7));
685 printk("param[7]=0x%04x\n", AI_FIFO_DEPTH / 2);
687 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
688 ret = dt3k_send_cmd(dev, CMD_CONFIG);
690 writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
691 devpriv->io_addr + DPR_Int_Mask);
693 debug_n_ints = 0;
695 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
696 ret = dt3k_send_cmd(dev, CMD_START);
698 return 0;
701 static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
703 int ret;
705 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
706 ret = dt3k_send_cmd(dev, CMD_STOP);
708 writew(0, devpriv->io_addr + DPR_Int_Mask);
710 return 0;
713 static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
714 struct comedi_insn *insn, unsigned int *data)
716 int i;
717 unsigned int chan, gain, aref;
719 chan = CR_CHAN(insn->chanspec);
720 gain = CR_RANGE(insn->chanspec);
721 aref = CR_AREF(insn->chanspec);
723 for (i = 0; i < insn->n; i++)
724 data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
726 return i;
729 static int dt3k_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
730 struct comedi_insn *insn, unsigned int *data)
732 int i;
733 unsigned int chan;
735 chan = CR_CHAN(insn->chanspec);
736 for (i = 0; i < insn->n; i++) {
737 dt3k_writesingle(dev, SUBS_AO, chan, data[i]);
738 devpriv->ao_readback[chan] = data[i];
741 return i;
744 static int dt3k_ao_insn_read(struct comedi_device *dev,
745 struct comedi_subdevice *s,
746 struct comedi_insn *insn, unsigned int *data)
748 int i;
749 unsigned int chan;
751 chan = CR_CHAN(insn->chanspec);
752 for (i = 0; i < insn->n; i++)
753 data[i] = devpriv->ao_readback[chan];
755 return i;
758 static void dt3k_dio_config(struct comedi_device *dev, int bits)
760 writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys);
762 writew(bits, devpriv->io_addr + DPR_Params(0));
764 dt3k_send_cmd(dev, CMD_CONFIG);
767 static int dt3k_dio_insn_config(struct comedi_device *dev,
768 struct comedi_subdevice *s,
769 struct comedi_insn *insn, unsigned int *data)
771 int mask;
773 mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
775 switch (data[0]) {
776 case INSN_CONFIG_DIO_OUTPUT:
777 s->io_bits |= mask;
778 break;
779 case INSN_CONFIG_DIO_INPUT:
780 s->io_bits &= ~mask;
781 break;
782 case INSN_CONFIG_DIO_QUERY:
783 data[1] =
784 (s->
785 io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
786 COMEDI_INPUT;
787 return insn->n;
788 break;
789 default:
790 return -EINVAL;
791 break;
793 mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3);
794 dt3k_dio_config(dev, mask);
796 return insn->n;
799 static int dt3k_dio_insn_bits(struct comedi_device *dev,
800 struct comedi_subdevice *s,
801 struct comedi_insn *insn, unsigned int *data)
803 if (insn->n != 2)
804 return -EINVAL;
806 if (data[0]) {
807 s->state &= ~data[0];
808 s->state |= data[1] & data[0];
809 dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
811 data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
813 return 2;
816 static int dt3k_mem_insn_read(struct comedi_device *dev,
817 struct comedi_subdevice *s,
818 struct comedi_insn *insn, unsigned int *data)
820 unsigned int addr = CR_CHAN(insn->chanspec);
821 int i;
823 for (i = 0; i < insn->n; i++) {
824 writew(SUBS_MEM, devpriv->io_addr + DPR_SubSys);
825 writew(addr, devpriv->io_addr + DPR_Params(0));
826 writew(1, devpriv->io_addr + DPR_Params(1));
828 dt3k_send_cmd(dev, CMD_READCODE);
830 data[i] = readw(devpriv->io_addr + DPR_Params(2));
833 return i;
836 static int dt_pci_probe(struct comedi_device *dev, int bus, int slot);
838 static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
840 struct comedi_subdevice *s;
841 int bus, slot;
842 int ret = 0;
844 printk("dt3000:");
845 bus = it->options[0];
846 slot = it->options[1];
848 ret = alloc_private(dev, sizeof(struct dt3k_private));
849 if (ret < 0)
850 return ret;
852 ret = dt_pci_probe(dev, bus, slot);
853 if (ret < 0)
854 return ret;
855 if (ret == 0) {
856 printk(" no DT board found\n");
857 return -ENODEV;
860 dev->board_name = this_board->name;
862 if (request_irq(devpriv->pci_dev->irq, dt3k_interrupt, IRQF_SHARED,
863 "dt3000", dev)) {
864 printk(" unable to allocate IRQ %u\n", devpriv->pci_dev->irq);
865 return -EINVAL;
867 dev->irq = devpriv->pci_dev->irq;
869 ret = alloc_subdevices(dev, 4);
870 if (ret < 0)
871 return ret;
873 s = dev->subdevices;
874 dev->read_subdev = s;
876 /* ai subdevice */
877 s->type = COMEDI_SUBD_AI;
878 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
879 s->n_chan = this_board->adchan;
880 s->insn_read = dt3k_ai_insn;
881 s->maxdata = (1 << this_board->adbits) - 1;
882 s->len_chanlist = 512;
883 s->range_table = &range_dt3000_ai;
884 s->do_cmd = dt3k_ai_cmd;
885 s->do_cmdtest = dt3k_ai_cmdtest;
886 s->cancel = dt3k_ai_cancel;
888 s++;
889 /* ao subsystem */
890 s->type = COMEDI_SUBD_AO;
891 s->subdev_flags = SDF_WRITABLE;
892 s->n_chan = 2;
893 s->insn_read = dt3k_ao_insn_read;
894 s->insn_write = dt3k_ao_insn;
895 s->maxdata = (1 << this_board->dabits) - 1;
896 s->len_chanlist = 1;
897 s->range_table = &range_bipolar10;
899 s++;
900 /* dio subsystem */
901 s->type = COMEDI_SUBD_DIO;
902 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
903 s->n_chan = 8;
904 s->insn_config = dt3k_dio_insn_config;
905 s->insn_bits = dt3k_dio_insn_bits;
906 s->maxdata = 1;
907 s->len_chanlist = 8;
908 s->range_table = &range_digital;
910 s++;
911 /* mem subsystem */
912 s->type = COMEDI_SUBD_MEMORY;
913 s->subdev_flags = SDF_READABLE;
914 s->n_chan = 0x1000;
915 s->insn_read = dt3k_mem_insn_read;
916 s->maxdata = 0xff;
917 s->len_chanlist = 1;
918 s->range_table = &range_unknown;
921 return 0;
924 static int dt3000_detach(struct comedi_device *dev)
926 if (dev->irq)
927 free_irq(dev->irq, dev);
929 if (devpriv) {
930 if (devpriv->pci_dev) {
931 if (devpriv->phys_addr)
932 comedi_pci_disable(devpriv->pci_dev);
933 pci_dev_put(devpriv->pci_dev);
935 if (devpriv->io_addr)
936 iounmap(devpriv->io_addr);
939 return 0;
942 static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board);
943 static int setup_pci(struct comedi_device *dev);
945 static int dt_pci_probe(struct comedi_device *dev, int bus, int slot)
947 int board;
948 int ret;
949 struct pci_dev *pcidev;
951 pcidev = NULL;
952 while ((pcidev = dt_pci_find_device(pcidev, &board)) != NULL) {
953 if ((bus == 0 && slot == 0) ||
954 (pcidev->bus->number == bus &&
955 PCI_SLOT(pcidev->devfn) == slot)) {
956 break;
959 devpriv->pci_dev = pcidev;
961 if (board >= 0)
962 dev->board_ptr = dt3k_boardtypes + board;
964 if (!devpriv->pci_dev)
965 return 0;
967 ret = setup_pci(dev);
968 if (ret < 0)
969 return ret;
971 return 1;
974 static int setup_pci(struct comedi_device *dev)
976 resource_size_t addr;
977 int ret;
979 ret = comedi_pci_enable(devpriv->pci_dev, "dt3000");
980 if (ret < 0)
981 return ret;
983 addr = pci_resource_start(devpriv->pci_dev, 0);
984 devpriv->phys_addr = addr;
985 devpriv->io_addr = ioremap(devpriv->phys_addr, DT3000_SIZE);
986 if (!devpriv->io_addr)
987 return -ENOMEM;
988 #if DEBUG
989 printk("0x%08llx mapped to %p, ",
990 (unsigned long long)devpriv->phys_addr, devpriv->io_addr);
991 #endif
993 return 0;
996 static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board)
998 int i;
1000 for (from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from);
1001 from != NULL;
1002 from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from)) {
1003 for (i = 0; i < n_dt3k_boards; i++) {
1004 if (from->device == dt3k_boardtypes[i].device_id) {
1005 *board = i;
1006 return from;
1009 printk
1010 ("unknown Data Translation PCI device found with device_id=0x%04x\n",
1011 from->device);
1013 *board = -1;
1014 return from;
1017 MODULE_AUTHOR("Comedi http://www.comedi.org");
1018 MODULE_DESCRIPTION("Comedi low-level driver");
1019 MODULE_LICENSE("GPL");