linux/drivers/staging/comedi/drivers/ni_mio_cs.c
<<
>>
Prefs
   1/*
   2    comedi/drivers/ni_mio_cs.c
   3    Hardware driver for NI PCMCIA MIO E series cards
   4
   5    COMEDI - Linux Control and Measurement Device Interface
   6    Copyright (C) 1997-2000 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    You should have received a copy of the GNU General Public License
  19    along with this program; if not, write to the Free Software
  20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21
  22*/
  23/*
  24Driver: ni_mio_cs
  25Description: National Instruments DAQCard E series
  26Author: ds
  27Status: works
  28Devices: [National Instruments] DAQCard-AI-16XE-50 (ni_mio_cs),
  29  DAQCard-AI-16E-4, DAQCard-6062E, DAQCard-6024E, DAQCard-6036E
  30Updated: Thu Oct 23 19:43:17 CDT 2003
  31
  32See the notes in the ni_atmio.o driver.
  33*/
  34/*
  35        The real guts of the driver is in ni_mio_common.c, which is
  36        included by all the E series drivers.
  37
  38        References for specifications:
  39
  40           341080a.pdf  DAQCard E Series Register Level Programmer Manual
  41
  42*/
  43
  44#include "../comedidev.h"
  45
  46#include <linux/delay.h>
  47
  48#include "ni_stc.h"
  49#include "8255.h"
  50
  51#include <pcmcia/cs_types.h>
  52#include <pcmcia/cs.h>
  53#include <pcmcia/cistpl.h>
  54#include <pcmcia/ds.h>
  55
  56#undef DEBUG
  57
  58#define ATMIO 1
  59#undef PCIMIO
  60
  61/*
  62 *  AT specific setup
  63 */
  64
  65#define NI_SIZE 0x20
  66
  67#define MAX_N_CALDACS 32
  68
  69static const struct ni_board_struct ni_boards[] = {
  70        {.device_id = 0x010d,
  71         .name = "DAQCard-ai-16xe-50",
  72         .n_adchan = 16,
  73         .adbits = 16,
  74         .ai_fifo_depth = 1024,
  75         .alwaysdither = 0,
  76         .gainlkup = ai_gain_8,
  77         .ai_speed = 5000,
  78         .n_aochan = 0,
  79         .aobits = 0,
  80         .ao_fifo_depth = 0,
  81         .ao_unipolar = 0,
  82         .num_p0_dio_channels = 8,
  83         .has_8255 = 0,
  84         .caldac = {dac8800, dac8043},
  85         },
  86        {.device_id = 0x010c,
  87         .name = "DAQCard-ai-16e-4",
  88         .n_adchan = 16,
  89         .adbits = 12,
  90         .ai_fifo_depth = 1024,
  91         .alwaysdither = 0,
  92         .gainlkup = ai_gain_16,
  93         .ai_speed = 4000,
  94         .n_aochan = 0,
  95         .aobits = 0,
  96         .ao_fifo_depth = 0,
  97         .ao_unipolar = 0,
  98         .num_p0_dio_channels = 8,
  99         .has_8255 = 0,
 100         .caldac = {mb88341},   /* verified */
 101         },
 102        {.device_id = 0x02c4,
 103         .name = "DAQCard-6062E",
 104         .n_adchan = 16,
 105         .adbits = 12,
 106         .ai_fifo_depth = 8192,
 107         .alwaysdither = 0,
 108         .gainlkup = ai_gain_16,
 109         .ai_speed = 2000,
 110         .n_aochan = 2,
 111         .aobits = 12,
 112         .ao_fifo_depth = 2048,
 113         .ao_range_table = &range_bipolar10,
 114         .ao_unipolar = 0,
 115         .ao_speed = 1176,
 116         .num_p0_dio_channels = 8,
 117         .has_8255 = 0,
 118         .caldac = {ad8804_debug},      /* verified */
 119         },
 120        {.device_id = 0x075e,
 121         .name = "DAQCard-6024E",       /* specs incorrect! */
 122         .n_adchan = 16,
 123         .adbits = 12,
 124         .ai_fifo_depth = 1024,
 125         .alwaysdither = 0,
 126         .gainlkup = ai_gain_16,
 127         .ai_speed = 5000,
 128         .n_aochan = 2,
 129         .aobits = 12,
 130         .ao_fifo_depth = 0,
 131         .ao_range_table = &range_bipolar10,
 132         .ao_unipolar = 0,
 133         .ao_speed = 1000000,
 134         .num_p0_dio_channels = 8,
 135         .has_8255 = 0,
 136         .caldac = {ad8804_debug},
 137         },
 138        {.device_id = 0x0245,
 139         .name = "DAQCard-6036E",       /* specs incorrect! */
 140         .n_adchan = 16,
 141         .adbits = 16,
 142         .ai_fifo_depth = 1024,
 143         .alwaysdither = 1,
 144         .gainlkup = ai_gain_4,
 145         .ai_speed = 5000,
 146         .n_aochan = 2,
 147         .aobits = 16,
 148         .ao_fifo_depth = 0,
 149         .ao_range_table = &range_bipolar10,
 150         .ao_unipolar = 0,
 151         .ao_speed = 1000000,
 152         .num_p0_dio_channels = 8,
 153         .has_8255 = 0,
 154         .caldac = {ad8804_debug},
 155         },
 156#if 0
 157        {.device_id = 0x0000,   /* unknown */
 158         .name = "DAQCard-6715",
 159         .n_adchan = 0,
 160         .n_aochan = 8,
 161         .aobits = 12,
 162         .ao_671x = 8192,
 163         .num_p0_dio_channels = 8,
 164         .caldac = {mb88341, mb88341},
 165         },
 166#endif
 167        /* N.B. Update ni_mio_cs_ids[] when entries added above. */
 168};
 169
 170#define interrupt_pin(a)        0
 171
 172#define IRQ_POLARITY 1
 173
 174#define NI_E_IRQ_FLAGS          IRQF_SHARED
 175
 176struct ni_private {
 177
 178        struct pcmcia_device *link;
 179
 180 NI_PRIVATE_COMMON};
 181
 182#define devpriv ((struct ni_private *)dev->private)
 183
 184/* How we access registers */
 185
 186#define ni_writel(a, b)         (outl((a), (b)+dev->iobase))
 187#define ni_readl(a)             (inl((a)+dev->iobase))
 188#define ni_writew(a, b)         (outw((a), (b)+dev->iobase))
 189#define ni_readw(a)             (inw((a)+dev->iobase))
 190#define ni_writeb(a, b)         (outb((a), (b)+dev->iobase))
 191#define ni_readb(a)             (inb((a)+dev->iobase))
 192
 193/* How we access windowed registers */
 194
 195/* We automatically take advantage of STC registers that can be
 196 * read/written directly in the I/O space of the board.  The
 197 * DAQCard devices map the low 8 STC registers to iobase+addr*2. */
 198
 199static void mio_cs_win_out(struct comedi_device *dev, uint16_t data, int addr)
 200{
 201        unsigned long flags;
 202
 203        spin_lock_irqsave(&devpriv->window_lock, flags);
 204        if (addr < 8) {
 205                ni_writew(data, addr * 2);
 206        } else {
 207                ni_writew(addr, Window_Address);
 208                ni_writew(data, Window_Data);
 209        }
 210        spin_unlock_irqrestore(&devpriv->window_lock, flags);
 211}
 212
 213static uint16_t mio_cs_win_in(struct comedi_device *dev, int addr)
 214{
 215        unsigned long flags;
 216        uint16_t ret;
 217
 218        spin_lock_irqsave(&devpriv->window_lock, flags);
 219        if (addr < 8) {
 220                ret = ni_readw(addr * 2);
 221        } else {
 222                ni_writew(addr, Window_Address);
 223                ret = ni_readw(Window_Data);
 224        }
 225        spin_unlock_irqrestore(&devpriv->window_lock, flags);
 226
 227        return ret;
 228}
 229
 230static int mio_cs_attach(struct comedi_device *dev,
 231                         struct comedi_devconfig *it);
 232static int mio_cs_detach(struct comedi_device *dev);
 233static struct comedi_driver driver_ni_mio_cs = {
 234        .driver_name = "ni_mio_cs",
 235        .module = THIS_MODULE,
 236        .attach = mio_cs_attach,
 237        .detach = mio_cs_detach,
 238};
 239
 240#include "ni_mio_common.c"
 241
 242static int ni_getboardtype(struct comedi_device *dev,
 243                           struct pcmcia_device *link);
 244
 245/* clean up allocated resources */
 246/* called when driver is removed */
 247static int mio_cs_detach(struct comedi_device *dev)
 248{
 249        mio_common_detach(dev);
 250
 251        /* PCMCIA layer frees the IO region */
 252
 253        if (dev->irq) {
 254                free_irq(dev->irq, dev);
 255        }
 256
 257        return 0;
 258}
 259
 260static void mio_cs_config(struct pcmcia_device *link);
 261static void cs_release(struct pcmcia_device *link);
 262static void cs_detach(struct pcmcia_device *);
 263
 264static struct pcmcia_device *cur_dev = NULL;
 265static const dev_info_t dev_info = "ni_mio_cs";
 266static dev_node_t dev_node = {
 267        "ni_mio_cs",
 268        COMEDI_MAJOR, 0,
 269        NULL
 270};
 271
 272static int cs_attach(struct pcmcia_device *link)
 273{
 274        link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
 275        link->io.NumPorts1 = 16;
 276        link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
 277        link->irq.IRQInfo1 = IRQ_LEVEL_ID;
 278        link->conf.Attributes = CONF_ENABLE_IRQ;
 279        link->conf.IntType = INT_MEMORY_AND_IO;
 280
 281        cur_dev = link;
 282
 283        mio_cs_config(link);
 284
 285        return 0;
 286}
 287
 288static void cs_release(struct pcmcia_device *link)
 289{
 290        pcmcia_disable_device(link);
 291}
 292
 293static void cs_detach(struct pcmcia_device *link)
 294{
 295        DPRINTK("cs_detach(link=%p)\n", link);
 296
 297        if (link->dev_node) {
 298                cs_release(link);
 299        }
 300}
 301
 302static int mio_cs_suspend(struct pcmcia_device *link)
 303{
 304        DPRINTK("pm suspend\n");
 305
 306        return 0;
 307}
 308
 309static int mio_cs_resume(struct pcmcia_device *link)
 310{
 311        DPRINTK("pm resume\n");
 312        return 0;
 313}
 314
 315static void mio_cs_config(struct pcmcia_device *link)
 316{
 317        tuple_t tuple;
 318        u_short buf[128];
 319        cisparse_t parse;
 320        int manfid = 0, prodid = 0;
 321        int ret;
 322
 323        DPRINTK("mio_cs_config(link=%p)\n", link);
 324
 325        tuple.TupleData = (cisdata_t *) buf;
 326        tuple.TupleOffset = 0;
 327        tuple.TupleDataMax = 255;
 328        tuple.Attributes = 0;
 329
 330        tuple.DesiredTuple = CISTPL_CONFIG;
 331        ret = pcmcia_get_first_tuple(link, &tuple);
 332        ret = pcmcia_get_tuple_data(link, &tuple);
 333        ret = pcmcia_parse_tuple(&tuple, &parse);
 334        link->conf.ConfigBase = parse.config.base;
 335        link->conf.Present = parse.config.rmask[0];
 336
 337#if 0
 338        tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
 339        tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
 340        info->multi(first_tuple(link, &tuple, &parse) == 0);
 341#endif
 342
 343        tuple.DesiredTuple = CISTPL_MANFID;
 344        tuple.Attributes = TUPLE_RETURN_COMMON;
 345        if ((pcmcia_get_first_tuple(link, &tuple) == 0) &&
 346            (pcmcia_get_tuple_data(link, &tuple) == 0)) {
 347                manfid = le16_to_cpu(buf[0]);
 348                prodid = le16_to_cpu(buf[1]);
 349        }
 350        /* printk("manfid = 0x%04x, 0x%04x\n",manfid,prodid); */
 351
 352        tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
 353        tuple.Attributes = 0;
 354        ret = pcmcia_get_first_tuple(link, &tuple);
 355        ret = pcmcia_get_tuple_data(link, &tuple);
 356        ret = pcmcia_parse_tuple(&tuple, &parse);
 357
 358#if 0
 359        printk(" index: 0x%x\n", parse.cftable_entry.index);
 360        printk(" flags: 0x%x\n", parse.cftable_entry.flags);
 361        printk(" io flags: 0x%x\n", parse.cftable_entry.io.flags);
 362        printk(" io nwin: 0x%x\n", parse.cftable_entry.io.nwin);
 363        printk(" io base: 0x%x\n", parse.cftable_entry.io.win[0].base);
 364        printk(" io len: 0x%x\n", parse.cftable_entry.io.win[0].len);
 365        printk(" irq1: 0x%x\n", parse.cftable_entry.irq.IRQInfo1);
 366        printk(" irq2: 0x%x\n", parse.cftable_entry.irq.IRQInfo2);
 367        printk(" mem flags: 0x%x\n", parse.cftable_entry.mem.flags);
 368        printk(" mem nwin: 0x%x\n", parse.cftable_entry.mem.nwin);
 369        printk(" subtuples: 0x%x\n", parse.cftable_entry.subtuples);
 370#endif
 371
 372#if 0
 373        link->io.NumPorts1 = 0x20;
 374        link->io.IOAddrLines = 5;
 375        link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
 376#endif
 377        link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
 378        link->io.IOAddrLines =
 379            parse.cftable_entry.io.flags & CISTPL_IO_LINES_MASK;
 380        link->io.NumPorts2 = 0;
 381
 382        {
 383                int base;
 384                for (base = 0x000; base < 0x400; base += 0x20) {
 385                        link->io.BasePort1 = base;
 386                        ret = pcmcia_request_io(link, &link->io);
 387                        /* printk("RequestIO 0x%02x\n",ret); */
 388                        if (!ret)
 389                                break;
 390                }
 391        }
 392
 393        link->irq.IRQInfo1 = parse.cftable_entry.irq.IRQInfo1;
 394        link->irq.IRQInfo2 = parse.cftable_entry.irq.IRQInfo2;
 395        ret = pcmcia_request_irq(link, &link->irq);
 396        if (ret) {
 397                printk("pcmcia_request_irq() returned error: %i\n", ret);
 398        }
 399        /* printk("RequestIRQ 0x%02x\n",ret); */
 400
 401        link->conf.ConfigIndex = 1;
 402
 403        ret = pcmcia_request_configuration(link, &link->conf);
 404        /* printk("RequestConfiguration %d\n",ret); */
 405
 406        link->dev_node = &dev_node;
 407}
 408
 409static int mio_cs_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 410{
 411        struct pcmcia_device *link;
 412        unsigned int irq;
 413        int ret;
 414
 415        DPRINTK("mio_cs_attach(dev=%p,it=%p)\n", dev, it);
 416
 417        link = cur_dev;         /* XXX hack */
 418        if (!link)
 419                return -EIO;
 420
 421        dev->driver = &driver_ni_mio_cs;
 422        dev->iobase = link->io.BasePort1;
 423
 424        irq = link->irq.AssignedIRQ;
 425
 426        printk("comedi%d: %s: DAQCard: io 0x%04lx, irq %u, ",
 427               dev->minor, dev->driver->driver_name, dev->iobase, irq);
 428
 429#if 0
 430        {
 431                int i;
 432
 433                printk(" board fingerprint:");
 434                for (i = 0; i < 32; i += 2) {
 435                        printk(" %04x %02x", inw(dev->iobase + i),
 436                               inb(dev->iobase + i + 1));
 437                }
 438                printk("\n");
 439                printk(" board fingerprint (windowed):");
 440                for (i = 0; i < 10; i++) {
 441                        printk(" 0x%04x", win_in(i));
 442                }
 443                printk("\n");
 444        }
 445#endif
 446
 447        dev->board_ptr = ni_boards + ni_getboardtype(dev, link);
 448
 449        printk(" %s", boardtype.name);
 450        dev->board_name = boardtype.name;
 451
 452        ret = request_irq(irq, ni_E_interrupt, NI_E_IRQ_FLAGS,
 453                          "ni_mio_cs", dev);
 454        if (ret < 0) {
 455                printk(" irq not available\n");
 456                return -EINVAL;
 457        }
 458        dev->irq = irq;
 459
 460        /* allocate private area */
 461        ret = ni_alloc_private(dev);
 462        if (ret < 0)
 463                return ret;
 464
 465        devpriv->stc_writew = &mio_cs_win_out;
 466        devpriv->stc_readw = &mio_cs_win_in;
 467        devpriv->stc_writel = &win_out2;
 468        devpriv->stc_readl = &win_in2;
 469
 470        ret = ni_E_init(dev, it);
 471
 472        if (ret < 0)
 473                return ret;
 474
 475        return 0;
 476}
 477
 478static int get_prodid(struct comedi_device *dev, struct pcmcia_device *link)
 479{
 480        tuple_t tuple;
 481        u_short buf[128];
 482        int prodid = 0;
 483
 484        tuple.TupleData = (cisdata_t *) buf;
 485        tuple.TupleOffset = 0;
 486        tuple.TupleDataMax = 255;
 487        tuple.DesiredTuple = CISTPL_MANFID;
 488        tuple.Attributes = TUPLE_RETURN_COMMON;
 489        if ((pcmcia_get_first_tuple(link, &tuple) == 0) &&
 490            (pcmcia_get_tuple_data(link, &tuple) == 0)) {
 491                prodid = le16_to_cpu(buf[1]);
 492        }
 493
 494        return prodid;
 495}
 496
 497static int ni_getboardtype(struct comedi_device *dev,
 498                           struct pcmcia_device *link)
 499{
 500        int id;
 501        int i;
 502
 503        id = get_prodid(dev, link);
 504
 505        for (i = 0; i < n_ni_boards; i++) {
 506                if (ni_boards[i].device_id == id) {
 507                        return i;
 508                }
 509        }
 510
 511        printk("unknown board 0x%04x -- pretend it is a ", id);
 512
 513        return 0;
 514}
 515
 516#ifdef MODULE
 517
 518MODULE_LICENSE("GPL");
 519
 520static struct pcmcia_device_id ni_mio_cs_ids[] = {
 521        PCMCIA_DEVICE_MANF_CARD(0x010b, 0x010d),        /* DAQCard-ai-16xe-50 */
 522        PCMCIA_DEVICE_MANF_CARD(0x010b, 0x010c),        /* DAQCard-ai-16e-4 */
 523        PCMCIA_DEVICE_MANF_CARD(0x010b, 0x02c4),        /* DAQCard-6062E */
 524        PCMCIA_DEVICE_MANF_CARD(0x010b, 0x075e),        /* DAQCard-6024E */
 525        PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0245),        /* DAQCard-6036E */
 526        PCMCIA_DEVICE_NULL
 527};
 528
 529MODULE_DEVICE_TABLE(pcmcia, ni_mio_cs_ids);
 530
 531struct pcmcia_driver ni_mio_cs_driver = {
 532        .probe = &cs_attach,
 533        .remove = &cs_detach,
 534        .suspend = &mio_cs_suspend,
 535        .resume = &mio_cs_resume,
 536        .id_table = ni_mio_cs_ids,
 537        .owner = THIS_MODULE,
 538        .drv = {
 539                .name = dev_info,
 540                },
 541};
 542
 543int init_module(void)
 544{
 545        pcmcia_register_driver(&ni_mio_cs_driver);
 546        comedi_driver_register(&driver_ni_mio_cs);
 547        return 0;
 548}
 549
 550void cleanup_module(void)
 551{
 552        pcmcia_unregister_driver(&ni_mio_cs_driver);
 553#if 0
 554        while (cur_dev != NULL)
 555                cs_detach(cur_dev->handle);
 556#endif
 557        comedi_driver_unregister(&driver_ni_mio_cs);
 558}
 559#endif
 560