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 <ds@schleef.org>
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 <trux@truxton.com>
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 {
282 struct pnp_dev *isapnp_dev;
283 NI_PRIVATE_COMMON
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
ni_atmio_win_out(struct comedi_device * dev,uint16_t data,int addr)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
ni_atmio_win_in(struct comedi_device * dev,int addr)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 static int ni_atmio_attach(struct comedi_device *dev,
347 struct comedi_devconfig *it);
348 static int ni_atmio_detach(struct comedi_device *dev);
349 static struct comedi_driver driver_atmio = {
350 .driver_name = "ni_atmio",
351 .module = THIS_MODULE,
352 .attach = ni_atmio_attach,
353 .detach = ni_atmio_detach,
354 };
355
driver_atmio_init_module(void)356 static int __init driver_atmio_init_module(void)
357 {
358 return comedi_driver_register(&driver_atmio);
359 }
360
driver_atmio_cleanup_module(void)361 static void __exit driver_atmio_cleanup_module(void)
362 {
363 comedi_driver_unregister(&driver_atmio);
364 }
365
366 module_init(driver_atmio_init_module);
367 module_exit(driver_atmio_cleanup_module);
368
369 #include "ni_mio_common.c"
370
371 static int ni_getboardtype(struct comedi_device *dev);
372
373 /* clean up allocated resources */
ni_atmio_detach(struct comedi_device * dev)374 static int ni_atmio_detach(struct comedi_device *dev)
375 {
376 mio_common_detach(dev);
377
378 if (dev->iobase)
379 release_region(dev->iobase, NI_SIZE);
380 if (dev->irq)
381 free_irq(dev->irq, dev);
382
383 if (devpriv->isapnp_dev)
384 pnp_device_detach(devpriv->isapnp_dev);
385
386 return 0;
387 }
388
ni_isapnp_find_board(struct pnp_dev ** dev)389 static int ni_isapnp_find_board(struct pnp_dev **dev)
390 {
391 struct pnp_dev *isapnp_dev = NULL;
392 int i;
393
394 for (i = 0; i < n_ni_boards; i++) {
395 isapnp_dev = pnp_find_dev(NULL,
396 ISAPNP_VENDOR('N', 'I', 'C'),
397 ISAPNP_FUNCTION(ni_boards[i].
398 isapnp_id), NULL);
399
400 if (isapnp_dev == NULL || isapnp_dev->card == NULL)
401 continue;
402
403 if (pnp_device_attach(isapnp_dev) < 0) {
404 printk
405 ("ni_atmio: %s found but already active, skipping.\n",
406 ni_boards[i].name);
407 continue;
408 }
409 if (pnp_activate_dev(isapnp_dev) < 0) {
410 pnp_device_detach(isapnp_dev);
411 return -EAGAIN;
412 }
413 if (!pnp_port_valid(isapnp_dev, 0)
414 || !pnp_irq_valid(isapnp_dev, 0)) {
415 pnp_device_detach(isapnp_dev);
416 printk("ni_atmio: pnp invalid port or irq, aborting\n");
417 return -ENOMEM;
418 }
419 break;
420 }
421 if (i == n_ni_boards)
422 return -ENODEV;
423 *dev = isapnp_dev;
424 return 0;
425 }
426
ni_atmio_attach(struct comedi_device * dev,struct comedi_devconfig * it)427 static int ni_atmio_attach(struct comedi_device *dev,
428 struct comedi_devconfig *it)
429 {
430 struct pnp_dev *isapnp_dev;
431 int ret;
432 unsigned long iobase;
433 int board;
434 unsigned int irq;
435
436 /* allocate private area */
437 ret = ni_alloc_private(dev);
438 if (ret < 0)
439 return ret;
440
441 devpriv->stc_writew = &ni_atmio_win_out;
442 devpriv->stc_readw = &ni_atmio_win_in;
443 devpriv->stc_writel = &win_out2;
444 devpriv->stc_readl = &win_in2;
445
446 iobase = it->options[0];
447 irq = it->options[1];
448 isapnp_dev = NULL;
449 if (iobase == 0) {
450 ret = ni_isapnp_find_board(&isapnp_dev);
451 if (ret < 0)
452 return ret;
453
454 iobase = pnp_port_start(isapnp_dev, 0);
455 irq = pnp_irq(isapnp_dev, 0);
456 devpriv->isapnp_dev = isapnp_dev;
457 }
458
459 /* reserve our I/O region */
460
461 printk("comedi%d: ni_atmio: 0x%04lx", dev->minor, iobase);
462 if (!request_region(iobase, NI_SIZE, "ni_atmio")) {
463 printk(" I/O port conflict\n");
464 return -EIO;
465 }
466
467 dev->iobase = iobase;
468
469 #ifdef DEBUG
470 /* board existence sanity check */
471 {
472 int i;
473
474 printk(" board fingerprint:");
475 for (i = 0; i < 16; i += 2) {
476 printk(" %04x %02x", inw(dev->iobase + i),
477 inb(dev->iobase + i + 1));
478 }
479 }
480 #endif
481
482 /* get board type */
483
484 board = ni_getboardtype(dev);
485 if (board < 0)
486 return -EIO;
487
488 dev->board_ptr = ni_boards + board;
489
490 printk(" %s", boardtype.name);
491 dev->board_name = boardtype.name;
492
493 /* irq stuff */
494
495 if (irq != 0) {
496 if (irq > 15 || ni_irqpin[irq] == -1) {
497 printk(" invalid irq %u\n", irq);
498 return -EINVAL;
499 }
500 printk(" ( irq = %u )", irq);
501 ret = request_irq(irq, ni_E_interrupt, NI_E_IRQ_FLAGS,
502 "ni_atmio", dev);
503
504 if (ret < 0) {
505 printk(" irq not available\n");
506 return -EINVAL;
507 }
508 dev->irq = irq;
509 }
510
511 /* generic E series stuff in ni_mio_common.c */
512
513 ret = ni_E_init(dev, it);
514 if (ret < 0)
515 return ret;
516
517
518 return 0;
519 }
520
ni_getboardtype(struct comedi_device * dev)521 static int ni_getboardtype(struct comedi_device *dev)
522 {
523 int device_id = ni_read_eeprom(dev, 511);
524 int i;
525
526 for (i = 0; i < n_ni_boards; i++) {
527 if (ni_boards[i].device_id == device_id)
528 return i;
529
530 }
531 if (device_id == 255)
532 printk(" can't find board\n");
533 else if (device_id == 0)
534 printk(" EEPROM read error (?) or device not found\n");
535 else
536 printk(" unknown device ID %d -- contact author\n", device_id);
537
538 return -1;
539 }
540