linux/drivers/staging/comedi/drivers/das16.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * das16.c
   4 * DAS16 driver
   5 *
   6 * COMEDI - Linux Control and Measurement Device Interface
   7 * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
   8 * Copyright (C) 2000 Chris R. Baugher <baugher@enteract.com>
   9 * Copyright (C) 2001,2002 Frank Mori Hess <fmhess@users.sourceforge.net>
  10 */
  11
  12/*
  13 * Driver: das16
  14 * Description: DAS16 compatible boards
  15 * Author: Sam Moore, Warren Jasper, ds, Chris Baugher, Frank Hess, Roman Fietze
  16 * Devices: [Keithley Metrabyte] DAS-16 (das-16), DAS-16G (das-16g),
  17 *   DAS-16F (das-16f), DAS-1201 (das-1201), DAS-1202 (das-1202),
  18 *   DAS-1401 (das-1401), DAS-1402 (das-1402), DAS-1601 (das-1601),
  19 *   DAS-1602 (das-1602),
  20 *   [ComputerBoards] PC104-DAS16/JR (pc104-das16jr),
  21 *   PC104-DAS16JR/16 (pc104-das16jr/16), CIO-DAS16 (cio-das16),
  22 *   CIO-DAS16F (cio-das16/f), CIO-DAS16/JR (cio-das16/jr),
  23 *   CIO-DAS16JR/16 (cio-das16jr/16), CIO-DAS1401/12 (cio-das1401/12),
  24 *   CIO-DAS1402/12 (cio-das1402/12), CIO-DAS1402/16 (cio-das1402/16),
  25 *   CIO-DAS1601/12 (cio-das1601/12), CIO-DAS1602/12 (cio-das1602/12),
  26 *   CIO-DAS1602/16 (cio-das1602/16), CIO-DAS16/330 (cio-das16/330)
  27 * Status: works
  28 * Updated: 2003-10-12
  29 *
  30 * A rewrite of the das16 and das1600 drivers.
  31 *
  32 * Options:
  33 *      [0] - base io address
  34 *      [1] - irq (does nothing, irq is not used anymore)
  35 *      [2] - dma channel (optional, required for comedi_command support)
  36 *      [3] - master clock speed in MHz (optional, 1 or 10, ignored if
  37 *              board can probe clock, defaults to 1)
  38 *      [4] - analog input range lowest voltage in microvolts (optional,
  39 *              only useful if your board does not have software
  40 *              programmable gain)
  41 *      [5] - analog input range highest voltage in microvolts (optional,
  42 *              only useful if board does not have software programmable
  43 *              gain)
  44 *      [6] - analog output range lowest voltage in microvolts (optional)
  45 *      [7] - analog output range highest voltage in microvolts (optional)
  46 *
  47 * Passing a zero for an option is the same as leaving it unspecified.
  48 */
  49
  50/*
  51 * Testing and debugging help provided by Daniel Koch.
  52 *
  53 * Keithley Manuals:
  54 *      2309.PDF (das16)
  55 *      4919.PDF (das1400, 1600)
  56 *      4922.PDF (das-1400)
  57 *      4923.PDF (das1200, 1400, 1600)
  58 *
  59 * Computer boards manuals also available from their website
  60 * www.measurementcomputing.com
  61 */
  62
  63#include <linux/module.h>
  64#include <linux/slab.h>
  65#include <linux/interrupt.h>
  66
  67#include "../comedidev.h"
  68
  69#include "comedi_isadma.h"
  70#include "comedi_8254.h"
  71#include "8255.h"
  72
  73#define DAS16_DMA_SIZE 0xff00   /*  size in bytes of allocated dma buffer */
  74
  75/*
  76 * Register I/O map
  77 */
  78#define DAS16_TRIG_REG                  0x00
  79#define DAS16_AI_LSB_REG                0x00
  80#define DAS16_AI_MSB_REG                0x01
  81#define DAS16_MUX_REG                   0x02
  82#define DAS16_DIO_REG                   0x03
  83#define DAS16_AO_LSB_REG(x)             ((x) ? 0x06 : 0x04)
  84#define DAS16_AO_MSB_REG(x)             ((x) ? 0x07 : 0x05)
  85#define DAS16_STATUS_REG                0x08
  86#define DAS16_STATUS_BUSY               BIT(7)
  87#define DAS16_STATUS_UNIPOLAR           BIT(6)
  88#define DAS16_STATUS_MUXBIT             BIT(5)
  89#define DAS16_STATUS_INT                BIT(4)
  90#define DAS16_CTRL_REG                  0x09
  91#define DAS16_CTRL_INTE                 BIT(7)
  92#define DAS16_CTRL_IRQ(x)               (((x) & 0x7) << 4)
  93#define DAS16_CTRL_DMAE                 BIT(2)
  94#define DAS16_CTRL_PACING_MASK          (3 << 0)
  95#define DAS16_CTRL_INT_PACER            (3 << 0)
  96#define DAS16_CTRL_EXT_PACER            (2 << 0)
  97#define DAS16_CTRL_SOFT_PACER           (0 << 0)
  98#define DAS16_PACER_REG                 0x0a
  99#define DAS16_PACER_BURST_LEN(x)        (((x) & 0xf) << 4)
 100#define DAS16_PACER_CTR0                BIT(1)
 101#define DAS16_PACER_TRIG0               BIT(0)
 102#define DAS16_GAIN_REG                  0x0b
 103#define DAS16_TIMER_BASE_REG            0x0c    /* to 0x0f */
 104
 105#define DAS1600_CONV_REG                0x404
 106#define DAS1600_CONV_DISABLE            BIT(6)
 107#define DAS1600_BURST_REG               0x405
 108#define DAS1600_BURST_VAL               BIT(6)
 109#define DAS1600_ENABLE_REG              0x406
 110#define DAS1600_ENABLE_VAL              BIT(6)
 111#define DAS1600_STATUS_REG              0x407
 112#define DAS1600_STATUS_BME              BIT(6)
 113#define DAS1600_STATUS_ME               BIT(5)
 114#define DAS1600_STATUS_CD               BIT(4)
 115#define DAS1600_STATUS_WS               BIT(1)
 116#define DAS1600_STATUS_CLK_10MHZ        BIT(0)
 117
 118static const struct comedi_lrange range_das1x01_bip = {
 119        4, {
 120                BIP_RANGE(10),
 121                BIP_RANGE(1),
 122                BIP_RANGE(0.1),
 123                BIP_RANGE(0.01)
 124        }
 125};
 126
 127static const struct comedi_lrange range_das1x01_unip = {
 128        4, {
 129                UNI_RANGE(10),
 130                UNI_RANGE(1),
 131                UNI_RANGE(0.1),
 132                UNI_RANGE(0.01)
 133        }
 134};
 135
 136static const struct comedi_lrange range_das1x02_bip = {
 137        4, {
 138                BIP_RANGE(10),
 139                BIP_RANGE(5),
 140                BIP_RANGE(2.5),
 141                BIP_RANGE(1.25)
 142        }
 143};
 144
 145static const struct comedi_lrange range_das1x02_unip = {
 146        4, {
 147                UNI_RANGE(10),
 148                UNI_RANGE(5),
 149                UNI_RANGE(2.5),
 150                UNI_RANGE(1.25)
 151        }
 152};
 153
 154static const struct comedi_lrange range_das16jr = {
 155        9, {
 156                BIP_RANGE(10),
 157                BIP_RANGE(5),
 158                BIP_RANGE(2.5),
 159                BIP_RANGE(1.25),
 160                BIP_RANGE(0.625),
 161                UNI_RANGE(10),
 162                UNI_RANGE(5),
 163                UNI_RANGE(2.5),
 164                UNI_RANGE(1.25)
 165        }
 166};
 167
 168static const struct comedi_lrange range_das16jr_16 = {
 169        8, {
 170                BIP_RANGE(10),
 171                BIP_RANGE(5),
 172                BIP_RANGE(2.5),
 173                BIP_RANGE(1.25),
 174                UNI_RANGE(10),
 175                UNI_RANGE(5),
 176                UNI_RANGE(2.5),
 177                UNI_RANGE(1.25)
 178        }
 179};
 180
 181static const int das16jr_gainlist[] = { 8, 0, 1, 2, 3, 4, 5, 6, 7 };
 182static const int das16jr_16_gainlist[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
 183static const int das1600_gainlist[] = { 0, 1, 2, 3 };
 184
 185enum {
 186        das16_pg_none = 0,
 187        das16_pg_16jr,
 188        das16_pg_16jr_16,
 189        das16_pg_1601,
 190        das16_pg_1602,
 191};
 192
 193static const int *const das16_gainlists[] = {
 194        NULL,
 195        das16jr_gainlist,
 196        das16jr_16_gainlist,
 197        das1600_gainlist,
 198        das1600_gainlist,
 199};
 200
 201static const struct comedi_lrange *const das16_ai_uni_lranges[] = {
 202        &range_unknown,
 203        &range_das16jr,
 204        &range_das16jr_16,
 205        &range_das1x01_unip,
 206        &range_das1x02_unip,
 207};
 208
 209static const struct comedi_lrange *const das16_ai_bip_lranges[] = {
 210        &range_unknown,
 211        &range_das16jr,
 212        &range_das16jr_16,
 213        &range_das1x01_bip,
 214        &range_das1x02_bip,
 215};
 216
 217struct das16_board {
 218        const char *name;
 219        unsigned int ai_maxdata;
 220        unsigned int ai_speed;  /*  max conversion speed in nanosec */
 221        unsigned int ai_pg;
 222        unsigned int has_ao:1;
 223        unsigned int has_8255:1;
 224
 225        unsigned int i8255_offset;
 226
 227        unsigned int size;
 228        unsigned int id;
 229};
 230
 231static const struct das16_board das16_boards[] = {
 232        {
 233                .name           = "das-16",
 234                .ai_maxdata     = 0x0fff,
 235                .ai_speed       = 15000,
 236                .ai_pg          = das16_pg_none,
 237                .has_ao         = 1,
 238                .has_8255       = 1,
 239                .i8255_offset   = 0x10,
 240                .size           = 0x14,
 241                .id             = 0x00,
 242        }, {
 243                .name           = "das-16g",
 244                .ai_maxdata     = 0x0fff,
 245                .ai_speed       = 15000,
 246                .ai_pg          = das16_pg_none,
 247                .has_ao         = 1,
 248                .has_8255       = 1,
 249                .i8255_offset   = 0x10,
 250                .size           = 0x14,
 251                .id             = 0x00,
 252        }, {
 253                .name           = "das-16f",
 254                .ai_maxdata     = 0x0fff,
 255                .ai_speed       = 8500,
 256                .ai_pg          = das16_pg_none,
 257                .has_ao         = 1,
 258                .has_8255       = 1,
 259                .i8255_offset   = 0x10,
 260                .size           = 0x14,
 261                .id             = 0x00,
 262        }, {
 263                .name           = "cio-das16",
 264                .ai_maxdata     = 0x0fff,
 265                .ai_speed       = 20000,
 266                .ai_pg          = das16_pg_none,
 267                .has_ao         = 1,
 268                .has_8255       = 1,
 269                .i8255_offset   = 0x10,
 270                .size           = 0x14,
 271                .id             = 0x80,
 272        }, {
 273                .name           = "cio-das16/f",
 274                .ai_maxdata     = 0x0fff,
 275                .ai_speed       = 10000,
 276                .ai_pg          = das16_pg_none,
 277                .has_ao         = 1,
 278                .has_8255       = 1,
 279                .i8255_offset   = 0x10,
 280                .size           = 0x14,
 281                .id             = 0x80,
 282        }, {
 283                .name           = "cio-das16/jr",
 284                .ai_maxdata     = 0x0fff,
 285                .ai_speed       = 7692,
 286                .ai_pg          = das16_pg_16jr,
 287                .size           = 0x10,
 288                .id             = 0x00,
 289        }, {
 290                .name           = "pc104-das16jr",
 291                .ai_maxdata     = 0x0fff,
 292                .ai_speed       = 3300,
 293                .ai_pg          = das16_pg_16jr,
 294                .size           = 0x10,
 295                .id             = 0x00,
 296        }, {
 297                .name           = "cio-das16jr/16",
 298                .ai_maxdata     = 0xffff,
 299                .ai_speed       = 10000,
 300                .ai_pg          = das16_pg_16jr_16,
 301                .size           = 0x10,
 302                .id             = 0x00,
 303        }, {
 304                .name           = "pc104-das16jr/16",
 305                .ai_maxdata     = 0xffff,
 306                .ai_speed       = 10000,
 307                .ai_pg          = das16_pg_16jr_16,
 308                .size           = 0x10,
 309                .id             = 0x00,
 310        }, {
 311                .name           = "das-1201",
 312                .ai_maxdata     = 0x0fff,
 313                .ai_speed       = 20000,
 314                .ai_pg          = das16_pg_none,
 315                .has_8255       = 1,
 316                .i8255_offset   = 0x400,
 317                .size           = 0x408,
 318                .id             = 0x20,
 319        }, {
 320                .name           = "das-1202",
 321                .ai_maxdata     = 0x0fff,
 322                .ai_speed       = 10000,
 323                .ai_pg          = das16_pg_none,
 324                .has_8255       = 1,
 325                .i8255_offset   = 0x400,
 326                .size           = 0x408,
 327                .id             = 0x20,
 328        }, {
 329                .name           = "das-1401",
 330                .ai_maxdata     = 0x0fff,
 331                .ai_speed       = 10000,
 332                .ai_pg          = das16_pg_1601,
 333                .size           = 0x408,
 334                .id             = 0xc0,
 335        }, {
 336                .name           = "das-1402",
 337                .ai_maxdata     = 0x0fff,
 338                .ai_speed       = 10000,
 339                .ai_pg          = das16_pg_1602,
 340                .size           = 0x408,
 341                .id             = 0xc0,
 342        }, {
 343                .name           = "das-1601",
 344                .ai_maxdata     = 0x0fff,
 345                .ai_speed       = 10000,
 346                .ai_pg          = das16_pg_1601,
 347                .has_ao         = 1,
 348                .has_8255       = 1,
 349                .i8255_offset   = 0x400,
 350                .size           = 0x408,
 351                .id             = 0xc0,
 352        }, {
 353                .name           = "das-1602",
 354                .ai_maxdata     = 0x0fff,
 355                .ai_speed       = 10000,
 356                .ai_pg          = das16_pg_1602,
 357                .has_ao         = 1,
 358                .has_8255       = 1,
 359                .i8255_offset   = 0x400,
 360                .size           = 0x408,
 361                .id             = 0xc0,
 362        }, {
 363                .name           = "cio-das1401/12",
 364                .ai_maxdata     = 0x0fff,
 365                .ai_speed       = 6250,
 366                .ai_pg          = das16_pg_1601,
 367                .size           = 0x408,
 368                .id             = 0xc0,
 369        }, {
 370                .name           = "cio-das1402/12",
 371                .ai_maxdata     = 0x0fff,
 372                .ai_speed       = 6250,
 373                .ai_pg          = das16_pg_1602,
 374                .size           = 0x408,
 375                .id             = 0xc0,
 376        }, {
 377                .name           = "cio-das1402/16",
 378                .ai_maxdata     = 0xffff,
 379                .ai_speed       = 10000,
 380                .ai_pg          = das16_pg_1602,
 381                .size           = 0x408,
 382                .id             = 0xc0,
 383        }, {
 384                .name           = "cio-das1601/12",
 385                .ai_maxdata     = 0x0fff,
 386                .ai_speed       = 6250,
 387                .ai_pg          = das16_pg_1601,
 388                .has_ao         = 1,
 389                .has_8255       = 1,
 390                .i8255_offset   = 0x400,
 391                .size           = 0x408,
 392                .id             = 0xc0,
 393        }, {
 394                .name           = "cio-das1602/12",
 395                .ai_maxdata     = 0x0fff,
 396                .ai_speed       = 10000,
 397                .ai_pg          = das16_pg_1602,
 398                .has_ao         = 1,
 399                .has_8255       = 1,
 400                .i8255_offset   = 0x400,
 401                .size           = 0x408,
 402                .id             = 0xc0,
 403        }, {
 404                .name           = "cio-das1602/16",
 405                .ai_maxdata     = 0xffff,
 406                .ai_speed       = 10000,
 407                .ai_pg          = das16_pg_1602,
 408                .has_ao         = 1,
 409                .has_8255       = 1,
 410                .i8255_offset   = 0x400,
 411                .size           = 0x408,
 412                .id             = 0xc0,
 413        }, {
 414                .name           = "cio-das16/330",
 415                .ai_maxdata     = 0x0fff,
 416                .ai_speed       = 3030,
 417                .ai_pg          = das16_pg_16jr,
 418                .size           = 0x14,
 419                .id             = 0xf0,
 420        },
 421};
 422
 423/*
 424 * Period for timer interrupt in jiffies.  It's a function
 425 * to deal with possibility of dynamic HZ patches
 426 */
 427static inline int timer_period(void)
 428{
 429        return HZ / 20;
 430}
 431
 432struct das16_private_struct {
 433        struct comedi_isadma    *dma;
 434        struct comedi_device    *dev;
 435        unsigned int            clockbase;
 436        unsigned int            ctrl_reg;
 437        unsigned int            divisor1;
 438        unsigned int            divisor2;
 439        struct timer_list       timer;
 440        unsigned long           extra_iobase;
 441        unsigned int            can_burst:1;
 442        unsigned int            timer_running:1;
 443};
 444
 445static void das16_ai_setup_dma(struct comedi_device *dev,
 446                               struct comedi_subdevice *s,
 447                               unsigned int unread_samples)
 448{
 449        struct das16_private_struct *devpriv = dev->private;
 450        struct comedi_isadma *dma = devpriv->dma;
 451        struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
 452        unsigned int max_samples = comedi_bytes_to_samples(s, desc->maxsize);
 453        unsigned int nsamples;
 454
 455        /*
 456         * Determine dma size based on the buffer size plus the number of
 457         * unread samples and the number of samples remaining in the command.
 458         */
 459        nsamples = comedi_nsamples_left(s, max_samples + unread_samples);
 460        if (nsamples > unread_samples) {
 461                nsamples -= unread_samples;
 462                desc->size = comedi_samples_to_bytes(s, nsamples);
 463                comedi_isadma_program(desc);
 464        }
 465}
 466
 467static void das16_interrupt(struct comedi_device *dev)
 468{
 469        struct das16_private_struct *devpriv = dev->private;
 470        struct comedi_subdevice *s = dev->read_subdev;
 471        struct comedi_async *async = s->async;
 472        struct comedi_cmd *cmd = &async->cmd;
 473        struct comedi_isadma *dma = devpriv->dma;
 474        struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
 475        unsigned long spin_flags;
 476        unsigned int residue;
 477        unsigned int nbytes;
 478        unsigned int nsamples;
 479
 480        spin_lock_irqsave(&dev->spinlock, spin_flags);
 481        if (!(devpriv->ctrl_reg & DAS16_CTRL_DMAE)) {
 482                spin_unlock_irqrestore(&dev->spinlock, spin_flags);
 483                return;
 484        }
 485
 486        /*
 487         * The pc104-das16jr (at least) has problems if the dma
 488         * transfer is interrupted in the middle of transferring
 489         * a 16 bit sample.
 490         */
 491        residue = comedi_isadma_disable_on_sample(desc->chan,
 492                                                  comedi_bytes_per_sample(s));
 493
 494        /* figure out how many samples to read */
 495        if (residue > desc->size) {
 496                dev_err(dev->class_dev, "residue > transfer size!\n");
 497                async->events |= COMEDI_CB_ERROR;
 498                nbytes = 0;
 499        } else {
 500                nbytes = desc->size - residue;
 501        }
 502        nsamples = comedi_bytes_to_samples(s, nbytes);
 503
 504        /* restart DMA if more samples are needed */
 505        if (nsamples) {
 506                dma->cur_dma = 1 - dma->cur_dma;
 507                das16_ai_setup_dma(dev, s, nsamples);
 508        }
 509
 510        spin_unlock_irqrestore(&dev->spinlock, spin_flags);
 511
 512        comedi_buf_write_samples(s, desc->virt_addr, nsamples);
 513
 514        if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg)
 515                async->events |= COMEDI_CB_EOA;
 516
 517        comedi_handle_events(dev, s);
 518}
 519
 520static void das16_timer_interrupt(struct timer_list *t)
 521{
 522        struct das16_private_struct *devpriv = from_timer(devpriv, t, timer);
 523        struct comedi_device *dev = devpriv->dev;
 524        unsigned long flags;
 525
 526        das16_interrupt(dev);
 527
 528        spin_lock_irqsave(&dev->spinlock, flags);
 529        if (devpriv->timer_running)
 530                mod_timer(&devpriv->timer, jiffies + timer_period());
 531        spin_unlock_irqrestore(&dev->spinlock, flags);
 532}
 533
 534static void das16_ai_set_mux_range(struct comedi_device *dev,
 535                                   unsigned int first_chan,
 536                                   unsigned int last_chan,
 537                                   unsigned int range)
 538{
 539        const struct das16_board *board = dev->board_ptr;
 540
 541        /* set multiplexer */
 542        outb(first_chan | (last_chan << 4), dev->iobase + DAS16_MUX_REG);
 543
 544        /* some boards do not have programmable gain */
 545        if (board->ai_pg == das16_pg_none)
 546                return;
 547
 548        /*
 549         * Set gain (this is also burst rate register but according to
 550         * computer boards manual, burst rate does nothing, even on
 551         * keithley cards).
 552         */
 553        outb((das16_gainlists[board->ai_pg])[range],
 554             dev->iobase + DAS16_GAIN_REG);
 555}
 556
 557static int das16_ai_check_chanlist(struct comedi_device *dev,
 558                                   struct comedi_subdevice *s,
 559                                   struct comedi_cmd *cmd)
 560{
 561        unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
 562        unsigned int range0 = CR_RANGE(cmd->chanlist[0]);
 563        int i;
 564
 565        for (i = 1; i < cmd->chanlist_len; i++) {
 566                unsigned int chan = CR_CHAN(cmd->chanlist[i]);
 567                unsigned int range = CR_RANGE(cmd->chanlist[i]);
 568
 569                if (chan != ((chan0 + i) % s->n_chan)) {
 570                        dev_dbg(dev->class_dev,
 571                                "entries in chanlist must be consecutive channels, counting upwards\n");
 572                        return -EINVAL;
 573                }
 574
 575                if (range != range0) {
 576                        dev_dbg(dev->class_dev,
 577                                "entries in chanlist must all have the same gain\n");
 578                        return -EINVAL;
 579                }
 580        }
 581
 582        return 0;
 583}
 584
 585static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
 586                          struct comedi_cmd *cmd)
 587{
 588        const struct das16_board *board = dev->board_ptr;
 589        struct das16_private_struct *devpriv = dev->private;
 590        int err = 0;
 591        unsigned int trig_mask;
 592        unsigned int arg;
 593
 594        /* Step 1 : check if triggers are trivially valid */
 595
 596        err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW);
 597
 598        trig_mask = TRIG_FOLLOW;
 599        if (devpriv->can_burst)
 600                trig_mask |= TRIG_TIMER | TRIG_EXT;
 601        err |= comedi_check_trigger_src(&cmd->scan_begin_src, trig_mask);
 602
 603        trig_mask = TRIG_TIMER | TRIG_EXT;
 604        if (devpriv->can_burst)
 605                trig_mask |= TRIG_NOW;
 606        err |= comedi_check_trigger_src(&cmd->convert_src, trig_mask);
 607
 608        err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
 609        err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 610
 611        if (err)
 612                return 1;
 613
 614        /* Step 2a : make sure trigger sources are unique */
 615
 616        err |= comedi_check_trigger_is_unique(cmd->scan_begin_src);
 617        err |= comedi_check_trigger_is_unique(cmd->convert_src);
 618        err |= comedi_check_trigger_is_unique(cmd->stop_src);
 619
 620        /* Step 2b : and mutually compatible */
 621
 622        /*  make sure scan_begin_src and convert_src don't conflict */
 623        if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW)
 624                err |= -EINVAL;
 625        if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->convert_src != TRIG_NOW)
 626                err |= -EINVAL;
 627
 628        if (err)
 629                return 2;
 630
 631        /* Step 3: check if arguments are trivially valid */
 632
 633        err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
 634
 635        if (cmd->scan_begin_src == TRIG_FOLLOW) /* internal trigger */
 636                err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
 637
 638        err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
 639                                           cmd->chanlist_len);
 640
 641        /* check against maximum frequency */
 642        if (cmd->scan_begin_src == TRIG_TIMER) {
 643                err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg,
 644                                                    board->ai_speed *
 645                                                    cmd->chanlist_len);
 646        }
 647
 648        if (cmd->convert_src == TRIG_TIMER) {
 649                err |= comedi_check_trigger_arg_min(&cmd->convert_arg,
 650                                                    board->ai_speed);
 651        }
 652
 653        if (cmd->stop_src == TRIG_COUNT)
 654                err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
 655        else    /* TRIG_NONE */
 656                err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
 657
 658        if (err)
 659                return 3;
 660
 661        /*  step 4: fix up arguments */
 662        if (cmd->scan_begin_src == TRIG_TIMER) {
 663                arg = cmd->scan_begin_arg;
 664                comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
 665                err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
 666        }
 667        if (cmd->convert_src == TRIG_TIMER) {
 668                arg = cmd->convert_arg;
 669                comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
 670                err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
 671        }
 672        if (err)
 673                return 4;
 674
 675        /* Step 5: check channel list if it exists */
 676        if (cmd->chanlist && cmd->chanlist_len > 0)
 677                err |= das16_ai_check_chanlist(dev, s, cmd);
 678
 679        if (err)
 680                return 5;
 681
 682        return 0;
 683}
 684
 685static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns,
 686                                    unsigned int flags)
 687{
 688        comedi_8254_cascade_ns_to_timer(dev->pacer, &ns, flags);
 689        comedi_8254_update_divisors(dev->pacer);
 690        comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
 691
 692        return ns;
 693}
 694
 695static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s)
 696{
 697        struct das16_private_struct *devpriv = dev->private;
 698        struct comedi_isadma *dma = devpriv->dma;
 699        struct comedi_async *async = s->async;
 700        struct comedi_cmd *cmd = &async->cmd;
 701        unsigned int first_chan = CR_CHAN(cmd->chanlist[0]);
 702        unsigned int last_chan = CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]);
 703        unsigned int range = CR_RANGE(cmd->chanlist[0]);
 704        unsigned int byte;
 705        unsigned long flags;
 706
 707        if (cmd->flags & CMDF_PRIORITY) {
 708                dev_err(dev->class_dev,
 709                        "isa dma transfers cannot be performed with CMDF_PRIORITY, aborting\n");
 710                return -1;
 711        }
 712
 713        if (devpriv->can_burst)
 714                outb(DAS1600_CONV_DISABLE, dev->iobase + DAS1600_CONV_REG);
 715
 716        /* set mux and range for chanlist scan */
 717        das16_ai_set_mux_range(dev, first_chan, last_chan, range);
 718
 719        /* set counter mode and counts */
 720        cmd->convert_arg = das16_set_pacer(dev, cmd->convert_arg, cmd->flags);
 721
 722        /* enable counters */
 723        byte = 0;
 724        if (devpriv->can_burst) {
 725                if (cmd->convert_src == TRIG_NOW) {
 726                        outb(DAS1600_BURST_VAL,
 727                             dev->iobase + DAS1600_BURST_REG);
 728                        /*  set burst length */
 729                        byte |= DAS16_PACER_BURST_LEN(cmd->chanlist_len - 1);
 730                } else {
 731                        outb(0, dev->iobase + DAS1600_BURST_REG);
 732                }
 733        }
 734        outb(byte, dev->iobase + DAS16_PACER_REG);
 735
 736        /* set up dma transfer */
 737        dma->cur_dma = 0;
 738        das16_ai_setup_dma(dev, s, 0);
 739
 740        /*  set up timer */
 741        spin_lock_irqsave(&dev->spinlock, flags);
 742        devpriv->timer_running = 1;
 743        devpriv->timer.expires = jiffies + timer_period();
 744        add_timer(&devpriv->timer);
 745
 746        /* enable DMA interrupt with external or internal pacing */
 747        devpriv->ctrl_reg &= ~(DAS16_CTRL_INTE | DAS16_CTRL_PACING_MASK);
 748        devpriv->ctrl_reg |= DAS16_CTRL_DMAE;
 749        if (cmd->convert_src == TRIG_EXT)
 750                devpriv->ctrl_reg |= DAS16_CTRL_EXT_PACER;
 751        else
 752                devpriv->ctrl_reg |= DAS16_CTRL_INT_PACER;
 753        outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG);
 754
 755        if (devpriv->can_burst)
 756                outb(0, dev->iobase + DAS1600_CONV_REG);
 757        spin_unlock_irqrestore(&dev->spinlock, flags);
 758
 759        return 0;
 760}
 761
 762static int das16_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
 763{
 764        struct das16_private_struct *devpriv = dev->private;
 765        struct comedi_isadma *dma = devpriv->dma;
 766        unsigned long flags;
 767
 768        spin_lock_irqsave(&dev->spinlock, flags);
 769
 770        /* disable interrupts, dma and pacer clocked conversions */
 771        devpriv->ctrl_reg &= ~(DAS16_CTRL_INTE | DAS16_CTRL_DMAE |
 772                               DAS16_CTRL_PACING_MASK);
 773        outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG);
 774
 775        comedi_isadma_disable(dma->chan);
 776
 777        /*  disable SW timer */
 778        if (devpriv->timer_running) {
 779                devpriv->timer_running = 0;
 780                del_timer(&devpriv->timer);
 781        }
 782
 783        if (devpriv->can_burst)
 784                outb(0, dev->iobase + DAS1600_BURST_REG);
 785
 786        spin_unlock_irqrestore(&dev->spinlock, flags);
 787
 788        return 0;
 789}
 790
 791static void das16_ai_munge(struct comedi_device *dev,
 792                           struct comedi_subdevice *s, void *array,
 793                           unsigned int num_bytes,
 794                           unsigned int start_chan_index)
 795{
 796        unsigned short *data = array;
 797        unsigned int num_samples = comedi_bytes_to_samples(s, num_bytes);
 798        unsigned int i;
 799        __le16 *buf = array;
 800
 801        for (i = 0; i < num_samples; i++) {
 802                data[i] = le16_to_cpu(buf[i]);
 803                if (s->maxdata == 0x0fff)
 804                        data[i] >>= 4;
 805                data[i] &= s->maxdata;
 806        }
 807}
 808
 809static int das16_ai_eoc(struct comedi_device *dev,
 810                        struct comedi_subdevice *s,
 811                        struct comedi_insn *insn,
 812                        unsigned long context)
 813{
 814        unsigned int status;
 815
 816        status = inb(dev->iobase + DAS16_STATUS_REG);
 817        if ((status & DAS16_STATUS_BUSY) == 0)
 818                return 0;
 819        return -EBUSY;
 820}
 821
 822static int das16_ai_insn_read(struct comedi_device *dev,
 823                              struct comedi_subdevice *s,
 824                              struct comedi_insn *insn,
 825                              unsigned int *data)
 826{
 827        unsigned int chan = CR_CHAN(insn->chanspec);
 828        unsigned int range = CR_RANGE(insn->chanspec);
 829        unsigned int val;
 830        int ret;
 831        int i;
 832
 833        /* set mux and range for single channel */
 834        das16_ai_set_mux_range(dev, chan, chan, range);
 835
 836        for (i = 0; i < insn->n; i++) {
 837                /* trigger conversion */
 838                outb_p(0, dev->iobase + DAS16_TRIG_REG);
 839
 840                ret = comedi_timeout(dev, s, insn, das16_ai_eoc, 0);
 841                if (ret)
 842                        return ret;
 843
 844                val = inb(dev->iobase + DAS16_AI_MSB_REG) << 8;
 845                val |= inb(dev->iobase + DAS16_AI_LSB_REG);
 846                if (s->maxdata == 0x0fff)
 847                        val >>= 4;
 848                val &= s->maxdata;
 849
 850                data[i] = val;
 851        }
 852
 853        return insn->n;
 854}
 855
 856static int das16_ao_insn_write(struct comedi_device *dev,
 857                               struct comedi_subdevice *s,
 858                               struct comedi_insn *insn,
 859                               unsigned int *data)
 860{
 861        unsigned int chan = CR_CHAN(insn->chanspec);
 862        int i;
 863
 864        for (i = 0; i < insn->n; i++) {
 865                unsigned int val = data[i];
 866
 867                s->readback[chan] = val;
 868
 869                val <<= 4;
 870
 871                outb(val & 0xff, dev->iobase + DAS16_AO_LSB_REG(chan));
 872                outb((val >> 8) & 0xff, dev->iobase + DAS16_AO_MSB_REG(chan));
 873        }
 874
 875        return insn->n;
 876}
 877
 878static int das16_di_insn_bits(struct comedi_device *dev,
 879                              struct comedi_subdevice *s,
 880                              struct comedi_insn *insn,
 881                              unsigned int *data)
 882{
 883        data[1] = inb(dev->iobase + DAS16_DIO_REG) & 0xf;
 884
 885        return insn->n;
 886}
 887
 888static int das16_do_insn_bits(struct comedi_device *dev,
 889                              struct comedi_subdevice *s,
 890                              struct comedi_insn *insn,
 891                              unsigned int *data)
 892{
 893        if (comedi_dio_update_state(s, data))
 894                outb(s->state, dev->iobase + DAS16_DIO_REG);
 895
 896        data[1] = s->state;
 897
 898        return insn->n;
 899}
 900
 901static int das16_probe(struct comedi_device *dev, struct comedi_devconfig *it)
 902{
 903        const struct das16_board *board = dev->board_ptr;
 904        int diobits;
 905
 906        /* diobits indicates boards */
 907        diobits = inb(dev->iobase + DAS16_DIO_REG) & 0xf0;
 908        if (board->id != diobits) {
 909                dev_err(dev->class_dev,
 910                        "requested board's id bits are incorrect (0x%x != 0x%x)\n",
 911                        board->id, diobits);
 912                return -EINVAL;
 913        }
 914
 915        return 0;
 916}
 917
 918static void das16_reset(struct comedi_device *dev)
 919{
 920        outb(0, dev->iobase + DAS16_STATUS_REG);
 921        outb(0, dev->iobase + DAS16_CTRL_REG);
 922        outb(0, dev->iobase + DAS16_PACER_REG);
 923}
 924
 925static void das16_alloc_dma(struct comedi_device *dev, unsigned int dma_chan)
 926{
 927        struct das16_private_struct *devpriv = dev->private;
 928
 929        timer_setup(&devpriv->timer, das16_timer_interrupt, 0);
 930
 931        /* only DMA channels 3 and 1 are valid */
 932        if (!(dma_chan == 1 || dma_chan == 3))
 933                return;
 934
 935        /* DMA uses two buffers */
 936        devpriv->dma = comedi_isadma_alloc(dev, 2, dma_chan, dma_chan,
 937                                           DAS16_DMA_SIZE, COMEDI_ISADMA_READ);
 938}
 939
 940static void das16_free_dma(struct comedi_device *dev)
 941{
 942        struct das16_private_struct *devpriv = dev->private;
 943
 944        if (devpriv) {
 945                del_timer_sync(&devpriv->timer);
 946                comedi_isadma_free(devpriv->dma);
 947        }
 948}
 949
 950static const struct comedi_lrange *das16_ai_range(struct comedi_device *dev,
 951                                                  struct comedi_subdevice *s,
 952                                                  struct comedi_devconfig *it,
 953                                                  unsigned int pg_type,
 954                                                  unsigned int status)
 955{
 956        unsigned int min = it->options[4];
 957        unsigned int max = it->options[5];
 958
 959        /* get any user-defined input range */
 960        if (pg_type == das16_pg_none && (min || max)) {
 961                struct comedi_lrange *lrange;
 962                struct comedi_krange *krange;
 963
 964                /* allocate single-range range table */
 965                lrange = comedi_alloc_spriv(s,
 966                                            sizeof(*lrange) + sizeof(*krange));
 967                if (!lrange)
 968                        return &range_unknown;
 969
 970                /* initialize ai range */
 971                lrange->length = 1;
 972                krange = lrange->range;
 973                krange->min = min;
 974                krange->max = max;
 975                krange->flags = UNIT_volt;
 976
 977                return lrange;
 978        }
 979
 980        /* use software programmable range */
 981        if (status & DAS16_STATUS_UNIPOLAR)
 982                return das16_ai_uni_lranges[pg_type];
 983        return das16_ai_bip_lranges[pg_type];
 984}
 985
 986static const struct comedi_lrange *das16_ao_range(struct comedi_device *dev,
 987                                                  struct comedi_subdevice *s,
 988                                                  struct comedi_devconfig *it)
 989{
 990        unsigned int min = it->options[6];
 991        unsigned int max = it->options[7];
 992
 993        /* get any user-defined output range */
 994        if (min || max) {
 995                struct comedi_lrange *lrange;
 996                struct comedi_krange *krange;
 997
 998                /* allocate single-range range table */
 999                lrange = comedi_alloc_spriv(s,
1000                                            sizeof(*lrange) + sizeof(*krange));
1001                if (!lrange)
1002                        return &range_unknown;
1003
1004                /* initialize ao range */
1005                lrange->length = 1;
1006                krange = lrange->range;
1007                krange->min = min;
1008                krange->max = max;
1009                krange->flags = UNIT_volt;
1010
1011                return lrange;
1012        }
1013
1014        return &range_unknown;
1015}
1016
1017static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1018{
1019        const struct das16_board *board = dev->board_ptr;
1020        struct das16_private_struct *devpriv;
1021        struct comedi_subdevice *s;
1022        unsigned int osc_base;
1023        unsigned int status;
1024        int ret;
1025
1026        /*  check that clock setting is valid */
1027        if (it->options[3]) {
1028                if (it->options[3] != 1 && it->options[3] != 10) {
1029                        dev_err(dev->class_dev,
1030                                "Invalid option. Master clock must be set to 1 or 10 (MHz)\n");
1031                        return -EINVAL;
1032                }
1033        }
1034
1035        devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1036        if (!devpriv)
1037                return -ENOMEM;
1038        devpriv->dev = dev;
1039
1040        if (board->size < 0x400) {
1041                ret = comedi_request_region(dev, it->options[0], board->size);
1042                if (ret)
1043                        return ret;
1044        } else {
1045                ret = comedi_request_region(dev, it->options[0], 0x10);
1046                if (ret)
1047                        return ret;
1048                /* Request an additional region for the 8255 */
1049                ret = __comedi_request_region(dev, dev->iobase + 0x400,
1050                                              board->size & 0x3ff);
1051                if (ret)
1052                        return ret;
1053                devpriv->extra_iobase = dev->iobase + 0x400;
1054                devpriv->can_burst = 1;
1055        }
1056
1057        /*  probe id bits to make sure they are consistent */
1058        if (das16_probe(dev, it))
1059                return -EINVAL;
1060
1061        /*  get master clock speed */
1062        osc_base = I8254_OSC_BASE_1MHZ;
1063        if (devpriv->can_burst) {
1064                status = inb(dev->iobase + DAS1600_STATUS_REG);
1065                if (status & DAS1600_STATUS_CLK_10MHZ)
1066                        osc_base = I8254_OSC_BASE_10MHZ;
1067        } else {
1068                if (it->options[3])
1069                        osc_base = I8254_OSC_BASE_1MHZ / it->options[3];
1070        }
1071
1072        dev->pacer = comedi_8254_init(dev->iobase + DAS16_TIMER_BASE_REG,
1073                                      osc_base, I8254_IO8, 0);
1074        if (!dev->pacer)
1075                return -ENOMEM;
1076
1077        das16_alloc_dma(dev, it->options[2]);
1078
1079        ret = comedi_alloc_subdevices(dev, 4 + board->has_8255);
1080        if (ret)
1081                return ret;
1082
1083        status = inb(dev->iobase + DAS16_STATUS_REG);
1084
1085        /* Analog Input subdevice */
1086        s = &dev->subdevices[0];
1087        s->type         = COMEDI_SUBD_AI;
1088        s->subdev_flags = SDF_READABLE;
1089        if (status & DAS16_STATUS_MUXBIT) {
1090                s->subdev_flags |= SDF_GROUND;
1091                s->n_chan       = 16;
1092        } else {
1093                s->subdev_flags |= SDF_DIFF;
1094                s->n_chan       = 8;
1095        }
1096        s->len_chanlist = s->n_chan;
1097        s->maxdata      = board->ai_maxdata;
1098        s->range_table  = das16_ai_range(dev, s, it, board->ai_pg, status);
1099        s->insn_read    = das16_ai_insn_read;
1100        if (devpriv->dma) {
1101                dev->read_subdev = s;
1102                s->subdev_flags |= SDF_CMD_READ;
1103                s->do_cmdtest   = das16_cmd_test;
1104                s->do_cmd       = das16_cmd_exec;
1105                s->cancel       = das16_cancel;
1106                s->munge        = das16_ai_munge;
1107        }
1108
1109        /* Analog Output subdevice */
1110        s = &dev->subdevices[1];
1111        if (board->has_ao) {
1112                s->type         = COMEDI_SUBD_AO;
1113                s->subdev_flags = SDF_WRITABLE;
1114                s->n_chan       = 2;
1115                s->maxdata      = 0x0fff;
1116                s->range_table  = das16_ao_range(dev, s, it);
1117                s->insn_write   = das16_ao_insn_write;
1118
1119                ret = comedi_alloc_subdev_readback(s);
1120                if (ret)
1121                        return ret;
1122        } else {
1123                s->type         = COMEDI_SUBD_UNUSED;
1124        }
1125
1126        /* Digital Input subdevice */
1127        s = &dev->subdevices[2];
1128        s->type         = COMEDI_SUBD_DI;
1129        s->subdev_flags = SDF_READABLE;
1130        s->n_chan       = 4;
1131        s->maxdata      = 1;
1132        s->range_table  = &range_digital;
1133        s->insn_bits    = das16_di_insn_bits;
1134
1135        /* Digital Output subdevice */
1136        s = &dev->subdevices[3];
1137        s->type         = COMEDI_SUBD_DO;
1138        s->subdev_flags = SDF_WRITABLE;
1139        s->n_chan       = 4;
1140        s->maxdata      = 1;
1141        s->range_table  = &range_digital;
1142        s->insn_bits    = das16_do_insn_bits;
1143
1144        /* initialize digital output lines */
1145        outb(s->state, dev->iobase + DAS16_DIO_REG);
1146
1147        /* 8255 Digital I/O subdevice */
1148        if (board->has_8255) {
1149                s = &dev->subdevices[4];
1150                ret = subdev_8255_init(dev, s, NULL, board->i8255_offset);
1151                if (ret)
1152                        return ret;
1153        }
1154
1155        das16_reset(dev);
1156        /* set the interrupt level */
1157        devpriv->ctrl_reg = DAS16_CTRL_IRQ(dev->irq);
1158        outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG);
1159
1160        if (devpriv->can_burst) {
1161                outb(DAS1600_ENABLE_VAL, dev->iobase + DAS1600_ENABLE_REG);
1162                outb(0, dev->iobase + DAS1600_CONV_REG);
1163                outb(0, dev->iobase + DAS1600_BURST_REG);
1164        }
1165
1166        return 0;
1167}
1168
1169static void das16_detach(struct comedi_device *dev)
1170{
1171        const struct das16_board *board = dev->board_ptr;
1172        struct das16_private_struct *devpriv = dev->private;
1173
1174        if (devpriv) {
1175                if (dev->iobase)
1176                        das16_reset(dev);
1177                das16_free_dma(dev);
1178
1179                if (devpriv->extra_iobase)
1180                        release_region(devpriv->extra_iobase,
1181                                       board->size & 0x3ff);
1182        }
1183
1184        comedi_legacy_detach(dev);
1185}
1186
1187static struct comedi_driver das16_driver = {
1188        .driver_name    = "das16",
1189        .module         = THIS_MODULE,
1190        .attach         = das16_attach,
1191        .detach         = das16_detach,
1192        .board_name     = &das16_boards[0].name,
1193        .num_names      = ARRAY_SIZE(das16_boards),
1194        .offset         = sizeof(das16_boards[0]),
1195};
1196module_comedi_driver(das16_driver);
1197
1198MODULE_AUTHOR("Comedi http://www.comedi.org");
1199MODULE_DESCRIPTION("Comedi driver for DAS16 compatible boards");
1200MODULE_LICENSE("GPL");
1201