Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ni_atmio.c
Go to the documentation of this file.
1 /*
2  comedi/drivers/ni_atmio.c
3  Hardware driver for NI AT-MIO E series cards
4 
5  COMEDI - Linux Control and Measurement Device Interface
6  Copyright (C) 1997-2001 David A. Schleef <[email protected]>
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 Driver: ni_atmio
24 Description: National Instruments AT-MIO-E series
25 Author: ds
26 Devices: [National Instruments] AT-MIO-16E-1 (ni_atmio),
27  AT-MIO-16E-2, AT-MIO-16E-10, AT-MIO-16DE-10, AT-MIO-64E-3,
28  AT-MIO-16XE-50, AT-MIO-16XE-10, AT-AI-16XE-10
29 Status: works
30 Updated: Thu May 1 20:03:02 CDT 2003
31 
32 The driver has 2.6 kernel isapnp support, and
33 will automatically probe for a supported board if the
34 I/O base is left unspecified with comedi_config.
35 However, many of
36 the isapnp id numbers are unknown. If your board is not
37 recognized, please send the output of 'cat /proc/isapnp'
38 (you may need to modprobe the isa-pnp module for
39 /proc/isapnp to exist) so the
40 id numbers for your board can be added to the driver.
41 
42 Otherwise, you can use the isapnptools package to configure
43 your board. Use isapnp to
44 configure the I/O base and IRQ for the board, and then pass
45 the same values as
46 parameters in comedi_config. A sample isapnp.conf file is included
47 in the etc/ directory of Comedilib.
48 
49 Comedilib includes a utility to autocalibrate these boards. The
50 boards seem to boot into a state where the all calibration DACs
51 are at one extreme of their range, thus the default calibration
52 is terrible. Calibration at boot is strongly encouraged.
53 
54 To use the extended digital I/O on some of the boards, enable the
55 8255 driver when configuring the Comedi source tree.
56 
57 External triggering is supported for some events. The channel index
58 (scan_begin_arg, etc.) maps to PFI0 - PFI9.
59 
60 Some of the more esoteric triggering possibilities of these boards
61 are not supported.
62 */
63 /*
64  The real guts of the driver is in ni_mio_common.c, which is included
65  both here and in ni_pcimio.c
66 
67  Interrupt support added by Truxton Fulton <[email protected]>
68 
69  References for specifications:
70 
71  340747b.pdf Register Level Programmer Manual (obsolete)
72  340747c.pdf Register Level Programmer Manual (new)
73  DAQ-STC reference manual
74 
75  Other possibly relevant info:
76 
77  320517c.pdf User manual (obsolete)
78  320517f.pdf User manual (new)
79  320889a.pdf delete
80  320906c.pdf maximum signal ratings
81  321066a.pdf about 16x
82  321791a.pdf discontinuation of at-mio-16e-10 rev. c
83  321808a.pdf about at-mio-16e-10 rev P
84  321837a.pdf discontinuation of at-mio-16de-10 rev d
85  321838a.pdf about at-mio-16de-10 rev N
86 
87  ISSUES:
88 
89  need to deal with external reference for DAC, and other DAC
90  properties in board properties
91 
92  deal with at-mio-16de-10 revision D to N changes, etc.
93 
94 */
95 
96 #include <linux/interrupt.h>
97 #include "../comedidev.h"
98 
99 #include <linux/delay.h>
100 #include <linux/isapnp.h>
101 
102 #include "ni_stc.h"
103 #include "8255.h"
104 
105 #undef DEBUG
106 
107 #define ATMIO 1
108 #undef PCIMIO
109 
110 /*
111  * AT specific setup
112  */
113 
114 #define NI_SIZE 0x20
115 
116 #define MAX_N_CALDACS 32
117 
118 static const struct ni_board_struct ni_boards[] = {
119  {.device_id = 44,
120  .isapnp_id = 0x0000, /* XXX unknown */
121  .name = "at-mio-16e-1",
122  .n_adchan = 16,
123  .adbits = 12,
124  .ai_fifo_depth = 8192,
125  .alwaysdither = 0,
126  .gainlkup = ai_gain_16,
127  .ai_speed = 800,
128  .n_aochan = 2,
129  .aobits = 12,
130  .ao_fifo_depth = 2048,
131  .ao_range_table = &range_ni_E_ao_ext,
132  .ao_unipolar = 1,
133  .ao_speed = 1000,
134  .has_8255 = 0,
135  .num_p0_dio_channels = 8,
136  .caldac = {mb88341},
137  },
138  {.device_id = 25,
139  .isapnp_id = 0x1900,
140  .name = "at-mio-16e-2",
141  .n_adchan = 16,
142  .adbits = 12,
143  .ai_fifo_depth = 2048,
144  .alwaysdither = 0,
145  .gainlkup = ai_gain_16,
146  .ai_speed = 2000,
147  .n_aochan = 2,
148  .aobits = 12,
149  .ao_fifo_depth = 2048,
150  .ao_range_table = &range_ni_E_ao_ext,
151  .ao_unipolar = 1,
152  .ao_speed = 1000,
153  .has_8255 = 0,
154  .num_p0_dio_channels = 8,
155  .caldac = {mb88341},
156  },
157  {.device_id = 36,
158  .isapnp_id = 0x2400,
159  .name = "at-mio-16e-10",
160  .n_adchan = 16,
161  .adbits = 12,
162  .ai_fifo_depth = 512,
163  .alwaysdither = 0,
164  .gainlkup = ai_gain_16,
165  .ai_speed = 10000,
166  .n_aochan = 2,
167  .aobits = 12,
168  .ao_fifo_depth = 0,
169  .ao_range_table = &range_ni_E_ao_ext,
170  .ao_unipolar = 1,
171  .ao_speed = 10000,
172  .num_p0_dio_channels = 8,
173  .caldac = {ad8804_debug},
174  .has_8255 = 0,
175  },
176  {.device_id = 37,
177  .isapnp_id = 0x2500,
178  .name = "at-mio-16de-10",
179  .n_adchan = 16,
180  .adbits = 12,
181  .ai_fifo_depth = 512,
182  .alwaysdither = 0,
183  .gainlkup = ai_gain_16,
184  .ai_speed = 10000,
185  .n_aochan = 2,
186  .aobits = 12,
187  .ao_fifo_depth = 0,
188  .ao_range_table = &range_ni_E_ao_ext,
189  .ao_unipolar = 1,
190  .ao_speed = 10000,
191  .num_p0_dio_channels = 8,
192  .caldac = {ad8804_debug},
193  .has_8255 = 1,
194  },
195  {.device_id = 38,
196  .isapnp_id = 0x2600,
197  .name = "at-mio-64e-3",
198  .n_adchan = 64,
199  .adbits = 12,
200  .ai_fifo_depth = 2048,
201  .alwaysdither = 0,
202  .gainlkup = ai_gain_16,
203  .ai_speed = 2000,
204  .n_aochan = 2,
205  .aobits = 12,
206  .ao_fifo_depth = 2048,
207  .ao_range_table = &range_ni_E_ao_ext,
208  .ao_unipolar = 1,
209  .ao_speed = 1000,
210  .has_8255 = 0,
211  .num_p0_dio_channels = 8,
212  .caldac = {ad8804_debug},
213  },
214  {.device_id = 39,
215  .isapnp_id = 0x2700,
216  .name = "at-mio-16xe-50",
217  .n_adchan = 16,
218  .adbits = 16,
219  .ai_fifo_depth = 512,
220  .alwaysdither = 1,
221  .gainlkup = ai_gain_8,
222  .ai_speed = 50000,
223  .n_aochan = 2,
224  .aobits = 12,
225  .ao_fifo_depth = 0,
226  .ao_range_table = &range_bipolar10,
227  .ao_unipolar = 0,
228  .ao_speed = 50000,
229  .num_p0_dio_channels = 8,
230  .caldac = {dac8800, dac8043},
231  .has_8255 = 0,
232  },
233  {.device_id = 50,
234  .isapnp_id = 0x0000, /* XXX unknown */
235  .name = "at-mio-16xe-10",
236  .n_adchan = 16,
237  .adbits = 16,
238  .ai_fifo_depth = 512,
239  .alwaysdither = 1,
240  .gainlkup = ai_gain_14,
241  .ai_speed = 10000,
242  .n_aochan = 2,
243  .aobits = 16,
244  .ao_fifo_depth = 2048,
245  .ao_range_table = &range_ni_E_ao_ext,
246  .ao_unipolar = 1,
247  .ao_speed = 1000,
248  .num_p0_dio_channels = 8,
249  .caldac = {dac8800, dac8043, ad8522},
250  .has_8255 = 0,
251  },
252  {.device_id = 51,
253  .isapnp_id = 0x0000, /* XXX unknown */
254  .name = "at-ai-16xe-10",
255  .n_adchan = 16,
256  .adbits = 16,
257  .ai_fifo_depth = 512,
258  .alwaysdither = 1, /* unknown */
259  .gainlkup = ai_gain_14,
260  .ai_speed = 10000,
261  .n_aochan = 0,
262  .aobits = 0,
263  .ao_fifo_depth = 0,
264  .ao_unipolar = 0,
265  .num_p0_dio_channels = 8,
266  .caldac = {dac8800, dac8043, ad8522},
267  .has_8255 = 0,
268  }
269 };
270 
271 static const int ni_irqpin[] = {
272  -1, -1, -1, 0, 1, 2, -1, 3, -1, -1, 4, 5, 6, -1, -1, 7
273 };
274 
275 #define interrupt_pin(a) (ni_irqpin[(a)])
276 
277 #define IRQ_POLARITY 0
278 
279 #define NI_E_IRQ_FLAGS 0
280 
281 struct ni_private {
284 
285 };
286 
287 #define devpriv ((struct ni_private *)dev->private)
288 
289 /* How we access registers */
290 
291 #define ni_writel(a, b) (outl((a), (b)+dev->iobase))
292 #define ni_readl(a) (inl((a)+dev->iobase))
293 #define ni_writew(a, b) (outw((a), (b)+dev->iobase))
294 #define ni_readw(a) (inw((a)+dev->iobase))
295 #define ni_writeb(a, b) (outb((a), (b)+dev->iobase))
296 #define ni_readb(a) (inb((a)+dev->iobase))
297 
298 /* How we access windowed registers */
299 
300 /* We automatically take advantage of STC registers that can be
301  * read/written directly in the I/O space of the board. The
302  * AT-MIO devices map the low 8 STC registers to iobase+addr*2. */
303 
304 static void ni_atmio_win_out(struct comedi_device *dev, uint16_t data, int addr)
305 {
306  unsigned long flags;
307 
308  spin_lock_irqsave(&devpriv->window_lock, flags);
309  if ((addr) < 8) {
310  ni_writew(data, addr * 2);
311  } else {
312  ni_writew(addr, Window_Address);
313  ni_writew(data, Window_Data);
314  }
315  spin_unlock_irqrestore(&devpriv->window_lock, flags);
316 }
317 
318 static uint16_t ni_atmio_win_in(struct comedi_device *dev, int addr)
319 {
320  unsigned long flags;
321  uint16_t ret;
322 
323  spin_lock_irqsave(&devpriv->window_lock, flags);
324  if (addr < 8) {
325  ret = ni_readw(addr * 2);
326  } else {
327  ni_writew(addr, Window_Address);
328  ret = ni_readw(Window_Data);
329  }
330  spin_unlock_irqrestore(&devpriv->window_lock, flags);
331 
332  return ret;
333 }
334 
335 static struct pnp_device_id device_ids[] = {
336  {.id = "NIC1900", .driver_data = 0},
337  {.id = "NIC2400", .driver_data = 0},
338  {.id = "NIC2500", .driver_data = 0},
339  {.id = "NIC2600", .driver_data = 0},
340  {.id = "NIC2700", .driver_data = 0},
341  {.id = ""}
342 };
343 
344 MODULE_DEVICE_TABLE(pnp, device_ids);
345 
346 #include "ni_mio_common.c"
347 
348 static int ni_isapnp_find_board(struct pnp_dev **dev)
349 {
350  struct pnp_dev *isapnp_dev = NULL;
351  int i;
352 
353  for (i = 0; i < n_ni_boards; i++) {
354  isapnp_dev = pnp_find_dev(NULL,
355  ISAPNP_VENDOR('N', 'I', 'C'),
356  ISAPNP_FUNCTION(ni_boards[i].
357  isapnp_id), NULL);
358 
359  if (isapnp_dev == NULL || isapnp_dev->card == NULL)
360  continue;
361 
362  if (pnp_device_attach(isapnp_dev) < 0) {
363  printk
364  ("ni_atmio: %s found but already active, skipping.\n",
365  ni_boards[i].name);
366  continue;
367  }
368  if (pnp_activate_dev(isapnp_dev) < 0) {
369  pnp_device_detach(isapnp_dev);
370  return -EAGAIN;
371  }
372  if (!pnp_port_valid(isapnp_dev, 0)
373  || !pnp_irq_valid(isapnp_dev, 0)) {
374  pnp_device_detach(isapnp_dev);
375  printk("ni_atmio: pnp invalid port or irq, aborting\n");
376  return -ENOMEM;
377  }
378  break;
379  }
380  if (i == n_ni_boards)
381  return -ENODEV;
382  *dev = isapnp_dev;
383  return 0;
384 }
385 
386 static int ni_getboardtype(struct comedi_device *dev)
387 {
388  int device_id = ni_read_eeprom(dev, 511);
389  int i;
390 
391  for (i = 0; i < n_ni_boards; i++) {
392  if (ni_boards[i].device_id == device_id)
393  return i;
394 
395  }
396  if (device_id == 255)
397  printk(" can't find board\n");
398  else if (device_id == 0)
399  printk(" EEPROM read error (?) or device not found\n");
400  else
401  printk(" unknown device ID %d -- contact author\n", device_id);
402 
403  return -1;
404 }
405 
406 static int ni_atmio_attach(struct comedi_device *dev,
407  struct comedi_devconfig *it)
408 {
409  struct pnp_dev *isapnp_dev;
410  int ret;
411  unsigned long iobase;
412  int board;
413  unsigned int irq;
414 
415  /* allocate private area */
416  ret = ni_alloc_private(dev);
417  if (ret < 0)
418  return ret;
419 
420  devpriv->stc_writew = &ni_atmio_win_out;
421  devpriv->stc_readw = &ni_atmio_win_in;
422  devpriv->stc_writel = &win_out2;
423  devpriv->stc_readl = &win_in2;
424 
425  iobase = it->options[0];
426  irq = it->options[1];
427  isapnp_dev = NULL;
428  if (iobase == 0) {
429  ret = ni_isapnp_find_board(&isapnp_dev);
430  if (ret < 0)
431  return ret;
432 
433  iobase = pnp_port_start(isapnp_dev, 0);
434  irq = pnp_irq(isapnp_dev, 0);
435  devpriv->isapnp_dev = isapnp_dev;
436  }
437 
438  /* reserve our I/O region */
439 
440  printk("comedi%d: ni_atmio: 0x%04lx", dev->minor, iobase);
441  if (!request_region(iobase, NI_SIZE, "ni_atmio")) {
442  printk(" I/O port conflict\n");
443  return -EIO;
444  }
445 
446  dev->iobase = iobase;
447 
448 #ifdef DEBUG
449  /* board existence sanity check */
450  {
451  int i;
452 
453  printk(" board fingerprint:");
454  for (i = 0; i < 16; i += 2) {
455  printk(" %04x %02x", inw(dev->iobase + i),
456  inb(dev->iobase + i + 1));
457  }
458  }
459 #endif
460 
461  /* get board type */
462 
463  board = ni_getboardtype(dev);
464  if (board < 0)
465  return -EIO;
466 
467  dev->board_ptr = ni_boards + board;
468 
469  printk(" %s", boardtype.name);
470  dev->board_name = boardtype.name;
471 
472  /* irq stuff */
473 
474  if (irq != 0) {
475  if (irq > 15 || ni_irqpin[irq] == -1) {
476  printk(" invalid irq %u\n", irq);
477  return -EINVAL;
478  }
479  printk(" ( irq = %u )", irq);
480  ret = request_irq(irq, ni_E_interrupt, NI_E_IRQ_FLAGS,
481  "ni_atmio", dev);
482 
483  if (ret < 0) {
484  printk(" irq not available\n");
485  return -EINVAL;
486  }
487  dev->irq = irq;
488  }
489 
490  /* generic E series stuff in ni_mio_common.c */
491 
492  ret = ni_E_init(dev);
493  if (ret < 0)
494  return ret;
495 
496 
497  return 0;
498 }
499 
500 static void ni_atmio_detach(struct comedi_device *dev)
501 {
502  mio_common_detach(dev);
503  if (dev->iobase)
505  if (dev->irq)
506  free_irq(dev->irq, dev);
507  if (devpriv->isapnp_dev)
508  pnp_device_detach(devpriv->isapnp_dev);
509 }
510 
511 static struct comedi_driver ni_atmio_driver = {
512  .driver_name = "ni_atmio",
513  .module = THIS_MODULE,
514  .attach = ni_atmio_attach,
515  .detach = ni_atmio_detach,
516 };
517 module_comedi_driver(ni_atmio_driver);