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