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