linux/drivers/staging/comedi/drivers/cb_das16_cs.c
<<
>>
Prefs
   1/*
   2    comedi/drivers/das16cs.c
   3    Driver for Computer Boards PC-CARD DAS16/16.
   4
   5    COMEDI - Linux Control and Measurement Device Interface
   6    Copyright (C) 2000, 2001, 2002 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: cb_das16_cs
  25Description: Computer Boards PC-CARD DAS16/16
  26Devices: [ComputerBoards] PC-CARD DAS16/16 (cb_das16_cs), PC-CARD DAS16/16-AO
  27Author: ds
  28Updated: Mon, 04 Nov 2002 20:04:21 -0800
  29Status: experimental
  30
  31
  32*/
  33
  34#include <linux/interrupt.h>
  35#include "../comedidev.h"
  36#include <linux/delay.h>
  37#include <linux/pci.h>
  38
  39#include <pcmcia/cs_types.h>
  40#include <pcmcia/cs.h>
  41#include <pcmcia/cistpl.h>
  42#include <pcmcia/ds.h>
  43
  44#include "8253.h"
  45
  46#define DAS16CS_SIZE                    18
  47
  48#define DAS16CS_ADC_DATA                0
  49#define DAS16CS_DIO_MUX                 2
  50#define DAS16CS_MISC1                   4
  51#define DAS16CS_MISC2                   6
  52#define DAS16CS_CTR0                    8
  53#define DAS16CS_CTR1                    10
  54#define DAS16CS_CTR2                    12
  55#define DAS16CS_CTR_CONTROL             14
  56#define DAS16CS_DIO                     16
  57
  58struct das16cs_board {
  59        const char *name;
  60        int device_id;
  61        int n_ao_chans;
  62};
  63static const struct das16cs_board das16cs_boards[] = {
  64        {
  65         .device_id = 0x0000,   /* unknown */
  66         .name = "PC-CARD DAS16/16",
  67         .n_ao_chans = 0,
  68         },
  69        {
  70         .device_id = 0x0039,
  71         .name = "PC-CARD DAS16/16-AO",
  72         .n_ao_chans = 2,
  73         },
  74        {
  75         .device_id = 0x4009,
  76         .name = "PCM-DAS16s/16",
  77         .n_ao_chans = 0,
  78         },
  79};
  80
  81#define n_boards ARRAY_SIZE(das16cs_boards)
  82#define thisboard ((const struct das16cs_board *)dev->board_ptr)
  83
  84struct das16cs_private {
  85        struct pcmcia_device *link;
  86
  87        unsigned int ao_readback[2];
  88        unsigned short status1;
  89        unsigned short status2;
  90};
  91#define devpriv ((struct das16cs_private *)dev->private)
  92
  93static int das16cs_attach(struct comedi_device *dev,
  94                          struct comedi_devconfig *it);
  95static int das16cs_detach(struct comedi_device *dev);
  96static struct comedi_driver driver_das16cs = {
  97        .driver_name = "cb_das16_cs",
  98        .module = THIS_MODULE,
  99        .attach = das16cs_attach,
 100        .detach = das16cs_detach,
 101};
 102
 103static struct pcmcia_device *cur_dev = NULL;
 104
 105static const struct comedi_lrange das16cs_ai_range = { 4, {
 106                                                           RANGE(-10, 10),
 107                                                           RANGE(-5, 5),
 108                                                           RANGE(-2.5, 2.5),
 109                                                           RANGE(-1.25, 1.25),
 110                                                           }
 111};
 112
 113static irqreturn_t das16cs_interrupt(int irq, void *d);
 114static int das16cs_ai_rinsn(struct comedi_device *dev,
 115                            struct comedi_subdevice *s,
 116                            struct comedi_insn *insn, unsigned int *data);
 117static int das16cs_ai_cmd(struct comedi_device *dev,
 118                          struct comedi_subdevice *s);
 119static int das16cs_ai_cmdtest(struct comedi_device *dev,
 120                              struct comedi_subdevice *s,
 121                              struct comedi_cmd *cmd);
 122static int das16cs_ao_winsn(struct comedi_device *dev,
 123                            struct comedi_subdevice *s,
 124                            struct comedi_insn *insn, unsigned int *data);
 125static int das16cs_ao_rinsn(struct comedi_device *dev,
 126                            struct comedi_subdevice *s,
 127                            struct comedi_insn *insn, unsigned int *data);
 128static int das16cs_dio_insn_bits(struct comedi_device *dev,
 129                                 struct comedi_subdevice *s,
 130                                 struct comedi_insn *insn, unsigned int *data);
 131static int das16cs_dio_insn_config(struct comedi_device *dev,
 132                                   struct comedi_subdevice *s,
 133                                   struct comedi_insn *insn,
 134                                   unsigned int *data);
 135static int das16cs_timer_insn_read(struct comedi_device *dev,
 136                                   struct comedi_subdevice *s,
 137                                   struct comedi_insn *insn,
 138                                   unsigned int *data);
 139static int das16cs_timer_insn_config(struct comedi_device *dev,
 140                                     struct comedi_subdevice *s,
 141                                     struct comedi_insn *insn,
 142                                     unsigned int *data);
 143
 144static int get_prodid(struct comedi_device *dev, struct pcmcia_device *link)
 145{
 146        tuple_t tuple;
 147        u_short buf[128];
 148        int prodid = 0;
 149
 150        tuple.TupleData = (cisdata_t *) buf;
 151        tuple.TupleOffset = 0;
 152        tuple.TupleDataMax = 255;
 153        tuple.DesiredTuple = CISTPL_MANFID;
 154        tuple.Attributes = TUPLE_RETURN_COMMON;
 155        if ((pcmcia_get_first_tuple(link, &tuple) == 0) &&
 156            (pcmcia_get_tuple_data(link, &tuple) == 0)) {
 157                prodid = le16_to_cpu(buf[1]);
 158        }
 159
 160        return prodid;
 161}
 162
 163static const struct das16cs_board *das16cs_probe(struct comedi_device *dev,
 164                                                 struct pcmcia_device *link)
 165{
 166        int id;
 167        int i;
 168
 169        id = get_prodid(dev, link);
 170
 171        for (i = 0; i < n_boards; i++) {
 172                if (das16cs_boards[i].device_id == id) {
 173                        return das16cs_boards + i;
 174                }
 175        }
 176
 177        printk("unknown board!\n");
 178
 179        return NULL;
 180}
 181
 182static int das16cs_attach(struct comedi_device *dev,
 183                          struct comedi_devconfig *it)
 184{
 185        struct pcmcia_device *link;
 186        struct comedi_subdevice *s;
 187        int ret;
 188        int i;
 189
 190        printk("comedi%d: cb_das16_cs: ", dev->minor);
 191
 192        link = cur_dev;         /* XXX hack */
 193        if (!link)
 194                return -EIO;
 195
 196        dev->iobase = link->io.BasePort1;
 197        printk("I/O base=0x%04lx ", dev->iobase);
 198
 199        printk("fingerprint:\n");
 200        for (i = 0; i < 48; i += 2) {
 201                printk("%04x ", inw(dev->iobase + i));
 202        }
 203        printk("\n");
 204
 205        ret = request_irq(link->irq.AssignedIRQ, das16cs_interrupt,
 206                          IRQF_SHARED, "cb_das16_cs", dev);
 207        if (ret < 0) {
 208                return ret;
 209        }
 210        dev->irq = link->irq.AssignedIRQ;
 211        printk("irq=%u ", dev->irq);
 212
 213        dev->board_ptr = das16cs_probe(dev, link);
 214        if (!dev->board_ptr)
 215                return -EIO;
 216
 217        dev->board_name = thisboard->name;
 218
 219        if (alloc_private(dev, sizeof(struct das16cs_private)) < 0)
 220                return -ENOMEM;
 221
 222        if (alloc_subdevices(dev, 4) < 0)
 223                return -ENOMEM;
 224
 225        s = dev->subdevices + 0;
 226        dev->read_subdev = s;
 227        /* analog input subdevice */
 228        s->type = COMEDI_SUBD_AI;
 229        s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
 230        s->n_chan = 16;
 231        s->maxdata = 0xffff;
 232        s->range_table = &das16cs_ai_range;
 233        s->len_chanlist = 16;
 234        s->insn_read = das16cs_ai_rinsn;
 235        s->do_cmd = das16cs_ai_cmd;
 236        s->do_cmdtest = das16cs_ai_cmdtest;
 237
 238        s = dev->subdevices + 1;
 239        /* analog output subdevice */
 240        if (thisboard->n_ao_chans) {
 241                s->type = COMEDI_SUBD_AO;
 242                s->subdev_flags = SDF_WRITABLE;
 243                s->n_chan = thisboard->n_ao_chans;
 244                s->maxdata = 0xffff;
 245                s->range_table = &range_bipolar10;
 246                s->insn_write = &das16cs_ao_winsn;
 247                s->insn_read = &das16cs_ao_rinsn;
 248        }
 249
 250        s = dev->subdevices + 2;
 251        /* digital i/o subdevice */
 252        if (1) {
 253                s->type = COMEDI_SUBD_DIO;
 254                s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 255                s->n_chan = 8;
 256                s->maxdata = 1;
 257                s->range_table = &range_digital;
 258                s->insn_bits = das16cs_dio_insn_bits;
 259                s->insn_config = das16cs_dio_insn_config;
 260        } else {
 261                s->type = COMEDI_SUBD_UNUSED;
 262        }
 263
 264        s = dev->subdevices + 3;
 265        /* timer subdevice */
 266        if (0) {
 267                s->type = COMEDI_SUBD_TIMER;
 268                s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 269                s->n_chan = 1;
 270                s->maxdata = 0xff;
 271                s->range_table = &range_unknown;
 272                s->insn_read = das16cs_timer_insn_read;
 273                s->insn_config = das16cs_timer_insn_config;
 274        } else {
 275                s->type = COMEDI_SUBD_UNUSED;
 276        }
 277
 278        printk("attached\n");
 279
 280        return 1;
 281}
 282
 283static int das16cs_detach(struct comedi_device *dev)
 284{
 285        printk("comedi%d: das16cs: remove\n", dev->minor);
 286
 287        if (dev->irq) {
 288                free_irq(dev->irq, dev);
 289        }
 290
 291        return 0;
 292}
 293
 294static irqreturn_t das16cs_interrupt(int irq, void *d)
 295{
 296        /* struct comedi_device *dev = d; */
 297        return IRQ_HANDLED;
 298}
 299
 300/*
 301 * "instructions" read/write data in "one-shot" or "software-triggered"
 302 * mode.
 303 */
 304static int das16cs_ai_rinsn(struct comedi_device *dev,
 305                            struct comedi_subdevice *s,
 306                            struct comedi_insn *insn, unsigned int *data)
 307{
 308        int i;
 309        int to;
 310        int aref;
 311        int range;
 312        int chan;
 313        static int range_bits[] = { 0x800, 0x000, 0x100, 0x200 };
 314
 315        chan = CR_CHAN(insn->chanspec);
 316        aref = CR_AREF(insn->chanspec);
 317        range = CR_RANGE(insn->chanspec);
 318
 319        outw(chan, dev->iobase + 2);
 320
 321        devpriv->status1 &= ~0xf320;
 322        devpriv->status1 |= (aref == AREF_DIFF) ? 0 : 0x0020;
 323        outw(devpriv->status1, dev->iobase + 4);
 324
 325        devpriv->status2 &= ~0xff00;
 326        devpriv->status2 |= range_bits[range];
 327        outw(devpriv->status2, dev->iobase + 6);
 328
 329        for (i = 0; i < insn->n; i++) {
 330                outw(0, dev->iobase);
 331
 332#define TIMEOUT 1000
 333                for (to = 0; to < TIMEOUT; to++) {
 334                        if (inw(dev->iobase + 4) & 0x0080)
 335                                break;
 336                }
 337                if (to == TIMEOUT) {
 338                        printk("cb_das16_cs: ai timeout\n");
 339                        return -ETIME;
 340                }
 341                data[i] = (unsigned short)inw(dev->iobase + 0);
 342        }
 343
 344        return i;
 345}
 346
 347static int das16cs_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 348{
 349        return -EINVAL;
 350}
 351
 352static int das16cs_ai_cmdtest(struct comedi_device *dev,
 353                              struct comedi_subdevice *s,
 354                              struct comedi_cmd *cmd)
 355{
 356        int err = 0;
 357        int tmp;
 358
 359        /* cmdtest tests a particular command to see if it is valid.
 360         * Using the cmdtest ioctl, a user can create a valid cmd
 361         * and then have it executes by the cmd ioctl.
 362         *
 363         * cmdtest returns 1,2,3,4 or 0, depending on which tests
 364         * the command passes. */
 365
 366        /* step 1: make sure trigger sources are trivially valid */
 367
 368        tmp = cmd->start_src;
 369        cmd->start_src &= TRIG_NOW;
 370        if (!cmd->start_src || tmp != cmd->start_src)
 371                err++;
 372
 373        tmp = cmd->scan_begin_src;
 374        cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;
 375        if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
 376                err++;
 377
 378        tmp = cmd->convert_src;
 379        cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
 380        if (!cmd->convert_src || tmp != cmd->convert_src)
 381                err++;
 382
 383        tmp = cmd->scan_end_src;
 384        cmd->scan_end_src &= TRIG_COUNT;
 385        if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
 386                err++;
 387
 388        tmp = cmd->stop_src;
 389        cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
 390        if (!cmd->stop_src || tmp != cmd->stop_src)
 391                err++;
 392
 393        if (err)
 394                return 1;
 395
 396        /* step 2: make sure trigger sources are unique and mutually compatible */
 397
 398        /* note that mutual compatiblity is not an issue here */
 399        if (cmd->scan_begin_src != TRIG_TIMER &&
 400            cmd->scan_begin_src != TRIG_EXT)
 401                err++;
 402        if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
 403                err++;
 404        if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
 405                err++;
 406
 407        if (err)
 408                return 2;
 409
 410        /* step 3: make sure arguments are trivially compatible */
 411
 412        if (cmd->start_arg != 0) {
 413                cmd->start_arg = 0;
 414                err++;
 415        }
 416#define MAX_SPEED       10000   /* in nanoseconds */
 417#define MIN_SPEED       1000000000      /* in nanoseconds */
 418
 419        if (cmd->scan_begin_src == TRIG_TIMER) {
 420                if (cmd->scan_begin_arg < MAX_SPEED) {
 421                        cmd->scan_begin_arg = MAX_SPEED;
 422                        err++;
 423                }
 424                if (cmd->scan_begin_arg > MIN_SPEED) {
 425                        cmd->scan_begin_arg = MIN_SPEED;
 426                        err++;
 427                }
 428        } else {
 429                /* external trigger */
 430                /* should be level/edge, hi/lo specification here */
 431                /* should specify multiple external triggers */
 432                if (cmd->scan_begin_arg > 9) {
 433                        cmd->scan_begin_arg = 9;
 434                        err++;
 435                }
 436        }
 437        if (cmd->convert_src == TRIG_TIMER) {
 438                if (cmd->convert_arg < MAX_SPEED) {
 439                        cmd->convert_arg = MAX_SPEED;
 440                        err++;
 441                }
 442                if (cmd->convert_arg > MIN_SPEED) {
 443                        cmd->convert_arg = MIN_SPEED;
 444                        err++;
 445                }
 446        } else {
 447                /* external trigger */
 448                /* see above */
 449                if (cmd->convert_arg > 9) {
 450                        cmd->convert_arg = 9;
 451                        err++;
 452                }
 453        }
 454
 455        if (cmd->scan_end_arg != cmd->chanlist_len) {
 456                cmd->scan_end_arg = cmd->chanlist_len;
 457                err++;
 458        }
 459        if (cmd->stop_src == TRIG_COUNT) {
 460                if (cmd->stop_arg > 0x00ffffff) {
 461                        cmd->stop_arg = 0x00ffffff;
 462                        err++;
 463                }
 464        } else {
 465                /* TRIG_NONE */
 466                if (cmd->stop_arg != 0) {
 467                        cmd->stop_arg = 0;
 468                        err++;
 469                }
 470        }
 471
 472        if (err)
 473                return 3;
 474
 475        /* step 4: fix up any arguments */
 476
 477        if (cmd->scan_begin_src == TRIG_TIMER) {
 478                unsigned int div1, div2;
 479
 480                tmp = cmd->scan_begin_arg;
 481                i8253_cascade_ns_to_timer(100, &div1, &div2,
 482                                          &cmd->scan_begin_arg,
 483                                          cmd->flags & TRIG_ROUND_MASK);
 484                if (tmp != cmd->scan_begin_arg)
 485                        err++;
 486        }
 487        if (cmd->convert_src == TRIG_TIMER) {
 488                unsigned int div1, div2;
 489
 490                tmp = cmd->convert_arg;
 491                i8253_cascade_ns_to_timer(100, &div1, &div2,
 492                                          &cmd->scan_begin_arg,
 493                                          cmd->flags & TRIG_ROUND_MASK);
 494                if (tmp != cmd->convert_arg)
 495                        err++;
 496                if (cmd->scan_begin_src == TRIG_TIMER &&
 497                    cmd->scan_begin_arg <
 498                    cmd->convert_arg * cmd->scan_end_arg) {
 499                        cmd->scan_begin_arg =
 500                            cmd->convert_arg * cmd->scan_end_arg;
 501                        err++;
 502                }
 503        }
 504
 505        if (err)
 506                return 4;
 507
 508        return 0;
 509}
 510
 511static int das16cs_ao_winsn(struct comedi_device *dev,
 512                            struct comedi_subdevice *s,
 513                            struct comedi_insn *insn, unsigned int *data)
 514{
 515        int i;
 516        int chan = CR_CHAN(insn->chanspec);
 517        unsigned short status1;
 518        unsigned short d;
 519        int bit;
 520
 521        for (i = 0; i < insn->n; i++) {
 522                devpriv->ao_readback[chan] = data[i];
 523                d = data[i];
 524
 525                outw(devpriv->status1, dev->iobase + 4);
 526                udelay(1);
 527
 528                status1 = devpriv->status1 & ~0xf;
 529                if (chan)
 530                        status1 |= 0x0001;
 531                else
 532                        status1 |= 0x0008;
 533
 534/*              printk("0x%04x\n",status1);*/
 535                outw(status1, dev->iobase + 4);
 536                udelay(1);
 537
 538                for (bit = 15; bit >= 0; bit--) {
 539                        int b = (d >> bit) & 0x1;
 540                        b <<= 1;
 541/*                      printk("0x%04x\n",status1 | b | 0x0000);*/
 542                        outw(status1 | b | 0x0000, dev->iobase + 4);
 543                        udelay(1);
 544/*                      printk("0x%04x\n",status1 | b | 0x0004);*/
 545                        outw(status1 | b | 0x0004, dev->iobase + 4);
 546                        udelay(1);
 547                }
 548/*              make high both DAC0CS and DAC1CS to load
 549                new data and update analog output*/
 550                outw(status1 | 0x9, dev->iobase + 4);
 551        }
 552
 553        return i;
 554}
 555
 556/* AO subdevices should have a read insn as well as a write insn.
 557 * Usually this means copying a value stored in devpriv. */
 558static int das16cs_ao_rinsn(struct comedi_device *dev,
 559                            struct comedi_subdevice *s,
 560                            struct comedi_insn *insn, unsigned int *data)
 561{
 562        int i;
 563        int chan = CR_CHAN(insn->chanspec);
 564
 565        for (i = 0; i < insn->n; i++)
 566                data[i] = devpriv->ao_readback[chan];
 567
 568        return i;
 569}
 570
 571/* DIO devices are slightly special.  Although it is possible to
 572 * implement the insn_read/insn_write interface, it is much more
 573 * useful to applications if you implement the insn_bits interface.
 574 * This allows packed reading/writing of the DIO channels.  The
 575 * comedi core can convert between insn_bits and insn_read/write */
 576static int das16cs_dio_insn_bits(struct comedi_device *dev,
 577                                 struct comedi_subdevice *s,
 578                                 struct comedi_insn *insn, unsigned int *data)
 579{
 580        if (insn->n != 2)
 581                return -EINVAL;
 582
 583        if (data[0]) {
 584                s->state &= ~data[0];
 585                s->state |= data[0] & data[1];
 586
 587                outw(s->state, dev->iobase + 16);
 588        }
 589
 590        /* on return, data[1] contains the value of the digital
 591         * input and output lines. */
 592        data[1] = inw(dev->iobase + 16);
 593
 594        return 2;
 595}
 596
 597static int das16cs_dio_insn_config(struct comedi_device *dev,
 598                                   struct comedi_subdevice *s,
 599                                   struct comedi_insn *insn, unsigned int *data)
 600{
 601        int chan = CR_CHAN(insn->chanspec);
 602        int bits;
 603
 604        if (chan < 4)
 605                bits = 0x0f;
 606        else
 607                bits = 0xf0;
 608
 609        switch (data[0]) {
 610        case INSN_CONFIG_DIO_OUTPUT:
 611                s->io_bits |= bits;
 612                break;
 613        case INSN_CONFIG_DIO_INPUT:
 614                s->io_bits &= bits;
 615                break;
 616        case INSN_CONFIG_DIO_QUERY:
 617                data[1] =
 618                    (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
 619                return insn->n;
 620                break;
 621        default:
 622                return -EINVAL;
 623                break;
 624        }
 625
 626        devpriv->status2 &= ~0x00c0;
 627        devpriv->status2 |= (s->io_bits & 0xf0) ? 0x0080 : 0;
 628        devpriv->status2 |= (s->io_bits & 0x0f) ? 0x0040 : 0;
 629
 630        outw(devpriv->status2, dev->iobase + 6);
 631
 632        return insn->n;
 633}
 634
 635static int das16cs_timer_insn_read(struct comedi_device *dev,
 636                                   struct comedi_subdevice *s,
 637                                   struct comedi_insn *insn, unsigned int *data)
 638{
 639        return -EINVAL;
 640}
 641
 642static int das16cs_timer_insn_config(struct comedi_device *dev,
 643                                     struct comedi_subdevice *s,
 644                                     struct comedi_insn *insn,
 645                                     unsigned int *data)
 646{
 647        return -EINVAL;
 648}
 649
 650/* PCMCIA stuff */
 651
 652/*======================================================================
 653
 654    The following pcmcia code for the pcm-das08 is adapted from the
 655    dummy_cs.c driver of the Linux PCMCIA Card Services package.
 656
 657    The initial developer of the original code is David A. Hinds
 658    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
 659    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 660
 661======================================================================*/
 662
 663/*
 664   All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
 665   you do not define PCMCIA_DEBUG at all, all the debug code will be
 666   left out.  If you compile with PCMCIA_DEBUG=0, the debug code will
 667   be present but disabled -- but it can then be enabled for specific
 668   modules at load time with a 'pc_debug=#' option to insmod.
 669*/
 670#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)
 671
 672#ifdef PCMCIA_DEBUG
 673static int pc_debug = PCMCIA_DEBUG;
 674module_param(pc_debug, int, 0644);
 675#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 676static char *version =
 677    "cb_das16_cs.c pcmcia code (David Schleef), modified from dummy_cs.c 1.31 2001/08/24 12:13:13 (David Hinds)";
 678#else
 679#define DEBUG(n, args...)
 680#endif
 681
 682/*====================================================================*/
 683
 684static void das16cs_pcmcia_config(struct pcmcia_device *link);
 685static void das16cs_pcmcia_release(struct pcmcia_device *link);
 686static int das16cs_pcmcia_suspend(struct pcmcia_device *p_dev);
 687static int das16cs_pcmcia_resume(struct pcmcia_device *p_dev);
 688
 689/*
 690   The attach() and detach() entry points are used to create and destroy
 691   "instances" of the driver, where each instance represents everything
 692   needed to manage one actual PCMCIA card.
 693*/
 694
 695static int das16cs_pcmcia_attach(struct pcmcia_device *);
 696static void das16cs_pcmcia_detach(struct pcmcia_device *);
 697
 698/*
 699   You'll also need to prototype all the functions that will actually
 700   be used to talk to your device.  See 'memory_cs' for a good example
 701   of a fully self-sufficient driver; the other drivers rely more or
 702   less on other parts of the kernel.
 703*/
 704
 705/*
 706   The dev_info variable is the "key" that is used to match up this
 707   device driver with appropriate cards, through the card configuration
 708   database.
 709*/
 710
 711static dev_info_t dev_info = "cb_das16_cs";
 712
 713struct local_info_t {
 714        struct pcmcia_device *link;
 715        dev_node_t node;
 716        int stop;
 717        struct bus_operations *bus;
 718};
 719
 720/*======================================================================
 721
 722    das16cs_pcmcia_attach() creates an "instance" of the driver, allocating
 723    local data structures for one device.  The device is registered
 724    with Card Services.
 725
 726    The dev_link structure is initialized, but we don't actually
 727    configure the card at this point -- we wait until we receive a
 728    card insertion event.
 729
 730======================================================================*/
 731
 732static int das16cs_pcmcia_attach(struct pcmcia_device *link)
 733{
 734        struct local_info_t *local;
 735
 736        DEBUG(0, "das16cs_pcmcia_attach()\n");
 737
 738        /* Allocate space for private device-specific data */
 739        local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL);
 740        if (!local)
 741                return -ENOMEM;
 742        local->link = link;
 743        link->priv = local;
 744
 745        /* Initialize the pcmcia_device structure */
 746        /* Interrupt setup */
 747        link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
 748        link->irq.IRQInfo1 = IRQ_LEVEL_ID;
 749        link->irq.Handler = NULL;
 750
 751        link->conf.Attributes = 0;
 752        link->conf.IntType = INT_MEMORY_AND_IO;
 753
 754        cur_dev = link;
 755
 756        das16cs_pcmcia_config(link);
 757
 758        return 0;
 759}                               /* das16cs_pcmcia_attach */
 760
 761static void das16cs_pcmcia_detach(struct pcmcia_device *link)
 762{
 763        DEBUG(0, "das16cs_pcmcia_detach(0x%p)\n", link);
 764
 765        if (link->dev_node) {
 766                ((struct local_info_t *)link->priv)->stop = 1;
 767                das16cs_pcmcia_release(link);
 768        }
 769        /* This points to the parent struct local_info_t struct */
 770        if (link->priv)
 771                kfree(link->priv);
 772}                               /* das16cs_pcmcia_detach */
 773
 774static void das16cs_pcmcia_config(struct pcmcia_device *link)
 775{
 776        struct local_info_t *dev = link->priv;
 777        tuple_t tuple;
 778        cisparse_t parse;
 779        int last_fn, last_ret;
 780        u_char buf[64];
 781        cistpl_cftable_entry_t dflt = { 0 };
 782
 783        DEBUG(0, "das16cs_pcmcia_config(0x%p)\n", link);
 784
 785        /*
 786           This reads the card's CONFIG tuple to find its configuration
 787           registers.
 788         */
 789        tuple.DesiredTuple = CISTPL_CONFIG;
 790        tuple.Attributes = 0;
 791        tuple.TupleData = buf;
 792        tuple.TupleDataMax = sizeof(buf);
 793        tuple.TupleOffset = 0;
 794
 795        last_fn = GetFirstTuple;
 796        last_ret = pcmcia_get_first_tuple(link, &tuple);
 797        if (last_ret != 0)
 798                goto cs_failed;
 799
 800        last_fn = GetTupleData;
 801        last_ret = pcmcia_get_tuple_data(link, &tuple);
 802        if (last_ret != 0)
 803                goto cs_failed;
 804
 805        last_fn = ParseTuple;
 806        last_ret = pcmcia_parse_tuple(&tuple, &parse);
 807        if (last_ret != 0)
 808                goto cs_failed;
 809
 810        link->conf.ConfigBase = parse.config.base;
 811        link->conf.Present = parse.config.rmask[0];
 812
 813        /*
 814           In this loop, we scan the CIS for configuration table entries,
 815           each of which describes a valid card configuration, including
 816           voltage, IO window, memory window, and interrupt settings.
 817
 818           We make no assumptions about the card to be configured: we use
 819           just the information available in the CIS.  In an ideal world,
 820           this would work for any PCMCIA card, but it requires a complete
 821           and accurate CIS.  In practice, a driver usually "knows" most of
 822           these things without consulting the CIS, and most client drivers
 823           will only use the CIS to fill in implementation-defined details.
 824         */
 825        tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
 826        last_fn = GetFirstTuple;
 827
 828        last_ret = pcmcia_get_first_tuple(link, &tuple);
 829        if (last_ret)
 830                goto cs_failed;
 831
 832        while (1) {
 833                cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
 834                if (pcmcia_get_tuple_data(link, &tuple))
 835                        goto next_entry;
 836                if (pcmcia_parse_tuple(&tuple, &parse))
 837                        goto next_entry;
 838
 839                if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
 840                        dflt = *cfg;
 841                if (cfg->index == 0)
 842                        goto next_entry;
 843                link->conf.ConfigIndex = cfg->index;
 844
 845                /* Does this card need audio output? */
 846/*      if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
 847                link->conf.Attributes |= CONF_ENABLE_SPKR;
 848                link->conf.Status = CCSR_AUDIO_ENA;
 849        }
 850*/
 851                /* Do we need to allocate an interrupt? */
 852                if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
 853                        link->conf.Attributes |= CONF_ENABLE_IRQ;
 854
 855                /* IO window settings */
 856                link->io.NumPorts1 = link->io.NumPorts2 = 0;
 857                if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
 858                        cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
 859                        link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
 860                        if (!(io->flags & CISTPL_IO_8BIT))
 861                                link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
 862                        if (!(io->flags & CISTPL_IO_16BIT))
 863                                link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
 864                        link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
 865                        link->io.BasePort1 = io->win[0].base;
 866                        link->io.NumPorts1 = io->win[0].len;
 867                        if (io->nwin > 1) {
 868                                link->io.Attributes2 = link->io.Attributes1;
 869                                link->io.BasePort2 = io->win[1].base;
 870                                link->io.NumPorts2 = io->win[1].len;
 871                        }
 872                        /* This reserves IO space but doesn't actually enable it */
 873                        if (pcmcia_request_io(link, &link->io))
 874                                goto next_entry;
 875                }
 876
 877                /* If we got this far, we're cool! */
 878                break;
 879
 880next_entry:
 881                last_fn = GetNextTuple;
 882
 883                last_ret = pcmcia_get_next_tuple(link, &tuple);
 884                if (last_ret)
 885                        goto cs_failed;
 886        }
 887
 888        /*
 889           Allocate an interrupt line.  Note that this does not assign a
 890           handler to the interrupt, unless the 'Handler' member of the
 891           irq structure is initialized.
 892         */
 893        if (link->conf.Attributes & CONF_ENABLE_IRQ) {
 894                last_fn = RequestIRQ;
 895
 896                last_ret = pcmcia_request_irq(link, &link->irq);
 897                if (last_ret)
 898                        goto cs_failed;
 899        }
 900        /*
 901           This actually configures the PCMCIA socket -- setting up
 902           the I/O windows and the interrupt mapping, and putting the
 903           card and host interface into "Memory and IO" mode.
 904         */
 905        last_fn = RequestConfiguration;
 906        last_ret = pcmcia_request_configuration(link, &link->conf);
 907        if (last_ret)
 908                goto cs_failed;
 909
 910        /*
 911           At this point, the dev_node_t structure(s) need to be
 912           initialized and arranged in a linked list at link->dev.
 913         */
 914        sprintf(dev->node.dev_name, "cb_das16_cs");
 915        dev->node.major = dev->node.minor = 0;
 916        link->dev_node = &dev->node;
 917
 918        /* Finally, report what we've done */
 919        printk(KERN_INFO "%s: index 0x%02x",
 920               dev->node.dev_name, link->conf.ConfigIndex);
 921        if (link->conf.Attributes & CONF_ENABLE_IRQ)
 922                printk(", irq %u", link->irq.AssignedIRQ);
 923        if (link->io.NumPorts1)
 924                printk(", io 0x%04x-0x%04x", link->io.BasePort1,
 925                       link->io.BasePort1 + link->io.NumPorts1 - 1);
 926        if (link->io.NumPorts2)
 927                printk(" & 0x%04x-0x%04x", link->io.BasePort2,
 928                       link->io.BasePort2 + link->io.NumPorts2 - 1);
 929        printk("\n");
 930
 931        return;
 932
 933cs_failed:
 934        cs_error(link, last_fn, last_ret);
 935        das16cs_pcmcia_release(link);
 936}                               /* das16cs_pcmcia_config */
 937
 938static void das16cs_pcmcia_release(struct pcmcia_device *link)
 939{
 940        DEBUG(0, "das16cs_pcmcia_release(0x%p)\n", link);
 941        pcmcia_disable_device(link);
 942}                               /* das16cs_pcmcia_release */
 943
 944static int das16cs_pcmcia_suspend(struct pcmcia_device *link)
 945{
 946        struct local_info_t *local = link->priv;
 947
 948        /* Mark the device as stopped, to block IO until later */
 949        local->stop = 1;
 950
 951        return 0;
 952}                               /* das16cs_pcmcia_suspend */
 953
 954static int das16cs_pcmcia_resume(struct pcmcia_device *link)
 955{
 956        struct local_info_t *local = link->priv;
 957
 958        local->stop = 0;
 959        return 0;
 960}                               /* das16cs_pcmcia_resume */
 961
 962/*====================================================================*/
 963
 964static struct pcmcia_device_id das16cs_id_table[] = {
 965        PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x0039),
 966        PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4009),
 967        PCMCIA_DEVICE_NULL
 968};
 969
 970MODULE_DEVICE_TABLE(pcmcia, das16cs_id_table);
 971
 972struct pcmcia_driver das16cs_driver = {
 973        .probe = das16cs_pcmcia_attach,
 974        .remove = das16cs_pcmcia_detach,
 975        .suspend = das16cs_pcmcia_suspend,
 976        .resume = das16cs_pcmcia_resume,
 977        .id_table = das16cs_id_table,
 978        .owner = THIS_MODULE,
 979        .drv = {
 980                .name = dev_info,
 981                },
 982};
 983
 984static int __init init_das16cs_pcmcia_cs(void)
 985{
 986        DEBUG(0, "%s\n", version);
 987        pcmcia_register_driver(&das16cs_driver);
 988        return 0;
 989}
 990
 991static void __exit exit_das16cs_pcmcia_cs(void)
 992{
 993        DEBUG(0, "das16cs_pcmcia_cs: unloading\n");
 994        pcmcia_unregister_driver(&das16cs_driver);
 995}
 996
 997int __init init_module(void)
 998{
 999        int ret;
1000
1001        ret = init_das16cs_pcmcia_cs();
1002        if (ret < 0)
1003                return ret;
1004
1005        return comedi_driver_register(&driver_das16cs);
1006}
1007
1008void __exit cleanup_module(void)
1009{
1010        exit_das16cs_pcmcia_cs();
1011        comedi_driver_unregister(&driver_das16cs);
1012}
1013
1014#else
1015COMEDI_INITCLEANUP(driver_das16cs);
1016#endif /* CONFIG_PCMCIA */
1017