linux/drivers/staging/comedi/drivers/das800.c
<<
>>
Prefs
   1/*
   2    comedi/drivers/das800.c
   3    Driver for Keitley das800 series boards and compatibles
   4    Copyright (C) 2000 Frank Mori Hess <fmhess@users.sourceforge.net>
   5
   6    COMEDI - Linux Control and Measurement Device Interface
   7    Copyright (C) 2000 David A. Schleef <ds@schleef.org>
   8
   9    This program is free software; you can redistribute it and/or modify
  10    it under the terms of the GNU General Public License as published by
  11    the Free Software Foundation; either version 2 of the License, or
  12    (at your option) any later version.
  13
  14    This program is distributed in the hope that it will be useful,
  15    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17    GNU General Public License for more details.
  18
  19    You should have received a copy of the GNU General Public License
  20    along with this program; if not, write to the Free Software
  21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22
  23************************************************************************
  24*/
  25/*
  26Driver: das800
  27Description: Keithley Metrabyte DAS800 (& compatibles)
  28Author: Frank Mori Hess <fmhess@users.sourceforge.net>
  29Devices: [Keithley Metrabyte] DAS-800 (das-800), DAS-801 (das-801),
  30  DAS-802 (das-802),
  31  [Measurement Computing] CIO-DAS800 (cio-das800),
  32  CIO-DAS801 (cio-das801), CIO-DAS802 (cio-das802),
  33  CIO-DAS802/16 (cio-das802/16)
  34Status: works, cio-das802/16 untested - email me if you have tested it
  35
  36Configuration options:
  37  [0] - I/O port base address
  38  [1] - IRQ (optional, required for timed or externally triggered conversions)
  39
  40Notes:
  41        IRQ can be omitted, although the cmd interface will not work without it.
  42
  43        All entries in the channel/gain list must use the same gain and be
  44        consecutive channels counting upwards in channel number (these are
  45        hardware limitations.)
  46
  47        I've never tested the gain setting stuff since I only have a
  48        DAS-800 board with fixed gain.
  49
  50        The cio-das802/16 does not have a fifo-empty status bit!  Therefore
  51        only fifo-half-full transfers are possible with this card.
  52*/
  53/*
  54
  55cmd triggers supported:
  56        start_src:      TRIG_NOW | TRIG_EXT
  57        scan_begin_src: TRIG_FOLLOW
  58        scan_end_src:   TRIG_COUNT
  59        convert_src:    TRIG_TIMER | TRIG_EXT
  60        stop_src:       TRIG_NONE | TRIG_COUNT
  61
  62
  63*/
  64
  65#include <linux/interrupt.h>
  66#include "../comedidev.h"
  67
  68#include <linux/ioport.h>
  69#include <linux/delay.h>
  70
  71#include "8253.h"
  72#include "comedi_fc.h"
  73
  74#define DAS800_SIZE           8
  75#define TIMER_BASE            1000
  76#define N_CHAN_AI             8 /*  number of analog input channels */
  77
  78/* Registers for the das800 */
  79
  80#define DAS800_LSB            0
  81#define   FIFO_EMPTY            0x1
  82#define   FIFO_OVF              0x2
  83#define DAS800_MSB            1
  84#define DAS800_CONTROL1       2
  85#define   CONTROL1_INTE         0x8
  86#define DAS800_CONV_CONTROL   2
  87#define   ITE                   0x1
  88#define   CASC                  0x2
  89#define   DTEN                  0x4
  90#define   IEOC                  0x8
  91#define   EACS                  0x10
  92#define   CONV_HCEN             0x80
  93#define DAS800_SCAN_LIMITS    2
  94#define DAS800_STATUS         2
  95#define   IRQ                   0x8
  96#define   BUSY                  0x80
  97#define DAS800_GAIN           3
  98#define   CIO_FFOV              0x8     /*  fifo overflow for cio-das802/16 */
  99#define   CIO_ENHF              0x90    /*  interrupt fifo half full for cio-das802/16 */
 100#define   CONTROL1              0x80
 101#define   CONV_CONTROL          0xa0
 102#define   SCAN_LIMITS           0xc0
 103#define   ID                    0xe0
 104#define DAS800_8254           4
 105#define DAS800_STATUS2        7
 106#define   STATUS2_HCEN          0x80
 107#define   STATUS2_INTE          0X20
 108#define DAS800_ID             7
 109
 110struct das800_board {
 111        const char *name;
 112        int ai_speed;
 113        const struct comedi_lrange *ai_range;
 114        int resolution;
 115};
 116
 117/* analog input ranges */
 118static const struct comedi_lrange range_das800_ai = {
 119        1,
 120        {
 121         RANGE(-5, 5),
 122         }
 123};
 124
 125static const struct comedi_lrange range_das801_ai = {
 126        9,
 127        {
 128         RANGE(-5, 5),
 129         RANGE(-10, 10),
 130         RANGE(0, 10),
 131         RANGE(-0.5, 0.5),
 132         RANGE(0, 1),
 133         RANGE(-0.05, 0.05),
 134         RANGE(0, 0.1),
 135         RANGE(-0.01, 0.01),
 136         RANGE(0, 0.02),
 137         }
 138};
 139
 140static const struct comedi_lrange range_cio_das801_ai = {
 141        9,
 142        {
 143         RANGE(-5, 5),
 144         RANGE(-10, 10),
 145         RANGE(0, 10),
 146         RANGE(-0.5, 0.5),
 147         RANGE(0, 1),
 148         RANGE(-0.05, 0.05),
 149         RANGE(0, 0.1),
 150         RANGE(-0.005, 0.005),
 151         RANGE(0, 0.01),
 152         }
 153};
 154
 155static const struct comedi_lrange range_das802_ai = {
 156        9,
 157        {
 158         RANGE(-5, 5),
 159         RANGE(-10, 10),
 160         RANGE(0, 10),
 161         RANGE(-2.5, 2.5),
 162         RANGE(0, 5),
 163         RANGE(-1.25, 1.25),
 164         RANGE(0, 2.5),
 165         RANGE(-0.625, 0.625),
 166         RANGE(0, 1.25),
 167         }
 168};
 169
 170static const struct comedi_lrange range_das80216_ai = {
 171        8,
 172        {
 173         RANGE(-10, 10),
 174         RANGE(0, 10),
 175         RANGE(-5, 5),
 176         RANGE(0, 5),
 177         RANGE(-2.5, 2.5),
 178         RANGE(0, 2.5),
 179         RANGE(-1.25, 1.25),
 180         RANGE(0, 1.25),
 181         }
 182};
 183
 184enum { das800, ciodas800, das801, ciodas801, das802, ciodas802, ciodas80216 };
 185
 186static const struct das800_board das800_boards[] = {
 187        {
 188         .name = "das-800",
 189         .ai_speed = 25000,
 190         .ai_range = &range_das800_ai,
 191         .resolution = 12,
 192         },
 193        {
 194         .name = "cio-das800",
 195         .ai_speed = 20000,
 196         .ai_range = &range_das800_ai,
 197         .resolution = 12,
 198         },
 199        {
 200         .name = "das-801",
 201         .ai_speed = 25000,
 202         .ai_range = &range_das801_ai,
 203         .resolution = 12,
 204         },
 205        {
 206         .name = "cio-das801",
 207         .ai_speed = 20000,
 208         .ai_range = &range_cio_das801_ai,
 209         .resolution = 12,
 210         },
 211        {
 212         .name = "das-802",
 213         .ai_speed = 25000,
 214         .ai_range = &range_das802_ai,
 215         .resolution = 12,
 216         },
 217        {
 218         .name = "cio-das802",
 219         .ai_speed = 20000,
 220         .ai_range = &range_das802_ai,
 221         .resolution = 12,
 222         },
 223        {
 224         .name = "cio-das802/16",
 225         .ai_speed = 10000,
 226         .ai_range = &range_das80216_ai,
 227         .resolution = 16,
 228         },
 229};
 230
 231/*
 232 * Useful for shorthand access to the particular board structure
 233 */
 234#define thisboard ((const struct das800_board *)dev->board_ptr)
 235
 236struct das800_private {
 237        volatile unsigned int count;    /* number of data points left to be taken */
 238        volatile int forever;   /* flag indicating whether we should take data forever */
 239        unsigned int divisor1;  /* value to load into board's counter 1 for timed conversions */
 240        unsigned int divisor2;  /* value to load into board's counter 2 for timed conversions */
 241        volatile int do_bits;   /* digital output bits */
 242};
 243
 244#define devpriv ((struct das800_private *)dev->private)
 245
 246static int das800_attach(struct comedi_device *dev,
 247                         struct comedi_devconfig *it);
 248static int das800_detach(struct comedi_device *dev);
 249static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
 250
 251static struct comedi_driver driver_das800 = {
 252        .driver_name = "das800",
 253        .module = THIS_MODULE,
 254        .attach = das800_attach,
 255        .detach = das800_detach,
 256        .num_names = ARRAY_SIZE(das800_boards),
 257        .board_name = &das800_boards[0].name,
 258        .offset = sizeof(struct das800_board),
 259};
 260
 261static irqreturn_t das800_interrupt(int irq, void *d);
 262static void enable_das800(struct comedi_device *dev);
 263static void disable_das800(struct comedi_device *dev);
 264static int das800_ai_do_cmdtest(struct comedi_device *dev,
 265                                struct comedi_subdevice *s,
 266                                struct comedi_cmd *cmd);
 267static int das800_ai_do_cmd(struct comedi_device *dev,
 268                            struct comedi_subdevice *s);
 269static int das800_ai_rinsn(struct comedi_device *dev,
 270                           struct comedi_subdevice *s, struct comedi_insn *insn,
 271                           unsigned int *data);
 272static int das800_di_rbits(struct comedi_device *dev,
 273                           struct comedi_subdevice *s, struct comedi_insn *insn,
 274                           unsigned int *data);
 275static int das800_do_wbits(struct comedi_device *dev,
 276                           struct comedi_subdevice *s, struct comedi_insn *insn,
 277                           unsigned int *data);
 278static int das800_probe(struct comedi_device *dev);
 279static int das800_set_frequency(struct comedi_device *dev);
 280
 281/* checks and probes das-800 series board type */
 282static int das800_probe(struct comedi_device *dev)
 283{
 284        int id_bits;
 285        unsigned long irq_flags;
 286        int board;
 287
 288        /*  'comedi spin lock irqsave' disables even rt interrupts, we use them to protect indirect addressing */
 289        spin_lock_irqsave(&dev->spinlock, irq_flags);
 290        outb(ID, dev->iobase + DAS800_GAIN);    /* select base address + 7 to be ID register */
 291        id_bits = inb(dev->iobase + DAS800_ID) & 0x3;   /* get id bits */
 292        spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 293
 294        board = thisboard - das800_boards;
 295
 296        switch (id_bits) {
 297        case 0x0:
 298                if (board == das800) {
 299                        printk(" Board model: DAS-800\n");
 300                        return board;
 301                }
 302                if (board == ciodas800) {
 303                        printk(" Board model: CIO-DAS800\n");
 304                        return board;
 305                }
 306                printk(" Board model (probed): DAS-800\n");
 307                return das800;
 308                break;
 309        case 0x2:
 310                if (board == das801) {
 311                        printk(" Board model: DAS-801\n");
 312                        return board;
 313                }
 314                if (board == ciodas801) {
 315                        printk(" Board model: CIO-DAS801\n");
 316                        return board;
 317                }
 318                printk(" Board model (probed): DAS-801\n");
 319                return das801;
 320                break;
 321        case 0x3:
 322                if (board == das802) {
 323                        printk(" Board model: DAS-802\n");
 324                        return board;
 325                }
 326                if (board == ciodas802) {
 327                        printk(" Board model: CIO-DAS802\n");
 328                        return board;
 329                }
 330                if (board == ciodas80216) {
 331                        printk(" Board model: CIO-DAS802/16\n");
 332                        return board;
 333                }
 334                printk(" Board model (probed): DAS-802\n");
 335                return das802;
 336                break;
 337        default:
 338                printk(" Board model: probe returned 0x%x (unknown)\n",
 339                       id_bits);
 340                return board;
 341                break;
 342        }
 343        return -1;
 344}
 345
 346/*
 347 * A convenient macro that defines init_module() and cleanup_module(),
 348 * as necessary.
 349 */
 350COMEDI_INITCLEANUP(driver_das800);
 351
 352/* interrupt service routine */
 353static irqreturn_t das800_interrupt(int irq, void *d)
 354{
 355        short i;                /* loop index */
 356        short dataPoint = 0;
 357        struct comedi_device *dev = d;
 358        struct comedi_subdevice *s = dev->read_subdev;  /* analog input subdevice */
 359        struct comedi_async *async;
 360        int status;
 361        unsigned long irq_flags;
 362        static const int max_loops = 128;       /*  half-fifo size for cio-das802/16 */
 363        /*  flags */
 364        int fifo_empty = 0;
 365        int fifo_overflow = 0;
 366
 367        status = inb(dev->iobase + DAS800_STATUS);
 368        /* if interrupt was not generated by board or driver not attached, quit */
 369        if (!(status & IRQ))
 370                return IRQ_NONE;
 371        if (!(dev->attached))
 372                return IRQ_HANDLED;
 373
 374        /* wait until here to initialize async, since we will get null dereference
 375         * if interrupt occurs before driver is fully attached!
 376         */
 377        async = s->async;
 378
 379        /*  if hardware conversions are not enabled, then quit */
 380        spin_lock_irqsave(&dev->spinlock, irq_flags);
 381        outb(CONTROL1, dev->iobase + DAS800_GAIN);      /* select base address + 7 to be STATUS2 register */
 382        status = inb(dev->iobase + DAS800_STATUS2) & STATUS2_HCEN;
 383        /* don't release spinlock yet since we want to make sure noone else disables hardware conversions */
 384        if (status == 0) {
 385                spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 386                return IRQ_HANDLED;
 387        }
 388
 389        /* loop while card's fifo is not empty (and limit to half fifo for cio-das802/16) */
 390        for (i = 0; i < max_loops; i++) {
 391                /* read 16 bits from dev->iobase and dev->iobase + 1 */
 392                dataPoint = inb(dev->iobase + DAS800_LSB);
 393                dataPoint += inb(dev->iobase + DAS800_MSB) << 8;
 394                if (thisboard->resolution == 12) {
 395                        fifo_empty = dataPoint & FIFO_EMPTY;
 396                        fifo_overflow = dataPoint & FIFO_OVF;
 397                        if (fifo_overflow)
 398                                break;
 399                } else {
 400                        fifo_empty = 0; /*  cio-das802/16 has no fifo empty status bit */
 401                }
 402                if (fifo_empty) {
 403                        break;
 404                }
 405                /* strip off extraneous bits for 12 bit cards */
 406                if (thisboard->resolution == 12)
 407                        dataPoint = (dataPoint >> 4) & 0xfff;
 408                /* if there are more data points to collect */
 409                if (devpriv->count > 0 || devpriv->forever == 1) {
 410                        /* write data point to buffer */
 411                        cfc_write_to_buffer(s, dataPoint);
 412                        if (devpriv->count > 0)
 413                                devpriv->count--;
 414                }
 415        }
 416        async->events |= COMEDI_CB_BLOCK;
 417        /* check for fifo overflow */
 418        if (thisboard->resolution == 12) {
 419                fifo_overflow = dataPoint & FIFO_OVF;
 420                /*  else cio-das802/16 */
 421        } else {
 422                fifo_overflow = inb(dev->iobase + DAS800_GAIN) & CIO_FFOV;
 423        }
 424        if (fifo_overflow) {
 425                spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 426                comedi_error(dev, "DAS800 FIFO overflow");
 427                das800_cancel(dev, dev->subdevices + 0);
 428                async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
 429                comedi_event(dev, s);
 430                async->events = 0;
 431                return IRQ_HANDLED;
 432        }
 433        if (devpriv->count > 0 || devpriv->forever == 1) {
 434                /* Re-enable card's interrupt.
 435                 * We already have spinlock, so indirect addressing is safe */
 436                outb(CONTROL1, dev->iobase + DAS800_GAIN);      /* select dev->iobase + 2 to be control register 1 */
 437                outb(CONTROL1_INTE | devpriv->do_bits,
 438                     dev->iobase + DAS800_CONTROL1);
 439                spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 440                /* otherwise, stop taking data */
 441        } else {
 442                spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 443                disable_das800(dev);    /* diable hardware triggered conversions */
 444                async->events |= COMEDI_CB_EOA;
 445        }
 446        comedi_event(dev, s);
 447        async->events = 0;
 448        return IRQ_HANDLED;
 449}
 450
 451static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 452{
 453        struct comedi_subdevice *s;
 454        unsigned long iobase = it->options[0];
 455        unsigned int irq = it->options[1];
 456        unsigned long irq_flags;
 457        int board;
 458
 459        printk("comedi%d: das800: io 0x%lx", dev->minor, iobase);
 460        if (irq) {
 461                printk(", irq %u", irq);
 462        }
 463        printk("\n");
 464
 465        /* allocate and initialize dev->private */
 466        if (alloc_private(dev, sizeof(struct das800_private)) < 0)
 467                return -ENOMEM;
 468
 469        if (iobase == 0) {
 470                printk("io base address required for das800\n");
 471                return -EINVAL;
 472        }
 473
 474        /* check if io addresses are available */
 475        if (!request_region(iobase, DAS800_SIZE, "das800")) {
 476                printk("I/O port conflict\n");
 477                return -EIO;
 478        }
 479        dev->iobase = iobase;
 480
 481        board = das800_probe(dev);
 482        if (board < 0) {
 483                printk("unable to determine board type\n");
 484                return -ENODEV;
 485        }
 486        dev->board_ptr = das800_boards + board;
 487
 488        /* grab our IRQ */
 489        if (irq == 1 || irq > 7) {
 490                printk("irq out of range\n");
 491                return -EINVAL;
 492        }
 493        if (irq) {
 494                if (request_irq(irq, das800_interrupt, 0, "das800", dev)) {
 495                        printk("unable to allocate irq %u\n", irq);
 496                        return -EINVAL;
 497                }
 498        }
 499        dev->irq = irq;
 500
 501        dev->board_name = thisboard->name;
 502
 503        if (alloc_subdevices(dev, 3) < 0)
 504                return -ENOMEM;
 505
 506        /* analog input subdevice */
 507        s = dev->subdevices + 0;
 508        dev->read_subdev = s;
 509        s->type = COMEDI_SUBD_AI;
 510        s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
 511        s->n_chan = 8;
 512        s->len_chanlist = 8;
 513        s->maxdata = (1 << thisboard->resolution) - 1;
 514        s->range_table = thisboard->ai_range;
 515        s->do_cmd = das800_ai_do_cmd;
 516        s->do_cmdtest = das800_ai_do_cmdtest;
 517        s->insn_read = das800_ai_rinsn;
 518        s->cancel = das800_cancel;
 519
 520        /* di */
 521        s = dev->subdevices + 1;
 522        s->type = COMEDI_SUBD_DI;
 523        s->subdev_flags = SDF_READABLE;
 524        s->n_chan = 3;
 525        s->maxdata = 1;
 526        s->range_table = &range_digital;
 527        s->insn_bits = das800_di_rbits;
 528
 529        /* do */
 530        s = dev->subdevices + 2;
 531        s->type = COMEDI_SUBD_DO;
 532        s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
 533        s->n_chan = 4;
 534        s->maxdata = 1;
 535        s->range_table = &range_digital;
 536        s->insn_bits = das800_do_wbits;
 537
 538        disable_das800(dev);
 539
 540        /* initialize digital out channels */
 541        spin_lock_irqsave(&dev->spinlock, irq_flags);
 542        outb(CONTROL1, dev->iobase + DAS800_GAIN);      /* select dev->iobase + 2 to be control register 1 */
 543        outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1);
 544        spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 545
 546        return 0;
 547};
 548
 549static int das800_detach(struct comedi_device *dev)
 550{
 551        printk("comedi%d: das800: remove\n", dev->minor);
 552
 553        /* only free stuff if it has been allocated by _attach */
 554        if (dev->iobase)
 555                release_region(dev->iobase, DAS800_SIZE);
 556        if (dev->irq)
 557                free_irq(dev->irq, dev);
 558        return 0;
 559};
 560
 561static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
 562{
 563        devpriv->forever = 0;
 564        devpriv->count = 0;
 565        disable_das800(dev);
 566        return 0;
 567}
 568
 569/* enable_das800 makes the card start taking hardware triggered conversions */
 570static void enable_das800(struct comedi_device *dev)
 571{
 572        unsigned long irq_flags;
 573        spin_lock_irqsave(&dev->spinlock, irq_flags);
 574        /*  enable fifo-half full interrupts for cio-das802/16 */
 575        if (thisboard->resolution == 16)
 576                outb(CIO_ENHF, dev->iobase + DAS800_GAIN);
 577        outb(CONV_CONTROL, dev->iobase + DAS800_GAIN);  /* select dev->iobase + 2 to be conversion control register */
 578        outb(CONV_HCEN, dev->iobase + DAS800_CONV_CONTROL);     /* enable hardware triggering */
 579        outb(CONTROL1, dev->iobase + DAS800_GAIN);      /* select dev->iobase + 2 to be control register 1 */
 580        outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1);  /* enable card's interrupt */
 581        spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 582}
 583
 584/* disable_das800 stops hardware triggered conversions */
 585static void disable_das800(struct comedi_device *dev)
 586{
 587        unsigned long irq_flags;
 588        spin_lock_irqsave(&dev->spinlock, irq_flags);
 589        outb(CONV_CONTROL, dev->iobase + DAS800_GAIN);  /* select dev->iobase + 2 to be conversion control register */
 590        outb(0x0, dev->iobase + DAS800_CONV_CONTROL);   /* disable hardware triggering of conversions */
 591        spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 592}
 593
 594static int das800_ai_do_cmdtest(struct comedi_device *dev,
 595                                struct comedi_subdevice *s,
 596                                struct comedi_cmd *cmd)
 597{
 598        int err = 0;
 599        int tmp;
 600        int gain, startChan;
 601        int i;
 602
 603        /* step 1: make sure trigger sources are trivially valid */
 604
 605        tmp = cmd->start_src;
 606        cmd->start_src &= TRIG_NOW | TRIG_EXT;
 607        if (!cmd->start_src || tmp != cmd->start_src)
 608                err++;
 609
 610        tmp = cmd->scan_begin_src;
 611        cmd->scan_begin_src &= TRIG_FOLLOW;
 612        if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
 613                err++;
 614
 615        tmp = cmd->convert_src;
 616        cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
 617        if (!cmd->convert_src || tmp != cmd->convert_src)
 618                err++;
 619
 620        tmp = cmd->scan_end_src;
 621        cmd->scan_end_src &= TRIG_COUNT;
 622        if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
 623                err++;
 624
 625        tmp = cmd->stop_src;
 626        cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
 627        if (!cmd->stop_src || tmp != cmd->stop_src)
 628                err++;
 629
 630        if (err)
 631                return 1;
 632
 633        /* step 2: make sure trigger sources are unique and mutually compatible */
 634
 635        if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT)
 636                err++;
 637        if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
 638                err++;
 639        if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
 640                err++;
 641
 642        if (err)
 643                return 2;
 644
 645        /* step 3: make sure arguments are trivially compatible */
 646
 647        if (cmd->start_arg != 0) {
 648                cmd->start_arg = 0;
 649                err++;
 650        }
 651        if (cmd->convert_src == TRIG_TIMER) {
 652                if (cmd->convert_arg < thisboard->ai_speed) {
 653                        cmd->convert_arg = thisboard->ai_speed;
 654                        err++;
 655                }
 656        }
 657        if (!cmd->chanlist_len) {
 658                cmd->chanlist_len = 1;
 659                err++;
 660        }
 661        if (cmd->scan_end_arg != cmd->chanlist_len) {
 662                cmd->scan_end_arg = cmd->chanlist_len;
 663                err++;
 664        }
 665        if (cmd->stop_src == TRIG_COUNT) {
 666                if (!cmd->stop_arg) {
 667                        cmd->stop_arg = 1;
 668                        err++;
 669                }
 670        } else {                /* TRIG_NONE */
 671                if (cmd->stop_arg != 0) {
 672                        cmd->stop_arg = 0;
 673                        err++;
 674                }
 675        }
 676
 677        if (err)
 678                return 3;
 679
 680        /* step 4: fix up any arguments */
 681
 682        if (cmd->convert_src == TRIG_TIMER) {
 683                tmp = cmd->convert_arg;
 684                /* calculate counter values that give desired timing */
 685                i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1),
 686                                               &(devpriv->divisor2),
 687                                               &(cmd->convert_arg),
 688                                               cmd->flags & TRIG_ROUND_MASK);
 689                if (tmp != cmd->convert_arg)
 690                        err++;
 691        }
 692
 693        if (err)
 694                return 4;
 695
 696        /*  check channel/gain list against card's limitations */
 697        if (cmd->chanlist) {
 698                gain = CR_RANGE(cmd->chanlist[0]);
 699                startChan = CR_CHAN(cmd->chanlist[0]);
 700                for (i = 1; i < cmd->chanlist_len; i++) {
 701                        if (CR_CHAN(cmd->chanlist[i]) !=
 702                            (startChan + i) % N_CHAN_AI) {
 703                                comedi_error(dev,
 704                                             "entries in chanlist must be consecutive channels, counting upwards\n");
 705                                err++;
 706                        }
 707                        if (CR_RANGE(cmd->chanlist[i]) != gain) {
 708                                comedi_error(dev,
 709                                             "entries in chanlist must all have the same gain\n");
 710                                err++;
 711                        }
 712                }
 713        }
 714
 715        if (err)
 716                return 5;
 717
 718        return 0;
 719}
 720
 721static int das800_ai_do_cmd(struct comedi_device *dev,
 722                            struct comedi_subdevice *s)
 723{
 724        int startChan, endChan, scan, gain;
 725        int conv_bits;
 726        unsigned long irq_flags;
 727        struct comedi_async *async = s->async;
 728
 729        if (!dev->irq) {
 730                comedi_error(dev,
 731                             "no irq assigned for das-800, cannot do hardware conversions");
 732                return -1;
 733        }
 734
 735        disable_das800(dev);
 736
 737        /* set channel scan limits */
 738        startChan = CR_CHAN(async->cmd.chanlist[0]);
 739        endChan = (startChan + async->cmd.chanlist_len - 1) % 8;
 740        scan = (endChan << 3) | startChan;
 741
 742        spin_lock_irqsave(&dev->spinlock, irq_flags);
 743        outb(SCAN_LIMITS, dev->iobase + DAS800_GAIN);   /* select base address + 2 to be scan limits register */
 744        outb(scan, dev->iobase + DAS800_SCAN_LIMITS);   /* set scan limits */
 745        spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 746
 747        /* set gain */
 748        gain = CR_RANGE(async->cmd.chanlist[0]);
 749        if (thisboard->resolution == 12 && gain > 0)
 750                gain += 0x7;
 751        gain &= 0xf;
 752        outb(gain, dev->iobase + DAS800_GAIN);
 753
 754        switch (async->cmd.stop_src) {
 755        case TRIG_COUNT:
 756                devpriv->count = async->cmd.stop_arg * async->cmd.chanlist_len;
 757                devpriv->forever = 0;
 758                break;
 759        case TRIG_NONE:
 760                devpriv->forever = 1;
 761                devpriv->count = 0;
 762                break;
 763        default:
 764                break;
 765        }
 766
 767        /* enable auto channel scan, send interrupts on end of conversion
 768         * and set clock source to internal or external
 769         */
 770        conv_bits = 0;
 771        conv_bits |= EACS | IEOC;
 772        if (async->cmd.start_src == TRIG_EXT)
 773                conv_bits |= DTEN;
 774        switch (async->cmd.convert_src) {
 775        case TRIG_TIMER:
 776                conv_bits |= CASC | ITE;
 777                /* set conversion frequency */
 778                i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1),
 779                                               &(devpriv->divisor2),
 780                                               &(async->cmd.convert_arg),
 781                                               async->cmd.
 782                                               flags & TRIG_ROUND_MASK);
 783                if (das800_set_frequency(dev) < 0) {
 784                        comedi_error(dev, "Error setting up counters");
 785                        return -1;
 786                }
 787                break;
 788        case TRIG_EXT:
 789                break;
 790        default:
 791                break;
 792        }
 793
 794        spin_lock_irqsave(&dev->spinlock, irq_flags);
 795        outb(CONV_CONTROL, dev->iobase + DAS800_GAIN);  /* select dev->iobase + 2 to be conversion control register */
 796        outb(conv_bits, dev->iobase + DAS800_CONV_CONTROL);
 797        spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 798        async->events = 0;
 799        enable_das800(dev);
 800        return 0;
 801}
 802
 803static int das800_ai_rinsn(struct comedi_device *dev,
 804                           struct comedi_subdevice *s, struct comedi_insn *insn,
 805                           unsigned int *data)
 806{
 807        int i, n;
 808        int chan;
 809        int range;
 810        int lsb, msb;
 811        int timeout = 1000;
 812        unsigned long irq_flags;
 813
 814        disable_das800(dev);    /* disable hardware conversions (enables software conversions) */
 815
 816        /* set multiplexer */
 817        chan = CR_CHAN(insn->chanspec);
 818
 819        spin_lock_irqsave(&dev->spinlock, irq_flags);
 820        outb(CONTROL1, dev->iobase + DAS800_GAIN);      /* select dev->iobase + 2 to be control register 1 */
 821        outb(chan | devpriv->do_bits, dev->iobase + DAS800_CONTROL1);
 822        spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 823
 824        /* set gain / range */
 825        range = CR_RANGE(insn->chanspec);
 826        if (thisboard->resolution == 12 && range)
 827                range += 0x7;
 828        range &= 0xf;
 829        outb(range, dev->iobase + DAS800_GAIN);
 830
 831        udelay(5);
 832
 833        for (n = 0; n < insn->n; n++) {
 834                /* trigger conversion */
 835                outb_p(0, dev->iobase + DAS800_MSB);
 836
 837                for (i = 0; i < timeout; i++) {
 838                        if (!(inb(dev->iobase + DAS800_STATUS) & BUSY))
 839                                break;
 840                }
 841                if (i == timeout) {
 842                        comedi_error(dev, "timeout");
 843                        return -ETIME;
 844                }
 845                lsb = inb(dev->iobase + DAS800_LSB);
 846                msb = inb(dev->iobase + DAS800_MSB);
 847                if (thisboard->resolution == 12) {
 848                        data[n] = (lsb >> 4) & 0xff;
 849                        data[n] |= (msb << 4);
 850                } else {
 851                        data[n] = (msb << 8) | lsb;
 852                }
 853        }
 854
 855        return n;
 856}
 857
 858static int das800_di_rbits(struct comedi_device *dev,
 859                           struct comedi_subdevice *s, struct comedi_insn *insn,
 860                           unsigned int *data)
 861{
 862        unsigned int bits;
 863
 864        bits = inb(dev->iobase + DAS800_STATUS) >> 4;
 865        bits &= 0x7;
 866        data[1] = bits;
 867        data[0] = 0;
 868
 869        return 2;
 870}
 871
 872static int das800_do_wbits(struct comedi_device *dev,
 873                           struct comedi_subdevice *s, struct comedi_insn *insn,
 874                           unsigned int *data)
 875{
 876        int wbits;
 877        unsigned long irq_flags;
 878
 879        /*  only set bits that have been masked */
 880        data[0] &= 0xf;
 881        wbits = devpriv->do_bits >> 4;
 882        wbits &= ~data[0];
 883        wbits |= data[0] & data[1];
 884        devpriv->do_bits = wbits << 4;
 885
 886        spin_lock_irqsave(&dev->spinlock, irq_flags);
 887        outb(CONTROL1, dev->iobase + DAS800_GAIN);      /* select dev->iobase + 2 to be control register 1 */
 888        outb(devpriv->do_bits | CONTROL1_INTE, dev->iobase + DAS800_CONTROL1);
 889        spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 890
 891        data[1] = wbits;
 892
 893        return 2;
 894}
 895
 896/* loads counters with divisor1, divisor2 from private structure */
 897static int das800_set_frequency(struct comedi_device *dev)
 898{
 899        int err = 0;
 900
 901        if (i8254_load(dev->iobase + DAS800_8254, 0, 1, devpriv->divisor1, 2))
 902                err++;
 903        if (i8254_load(dev->iobase + DAS800_8254, 0, 2, devpriv->divisor2, 2))
 904                err++;
 905        if (err)
 906                return -1;
 907
 908        return 0;
 909}
 910