1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53#include <linux/ioport.h>
54#include <linux/interrupt.h>
55#include <linux/slab.h>
56
57#include "../comedidev.h"
58
59#include <pcmcia/cistpl.h>
60#include <pcmcia/ds.h>
61
62
63#define DIO_W 0x04
64#define DIO_R 0x05
65#define CMD_R1 0x00
66#define CMD_R2 0x07
67#define CMD_R3 0x05
68#define STA_R1 0x00
69#define STA_R2 0x01
70#define ADFIFO_R 0x02
71#define ADCLEAR_R 0x01
72#define CDA_R0 0x08
73#define CDA_R1 0x09
74#define CDA_R2 0x0A
75#define CMO_R 0x0B
76#define TIC_R 0x06
77
78static int daq700_dio_insn_bits(struct comedi_device *dev,
79 struct comedi_subdevice *s,
80 struct comedi_insn *insn, unsigned int *data)
81{
82 if (data[0]) {
83 s->state &= ~data[0];
84 s->state |= (data[0] & data[1]);
85
86 if (data[0] & 0xff)
87 outb(s->state & 0xff, dev->iobase + DIO_W);
88 }
89
90 data[1] = s->state & 0xff;
91 data[1] |= inb(dev->iobase + DIO_R) << 8;
92
93 return insn->n;
94}
95
96static int daq700_dio_insn_config(struct comedi_device *dev,
97 struct comedi_subdevice *s,
98 struct comedi_insn *insn, unsigned int *data)
99{
100 unsigned int chan = 1 << CR_CHAN(insn->chanspec);
101
102 switch (data[0]) {
103 case INSN_CONFIG_DIO_INPUT:
104 break;
105 case INSN_CONFIG_DIO_OUTPUT:
106 break;
107 case INSN_CONFIG_DIO_QUERY:
108 data[1] = (s->io_bits & chan) ? COMEDI_OUTPUT : COMEDI_INPUT;
109 break;
110 default:
111 return -EINVAL;
112 }
113
114 return insn->n;
115}
116
117static int daq700_ai_rinsn(struct comedi_device *dev,
118 struct comedi_subdevice *s,
119 struct comedi_insn *insn, unsigned int *data)
120{
121 int n, i, chan;
122 int d;
123 unsigned int status;
124 enum { TIMEOUT = 100 };
125
126 chan = CR_CHAN(insn->chanspec);
127
128
129 outb(chan | 0x80, dev->iobase + CMD_R1);
130
131
132 for (n = 0; n < insn->n; n++) {
133
134 outb(0x00, dev->iobase + CMD_R2);
135 outb(0x30, dev->iobase + CMO_R);
136
137 outb(0x32, dev->iobase + CMO_R);
138
139 for (i = 0; i < TIMEOUT; i++) {
140 status = inb(dev->iobase + STA_R2);
141 if ((status & 0x03) != 0) {
142 dev_info(dev->class_dev,
143 "Overflow/run Error\n");
144 return -EOVERFLOW;
145 }
146 status = inb(dev->iobase + STA_R1);
147 if ((status & 0x02) != 0) {
148 dev_info(dev->class_dev, "Data Error\n");
149 return -ENODATA;
150 }
151 if ((status & 0x11) == 0x01) {
152
153 break;
154 }
155 udelay(1);
156 }
157 if (i == TIMEOUT) {
158 dev_info(dev->class_dev,
159 "timeout during ADC conversion\n");
160 return -ETIMEDOUT;
161 }
162
163 d = inw(dev->iobase + ADFIFO_R);
164
165
166 d &= 0x0fff;
167 d ^= 0x0800;
168 data[n] = d;
169 }
170 return n;
171}
172
173
174
175
176
177
178
179
180
181
182
183
184static void daq700_ai_config(struct comedi_device *dev,
185 struct comedi_subdevice *s)
186{
187 unsigned long iobase = dev->iobase;
188
189 outb(0x80, iobase + CMD_R1);
190 outb(0x00, iobase + CMD_R2);
191 outb(0x00, iobase + CMD_R3);
192 outb(0x32, iobase + CMO_R);
193 outb(0x00, iobase + TIC_R);
194 outb(0x00, iobase + ADCLEAR_R);
195 inw(iobase + ADFIFO_R);
196}
197
198static int daq700_auto_attach(struct comedi_device *dev,
199 unsigned long context)
200{
201 struct pcmcia_device *link = comedi_to_pcmcia_dev(dev);
202 struct comedi_subdevice *s;
203 int ret;
204
205 dev->board_name = dev->driver->driver_name;
206
207 link->config_flags |= CONF_AUTO_SET_IO;
208 ret = comedi_pcmcia_enable(dev, NULL);
209 if (ret)
210 return ret;
211 dev->iobase = link->resource[0]->start;
212
213 ret = comedi_alloc_subdevices(dev, 2);
214 if (ret)
215 return ret;
216
217
218 s = &dev->subdevices[0];
219 s->type = COMEDI_SUBD_DIO;
220 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
221 s->n_chan = 16;
222 s->range_table = &range_digital;
223 s->maxdata = 1;
224 s->insn_bits = daq700_dio_insn_bits;
225 s->insn_config = daq700_dio_insn_config;
226 s->state = 0;
227 s->io_bits = 0x00ff;
228
229
230 s = &dev->subdevices[1];
231 s->type = COMEDI_SUBD_AI;
232
233 s->subdev_flags = SDF_READABLE | SDF_GROUND;
234 s->n_chan = 16;
235 s->maxdata = (1 << 12) - 1;
236 s->range_table = &range_bipolar10;
237 s->insn_read = daq700_ai_rinsn;
238 daq700_ai_config(dev, s);
239
240 dev_info(dev->class_dev, "%s: %s, io 0x%lx\n",
241 dev->driver->driver_name,
242 dev->board_name,
243 dev->iobase);
244
245 return 0;
246}
247
248static struct comedi_driver daq700_driver = {
249 .driver_name = "ni_daq_700",
250 .module = THIS_MODULE,
251 .auto_attach = daq700_auto_attach,
252 .detach = comedi_pcmcia_disable,
253};
254
255static int daq700_cs_attach(struct pcmcia_device *link)
256{
257 return comedi_pcmcia_auto_config(link, &daq700_driver);
258}
259
260static const struct pcmcia_device_id daq700_cs_ids[] = {
261 PCMCIA_DEVICE_MANF_CARD(0x010b, 0x4743),
262 PCMCIA_DEVICE_NULL
263};
264MODULE_DEVICE_TABLE(pcmcia, daq700_cs_ids);
265
266static struct pcmcia_driver daq700_cs_driver = {
267 .name = "ni_daq_700",
268 .owner = THIS_MODULE,
269 .id_table = daq700_cs_ids,
270 .probe = daq700_cs_attach,
271 .remove = comedi_pcmcia_auto_unconfig,
272};
273module_comedi_pcmcia_driver(daq700_driver, daq700_cs_driver);
274
275MODULE_AUTHOR("Fred Brooks <nsaspook@nsaspook.com>");
276MODULE_DESCRIPTION(
277 "Comedi driver for National Instruments PCMCIA DAQCard-700 DIO/AI");
278MODULE_VERSION("0.2.00");
279MODULE_LICENSE("GPL");
280