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