Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ni_daq_700.c
Go to the documentation of this file.
1 /*
2  * comedi/drivers/ni_daq_700.c
3  * Driver for DAQCard-700 DIO/AI
4  * copied from 8255
5  *
6  * COMEDI - Linux Control and Measurement Device Interface
7  * Copyright (C) 1998 David A. Schleef <[email protected]>
8  *
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.
13  *
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.
18  *
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.
22  *
23  */
24 
25 /*
26 Driver: ni_daq_700
27 Description: National Instruments PCMCIA DAQCard-700 DIO only
28 Author: Fred Brooks <[email protected]>,
29  based on ni_daq_dio24 by Daniel Vecino Castel <[email protected]>
30 Devices: [National Instruments] PCMCIA DAQ-Card-700 (ni_daq_700)
31 Status: works
32 Updated: Wed, 19 Sep 2012 12:07:20 +0000
33 
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.
36 
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.
39 
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).
42 
43 Analog: The input range is 0 to 4095 for -10 to +10 volts
44 IRQ is assigned but not used.
45 
46 Version 0.1 Original DIO only driver
47 Version 0.2 DIO and basic AI analog input support on 16 se channels
48 
49 Manuals: Register level: http://www.ni.com/pdf/manuals/340698.pdf
50  User Manual: http://www.ni.com/pdf/manuals/320676d.pdf
51 */
52 
53 #include <linux/interrupt.h>
54 #include <linux/slab.h>
55 #include "../comedidev.h"
56 
57 #include <linux/ioport.h>
58 
59 #include <pcmcia/cistpl.h>
60 #include <pcmcia/cisreg.h>
61 #include <pcmcia/ds.h>
62 
63 static struct pcmcia_device *pcmcia_cur_dev;
64 
65 struct daq700_board {
66  const char *name;
67 };
68 
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 */
84 
85 static int daq700_dio_insn_bits(struct comedi_device *dev,
86  struct comedi_subdevice *s,
87  struct comedi_insn *insn, unsigned int *data)
88 {
89  if (data[0]) {
90  s->state &= ~data[0];
91  s->state |= (data[0] & data[1]);
92 
93  if (data[0] & 0xff)
94  outb(s->state & 0xff, dev->iobase + DIO_W);
95  }
96 
97  data[1] = s->state & 0xff;
98  data[1] |= inb(dev->iobase + DIO_R) << 8;
99 
100  return insn->n;
101 }
102 
103 static int daq700_dio_insn_config(struct comedi_device *dev,
104  struct comedi_subdevice *s,
105  struct comedi_insn *insn, unsigned int *data)
106 {
107  unsigned int chan = 1 << CR_CHAN(insn->chanspec);
108 
109  switch (data[0]) {
111  break;
113  break;
115  data[1] = (s->io_bits & chan) ? COMEDI_OUTPUT : COMEDI_INPUT;
116  break;
117  default:
118  return -EINVAL;
119  }
120 
121  return insn->n;
122 }
123 
124 static int daq700_ai_rinsn(struct comedi_device *dev,
125  struct comedi_subdevice *s,
126  struct comedi_insn *insn, unsigned int *data)
127 {
128  int n, i, chan;
129  int d;
130  unsigned int status;
131  enum { TIMEOUT = 100 };
132 
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);
137 
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");
151  return -EOVERFLOW;
152  }
153  status = inb(dev->iobase + STA_R1);
154  if ((status & 0x02) != 0) {
155  dev_info(dev->class_dev, "Data Error\n");
156  return -ENODATA;
157  }
158  if ((status & 0x11) == 0x01) {
159  /* ADC conversion complete */
160  break;
161  }
162  udelay(1);
163  }
164  if (i == TIMEOUT) {
165  dev_info(dev->class_dev,
166  "timeout during ADC conversion\n");
167  return -ETIMEDOUT;
168  }
169  /* read data */
170  d = inw(dev->iobase + ADFIFO_R);
171  /* mangle the data as necessary */
172  /* Bipolar Offset Binary: 0 to 4095 for -10 to +10 */
173  d &= 0x0fff;
174  d ^= 0x0800;
175  data[n] = d;
176  }
177  return n;
178 }
179 
180 /*
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.
190  */
191 static void daq700_ai_config(struct comedi_device *dev,
192  struct comedi_subdevice *s)
193 {
194  unsigned long iobase = dev->iobase;
195 
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 */
203 }
204 
205 static int daq700_attach(struct comedi_device *dev, struct comedi_devconfig *it)
206 {
207  const struct daq700_board *thisboard = comedi_board(dev);
208  struct comedi_subdevice *s;
209  struct pcmcia_device *link;
210  int ret;
211 
212  link = pcmcia_cur_dev; /* XXX hack */
213  if (!link)
214  return -EIO;
215 
216  dev->iobase = link->resource[0]->start;
217  if (!dev->iobase) {
218  dev_err(dev->class_dev, "io base address is zero!\n");
219  return -EINVAL;
220  }
221 
222  dev->board_name = thisboard->name;
223 
224  ret = comedi_alloc_subdevices(dev, 2);
225  if (ret)
226  return ret;
227 
228  /* DAQCard-700 dio */
229  s = &dev->subdevices[0];
230  s->type = COMEDI_SUBD_DIO;
232  s->n_chan = 16;
234  s->maxdata = 1;
235  s->insn_bits = daq700_dio_insn_bits;
236  s->insn_config = daq700_dio_insn_config;
237  s->state = 0;
238  s->io_bits = 0x00ff;
239 
240  /* DAQCard-700 ai */
241  s = &dev->subdevices[1];
242  s->type = COMEDI_SUBD_AI;
243  /* we support single-ended (ground) */
245  s->n_chan = 16;
246  s->maxdata = (1 << 12) - 1;
248  s->insn_read = daq700_ai_rinsn;
249  daq700_ai_config(dev, s);
250 
251  dev_info(dev->class_dev, "%s: %s, io 0x%lx\n",
252  dev->driver->driver_name,
253  dev->board_name,
254  dev->iobase);
255 
256  return 0;
257 }
258 
259 static void daq700_detach(struct comedi_device *dev)
260 {
261  /* nothing to cleanup */
262 }
263 
264 static const struct daq700_board daq700_boards[] = {
265  {
266  .name = "daqcard-700",
267  }, {
268  .name = "ni_daq_700",
269  },
270 };
271 
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),
280 };
281 
282 static int daq700_pcmcia_config_loop(struct pcmcia_device *p_dev,
283  void *priv_data)
284 {
285  if (p_dev->config_index == 0)
286  return -EINVAL;
287 
288  return pcmcia_request_io(p_dev);
289 }
290 
291 static int daq700_cs_attach(struct pcmcia_device *link)
292 {
293  int ret;
294 
295  link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_AUDIO |
296  CONF_AUTO_SET_IO;
297 
298  ret = pcmcia_loop_config(link, daq700_pcmcia_config_loop, NULL);
299  if (ret)
300  goto failed;
301 
302  if (!link->irq)
303  goto failed;
304 
305  ret = pcmcia_enable_device(link);
306  if (ret)
307  goto failed;
308 
309  pcmcia_cur_dev = link;
310  return 0;
311 
312 failed:
313  pcmcia_disable_device(link);
314  return ret;
315 }
316 
317 static void daq700_cs_detach(struct pcmcia_device *link)
318 {
319  pcmcia_disable_device(link);
320  pcmcia_cur_dev = NULL;
321 }
322 
323 static const struct pcmcia_device_id daq700_cs_ids[] = {
324  PCMCIA_DEVICE_MANF_CARD(0x010b, 0x4743),
325  PCMCIA_DEVICE_NULL
326 };
327 MODULE_DEVICE_TABLE(pcmcia, daq700_cs_ids);
328 
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,
335 };
336 
337 static int __init daq700_cs_init(void)
338 {
339  int ret;
340 
341  ret = comedi_driver_register(&daq700_driver);
342  if (ret < 0)
343  return ret;
344 
345  ret = pcmcia_register_driver(&daq700_cs_driver);
346  if (ret < 0) {
347  comedi_driver_unregister(&daq700_driver);
348  return ret;
349  }
350 
351  return 0;
352 }
353 module_init(daq700_cs_init);
354 
355 static void __exit daq700_cs_exit(void)
356 {
357  pcmcia_unregister_driver(&daq700_cs_driver);
358  comedi_driver_unregister(&daq700_driver);
359 }
360 module_exit(daq700_cs_exit);
361 
362 MODULE_AUTHOR("Fred Brooks <[email protected]>");
364  "Comedi driver for National Instruments PCMCIA DAQCard-700 DIO/AI");
365 MODULE_VERSION("0.2.00");
366 MODULE_LICENSE("GPL");