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