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