ni_atmio.c revision 050e2d3a3b9147d43a6acf4ef99f0028d117b701
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 .gainlkup = ai_gain_16, 118 .ai_speed = 800, 119 .n_aochan = 2, 120 .aobits = 12, 121 .ao_fifo_depth = 2048, 122 .ao_range_table = &range_ni_E_ao_ext, 123 .ao_unipolar = 1, 124 .ao_speed = 1000, 125 .num_p0_dio_channels = 8, 126 .caldac = {mb88341}, 127 }, 128 {.device_id = 25, 129 .isapnp_id = 0x1900, 130 .name = "at-mio-16e-2", 131 .n_adchan = 16, 132 .adbits = 12, 133 .ai_fifo_depth = 2048, 134 .gainlkup = ai_gain_16, 135 .ai_speed = 2000, 136 .n_aochan = 2, 137 .aobits = 12, 138 .ao_fifo_depth = 2048, 139 .ao_range_table = &range_ni_E_ao_ext, 140 .ao_unipolar = 1, 141 .ao_speed = 1000, 142 .num_p0_dio_channels = 8, 143 .caldac = {mb88341}, 144 }, 145 {.device_id = 36, 146 .isapnp_id = 0x2400, 147 .name = "at-mio-16e-10", 148 .n_adchan = 16, 149 .adbits = 12, 150 .ai_fifo_depth = 512, 151 .gainlkup = ai_gain_16, 152 .ai_speed = 10000, 153 .n_aochan = 2, 154 .aobits = 12, 155 .ao_range_table = &range_ni_E_ao_ext, 156 .ao_unipolar = 1, 157 .ao_speed = 10000, 158 .num_p0_dio_channels = 8, 159 .caldac = {ad8804_debug}, 160 }, 161 {.device_id = 37, 162 .isapnp_id = 0x2500, 163 .name = "at-mio-16de-10", 164 .n_adchan = 16, 165 .adbits = 12, 166 .ai_fifo_depth = 512, 167 .gainlkup = ai_gain_16, 168 .ai_speed = 10000, 169 .n_aochan = 2, 170 .aobits = 12, 171 .ao_range_table = &range_ni_E_ao_ext, 172 .ao_unipolar = 1, 173 .ao_speed = 10000, 174 .num_p0_dio_channels = 8, 175 .caldac = {ad8804_debug}, 176 .has_8255 = 1, 177 }, 178 {.device_id = 38, 179 .isapnp_id = 0x2600, 180 .name = "at-mio-64e-3", 181 .n_adchan = 64, 182 .adbits = 12, 183 .ai_fifo_depth = 2048, 184 .gainlkup = ai_gain_16, 185 .ai_speed = 2000, 186 .n_aochan = 2, 187 .aobits = 12, 188 .ao_fifo_depth = 2048, 189 .ao_range_table = &range_ni_E_ao_ext, 190 .ao_unipolar = 1, 191 .ao_speed = 1000, 192 .num_p0_dio_channels = 8, 193 .caldac = {ad8804_debug}, 194 }, 195 {.device_id = 39, 196 .isapnp_id = 0x2700, 197 .name = "at-mio-16xe-50", 198 .n_adchan = 16, 199 .adbits = 16, 200 .ai_fifo_depth = 512, 201 .alwaysdither = 1, 202 .gainlkup = ai_gain_8, 203 .ai_speed = 50000, 204 .n_aochan = 2, 205 .aobits = 12, 206 .ao_range_table = &range_bipolar10, 207 .ao_speed = 50000, 208 .num_p0_dio_channels = 8, 209 .caldac = {dac8800, dac8043}, 210 }, 211 {.device_id = 50, 212 .isapnp_id = 0x0000, /* XXX unknown */ 213 .name = "at-mio-16xe-10", 214 .n_adchan = 16, 215 .adbits = 16, 216 .ai_fifo_depth = 512, 217 .alwaysdither = 1, 218 .gainlkup = ai_gain_14, 219 .ai_speed = 10000, 220 .n_aochan = 2, 221 .aobits = 16, 222 .ao_fifo_depth = 2048, 223 .ao_range_table = &range_ni_E_ao_ext, 224 .ao_unipolar = 1, 225 .ao_speed = 1000, 226 .num_p0_dio_channels = 8, 227 .caldac = {dac8800, dac8043, ad8522}, 228 }, 229 {.device_id = 51, 230 .isapnp_id = 0x0000, /* XXX unknown */ 231 .name = "at-ai-16xe-10", 232 .n_adchan = 16, 233 .adbits = 16, 234 .ai_fifo_depth = 512, 235 .alwaysdither = 1, /* unknown */ 236 .gainlkup = ai_gain_14, 237 .ai_speed = 10000, 238 .num_p0_dio_channels = 8, 239 .caldac = {dac8800, dac8043, ad8522}, 240 } 241}; 242 243static const int ni_irqpin[] = { 244 -1, -1, -1, 0, 1, 2, -1, 3, -1, -1, 4, 5, 6, -1, -1, 7 245}; 246 247#include "ni_mio_common.c" 248 249static struct pnp_device_id device_ids[] = { 250 {.id = "NIC1900", .driver_data = 0}, 251 {.id = "NIC2400", .driver_data = 0}, 252 {.id = "NIC2500", .driver_data = 0}, 253 {.id = "NIC2600", .driver_data = 0}, 254 {.id = "NIC2700", .driver_data = 0}, 255 {.id = ""} 256}; 257 258MODULE_DEVICE_TABLE(pnp, device_ids); 259 260static int ni_isapnp_find_board(struct pnp_dev **dev) 261{ 262 struct pnp_dev *isapnp_dev = NULL; 263 int i; 264 265 for (i = 0; i < ARRAY_SIZE(ni_boards); i++) { 266 isapnp_dev = pnp_find_dev(NULL, 267 ISAPNP_VENDOR('N', 'I', 'C'), 268 ISAPNP_FUNCTION(ni_boards[i]. 269 isapnp_id), NULL); 270 271 if (isapnp_dev == NULL || isapnp_dev->card == NULL) 272 continue; 273 274 if (pnp_device_attach(isapnp_dev) < 0) { 275 printk 276 ("ni_atmio: %s found but already active, skipping.\n", 277 ni_boards[i].name); 278 continue; 279 } 280 if (pnp_activate_dev(isapnp_dev) < 0) { 281 pnp_device_detach(isapnp_dev); 282 return -EAGAIN; 283 } 284 if (!pnp_port_valid(isapnp_dev, 0) 285 || !pnp_irq_valid(isapnp_dev, 0)) { 286 pnp_device_detach(isapnp_dev); 287 printk("ni_atmio: pnp invalid port or irq, aborting\n"); 288 return -ENOMEM; 289 } 290 break; 291 } 292 if (i == ARRAY_SIZE(ni_boards)) 293 return -ENODEV; 294 *dev = isapnp_dev; 295 return 0; 296} 297 298static int ni_getboardtype(struct comedi_device *dev) 299{ 300 int device_id = ni_read_eeprom(dev, 511); 301 int i; 302 303 for (i = 0; i < ARRAY_SIZE(ni_boards); i++) { 304 if (ni_boards[i].device_id == device_id) 305 return i; 306 307 } 308 if (device_id == 255) 309 printk(" can't find board\n"); 310 else if (device_id == 0) 311 printk(" EEPROM read error (?) or device not found\n"); 312 else 313 printk(" unknown device ID %d -- contact author\n", device_id); 314 315 return -1; 316} 317 318static int ni_atmio_attach(struct comedi_device *dev, 319 struct comedi_devconfig *it) 320{ 321 const struct ni_board_struct *boardtype; 322 struct ni_private *devpriv; 323 struct pnp_dev *isapnp_dev; 324 int ret; 325 unsigned long iobase; 326 int board; 327 unsigned int irq; 328 329 ret = ni_alloc_private(dev); 330 if (ret) 331 return ret; 332 devpriv = dev->private; 333 334 iobase = it->options[0]; 335 irq = it->options[1]; 336 isapnp_dev = NULL; 337 if (iobase == 0) { 338 ret = ni_isapnp_find_board(&isapnp_dev); 339 if (ret < 0) 340 return ret; 341 342 iobase = pnp_port_start(isapnp_dev, 0); 343 irq = pnp_irq(isapnp_dev, 0); 344 comedi_set_hw_dev(dev, &isapnp_dev->dev); 345 } 346 347 ret = comedi_request_region(dev, iobase, NI_SIZE); 348 if (ret) 349 return ret; 350 351 /* get board type */ 352 353 board = ni_getboardtype(dev); 354 if (board < 0) 355 return -EIO; 356 357 dev->board_ptr = ni_boards + board; 358 boardtype = comedi_board(dev); 359 360 printk(" %s", boardtype->name); 361 dev->board_name = boardtype->name; 362 363 /* irq stuff */ 364 365 if (irq != 0) { 366 if (irq > 15 || ni_irqpin[irq] == -1) { 367 printk(" invalid irq %u\n", irq); 368 return -EINVAL; 369 } 370 printk(" ( irq = %u )", irq); 371 ret = request_irq(irq, ni_E_interrupt, 0, 372 "ni_atmio", dev); 373 374 if (ret < 0) { 375 printk(" irq not available\n"); 376 return -EINVAL; 377 } 378 dev->irq = irq; 379 } 380 381 /* generic E series stuff in ni_mio_common.c */ 382 383 ret = ni_E_init(dev, ni_irqpin[dev->irq], 0); 384 if (ret < 0) 385 return ret; 386 387 388 return 0; 389} 390 391static void ni_atmio_detach(struct comedi_device *dev) 392{ 393 struct pnp_dev *isapnp_dev; 394 395 mio_common_detach(dev); 396 comedi_legacy_detach(dev); 397 398 isapnp_dev = dev->hw_dev ? to_pnp_dev(dev->hw_dev) : NULL; 399 if (isapnp_dev) 400 pnp_device_detach(isapnp_dev); 401} 402 403static struct comedi_driver ni_atmio_driver = { 404 .driver_name = "ni_atmio", 405 .module = THIS_MODULE, 406 .attach = ni_atmio_attach, 407 .detach = ni_atmio_detach, 408}; 409module_comedi_driver(ni_atmio_driver); 410