linux/drivers/staging/comedi/drivers/me4000.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * me4000.c
   4 * Source code for the Meilhaus ME-4000 board family.
   5 *
   6 * COMEDI - Linux Control and Measurement Device Interface
   7 * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
   8 */
   9
  10/*
  11 * Driver: me4000
  12 * Description: Meilhaus ME-4000 series boards
  13 * Devices: [Meilhaus] ME-4650 (me4000), ME-4670i, ME-4680, ME-4680i,
  14 *          ME-4680is
  15 * Author: gg (Guenter Gebhardt <g.gebhardt@meilhaus.com>)
  16 * Updated: Mon, 18 Mar 2002 15:34:01 -0800
  17 * Status: untested
  18 *
  19 * Supports:
  20 *      - Analog Input
  21 *      - Analog Output
  22 *      - Digital I/O
  23 *      - Counter
  24 *
  25 * Configuration Options: not applicable, uses PCI auto config
  26 *
  27 * The firmware required by these boards is available in the
  28 * comedi_nonfree_firmware tarball available from
  29 * https://www.comedi.org.
  30 */
  31
  32#include <linux/module.h>
  33#include <linux/delay.h>
  34#include <linux/interrupt.h>
  35
  36#include "../comedi_pci.h"
  37
  38#include "comedi_8254.h"
  39#include "plx9052.h"
  40
  41#define ME4000_FIRMWARE         "me4000_firmware.bin"
  42
  43/*
  44 * ME4000 Register map and bit defines
  45 */
  46#define ME4000_AO_CHAN(x)                       ((x) * 0x18)
  47
  48#define ME4000_AO_CTRL_REG(x)                   (0x00 + ME4000_AO_CHAN(x))
  49#define ME4000_AO_CTRL_MODE_0                   BIT(0)
  50#define ME4000_AO_CTRL_MODE_1                   BIT(1)
  51#define ME4000_AO_CTRL_STOP                     BIT(2)
  52#define ME4000_AO_CTRL_ENABLE_FIFO              BIT(3)
  53#define ME4000_AO_CTRL_ENABLE_EX_TRIG           BIT(4)
  54#define ME4000_AO_CTRL_EX_TRIG_EDGE             BIT(5)
  55#define ME4000_AO_CTRL_IMMEDIATE_STOP           BIT(7)
  56#define ME4000_AO_CTRL_ENABLE_DO                BIT(8)
  57#define ME4000_AO_CTRL_ENABLE_IRQ               BIT(9)
  58#define ME4000_AO_CTRL_RESET_IRQ                BIT(10)
  59#define ME4000_AO_STATUS_REG(x)                 (0x04 + ME4000_AO_CHAN(x))
  60#define ME4000_AO_STATUS_FSM                    BIT(0)
  61#define ME4000_AO_STATUS_FF                     BIT(1)
  62#define ME4000_AO_STATUS_HF                     BIT(2)
  63#define ME4000_AO_STATUS_EF                     BIT(3)
  64#define ME4000_AO_FIFO_REG(x)                   (0x08 + ME4000_AO_CHAN(x))
  65#define ME4000_AO_SINGLE_REG(x)                 (0x0c + ME4000_AO_CHAN(x))
  66#define ME4000_AO_TIMER_REG(x)                  (0x10 + ME4000_AO_CHAN(x))
  67#define ME4000_AI_CTRL_REG                      0x74
  68#define ME4000_AI_STATUS_REG                    0x74
  69#define ME4000_AI_CTRL_MODE_0                   BIT(0)
  70#define ME4000_AI_CTRL_MODE_1                   BIT(1)
  71#define ME4000_AI_CTRL_MODE_2                   BIT(2)
  72#define ME4000_AI_CTRL_SAMPLE_HOLD              BIT(3)
  73#define ME4000_AI_CTRL_IMMEDIATE_STOP           BIT(4)
  74#define ME4000_AI_CTRL_STOP                     BIT(5)
  75#define ME4000_AI_CTRL_CHANNEL_FIFO             BIT(6)
  76#define ME4000_AI_CTRL_DATA_FIFO                BIT(7)
  77#define ME4000_AI_CTRL_FULLSCALE                BIT(8)
  78#define ME4000_AI_CTRL_OFFSET                   BIT(9)
  79#define ME4000_AI_CTRL_EX_TRIG_ANALOG           BIT(10)
  80#define ME4000_AI_CTRL_EX_TRIG                  BIT(11)
  81#define ME4000_AI_CTRL_EX_TRIG_FALLING          BIT(12)
  82#define ME4000_AI_CTRL_EX_IRQ                   BIT(13)
  83#define ME4000_AI_CTRL_EX_IRQ_RESET             BIT(14)
  84#define ME4000_AI_CTRL_LE_IRQ                   BIT(15)
  85#define ME4000_AI_CTRL_LE_IRQ_RESET             BIT(16)
  86#define ME4000_AI_CTRL_HF_IRQ                   BIT(17)
  87#define ME4000_AI_CTRL_HF_IRQ_RESET             BIT(18)
  88#define ME4000_AI_CTRL_SC_IRQ                   BIT(19)
  89#define ME4000_AI_CTRL_SC_IRQ_RESET             BIT(20)
  90#define ME4000_AI_CTRL_SC_RELOAD                BIT(21)
  91#define ME4000_AI_STATUS_EF_CHANNEL             BIT(22)
  92#define ME4000_AI_STATUS_HF_CHANNEL             BIT(23)
  93#define ME4000_AI_STATUS_FF_CHANNEL             BIT(24)
  94#define ME4000_AI_STATUS_EF_DATA                BIT(25)
  95#define ME4000_AI_STATUS_HF_DATA                BIT(26)
  96#define ME4000_AI_STATUS_FF_DATA                BIT(27)
  97#define ME4000_AI_STATUS_LE                     BIT(28)
  98#define ME4000_AI_STATUS_FSM                    BIT(29)
  99#define ME4000_AI_CTRL_EX_TRIG_BOTH             BIT(31)
 100#define ME4000_AI_CHANNEL_LIST_REG              0x78
 101#define ME4000_AI_LIST_INPUT_DIFFERENTIAL       BIT(5)
 102#define ME4000_AI_LIST_RANGE(x)                 ((3 - ((x) & 3)) << 6)
 103#define ME4000_AI_LIST_LAST_ENTRY               BIT(8)
 104#define ME4000_AI_DATA_REG                      0x7c
 105#define ME4000_AI_CHAN_TIMER_REG                0x80
 106#define ME4000_AI_CHAN_PRE_TIMER_REG            0x84
 107#define ME4000_AI_SCAN_TIMER_LOW_REG            0x88
 108#define ME4000_AI_SCAN_TIMER_HIGH_REG           0x8c
 109#define ME4000_AI_SCAN_PRE_TIMER_LOW_REG        0x90
 110#define ME4000_AI_SCAN_PRE_TIMER_HIGH_REG       0x94
 111#define ME4000_AI_START_REG                     0x98
 112#define ME4000_IRQ_STATUS_REG                   0x9c
 113#define ME4000_IRQ_STATUS_EX                    BIT(0)
 114#define ME4000_IRQ_STATUS_LE                    BIT(1)
 115#define ME4000_IRQ_STATUS_AI_HF                 BIT(2)
 116#define ME4000_IRQ_STATUS_AO_0_HF               BIT(3)
 117#define ME4000_IRQ_STATUS_AO_1_HF               BIT(4)
 118#define ME4000_IRQ_STATUS_AO_2_HF               BIT(5)
 119#define ME4000_IRQ_STATUS_AO_3_HF               BIT(6)
 120#define ME4000_IRQ_STATUS_SC                    BIT(7)
 121#define ME4000_DIO_PORT_0_REG                   0xa0
 122#define ME4000_DIO_PORT_1_REG                   0xa4
 123#define ME4000_DIO_PORT_2_REG                   0xa8
 124#define ME4000_DIO_PORT_3_REG                   0xac
 125#define ME4000_DIO_DIR_REG                      0xb0
 126#define ME4000_AO_LOADSETREG_XX                 0xb4
 127#define ME4000_DIO_CTRL_REG                     0xb8
 128#define ME4000_DIO_CTRL_MODE_0                  BIT(0)
 129#define ME4000_DIO_CTRL_MODE_1                  BIT(1)
 130#define ME4000_DIO_CTRL_MODE_2                  BIT(2)
 131#define ME4000_DIO_CTRL_MODE_3                  BIT(3)
 132#define ME4000_DIO_CTRL_MODE_4                  BIT(4)
 133#define ME4000_DIO_CTRL_MODE_5                  BIT(5)
 134#define ME4000_DIO_CTRL_MODE_6                  BIT(6)
 135#define ME4000_DIO_CTRL_MODE_7                  BIT(7)
 136#define ME4000_DIO_CTRL_FUNCTION_0              BIT(8)
 137#define ME4000_DIO_CTRL_FUNCTION_1              BIT(9)
 138#define ME4000_DIO_CTRL_FIFO_HIGH_0             BIT(10)
 139#define ME4000_DIO_CTRL_FIFO_HIGH_1             BIT(11)
 140#define ME4000_DIO_CTRL_FIFO_HIGH_2             BIT(12)
 141#define ME4000_DIO_CTRL_FIFO_HIGH_3             BIT(13)
 142#define ME4000_AO_DEMUX_ADJUST_REG              0xbc
 143#define ME4000_AO_DEMUX_ADJUST_VALUE            0x4c
 144#define ME4000_AI_SAMPLE_COUNTER_REG            0xc0
 145
 146#define ME4000_AI_FIFO_COUNT                    2048
 147
 148#define ME4000_AI_MIN_TICKS                     66
 149#define ME4000_AI_MIN_SAMPLE_TIME               2000
 150
 151#define ME4000_AI_CHANNEL_LIST_COUNT            1024
 152
 153struct me4000_private {
 154        unsigned long plx_regbase;
 155        unsigned int ai_ctrl_mode;
 156        unsigned int ai_init_ticks;
 157        unsigned int ai_scan_ticks;
 158        unsigned int ai_chan_ticks;
 159};
 160
 161enum me4000_boardid {
 162        BOARD_ME4650,
 163        BOARD_ME4660,
 164        BOARD_ME4660I,
 165        BOARD_ME4660S,
 166        BOARD_ME4660IS,
 167        BOARD_ME4670,
 168        BOARD_ME4670I,
 169        BOARD_ME4670S,
 170        BOARD_ME4670IS,
 171        BOARD_ME4680,
 172        BOARD_ME4680I,
 173        BOARD_ME4680S,
 174        BOARD_ME4680IS,
 175};
 176
 177struct me4000_board {
 178        const char *name;
 179        int ai_nchan;
 180        unsigned int can_do_diff_ai:1;
 181        unsigned int can_do_sh_ai:1;    /* sample & hold (8 channels) */
 182        unsigned int ex_trig_analog:1;
 183        unsigned int has_ao:1;
 184        unsigned int has_ao_fifo:1;
 185        unsigned int has_counter:1;
 186};
 187
 188static const struct me4000_board me4000_boards[] = {
 189        [BOARD_ME4650] = {
 190                .name           = "ME-4650",
 191                .ai_nchan       = 16,
 192        },
 193        [BOARD_ME4660] = {
 194                .name           = "ME-4660",
 195                .ai_nchan       = 32,
 196                .can_do_diff_ai = 1,
 197                .has_counter    = 1,
 198        },
 199        [BOARD_ME4660I] = {
 200                .name           = "ME-4660i",
 201                .ai_nchan       = 32,
 202                .can_do_diff_ai = 1,
 203                .has_counter    = 1,
 204        },
 205        [BOARD_ME4660S] = {
 206                .name           = "ME-4660s",
 207                .ai_nchan       = 32,
 208                .can_do_diff_ai = 1,
 209                .can_do_sh_ai   = 1,
 210                .has_counter    = 1,
 211        },
 212        [BOARD_ME4660IS] = {
 213                .name           = "ME-4660is",
 214                .ai_nchan       = 32,
 215                .can_do_diff_ai = 1,
 216                .can_do_sh_ai   = 1,
 217                .has_counter    = 1,
 218        },
 219        [BOARD_ME4670] = {
 220                .name           = "ME-4670",
 221                .ai_nchan       = 32,
 222                .can_do_diff_ai = 1,
 223                .ex_trig_analog = 1,
 224                .has_ao         = 1,
 225                .has_counter    = 1,
 226        },
 227        [BOARD_ME4670I] = {
 228                .name           = "ME-4670i",
 229                .ai_nchan       = 32,
 230                .can_do_diff_ai = 1,
 231                .ex_trig_analog = 1,
 232                .has_ao         = 1,
 233                .has_counter    = 1,
 234        },
 235        [BOARD_ME4670S] = {
 236                .name           = "ME-4670s",
 237                .ai_nchan       = 32,
 238                .can_do_diff_ai = 1,
 239                .can_do_sh_ai   = 1,
 240                .ex_trig_analog = 1,
 241                .has_ao         = 1,
 242                .has_counter    = 1,
 243        },
 244        [BOARD_ME4670IS] = {
 245                .name           = "ME-4670is",
 246                .ai_nchan       = 32,
 247                .can_do_diff_ai = 1,
 248                .can_do_sh_ai   = 1,
 249                .ex_trig_analog = 1,
 250                .has_ao         = 1,
 251                .has_counter    = 1,
 252        },
 253        [BOARD_ME4680] = {
 254                .name           = "ME-4680",
 255                .ai_nchan       = 32,
 256                .can_do_diff_ai = 1,
 257                .ex_trig_analog = 1,
 258                .has_ao         = 1,
 259                .has_ao_fifo    = 1,
 260                .has_counter    = 1,
 261        },
 262        [BOARD_ME4680I] = {
 263                .name           = "ME-4680i",
 264                .ai_nchan       = 32,
 265                .can_do_diff_ai = 1,
 266                .ex_trig_analog = 1,
 267                .has_ao         = 1,
 268                .has_ao_fifo    = 1,
 269                .has_counter    = 1,
 270        },
 271        [BOARD_ME4680S] = {
 272                .name           = "ME-4680s",
 273                .ai_nchan       = 32,
 274                .can_do_diff_ai = 1,
 275                .can_do_sh_ai   = 1,
 276                .ex_trig_analog = 1,
 277                .has_ao         = 1,
 278                .has_ao_fifo    = 1,
 279                .has_counter    = 1,
 280        },
 281        [BOARD_ME4680IS] = {
 282                .name           = "ME-4680is",
 283                .ai_nchan       = 32,
 284                .can_do_diff_ai = 1,
 285                .can_do_sh_ai   = 1,
 286                .ex_trig_analog = 1,
 287                .has_ao         = 1,
 288                .has_ao_fifo    = 1,
 289                .has_counter    = 1,
 290        },
 291};
 292
 293/*
 294 * NOTE: the ranges here are inverted compared to the values
 295 * written to the ME4000_AI_CHANNEL_LIST_REG,
 296 *
 297 * The ME4000_AI_LIST_RANGE() macro handles the inversion.
 298 */
 299static const struct comedi_lrange me4000_ai_range = {
 300        4, {
 301                UNI_RANGE(2.5),
 302                UNI_RANGE(10),
 303                BIP_RANGE(2.5),
 304                BIP_RANGE(10)
 305        }
 306};
 307
 308static int me4000_xilinx_download(struct comedi_device *dev,
 309                                  const u8 *data, size_t size,
 310                                  unsigned long context)
 311{
 312        struct pci_dev *pcidev = comedi_to_pci_dev(dev);
 313        struct me4000_private *devpriv = dev->private;
 314        unsigned long xilinx_iobase = pci_resource_start(pcidev, 5);
 315        unsigned int file_length;
 316        unsigned int val;
 317        unsigned int i;
 318
 319        if (!xilinx_iobase)
 320                return -ENODEV;
 321
 322        /*
 323         * Set PLX local interrupt 2 polarity to high.
 324         * Interrupt is thrown by init pin of xilinx.
 325         */
 326        outl(PLX9052_INTCSR_LI2POL, devpriv->plx_regbase + PLX9052_INTCSR);
 327
 328        /* Set /CS and /WRITE of the Xilinx */
 329        val = inl(devpriv->plx_regbase + PLX9052_CNTRL);
 330        val |= PLX9052_CNTRL_UIO2_DATA;
 331        outl(val, devpriv->plx_regbase + PLX9052_CNTRL);
 332
 333        /* Init Xilinx with CS1 */
 334        inb(xilinx_iobase + 0xC8);
 335
 336        /* Wait until /INIT pin is set */
 337        usleep_range(20, 1000);
 338        val = inl(devpriv->plx_regbase + PLX9052_INTCSR);
 339        if (!(val & PLX9052_INTCSR_LI2STAT)) {
 340                dev_err(dev->class_dev, "Can't init Xilinx\n");
 341                return -EIO;
 342        }
 343
 344        /* Reset /CS and /WRITE of the Xilinx */
 345        val = inl(devpriv->plx_regbase + PLX9052_CNTRL);
 346        val &= ~PLX9052_CNTRL_UIO2_DATA;
 347        outl(val, devpriv->plx_regbase + PLX9052_CNTRL);
 348
 349        /* Download Xilinx firmware */
 350        file_length = (((unsigned int)data[0] & 0xff) << 24) +
 351                      (((unsigned int)data[1] & 0xff) << 16) +
 352                      (((unsigned int)data[2] & 0xff) << 8) +
 353                      ((unsigned int)data[3] & 0xff);
 354        usleep_range(10, 1000);
 355
 356        for (i = 0; i < file_length; i++) {
 357                outb(data[16 + i], xilinx_iobase);
 358                usleep_range(10, 1000);
 359
 360                /* Check if BUSY flag is low */
 361                val = inl(devpriv->plx_regbase + PLX9052_CNTRL);
 362                if (val & PLX9052_CNTRL_UIO1_DATA) {
 363                        dev_err(dev->class_dev,
 364                                "Xilinx is still busy (i = %d)\n", i);
 365                        return -EIO;
 366                }
 367        }
 368
 369        /* If done flag is high download was successful */
 370        val = inl(devpriv->plx_regbase + PLX9052_CNTRL);
 371        if (!(val & PLX9052_CNTRL_UIO0_DATA)) {
 372                dev_err(dev->class_dev, "DONE flag is not set\n");
 373                dev_err(dev->class_dev, "Download not successful\n");
 374                return -EIO;
 375        }
 376
 377        /* Set /CS and /WRITE */
 378        val = inl(devpriv->plx_regbase + PLX9052_CNTRL);
 379        val |= PLX9052_CNTRL_UIO2_DATA;
 380        outl(val, devpriv->plx_regbase + PLX9052_CNTRL);
 381
 382        return 0;
 383}
 384
 385static void me4000_ai_reset(struct comedi_device *dev)
 386{
 387        unsigned int ctrl;
 388
 389        /* Stop any running conversion */
 390        ctrl = inl(dev->iobase + ME4000_AI_CTRL_REG);
 391        ctrl |= ME4000_AI_CTRL_STOP | ME4000_AI_CTRL_IMMEDIATE_STOP;
 392        outl(ctrl, dev->iobase + ME4000_AI_CTRL_REG);
 393
 394        /* Clear the control register */
 395        outl(0x0, dev->iobase + ME4000_AI_CTRL_REG);
 396}
 397
 398static void me4000_reset(struct comedi_device *dev)
 399{
 400        struct me4000_private *devpriv = dev->private;
 401        unsigned int val;
 402        int chan;
 403
 404        /* Disable interrupts on the PLX */
 405        outl(0, devpriv->plx_regbase + PLX9052_INTCSR);
 406
 407        /* Software reset the PLX */
 408        val = inl(devpriv->plx_regbase + PLX9052_CNTRL);
 409        val |= PLX9052_CNTRL_PCI_RESET;
 410        outl(val, devpriv->plx_regbase + PLX9052_CNTRL);
 411        val &= ~PLX9052_CNTRL_PCI_RESET;
 412        outl(val, devpriv->plx_regbase + PLX9052_CNTRL);
 413
 414        /* 0x8000 to the DACs means an output voltage of 0V */
 415        for (chan = 0; chan < 4; chan++)
 416                outl(0x8000, dev->iobase + ME4000_AO_SINGLE_REG(chan));
 417
 418        me4000_ai_reset(dev);
 419
 420        /* Set both stop bits in the analog output control register */
 421        val = ME4000_AO_CTRL_IMMEDIATE_STOP | ME4000_AO_CTRL_STOP;
 422        for (chan = 0; chan < 4; chan++)
 423                outl(val, dev->iobase + ME4000_AO_CTRL_REG(chan));
 424
 425        /* Set the adustment register for AO demux */
 426        outl(ME4000_AO_DEMUX_ADJUST_VALUE,
 427             dev->iobase + ME4000_AO_DEMUX_ADJUST_REG);
 428
 429        /*
 430         * Set digital I/O direction for port 0
 431         * to output on isolated versions
 432         */
 433        if (!(inl(dev->iobase + ME4000_DIO_DIR_REG) & 0x1))
 434                outl(0x1, dev->iobase + ME4000_DIO_CTRL_REG);
 435}
 436
 437static unsigned int me4000_ai_get_sample(struct comedi_device *dev,
 438                                         struct comedi_subdevice *s)
 439{
 440        unsigned int val;
 441
 442        /* read two's complement value and munge to offset binary */
 443        val = inl(dev->iobase + ME4000_AI_DATA_REG);
 444        return comedi_offset_munge(s, val);
 445}
 446
 447static int me4000_ai_eoc(struct comedi_device *dev,
 448                         struct comedi_subdevice *s,
 449                         struct comedi_insn *insn,
 450                         unsigned long context)
 451{
 452        unsigned int status;
 453
 454        status = inl(dev->iobase + ME4000_AI_STATUS_REG);
 455        if (status & ME4000_AI_STATUS_EF_DATA)
 456                return 0;
 457        return -EBUSY;
 458}
 459
 460static int me4000_ai_insn_read(struct comedi_device *dev,
 461                               struct comedi_subdevice *s,
 462                               struct comedi_insn *insn,
 463                               unsigned int *data)
 464{
 465        unsigned int chan = CR_CHAN(insn->chanspec);
 466        unsigned int range = CR_RANGE(insn->chanspec);
 467        unsigned int aref = CR_AREF(insn->chanspec);
 468        unsigned int entry;
 469        int ret = 0;
 470        int i;
 471
 472        entry = chan | ME4000_AI_LIST_RANGE(range);
 473        if (aref == AREF_DIFF) {
 474                if (!(s->subdev_flags & SDF_DIFF)) {
 475                        dev_err(dev->class_dev,
 476                                "Differential inputs are not available\n");
 477                        return -EINVAL;
 478                }
 479
 480                if (!comedi_range_is_bipolar(s, range)) {
 481                        dev_err(dev->class_dev,
 482                                "Range must be bipolar when aref = diff\n");
 483                        return -EINVAL;
 484                }
 485
 486                if (chan >= (s->n_chan / 2)) {
 487                        dev_err(dev->class_dev,
 488                                "Analog input is not available\n");
 489                        return -EINVAL;
 490                }
 491                entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL;
 492        }
 493
 494        entry |= ME4000_AI_LIST_LAST_ENTRY;
 495
 496        /* Enable channel list and data fifo for single acquisition mode */
 497        outl(ME4000_AI_CTRL_CHANNEL_FIFO | ME4000_AI_CTRL_DATA_FIFO,
 498             dev->iobase + ME4000_AI_CTRL_REG);
 499
 500        /* Generate channel list entry */
 501        outl(entry, dev->iobase + ME4000_AI_CHANNEL_LIST_REG);
 502
 503        /* Set the timer to maximum sample rate */
 504        outl(ME4000_AI_MIN_TICKS, dev->iobase + ME4000_AI_CHAN_TIMER_REG);
 505        outl(ME4000_AI_MIN_TICKS, dev->iobase + ME4000_AI_CHAN_PRE_TIMER_REG);
 506
 507        for (i = 0; i < insn->n; i++) {
 508                unsigned int val;
 509
 510                /* start conversion by dummy read */
 511                inl(dev->iobase + ME4000_AI_START_REG);
 512
 513                ret = comedi_timeout(dev, s, insn, me4000_ai_eoc, 0);
 514                if (ret)
 515                        break;
 516
 517                val = me4000_ai_get_sample(dev, s);
 518                data[i] = comedi_offset_munge(s, val);
 519        }
 520
 521        me4000_ai_reset(dev);
 522
 523        return ret ? ret : insn->n;
 524}
 525
 526static int me4000_ai_cancel(struct comedi_device *dev,
 527                            struct comedi_subdevice *s)
 528{
 529        me4000_ai_reset(dev);
 530
 531        return 0;
 532}
 533
 534static int me4000_ai_check_chanlist(struct comedi_device *dev,
 535                                    struct comedi_subdevice *s,
 536                                    struct comedi_cmd *cmd)
 537{
 538        unsigned int aref0 = CR_AREF(cmd->chanlist[0]);
 539        int i;
 540
 541        for (i = 0; i < cmd->chanlist_len; i++) {
 542                unsigned int chan = CR_CHAN(cmd->chanlist[i]);
 543                unsigned int range = CR_RANGE(cmd->chanlist[i]);
 544                unsigned int aref = CR_AREF(cmd->chanlist[i]);
 545
 546                if (aref != aref0) {
 547                        dev_dbg(dev->class_dev,
 548                                "Mode is not equal for all entries\n");
 549                        return -EINVAL;
 550                }
 551
 552                if (aref == AREF_DIFF) {
 553                        if (!(s->subdev_flags & SDF_DIFF)) {
 554                                dev_err(dev->class_dev,
 555                                        "Differential inputs are not available\n");
 556                                return -EINVAL;
 557                        }
 558
 559                        if (chan >= (s->n_chan / 2)) {
 560                                dev_dbg(dev->class_dev,
 561                                        "Channel number to high\n");
 562                                return -EINVAL;
 563                        }
 564
 565                        if (!comedi_range_is_bipolar(s, range)) {
 566                                dev_dbg(dev->class_dev,
 567                                        "Bipolar is not selected in differential mode\n");
 568                                return -EINVAL;
 569                        }
 570                }
 571        }
 572
 573        return 0;
 574}
 575
 576static void me4000_ai_round_cmd_args(struct comedi_device *dev,
 577                                     struct comedi_subdevice *s,
 578                                     struct comedi_cmd *cmd)
 579{
 580        struct me4000_private *devpriv = dev->private;
 581        int rest;
 582
 583        devpriv->ai_init_ticks = 0;
 584        devpriv->ai_scan_ticks = 0;
 585        devpriv->ai_chan_ticks = 0;
 586
 587        if (cmd->start_arg) {
 588                devpriv->ai_init_ticks = (cmd->start_arg * 33) / 1000;
 589                rest = (cmd->start_arg * 33) % 1000;
 590
 591                if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_NEAREST) {
 592                        if (rest > 33)
 593                                devpriv->ai_init_ticks++;
 594                } else if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_UP) {
 595                        if (rest)
 596                                devpriv->ai_init_ticks++;
 597                }
 598        }
 599
 600        if (cmd->scan_begin_arg) {
 601                devpriv->ai_scan_ticks = (cmd->scan_begin_arg * 33) / 1000;
 602                rest = (cmd->scan_begin_arg * 33) % 1000;
 603
 604                if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_NEAREST) {
 605                        if (rest > 33)
 606                                devpriv->ai_scan_ticks++;
 607                } else if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_UP) {
 608                        if (rest)
 609                                devpriv->ai_scan_ticks++;
 610                }
 611        }
 612
 613        if (cmd->convert_arg) {
 614                devpriv->ai_chan_ticks = (cmd->convert_arg * 33) / 1000;
 615                rest = (cmd->convert_arg * 33) % 1000;
 616
 617                if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_NEAREST) {
 618                        if (rest > 33)
 619                                devpriv->ai_chan_ticks++;
 620                } else if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_UP) {
 621                        if (rest)
 622                                devpriv->ai_chan_ticks++;
 623                }
 624        }
 625}
 626
 627static void me4000_ai_write_chanlist(struct comedi_device *dev,
 628                                     struct comedi_subdevice *s,
 629                                     struct comedi_cmd *cmd)
 630{
 631        int i;
 632
 633        for (i = 0; i < cmd->chanlist_len; i++) {
 634                unsigned int chan = CR_CHAN(cmd->chanlist[i]);
 635                unsigned int range = CR_RANGE(cmd->chanlist[i]);
 636                unsigned int aref = CR_AREF(cmd->chanlist[i]);
 637                unsigned int entry;
 638
 639                entry = chan | ME4000_AI_LIST_RANGE(range);
 640
 641                if (aref == AREF_DIFF)
 642                        entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL;
 643
 644                if (i == (cmd->chanlist_len - 1))
 645                        entry |= ME4000_AI_LIST_LAST_ENTRY;
 646
 647                outl(entry, dev->iobase + ME4000_AI_CHANNEL_LIST_REG);
 648        }
 649}
 650
 651static int me4000_ai_do_cmd(struct comedi_device *dev,
 652                            struct comedi_subdevice *s)
 653{
 654        struct me4000_private *devpriv = dev->private;
 655        struct comedi_cmd *cmd = &s->async->cmd;
 656        unsigned int ctrl;
 657
 658        /* Write timer arguments */
 659        outl(devpriv->ai_init_ticks - 1,
 660             dev->iobase + ME4000_AI_SCAN_PRE_TIMER_LOW_REG);
 661        outl(0x0, dev->iobase + ME4000_AI_SCAN_PRE_TIMER_HIGH_REG);
 662
 663        if (devpriv->ai_scan_ticks) {
 664                outl(devpriv->ai_scan_ticks - 1,
 665                     dev->iobase + ME4000_AI_SCAN_TIMER_LOW_REG);
 666                outl(0x0, dev->iobase + ME4000_AI_SCAN_TIMER_HIGH_REG);
 667        }
 668
 669        outl(devpriv->ai_chan_ticks - 1,
 670             dev->iobase + ME4000_AI_CHAN_PRE_TIMER_REG);
 671        outl(devpriv->ai_chan_ticks - 1,
 672             dev->iobase + ME4000_AI_CHAN_TIMER_REG);
 673
 674        /* Start sources */
 675        ctrl = devpriv->ai_ctrl_mode |
 676               ME4000_AI_CTRL_CHANNEL_FIFO |
 677               ME4000_AI_CTRL_DATA_FIFO;
 678
 679        /* Stop triggers */
 680        if (cmd->stop_src == TRIG_COUNT) {
 681                outl(cmd->chanlist_len * cmd->stop_arg,
 682                     dev->iobase + ME4000_AI_SAMPLE_COUNTER_REG);
 683                ctrl |= ME4000_AI_CTRL_SC_IRQ;
 684        } else if (cmd->stop_src == TRIG_NONE &&
 685                   cmd->scan_end_src == TRIG_COUNT) {
 686                outl(cmd->scan_end_arg,
 687                     dev->iobase + ME4000_AI_SAMPLE_COUNTER_REG);
 688                ctrl |= ME4000_AI_CTRL_SC_IRQ;
 689        }
 690        ctrl |= ME4000_AI_CTRL_HF_IRQ;
 691
 692        /* Write the setup to the control register */
 693        outl(ctrl, dev->iobase + ME4000_AI_CTRL_REG);
 694
 695        /* Write the channel list */
 696        me4000_ai_write_chanlist(dev, s, cmd);
 697
 698        /* Start acquistion by dummy read */
 699        inl(dev->iobase + ME4000_AI_START_REG);
 700
 701        return 0;
 702}
 703
 704static int me4000_ai_do_cmd_test(struct comedi_device *dev,
 705                                 struct comedi_subdevice *s,
 706                                 struct comedi_cmd *cmd)
 707{
 708        struct me4000_private *devpriv = dev->private;
 709        int err = 0;
 710
 711        /* Step 1 : check if triggers are trivially valid */
 712
 713        err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
 714        err |= comedi_check_trigger_src(&cmd->scan_begin_src,
 715                                        TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT);
 716        err |= comedi_check_trigger_src(&cmd->convert_src,
 717                                        TRIG_TIMER | TRIG_EXT);
 718        err |= comedi_check_trigger_src(&cmd->scan_end_src,
 719                                        TRIG_NONE | TRIG_COUNT);
 720        err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_NONE | TRIG_COUNT);
 721
 722        if (err)
 723                return 1;
 724
 725        /* Step 2a : make sure trigger sources are unique */
 726
 727        err |= comedi_check_trigger_is_unique(cmd->start_src);
 728        err |= comedi_check_trigger_is_unique(cmd->scan_begin_src);
 729        err |= comedi_check_trigger_is_unique(cmd->convert_src);
 730        err |= comedi_check_trigger_is_unique(cmd->scan_end_src);
 731        err |= comedi_check_trigger_is_unique(cmd->stop_src);
 732
 733        /* Step 2b : and mutually compatible */
 734
 735        if (cmd->start_src == TRIG_NOW &&
 736            cmd->scan_begin_src == TRIG_TIMER &&
 737            cmd->convert_src == TRIG_TIMER) {
 738                devpriv->ai_ctrl_mode = ME4000_AI_CTRL_MODE_0;
 739        } else if (cmd->start_src == TRIG_NOW &&
 740                   cmd->scan_begin_src == TRIG_FOLLOW &&
 741                   cmd->convert_src == TRIG_TIMER) {
 742                devpriv->ai_ctrl_mode = ME4000_AI_CTRL_MODE_0;
 743        } else if (cmd->start_src == TRIG_EXT &&
 744                   cmd->scan_begin_src == TRIG_TIMER &&
 745                   cmd->convert_src == TRIG_TIMER) {
 746                devpriv->ai_ctrl_mode = ME4000_AI_CTRL_MODE_1;
 747        } else if (cmd->start_src == TRIG_EXT &&
 748                   cmd->scan_begin_src == TRIG_FOLLOW &&
 749                   cmd->convert_src == TRIG_TIMER) {
 750                devpriv->ai_ctrl_mode = ME4000_AI_CTRL_MODE_1;
 751        } else if (cmd->start_src == TRIG_EXT &&
 752                   cmd->scan_begin_src == TRIG_EXT &&
 753                   cmd->convert_src == TRIG_TIMER) {
 754                devpriv->ai_ctrl_mode = ME4000_AI_CTRL_MODE_2;
 755        } else if (cmd->start_src == TRIG_EXT &&
 756                   cmd->scan_begin_src == TRIG_EXT &&
 757                   cmd->convert_src == TRIG_EXT) {
 758                devpriv->ai_ctrl_mode = ME4000_AI_CTRL_MODE_0 |
 759                                        ME4000_AI_CTRL_MODE_1;
 760        } else {
 761                err |= -EINVAL;
 762        }
 763
 764        if (err)
 765                return 2;
 766
 767        /* Step 3: check if arguments are trivially valid */
 768
 769        err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
 770
 771        if (cmd->chanlist_len < 1) {
 772                cmd->chanlist_len = 1;
 773                err |= -EINVAL;
 774        }
 775
 776        /* Round the timer arguments */
 777        me4000_ai_round_cmd_args(dev, s, cmd);
 778
 779        if (devpriv->ai_init_ticks < 66) {
 780                cmd->start_arg = 2000;
 781                err |= -EINVAL;
 782        }
 783        if (devpriv->ai_scan_ticks && devpriv->ai_scan_ticks < 67) {
 784                cmd->scan_begin_arg = 2031;
 785                err |= -EINVAL;
 786        }
 787        if (devpriv->ai_chan_ticks < 66) {
 788                cmd->convert_arg = 2000;
 789                err |= -EINVAL;
 790        }
 791
 792        if (cmd->stop_src == TRIG_COUNT)
 793                err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
 794        else    /* TRIG_NONE */
 795                err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
 796
 797        if (err)
 798                return 3;
 799
 800        /*
 801         * Stage 4. Check for argument conflicts.
 802         */
 803        if (cmd->start_src == TRIG_NOW &&
 804            cmd->scan_begin_src == TRIG_TIMER &&
 805            cmd->convert_src == TRIG_TIMER) {
 806                /* Check timer arguments */
 807                if (devpriv->ai_init_ticks < ME4000_AI_MIN_TICKS) {
 808                        dev_err(dev->class_dev, "Invalid start arg\n");
 809                        cmd->start_arg = 2000;  /*  66 ticks at least */
 810                        err++;
 811                }
 812                if (devpriv->ai_chan_ticks < ME4000_AI_MIN_TICKS) {
 813                        dev_err(dev->class_dev, "Invalid convert arg\n");
 814                        cmd->convert_arg = 2000;        /*  66 ticks at least */
 815                        err++;
 816                }
 817                if (devpriv->ai_scan_ticks <=
 818                    cmd->chanlist_len * devpriv->ai_chan_ticks) {
 819                        dev_err(dev->class_dev, "Invalid scan end arg\n");
 820
 821                        /*  At least one tick more */
 822                        cmd->scan_end_arg = 2000 * cmd->chanlist_len + 31;
 823                        err++;
 824                }
 825        } else if (cmd->start_src == TRIG_NOW &&
 826                   cmd->scan_begin_src == TRIG_FOLLOW &&
 827                   cmd->convert_src == TRIG_TIMER) {
 828                /* Check timer arguments */
 829                if (devpriv->ai_init_ticks < ME4000_AI_MIN_TICKS) {
 830                        dev_err(dev->class_dev, "Invalid start arg\n");
 831                        cmd->start_arg = 2000;  /*  66 ticks at least */
 832                        err++;
 833                }
 834                if (devpriv->ai_chan_ticks < ME4000_AI_MIN_TICKS) {
 835                        dev_err(dev->class_dev, "Invalid convert arg\n");
 836                        cmd->convert_arg = 2000;        /*  66 ticks at least */
 837                        err++;
 838                }
 839        } else if (cmd->start_src == TRIG_EXT &&
 840                   cmd->scan_begin_src == TRIG_TIMER &&
 841                   cmd->convert_src == TRIG_TIMER) {
 842                /* Check timer arguments */
 843                if (devpriv->ai_init_ticks < ME4000_AI_MIN_TICKS) {
 844                        dev_err(dev->class_dev, "Invalid start arg\n");
 845                        cmd->start_arg = 2000;  /*  66 ticks at least */
 846                        err++;
 847                }
 848                if (devpriv->ai_chan_ticks < ME4000_AI_MIN_TICKS) {
 849                        dev_err(dev->class_dev, "Invalid convert arg\n");
 850                        cmd->convert_arg = 2000;        /*  66 ticks at least */
 851                        err++;
 852                }
 853                if (devpriv->ai_scan_ticks <=
 854                    cmd->chanlist_len * devpriv->ai_chan_ticks) {
 855                        dev_err(dev->class_dev, "Invalid scan end arg\n");
 856
 857                        /*  At least one tick more */
 858                        cmd->scan_end_arg = 2000 * cmd->chanlist_len + 31;
 859                        err++;
 860                }
 861        } else if (cmd->start_src == TRIG_EXT &&
 862                   cmd->scan_begin_src == TRIG_FOLLOW &&
 863                   cmd->convert_src == TRIG_TIMER) {
 864                /* Check timer arguments */
 865                if (devpriv->ai_init_ticks < ME4000_AI_MIN_TICKS) {
 866                        dev_err(dev->class_dev, "Invalid start arg\n");
 867                        cmd->start_arg = 2000;  /*  66 ticks at least */
 868                        err++;
 869                }
 870                if (devpriv->ai_chan_ticks < ME4000_AI_MIN_TICKS) {
 871                        dev_err(dev->class_dev, "Invalid convert arg\n");
 872                        cmd->convert_arg = 2000;        /*  66 ticks at least */
 873                        err++;
 874                }
 875        } else if (cmd->start_src == TRIG_EXT &&
 876                   cmd->scan_begin_src == TRIG_EXT &&
 877                   cmd->convert_src == TRIG_TIMER) {
 878                /* Check timer arguments */
 879                if (devpriv->ai_init_ticks < ME4000_AI_MIN_TICKS) {
 880                        dev_err(dev->class_dev, "Invalid start arg\n");
 881                        cmd->start_arg = 2000;  /*  66 ticks at least */
 882                        err++;
 883                }
 884                if (devpriv->ai_chan_ticks < ME4000_AI_MIN_TICKS) {
 885                        dev_err(dev->class_dev, "Invalid convert arg\n");
 886                        cmd->convert_arg = 2000;        /*  66 ticks at least */
 887                        err++;
 888                }
 889        } else if (cmd->start_src == TRIG_EXT &&
 890                   cmd->scan_begin_src == TRIG_EXT &&
 891                   cmd->convert_src == TRIG_EXT) {
 892                /* Check timer arguments */
 893                if (devpriv->ai_init_ticks < ME4000_AI_MIN_TICKS) {
 894                        dev_err(dev->class_dev, "Invalid start arg\n");
 895                        cmd->start_arg = 2000;  /*  66 ticks at least */
 896                        err++;
 897                }
 898        }
 899        if (cmd->scan_end_src == TRIG_COUNT) {
 900                if (cmd->scan_end_arg == 0) {
 901                        dev_err(dev->class_dev, "Invalid scan end arg\n");
 902                        cmd->scan_end_arg = 1;
 903                        err++;
 904                }
 905        }
 906
 907        if (err)
 908                return 4;
 909
 910        /* Step 5: check channel list if it exists */
 911        if (cmd->chanlist && cmd->chanlist_len > 0)
 912                err |= me4000_ai_check_chanlist(dev, s, cmd);
 913
 914        if (err)
 915                return 5;
 916
 917        return 0;
 918}
 919
 920static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
 921{
 922        unsigned int tmp;
 923        struct comedi_device *dev = dev_id;
 924        struct comedi_subdevice *s = dev->read_subdev;
 925        int i;
 926        int c = 0;
 927        unsigned int lval;
 928
 929        if (!dev->attached)
 930                return IRQ_NONE;
 931
 932        if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) &
 933            ME4000_IRQ_STATUS_AI_HF) {
 934                /* Read status register to find out what happened */
 935                tmp = inl(dev->iobase + ME4000_AI_STATUS_REG);
 936
 937                if (!(tmp & ME4000_AI_STATUS_FF_DATA) &&
 938                    !(tmp & ME4000_AI_STATUS_HF_DATA) &&
 939                    (tmp & ME4000_AI_STATUS_EF_DATA)) {
 940                        dev_err(dev->class_dev, "FIFO overflow\n");
 941                        s->async->events |= COMEDI_CB_ERROR;
 942                        c = ME4000_AI_FIFO_COUNT;
 943                } else if ((tmp & ME4000_AI_STATUS_FF_DATA) &&
 944                           !(tmp & ME4000_AI_STATUS_HF_DATA) &&
 945                           (tmp & ME4000_AI_STATUS_EF_DATA)) {
 946                        c = ME4000_AI_FIFO_COUNT / 2;
 947                } else {
 948                        dev_err(dev->class_dev, "Undefined FIFO state\n");
 949                        s->async->events |= COMEDI_CB_ERROR;
 950                        c = 0;
 951                }
 952
 953                for (i = 0; i < c; i++) {
 954                        lval = me4000_ai_get_sample(dev, s);
 955                        if (!comedi_buf_write_samples(s, &lval, 1))
 956                                break;
 957                }
 958
 959                /* Work is done, so reset the interrupt */
 960                tmp |= ME4000_AI_CTRL_HF_IRQ_RESET;
 961                outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
 962                tmp &= ~ME4000_AI_CTRL_HF_IRQ_RESET;
 963                outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
 964        }
 965
 966        if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) &
 967            ME4000_IRQ_STATUS_SC) {
 968                /* Acquisition is complete */
 969                s->async->events |= COMEDI_CB_EOA;
 970
 971                /* Poll data until fifo empty */
 972                while (inl(dev->iobase + ME4000_AI_STATUS_REG) &
 973                       ME4000_AI_STATUS_EF_DATA) {
 974                        lval = me4000_ai_get_sample(dev, s);
 975                        if (!comedi_buf_write_samples(s, &lval, 1))
 976                                break;
 977                }
 978
 979                /* Work is done, so reset the interrupt */
 980                tmp = inl(dev->iobase + ME4000_AI_CTRL_REG);
 981                tmp |= ME4000_AI_CTRL_SC_IRQ_RESET;
 982                outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
 983                tmp &= ~ME4000_AI_CTRL_SC_IRQ_RESET;
 984                outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
 985        }
 986
 987        comedi_handle_events(dev, s);
 988
 989        return IRQ_HANDLED;
 990}
 991
 992static int me4000_ao_insn_write(struct comedi_device *dev,
 993                                struct comedi_subdevice *s,
 994                                struct comedi_insn *insn,
 995                                unsigned int *data)
 996{
 997        unsigned int chan = CR_CHAN(insn->chanspec);
 998        unsigned int tmp;
 999
1000        /* Stop any running conversion */
1001        tmp = inl(dev->iobase + ME4000_AO_CTRL_REG(chan));
1002        tmp |= ME4000_AO_CTRL_IMMEDIATE_STOP;
1003        outl(tmp, dev->iobase + ME4000_AO_CTRL_REG(chan));
1004
1005        /* Clear control register and set to single mode */
1006        outl(0x0, dev->iobase + ME4000_AO_CTRL_REG(chan));
1007
1008        /* Write data value */
1009        outl(data[0], dev->iobase + ME4000_AO_SINGLE_REG(chan));
1010
1011        /* Store in the mirror */
1012        s->readback[chan] = data[0];
1013
1014        return 1;
1015}
1016
1017static int me4000_dio_insn_bits(struct comedi_device *dev,
1018                                struct comedi_subdevice *s,
1019                                struct comedi_insn *insn,
1020                                unsigned int *data)
1021{
1022        if (comedi_dio_update_state(s, data)) {
1023                outl((s->state >> 0) & 0xFF,
1024                     dev->iobase + ME4000_DIO_PORT_0_REG);
1025                outl((s->state >> 8) & 0xFF,
1026                     dev->iobase + ME4000_DIO_PORT_1_REG);
1027                outl((s->state >> 16) & 0xFF,
1028                     dev->iobase + ME4000_DIO_PORT_2_REG);
1029                outl((s->state >> 24) & 0xFF,
1030                     dev->iobase + ME4000_DIO_PORT_3_REG);
1031        }
1032
1033        data[1] = ((inl(dev->iobase + ME4000_DIO_PORT_0_REG) & 0xFF) << 0) |
1034                  ((inl(dev->iobase + ME4000_DIO_PORT_1_REG) & 0xFF) << 8) |
1035                  ((inl(dev->iobase + ME4000_DIO_PORT_2_REG) & 0xFF) << 16) |
1036                  ((inl(dev->iobase + ME4000_DIO_PORT_3_REG) & 0xFF) << 24);
1037
1038        return insn->n;
1039}
1040
1041static int me4000_dio_insn_config(struct comedi_device *dev,
1042                                  struct comedi_subdevice *s,
1043                                  struct comedi_insn *insn,
1044                                  unsigned int *data)
1045{
1046        unsigned int chan = CR_CHAN(insn->chanspec);
1047        unsigned int mask;
1048        unsigned int tmp;
1049        int ret;
1050
1051        if (chan < 8)
1052                mask = 0x000000ff;
1053        else if (chan < 16)
1054                mask = 0x0000ff00;
1055        else if (chan < 24)
1056                mask = 0x00ff0000;
1057        else
1058                mask = 0xff000000;
1059
1060        ret = comedi_dio_insn_config(dev, s, insn, data, mask);
1061        if (ret)
1062                return ret;
1063
1064        tmp = inl(dev->iobase + ME4000_DIO_CTRL_REG);
1065        tmp &= ~(ME4000_DIO_CTRL_MODE_0 | ME4000_DIO_CTRL_MODE_1 |
1066                 ME4000_DIO_CTRL_MODE_2 | ME4000_DIO_CTRL_MODE_3 |
1067                 ME4000_DIO_CTRL_MODE_4 | ME4000_DIO_CTRL_MODE_5 |
1068                 ME4000_DIO_CTRL_MODE_6 | ME4000_DIO_CTRL_MODE_7);
1069        if (s->io_bits & 0x000000ff)
1070                tmp |= ME4000_DIO_CTRL_MODE_0;
1071        if (s->io_bits & 0x0000ff00)
1072                tmp |= ME4000_DIO_CTRL_MODE_2;
1073        if (s->io_bits & 0x00ff0000)
1074                tmp |= ME4000_DIO_CTRL_MODE_4;
1075        if (s->io_bits & 0xff000000)
1076                tmp |= ME4000_DIO_CTRL_MODE_6;
1077
1078        /*
1079         * Check for optoisolated ME-4000 version.
1080         * If one the first port is a fixed output
1081         * port and the second is a fixed input port.
1082         */
1083        if (inl(dev->iobase + ME4000_DIO_DIR_REG)) {
1084                s->io_bits |= 0x000000ff;
1085                s->io_bits &= ~0x0000ff00;
1086                tmp |= ME4000_DIO_CTRL_MODE_0;
1087                tmp &= ~(ME4000_DIO_CTRL_MODE_2 | ME4000_DIO_CTRL_MODE_3);
1088        }
1089
1090        outl(tmp, dev->iobase + ME4000_DIO_CTRL_REG);
1091
1092        return insn->n;
1093}
1094
1095static int me4000_auto_attach(struct comedi_device *dev,
1096                              unsigned long context)
1097{
1098        struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1099        const struct me4000_board *board = NULL;
1100        struct me4000_private *devpriv;
1101        struct comedi_subdevice *s;
1102        int result;
1103
1104        if (context < ARRAY_SIZE(me4000_boards))
1105                board = &me4000_boards[context];
1106        if (!board)
1107                return -ENODEV;
1108        dev->board_ptr = board;
1109        dev->board_name = board->name;
1110
1111        devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1112        if (!devpriv)
1113                return -ENOMEM;
1114
1115        result = comedi_pci_enable(dev);
1116        if (result)
1117                return result;
1118
1119        devpriv->plx_regbase = pci_resource_start(pcidev, 1);
1120        dev->iobase = pci_resource_start(pcidev, 2);
1121        if (!devpriv->plx_regbase || !dev->iobase)
1122                return -ENODEV;
1123
1124        result = comedi_load_firmware(dev, &pcidev->dev, ME4000_FIRMWARE,
1125                                      me4000_xilinx_download, 0);
1126        if (result < 0)
1127                return result;
1128
1129        me4000_reset(dev);
1130
1131        if (pcidev->irq > 0) {
1132                result = request_irq(pcidev->irq, me4000_ai_isr, IRQF_SHARED,
1133                                     dev->board_name, dev);
1134                if (result == 0) {
1135                        dev->irq = pcidev->irq;
1136
1137                        /* Enable interrupts on the PLX */
1138                        outl(PLX9052_INTCSR_LI1ENAB | PLX9052_INTCSR_LI1POL |
1139                             PLX9052_INTCSR_PCIENAB,
1140                             devpriv->plx_regbase + PLX9052_INTCSR);
1141                }
1142        }
1143
1144        result = comedi_alloc_subdevices(dev, 4);
1145        if (result)
1146                return result;
1147
1148        /* Analog Input subdevice */
1149        s = &dev->subdevices[0];
1150        s->type         = COMEDI_SUBD_AI;
1151        s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1152        if (board->can_do_diff_ai)
1153                s->subdev_flags |= SDF_DIFF;
1154        s->n_chan       = board->ai_nchan;
1155        s->maxdata      = 0xffff;
1156        s->len_chanlist = ME4000_AI_CHANNEL_LIST_COUNT;
1157        s->range_table  = &me4000_ai_range;
1158        s->insn_read    = me4000_ai_insn_read;
1159
1160        if (dev->irq) {
1161                dev->read_subdev = s;
1162                s->subdev_flags |= SDF_CMD_READ;
1163                s->cancel       = me4000_ai_cancel;
1164                s->do_cmdtest   = me4000_ai_do_cmd_test;
1165                s->do_cmd       = me4000_ai_do_cmd;
1166        }
1167
1168        /* Analog Output subdevice */
1169        s = &dev->subdevices[1];
1170        if (board->has_ao) {
1171                s->type         = COMEDI_SUBD_AO;
1172                s->subdev_flags = SDF_WRITABLE | SDF_COMMON | SDF_GROUND;
1173                s->n_chan       = 4;
1174                s->maxdata      = 0xffff;
1175                s->range_table  = &range_bipolar10;
1176                s->insn_write   = me4000_ao_insn_write;
1177
1178                result = comedi_alloc_subdev_readback(s);
1179                if (result)
1180                        return result;
1181        } else {
1182                s->type         = COMEDI_SUBD_UNUSED;
1183        }
1184
1185        /* Digital I/O subdevice */
1186        s = &dev->subdevices[2];
1187        s->type         = COMEDI_SUBD_DIO;
1188        s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1189        s->n_chan       = 32;
1190        s->maxdata      = 1;
1191        s->range_table  = &range_digital;
1192        s->insn_bits    = me4000_dio_insn_bits;
1193        s->insn_config  = me4000_dio_insn_config;
1194
1195        /*
1196         * Check for optoisolated ME-4000 version. If one the first
1197         * port is a fixed output port and the second is a fixed input port.
1198         */
1199        if (!inl(dev->iobase + ME4000_DIO_DIR_REG)) {
1200                s->io_bits |= 0xFF;
1201                outl(ME4000_DIO_CTRL_MODE_0,
1202                     dev->iobase + ME4000_DIO_DIR_REG);
1203        }
1204
1205        /* Counter subdevice (8254) */
1206        s = &dev->subdevices[3];
1207        if (board->has_counter) {
1208                unsigned long timer_base = pci_resource_start(pcidev, 3);
1209
1210                if (!timer_base)
1211                        return -ENODEV;
1212
1213                dev->pacer = comedi_8254_init(timer_base, 0, I8254_IO8, 0);
1214                if (!dev->pacer)
1215                        return -ENOMEM;
1216
1217                comedi_8254_subdevice_init(s, dev->pacer);
1218        } else {
1219                s->type = COMEDI_SUBD_UNUSED;
1220        }
1221
1222        return 0;
1223}
1224
1225static void me4000_detach(struct comedi_device *dev)
1226{
1227        if (dev->irq) {
1228                struct me4000_private *devpriv = dev->private;
1229
1230                /* Disable interrupts on the PLX */
1231                outl(0, devpriv->plx_regbase + PLX9052_INTCSR);
1232        }
1233        comedi_pci_detach(dev);
1234}
1235
1236static struct comedi_driver me4000_driver = {
1237        .driver_name    = "me4000",
1238        .module         = THIS_MODULE,
1239        .auto_attach    = me4000_auto_attach,
1240        .detach         = me4000_detach,
1241};
1242
1243static int me4000_pci_probe(struct pci_dev *dev,
1244                            const struct pci_device_id *id)
1245{
1246        return comedi_pci_auto_config(dev, &me4000_driver, id->driver_data);
1247}
1248
1249static const struct pci_device_id me4000_pci_table[] = {
1250        { PCI_VDEVICE(MEILHAUS, 0x4650), BOARD_ME4650 },
1251        { PCI_VDEVICE(MEILHAUS, 0x4660), BOARD_ME4660 },
1252        { PCI_VDEVICE(MEILHAUS, 0x4661), BOARD_ME4660I },
1253        { PCI_VDEVICE(MEILHAUS, 0x4662), BOARD_ME4660S },
1254        { PCI_VDEVICE(MEILHAUS, 0x4663), BOARD_ME4660IS },
1255        { PCI_VDEVICE(MEILHAUS, 0x4670), BOARD_ME4670 },
1256        { PCI_VDEVICE(MEILHAUS, 0x4671), BOARD_ME4670I },
1257        { PCI_VDEVICE(MEILHAUS, 0x4672), BOARD_ME4670S },
1258        { PCI_VDEVICE(MEILHAUS, 0x4673), BOARD_ME4670IS },
1259        { PCI_VDEVICE(MEILHAUS, 0x4680), BOARD_ME4680 },
1260        { PCI_VDEVICE(MEILHAUS, 0x4681), BOARD_ME4680I },
1261        { PCI_VDEVICE(MEILHAUS, 0x4682), BOARD_ME4680S },
1262        { PCI_VDEVICE(MEILHAUS, 0x4683), BOARD_ME4680IS },
1263        { 0 }
1264};
1265MODULE_DEVICE_TABLE(pci, me4000_pci_table);
1266
1267static struct pci_driver me4000_pci_driver = {
1268        .name           = "me4000",
1269        .id_table       = me4000_pci_table,
1270        .probe          = me4000_pci_probe,
1271        .remove         = comedi_pci_auto_unconfig,
1272};
1273module_comedi_pci_driver(me4000_driver, me4000_pci_driver);
1274
1275MODULE_AUTHOR("Comedi https://www.comedi.org");
1276MODULE_DESCRIPTION("Comedi driver for Meilhaus ME-4000 series boards");
1277MODULE_LICENSE("GPL");
1278MODULE_FIRMWARE(ME4000_FIRMWARE);
1279