root/drivers/staging/comedi/drivers/ni_atmio.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ni_isapnp_find_board
  2. ni_atmio_probe
  3. ni_atmio_attach
  4. ni_atmio_detach

   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 "../comedidev.h"
  77 
  78 #include <linux/isapnp.h>
  79 
  80 #include "ni_stc.h"
  81 #include "8255.h"
  82 
  83 /* AT specific setup */
  84 static const struct ni_board_struct ni_boards[] = {
  85         {
  86                 .name           = "at-mio-16e-1",
  87                 .device_id      = 44,
  88                 .isapnp_id      = 0x0000,       /* XXX unknown */
  89                 .n_adchan       = 16,
  90                 .ai_maxdata     = 0x0fff,
  91                 .ai_fifo_depth  = 8192,
  92                 .gainlkup       = ai_gain_16,
  93                 .ai_speed       = 800,
  94                 .n_aochan       = 2,
  95                 .ao_maxdata     = 0x0fff,
  96                 .ao_fifo_depth  = 2048,
  97                 .ao_range_table = &range_ni_E_ao_ext,
  98                 .ao_speed       = 1000,
  99                 .caldac         = { mb88341 },
 100         }, {
 101                 .name           = "at-mio-16e-2",
 102                 .device_id      = 25,
 103                 .isapnp_id      = 0x1900,
 104                 .n_adchan       = 16,
 105                 .ai_maxdata     = 0x0fff,
 106                 .ai_fifo_depth  = 2048,
 107                 .gainlkup       = ai_gain_16,
 108                 .ai_speed       = 2000,
 109                 .n_aochan       = 2,
 110                 .ao_maxdata     = 0x0fff,
 111                 .ao_fifo_depth  = 2048,
 112                 .ao_range_table = &range_ni_E_ao_ext,
 113                 .ao_speed       = 1000,
 114                 .caldac         = { mb88341 },
 115         }, {
 116                 .name           = "at-mio-16e-10",
 117                 .device_id      = 36,
 118                 .isapnp_id      = 0x2400,
 119                 .n_adchan       = 16,
 120                 .ai_maxdata     = 0x0fff,
 121                 .ai_fifo_depth  = 512,
 122                 .gainlkup       = ai_gain_16,
 123                 .ai_speed       = 10000,
 124                 .n_aochan       = 2,
 125                 .ao_maxdata     = 0x0fff,
 126                 .ao_range_table = &range_ni_E_ao_ext,
 127                 .ao_speed       = 10000,
 128                 .caldac         = { ad8804_debug },
 129         }, {
 130                 .name           = "at-mio-16de-10",
 131                 .device_id      = 37,
 132                 .isapnp_id      = 0x2500,
 133                 .n_adchan       = 16,
 134                 .ai_maxdata     = 0x0fff,
 135                 .ai_fifo_depth  = 512,
 136                 .gainlkup       = ai_gain_16,
 137                 .ai_speed       = 10000,
 138                 .n_aochan       = 2,
 139                 .ao_maxdata     = 0x0fff,
 140                 .ao_range_table = &range_ni_E_ao_ext,
 141                 .ao_speed       = 10000,
 142                 .caldac         = { ad8804_debug },
 143                 .has_8255       = 1,
 144         }, {
 145                 .name           = "at-mio-64e-3",
 146                 .device_id      = 38,
 147                 .isapnp_id      = 0x2600,
 148                 .n_adchan       = 64,
 149                 .ai_maxdata     = 0x0fff,
 150                 .ai_fifo_depth  = 2048,
 151                 .gainlkup       = ai_gain_16,
 152                 .ai_speed       = 2000,
 153                 .n_aochan       = 2,
 154                 .ao_maxdata     = 0x0fff,
 155                 .ao_fifo_depth  = 2048,
 156                 .ao_range_table = &range_ni_E_ao_ext,
 157                 .ao_speed       = 1000,
 158                 .caldac         = { ad8804_debug },
 159         }, {
 160                 .name           = "at-mio-16xe-50",
 161                 .device_id      = 39,
 162                 .isapnp_id      = 0x2700,
 163                 .n_adchan       = 16,
 164                 .ai_maxdata     = 0xffff,
 165                 .ai_fifo_depth  = 512,
 166                 .alwaysdither   = 1,
 167                 .gainlkup       = ai_gain_8,
 168                 .ai_speed       = 50000,
 169                 .n_aochan       = 2,
 170                 .ao_maxdata     = 0x0fff,
 171                 .ao_range_table = &range_bipolar10,
 172                 .ao_speed       = 50000,
 173                 .caldac         = { dac8800, dac8043 },
 174         }, {
 175                 .name           = "at-mio-16xe-10",
 176                 .device_id      = 50,
 177                 .isapnp_id      = 0x0000,       /* XXX unknown */
 178                 .n_adchan       = 16,
 179                 .ai_maxdata     = 0xffff,
 180                 .ai_fifo_depth  = 512,
 181                 .alwaysdither   = 1,
 182                 .gainlkup       = ai_gain_14,
 183                 .ai_speed       = 10000,
 184                 .n_aochan       = 2,
 185                 .ao_maxdata     = 0xffff,
 186                 .ao_fifo_depth  = 2048,
 187                 .ao_range_table = &range_ni_E_ao_ext,
 188                 .ao_speed       = 1000,
 189                 .caldac         = { dac8800, dac8043, ad8522 },
 190         }, {
 191                 .name           = "at-ai-16xe-10",
 192                 .device_id      = 51,
 193                 .isapnp_id      = 0x0000,       /* XXX unknown */
 194                 .n_adchan       = 16,
 195                 .ai_maxdata     = 0xffff,
 196                 .ai_fifo_depth  = 512,
 197                 .alwaysdither   = 1,            /* unknown */
 198                 .gainlkup       = ai_gain_14,
 199                 .ai_speed       = 10000,
 200                 .caldac         = { dac8800, dac8043, ad8522 },
 201         },
 202 };
 203 
 204 static const int ni_irqpin[] = {
 205         -1, -1, -1, 0, 1, 2, -1, 3, -1, -1, 4, 5, 6, -1, -1, 7
 206 };
 207 
 208 #include "ni_mio_common.c"
 209 
 210 static const struct pnp_device_id device_ids[] = {
 211         {.id = "NIC1900", .driver_data = 0},
 212         {.id = "NIC2400", .driver_data = 0},
 213         {.id = "NIC2500", .driver_data = 0},
 214         {.id = "NIC2600", .driver_data = 0},
 215         {.id = "NIC2700", .driver_data = 0},
 216         {.id = ""}
 217 };
 218 
 219 MODULE_DEVICE_TABLE(pnp, device_ids);
 220 
 221 static int ni_isapnp_find_board(struct pnp_dev **dev)
 222 {
 223         struct pnp_dev *isapnp_dev = NULL;
 224         int i;
 225 
 226         for (i = 0; i < ARRAY_SIZE(ni_boards); i++) {
 227                 isapnp_dev =
 228                         pnp_find_dev(NULL,
 229                                      ISAPNP_VENDOR('N', 'I', 'C'),
 230                                      ISAPNP_FUNCTION(ni_boards[i].isapnp_id),
 231                                      NULL);
 232 
 233                 if (!isapnp_dev || !isapnp_dev->card)
 234                         continue;
 235 
 236                 if (pnp_device_attach(isapnp_dev) < 0)
 237                         continue;
 238 
 239                 if (pnp_activate_dev(isapnp_dev) < 0) {
 240                         pnp_device_detach(isapnp_dev);
 241                         return -EAGAIN;
 242                 }
 243 
 244                 if (!pnp_port_valid(isapnp_dev, 0) ||
 245                     !pnp_irq_valid(isapnp_dev, 0)) {
 246                         pnp_device_detach(isapnp_dev);
 247                         return -ENOMEM;
 248                 }
 249                 break;
 250         }
 251         if (i == ARRAY_SIZE(ni_boards))
 252                 return -ENODEV;
 253         *dev = isapnp_dev;
 254         return 0;
 255 }
 256 
 257 static const struct ni_board_struct *ni_atmio_probe(struct comedi_device *dev)
 258 {
 259         int device_id = ni_read_eeprom(dev, 511);
 260         int i;
 261 
 262         for (i = 0; i < ARRAY_SIZE(ni_boards); i++) {
 263                 const struct ni_board_struct *board = &ni_boards[i];
 264 
 265                 if (board->device_id == device_id)
 266                         return board;
 267         }
 268         if (device_id == 255)
 269                 dev_err(dev->class_dev, "can't find board\n");
 270         else if (device_id == 0)
 271                 dev_err(dev->class_dev,
 272                         "EEPROM read error (?) or device not found\n");
 273         else
 274                 dev_err(dev->class_dev,
 275                         "unknown device ID %d -- contact author\n", device_id);
 276 
 277         return NULL;
 278 }
 279 
 280 static int ni_atmio_attach(struct comedi_device *dev,
 281                            struct comedi_devconfig *it)
 282 {
 283         const struct ni_board_struct *board;
 284         struct pnp_dev *isapnp_dev;
 285         int ret;
 286         unsigned long iobase;
 287         unsigned int irq;
 288 
 289         ret = ni_alloc_private(dev);
 290         if (ret)
 291                 return ret;
 292 
 293         iobase = it->options[0];
 294         irq = it->options[1];
 295         isapnp_dev = NULL;
 296         if (iobase == 0) {
 297                 ret = ni_isapnp_find_board(&isapnp_dev);
 298                 if (ret < 0)
 299                         return ret;
 300 
 301                 iobase = pnp_port_start(isapnp_dev, 0);
 302                 irq = pnp_irq(isapnp_dev, 0);
 303                 comedi_set_hw_dev(dev, &isapnp_dev->dev);
 304         }
 305 
 306         ret = comedi_request_region(dev, iobase, 0x20);
 307         if (ret)
 308                 return ret;
 309 
 310         board = ni_atmio_probe(dev);
 311         if (!board)
 312                 return -ENODEV;
 313         dev->board_ptr = board;
 314         dev->board_name = board->name;
 315 
 316         /* irq stuff */
 317 
 318         if (irq != 0) {
 319                 if (irq > 15 || ni_irqpin[irq] == -1)
 320                         return -EINVAL;
 321                 ret = request_irq(irq, ni_E_interrupt, 0,
 322                                   dev->board_name, dev);
 323                 if (ret < 0)
 324                         return -EINVAL;
 325                 dev->irq = irq;
 326         }
 327 
 328         /* generic E series stuff in ni_mio_common.c */
 329 
 330         ret = ni_E_init(dev, ni_irqpin[dev->irq], 0);
 331         if (ret < 0)
 332                 return ret;
 333 
 334         return 0;
 335 }
 336 
 337 static void ni_atmio_detach(struct comedi_device *dev)
 338 {
 339         struct pnp_dev *isapnp_dev;
 340 
 341         mio_common_detach(dev);
 342         comedi_legacy_detach(dev);
 343 
 344         isapnp_dev = dev->hw_dev ? to_pnp_dev(dev->hw_dev) : NULL;
 345         if (isapnp_dev)
 346                 pnp_device_detach(isapnp_dev);
 347 }
 348 
 349 static struct comedi_driver ni_atmio_driver = {
 350         .driver_name    = "ni_atmio",
 351         .module         = THIS_MODULE,
 352         .attach         = ni_atmio_attach,
 353         .detach         = ni_atmio_detach,
 354 };
 355 module_comedi_driver(ni_atmio_driver);
 356 
 357 MODULE_AUTHOR("Comedi http://www.comedi.org");
 358 MODULE_DESCRIPTION("Comedi low-level driver");
 359 MODULE_LICENSE("GPL");
 360 

/* [<][>][^][v][top][bottom][index][help] */