ni_atmio.c revision ce157f8032bbd46d9427034c335b0afd751da25d
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/delay.h> 97#include <linux/isapnp.h> 98 99#include "ni_stc.h" 100#include "8255.h" 101 102#undef DEBUG 103 104#define ATMIO 1 105#undef PCIMIO 106 107/* 108 * AT specific setup 109 */ 110 111#define NI_SIZE 0x20 112 113#define MAX_N_CALDACS 32 114 115static const struct ni_board_struct ni_boards[] = { 116 {.device_id = 44, 117 .isapnp_id = 0x0000, /* XXX unknown */ 118 .name = "at-mio-16e-1", 119 .n_adchan = 16, 120 .adbits = 12, 121 .ai_fifo_depth = 8192, 122 .alwaysdither = 0, 123 .gainlkup = ai_gain_16, 124 .ai_speed = 800, 125 .n_aochan = 2, 126 .aobits = 12, 127 .ao_fifo_depth = 2048, 128 .ao_range_table = &range_ni_E_ao_ext, 129 .ao_unipolar = 1, 130 .ao_speed = 1000, 131 .has_8255 = 0, 132 .num_p0_dio_channels = 8, 133 .caldac = {mb88341}, 134 }, 135 {.device_id = 25, 136 .isapnp_id = 0x1900, 137 .name = "at-mio-16e-2", 138 .n_adchan = 16, 139 .adbits = 12, 140 .ai_fifo_depth = 2048, 141 .alwaysdither = 0, 142 .gainlkup = ai_gain_16, 143 .ai_speed = 2000, 144 .n_aochan = 2, 145 .aobits = 12, 146 .ao_fifo_depth = 2048, 147 .ao_range_table = &range_ni_E_ao_ext, 148 .ao_unipolar = 1, 149 .ao_speed = 1000, 150 .has_8255 = 0, 151 .num_p0_dio_channels = 8, 152 .caldac = {mb88341}, 153 }, 154 {.device_id = 36, 155 .isapnp_id = 0x2400, 156 .name = "at-mio-16e-10", 157 .n_adchan = 16, 158 .adbits = 12, 159 .ai_fifo_depth = 512, 160 .alwaysdither = 0, 161 .gainlkup = ai_gain_16, 162 .ai_speed = 10000, 163 .n_aochan = 2, 164 .aobits = 12, 165 .ao_fifo_depth = 0, 166 .ao_range_table = &range_ni_E_ao_ext, 167 .ao_unipolar = 1, 168 .ao_speed = 10000, 169 .num_p0_dio_channels = 8, 170 .caldac = {ad8804_debug}, 171 .has_8255 = 0, 172 }, 173 {.device_id = 37, 174 .isapnp_id = 0x2500, 175 .name = "at-mio-16de-10", 176 .n_adchan = 16, 177 .adbits = 12, 178 .ai_fifo_depth = 512, 179 .alwaysdither = 0, 180 .gainlkup = ai_gain_16, 181 .ai_speed = 10000, 182 .n_aochan = 2, 183 .aobits = 12, 184 .ao_fifo_depth = 0, 185 .ao_range_table = &range_ni_E_ao_ext, 186 .ao_unipolar = 1, 187 .ao_speed = 10000, 188 .num_p0_dio_channels = 8, 189 .caldac = {ad8804_debug}, 190 .has_8255 = 1, 191 }, 192 {.device_id = 38, 193 .isapnp_id = 0x2600, 194 .name = "at-mio-64e-3", 195 .n_adchan = 64, 196 .adbits = 12, 197 .ai_fifo_depth = 2048, 198 .alwaysdither = 0, 199 .gainlkup = ai_gain_16, 200 .ai_speed = 2000, 201 .n_aochan = 2, 202 .aobits = 12, 203 .ao_fifo_depth = 2048, 204 .ao_range_table = &range_ni_E_ao_ext, 205 .ao_unipolar = 1, 206 .ao_speed = 1000, 207 .has_8255 = 0, 208 .num_p0_dio_channels = 8, 209 .caldac = {ad8804_debug}, 210 }, 211 {.device_id = 39, 212 .isapnp_id = 0x2700, 213 .name = "at-mio-16xe-50", 214 .n_adchan = 16, 215 .adbits = 16, 216 .ai_fifo_depth = 512, 217 .alwaysdither = 1, 218 .gainlkup = ai_gain_8, 219 .ai_speed = 50000, 220 .n_aochan = 2, 221 .aobits = 12, 222 .ao_fifo_depth = 0, 223 .ao_range_table = &range_bipolar10, 224 .ao_unipolar = 0, 225 .ao_speed = 50000, 226 .num_p0_dio_channels = 8, 227 .caldac = {dac8800, dac8043}, 228 .has_8255 = 0, 229 }, 230 {.device_id = 50, 231 .isapnp_id = 0x0000, /* XXX unknown */ 232 .name = "at-mio-16xe-10", 233 .n_adchan = 16, 234 .adbits = 16, 235 .ai_fifo_depth = 512, 236 .alwaysdither = 1, 237 .gainlkup = ai_gain_14, 238 .ai_speed = 10000, 239 .n_aochan = 2, 240 .aobits = 16, 241 .ao_fifo_depth = 2048, 242 .ao_range_table = &range_ni_E_ao_ext, 243 .ao_unipolar = 1, 244 .ao_speed = 1000, 245 .num_p0_dio_channels = 8, 246 .caldac = {dac8800, dac8043, ad8522}, 247 .has_8255 = 0, 248 }, 249 {.device_id = 51, 250 .isapnp_id = 0x0000, /* XXX unknown */ 251 .name = "at-ai-16xe-10", 252 .n_adchan = 16, 253 .adbits = 16, 254 .ai_fifo_depth = 512, 255 .alwaysdither = 1, /* unknown */ 256 .gainlkup = ai_gain_14, 257 .ai_speed = 10000, 258 .n_aochan = 0, 259 .aobits = 0, 260 .ao_fifo_depth = 0, 261 .ao_unipolar = 0, 262 .num_p0_dio_channels = 8, 263 .caldac = {dac8800, dac8043, ad8522}, 264 .has_8255 = 0, 265 } 266}; 267 268static const int ni_irqpin[] = { 269 -1, -1, -1, 0, 1, 2, -1, 3, -1, -1, 4, 5, 6, -1, -1, 7 270}; 271 272#define interrupt_pin(a) (ni_irqpin[(a)]) 273 274#define IRQ_POLARITY 0 275 276#define NI_E_IRQ_FLAGS 0 277 278struct ni_private { 279 struct pnp_dev *isapnp_dev; 280 NI_PRIVATE_COMMON 281 282}; 283 284/* How we access registers */ 285 286#define ni_writel(a, b) (outl((a), (b)+dev->iobase)) 287#define ni_readl(a) (inl((a)+dev->iobase)) 288#define ni_writew(a, b) (outw((a), (b)+dev->iobase)) 289#define ni_readw(a) (inw((a)+dev->iobase)) 290#define ni_writeb(a, b) (outb((a), (b)+dev->iobase)) 291#define ni_readb(a) (inb((a)+dev->iobase)) 292 293/* How we access windowed registers */ 294 295/* We automatically take advantage of STC registers that can be 296 * read/written directly in the I/O space of the board. The 297 * AT-MIO devices map the low 8 STC registers to iobase+addr*2. */ 298 299static void ni_atmio_win_out(struct comedi_device *dev, uint16_t data, int addr) 300{ 301 struct ni_private *devpriv = dev->private; 302 unsigned long flags; 303 304 spin_lock_irqsave(&devpriv->window_lock, flags); 305 if ((addr) < 8) { 306 ni_writew(data, addr * 2); 307 } else { 308 ni_writew(addr, Window_Address); 309 ni_writew(data, Window_Data); 310 } 311 spin_unlock_irqrestore(&devpriv->window_lock, flags); 312} 313 314static uint16_t ni_atmio_win_in(struct comedi_device *dev, int addr) 315{ 316 struct ni_private *devpriv = dev->private; 317 unsigned long flags; 318 uint16_t ret; 319 320 spin_lock_irqsave(&devpriv->window_lock, flags); 321 if (addr < 8) { 322 ret = ni_readw(addr * 2); 323 } else { 324 ni_writew(addr, Window_Address); 325 ret = ni_readw(Window_Data); 326 } 327 spin_unlock_irqrestore(&devpriv->window_lock, flags); 328 329 return ret; 330} 331 332static struct pnp_device_id device_ids[] = { 333 {.id = "NIC1900", .driver_data = 0}, 334 {.id = "NIC2400", .driver_data = 0}, 335 {.id = "NIC2500", .driver_data = 0}, 336 {.id = "NIC2600", .driver_data = 0}, 337 {.id = "NIC2700", .driver_data = 0}, 338 {.id = ""} 339}; 340 341MODULE_DEVICE_TABLE(pnp, device_ids); 342 343#include "ni_mio_common.c" 344 345static int ni_isapnp_find_board(struct pnp_dev **dev) 346{ 347 struct pnp_dev *isapnp_dev = NULL; 348 int i; 349 350 for (i = 0; i < ARRAY_SIZE(ni_boards); i++) { 351 isapnp_dev = pnp_find_dev(NULL, 352 ISAPNP_VENDOR('N', 'I', 'C'), 353 ISAPNP_FUNCTION(ni_boards[i]. 354 isapnp_id), NULL); 355 356 if (isapnp_dev == NULL || isapnp_dev->card == NULL) 357 continue; 358 359 if (pnp_device_attach(isapnp_dev) < 0) { 360 printk 361 ("ni_atmio: %s found but already active, skipping.\n", 362 ni_boards[i].name); 363 continue; 364 } 365 if (pnp_activate_dev(isapnp_dev) < 0) { 366 pnp_device_detach(isapnp_dev); 367 return -EAGAIN; 368 } 369 if (!pnp_port_valid(isapnp_dev, 0) 370 || !pnp_irq_valid(isapnp_dev, 0)) { 371 pnp_device_detach(isapnp_dev); 372 printk("ni_atmio: pnp invalid port or irq, aborting\n"); 373 return -ENOMEM; 374 } 375 break; 376 } 377 if (i == ARRAY_SIZE(ni_boards)) 378 return -ENODEV; 379 *dev = isapnp_dev; 380 return 0; 381} 382 383static int ni_getboardtype(struct comedi_device *dev) 384{ 385 int device_id = ni_read_eeprom(dev, 511); 386 int i; 387 388 for (i = 0; i < ARRAY_SIZE(ni_boards); i++) { 389 if (ni_boards[i].device_id == device_id) 390 return i; 391 392 } 393 if (device_id == 255) 394 printk(" can't find board\n"); 395 else if (device_id == 0) 396 printk(" EEPROM read error (?) or device not found\n"); 397 else 398 printk(" unknown device ID %d -- contact author\n", device_id); 399 400 return -1; 401} 402 403static int ni_atmio_attach(struct comedi_device *dev, 404 struct comedi_devconfig *it) 405{ 406 const struct ni_board_struct *boardtype; 407 struct ni_private *devpriv; 408 struct pnp_dev *isapnp_dev; 409 int ret; 410 unsigned long iobase; 411 int board; 412 unsigned int irq; 413 414 ret = ni_alloc_private(dev); 415 if (ret) 416 return ret; 417 devpriv = dev->private; 418 419 devpriv->stc_writew = &ni_atmio_win_out; 420 devpriv->stc_readw = &ni_atmio_win_in; 421 devpriv->stc_writel = &win_out2; 422 devpriv->stc_readl = &win_in2; 423 424 iobase = it->options[0]; 425 irq = it->options[1]; 426 isapnp_dev = NULL; 427 if (iobase == 0) { 428 ret = ni_isapnp_find_board(&isapnp_dev); 429 if (ret < 0) 430 return ret; 431 432 iobase = pnp_port_start(isapnp_dev, 0); 433 irq = pnp_irq(isapnp_dev, 0); 434 devpriv->isapnp_dev = isapnp_dev; 435 } 436 437 ret = comedi_request_region(dev, iobase, NI_SIZE); 438 if (ret) 439 return ret; 440 441#ifdef DEBUG 442 /* board existence sanity check */ 443 { 444 int i; 445 446 printk(" board fingerprint:"); 447 for (i = 0; i < 16; i += 2) { 448 printk(" %04x %02x", inw(dev->iobase + i), 449 inb(dev->iobase + i + 1)); 450 } 451 } 452#endif 453 454 /* get board type */ 455 456 board = ni_getboardtype(dev); 457 if (board < 0) 458 return -EIO; 459 460 dev->board_ptr = ni_boards + board; 461 boardtype = comedi_board(dev); 462 463 printk(" %s", boardtype->name); 464 dev->board_name = boardtype->name; 465 466 /* irq stuff */ 467 468 if (irq != 0) { 469 if (irq > 15 || ni_irqpin[irq] == -1) { 470 printk(" invalid irq %u\n", irq); 471 return -EINVAL; 472 } 473 printk(" ( irq = %u )", irq); 474 ret = request_irq(irq, ni_E_interrupt, NI_E_IRQ_FLAGS, 475 "ni_atmio", dev); 476 477 if (ret < 0) { 478 printk(" irq not available\n"); 479 return -EINVAL; 480 } 481 dev->irq = irq; 482 } 483 484 /* generic E series stuff in ni_mio_common.c */ 485 486 ret = ni_E_init(dev); 487 if (ret < 0) 488 return ret; 489 490 491 return 0; 492} 493 494static void ni_atmio_detach(struct comedi_device *dev) 495{ 496 struct ni_private *devpriv = dev->private; 497 498 mio_common_detach(dev); 499 comedi_legacy_detach(dev); 500 if (devpriv->isapnp_dev) 501 pnp_device_detach(devpriv->isapnp_dev); 502} 503 504static struct comedi_driver ni_atmio_driver = { 505 .driver_name = "ni_atmio", 506 .module = THIS_MODULE, 507 .attach = ni_atmio_attach, 508 .detach = ni_atmio_detach, 509}; 510module_comedi_driver(ni_atmio_driver); 511