FILE
ni_atmio.c
File preview with syntax highlighting.
linux-6.19.14/drivers/comedi/drivers/ni_atmio.c
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Comedi 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 9/* 10 * Driver: ni_atmio 11 * Description: National Instruments AT-MIO-E series 12 * Author: ds 13 * Devices: [National Instruments] AT-MIO-16E-1 (ni_atmio), 14 * AT-MIO-16E-2, AT-MIO-16E-10, AT-MIO-16DE-10, AT-MIO-64E-3, 15 * AT-MIO-16XE-50, AT-MIO-16XE-10, AT-AI-16XE-10 16 * Status: works 17 * Updated: Thu May 1 20:03:02 CDT 2003 18 * 19 * The driver has 2.6 kernel isapnp support, and will automatically probe for 20 * a supported board if the I/O base is left unspecified with comedi_config. 21 * However, many of the isapnp id numbers are unknown. If your board is not 22 * recognized, please send the output of 'cat /proc/isapnp' (you may need to 23 * modprobe the isa-pnp module for /proc/isapnp to exist) so the id numbers 24 * for your board can be added to the driver. 25 * 26 * Otherwise, you can use the isapnptools package to configure your board. 27 * Use isapnp to configure the I/O base and IRQ for the board, and then pass 28 * the same values as parameters in comedi_config. A sample isapnp.conf file 29 * is included in the etc/ directory of Comedilib. 30 * 31 * Comedilib includes a utility to autocalibrate these boards. The boards 32 * seem to boot into a state where the all calibration DACs are at one 33 * extreme of their range, thus the default calibration is terrible. 34 * Calibration at boot is strongly encouraged. 35 * 36 * To use the extended digital I/O on some of the boards, enable the 37 * 8255 driver when configuring the Comedi source tree. 38 * 39 * External triggering is supported for some events. The channel index 40 * (scan_begin_arg, etc.) maps to PFI0 - PFI9. 41 * 42 * Some of the more esoteric triggering possibilities of these boards are 43 * not supported. 44 */ 45 46/* 47 * The real guts of the driver is in ni_mio_common.c, which is included 48 * both here and in ni_pcimio.c 49 * 50 * Interrupt support added by Truxton Fulton <trux@truxton.com> 51 * 52 * References for specifications: 53 * 340747b.pdf Register Level Programmer Manual (obsolete) 54 * 340747c.pdf Register Level Programmer Manual (new) 55 * DAQ-STC reference manual 56 * 57 * Other possibly relevant info: 58 * 320517c.pdf User manual (obsolete) 59 * 320517f.pdf User manual (new) 60 * 320889a.pdf delete 61 * 320906c.pdf maximum signal ratings 62 * 321066a.pdf about 16x 63 * 321791a.pdf discontinuation of at-mio-16e-10 rev. c 64 * 321808a.pdf about at-mio-16e-10 rev P 65 * 321837a.pdf discontinuation of at-mio-16de-10 rev d 66 * 321838a.pdf about at-mio-16de-10 rev N 67 * 68 * ISSUES: 69 * - need to deal with external reference for DAC, and other DAC 70 * properties in board properties 71 * - deal with at-mio-16de-10 revision D to N changes, etc. 72 */ 73 74#include <linux/module.h> 75#include <linux/interrupt.h> 76#include <linux/comedi/comedidev.h> 77#include <linux/isapnp.h> 78#include <linux/comedi/comedi_8255.h> 79 80#include "ni_stc.h" 81 82static const struct comedi_lrange range_ni_E_ao_ext = { 83 4, { 84 BIP_RANGE(10), 85 UNI_RANGE(10), 86 RANGE_ext(-1, 1), 87 RANGE_ext(0, 1) 88 } 89}; 90 91/* AT specific setup */ 92static const struct ni_board_struct ni_boards[] = { 93 { 94 .name = "at-mio-16e-1", 95 .device_id = 44, 96 .isapnp_id = 0x0000, /* XXX unknown */ 97 .n_adchan = 16, 98 .ai_maxdata = 0x0fff, 99 .ai_fifo_depth = 8192, 100 .gainlkup = ai_gain_16, 101 .ai_speed = 800, 102 .n_aochan = 2, 103 .ao_maxdata = 0x0fff, 104 .ao_fifo_depth = 2048, 105 .ao_range_table = &range_ni_E_ao_ext, 106 .ao_speed = 1000, 107 .caldac = { mb88341 }, 108 }, { 109 .name = "at-mio-16e-2", 110 .device_id = 25, 111 .isapnp_id = 0x1900, 112 .n_adchan = 16, 113 .ai_maxdata = 0x0fff, 114 .ai_fifo_depth = 2048, 115 .gainlkup = ai_gain_16, 116 .ai_speed = 2000, 117 .n_aochan = 2, 118 .ao_maxdata = 0x0fff, 119 .ao_fifo_depth = 2048, 120 .ao_range_table = &range_ni_E_ao_ext, 121 .ao_speed = 1000, 122 .caldac = { mb88341 }, 123 }, { 124 .name = "at-mio-16e-10", 125 .device_id = 36, 126 .isapnp_id = 0x2400, 127 .n_adchan = 16, 128 .ai_maxdata = 0x0fff, 129 .ai_fifo_depth = 512, 130 .gainlkup = ai_gain_16, 131 .ai_speed = 10000, 132 .n_aochan = 2, 133 .ao_maxdata = 0x0fff, 134 .ao_range_table = &range_ni_E_ao_ext, 135 .ao_speed = 10000, 136 .caldac = { ad8804_debug }, 137 }, { 138 .name = "at-mio-16de-10", 139 .device_id = 37, 140 .isapnp_id = 0x2500, 141 .n_adchan = 16, 142 .ai_maxdata = 0x0fff, 143 .ai_fifo_depth = 512, 144 .gainlkup = ai_gain_16, 145 .ai_speed = 10000, 146 .n_aochan = 2, 147 .ao_maxdata = 0x0fff, 148 .ao_range_table = &range_ni_E_ao_ext, 149 .ao_speed = 10000, 150 .caldac = { ad8804_debug }, 151 .has_8255 = 1, 152 }, { 153 .name = "at-mio-64e-3", 154 .device_id = 38, 155 .isapnp_id = 0x2600, 156 .n_adchan = 64, 157 .ai_maxdata = 0x0fff, 158 .ai_fifo_depth = 2048, 159 .gainlkup = ai_gain_16, 160 .ai_speed = 2000, 161 .n_aochan = 2, 162 .ao_maxdata = 0x0fff, 163 .ao_fifo_depth = 2048, 164 .ao_range_table = &range_ni_E_ao_ext, 165 .ao_speed = 1000, 166 .caldac = { ad8804_debug }, 167 }, { 168 .name = "at-mio-16xe-50", 169 .device_id = 39, 170 .isapnp_id = 0x2700, 171 .n_adchan = 16, 172 .ai_maxdata = 0xffff, 173 .ai_fifo_depth = 512, 174 .alwaysdither = 1, 175 .gainlkup = ai_gain_8, 176 .ai_speed = 50000, 177 .n_aochan = 2, 178 .ao_maxdata = 0x0fff, 179 .ao_range_table = &range_bipolar10, 180 .ao_speed = 50000, 181 .caldac = { dac8800, dac8043 }, 182 }, { 183 .name = "at-mio-16xe-10", 184 .device_id = 50, 185 .isapnp_id = 0x0000, /* XXX unknown */ 186 .n_adchan = 16, 187 .ai_maxdata = 0xffff, 188 .ai_fifo_depth = 512, 189 .alwaysdither = 1, 190 .gainlkup = ai_gain_14, 191 .ai_speed = 10000, 192 .n_aochan = 2, 193 .ao_maxdata = 0xffff, 194 .ao_fifo_depth = 2048, 195 .ao_range_table = &range_ni_E_ao_ext, 196 .ao_speed = 1000, 197 .caldac = { dac8800, dac8043, ad8522 }, 198 }, { 199 .name = "at-ai-16xe-10", 200 .device_id = 51, 201 .isapnp_id = 0x0000, /* XXX unknown */ 202 .n_adchan = 16, 203 .ai_maxdata = 0xffff, 204 .ai_fifo_depth = 512, 205 .alwaysdither = 1, /* unknown */ 206 .gainlkup = ai_gain_14, 207 .ai_speed = 10000, 208 .caldac = { dac8800, dac8043, ad8522 }, 209 }, 210}; 211 212static const int ni_irqpin[] = { 213 -1, -1, -1, 0, 1, 2, -1, 3, -1, -1, 4, 5, 6, -1, -1, 7 214}; 215 216#include "ni_mio_common.c" 217 218static const struct pnp_device_id __maybe_unused device_ids[] = { 219 {.id = "NIC1900", .driver_data = 0}, 220 {.id = "NIC2400", .driver_data = 0}, 221 {.id = "NIC2500", .driver_data = 0}, 222 {.id = "NIC2600", .driver_data = 0}, 223 {.id = "NIC2700", .driver_data = 0}, 224 {.id = ""} 225}; 226 227MODULE_DEVICE_TABLE(pnp, device_ids); 228 229static int ni_isapnp_find_board(struct pnp_dev **dev) 230{ 231 struct pnp_dev *isapnp_dev = NULL; 232 int i; 233 234 for (i = 0; i < ARRAY_SIZE(ni_boards); i++) { 235 isapnp_dev = 236 pnp_find_dev(NULL, 237 ISAPNP_VENDOR('N', 'I', 'C'), 238 ISAPNP_FUNCTION(ni_boards[i].isapnp_id), 239 NULL); 240 241 if (!isapnp_dev || !isapnp_dev->card) 242 continue; 243 244 if (pnp_device_attach(isapnp_dev) < 0) 245 continue; 246 247 if (pnp_activate_dev(isapnp_dev) < 0) { 248 pnp_device_detach(isapnp_dev); 249 return -EAGAIN; 250 } 251 252 if (!pnp_port_valid(isapnp_dev, 0) || 253 !pnp_irq_valid(isapnp_dev, 0)) { 254 pnp_device_detach(isapnp_dev); 255 return -ENOMEM; 256 } 257 break; 258 } 259 if (i == ARRAY_SIZE(ni_boards)) 260 return -ENODEV; 261 *dev = isapnp_dev; 262 return 0; 263} 264 265static const struct ni_board_struct *ni_atmio_probe(struct comedi_device *dev) 266{ 267 int device_id = ni_read_eeprom(dev, 511); 268 int i; 269 270 for (i = 0; i < ARRAY_SIZE(ni_boards); i++) { 271 const struct ni_board_struct *board = &ni_boards[i]; 272 273 if (board->device_id == device_id) 274 return board; 275 } 276 if (device_id == 255) 277 dev_err(dev->class_dev, "can't find board\n"); 278 else if (device_id == 0) 279 dev_err(dev->class_dev, 280 "EEPROM read error (?) or device not found\n"); 281 else 282 dev_err(dev->class_dev, 283 "unknown device ID %d -- contact author\n", device_id); 284 285 return NULL; 286} 287 288static int ni_atmio_attach(struct comedi_device *dev, 289 struct comedi_devconfig *it) 290{ 291 const struct ni_board_struct *board; 292 struct pnp_dev *isapnp_dev; 293 int ret; 294 unsigned long iobase; 295 unsigned int irq; 296 297 ret = ni_alloc_private(dev); 298 if (ret) 299 return ret; 300 301 iobase = it->options[0]; 302 irq = it->options[1]; 303 isapnp_dev = NULL; 304 if (iobase == 0) { 305 ret = ni_isapnp_find_board(&isapnp_dev); 306 if (ret < 0) 307 return ret; 308 309 iobase = pnp_port_start(isapnp_dev, 0); 310 irq = pnp_irq(isapnp_dev, 0); 311 comedi_set_hw_dev(dev, &isapnp_dev->dev); 312 } 313 314 ret = comedi_request_region(dev, iobase, 0x20); 315 if (ret) 316 return ret; 317 318 board = ni_atmio_probe(dev); 319 if (!board) 320 return -ENODEV; 321 dev->board_ptr = board; 322 dev->board_name = board->name; 323 324 /* irq stuff */ 325 326 if (irq != 0) { 327 if (irq > 15 || ni_irqpin[irq] == -1) 328 return -EINVAL; 329 ret = request_irq(irq, ni_E_interrupt, 0, 330 dev->board_name, dev); 331 if (ret < 0) 332 return -EINVAL; 333 dev->irq = irq; 334 } 335 336 /* generic E series stuff in ni_mio_common.c */ 337 338 ret = ni_E_init(dev, ni_irqpin[dev->irq], 0); 339 if (ret < 0) 340 return ret; 341 342 return 0; 343} 344 345static void ni_atmio_detach(struct comedi_device *dev) 346{ 347 struct pnp_dev *isapnp_dev; 348 349 mio_common_detach(dev); 350 comedi_legacy_detach(dev); 351 352 isapnp_dev = dev->hw_dev ? to_pnp_dev(dev->hw_dev) : NULL; 353 if (isapnp_dev) 354 pnp_device_detach(isapnp_dev); 355} 356 357static struct comedi_driver ni_atmio_driver = { 358 .driver_name = "ni_atmio", 359 .module = THIS_MODULE, 360 .attach = ni_atmio_attach, 361 .detach = ni_atmio_detach, 362}; 363module_comedi_driver(ni_atmio_driver); 364 365MODULE_AUTHOR("Comedi https://www.comedi.org"); 366MODULE_DESCRIPTION("Comedi low-level driver"); 367MODULE_LICENSE("GPL"); 368
~/
Read-only file preview.