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