dt3000.c revision a471eace7baa40cdf16d3f26b2f78ddce613ca8f
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/interrupt.h>
59#include "../comedidev.h"
60#include <linux/delay.h>
61
62#include "comedi_fc.h"
63
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
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	}
82};
83
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	}
91};
92
93struct dt3k_boardtype {
94	const char *name;
95	unsigned int device_id;
96	int adchan;
97	int adbits;
98	int ai_speed;
99	const struct comedi_lrange *adrange;
100	int dachan;
101	int dabits;
102};
103
104static const struct dt3k_boardtype dt3k_boardtypes[] = {
105	{
106		.name		= "dt3001",
107		.device_id	= PCI_DEVICE_ID_DT3001,
108		.adchan		= 16,
109		.adbits		= 12,
110		.adrange	= &range_dt3000_ai,
111		.ai_speed	= 3000,
112		.dachan		= 2,
113		.dabits		= 12,
114	}, {
115		.name		= "dt3001-pgl",
116		.device_id	= PCI_DEVICE_ID_DT3001_PGL,
117		.adchan		= 16,
118		.adbits		= 12,
119		.adrange	= &range_dt3000_ai_pgl,
120		.ai_speed	= 3000,
121		.dachan		= 2,
122		.dabits		= 12,
123	}, {
124		.name		= "dt3002",
125		.device_id	= PCI_DEVICE_ID_DT3002,
126		.adchan		= 32,
127		.adbits		= 12,
128		.adrange	= &range_dt3000_ai,
129		.ai_speed	= 3000,
130	}, {
131		.name		= "dt3003",
132		.device_id	= PCI_DEVICE_ID_DT3003,
133		.adchan		= 64,
134		.adbits		= 12,
135		.adrange	= &range_dt3000_ai,
136		.ai_speed	= 3000,
137		.dachan		= 2,
138		.dabits		= 12,
139	}, {
140		.name		= "dt3003-pgl",
141		.device_id	= PCI_DEVICE_ID_DT3003_PGL,
142		.adchan		= 64,
143		.adbits		= 12,
144		.adrange	= &range_dt3000_ai_pgl,
145		.ai_speed	= 3000,
146		.dachan		= 2,
147		.dabits		= 12,
148	}, {
149		.name		= "dt3004",
150		.device_id	= PCI_DEVICE_ID_DT3004,
151		.adchan		= 16,
152		.adbits		= 16,
153		.adrange	= &range_dt3000_ai,
154		.ai_speed	= 10000,
155		.dachan		= 2,
156		.dabits		= 12,
157	}, {
158		.name		= "dt3005",	/* a.k.a. 3004-200 */
159		.device_id 	= PCI_DEVICE_ID_DT3005,
160		.adchan		= 16,
161		.adbits		= 16,
162		.adrange	= &range_dt3000_ai,
163		.ai_speed	= 5000,
164		.dachan		= 2,
165		.dabits		= 12,
166	},
167};
168
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
255struct dt3k_private {
256	void __iomem *io_addr;
257	unsigned int lock;
258	unsigned int ao_readback[2];
259	unsigned int ai_front;
260	unsigned int ai_rear;
261};
262
263#ifdef DEBUG
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}
279#endif
280
281#define TIMEOUT 100
282
283static void dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
284{
285	struct dt3k_private *devpriv = dev->private;
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;
295		udelay(1);
296	}
297
298	if ((status & DT3000_COMPLETION_MASK) != DT3000_NOERROR)
299		dev_dbg(dev->class_dev, "%s: timeout/error status=0x%04x\n",
300			__func__, status);
301}
302
303static unsigned int dt3k_readsingle(struct comedi_device *dev,
304				    unsigned int subsys, unsigned int chan,
305				    unsigned int gain)
306{
307	struct dt3k_private *devpriv = dev->private;
308
309	writew(subsys, devpriv->io_addr + DPR_SubSys);
310
311	writew(chan, devpriv->io_addr + DPR_Params(0));
312	writew(gain, devpriv->io_addr + DPR_Params(1));
313
314	dt3k_send_cmd(dev, CMD_READSINGLE);
315
316	return readw(devpriv->io_addr + DPR_Params(2));
317}
318
319static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
320			     unsigned int chan, unsigned int data)
321{
322	struct dt3k_private *devpriv = dev->private;
323
324	writew(subsys, devpriv->io_addr + DPR_SubSys);
325
326	writew(chan, devpriv->io_addr + DPR_Params(0));
327	writew(0, devpriv->io_addr + DPR_Params(1));
328	writew(data, devpriv->io_addr + DPR_Params(2));
329
330	dt3k_send_cmd(dev, CMD_WRITESINGLE);
331}
332
333static void dt3k_ai_empty_fifo(struct comedi_device *dev,
334			       struct comedi_subdevice *s)
335{
336	struct dt3k_private *devpriv = dev->private;
337	int front;
338	int rear;
339	int count;
340	int i;
341	short data;
342
343	front = readw(devpriv->io_addr + DPR_AD_Buf_Front);
344	count = front - devpriv->ai_front;
345	if (count < 0)
346		count += AI_FIFO_DEPTH;
347
348	rear = devpriv->ai_rear;
349
350	for (i = 0; i < count; i++) {
351		data = readw(devpriv->io_addr + DPR_ADC_buffer + rear);
352		comedi_buf_put(s->async, data);
353		rear++;
354		if (rear >= AI_FIFO_DEPTH)
355			rear = 0;
356	}
357
358	devpriv->ai_rear = rear;
359	writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear);
360}
361
362static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
363{
364	struct dt3k_private *devpriv = dev->private;
365
366	writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
367	dt3k_send_cmd(dev, CMD_STOP);
368
369	writew(0, devpriv->io_addr + DPR_Int_Mask);
370
371	return 0;
372}
373
374static int debug_n_ints;
375
376/* FIXME! Assumes shared interrupt is for this card. */
377/* What's this debug_n_ints stuff? Obviously needs some work... */
378static irqreturn_t dt3k_interrupt(int irq, void *d)
379{
380	struct comedi_device *dev = d;
381	struct dt3k_private *devpriv = dev->private;
382	struct comedi_subdevice *s;
383	unsigned int status;
384
385	if (!dev->attached)
386		return IRQ_NONE;
387
388	s = &dev->subdevices[0];
389	status = readw(devpriv->io_addr + DPR_Intr_Flag);
390#ifdef DEBUG
391	debug_intr_flags(status);
392#endif
393
394	if (status & DT3000_ADFULL) {
395		dt3k_ai_empty_fifo(dev, s);
396		s->async->events |= COMEDI_CB_BLOCK;
397	}
398
399	if (status & (DT3000_ADSWERR | DT3000_ADHWERR))
400		s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
401
402	debug_n_ints++;
403	if (debug_n_ints >= 10) {
404		dt3k_ai_cancel(dev, s);
405		s->async->events |= COMEDI_CB_EOA;
406	}
407
408	comedi_event(dev, s);
409	return IRQ_HANDLED;
410}
411
412static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
413			    unsigned int round_mode)
414{
415	int divider, base, prescale;
416
417	/* This function needs improvment */
418	/* Don't know if divider==0 works. */
419
420	for (prescale = 0; prescale < 16; prescale++) {
421		base = timer_base * (prescale + 1);
422		switch (round_mode) {
423		case TRIG_ROUND_NEAREST:
424		default:
425			divider = (*nanosec + base / 2) / base;
426			break;
427		case TRIG_ROUND_DOWN:
428			divider = (*nanosec) / base;
429			break;
430		case TRIG_ROUND_UP:
431			divider = (*nanosec) / base;
432			break;
433		}
434		if (divider < 65536) {
435			*nanosec = divider * base;
436			return (prescale << 16) | (divider);
437		}
438	}
439
440	prescale = 15;
441	base = timer_base * (1 << prescale);
442	divider = 65535;
443	*nanosec = divider * base;
444	return (prescale << 16) | (divider);
445}
446
447static int dt3k_ai_cmdtest(struct comedi_device *dev,
448			   struct comedi_subdevice *s, struct comedi_cmd *cmd)
449{
450	const struct dt3k_boardtype *this_board = comedi_board(dev);
451	int err = 0;
452	int tmp;
453
454	/* Step 1 : check if triggers are trivially valid */
455
456	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
457	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
458	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
459	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
460	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT);
461
462	if (err)
463		return 1;
464
465	/* Step 2a : make sure trigger sources are unique */
466	/* Step 2b : and mutually compatible */
467
468	if (err)
469		return 2;
470
471	/* Step 3: check if arguments are trivially valid */
472
473	err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
474
475	if (cmd->scan_begin_src == TRIG_TIMER) {
476		err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
477						 this_board->ai_speed);
478		err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg,
479						 100 * 16 * 65535);
480	}
481
482	if (cmd->convert_src == TRIG_TIMER) {
483		err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
484						 this_board->ai_speed);
485		err |= cfc_check_trigger_arg_max(&cmd->convert_arg,
486						 50 * 16 * 65535);
487	}
488
489	err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
490
491	if (cmd->stop_src == TRIG_COUNT)
492		err |= cfc_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff);
493	else	/* TRIG_NONE */
494		err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
495
496	if (err)
497		return 3;
498
499	/* step 4: fix up any arguments */
500
501	if (cmd->scan_begin_src == TRIG_TIMER) {
502		tmp = cmd->scan_begin_arg;
503		dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
504				 cmd->flags & TRIG_ROUND_MASK);
505		if (tmp != cmd->scan_begin_arg)
506			err++;
507	}
508
509	if (cmd->convert_src == TRIG_TIMER) {
510		tmp = cmd->convert_arg;
511		dt3k_ns_to_timer(50, &cmd->convert_arg,
512				 cmd->flags & TRIG_ROUND_MASK);
513		if (tmp != cmd->convert_arg)
514			err++;
515		if (cmd->scan_begin_src == TRIG_TIMER &&
516		    cmd->scan_begin_arg <
517		    cmd->convert_arg * cmd->scan_end_arg) {
518			cmd->scan_begin_arg =
519			    cmd->convert_arg * cmd->scan_end_arg;
520			err++;
521		}
522	}
523
524	if (err)
525		return 4;
526
527	return 0;
528}
529
530static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
531{
532	struct dt3k_private *devpriv = dev->private;
533	struct comedi_cmd *cmd = &s->async->cmd;
534	int i;
535	unsigned int chan, range, aref;
536	unsigned int divider;
537	unsigned int tscandiv;
538	unsigned int mode;
539
540	for (i = 0; i < cmd->chanlist_len; i++) {
541		chan = CR_CHAN(cmd->chanlist[i]);
542		range = CR_RANGE(cmd->chanlist[i]);
543
544		writew((range << 6) | chan,
545		       devpriv->io_addr + DPR_ADC_buffer + i);
546	}
547	aref = CR_AREF(cmd->chanlist[0]);
548
549	writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0));
550
551	if (cmd->convert_src == TRIG_TIMER) {
552		divider = dt3k_ns_to_timer(50, &cmd->convert_arg,
553					   cmd->flags & TRIG_ROUND_MASK);
554		writew((divider >> 16), devpriv->io_addr + DPR_Params(1));
555		writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2));
556	}
557
558	if (cmd->scan_begin_src == TRIG_TIMER) {
559		tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
560					    cmd->flags & TRIG_ROUND_MASK);
561		writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3));
562		writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4));
563	}
564
565	mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
566	writew(mode, devpriv->io_addr + DPR_Params(5));
567	writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6));
568
569	writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7));
570
571	writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
572	dt3k_send_cmd(dev, CMD_CONFIG);
573
574	writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
575	       devpriv->io_addr + DPR_Int_Mask);
576
577	debug_n_ints = 0;
578
579	writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
580	dt3k_send_cmd(dev, CMD_START);
581
582	return 0;
583}
584
585static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
586			struct comedi_insn *insn, unsigned int *data)
587{
588	int i;
589	unsigned int chan, gain, aref;
590
591	chan = CR_CHAN(insn->chanspec);
592	gain = CR_RANGE(insn->chanspec);
593	/* XXX docs don't explain how to select aref */
594	aref = CR_AREF(insn->chanspec);
595
596	for (i = 0; i < insn->n; i++)
597		data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
598
599	return i;
600}
601
602static int dt3k_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
603			struct comedi_insn *insn, unsigned int *data)
604{
605	struct dt3k_private *devpriv = dev->private;
606	int i;
607	unsigned int chan;
608
609	chan = CR_CHAN(insn->chanspec);
610	for (i = 0; i < insn->n; i++) {
611		dt3k_writesingle(dev, SUBS_AO, chan, data[i]);
612		devpriv->ao_readback[chan] = data[i];
613	}
614
615	return i;
616}
617
618static int dt3k_ao_insn_read(struct comedi_device *dev,
619			     struct comedi_subdevice *s,
620			     struct comedi_insn *insn, unsigned int *data)
621{
622	struct dt3k_private *devpriv = dev->private;
623	int i;
624	unsigned int chan;
625
626	chan = CR_CHAN(insn->chanspec);
627	for (i = 0; i < insn->n; i++)
628		data[i] = devpriv->ao_readback[chan];
629
630	return i;
631}
632
633static void dt3k_dio_config(struct comedi_device *dev, int bits)
634{
635	struct dt3k_private *devpriv = dev->private;
636
637	/* XXX */
638	writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys);
639
640	writew(bits, devpriv->io_addr + DPR_Params(0));
641#if 0
642	/* don't know */
643	writew(0, devpriv->io_addr + DPR_Params(1));
644	writew(0, devpriv->io_addr + DPR_Params(2));
645#endif
646
647	dt3k_send_cmd(dev, CMD_CONFIG);
648}
649
650static int dt3k_dio_insn_config(struct comedi_device *dev,
651				struct comedi_subdevice *s,
652				struct comedi_insn *insn, unsigned int *data)
653{
654	int mask;
655
656	mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
657
658	switch (data[0]) {
659	case INSN_CONFIG_DIO_OUTPUT:
660		s->io_bits |= mask;
661		break;
662	case INSN_CONFIG_DIO_INPUT:
663		s->io_bits &= ~mask;
664		break;
665	case INSN_CONFIG_DIO_QUERY:
666		data[1] =
667		    (s->
668		     io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
669		    COMEDI_INPUT;
670		return insn->n;
671		break;
672	default:
673		return -EINVAL;
674		break;
675	}
676	mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3);
677	dt3k_dio_config(dev, mask);
678
679	return insn->n;
680}
681
682static int dt3k_dio_insn_bits(struct comedi_device *dev,
683			      struct comedi_subdevice *s,
684			      struct comedi_insn *insn, unsigned int *data)
685{
686	if (data[0]) {
687		s->state &= ~data[0];
688		s->state |= data[1] & data[0];
689		dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
690	}
691	data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
692
693	return insn->n;
694}
695
696static int dt3k_mem_insn_read(struct comedi_device *dev,
697			      struct comedi_subdevice *s,
698			      struct comedi_insn *insn, unsigned int *data)
699{
700	struct dt3k_private *devpriv = dev->private;
701	unsigned int addr = CR_CHAN(insn->chanspec);
702	int i;
703
704	for (i = 0; i < insn->n; i++) {
705		writew(SUBS_MEM, devpriv->io_addr + DPR_SubSys);
706		writew(addr, devpriv->io_addr + DPR_Params(0));
707		writew(1, devpriv->io_addr + DPR_Params(1));
708
709		dt3k_send_cmd(dev, CMD_READCODE);
710
711		data[i] = readw(devpriv->io_addr + DPR_Params(2));
712	}
713
714	return i;
715}
716
717static const void *dt3000_find_boardinfo(struct comedi_device *dev,
718					 struct pci_dev *pcidev)
719{
720	const struct dt3k_boardtype *this_board;
721	int i;
722
723	for (i = 0; i < ARRAY_SIZE(dt3k_boardtypes); i++) {
724		this_board = &dt3k_boardtypes[i];
725		if (this_board->device_id == pcidev->device)
726			return this_board;
727	}
728	return NULL;
729}
730
731static int __devinit dt3000_auto_attach(struct comedi_device *dev,
732					unsigned long context_unused)
733{
734	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
735	const struct dt3k_boardtype *this_board;
736	struct dt3k_private *devpriv;
737	struct comedi_subdevice *s;
738	resource_size_t pci_base;
739	int ret = 0;
740
741	this_board = dt3000_find_boardinfo(dev, pcidev);
742	if (!this_board)
743		return -ENODEV;
744	dev->board_ptr = this_board;
745	dev->board_name = this_board->name;
746
747	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
748	if (!devpriv)
749		return -ENOMEM;
750	dev->private = devpriv;
751
752	ret = comedi_pci_enable(pcidev, dev->board_name);
753	if (ret < 0)
754		return ret;
755	dev->iobase = 1;	/* the "detach" needs this */
756
757	pci_base  = pci_resource_start(pcidev, 0);
758	devpriv->io_addr = ioremap(pci_base, DT3000_SIZE);
759	if (!devpriv->io_addr)
760		return -ENOMEM;
761
762	ret = request_irq(pcidev->irq, dt3k_interrupt, IRQF_SHARED,
763			  dev->board_name, dev);
764	if (ret)
765		return ret;
766	dev->irq = pcidev->irq;
767
768	ret = comedi_alloc_subdevices(dev, 4);
769	if (ret)
770		return ret;
771
772	s = &dev->subdevices[0];
773	dev->read_subdev = s;
774	/* ai subdevice */
775	s->type		= COMEDI_SUBD_AI;
776	s->subdev_flags	= SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
777	s->n_chan	= this_board->adchan;
778	s->insn_read	= dt3k_ai_insn;
779	s->maxdata	= (1 << this_board->adbits) - 1;
780	s->len_chanlist	= 512;
781	s->range_table	= &range_dt3000_ai;	/* XXX */
782	s->do_cmd	= dt3k_ai_cmd;
783	s->do_cmdtest	= dt3k_ai_cmdtest;
784	s->cancel	= dt3k_ai_cancel;
785
786	s = &dev->subdevices[1];
787	/* ao subsystem */
788	s->type		= COMEDI_SUBD_AO;
789	s->subdev_flags	= SDF_WRITABLE;
790	s->n_chan	= 2;
791	s->insn_read	= dt3k_ao_insn_read;
792	s->insn_write	= dt3k_ao_insn;
793	s->maxdata	= (1 << this_board->dabits) - 1;
794	s->len_chanlist	= 1;
795	s->range_table	= &range_bipolar10;
796
797	s = &dev->subdevices[2];
798	/* dio subsystem */
799	s->type		= COMEDI_SUBD_DIO;
800	s->subdev_flags	= SDF_READABLE | SDF_WRITABLE;
801	s->n_chan	= 8;
802	s->insn_config	= dt3k_dio_insn_config;
803	s->insn_bits	= dt3k_dio_insn_bits;
804	s->maxdata	= 1;
805	s->len_chanlist	= 8;
806	s->range_table	= &range_digital;
807
808	s = &dev->subdevices[3];
809	/* mem subsystem */
810	s->type		= COMEDI_SUBD_MEMORY;
811	s->subdev_flags	= SDF_READABLE;
812	s->n_chan	= 0x1000;
813	s->insn_read	= dt3k_mem_insn_read;
814	s->maxdata	= 0xff;
815	s->len_chanlist	= 1;
816	s->range_table	= &range_unknown;
817
818#if 0
819	s = &dev->subdevices[4];
820	/* proc subsystem */
821	s->type = COMEDI_SUBD_PROC;
822#endif
823
824	dev_info(dev->class_dev, "%s attached\n", dev->board_name);
825
826	return 0;
827}
828
829static void dt3000_detach(struct comedi_device *dev)
830{
831	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
832	struct dt3k_private *devpriv = dev->private;
833
834	if (dev->irq)
835		free_irq(dev->irq, dev);
836	if (devpriv) {
837		if (devpriv->io_addr)
838			iounmap(devpriv->io_addr);
839	}
840	if (pcidev) {
841		if (dev->iobase)
842			comedi_pci_disable(pcidev);
843	}
844}
845
846static struct comedi_driver dt3000_driver = {
847	.driver_name	= "dt3000",
848	.module		= THIS_MODULE,
849	.auto_attach	= dt3000_auto_attach,
850	.detach		= dt3000_detach,
851};
852
853static int __devinit dt3000_pci_probe(struct pci_dev *dev,
854				      const struct pci_device_id *ent)
855{
856	return comedi_pci_auto_config(dev, &dt3000_driver);
857}
858
859static void __devexit dt3000_pci_remove(struct pci_dev *dev)
860{
861	comedi_pci_auto_unconfig(dev);
862}
863
864static DEFINE_PCI_DEVICE_TABLE(dt3000_pci_table) = {
865	{ PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3001) },
866	{ PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3001_PGL) },
867	{ PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3002) },
868	{ PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3003) },
869	{ PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3003_PGL) },
870	{ PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3004) },
871	{ PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3005) },
872	{ 0 }
873};
874MODULE_DEVICE_TABLE(pci, dt3000_pci_table);
875
876static struct pci_driver dt3000_pci_driver = {
877	.name		= "dt3000",
878	.id_table	= dt3000_pci_table,
879	.probe		= dt3000_pci_probe,
880	.remove		= dt3000_pci_remove,
881};
882module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver);
883
884MODULE_AUTHOR("Comedi http://www.comedi.org");
885MODULE_DESCRIPTION("Comedi low-level driver");
886MODULE_LICENSE("GPL");
887