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