linux/drivers/staging/comedi/drivers/ni_atmio.c
<<
>>
Prefs
   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
 110#define MAX_N_CALDACS 32
 111
 112static const struct ni_board_struct ni_boards[] = {
 113        {.device_id = 44,
 114         .isapnp_id = 0x0000,   /* XXX unknown */
 115         .name = "at-mio-16e-1",
 116         .n_adchan = 16,
 117         .adbits = 12,
 118         .ai_fifo_depth = 8192,
 119         .alwaysdither = 0,
 120         .gainlkup = ai_gain_16,
 121         .ai_speed = 800,
 122         .n_aochan = 2,
 123         .aobits = 12,
 124         .ao_fifo_depth = 2048,
 125         .ao_range_table = &range_ni_E_ao_ext,
 126         .ao_unipolar = 1,
 127         .ao_speed = 1000,
 128         .has_8255 = 0,
 129         .num_p0_dio_channels = 8,
 130         .caldac = {mb88341},
 131         },
 132        {.device_id = 25,
 133         .isapnp_id = 0x1900,
 134         .name = "at-mio-16e-2",
 135         .n_adchan = 16,
 136         .adbits = 12,
 137         .ai_fifo_depth = 2048,
 138         .alwaysdither = 0,
 139         .gainlkup = ai_gain_16,
 140         .ai_speed = 2000,
 141         .n_aochan = 2,
 142         .aobits = 12,
 143         .ao_fifo_depth = 2048,
 144         .ao_range_table = &range_ni_E_ao_ext,
 145         .ao_unipolar = 1,
 146         .ao_speed = 1000,
 147         .has_8255 = 0,
 148         .num_p0_dio_channels = 8,
 149         .caldac = {mb88341},
 150         },
 151        {.device_id = 36,
 152         .isapnp_id = 0x2400,
 153         .name = "at-mio-16e-10",
 154         .n_adchan = 16,
 155         .adbits = 12,
 156         .ai_fifo_depth = 512,
 157         .alwaysdither = 0,
 158         .gainlkup = ai_gain_16,
 159         .ai_speed = 10000,
 160         .n_aochan = 2,
 161         .aobits = 12,
 162         .ao_fifo_depth = 0,
 163         .ao_range_table = &range_ni_E_ao_ext,
 164         .ao_unipolar = 1,
 165         .ao_speed = 10000,
 166         .num_p0_dio_channels = 8,
 167         .caldac = {ad8804_debug},
 168         .has_8255 = 0,
 169         },
 170        {.device_id = 37,
 171         .isapnp_id = 0x2500,
 172         .name = "at-mio-16de-10",
 173         .n_adchan = 16,
 174         .adbits = 12,
 175         .ai_fifo_depth = 512,
 176         .alwaysdither = 0,
 177         .gainlkup = ai_gain_16,
 178         .ai_speed = 10000,
 179         .n_aochan = 2,
 180         .aobits = 12,
 181         .ao_fifo_depth = 0,
 182         .ao_range_table = &range_ni_E_ao_ext,
 183         .ao_unipolar = 1,
 184         .ao_speed = 10000,
 185         .num_p0_dio_channels = 8,
 186         .caldac = {ad8804_debug},
 187         .has_8255 = 1,
 188         },
 189        {.device_id = 38,
 190         .isapnp_id = 0x2600,
 191         .name = "at-mio-64e-3",
 192         .n_adchan = 64,
 193         .adbits = 12,
 194         .ai_fifo_depth = 2048,
 195         .alwaysdither = 0,
 196         .gainlkup = ai_gain_16,
 197         .ai_speed = 2000,
 198         .n_aochan = 2,
 199         .aobits = 12,
 200         .ao_fifo_depth = 2048,
 201         .ao_range_table = &range_ni_E_ao_ext,
 202         .ao_unipolar = 1,
 203         .ao_speed = 1000,
 204         .has_8255 = 0,
 205         .num_p0_dio_channels = 8,
 206         .caldac = {ad8804_debug},
 207         },
 208        {.device_id = 39,
 209         .isapnp_id = 0x2700,
 210         .name = "at-mio-16xe-50",
 211         .n_adchan = 16,
 212         .adbits = 16,
 213         .ai_fifo_depth = 512,
 214         .alwaysdither = 1,
 215         .gainlkup = ai_gain_8,
 216         .ai_speed = 50000,
 217         .n_aochan = 2,
 218         .aobits = 12,
 219         .ao_fifo_depth = 0,
 220         .ao_range_table = &range_bipolar10,
 221         .ao_unipolar = 0,
 222         .ao_speed = 50000,
 223         .num_p0_dio_channels = 8,
 224         .caldac = {dac8800, dac8043},
 225         .has_8255 = 0,
 226         },
 227        {.device_id = 50,
 228         .isapnp_id = 0x0000,   /* XXX unknown */
 229         .name = "at-mio-16xe-10",
 230         .n_adchan = 16,
 231         .adbits = 16,
 232         .ai_fifo_depth = 512,
 233         .alwaysdither = 1,
 234         .gainlkup = ai_gain_14,
 235         .ai_speed = 10000,
 236         .n_aochan = 2,
 237         .aobits = 16,
 238         .ao_fifo_depth = 2048,
 239         .ao_range_table = &range_ni_E_ao_ext,
 240         .ao_unipolar = 1,
 241         .ao_speed = 1000,
 242         .num_p0_dio_channels = 8,
 243         .caldac = {dac8800, dac8043, ad8522},
 244         .has_8255 = 0,
 245         },
 246        {.device_id = 51,
 247         .isapnp_id = 0x0000,   /* XXX unknown */
 248         .name = "at-ai-16xe-10",
 249         .n_adchan = 16,
 250         .adbits = 16,
 251         .ai_fifo_depth = 512,
 252         .alwaysdither = 1,     /* unknown */
 253         .gainlkup = ai_gain_14,
 254         .ai_speed = 10000,
 255         .n_aochan = 0,
 256         .aobits = 0,
 257         .ao_fifo_depth = 0,
 258         .ao_unipolar = 0,
 259         .num_p0_dio_channels = 8,
 260         .caldac = {dac8800, dac8043, ad8522},
 261         .has_8255 = 0,
 262         }
 263};
 264
 265static const int ni_irqpin[] = {
 266        -1, -1, -1, 0, 1, 2, -1, 3, -1, -1, 4, 5, 6, -1, -1, 7
 267};
 268
 269#define interrupt_pin(a)        (ni_irqpin[(a)])
 270
 271#define IRQ_POLARITY 0
 272
 273#define NI_E_IRQ_FLAGS          0
 274
 275struct ni_private {
 276        struct pnp_dev *isapnp_dev;
 277        NI_PRIVATE_COMMON
 278
 279};
 280
 281/* How we access registers */
 282
 283#define ni_writel(a, b)         (outl((a), (b)+dev->iobase))
 284#define ni_readl(a)             (inl((a)+dev->iobase))
 285#define ni_writew(a, b)         (outw((a), (b)+dev->iobase))
 286#define ni_readw(a)             (inw((a)+dev->iobase))
 287#define ni_writeb(a, b)         (outb((a), (b)+dev->iobase))
 288#define ni_readb(a)             (inb((a)+dev->iobase))
 289
 290/* How we access windowed registers */
 291
 292/* We automatically take advantage of STC registers that can be
 293 * read/written directly in the I/O space of the board.  The
 294 * AT-MIO devices map the low 8 STC registers to iobase+addr*2. */
 295
 296static void ni_atmio_win_out(struct comedi_device *dev, uint16_t data, int addr)
 297{
 298        struct ni_private *devpriv = dev->private;
 299        unsigned long flags;
 300
 301        spin_lock_irqsave(&devpriv->window_lock, flags);
 302        if ((addr) < 8) {
 303                ni_writew(data, addr * 2);
 304        } else {
 305                ni_writew(addr, Window_Address);
 306                ni_writew(data, Window_Data);
 307        }
 308        spin_unlock_irqrestore(&devpriv->window_lock, flags);
 309}
 310
 311static uint16_t ni_atmio_win_in(struct comedi_device *dev, int addr)
 312{
 313        struct ni_private *devpriv = dev->private;
 314        unsigned long flags;
 315        uint16_t ret;
 316
 317        spin_lock_irqsave(&devpriv->window_lock, flags);
 318        if (addr < 8) {
 319                ret = ni_readw(addr * 2);
 320        } else {
 321                ni_writew(addr, Window_Address);
 322                ret = ni_readw(Window_Data);
 323        }
 324        spin_unlock_irqrestore(&devpriv->window_lock, flags);
 325
 326        return ret;
 327}
 328
 329static struct pnp_device_id device_ids[] = {
 330        {.id = "NIC1900", .driver_data = 0},
 331        {.id = "NIC2400", .driver_data = 0},
 332        {.id = "NIC2500", .driver_data = 0},
 333        {.id = "NIC2600", .driver_data = 0},
 334        {.id = "NIC2700", .driver_data = 0},
 335        {.id = ""}
 336};
 337
 338MODULE_DEVICE_TABLE(pnp, device_ids);
 339
 340#include "ni_mio_common.c"
 341
 342static int ni_isapnp_find_board(struct pnp_dev **dev)
 343{
 344        struct pnp_dev *isapnp_dev = NULL;
 345        int i;
 346
 347        for (i = 0; i < ARRAY_SIZE(ni_boards); i++) {
 348                isapnp_dev = pnp_find_dev(NULL,
 349                                          ISAPNP_VENDOR('N', 'I', 'C'),
 350                                          ISAPNP_FUNCTION(ni_boards[i].
 351                                                          isapnp_id), NULL);
 352
 353                if (isapnp_dev == NULL || isapnp_dev->card == NULL)
 354                        continue;
 355
 356                if (pnp_device_attach(isapnp_dev) < 0) {
 357                        printk
 358                         ("ni_atmio: %s found but already active, skipping.\n",
 359                          ni_boards[i].name);
 360                        continue;
 361                }
 362                if (pnp_activate_dev(isapnp_dev) < 0) {
 363                        pnp_device_detach(isapnp_dev);
 364                        return -EAGAIN;
 365                }
 366                if (!pnp_port_valid(isapnp_dev, 0)
 367                    || !pnp_irq_valid(isapnp_dev, 0)) {
 368                        pnp_device_detach(isapnp_dev);
 369                        printk("ni_atmio: pnp invalid port or irq, aborting\n");
 370                        return -ENOMEM;
 371                }
 372                break;
 373        }
 374        if (i == ARRAY_SIZE(ni_boards))
 375                return -ENODEV;
 376        *dev = isapnp_dev;
 377        return 0;
 378}
 379
 380static int ni_getboardtype(struct comedi_device *dev)
 381{
 382        int device_id = ni_read_eeprom(dev, 511);
 383        int i;
 384
 385        for (i = 0; i < ARRAY_SIZE(ni_boards); i++) {
 386                if (ni_boards[i].device_id == device_id)
 387                        return i;
 388
 389        }
 390        if (device_id == 255)
 391                printk(" can't find board\n");
 392         else if (device_id == 0)
 393                printk(" EEPROM read error (?) or device not found\n");
 394         else
 395                printk(" unknown device ID %d -- contact author\n", device_id);
 396
 397        return -1;
 398}
 399
 400static int ni_atmio_attach(struct comedi_device *dev,
 401                           struct comedi_devconfig *it)
 402{
 403        const struct ni_board_struct *boardtype;
 404        struct ni_private *devpriv;
 405        struct pnp_dev *isapnp_dev;
 406        int ret;
 407        unsigned long iobase;
 408        int board;
 409        unsigned int irq;
 410
 411        ret = ni_alloc_private(dev);
 412        if (ret)
 413                return ret;
 414        devpriv = dev->private;
 415
 416        devpriv->stc_writew = &ni_atmio_win_out;
 417        devpriv->stc_readw = &ni_atmio_win_in;
 418        devpriv->stc_writel = &win_out2;
 419        devpriv->stc_readl = &win_in2;
 420
 421        iobase = it->options[0];
 422        irq = it->options[1];
 423        isapnp_dev = NULL;
 424        if (iobase == 0) {
 425                ret = ni_isapnp_find_board(&isapnp_dev);
 426                if (ret < 0)
 427                        return ret;
 428
 429                iobase = pnp_port_start(isapnp_dev, 0);
 430                irq = pnp_irq(isapnp_dev, 0);
 431                devpriv->isapnp_dev = isapnp_dev;
 432        }
 433
 434        ret = comedi_request_region(dev, iobase, NI_SIZE);
 435        if (ret)
 436                return ret;
 437
 438        /* get board type */
 439
 440        board = ni_getboardtype(dev);
 441        if (board < 0)
 442                return -EIO;
 443
 444        dev->board_ptr = ni_boards + board;
 445        boardtype = comedi_board(dev);
 446
 447        printk(" %s", boardtype->name);
 448        dev->board_name = boardtype->name;
 449
 450        /* irq stuff */
 451
 452        if (irq != 0) {
 453                if (irq > 15 || ni_irqpin[irq] == -1) {
 454                        printk(" invalid irq %u\n", irq);
 455                        return -EINVAL;
 456                }
 457                printk(" ( irq = %u )", irq);
 458                ret = request_irq(irq, ni_E_interrupt, NI_E_IRQ_FLAGS,
 459                                  "ni_atmio", dev);
 460
 461                if (ret < 0) {
 462                        printk(" irq not available\n");
 463                        return -EINVAL;
 464                }
 465                dev->irq = irq;
 466        }
 467
 468        /* generic E series stuff in ni_mio_common.c */
 469
 470        ret = ni_E_init(dev);
 471        if (ret < 0)
 472                return ret;
 473
 474
 475        return 0;
 476}
 477
 478static void ni_atmio_detach(struct comedi_device *dev)
 479{
 480        struct ni_private *devpriv = dev->private;
 481
 482        mio_common_detach(dev);
 483        comedi_legacy_detach(dev);
 484        if (devpriv->isapnp_dev)
 485                pnp_device_detach(devpriv->isapnp_dev);
 486}
 487
 488static struct comedi_driver ni_atmio_driver = {
 489        .driver_name    = "ni_atmio",
 490        .module         = THIS_MODULE,
 491        .attach         = ni_atmio_attach,
 492        .detach         = ni_atmio_detach,
 493};
 494module_comedi_driver(ni_atmio_driver);
 495