dt3000.c revision 6f2c5f3852caf0afb6fae36e4f16fe765545bdb0
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	printk("dt3k_send_cmd() timeout/error status=0x%04x\n", status);
356
357	return -ETIME;
358}
359
360static unsigned int dt3k_readsingle(struct comedi_device *dev,
361				    unsigned int subsys, unsigned int chan,
362				    unsigned int gain)
363{
364	writew(subsys, devpriv->io_addr + DPR_SubSys);
365
366	writew(chan, devpriv->io_addr + DPR_Params(0));
367	writew(gain, devpriv->io_addr + DPR_Params(1));
368
369	dt3k_send_cmd(dev, CMD_READSINGLE);
370
371	return readw(devpriv->io_addr + DPR_Params(2));
372}
373
374static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
375			     unsigned int chan, unsigned int data)
376{
377	writew(subsys, devpriv->io_addr + DPR_SubSys);
378
379	writew(chan, devpriv->io_addr + DPR_Params(0));
380	writew(0, devpriv->io_addr + DPR_Params(1));
381	writew(data, devpriv->io_addr + DPR_Params(2));
382
383	dt3k_send_cmd(dev, CMD_WRITESINGLE);
384}
385
386static int debug_n_ints;
387
388/* FIXME! Assumes shared interrupt is for this card. */
389/* What's this debug_n_ints stuff? Obviously needs some work... */
390static irqreturn_t dt3k_interrupt(int irq, void *d)
391{
392	struct comedi_device *dev = d;
393	struct comedi_subdevice *s;
394	unsigned int status;
395
396	if (!dev->attached)
397		return IRQ_NONE;
398
399	s = dev->subdevices + 0;
400	status = readw(devpriv->io_addr + DPR_Intr_Flag);
401#ifdef DEBUG
402	debug_intr_flags(status);
403#endif
404
405	if (status & DT3000_ADFULL) {
406		dt3k_ai_empty_fifo(dev, s);
407		s->async->events |= COMEDI_CB_BLOCK;
408	}
409
410	if (status & (DT3000_ADSWERR | DT3000_ADHWERR))
411		s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
412
413	debug_n_ints++;
414	if (debug_n_ints >= 10) {
415		dt3k_ai_cancel(dev, s);
416		s->async->events |= COMEDI_CB_EOA;
417	}
418
419	comedi_event(dev, s);
420	return IRQ_HANDLED;
421}
422
423#ifdef DEBUG
424static char *intr_flags[] = {
425	"AdFull", "AdSwError", "AdHwError", "DaEmpty",
426	"DaSwError", "DaHwError", "CtDone", "CmDone",
427};
428
429static void debug_intr_flags(unsigned int flags)
430{
431	int i;
432	printk("dt3k: intr_flags:");
433	for (i = 0; i < 8; i++) {
434		if (flags & (1 << i))
435			printk(" %s", intr_flags[i]);
436	}
437	printk("\n");
438}
439#endif
440
441static void dt3k_ai_empty_fifo(struct comedi_device *dev,
442			       struct comedi_subdevice *s)
443{
444	int front;
445	int rear;
446	int count;
447	int i;
448	short data;
449
450	front = readw(devpriv->io_addr + DPR_AD_Buf_Front);
451	count = front - devpriv->ai_front;
452	if (count < 0)
453		count += AI_FIFO_DEPTH;
454
455	printk("reading %d samples\n", count);
456
457	rear = devpriv->ai_rear;
458
459	for (i = 0; i < count; i++) {
460		data = readw(devpriv->io_addr + DPR_ADC_buffer + rear);
461		comedi_buf_put(s->async, data);
462		rear++;
463		if (rear >= AI_FIFO_DEPTH)
464			rear = 0;
465	}
466
467	devpriv->ai_rear = rear;
468	writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear);
469}
470
471static int dt3k_ai_cmdtest(struct comedi_device *dev,
472			   struct comedi_subdevice *s, struct comedi_cmd *cmd)
473{
474	int err = 0;
475	int tmp;
476
477	/* step 1: make sure trigger sources are trivially valid */
478
479	tmp = cmd->start_src;
480	cmd->start_src &= TRIG_NOW;
481	if (!cmd->start_src || tmp != cmd->start_src)
482		err++;
483
484	tmp = cmd->scan_begin_src;
485	cmd->scan_begin_src &= TRIG_TIMER;
486	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
487		err++;
488
489	tmp = cmd->convert_src;
490	cmd->convert_src &= TRIG_TIMER;
491	if (!cmd->convert_src || tmp != cmd->convert_src)
492		err++;
493
494	tmp = cmd->scan_end_src;
495	cmd->scan_end_src &= TRIG_COUNT;
496	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
497		err++;
498
499	tmp = cmd->stop_src;
500	cmd->stop_src &= TRIG_COUNT;
501	if (!cmd->stop_src || tmp != cmd->stop_src)
502		err++;
503
504	if (err)
505		return 1;
506
507	/* step 2: make sure trigger sources are unique and mutually compatible */
508
509	if (err)
510		return 2;
511
512	/* step 3: make sure arguments are trivially compatible */
513
514	if (cmd->start_arg != 0) {
515		cmd->start_arg = 0;
516		err++;
517	}
518
519	if (cmd->scan_begin_src == TRIG_TIMER) {
520		if (cmd->scan_begin_arg < this_board->ai_speed) {
521			cmd->scan_begin_arg = this_board->ai_speed;
522			err++;
523		}
524		if (cmd->scan_begin_arg > 100 * 16 * 65535) {
525			cmd->scan_begin_arg = 100 * 16 * 65535;
526			err++;
527		}
528	} else {
529		/* not supported */
530	}
531	if (cmd->convert_src == TRIG_TIMER) {
532		if (cmd->convert_arg < this_board->ai_speed) {
533			cmd->convert_arg = this_board->ai_speed;
534			err++;
535		}
536		if (cmd->convert_arg > 50 * 16 * 65535) {
537			cmd->convert_arg = 50 * 16 * 65535;
538			err++;
539		}
540	} else {
541		/* not supported */
542	}
543
544	if (cmd->scan_end_arg != cmd->chanlist_len) {
545		cmd->scan_end_arg = cmd->chanlist_len;
546		err++;
547	}
548	if (cmd->stop_src == TRIG_COUNT) {
549		if (cmd->stop_arg > 0x00ffffff) {
550			cmd->stop_arg = 0x00ffffff;
551			err++;
552		}
553	} else {
554		/* TRIG_NONE */
555		if (cmd->stop_arg != 0) {
556			cmd->stop_arg = 0;
557			err++;
558		}
559	}
560
561	if (err)
562		return 3;
563
564	/* step 4: fix up any arguments */
565
566	if (cmd->scan_begin_src == TRIG_TIMER) {
567		tmp = cmd->scan_begin_arg;
568		dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
569				 cmd->flags & TRIG_ROUND_MASK);
570		if (tmp != cmd->scan_begin_arg)
571			err++;
572	} else {
573		/* not supported */
574	}
575	if (cmd->convert_src == TRIG_TIMER) {
576		tmp = cmd->convert_arg;
577		dt3k_ns_to_timer(50, &cmd->convert_arg,
578				 cmd->flags & TRIG_ROUND_MASK);
579		if (tmp != cmd->convert_arg)
580			err++;
581		if (cmd->scan_begin_src == TRIG_TIMER &&
582		    cmd->scan_begin_arg <
583		    cmd->convert_arg * cmd->scan_end_arg) {
584			cmd->scan_begin_arg =
585			    cmd->convert_arg * cmd->scan_end_arg;
586			err++;
587		}
588	} else {
589		/* not supported */
590	}
591
592	if (err)
593		return 4;
594
595	return 0;
596}
597
598static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
599			    unsigned int round_mode)
600{
601	int divider, base, prescale;
602
603	/* This function needs improvment */
604	/* Don't know if divider==0 works. */
605
606	for (prescale = 0; prescale < 16; prescale++) {
607		base = timer_base * (prescale + 1);
608		switch (round_mode) {
609		case TRIG_ROUND_NEAREST:
610		default:
611			divider = (*nanosec + base / 2) / base;
612			break;
613		case TRIG_ROUND_DOWN:
614			divider = (*nanosec) / base;
615			break;
616		case TRIG_ROUND_UP:
617			divider = (*nanosec) / base;
618			break;
619		}
620		if (divider < 65536) {
621			*nanosec = divider * base;
622			return (prescale << 16) | (divider);
623		}
624	}
625
626	prescale = 15;
627	base = timer_base * (1 << prescale);
628	divider = 65535;
629	*nanosec = divider * base;
630	return (prescale << 16) | (divider);
631}
632
633static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
634{
635	struct comedi_cmd *cmd = &s->async->cmd;
636	int i;
637	unsigned int chan, range, aref;
638	unsigned int divider;
639	unsigned int tscandiv;
640	int ret;
641	unsigned int mode;
642
643	printk("dt3k_ai_cmd:\n");
644	for (i = 0; i < cmd->chanlist_len; i++) {
645		chan = CR_CHAN(cmd->chanlist[i]);
646		range = CR_RANGE(cmd->chanlist[i]);
647
648		writew((range << 6) | chan,
649		       devpriv->io_addr + DPR_ADC_buffer + i);
650	}
651	aref = CR_AREF(cmd->chanlist[0]);
652
653	writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0));
654	printk("param[0]=0x%04x\n", cmd->scan_end_arg);
655
656	if (cmd->convert_src == TRIG_TIMER) {
657		divider = dt3k_ns_to_timer(50, &cmd->convert_arg,
658					   cmd->flags & TRIG_ROUND_MASK);
659		writew((divider >> 16), devpriv->io_addr + DPR_Params(1));
660		printk("param[1]=0x%04x\n", divider >> 16);
661		writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2));
662		printk("param[2]=0x%04x\n", divider & 0xffff);
663	} else {
664		/* not supported */
665	}
666
667	if (cmd->scan_begin_src == TRIG_TIMER) {
668		tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
669					    cmd->flags & TRIG_ROUND_MASK);
670		writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3));
671		printk("param[3]=0x%04x\n", tscandiv >> 16);
672		writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4));
673		printk("param[4]=0x%04x\n", tscandiv & 0xffff);
674	} else {
675		/* not supported */
676	}
677
678	mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
679	writew(mode, devpriv->io_addr + DPR_Params(5));
680	printk("param[5]=0x%04x\n", mode);
681	writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6));
682	printk("param[6]=0x%04x\n", aref == AREF_DIFF);
683
684	writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7));
685	printk("param[7]=0x%04x\n", AI_FIFO_DEPTH / 2);
686
687	writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
688	ret = dt3k_send_cmd(dev, CMD_CONFIG);
689
690	writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
691	       devpriv->io_addr + DPR_Int_Mask);
692
693	debug_n_ints = 0;
694
695	writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
696	ret = dt3k_send_cmd(dev, CMD_START);
697
698	return 0;
699}
700
701static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
702{
703	int ret;
704
705	writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
706	ret = dt3k_send_cmd(dev, CMD_STOP);
707
708	writew(0, devpriv->io_addr + DPR_Int_Mask);
709
710	return 0;
711}
712
713static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
714			struct comedi_insn *insn, unsigned int *data)
715{
716	int i;
717	unsigned int chan, gain, aref;
718
719	chan = CR_CHAN(insn->chanspec);
720	gain = CR_RANGE(insn->chanspec);
721	/* XXX docs don't explain how to select aref */
722	aref = CR_AREF(insn->chanspec);
723
724	for (i = 0; i < insn->n; i++)
725		data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
726
727	return i;
728}
729
730static int dt3k_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
731			struct comedi_insn *insn, unsigned int *data)
732{
733	int i;
734	unsigned int chan;
735
736	chan = CR_CHAN(insn->chanspec);
737	for (i = 0; i < insn->n; i++) {
738		dt3k_writesingle(dev, SUBS_AO, chan, data[i]);
739		devpriv->ao_readback[chan] = data[i];
740	}
741
742	return i;
743}
744
745static int dt3k_ao_insn_read(struct comedi_device *dev,
746			     struct comedi_subdevice *s,
747			     struct comedi_insn *insn, unsigned int *data)
748{
749	int i;
750	unsigned int chan;
751
752	chan = CR_CHAN(insn->chanspec);
753	for (i = 0; i < insn->n; i++)
754		data[i] = devpriv->ao_readback[chan];
755
756	return i;
757}
758
759static void dt3k_dio_config(struct comedi_device *dev, int bits)
760{
761	/* XXX */
762	writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys);
763
764	writew(bits, devpriv->io_addr + DPR_Params(0));
765#if 0
766	/* don't know */
767	writew(0, devpriv->io_addr + DPR_Params(1));
768	writew(0, devpriv->io_addr + DPR_Params(2));
769#endif
770
771	dt3k_send_cmd(dev, CMD_CONFIG);
772}
773
774static int dt3k_dio_insn_config(struct comedi_device *dev,
775				struct comedi_subdevice *s,
776				struct comedi_insn *insn, unsigned int *data)
777{
778	int mask;
779
780	mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
781
782	switch (data[0]) {
783	case INSN_CONFIG_DIO_OUTPUT:
784		s->io_bits |= mask;
785		break;
786	case INSN_CONFIG_DIO_INPUT:
787		s->io_bits &= ~mask;
788		break;
789	case INSN_CONFIG_DIO_QUERY:
790		data[1] =
791		    (s->
792		     io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
793		    COMEDI_INPUT;
794		return insn->n;
795		break;
796	default:
797		return -EINVAL;
798		break;
799	}
800	mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3);
801	dt3k_dio_config(dev, mask);
802
803	return insn->n;
804}
805
806static int dt3k_dio_insn_bits(struct comedi_device *dev,
807			      struct comedi_subdevice *s,
808			      struct comedi_insn *insn, unsigned int *data)
809{
810	if (insn->n != 2)
811		return -EINVAL;
812
813	if (data[0]) {
814		s->state &= ~data[0];
815		s->state |= data[1] & data[0];
816		dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
817	}
818	data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
819
820	return 2;
821}
822
823static int dt3k_mem_insn_read(struct comedi_device *dev,
824			      struct comedi_subdevice *s,
825			      struct comedi_insn *insn, unsigned int *data)
826{
827	unsigned int addr = CR_CHAN(insn->chanspec);
828	int i;
829
830	for (i = 0; i < insn->n; i++) {
831		writew(SUBS_MEM, devpriv->io_addr + DPR_SubSys);
832		writew(addr, devpriv->io_addr + DPR_Params(0));
833		writew(1, devpriv->io_addr + DPR_Params(1));
834
835		dt3k_send_cmd(dev, CMD_READCODE);
836
837		data[i] = readw(devpriv->io_addr + DPR_Params(2));
838	}
839
840	return i;
841}
842
843static int dt_pci_probe(struct comedi_device *dev, int bus, int slot);
844
845static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
846{
847	struct comedi_subdevice *s;
848	int bus, slot;
849	int ret = 0;
850
851	printk("dt3000:");
852	bus = it->options[0];
853	slot = it->options[1];
854
855	ret = alloc_private(dev, sizeof(struct dt3k_private));
856	if (ret < 0)
857		return ret;
858
859	ret = dt_pci_probe(dev, bus, slot);
860	if (ret < 0)
861		return ret;
862	if (ret == 0) {
863		printk(" no DT board found\n");
864		return -ENODEV;
865	}
866
867	dev->board_name = this_board->name;
868
869	if (request_irq(devpriv->pci_dev->irq, dt3k_interrupt, IRQF_SHARED,
870			"dt3000", dev)) {
871		printk(" unable to allocate IRQ %u\n", devpriv->pci_dev->irq);
872		return -EINVAL;
873	}
874	dev->irq = devpriv->pci_dev->irq;
875
876	ret = alloc_subdevices(dev, 4);
877	if (ret < 0)
878		return ret;
879
880	s = dev->subdevices;
881	dev->read_subdev = s;
882
883	/* ai subdevice */
884	s->type = COMEDI_SUBD_AI;
885	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
886	s->n_chan = this_board->adchan;
887	s->insn_read = dt3k_ai_insn;
888	s->maxdata = (1 << this_board->adbits) - 1;
889	s->len_chanlist = 512;
890	s->range_table = &range_dt3000_ai;	/* XXX */
891	s->do_cmd = dt3k_ai_cmd;
892	s->do_cmdtest = dt3k_ai_cmdtest;
893	s->cancel = dt3k_ai_cancel;
894
895	s++;
896	/* ao subsystem */
897	s->type = COMEDI_SUBD_AO;
898	s->subdev_flags = SDF_WRITABLE;
899	s->n_chan = 2;
900	s->insn_read = dt3k_ao_insn_read;
901	s->insn_write = dt3k_ao_insn;
902	s->maxdata = (1 << this_board->dabits) - 1;
903	s->len_chanlist = 1;
904	s->range_table = &range_bipolar10;
905
906	s++;
907	/* dio subsystem */
908	s->type = COMEDI_SUBD_DIO;
909	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
910	s->n_chan = 8;
911	s->insn_config = dt3k_dio_insn_config;
912	s->insn_bits = dt3k_dio_insn_bits;
913	s->maxdata = 1;
914	s->len_chanlist = 8;
915	s->range_table = &range_digital;
916
917	s++;
918	/* mem subsystem */
919	s->type = COMEDI_SUBD_MEMORY;
920	s->subdev_flags = SDF_READABLE;
921	s->n_chan = 0x1000;
922	s->insn_read = dt3k_mem_insn_read;
923	s->maxdata = 0xff;
924	s->len_chanlist = 1;
925	s->range_table = &range_unknown;
926
927#if 0
928	s++;
929	/* proc subsystem */
930	s->type = COMEDI_SUBD_PROC;
931#endif
932
933	return 0;
934}
935
936static int dt3000_detach(struct comedi_device *dev)
937{
938	if (dev->irq)
939		free_irq(dev->irq, dev);
940
941	if (devpriv) {
942		if (devpriv->pci_dev) {
943			if (devpriv->phys_addr)
944				comedi_pci_disable(devpriv->pci_dev);
945			pci_dev_put(devpriv->pci_dev);
946		}
947		if (devpriv->io_addr)
948			iounmap(devpriv->io_addr);
949	}
950	/* XXX */
951
952	return 0;
953}
954
955static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board);
956static int setup_pci(struct comedi_device *dev);
957
958static int dt_pci_probe(struct comedi_device *dev, int bus, int slot)
959{
960	int board;
961	int ret;
962	struct pci_dev *pcidev;
963
964	pcidev = NULL;
965	while ((pcidev = dt_pci_find_device(pcidev, &board)) != NULL) {
966		if ((bus == 0 && slot == 0) ||
967		    (pcidev->bus->number == bus &&
968		     PCI_SLOT(pcidev->devfn) == slot)) {
969			break;
970		}
971	}
972	devpriv->pci_dev = pcidev;
973
974	if (board >= 0)
975		dev->board_ptr = dt3k_boardtypes + board;
976
977	if (!devpriv->pci_dev)
978		return 0;
979
980	ret = setup_pci(dev);
981	if (ret < 0)
982		return ret;
983
984	return 1;
985}
986
987static int setup_pci(struct comedi_device *dev)
988{
989	resource_size_t addr;
990	int ret;
991
992	ret = comedi_pci_enable(devpriv->pci_dev, "dt3000");
993	if (ret < 0)
994		return ret;
995
996	addr = pci_resource_start(devpriv->pci_dev, 0);
997	devpriv->phys_addr = addr;
998	devpriv->io_addr = ioremap(devpriv->phys_addr, DT3000_SIZE);
999	if (!devpriv->io_addr)
1000		return -ENOMEM;
1001#if DEBUG
1002	printk("0x%08llx mapped to %p, ",
1003	       (unsigned long long)devpriv->phys_addr, devpriv->io_addr);
1004#endif
1005
1006	return 0;
1007}
1008
1009static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board)
1010{
1011	int i;
1012
1013	for (from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from);
1014	     from != NULL;
1015	     from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from)) {
1016		for (i = 0; i < n_dt3k_boards; i++) {
1017			if (from->device == dt3k_boardtypes[i].device_id) {
1018				*board = i;
1019				return from;
1020			}
1021		}
1022		printk
1023		    ("unknown Data Translation PCI device found with device_id=0x%04x\n",
1024		     from->device);
1025	}
1026	*board = -1;
1027	return from;
1028}
1029
1030MODULE_AUTHOR("Comedi http://www.comedi.org");
1031MODULE_DESCRIPTION("Comedi low-level driver");
1032MODULE_LICENSE("GPL");
1033