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