ni_atmio.c revision ac63baf5517cb7c22d63e2c5d269994f3002c7e0
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#include "ni_mio_common.c" 274 275/* How we access windowed registers */ 276 277/* We automatically take advantage of STC registers that can be 278 * read/written directly in the I/O space of the board. The 279 * AT-MIO devices map the low 8 STC registers to iobase+addr*2. */ 280 281static void ni_atmio_win_out(struct comedi_device *dev, uint16_t data, int addr) 282{ 283 struct ni_private *devpriv = dev->private; 284 unsigned long flags; 285 286 spin_lock_irqsave(&devpriv->window_lock, flags); 287 if ((addr) < 8) { 288 ni_writew(dev, data, addr * 2); 289 } else { 290 ni_writew(dev, addr, Window_Address); 291 ni_writew(dev, data, Window_Data); 292 } 293 spin_unlock_irqrestore(&devpriv->window_lock, flags); 294} 295 296static uint16_t ni_atmio_win_in(struct comedi_device *dev, int addr) 297{ 298 struct ni_private *devpriv = dev->private; 299 unsigned long flags; 300 uint16_t ret; 301 302 spin_lock_irqsave(&devpriv->window_lock, flags); 303 if (addr < 8) { 304 ret = ni_readw(dev, addr * 2); 305 } else { 306 ni_writew(dev, addr, Window_Address); 307 ret = ni_readw(dev, Window_Data); 308 } 309 spin_unlock_irqrestore(&devpriv->window_lock, flags); 310 311 return ret; 312} 313 314static struct pnp_device_id device_ids[] = { 315 {.id = "NIC1900", .driver_data = 0}, 316 {.id = "NIC2400", .driver_data = 0}, 317 {.id = "NIC2500", .driver_data = 0}, 318 {.id = "NIC2600", .driver_data = 0}, 319 {.id = "NIC2700", .driver_data = 0}, 320 {.id = ""} 321}; 322 323MODULE_DEVICE_TABLE(pnp, device_ids); 324 325static int ni_isapnp_find_board(struct pnp_dev **dev) 326{ 327 struct pnp_dev *isapnp_dev = NULL; 328 int i; 329 330 for (i = 0; i < ARRAY_SIZE(ni_boards); i++) { 331 isapnp_dev = pnp_find_dev(NULL, 332 ISAPNP_VENDOR('N', 'I', 'C'), 333 ISAPNP_FUNCTION(ni_boards[i]. 334 isapnp_id), NULL); 335 336 if (isapnp_dev == NULL || isapnp_dev->card == NULL) 337 continue; 338 339 if (pnp_device_attach(isapnp_dev) < 0) { 340 printk 341 ("ni_atmio: %s found but already active, skipping.\n", 342 ni_boards[i].name); 343 continue; 344 } 345 if (pnp_activate_dev(isapnp_dev) < 0) { 346 pnp_device_detach(isapnp_dev); 347 return -EAGAIN; 348 } 349 if (!pnp_port_valid(isapnp_dev, 0) 350 || !pnp_irq_valid(isapnp_dev, 0)) { 351 pnp_device_detach(isapnp_dev); 352 printk("ni_atmio: pnp invalid port or irq, aborting\n"); 353 return -ENOMEM; 354 } 355 break; 356 } 357 if (i == ARRAY_SIZE(ni_boards)) 358 return -ENODEV; 359 *dev = isapnp_dev; 360 return 0; 361} 362 363static int ni_getboardtype(struct comedi_device *dev) 364{ 365 int device_id = ni_read_eeprom(dev, 511); 366 int i; 367 368 for (i = 0; i < ARRAY_SIZE(ni_boards); i++) { 369 if (ni_boards[i].device_id == device_id) 370 return i; 371 372 } 373 if (device_id == 255) 374 printk(" can't find board\n"); 375 else if (device_id == 0) 376 printk(" EEPROM read error (?) or device not found\n"); 377 else 378 printk(" unknown device ID %d -- contact author\n", device_id); 379 380 return -1; 381} 382 383static int ni_atmio_attach(struct comedi_device *dev, 384 struct comedi_devconfig *it) 385{ 386 const struct ni_board_struct *boardtype; 387 struct ni_private *devpriv; 388 struct pnp_dev *isapnp_dev; 389 int ret; 390 unsigned long iobase; 391 int board; 392 unsigned int irq; 393 394 ret = ni_alloc_private(dev); 395 if (ret) 396 return ret; 397 devpriv = dev->private; 398 399 devpriv->stc_writew = ni_atmio_win_out; 400 devpriv->stc_readw = ni_atmio_win_in; 401 devpriv->stc_writel = win_out2; 402 devpriv->stc_readl = win_in2; 403 404 iobase = it->options[0]; 405 irq = it->options[1]; 406 isapnp_dev = NULL; 407 if (iobase == 0) { 408 ret = ni_isapnp_find_board(&isapnp_dev); 409 if (ret < 0) 410 return ret; 411 412 iobase = pnp_port_start(isapnp_dev, 0); 413 irq = pnp_irq(isapnp_dev, 0); 414 comedi_set_hw_dev(dev, &isapnp_dev->dev); 415 } 416 417 ret = comedi_request_region(dev, iobase, NI_SIZE); 418 if (ret) 419 return ret; 420 421 /* get board type */ 422 423 board = ni_getboardtype(dev); 424 if (board < 0) 425 return -EIO; 426 427 dev->board_ptr = ni_boards + board; 428 boardtype = comedi_board(dev); 429 430 printk(" %s", boardtype->name); 431 dev->board_name = boardtype->name; 432 433 /* irq stuff */ 434 435 if (irq != 0) { 436 if (irq > 15 || ni_irqpin[irq] == -1) { 437 printk(" invalid irq %u\n", irq); 438 return -EINVAL; 439 } 440 printk(" ( irq = %u )", irq); 441 ret = request_irq(irq, ni_E_interrupt, NI_E_IRQ_FLAGS, 442 "ni_atmio", dev); 443 444 if (ret < 0) { 445 printk(" irq not available\n"); 446 return -EINVAL; 447 } 448 dev->irq = irq; 449 } 450 451 /* generic E series stuff in ni_mio_common.c */ 452 453 ret = ni_E_init(dev); 454 if (ret < 0) 455 return ret; 456 457 458 return 0; 459} 460 461static void ni_atmio_detach(struct comedi_device *dev) 462{ 463 struct pnp_dev *isapnp_dev; 464 465 mio_common_detach(dev); 466 comedi_legacy_detach(dev); 467 468 isapnp_dev = dev->hw_dev ? to_pnp_dev(dev->hw_dev) : NULL; 469 if (isapnp_dev) 470 pnp_device_detach(isapnp_dev); 471} 472 473static struct comedi_driver ni_atmio_driver = { 474 .driver_name = "ni_atmio", 475 .module = THIS_MODULE, 476 .attach = ni_atmio_attach, 477 .detach = ni_atmio_detach, 478}; 479module_comedi_driver(ni_atmio_driver); 480