1a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef/*
2a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef    comedi/drivers/dt2814.c
3a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef    Hardware driver for Data Translation DT2814
4a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
5a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef    COMEDI - Linux Control and Measurement Device Interface
6a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef    Copyright (C) 1998 David A. Schleef <ds@schleef.org>
7a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
8a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef    This program is free software; you can redistribute it and/or modify
9a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef    it under the terms of the GNU General Public License as published by
10a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef    the Free Software Foundation; either version 2 of the License, or
11a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef    (at your option) any later version.
12a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
13a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef    This program is distributed in the hope that it will be useful,
14a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef    but WITHOUT ANY WARRANTY; without even the implied warranty of
15a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef    GNU General Public License for more details.
17a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
18a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef    You should have received a copy of the GNU General Public License
19a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef    along with this program; if not, write to the Free Software
20a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
22a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef*/
23a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef/*
24a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid SchleefDriver: dt2814
25a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid SchleefDescription: Data Translation DT2814
26a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid SchleefAuthor: ds
27a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid SchleefStatus: complete
28a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid SchleefDevices: [Data Translation] DT2814 (dt2814)
29a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
30a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid SchleefConfiguration options:
31a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef  [0] - I/O port base address
32a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef  [1] - IRQ
33a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
34a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid SchleefThis card has 16 analog inputs multiplexed onto a 12 bit ADC.  There
35a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleefis a minimally useful onboard clock.  The base frequency for the
36a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleefclock is selected by jumpers, and the clock divider can be selected
37a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleefvia programmed I/O.  Unfortunately, the clock divider can only be
38a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleefa power of 10, from 1 to 10^7, of which only 3 or 4 are useful.  In
39a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleefaddition, the clock does not seem to be very accurate.
40a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef*/
41a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
4225436dc9d84f1be60ff549c9ab712bba2835f284Greg Kroah-Hartman#include <linux/interrupt.h>
43a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef#include "../comedidev.h"
44a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
45a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef#include <linux/ioport.h>
46a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef#include <linux/delay.h>
47a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
48a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef#define DT2814_SIZE 2
49a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
50a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef#define DT2814_CSR 0
51a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef#define DT2814_DATA 1
52a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
53a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef/*
54a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef * flags
55a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef */
56a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
57a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef#define DT2814_FINISH 0x80
58a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef#define DT2814_ERR 0x40
59a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef#define DT2814_BUSY 0x20
60a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef#define DT2814_ENB 0x10
61a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef#define DT2814_CHANMASK 0x0f
62a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
630a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int dt2814_attach(struct comedi_device *dev,
640a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 struct comedi_devconfig *it);
65da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int dt2814_detach(struct comedi_device *dev);
66139dfbdfacb02e3ef3df936d2fabd1ad5f14ea88Bill Pembertonstatic struct comedi_driver driver_dt2814 = {
6768c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.driver_name = "dt2814",
6868c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.module = THIS_MODULE,
6968c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.attach = dt2814_attach,
7068c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.detach = dt2814_detach,
71a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef};
72a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
737114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasstatic int __init driver_dt2814_init_module(void)
747114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas{
757114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas	return comedi_driver_register(&driver_dt2814);
767114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas}
777114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas
787114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasstatic void __exit driver_dt2814_cleanup_module(void)
797114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas{
807114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas	comedi_driver_unregister(&driver_dt2814);
817114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas}
827114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas
837114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasmodule_init(driver_dt2814_init_module);
847114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasmodule_exit(driver_dt2814_cleanup_module);
85a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
8670265d24e3404fe798b6edd55a02016b1edb49d7Jiri Slabystatic irqreturn_t dt2814_interrupt(int irq, void *dev);
87a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
88ca6f10ca8630d709e0d291fb9601f8c8d81c19a0Bill Pembertonstruct dt2814_private {
89ca6f10ca8630d709e0d291fb9601f8c8d81c19a0Bill Pemberton
90a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	int ntrig;
91a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	int curadchan;
92ca6f10ca8630d709e0d291fb9601f8c8d81c19a0Bill Pemberton};
93ca6f10ca8630d709e0d291fb9601f8c8d81c19a0Bill Pemberton
94ca6f10ca8630d709e0d291fb9601f8c8d81c19a0Bill Pemberton#define devpriv ((struct dt2814_private *)dev->private)
95a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
96a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef#define DT2814_TIMEOUT 10
97a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef#define DT2814_MAX_SPEED 100000	/* Arbitrary 10 khz limit */
98a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
990a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int dt2814_ai_insn_read(struct comedi_device *dev,
1000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_subdevice *s,
1010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_insn *insn, unsigned int *data)
102a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef{
103a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	int n, i, hi, lo;
104a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	int chan;
105a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	int status = 0;
106a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
107a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	for (n = 0; n < insn->n; n++) {
108a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		chan = CR_CHAN(insn->chanspec);
109a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
110a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		outb(chan, dev->iobase + DT2814_CSR);
111a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		for (i = 0; i < DT2814_TIMEOUT; i++) {
112a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef			status = inb(dev->iobase + DT2814_CSR);
1133f3ba29c78c4039a9fd746065ff89afec8bbc19aFelipe de Oliveira Tanus			printk(KERN_INFO "dt2814: status: %02x\n", status);
1145f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman			udelay(10);
115a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef			if (status & DT2814_FINISH)
116a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef				break;
117a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		}
118a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		if (i >= DT2814_TIMEOUT) {
1193f3ba29c78c4039a9fd746065ff89afec8bbc19aFelipe de Oliveira Tanus			printk(KERN_INFO "dt2814: status: %02x\n", status);
120a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef			return -ETIMEDOUT;
121a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		}
122a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
123a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		hi = inb(dev->iobase + DT2814_DATA);
124a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		lo = inb(dev->iobase + DT2814_DATA);
125a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
126a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		data[n] = (hi << 4) | (lo >> 4);
127a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	}
128a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
129a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	return n;
130a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef}
131a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
132a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleefstatic int dt2814_ns_to_timer(unsigned int *ns, unsigned int flags)
133a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef{
134a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	int i;
135a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	unsigned int f;
136a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
137a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	/* XXX ignores flags */
138a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
139a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	f = 10000;		/* ns */
140a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	for (i = 0; i < 8; i++) {
141a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		if ((2 * (*ns)) < (f * 11))
142a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef			break;
143a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		f *= 10;
144a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	}
145a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
146a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	*ns = f;
147a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
148a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	return i;
149a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef}
150a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
1510a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int dt2814_ai_cmdtest(struct comedi_device *dev,
1520a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_subdevice *s, struct comedi_cmd *cmd)
153a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef{
154a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	int err = 0;
155a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	int tmp;
156a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
157a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	/* step 1: make sure trigger sources are trivially valid */
158a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
159a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	tmp = cmd->start_src;
160a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	cmd->start_src &= TRIG_NOW;
161a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	if (!cmd->start_src || tmp != cmd->start_src)
162a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		err++;
163a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
164a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	tmp = cmd->scan_begin_src;
165a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	cmd->scan_begin_src &= TRIG_TIMER;
166a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
167a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		err++;
168a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
169a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	tmp = cmd->convert_src;
170a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	cmd->convert_src &= TRIG_NOW;
171a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	if (!cmd->convert_src || tmp != cmd->convert_src)
172a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		err++;
173a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
174a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	tmp = cmd->scan_end_src;
175a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	cmd->scan_end_src &= TRIG_COUNT;
176a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
177a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		err++;
178a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
179a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	tmp = cmd->stop_src;
180a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
181a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	if (!cmd->stop_src || tmp != cmd->stop_src)
182a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		err++;
183a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
184a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	if (err)
185a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		return 1;
186a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
1873f3ba29c78c4039a9fd746065ff89afec8bbc19aFelipe de Oliveira Tanus	/* step 2: make sure trigger sources are
1883f3ba29c78c4039a9fd746065ff89afec8bbc19aFelipe de Oliveira Tanus	 * unique and mutually compatible */
189a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
190828684f9a6e096f9150bad523c43b75d74b9baddDirk Hohndel	/* note that mutual compatibility is not an issue here */
191a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	if (cmd->stop_src != TRIG_TIMER && cmd->stop_src != TRIG_EXT)
192a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		err++;
193a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
194a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	if (err)
195a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		return 2;
196a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
197a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	/* step 3: make sure arguments are trivially compatible */
198a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
199a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	if (cmd->start_arg != 0) {
200a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		cmd->start_arg = 0;
201a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		err++;
202a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	}
203a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	if (cmd->scan_begin_arg > 1000000000) {
204a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		cmd->scan_begin_arg = 1000000000;
205a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		err++;
206a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	}
207a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	if (cmd->scan_begin_arg < DT2814_MAX_SPEED) {
208a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		cmd->scan_begin_arg = DT2814_MAX_SPEED;
209a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		err++;
210a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	}
211a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	if (cmd->scan_end_arg != cmd->chanlist_len) {
212a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		cmd->scan_end_arg = cmd->chanlist_len;
213a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		err++;
214a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	}
215a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	if (cmd->stop_src == TRIG_COUNT) {
216a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		if (cmd->stop_arg < 2) {
217a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef			cmd->stop_arg = 2;
218a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef			err++;
219a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		}
220a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	} else {
221a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		/* TRIG_NONE */
222a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		if (cmd->stop_arg != 0) {
223a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef			cmd->stop_arg = 0;
224a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef			err++;
225a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		}
226a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	}
227a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
228a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	if (err)
229a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		return 3;
230a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
231a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	/* step 4: fix up any arguments */
232a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
233a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	tmp = cmd->scan_begin_arg;
234a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	dt2814_ns_to_timer(&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK);
235a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	if (tmp != cmd->scan_begin_arg)
236a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		err++;
237a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
238a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	if (err)
239a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		return 4;
240a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
241a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	return 0;
242a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef}
243a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
244da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int dt2814_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
245a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef{
246ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd *cmd = &s->async->cmd;
247a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	int chan;
248a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	int trigvar;
249a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
250a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	trigvar =
2510a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    dt2814_ns_to_timer(&cmd->scan_begin_arg,
2520a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       cmd->flags & TRIG_ROUND_MASK);
253a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
254a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	chan = CR_CHAN(cmd->chanlist[0]);
255a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
256a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	devpriv->ntrig = cmd->stop_arg;
257a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	outb(chan | DT2814_ENB | (trigvar << 5), dev->iobase + DT2814_CSR);
258a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
259a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	return 0;
260a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
261a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef}
262a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
263da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int dt2814_attach(struct comedi_device *dev, struct comedi_devconfig *it)
264a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef{
265a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	int i, irq;
266a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	int ret;
26734c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
268a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	unsigned long iobase;
269a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
270a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	iobase = it->options[0];
2713f3ba29c78c4039a9fd746065ff89afec8bbc19aFelipe de Oliveira Tanus	printk(KERN_INFO "comedi%d: dt2814: 0x%04lx ", dev->minor, iobase);
272a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	if (!request_region(iobase, DT2814_SIZE, "dt2814")) {
2733f3ba29c78c4039a9fd746065ff89afec8bbc19aFelipe de Oliveira Tanus		printk(KERN_ERR "I/O port conflict\n");
274a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		return -EIO;
275a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	}
276a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	dev->iobase = iobase;
277a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	dev->board_name = "dt2814";
278a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
279a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	outb(0, dev->iobase + DT2814_CSR);
2805f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	udelay(100);
281a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	if (inb(dev->iobase + DT2814_CSR) & DT2814_ERR) {
2823f3ba29c78c4039a9fd746065ff89afec8bbc19aFelipe de Oliveira Tanus		printk(KERN_ERR "reset error (fatal)\n");
283a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		return -EIO;
284a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	}
285a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	i = inb(dev->iobase + DT2814_DATA);
286a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	i = inb(dev->iobase + DT2814_DATA);
287a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
288a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	irq = it->options[1];
289a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef#if 0
290a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	if (irq < 0) {
291a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		save_flags(flags);
292a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		sti();
293a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		irqs = probe_irq_on();
294a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
295a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		outb(0, dev->iobase + DT2814_CSR);
296a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
2975f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman		udelay(100);
298a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
299a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		irq = probe_irq_off(irqs);
300a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		restore_flags(flags);
3013f3ba29c78c4039a9fd746065ff89afec8bbc19aFelipe de Oliveira Tanus		if (inb(dev->iobase + DT2814_CSR) & DT2814_ERR)
3023f3ba29c78c4039a9fd746065ff89afec8bbc19aFelipe de Oliveira Tanus			printk(KERN_DEBUG "error probing irq (bad)\n");
3033f3ba29c78c4039a9fd746065ff89afec8bbc19aFelipe de Oliveira Tanus
304a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
305a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		i = inb(dev->iobase + DT2814_DATA);
306a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		i = inb(dev->iobase + DT2814_DATA);
307a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	}
308a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef#endif
309a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	dev->irq = 0;
310a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	if (irq > 0) {
3115f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman		if (request_irq(irq, dt2814_interrupt, 0, "dt2814", dev)) {
3123f3ba29c78c4039a9fd746065ff89afec8bbc19aFelipe de Oliveira Tanus			printk(KERN_WARNING "(irq %d unavailable)\n", irq);
313a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		} else {
3143f3ba29c78c4039a9fd746065ff89afec8bbc19aFelipe de Oliveira Tanus			printk(KERN_INFO "( irq = %d )\n", irq);
315a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef			dev->irq = irq;
316a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		}
317a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	} else if (irq == 0) {
3183f3ba29c78c4039a9fd746065ff89afec8bbc19aFelipe de Oliveira Tanus		printk(KERN_WARNING "(no irq)\n");
319a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	} else {
320a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef#if 0
3213f3ba29c78c4039a9fd746065ff89afec8bbc19aFelipe de Oliveira Tanus		printk(KERN_DEBUG "(probe returned multiple irqs--bad)\n");
322a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef#else
3233f3ba29c78c4039a9fd746065ff89afec8bbc19aFelipe de Oliveira Tanus		printk(KERN_WARNING "(irq probe not implemented)\n");
324a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef#endif
325a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	}
326a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
327c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	ret = alloc_subdevices(dev, 1);
328c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	if (ret < 0)
329a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		return ret;
330c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton
331c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	ret = alloc_private(dev, sizeof(struct dt2814_private));
332c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	if (ret < 0)
333a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		return ret;
334a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
335a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	s = dev->subdevices + 0;
336a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	dev->read_subdev = s;
337a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	s->type = COMEDI_SUBD_AI;
338a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
339a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	s->n_chan = 16;		/* XXX */
340a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	s->len_chanlist = 1;
341a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	s->insn_read = dt2814_ai_insn_read;
342a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	s->do_cmd = dt2814_ai_cmd;
343a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	s->do_cmdtest = dt2814_ai_cmdtest;
344a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	s->maxdata = 0xfff;
345a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	s->range_table = &range_unknown;	/* XXX */
346a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
347a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	return 0;
348a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef}
349a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
350da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int dt2814_detach(struct comedi_device *dev)
351a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef{
3523f3ba29c78c4039a9fd746065ff89afec8bbc19aFelipe de Oliveira Tanus	printk(KERN_INFO "comedi%d: dt2814: remove\n", dev->minor);
353a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
3543f3ba29c78c4039a9fd746065ff89afec8bbc19aFelipe de Oliveira Tanus	if (dev->irq)
3555f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman		free_irq(dev->irq, dev);
3563f3ba29c78c4039a9fd746065ff89afec8bbc19aFelipe de Oliveira Tanus
3573f3ba29c78c4039a9fd746065ff89afec8bbc19aFelipe de Oliveira Tanus	if (dev->iobase)
358a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		release_region(dev->iobase, DT2814_SIZE);
359a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
360a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	return 0;
361a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef}
362a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
36370265d24e3404fe798b6edd55a02016b1edb49d7Jiri Slabystatic irqreturn_t dt2814_interrupt(int irq, void *d)
364a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef{
365a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	int lo, hi;
36671b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = d;
36734c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
368a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	int data;
369a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
370a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	if (!dev->attached) {
371a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		comedi_error(dev, "spurious interrupt");
372a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		return IRQ_HANDLED;
373a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	}
374a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
375a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	s = dev->subdevices + 0;
376a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
377a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	hi = inb(dev->iobase + DT2814_DATA);
378a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	lo = inb(dev->iobase + DT2814_DATA);
379a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
380a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	data = (hi << 4) | (lo >> 4);
381a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
382a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	if (!(--devpriv->ntrig)) {
383a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		int i;
384a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
385a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		outb(0, dev->iobase + DT2814_CSR);
386a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		/* note: turning off timed mode triggers another
387a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		   sample. */
388a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
389a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		for (i = 0; i < DT2814_TIMEOUT; i++) {
390a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef			if (inb(dev->iobase + DT2814_CSR) & DT2814_FINISH)
391a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef				break;
392a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		}
393a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		inb(dev->iobase + DT2814_DATA);
394a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		inb(dev->iobase + DT2814_DATA);
395a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef
396a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef		s->async->events |= COMEDI_CB_EOA;
397a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	}
398a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	comedi_event(dev, s);
399a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef	return IRQ_HANDLED;
400a211ea977a4127a88fe0a5c4846e33d0e8b2309fDavid Schleef}
40190f703d30dd3e0c16ff80f35e34e511385a05ad5Arun Thomas
40290f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_AUTHOR("Comedi http://www.comedi.org");
40390f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_DESCRIPTION("Comedi low-level driver");
40490f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_LICENSE("GPL");
405