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