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