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