2 * comedi/drivers/ni_daq_700.c
3 * Driver for DAQCard-700 DIO/AI
6 * COMEDI - Linux Control and Measurement Device Interface
7 * Copyright (C) 1998 David A. Schleef <ds@schleef.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 Description: National Instruments PCMCIA DAQCard-700 DIO only
28 Author: Fred Brooks <nsaspook@nsaspook.com>,
29 based on ni_daq_dio24 by Daniel Vecino Castel <dvecino@able.es>
30 Devices: [National Instruments] PCMCIA DAQ-Card-700 (ni_daq_700)
32 Updated: Wed, 19 Sep 2012 12:07:20 +0000
34 The daqcard-700 appears in Comedi as a digital I/O subdevice (0) with
35 16 channels and a analog input subdevice (1) with 16 single-ended channels.
37 Digital: The channel 0 corresponds to the daqcard-700's output
38 port, bit 0; channel 8 corresponds to the input port, bit 0.
40 Digital direction configuration: channels 0-7 output, 8-15 input (8225 device
41 emu as port A output, port B input, port C N/A).
43 Analog: The input range is 0 to 4095 for -10 to +10 volts
44 IRQ is assigned but not used.
46 Version 0.1 Original DIO only driver
47 Version 0.2 DIO and basic AI analog input support on 16 se channels
49 Manuals: Register level: http://www.ni.com/pdf/manuals/340698.pdf
50 User Manual: http://www.ni.com/pdf/manuals/320676d.pdf
53 #include <linux/interrupt.h>
54 #include <linux/slab.h>
55 #include "../comedidev.h"
57 #include <linux/ioport.h>
59 #include <pcmcia/cistpl.h>
60 #include <pcmcia/cisreg.h>
61 #include <pcmcia/ds.h>
63 static struct pcmcia_device *pcmcia_cur_dev;
69 /* daqcard700 registers */
70 #define DIO_W 0x04 /* WO 8bit */
71 #define DIO_R 0x05 /* RO 8bit */
72 #define CMD_R1 0x00 /* WO 8bit */
73 #define CMD_R2 0x07 /* RW 8bit */
74 #define CMD_R3 0x05 /* W0 8bit */
75 #define STA_R1 0x00 /* RO 8bit */
76 #define STA_R2 0x01 /* RO 8bit */
77 #define ADFIFO_R 0x02 /* RO 16bit */
78 #define ADCLEAR_R 0x01 /* WO 8bit */
79 #define CDA_R0 0x08 /* RW 8bit */
80 #define CDA_R1 0x09 /* RW 8bit */
81 #define CDA_R2 0x0A /* RW 8bit */
82 #define CMO_R 0x0B /* RO 8bit */
83 #define TIC_R 0x06 /* WO 8bit */
85 static int daq700_dio_insn_bits(struct comedi_device *dev,
86 struct comedi_subdevice *s,
87 struct comedi_insn *insn, unsigned int *data)
91 s->state |= (data[0] & data[1]);
94 outb(s->state & 0xff, dev->iobase + DIO_W);
97 data[1] = s->state & 0xff;
98 data[1] |= inb(dev->iobase + DIO_R) << 8;
103 static int daq700_dio_insn_config(struct comedi_device *dev,
104 struct comedi_subdevice *s,
105 struct comedi_insn *insn, unsigned int *data)
107 unsigned int chan = 1 << CR_CHAN(insn->chanspec);
110 case INSN_CONFIG_DIO_INPUT:
112 case INSN_CONFIG_DIO_OUTPUT:
114 case INSN_CONFIG_DIO_QUERY:
115 data[1] = (s->io_bits & chan) ? COMEDI_OUTPUT : COMEDI_INPUT;
124 static int daq700_ai_rinsn(struct comedi_device *dev,
125 struct comedi_subdevice *s,
126 struct comedi_insn *insn, unsigned int *data)
131 enum { TIMEOUT = 100 };
133 chan = CR_CHAN(insn->chanspec);
134 /* write channel to multiplexer */
135 /* set mask scan bit high to disable scanning */
136 outb(chan | 0x80, dev->iobase + CMD_R1);
138 /* convert n samples */
139 for (n = 0; n < insn->n; n++) {
140 /* trigger conversion with out0 L to H */
141 outb(0x00, dev->iobase + CMD_R2); /* enable ADC conversions */
142 outb(0x30, dev->iobase + CMO_R); /* mode 0 out0 L, from H */
143 /* mode 1 out0 H, L to H, start conversion */
144 outb(0x32, dev->iobase + CMO_R);
145 /* wait for conversion to end */
146 for (i = 0; i < TIMEOUT; i++) {
147 status = inb(dev->iobase + STA_R2);
148 if ((status & 0x03) != 0) {
149 dev_info(dev->class_dev,
150 "Overflow/run Error\n");
153 status = inb(dev->iobase + STA_R1);
154 if ((status & 0x02) != 0) {
155 dev_info(dev->class_dev, "Data Error\n");
158 if ((status & 0x11) == 0x01) {
159 /* ADC conversion complete */
165 dev_info(dev->class_dev,
166 "timeout during ADC conversion\n");
170 d = inw(dev->iobase + ADFIFO_R);
171 /* mangle the data as necessary */
172 /* Bipolar Offset Binary: 0 to 4095 for -10 to +10 */
181 * Data acquisition is enabled.
182 * The counter 0 output is high.
183 * The I/O connector pin CLK1 drives counter 1 source.
184 * Multiple-channel scanning is disabled.
185 * All interrupts are disabled.
186 * The analog input range is set to +-10 V
187 * The analog input mode is single-ended.
188 * The analog input circuitry is initialized to channel 0.
189 * The A/D FIFO is cleared.
191 static void daq700_ai_config(struct comedi_device *dev,
192 struct comedi_subdevice *s)
194 unsigned long iobase = dev->iobase;
196 outb(0x80, iobase + CMD_R1); /* disable scanning, ADC to chan 0 */
197 outb(0x00, iobase + CMD_R2); /* clear all bits */
198 outb(0x00, iobase + CMD_R3); /* set +-10 range */
199 outb(0x32, iobase + CMO_R); /* config counter mode1, out0 to H */
200 outb(0x00, iobase + TIC_R); /* clear counter interrupt */
201 outb(0x00, iobase + ADCLEAR_R); /* clear the ADC FIFO */
202 inw(iobase + ADFIFO_R); /* read 16bit junk from FIFO to clear */
205 static int daq700_attach(struct comedi_device *dev, struct comedi_devconfig *it)
207 const struct daq700_board *thisboard = comedi_board(dev);
208 struct comedi_subdevice *s;
209 struct pcmcia_device *link;
212 link = pcmcia_cur_dev; /* XXX hack */
216 dev->iobase = link->resource[0]->start;
218 dev_err(dev->class_dev, "io base address is zero!\n");
222 dev->board_name = thisboard->name;
224 ret = comedi_alloc_subdevices(dev, 2);
228 /* DAQCard-700 dio */
229 s = &dev->subdevices[0];
230 s->type = COMEDI_SUBD_DIO;
231 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
233 s->range_table = &range_digital;
235 s->insn_bits = daq700_dio_insn_bits;
236 s->insn_config = daq700_dio_insn_config;
241 s = &dev->subdevices[1];
242 s->type = COMEDI_SUBD_AI;
243 /* we support single-ended (ground) */
244 s->subdev_flags = SDF_READABLE | SDF_GROUND;
246 s->maxdata = (1 << 12) - 1;
247 s->range_table = &range_bipolar10;
248 s->insn_read = daq700_ai_rinsn;
249 daq700_ai_config(dev, s);
251 dev_info(dev->class_dev, "%s: %s, io 0x%lx\n",
252 dev->driver->driver_name,
259 static void daq700_detach(struct comedi_device *dev)
261 /* nothing to cleanup */
264 static const struct daq700_board daq700_boards[] = {
266 .name = "daqcard-700",
268 .name = "ni_daq_700",
272 static struct comedi_driver daq700_driver = {
273 .driver_name = "ni_daq_700",
274 .module = THIS_MODULE,
275 .attach = daq700_attach,
276 .detach = daq700_detach,
277 .board_name = &daq700_boards[0].name,
278 .num_names = ARRAY_SIZE(daq700_boards),
279 .offset = sizeof(struct daq700_board),
282 static int daq700_pcmcia_config_loop(struct pcmcia_device *p_dev,
285 if (p_dev->config_index == 0)
288 return pcmcia_request_io(p_dev);
291 static int daq700_cs_attach(struct pcmcia_device *link)
295 link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_AUDIO |
298 ret = pcmcia_loop_config(link, daq700_pcmcia_config_loop, NULL);
305 ret = pcmcia_enable_device(link);
309 pcmcia_cur_dev = link;
313 pcmcia_disable_device(link);
317 static void daq700_cs_detach(struct pcmcia_device *link)
319 pcmcia_disable_device(link);
320 pcmcia_cur_dev = NULL;
323 static const struct pcmcia_device_id daq700_cs_ids[] = {
324 PCMCIA_DEVICE_MANF_CARD(0x010b, 0x4743),
327 MODULE_DEVICE_TABLE(pcmcia, daq700_cs_ids);
329 static struct pcmcia_driver daq700_cs_driver = {
330 .name = "ni_daq_700",
331 .owner = THIS_MODULE,
332 .probe = daq700_cs_attach,
333 .remove = daq700_cs_detach,
334 .id_table = daq700_cs_ids,
337 static int __init daq700_cs_init(void)
341 ret = comedi_driver_register(&daq700_driver);
345 ret = pcmcia_register_driver(&daq700_cs_driver);
347 comedi_driver_unregister(&daq700_driver);
353 module_init(daq700_cs_init);
355 static void __exit daq700_cs_exit(void)
357 pcmcia_unregister_driver(&daq700_cs_driver);
358 comedi_driver_unregister(&daq700_driver);
360 module_exit(daq700_cs_exit);
362 MODULE_AUTHOR("Fred Brooks <nsaspook@nsaspook.com>");
364 "Comedi driver for National Instruments PCMCIA DAQCard-700 DIO/AI");
365 MODULE_VERSION("0.2.00");
366 MODULE_LICENSE("GPL");