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