linux/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
<<
>>
Prefs
   1/**
   2@verbatim
   3
   4Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
   5
   6        ADDI-DATA GmbH
   7        Dieselstrasse 3
   8        D-77833 Ottersweier
   9        Tel: +19(0)7223/9493-0
  10        Fax: +49(0)7223/9493-92
  11        http://www.addi-data-com
  12        info@addi-data.com
  13
  14This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
  15
  16This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  17
  18You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19
  20You should also find the complete GPL in the COPYING file accompanying this source code.
  21
  22@endverbatim
  23*/
  24/*
  25  +-----------------------------------------------------------------------+
  26  | (C) ADDI-DATA GmbH          Dieselstrasse 3      D-77833 Ottersweier  |
  27  +-----------------------------------------------------------------------+
  28  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
  29  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
  30  +-----------------------------------------------------------------------+
  31  | Project     : APCI-3120       | Compiler   : GCC                      |
  32  | Module name : hwdrv_apci3120.c| Version    : 2.96                     |
  33  +-------------------------------+---------------------------------------+
  34  | Project manager: Eric Stolz   | Date       :  02/12/2002              |
  35  +-----------------------------------------------------------------------+
  36  | Description :APCI3120 Module.  Hardware abstraction Layer for APCI3120|
  37  +-----------------------------------------------------------------------+
  38  |                             UPDATE'S                                  |
  39  +-----------------------------------------------------------------------+
  40  |   Date   |   Author  |          Description of updates                |
  41  +----------+-----------+------------------------------------------------+
  42  |          |           |                                                |
  43  |          |           |                                                |
  44  +----------+-----------+------------------------------------------------+
  45*/
  46
  47#include "hwdrv_apci3120.h"
  48static unsigned int ui_Temp;
  49
  50/* FUNCTION DEFINITIONS */
  51
  52/*
  53+----------------------------------------------------------------------------+
  54|                           ANALOG INPUT SUBDEVICE                               |
  55+----------------------------------------------------------------------------+
  56*/
  57
  58/*
  59+----------------------------------------------------------------------------+
  60| Function name     :int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev,|
  61|  struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)                                       |
  62|                                                                                                |
  63+----------------------------------------------------------------------------+
  64| Task              : Calls card specific function                                           |
  65|                                                                                                                |
  66+----------------------------------------------------------------------------+
  67| Input Parameters  : struct comedi_device *dev                                                                  |
  68|                     struct comedi_subdevice *s                                                                         |
  69|                     struct comedi_insn *insn                                      |
  70|                     unsigned int *data                                                                 |
  71+----------------------------------------------------------------------------+
  72| Return Value      :                                                                            |
  73|                                                                                                                            |
  74+----------------------------------------------------------------------------+
  75*/
  76
  77int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s,
  78        struct comedi_insn *insn, unsigned int *data)
  79{
  80        unsigned int i;
  81
  82        if ((data[0] != APCI3120_EOC_MODE) && (data[0] != APCI3120_EOS_MODE))
  83                return -1;
  84
  85        /*  Check for Conversion time to be added ?? */
  86        devpriv->ui_EocEosConversionTime = data[2];
  87
  88        if (data[0] == APCI3120_EOS_MODE) {
  89
  90                /* Test the number of the channel */
  91                for (i = 0; i < data[3]; i++) {
  92
  93                        if (CR_CHAN(data[4 + i]) >= this_board->i_NbrAiChannel) {
  94                                printk("bad channel list\n");
  95                                return -2;
  96                        }
  97                }
  98
  99                devpriv->b_InterruptMode = APCI3120_EOS_MODE;
 100
 101                if (data[1])
 102                        devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
 103                else
 104                        devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
 105                /*  Copy channel list and Range List to devpriv */
 106
 107                devpriv->ui_AiNbrofChannels = data[3];
 108                for (i = 0; i < devpriv->ui_AiNbrofChannels; i++)
 109                        devpriv->ui_AiChannelList[i] = data[4 + i];
 110
 111        } else {                        /*  EOC */
 112                devpriv->b_InterruptMode = APCI3120_EOC_MODE;
 113                if (data[1])
 114                        devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
 115                else
 116                        devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
 117        }
 118
 119        return insn->n;
 120}
 121
 122/*
 123+----------------------------------------------------------------------------+
 124| Function name     :int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev,  |
 125|                       struct comedi_subdevice *s,struct comedi_insn *insn, unsigned int *data)         |
 126|                                                                                                |
 127+----------------------------------------------------------------------------+
 128| Task              :  card specific function                                                            |
 129|                               Reads analog input in synchronous mode               |
 130|                         EOC and EOS is selected as per configured              |
 131|                     if no conversion time is set uses default conversion   |
 132|                         time 10 microsec.                                                                      |
 133|                                                                                                                |
 134+----------------------------------------------------------------------------+
 135| Input Parameters  : struct comedi_device *dev                                                                  |
 136|                     struct comedi_subdevice *s                                                                         |
 137|                     struct comedi_insn *insn                                      |
 138|                     unsigned int *data                                                                         |
 139+----------------------------------------------------------------------------+
 140| Return Value      :                                                                            |
 141|                                                                                                                            |
 142+----------------------------------------------------------------------------+
 143*/
 144
 145int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s,
 146        struct comedi_insn *insn, unsigned int *data)
 147{
 148        unsigned short us_ConvertTiming, us_TmpValue, i;
 149        unsigned char b_Tmp;
 150
 151        /*  fix convertion time to 10 us */
 152        if (!devpriv->ui_EocEosConversionTime) {
 153                printk("No timer0 Value using 10 us\n");
 154                us_ConvertTiming = 10;
 155        } else
 156                us_ConvertTiming = (unsigned short) (devpriv->ui_EocEosConversionTime / 1000);  /*  nano to useconds */
 157
 158        /*  this_board->i_hwdrv_InsnReadAnalogInput(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]); */
 159
 160        /*  Clear software registers */
 161        devpriv->b_TimerSelectMode = 0;
 162        devpriv->b_ModeSelectRegister = 0;
 163        devpriv->us_OutputRegister = 0;
 164/* devpriv->b_DigitalOutputRegister=0; */
 165
 166        if (insn->unused[0] == 222) {   /*  second insn read */
 167                for (i = 0; i < insn->n; i++)
 168                        data[i] = devpriv->ui_AiReadData[i];
 169        } else {
 170                devpriv->tsk_Current = current; /*  Save the current process task structure */
 171/*
 172 * Testing if board have the new Quartz and calculate the time value
 173 * to set in the timer
 174 */
 175
 176                us_TmpValue =
 177                        (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
 178
 179                /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */
 180                if ((us_TmpValue & 0x00B0) == 0x00B0
 181                        || !strcmp(this_board->pc_DriverName, "apci3001")) {
 182                        us_ConvertTiming = (us_ConvertTiming * 2) - 2;
 183                } else {
 184                        us_ConvertTiming =
 185                                ((us_ConvertTiming * 12926) / 10000) - 1;
 186                }
 187
 188                us_TmpValue = (unsigned short) devpriv->b_InterruptMode;
 189
 190                switch (us_TmpValue) {
 191
 192                case APCI3120_EOC_MODE:
 193
 194/*
 195 * Testing the interrupt flag and set the EOC bit Clears the FIFO
 196 */
 197                        inw(devpriv->iobase + APCI3120_RESET_FIFO);
 198
 199                        /*  Initialize the sequence array */
 200
 201                        /* if (!i_APCI3120_SetupChannelList(dev,s,1,chanlist,0))  return -EINVAL; */
 202
 203                        if (!i_APCI3120_SetupChannelList(dev, s, 1,
 204                                        &insn->chanspec, 0))
 205                                return -EINVAL;
 206
 207                        /* Initialize Timer 0 mode 4 */
 208                        devpriv->b_TimerSelectMode =
 209                                (devpriv->
 210                                b_TimerSelectMode & 0xFC) |
 211                                APCI3120_TIMER_0_MODE_4;
 212                        outb(devpriv->b_TimerSelectMode,
 213                                devpriv->iobase + APCI3120_TIMER_CRT1);
 214
 215                        /*  Reset the scan bit and Disables the  EOS, DMA, EOC interrupt */
 216                        devpriv->b_ModeSelectRegister =
 217                                devpriv->
 218                                b_ModeSelectRegister & APCI3120_DISABLE_SCAN;
 219
 220                        if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
 221
 222                                /* Disables the EOS,DMA and enables the EOC interrupt */
 223                                devpriv->b_ModeSelectRegister =
 224                                        (devpriv->
 225                                        b_ModeSelectRegister &
 226                                        APCI3120_DISABLE_EOS_INT) |
 227                                        APCI3120_ENABLE_EOC_INT;
 228                                inw(devpriv->iobase);
 229
 230                        } else {
 231                                devpriv->b_ModeSelectRegister =
 232                                        devpriv->
 233                                        b_ModeSelectRegister &
 234                                        APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER;
 235                        }
 236
 237                        outb(devpriv->b_ModeSelectRegister,
 238                                devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
 239
 240                        /*  Sets gate 0 */
 241                        devpriv->us_OutputRegister =
 242                                (devpriv->
 243                                us_OutputRegister & APCI3120_CLEAR_PA_PR) |
 244                                APCI3120_ENABLE_TIMER0;
 245                        outw(devpriv->us_OutputRegister,
 246                                devpriv->iobase + APCI3120_WR_ADDRESS);
 247
 248                        /*  Select Timer 0 */
 249                        b_Tmp = ((devpriv->
 250                                        b_DigitalOutputRegister) & 0xF0) |
 251                                APCI3120_SELECT_TIMER_0_WORD;
 252                        outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
 253
 254                        /* Set the convertion time */
 255                        outw(us_ConvertTiming,
 256                                devpriv->iobase + APCI3120_TIMER_VALUE);
 257
 258                        us_TmpValue =
 259                                (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
 260
 261                        if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
 262
 263                                do {
 264                                        /*  Waiting for the end of conversion */
 265                                        us_TmpValue =
 266                                                inw(devpriv->iobase +
 267                                                APCI3120_RD_STATUS);
 268                                } while ((us_TmpValue & APCI3120_EOC) ==
 269                                        APCI3120_EOC);
 270
 271                                /* Read the result in FIFO  and put it in insn data pointer */
 272                                us_TmpValue = inw(devpriv->iobase + 0);
 273                                *data = us_TmpValue;
 274
 275                                inw(devpriv->iobase + APCI3120_RESET_FIFO);
 276                        }
 277
 278                        break;
 279
 280                case APCI3120_EOS_MODE:
 281
 282                        inw(devpriv->iobase);
 283                        /*  Clears the FIFO */
 284                        inw(devpriv->iobase + APCI3120_RESET_FIFO);
 285                        /*  clear PA PR  and disable timer 0 */
 286
 287                        devpriv->us_OutputRegister =
 288                                (devpriv->
 289                                us_OutputRegister & APCI3120_CLEAR_PA_PR) |
 290                                APCI3120_DISABLE_TIMER0;
 291
 292                        outw(devpriv->us_OutputRegister,
 293                                devpriv->iobase + APCI3120_WR_ADDRESS);
 294
 295                        if (!i_APCI3120_SetupChannelList(dev, s,
 296                                        devpriv->ui_AiNbrofChannels,
 297                                        devpriv->ui_AiChannelList, 0))
 298                                return -EINVAL;
 299
 300                        /* Initialize Timer 0 mode 2 */
 301                        devpriv->b_TimerSelectMode =
 302                                (devpriv->
 303                                b_TimerSelectMode & 0xFC) |
 304                                APCI3120_TIMER_0_MODE_2;
 305                        outb(devpriv->b_TimerSelectMode,
 306                                devpriv->iobase + APCI3120_TIMER_CRT1);
 307
 308                        /* Select Timer 0 */
 309                        b_Tmp = ((devpriv->
 310                                        b_DigitalOutputRegister) & 0xF0) |
 311                                APCI3120_SELECT_TIMER_0_WORD;
 312                        outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
 313
 314                        /* Set the convertion time */
 315                        outw(us_ConvertTiming,
 316                                devpriv->iobase + APCI3120_TIMER_VALUE);
 317
 318                        /* Set the scan bit */
 319                        devpriv->b_ModeSelectRegister =
 320                                devpriv->
 321                                b_ModeSelectRegister | APCI3120_ENABLE_SCAN;
 322                        outb(devpriv->b_ModeSelectRegister,
 323                                devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
 324
 325                        /* If Interrupt function is loaded */
 326                        if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
 327                                /* Disables the EOC,DMA and enables the EOS interrupt */
 328                                devpriv->b_ModeSelectRegister =
 329                                        (devpriv->
 330                                        b_ModeSelectRegister &
 331                                        APCI3120_DISABLE_EOC_INT) |
 332                                        APCI3120_ENABLE_EOS_INT;
 333                                inw(devpriv->iobase);
 334
 335                        } else
 336                                devpriv->b_ModeSelectRegister =
 337                                        devpriv->
 338                                        b_ModeSelectRegister &
 339                                        APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER;
 340
 341                        outb(devpriv->b_ModeSelectRegister,
 342                                devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
 343
 344                        inw(devpriv->iobase + APCI3120_RD_STATUS);
 345
 346                        /* Sets gate 0 */
 347
 348                        devpriv->us_OutputRegister =
 349                                devpriv->
 350                                us_OutputRegister | APCI3120_ENABLE_TIMER0;
 351                        outw(devpriv->us_OutputRegister,
 352                                devpriv->iobase + APCI3120_WR_ADDRESS);
 353
 354                        /* Start conversion */
 355                        outw(0, devpriv->iobase + APCI3120_START_CONVERSION);
 356
 357                        /* Waiting of end of convertion if interrupt is not installed */
 358                        if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
 359                                /* Waiting the end of convertion */
 360                                do {
 361                                        us_TmpValue =
 362                                                inw(devpriv->iobase +
 363                                                APCI3120_RD_STATUS);
 364                                } while ((us_TmpValue & APCI3120_EOS) !=
 365                                         APCI3120_EOS);
 366
 367                                for (i = 0; i < devpriv->ui_AiNbrofChannels;
 368                                        i++) {
 369                                        /* Read the result in FIFO and write them in shared memory */
 370                                        us_TmpValue = inw(devpriv->iobase);
 371                                        data[i] = (unsigned int) us_TmpValue;
 372                                }
 373
 374                                devpriv->b_InterruptMode = APCI3120_EOC_MODE;   /*  Restore defaults. */
 375                        }
 376                        break;
 377
 378                default:
 379                        printk("inputs wrong\n");
 380
 381                }
 382                devpriv->ui_EocEosConversionTime = 0;   /*  re initializing the variable; */
 383        }
 384
 385        return insn->n;
 386
 387}
 388
 389/*
 390+----------------------------------------------------------------------------+
 391| Function name     :int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev,|
 392|                                                                                            struct comedi_subdevice *s)|
 393|                                                                                                                |
 394+----------------------------------------------------------------------------+
 395| Task              : Stops Cyclic acquisition                                                       |
 396|                                                                                                                |
 397+----------------------------------------------------------------------------+
 398| Input Parameters  : struct comedi_device *dev                                                                  |
 399|                     struct comedi_subdevice *s                                                                         |
 400|                                                                                                |
 401+----------------------------------------------------------------------------+
 402| Return Value      :0                                                                       |
 403|                                                                                                                            |
 404+----------------------------------------------------------------------------+
 405*/
 406
 407int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev, struct comedi_subdevice *s)
 408{
 409        /*  Disable A2P Fifo write and AMWEN signal */
 410        outw(0, devpriv->i_IobaseAddon + 4);
 411
 412        /* Disable Bus Master ADD ON */
 413        outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
 414        outw(0, devpriv->i_IobaseAddon + 2);
 415        outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
 416        outw(0, devpriv->i_IobaseAddon + 2);
 417
 418        /* Disable BUS Master PCI */
 419        outl(0, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
 420
 421        /* outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR)&(~AINT_WRITE_COMPL),
 422         * devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR);  stop amcc irqs */
 423
 424        /* outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR)&(~EN_A2P_TRANSFERS),
 425         * devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR);  stop DMA */
 426
 427        /* Disable ext trigger */
 428        i_APCI3120_ExttrigDisable(dev);
 429
 430        devpriv->us_OutputRegister = 0;
 431        /* stop  counters */
 432        outw(devpriv->
 433                us_OutputRegister & APCI3120_DISABLE_TIMER0 &
 434                APCI3120_DISABLE_TIMER1, dev->iobase + APCI3120_WR_ADDRESS);
 435
 436        outw(APCI3120_DISABLE_ALL_TIMER, dev->iobase + APCI3120_WR_ADDRESS);
 437
 438        /* DISABLE_ALL_INTERRUPT */
 439        outb(APCI3120_DISABLE_ALL_INTERRUPT,
 440                dev->iobase + APCI3120_WRITE_MODE_SELECT);
 441        /* Flush FIFO */
 442        inb(dev->iobase + APCI3120_RESET_FIFO);
 443        inw(dev->iobase + APCI3120_RD_STATUS);
 444        devpriv->ui_AiActualScan = 0;
 445        devpriv->ui_AiActualScanPosition = 0;
 446        s->async->cur_chan = 0;
 447        devpriv->ui_AiBufferPtr = 0;
 448        devpriv->b_AiContinuous = 0;
 449        devpriv->ui_DmaActualBuffer = 0;
 450
 451        devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
 452        devpriv->b_InterruptMode = APCI3120_EOC_MODE;
 453        devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
 454        i_APCI3120_Reset(dev);
 455        return 0;
 456}
 457
 458/*
 459+----------------------------------------------------------------------------+
 460| Function name     :int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev|
 461|                       ,struct comedi_subdevice *s,struct comedi_cmd *cmd)                                      |
 462|                                                                                                                |
 463+----------------------------------------------------------------------------+
 464| Task              : Test validity for a command for cyclic anlog input     |
 465|                       acquisition                                                                      |
 466|                                                                                                                |
 467+----------------------------------------------------------------------------+
 468| Input Parameters  : struct comedi_device *dev                                                                  |
 469|                     struct comedi_subdevice *s                                                                         |
 470|                     struct comedi_cmd *cmd                                                             |
 471+----------------------------------------------------------------------------+
 472| Return Value      :0                                                                       |
 473|                                                                                                                            |
 474+----------------------------------------------------------------------------+
 475*/
 476
 477int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s,
 478        struct comedi_cmd *cmd)
 479{
 480        int err = 0;
 481        int tmp;                /*  divisor1,divisor2; */
 482
 483        /*  step 1: make sure trigger sources are trivially valid */
 484
 485        tmp = cmd->start_src;
 486        cmd->start_src &= TRIG_NOW | TRIG_EXT;
 487        if (!cmd->start_src || tmp != cmd->start_src)
 488                err++;
 489
 490        tmp = cmd->scan_begin_src;
 491        cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW;
 492        if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
 493                err++;
 494
 495        tmp = cmd->convert_src;
 496        cmd->convert_src &= TRIG_TIMER;
 497        if (!cmd->convert_src || tmp != cmd->convert_src)
 498                err++;
 499
 500        tmp = cmd->scan_end_src;
 501        cmd->scan_end_src &= TRIG_COUNT;
 502        if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
 503                err++;
 504
 505        tmp = cmd->stop_src;
 506        cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
 507        if (!cmd->stop_src || tmp != cmd->stop_src)
 508                err++;
 509
 510        if (err)
 511                return 1;
 512
 513        /* step 2: make sure trigger sources are unique and mutually compatible */
 514
 515        if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT)
 516                err++;
 517
 518        if (cmd->scan_begin_src != TRIG_TIMER &&
 519                cmd->scan_begin_src != TRIG_FOLLOW)
 520                err++;
 521
 522        if (cmd->convert_src != TRIG_TIMER)
 523                err++;
 524
 525        if (cmd->scan_end_src != TRIG_COUNT) {
 526                cmd->scan_end_src = TRIG_COUNT;
 527                err++;
 528        }
 529
 530        if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
 531                err++;
 532
 533        if (err)
 534                return 2;
 535
 536        /*  step 3: make sure arguments are trivially compatible */
 537
 538        if (cmd->start_arg != 0) {
 539                cmd->start_arg = 0;
 540                err++;
 541        }
 542
 543        if (cmd->scan_begin_src == TRIG_TIMER) {        /*  Test Delay timing */
 544                if (cmd->scan_begin_arg < this_board->ui_MinDelaytimeNs) {
 545                        cmd->scan_begin_arg = this_board->ui_MinDelaytimeNs;
 546                        err++;
 547                }
 548        }
 549
 550        if (cmd->convert_src == TRIG_TIMER) {   /*  Test Acquisition timing */
 551                if (cmd->scan_begin_src == TRIG_TIMER) {
 552                        if ((cmd->convert_arg)
 553                                && (cmd->convert_arg <
 554                                        this_board->ui_MinAcquisitiontimeNs)) {
 555                                cmd->convert_arg =
 556                                        this_board->ui_MinAcquisitiontimeNs;
 557                                err++;
 558                        }
 559                } else {
 560                        if (cmd->convert_arg <
 561                                this_board->ui_MinAcquisitiontimeNs) {
 562                                cmd->convert_arg =
 563                                        this_board->ui_MinAcquisitiontimeNs;
 564                                err++;
 565
 566                        }
 567                }
 568        }
 569
 570        if (!cmd->chanlist_len) {
 571                cmd->chanlist_len = 1;
 572                err++;
 573        }
 574        if (cmd->chanlist_len > this_board->i_AiChannelList) {
 575                cmd->chanlist_len = this_board->i_AiChannelList;
 576                err++;
 577        }
 578        if (cmd->stop_src == TRIG_COUNT) {
 579                if (!cmd->stop_arg) {
 580                        cmd->stop_arg = 1;
 581                        err++;
 582                }
 583        } else {                /*  TRIG_NONE */
 584                if (cmd->stop_arg != 0) {
 585                        cmd->stop_arg = 0;
 586                        err++;
 587                }
 588        }
 589
 590        if (err)
 591                return 3;
 592
 593        /*  step 4: fix up any arguments */
 594
 595        if (cmd->convert_src == TRIG_TIMER) {
 596
 597                if (cmd->scan_begin_src == TRIG_TIMER &&
 598                        cmd->scan_begin_arg <
 599                        cmd->convert_arg * cmd->scan_end_arg) {
 600                        cmd->scan_begin_arg =
 601                                cmd->convert_arg * cmd->scan_end_arg;
 602                        err++;
 603                }
 604        }
 605
 606        if (err)
 607                return 4;
 608
 609        return 0;
 610}
 611
 612/*
 613+----------------------------------------------------------------------------+
 614| Function name     : int i_APCI3120_CommandAnalogInput(struct comedi_device *dev,  |
 615|                                                                                               struct comedi_subdevice *s) |
 616|                                                                                                                |
 617+----------------------------------------------------------------------------+
 618| Task              : Does asynchronous acquisition                          |
 619|                     Determines the mode 1 or 2.                                                    |
 620|                                                                                                                |
 621+----------------------------------------------------------------------------+
 622| Input Parameters  : struct comedi_device *dev                                                                  |
 623|                     struct comedi_subdevice *s                                                                         |
 624|                                                                                                                                |
 625+----------------------------------------------------------------------------+
 626| Return Value      :                                                                            |
 627|                                                                                                                            |
 628+----------------------------------------------------------------------------+
 629*/
 630
 631int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s)
 632{
 633        struct comedi_cmd *cmd = &s->async->cmd;
 634
 635        /* loading private structure with cmd structure inputs */
 636        devpriv->ui_AiFlags = cmd->flags;
 637        devpriv->ui_AiNbrofChannels = cmd->chanlist_len;
 638        devpriv->ui_AiScanLength = cmd->scan_end_arg;
 639        devpriv->pui_AiChannelList = cmd->chanlist;
 640
 641        /* UPDATE-0.7.57->0.7.68devpriv->AiData=s->async->data; */
 642        devpriv->AiData = s->async->prealloc_buf;
 643        /* UPDATE-0.7.57->0.7.68devpriv->ui_AiDataLength=s->async->data_len; */
 644        devpriv->ui_AiDataLength = s->async->prealloc_bufsz;
 645
 646        if (cmd->stop_src == TRIG_COUNT)
 647                devpriv->ui_AiNbrofScans = cmd->stop_arg;
 648        else
 649                devpriv->ui_AiNbrofScans = 0;
 650
 651        devpriv->ui_AiTimer0 = 0;       /*  variables changed to timer0,timer1 */
 652        devpriv->ui_AiTimer1 = 0;
 653        if ((devpriv->ui_AiNbrofScans == 0) || (devpriv->ui_AiNbrofScans == -1))
 654                devpriv->b_AiContinuous = 1;    /*  user want neverending analog acquisition */
 655        /*  stopped using cancel */
 656
 657        if (cmd->start_src == TRIG_EXT)
 658                devpriv->b_ExttrigEnable = APCI3120_ENABLE;
 659        else
 660                devpriv->b_ExttrigEnable = APCI3120_DISABLE;
 661
 662        if (cmd->scan_begin_src == TRIG_FOLLOW) {
 663                /*  mode 1 or 3 */
 664                if (cmd->convert_src == TRIG_TIMER) {
 665                        /*  mode 1 */
 666
 667                        devpriv->ui_AiTimer0 = cmd->convert_arg;        /*  timer constant in nano seconds */
 668                        /* return this_board->i_hwdrv_CommandAnalogInput(1,dev,s); */
 669                        return i_APCI3120_CyclicAnalogInput(1, dev, s);
 670                }
 671
 672        }
 673        if ((cmd->scan_begin_src == TRIG_TIMER)
 674                && (cmd->convert_src == TRIG_TIMER)) {
 675                /*  mode 2 */
 676                devpriv->ui_AiTimer1 = cmd->scan_begin_arg;
 677                devpriv->ui_AiTimer0 = cmd->convert_arg;        /*  variable changed timer2 to timer0 */
 678                /* return this_board->i_hwdrv_CommandAnalogInput(2,dev,s); */
 679                return i_APCI3120_CyclicAnalogInput(2, dev, s);
 680        }
 681        return -1;
 682}
 683
 684/*
 685+----------------------------------------------------------------------------+
 686| Function name     :  int i_APCI3120_CyclicAnalogInput(int mode,            |
 687|                          struct comedi_device * dev,struct comedi_subdevice * s)                       |
 688+----------------------------------------------------------------------------+
 689| Task              : This is used for analog input cyclic acquisition       |
 690|                         Performs the command operations.                       |
 691|                         If DMA is configured does DMA initialization           |
 692|                         otherwise does the acquisition with EOS interrupt.     |
 693|                                                                                                                |
 694+----------------------------------------------------------------------------+
 695| Input Parameters  :                                                                                                            |
 696|                                                                                                                                |
 697|                                                                                                |
 698+----------------------------------------------------------------------------+
 699| Return Value      :                                                                            |
 700|                                                                                                                            |
 701+----------------------------------------------------------------------------+
 702*/
 703
 704int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device *dev,
 705        struct comedi_subdevice *s)
 706{
 707        unsigned char b_Tmp;
 708        unsigned int ui_Tmp, ui_DelayTiming = 0, ui_TimerValue1 = 0, dmalen0 =
 709                0, dmalen1 = 0, ui_TimerValue2 =
 710                0, ui_TimerValue0, ui_ConvertTiming;
 711        unsigned short us_TmpValue;
 712
 713        /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
 714        /* devpriv->b_AiCyclicAcquisition=APCI3120_ENABLE; */
 715        /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
 716
 717        /*******************/
 718        /* Resets the FIFO */
 719        /*******************/
 720        inb(dev->iobase + APCI3120_RESET_FIFO);
 721
 722        /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
 723        /* inw(dev->iobase+APCI3120_RD_STATUS); */
 724        /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
 725
 726        /***************************/
 727        /* Acquisition initialized */
 728        /***************************/
 729        /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
 730        devpriv->b_AiCyclicAcquisition = APCI3120_ENABLE;
 731        /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
 732
 733        /*  clear software  registers */
 734        devpriv->b_TimerSelectMode = 0;
 735        devpriv->us_OutputRegister = 0;
 736        devpriv->b_ModeSelectRegister = 0;
 737        /* devpriv->b_DigitalOutputRegister=0; */
 738
 739        /* COMMENT JK 07.05.04: Followings calls are in i_APCI3120_StartAnalogInputAcquisition */
 740
 741        /****************************/
 742        /* Clear Timer Write TC int */
 743        /****************************/
 744        outl(APCI3120_CLEAR_WRITE_TC_INT,
 745                devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_REG_INTCSR);
 746
 747        /************************************/
 748        /* Clears the timer status register */
 749        /************************************/
 750
 751        /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
 752        /* inw(dev->iobase+APCI3120_TIMER_STATUS_REGISTER); */
 753        /* inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); */
 754        /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
 755
 756        /**************************/
 757        /* Disables All Timer     */
 758        /* Sets PR and PA to 0    */
 759        /**************************/
 760        devpriv->us_OutputRegister = devpriv->us_OutputRegister &
 761                APCI3120_DISABLE_TIMER0 &
 762                APCI3120_DISABLE_TIMER1 & APCI3120_CLEAR_PA_PR;
 763
 764        outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
 765
 766        /*******************/
 767        /* Resets the FIFO */
 768        /*******************/
 769        /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
 770        inb(devpriv->iobase + APCI3120_RESET_FIFO);
 771        /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
 772
 773        devpriv->ui_AiActualScan = 0;
 774        devpriv->ui_AiActualScanPosition = 0;
 775        s->async->cur_chan = 0;
 776        devpriv->ui_AiBufferPtr = 0;
 777        devpriv->ui_DmaActualBuffer = 0;
 778
 779        /*  value for timer2  minus -2 has to be done .....dunno y?? */
 780        ui_TimerValue2 = devpriv->ui_AiNbrofScans - 2;
 781        ui_ConvertTiming = devpriv->ui_AiTimer0;
 782
 783        if (mode == 2)
 784                ui_DelayTiming = devpriv->ui_AiTimer1;
 785
 786   /**********************************/
 787        /* Initializes the sequence array */
 788   /**********************************/
 789        if (!i_APCI3120_SetupChannelList(dev, s, devpriv->ui_AiNbrofChannels,
 790                        devpriv->pui_AiChannelList, 0))
 791                return -EINVAL;
 792
 793        us_TmpValue = (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
 794/*** EL241003 : add this section in comment because floats must not be used
 795        if((us_TmpValue & 0x00B0)==0x00B0)
 796         {
 797                f_ConvertValue=(((float)ui_ConvertTiming * 0.002) - 2);
 798                ui_TimerValue0=(unsigned int)f_ConvertValue;
 799                if (mode==2)
 800                {
 801                        f_DelayValue     = (((float)ui_DelayTiming * 0.00002) - 2);
 802                        ui_TimerValue1  =   (unsigned int) f_DelayValue;
 803                }
 804         }
 805        else
 806         {
 807                f_ConvertValue=(((float)ui_ConvertTiming * 0.0012926) - 1);
 808                ui_TimerValue0=(unsigned int)f_ConvertValue;
 809                if (mode == 2)
 810                {
 811                     f_DelayValue     = (((float)ui_DelayTiming * 0.000012926) - 1);
 812                     ui_TimerValue1  =   (unsigned int) f_DelayValue;
 813                }
 814        }
 815***********************************************************************************************/
 816/*** EL241003 Begin : add this section to replace floats calculation by integer calculations **/
 817        /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */
 818        if ((us_TmpValue & 0x00B0) == 0x00B0
 819                || !strcmp(this_board->pc_DriverName, "apci3001")) {
 820                ui_TimerValue0 = ui_ConvertTiming * 2 - 2000;
 821                ui_TimerValue0 = ui_TimerValue0 / 1000;
 822
 823                if (mode == 2) {
 824                        ui_DelayTiming = ui_DelayTiming / 1000;
 825                        ui_TimerValue1 = ui_DelayTiming * 2 - 200;
 826                        ui_TimerValue1 = ui_TimerValue1 / 100;
 827                }
 828        } else {
 829                ui_ConvertTiming = ui_ConvertTiming / 1000;
 830                ui_TimerValue0 = ui_ConvertTiming * 12926 - 10000;
 831                ui_TimerValue0 = ui_TimerValue0 / 10000;
 832
 833                if (mode == 2) {
 834                        ui_DelayTiming = ui_DelayTiming / 1000;
 835                        ui_TimerValue1 = ui_DelayTiming * 12926 - 1;
 836                        ui_TimerValue1 = ui_TimerValue1 / 1000000;
 837                }
 838        }
 839/*** EL241003 End ******************************************************************************/
 840
 841        if (devpriv->b_ExttrigEnable == APCI3120_ENABLE)
 842                i_APCI3120_ExttrigEnable(dev);  /*  activate EXT trigger */
 843        switch (mode) {
 844        case 1:
 845                /*  init timer0 in mode 2 */
 846                devpriv->b_TimerSelectMode =
 847                        (devpriv->
 848                        b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
 849                outb(devpriv->b_TimerSelectMode,
 850                        dev->iobase + APCI3120_TIMER_CRT1);
 851
 852                /* Select Timer 0 */
 853                b_Tmp = ((devpriv->
 854                                b_DigitalOutputRegister) & 0xF0) |
 855                        APCI3120_SELECT_TIMER_0_WORD;
 856                outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
 857                /* Set the convertion time */
 858                outw(((unsigned short) ui_TimerValue0),
 859                        dev->iobase + APCI3120_TIMER_VALUE);
 860                break;
 861
 862        case 2:
 863                /*  init timer1 in mode 2 */
 864                devpriv->b_TimerSelectMode =
 865                        (devpriv->
 866                        b_TimerSelectMode & 0xF3) | APCI3120_TIMER_1_MODE_2;
 867                outb(devpriv->b_TimerSelectMode,
 868                        dev->iobase + APCI3120_TIMER_CRT1);
 869
 870                /* Select Timer 1 */
 871                b_Tmp = ((devpriv->
 872                                b_DigitalOutputRegister) & 0xF0) |
 873                        APCI3120_SELECT_TIMER_1_WORD;
 874                outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
 875                /* Set the convertion time */
 876                outw(((unsigned short) ui_TimerValue1),
 877                        dev->iobase + APCI3120_TIMER_VALUE);
 878
 879                /*  init timer0 in mode 2 */
 880                devpriv->b_TimerSelectMode =
 881                        (devpriv->
 882                        b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
 883                outb(devpriv->b_TimerSelectMode,
 884                        dev->iobase + APCI3120_TIMER_CRT1);
 885
 886                /* Select Timer 0 */
 887                b_Tmp = ((devpriv->
 888                                b_DigitalOutputRegister) & 0xF0) |
 889                        APCI3120_SELECT_TIMER_0_WORD;
 890                outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
 891
 892                /* Set the convertion time */
 893                outw(((unsigned short) ui_TimerValue0),
 894                        dev->iobase + APCI3120_TIMER_VALUE);
 895                break;
 896
 897        }
 898        /*    ##########common for all modes################# */
 899
 900        /***********************/
 901        /* Clears the SCAN bit */
 902        /***********************/
 903
 904        /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
 905        /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister | APCI3120_DISABLE_SCAN; */
 906
 907        devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
 908                APCI3120_DISABLE_SCAN;
 909        /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
 910
 911        outb(devpriv->b_ModeSelectRegister,
 912                dev->iobase + APCI3120_WRITE_MODE_SELECT);
 913
 914        /*  If DMA is disabled */
 915        if (devpriv->us_UseDma == APCI3120_DISABLE) {
 916                /*  disable EOC and enable EOS */
 917                devpriv->b_InterruptMode = APCI3120_EOS_MODE;
 918                devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
 919
 920                devpriv->b_ModeSelectRegister =
 921                        (devpriv->
 922                        b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT) |
 923                        APCI3120_ENABLE_EOS_INT;
 924                outb(devpriv->b_ModeSelectRegister,
 925                        dev->iobase + APCI3120_WRITE_MODE_SELECT);
 926
 927                if (!devpriv->b_AiContinuous) {
 928/*
 929 * configure Timer2 For counting EOS Reset gate 2 of Timer 2 to
 930 * disable it (Set Bit D14 to 0)
 931 */
 932                        devpriv->us_OutputRegister =
 933                                devpriv->
 934                                us_OutputRegister & APCI3120_DISABLE_TIMER2;
 935                        outw(devpriv->us_OutputRegister,
 936                                dev->iobase + APCI3120_WR_ADDRESS);
 937
 938                        /*  DISABLE TIMER intERRUPT */
 939                        devpriv->b_ModeSelectRegister =
 940                                devpriv->
 941                                b_ModeSelectRegister &
 942                                APCI3120_DISABLE_TIMER_INT & 0xEF;
 943                        outb(devpriv->b_ModeSelectRegister,
 944                                dev->iobase + APCI3120_WRITE_MODE_SELECT);
 945
 946                        /* (1) Init timer 2 in mode 0 and write timer value */
 947                        devpriv->b_TimerSelectMode =
 948                                (devpriv->
 949                                b_TimerSelectMode & 0x0F) |
 950                                APCI3120_TIMER_2_MODE_0;
 951                        outb(devpriv->b_TimerSelectMode,
 952                                dev->iobase + APCI3120_TIMER_CRT1);
 953
 954                        /* Writing LOW unsigned short */
 955                        b_Tmp = ((devpriv->
 956                                        b_DigitalOutputRegister) & 0xF0) |
 957                                APCI3120_SELECT_TIMER_2_LOW_WORD;
 958                        outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
 959                        outw(LOWORD(ui_TimerValue2),
 960                                dev->iobase + APCI3120_TIMER_VALUE);
 961
 962                        /* Writing HIGH unsigned short */
 963                        b_Tmp = ((devpriv->
 964                                        b_DigitalOutputRegister) & 0xF0) |
 965                                APCI3120_SELECT_TIMER_2_HIGH_WORD;
 966                        outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
 967                        outw(HIWORD(ui_TimerValue2),
 968                                dev->iobase + APCI3120_TIMER_VALUE);
 969
 970                        /* (2) Reset FC_TIMER BIT  Clearing timer status register */
 971                        inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
 972                        /*  enable timer counter and disable watch dog */
 973                        devpriv->b_ModeSelectRegister =
 974                                (devpriv->
 975                                b_ModeSelectRegister |
 976                                APCI3120_ENABLE_TIMER_COUNTER) &
 977                                APCI3120_DISABLE_WATCHDOG;
 978                        /*  select EOS clock input for timer 2 */
 979                        devpriv->b_ModeSelectRegister =
 980                                devpriv->
 981                                b_ModeSelectRegister |
 982                                APCI3120_TIMER2_SELECT_EOS;
 983                        /*  Enable timer2  interrupt */
 984                        devpriv->b_ModeSelectRegister =
 985                                devpriv->
 986                                b_ModeSelectRegister |
 987                                APCI3120_ENABLE_TIMER_INT;
 988                        outb(devpriv->b_ModeSelectRegister,
 989                                dev->iobase + APCI3120_WRITE_MODE_SELECT);
 990                        devpriv->b_Timer2Mode = APCI3120_COUNTER;
 991                        devpriv->b_Timer2Interrupt = APCI3120_ENABLE;
 992                }
 993        } else {
 994                /* If DMA Enabled */
 995
 996                /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
 997                /* inw(dev->iobase+0); reset EOC bit */
 998                /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
 999                devpriv->b_InterruptMode = APCI3120_DMA_MODE;
1000
1001                /************************************/
1002                /* Disables the EOC, EOS interrupt  */
1003                /************************************/
1004                devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
1005                        APCI3120_DISABLE_EOC_INT & APCI3120_DISABLE_EOS_INT;
1006
1007                outb(devpriv->b_ModeSelectRegister,
1008                        dev->iobase + APCI3120_WRITE_MODE_SELECT);
1009
1010                dmalen0 = devpriv->ui_DmaBufferSize[0];
1011                dmalen1 = devpriv->ui_DmaBufferSize[1];
1012
1013                if (!devpriv->b_AiContinuous) {
1014
1015                        if (dmalen0 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2)) {      /*  must we fill full first buffer? */
1016                                dmalen0 =
1017                                        devpriv->ui_AiNbrofScans *
1018                                        devpriv->ui_AiScanLength * 2;
1019                        } else if (dmalen1 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2 - dmalen0))       /*  and must we fill full second buffer when first is once filled? */
1020                                dmalen1 =
1021                                        devpriv->ui_AiNbrofScans *
1022                                        devpriv->ui_AiScanLength * 2 - dmalen0;
1023                }
1024
1025                if (devpriv->ui_AiFlags & TRIG_WAKE_EOS) {
1026                        /*  don't we want wake up every scan? */
1027                        if (dmalen0 > (devpriv->ui_AiScanLength * 2)) {
1028                                dmalen0 = devpriv->ui_AiScanLength * 2;
1029                                if (devpriv->ui_AiScanLength & 1)
1030                                        dmalen0 += 2;
1031                        }
1032                        if (dmalen1 > (devpriv->ui_AiScanLength * 2)) {
1033                                dmalen1 = devpriv->ui_AiScanLength * 2;
1034                                if (devpriv->ui_AiScanLength & 1)
1035                                        dmalen1 -= 2;
1036                                if (dmalen1 < 4)
1037                                        dmalen1 = 4;
1038                        }
1039                } else {        /*  isn't output buff smaller that our DMA buff? */
1040                        if (dmalen0 > (devpriv->ui_AiDataLength))
1041                                dmalen0 = devpriv->ui_AiDataLength;
1042                        if (dmalen1 > (devpriv->ui_AiDataLength))
1043                                dmalen1 = devpriv->ui_AiDataLength;
1044                }
1045                devpriv->ui_DmaBufferUsesize[0] = dmalen0;
1046                devpriv->ui_DmaBufferUsesize[1] = dmalen1;
1047
1048                /* Initialize DMA */
1049
1050/*
1051 * Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS
1052 * register 1
1053 */
1054                ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1055                outl(ui_Tmp, devpriv->i_IobaseAmcc + AMCC_OP_REG_AGCSTS);
1056
1057                /*  changed  since 16 bit interface for add on */
1058                /*********************/
1059                /* ENABLE BUS MASTER */
1060                /*********************/
1061                outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1062                outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1063                        devpriv->i_IobaseAddon + 2);
1064
1065                outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1066                outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH,
1067                        devpriv->i_IobaseAddon + 2);
1068
1069/*
1070 * TO VERIFIED BEGIN JK 07.05.04: Comparison between WIN32 and Linux
1071 * driver
1072 */
1073                outw(0x1000, devpriv->i_IobaseAddon + 2);
1074                /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1075
1076                /* 2 No change */
1077                /* A2P FIFO MANAGEMENT */
1078                /* A2P fifo reset & transfer control enable */
1079
1080                /***********************/
1081                /* A2P FIFO MANAGEMENT */
1082                /***********************/
1083                outl(APCI3120_A2P_FIFO_MANAGEMENT, devpriv->i_IobaseAmcc +
1084                        APCI3120_AMCC_OP_MCSR);
1085
1086/*
1087 * 3
1088 * beginning address of dma buf The 32 bit address of dma buffer
1089 * is converted into two 16 bit addresses Can done by using _attach
1090 * and put into into an array array used may be for differnet pages
1091 */
1092
1093                /*  DMA Start Adress Low */
1094                outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1095                outw((devpriv->ul_DmaBufferHw[0] & 0xFFFF),
1096                        devpriv->i_IobaseAddon + 2);
1097
1098                /*************************/
1099                /* DMA Start Adress High */
1100                /*************************/
1101                outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1102                outw((devpriv->ul_DmaBufferHw[0] / 65536),
1103                        devpriv->i_IobaseAddon + 2);
1104
1105/*
1106 * 4
1107 * amount of bytes to be transfered set transfer count used ADDON
1108 * MWTC register commented testing
1109 * outl(devpriv->ui_DmaBufferUsesize[0],
1110 * devpriv->i_IobaseAddon+AMCC_OP_REG_AMWTC);
1111 */
1112
1113                /**************************/
1114                /* Nbr of acquisition LOW */
1115                /**************************/
1116                outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1117                outw((devpriv->ui_DmaBufferUsesize[0] & 0xFFFF),
1118                        devpriv->i_IobaseAddon + 2);
1119
1120                /***************************/
1121                /* Nbr of acquisition HIGH */
1122                /***************************/
1123                outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1124                outw((devpriv->ui_DmaBufferUsesize[0] / 65536),
1125                        devpriv->i_IobaseAddon + 2);
1126
1127/*
1128 * 5
1129 * To configure A2P FIFO testing outl(
1130 * FIFO_ADVANCE_ON_BYTE_2,devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR);
1131 */
1132
1133                /******************/
1134                /* A2P FIFO RESET */
1135                /******************/
1136/*
1137 * TO VERIFY BEGIN JK 07.05.04: Comparison between WIN32 and Linux
1138 * driver
1139 */
1140                outl(0x04000000UL, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
1141                /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1142
1143/*
1144 * 6
1145 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN AMWEN_ENABLE |
1146 * A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1147 */
1148
1149                /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1150                /* outw(3,devpriv->i_IobaseAddon + 4); */
1151                /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1152
1153/*
1154 * 7
1155 * initialise end of dma interrupt AINT_WRITE_COMPL =
1156 * ENABLE_WRITE_TC_INT(ADDI)
1157 */
1158                /***************************************************/
1159                /* A2P FIFO CONFIGURATE, END OF DMA intERRUPT INIT */
1160                /***************************************************/
1161                outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1162                                APCI3120_ENABLE_WRITE_TC_INT),
1163                        devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1164
1165                /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1166                /******************************************/
1167                /* ENABLE A2P FIFO WRITE AND ENABLE AMWEN */
1168                /******************************************/
1169                outw(3, devpriv->i_IobaseAddon + 4);
1170                /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1171
1172                /******************/
1173                /* A2P FIFO RESET */
1174                /******************/
1175                /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1176                outl(0x04000000UL,
1177                        devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_MCSR);
1178                /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1179        }
1180
1181        if ((devpriv->us_UseDma == APCI3120_DISABLE)
1182                && !devpriv->b_AiContinuous) {
1183                /*  set gate 2   to start conversion */
1184                devpriv->us_OutputRegister =
1185                        devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER2;
1186                outw(devpriv->us_OutputRegister,
1187                        dev->iobase + APCI3120_WR_ADDRESS);
1188        }
1189
1190        switch (mode) {
1191        case 1:
1192                /*  set gate 0   to start conversion */
1193                devpriv->us_OutputRegister =
1194                        devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
1195                outw(devpriv->us_OutputRegister,
1196                        dev->iobase + APCI3120_WR_ADDRESS);
1197                break;
1198        case 2:
1199                /*  set  gate 0 and gate 1 */
1200                devpriv->us_OutputRegister =
1201                        devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER1;
1202                devpriv->us_OutputRegister =
1203                        devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
1204                outw(devpriv->us_OutputRegister,
1205                        dev->iobase + APCI3120_WR_ADDRESS);
1206                break;
1207
1208        }
1209
1210        return 0;
1211
1212}
1213
1214/*
1215+----------------------------------------------------------------------------+
1216|                       intERNAL FUNCTIONS                                                               |
1217+----------------------------------------------------------------------------+
1218*/
1219
1220/*
1221+----------------------------------------------------------------------------+
1222| Function name     : int i_APCI3120_Reset(struct comedi_device *dev)               |
1223|                                                                                                                |
1224|                                                                                                |
1225+----------------------------------------------------------------------------+
1226| Task              : Hardware reset function                                                        |
1227|                                                                                                                |
1228+----------------------------------------------------------------------------+
1229| Input Parameters  :   struct comedi_device *dev                                                                        |
1230|                                                                                                                                |
1231|                                                                                                |
1232+----------------------------------------------------------------------------+
1233| Return Value      :                                                                            |
1234|                                                                                                                            |
1235+----------------------------------------------------------------------------+
1236*/
1237
1238int i_APCI3120_Reset(struct comedi_device *dev)
1239{
1240        unsigned int i;
1241        unsigned short us_TmpValue;
1242
1243        devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1244        devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1245        devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1246        devpriv->ui_EocEosConversionTime = 0;   /*  set eoc eos conv time to 0 */
1247        devpriv->b_OutputMemoryStatus = 0;
1248
1249        /*  variables used in timer subdevice */
1250        devpriv->b_Timer2Mode = 0;
1251        devpriv->b_Timer2Interrupt = 0;
1252        devpriv->b_ExttrigEnable = 0;   /*  Disable ext trigger */
1253
1254        /* Disable all interrupts, watchdog for the anolog output */
1255        devpriv->b_ModeSelectRegister = 0;
1256        outb(devpriv->b_ModeSelectRegister,
1257                dev->iobase + APCI3120_WRITE_MODE_SELECT);
1258
1259        /*  Disables all counters, ext trigger and clears PA, PR */
1260        devpriv->us_OutputRegister = 0;
1261        outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1262
1263/*
1264 * Code to set the all anolog o/p channel to 0v 8191 is decimal
1265 * value for zero(0 v)volt in bipolar mode(default)
1266 */
1267        outw(8191 | APCI3120_ANALOG_OP_CHANNEL_1, dev->iobase + APCI3120_ANALOG_OUTPUT_1);      /* channel 1 */
1268        outw(8191 | APCI3120_ANALOG_OP_CHANNEL_2, dev->iobase + APCI3120_ANALOG_OUTPUT_1);      /* channel 2 */
1269        outw(8191 | APCI3120_ANALOG_OP_CHANNEL_3, dev->iobase + APCI3120_ANALOG_OUTPUT_1);      /* channel 3 */
1270        outw(8191 | APCI3120_ANALOG_OP_CHANNEL_4, dev->iobase + APCI3120_ANALOG_OUTPUT_1);      /* channel 4 */
1271
1272        outw(8191 | APCI3120_ANALOG_OP_CHANNEL_5, dev->iobase + APCI3120_ANALOG_OUTPUT_2);      /* channel 5 */
1273        outw(8191 | APCI3120_ANALOG_OP_CHANNEL_6, dev->iobase + APCI3120_ANALOG_OUTPUT_2);      /* channel 6 */
1274        outw(8191 | APCI3120_ANALOG_OP_CHANNEL_7, dev->iobase + APCI3120_ANALOG_OUTPUT_2);      /* channel 7 */
1275        outw(8191 | APCI3120_ANALOG_OP_CHANNEL_8, dev->iobase + APCI3120_ANALOG_OUTPUT_2);      /* channel 8 */
1276
1277        /*   Reset digital output to L0W */
1278
1279/* ES05  outb(0x0,dev->iobase+APCI3120_DIGITAL_OUTPUT); */
1280        udelay(10);
1281
1282        inw(dev->iobase + 0);   /* make a dummy read */
1283        inb(dev->iobase + APCI3120_RESET_FIFO); /*  flush FIFO */
1284        inw(dev->iobase + APCI3120_RD_STATUS);  /*  flush A/D status register */
1285
1286        /* code to reset the RAM sequence */
1287        for (i = 0; i < 16; i++) {
1288                us_TmpValue = i << 8;   /* select the location */
1289                outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
1290        }
1291        return 0;
1292}
1293
1294/*
1295+----------------------------------------------------------------------------+
1296| Function name     : int i_APCI3120_SetupChannelList(struct comedi_device * dev,   |
1297|                     struct comedi_subdevice * s, int n_chan,unsigned int *chanlist|
1298|                         ,char check)                                                                                   |
1299|                                                                                                |
1300+----------------------------------------------------------------------------+
1301| Task              :This function will first check channel list is ok or not|
1302|and then initialize the sequence RAM with the polarity, Gain,Channel number |
1303|If the last argument of function "check"is 1 then it only checks the channel|
1304|list is ok or not.                                                                                                              |
1305|                                                                                                                |
1306+----------------------------------------------------------------------------+
1307| Input Parameters  : struct comedi_device * dev                                                                         |
1308|                     struct comedi_subdevice * s                                                                        |
1309|                     int n_chan                                                                 |
1310                          unsigned int *chanlist
1311                          char check
1312+----------------------------------------------------------------------------+
1313| Return Value      :                                                                            |
1314|                                                                                                                            |
1315+----------------------------------------------------------------------------+
1316*/
1317
1318int i_APCI3120_SetupChannelList(struct comedi_device *dev, struct comedi_subdevice *s,
1319        int n_chan, unsigned int *chanlist, char check)
1320{
1321        unsigned int i;         /* , differencial=0, bipolar=0; */
1322        unsigned int gain;
1323        unsigned short us_TmpValue;
1324
1325        /* correct channel and range number check itself comedi/range.c */
1326        if (n_chan < 1) {
1327                if (!check)
1328                        comedi_error(dev, "range/channel list is empty!");
1329                return 0;
1330        }
1331        /*  All is ok, so we can setup channel/range list */
1332        if (check)
1333                return 1;
1334
1335        /* Code  to set the PA and PR...Here it set PA to 0.. */
1336        devpriv->us_OutputRegister =
1337                devpriv->us_OutputRegister & APCI3120_CLEAR_PA_PR;
1338        devpriv->us_OutputRegister = ((n_chan - 1) & 0xf) << 8;
1339        outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1340
1341        for (i = 0; i < n_chan; i++) {
1342                /*  store range list to card */
1343                us_TmpValue = CR_CHAN(chanlist[i]);     /*  get channel number; */
1344
1345                if (CR_RANGE(chanlist[i]) < APCI3120_BIPOLAR_RANGES)
1346                        us_TmpValue &= ((~APCI3120_UNIPOLAR) & 0xff);   /*  set bipolar */
1347                else
1348                        us_TmpValue |= APCI3120_UNIPOLAR;       /*  enable unipolar...... */
1349
1350                gain = CR_RANGE(chanlist[i]);   /*  get gain number */
1351                us_TmpValue |= ((gain & 0x03) << 4);    /* <<4 for G0 and G1 bit in RAM */
1352                us_TmpValue |= i << 8;  /* To select the RAM LOCATION.... */
1353                outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
1354
1355                printk("\n Gain = %i",
1356                        (((unsigned char)CR_RANGE(chanlist[i]) & 0x03) << 2));
1357                printk("\n Channel = %i", CR_CHAN(chanlist[i]));
1358                printk("\n Polarity = %i", us_TmpValue & APCI3120_UNIPOLAR);
1359        }
1360        return 1;               /*  we can serve this with scan logic */
1361}
1362
1363/*
1364+----------------------------------------------------------------------------+
1365| Function name     :   int i_APCI3120_ExttrigEnable(struct comedi_device * dev)    |
1366|                                                                                                                |
1367|                                                                                                |
1368+----------------------------------------------------------------------------+
1369| Task              :   Enable the external trigger                                                  |
1370|                                                                                                                |
1371+----------------------------------------------------------------------------+
1372| Input Parameters  :   struct comedi_device * dev                                                                       |
1373|                                                                                                                                |
1374|                                                                                                |
1375+----------------------------------------------------------------------------+
1376| Return Value      :      0                                                                     |
1377|                                                                                                                            |
1378+----------------------------------------------------------------------------+
1379*/
1380
1381int i_APCI3120_ExttrigEnable(struct comedi_device *dev)
1382{
1383
1384        devpriv->us_OutputRegister |= APCI3120_ENABLE_EXT_TRIGGER;
1385        outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1386        return 0;
1387}
1388
1389/*
1390+----------------------------------------------------------------------------+
1391| Function name     :   int i_APCI3120_ExttrigDisable(struct comedi_device * dev)   |
1392|                                                                                                                |
1393+----------------------------------------------------------------------------+
1394| Task              :   Disables the external trigger                                        |
1395|                                                                                                                |
1396+----------------------------------------------------------------------------+
1397| Input Parameters  :   struct comedi_device * dev                                                                       |
1398|                                                                                                                                |
1399|                                                                                                |
1400+----------------------------------------------------------------------------+
1401| Return Value      :    0                                                                       |
1402|                                                                                                                            |
1403+----------------------------------------------------------------------------+
1404*/
1405
1406int i_APCI3120_ExttrigDisable(struct comedi_device *dev)
1407{
1408        devpriv->us_OutputRegister &= ~APCI3120_ENABLE_EXT_TRIGGER;
1409        outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1410        return 0;
1411}
1412
1413/*
1414+----------------------------------------------------------------------------+
1415|                    intERRUPT FUNCTIONS                                                 |
1416+----------------------------------------------------------------------------+
1417*/
1418
1419/*
1420+----------------------------------------------------------------------------+
1421| Function name     : void v_APCI3120_Interrupt(int irq, void *d)                                                                |
1422|                                                                                                                |
1423|                                                                                                |
1424+----------------------------------------------------------------------------+
1425| Task              :Interrupt handler for APCI3120                              |
1426|                        When interrupt occurs this gets called.                 |
1427|                        First it finds which interrupt has been generated and   |
1428|                        handles  corresponding interrupt                        |
1429|                                                                                                                |
1430+----------------------------------------------------------------------------+
1431| Input Parameters  :   int irq                                                                                          |
1432|                        void *d                                                                                         |
1433|                                                                                                |
1434+----------------------------------------------------------------------------+
1435| Return Value      : void                                                                       |
1436|                                                                                                                            |
1437+----------------------------------------------------------------------------+
1438*/
1439
1440void v_APCI3120_Interrupt(int irq, void *d)
1441{
1442        struct comedi_device *dev = d;
1443        unsigned short int_daq;
1444
1445        unsigned int int_amcc, ui_Check, i;
1446        unsigned short us_TmpValue;
1447        unsigned char b_DummyRead;
1448
1449        struct comedi_subdevice *s = dev->subdevices + 0;
1450        ui_Check = 1;
1451
1452        int_daq = inw(dev->iobase + APCI3120_RD_STATUS) & 0xf000;       /*  get IRQ reasons */
1453        int_amcc = inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);     /*  get AMCC int register */
1454
1455        if ((!int_daq) && (!(int_amcc & ANY_S593X_INT))) {
1456                comedi_error(dev, "IRQ from unknown source");
1457                return;
1458        }
1459
1460        outl(int_amcc | 0x00ff0000, devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);        /*  shutdown IRQ reasons in AMCC */
1461
1462        int_daq = (int_daq >> 12) & 0xF;
1463
1464        if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) {
1465                /* Disable ext trigger */
1466                i_APCI3120_ExttrigDisable(dev);
1467                devpriv->b_ExttrigEnable = APCI3120_DISABLE;
1468        }
1469        /* clear the timer 2 interrupt */
1470        inb(devpriv->i_IobaseAmcc + APCI3120_TIMER_STATUS_REGISTER);
1471
1472        if (int_amcc & MASTER_ABORT_INT)
1473                comedi_error(dev, "AMCC IRQ - MASTER DMA ABORT!");
1474        if (int_amcc & TARGET_ABORT_INT)
1475                comedi_error(dev, "AMCC IRQ - TARGET DMA ABORT!");
1476
1477        /*  Ckeck if EOC interrupt */
1478        if (((int_daq & 0x8) == 0)
1479                && (devpriv->b_InterruptMode == APCI3120_EOC_MODE)) {
1480                if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
1481
1482                        /*  Read the AI Value */
1483
1484                        devpriv->ui_AiReadData[0] =
1485                                (unsigned int) inw(devpriv->iobase + 0);
1486                        devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1487                        send_sig(SIGIO, devpriv->tsk_Current, 0);       /*  send signal to the sample */
1488                } else {
1489                        /* Disable EOC Interrupt */
1490                        devpriv->b_ModeSelectRegister =
1491                                devpriv->
1492                                b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT;
1493                        outb(devpriv->b_ModeSelectRegister,
1494                                devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
1495
1496                }
1497        }
1498
1499        /*  Check If EOS interrupt */
1500        if ((int_daq & 0x2) && (devpriv->b_InterruptMode == APCI3120_EOS_MODE)) {
1501
1502                if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {    /*  enable this in without DMA ??? */
1503
1504                        if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
1505                                ui_Check = 0;
1506                                i_APCI3120_InterruptHandleEos(dev);
1507                                devpriv->ui_AiActualScan++;
1508                                devpriv->b_ModeSelectRegister =
1509                                        devpriv->
1510                                        b_ModeSelectRegister |
1511                                        APCI3120_ENABLE_EOS_INT;
1512                                outb(devpriv->b_ModeSelectRegister,
1513                                        dev->iobase +
1514                                        APCI3120_WRITE_MODE_SELECT);
1515                        } else {
1516                                ui_Check = 0;
1517                                for (i = 0; i < devpriv->ui_AiNbrofChannels;
1518                                        i++) {
1519                                        us_TmpValue = inw(devpriv->iobase + 0);
1520                                        devpriv->ui_AiReadData[i] =
1521                                                (unsigned int) us_TmpValue;
1522                                }
1523                                devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1524                                devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1525
1526                                send_sig(SIGIO, devpriv->tsk_Current, 0);       /*  send signal to the sample */
1527
1528                        }
1529
1530                } else {
1531                        devpriv->b_ModeSelectRegister =
1532                                devpriv->
1533                                b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
1534                        outb(devpriv->b_ModeSelectRegister,
1535                                dev->iobase + APCI3120_WRITE_MODE_SELECT);
1536                        devpriv->b_EocEosInterrupt = APCI3120_DISABLE;  /* Default settings */
1537                        devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1538                }
1539
1540        }
1541        /* Timer2 interrupt */
1542        if (int_daq & 0x1) {
1543
1544                switch (devpriv->b_Timer2Mode) {
1545                case APCI3120_COUNTER:
1546
1547                        devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1548                        devpriv->b_ModeSelectRegister =
1549                                devpriv->
1550                                b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
1551                        outb(devpriv->b_ModeSelectRegister,
1552                                dev->iobase + APCI3120_WRITE_MODE_SELECT);
1553
1554                        /*  stop timer 2 */
1555                        devpriv->us_OutputRegister =
1556                                devpriv->
1557                                us_OutputRegister & APCI3120_DISABLE_ALL_TIMER;
1558                        outw(devpriv->us_OutputRegister,
1559                                dev->iobase + APCI3120_WR_ADDRESS);
1560
1561                        /* stop timer 0 and timer 1 */
1562                        i_APCI3120_StopCyclicAcquisition(dev, s);
1563                        devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1564
1565                        /* UPDATE-0.7.57->0.7.68comedi_done(dev,s); */
1566                        s->async->events |= COMEDI_CB_EOA;
1567                        comedi_event(dev, s);
1568
1569                        break;
1570
1571                case APCI3120_TIMER:
1572
1573                        /* Send a signal to from kernel to user space */
1574                        send_sig(SIGIO, devpriv->tsk_Current, 0);
1575                        break;
1576
1577                case APCI3120_WATCHDOG:
1578
1579                        /* Send a signal to from kernel to user space */
1580                        send_sig(SIGIO, devpriv->tsk_Current, 0);
1581                        break;
1582
1583                default:
1584
1585                        /*  disable Timer Interrupt */
1586
1587                        devpriv->b_ModeSelectRegister =
1588                                devpriv->
1589                                b_ModeSelectRegister &
1590                                APCI3120_DISABLE_TIMER_INT;
1591
1592                        outb(devpriv->b_ModeSelectRegister,
1593                                dev->iobase + APCI3120_WRITE_MODE_SELECT);
1594
1595                }
1596
1597                b_DummyRead = inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1598
1599        }
1600
1601        if ((int_daq & 0x4) && (devpriv->b_InterruptMode == APCI3120_DMA_MODE)) {
1602                if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
1603
1604                        /****************************/
1605                        /* Clear Timer Write TC int */
1606                        /****************************/
1607
1608                        outl(APCI3120_CLEAR_WRITE_TC_INT,
1609                                devpriv->i_IobaseAmcc +
1610                                APCI3120_AMCC_OP_REG_INTCSR);
1611
1612                        /************************************/
1613                        /* Clears the timer status register */
1614                        /************************************/
1615                        inw(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1616                        v_APCI3120_InterruptDma(irq, d);        /*  do some data transfer */
1617                } else {
1618                        /* Stops the Timer */
1619                        outw(devpriv->
1620                                us_OutputRegister & APCI3120_DISABLE_TIMER0 &
1621                                APCI3120_DISABLE_TIMER1,
1622                                dev->iobase + APCI3120_WR_ADDRESS);
1623                }
1624
1625        }
1626
1627        return;
1628}
1629
1630/*
1631+----------------------------------------------------------------------------+
1632| Function name     :int i_APCI3120_InterruptHandleEos(struct comedi_device *dev)   |
1633|                                                                                                                |
1634|                                                                                                |
1635+----------------------------------------------------------------------------+
1636| Task              : This function handles EOS interrupt.                   |
1637|                     This function copies the acquired data(from FIFO)      |
1638|                               to Comedi buffer.                                                                        |
1639|                                                                                                                |
1640+----------------------------------------------------------------------------+
1641| Input Parameters  : struct comedi_device *dev                                                                  |
1642|                                                                                                                                |
1643|                                                                                                |
1644+----------------------------------------------------------------------------+
1645| Return Value      : 0                                                                          |
1646|                                                                                                                            |
1647+----------------------------------------------------------------------------+
1648*/
1649
1650
1651int i_APCI3120_InterruptHandleEos(struct comedi_device *dev)
1652{
1653        int n_chan, i;
1654        struct comedi_subdevice *s = dev->subdevices + 0;
1655        int err = 1;
1656
1657        n_chan = devpriv->ui_AiNbrofChannels;
1658
1659        s->async->events = 0;
1660
1661        for (i = 0; i < n_chan; i++)
1662                err &= comedi_buf_put(s->async, inw(dev->iobase + 0));
1663
1664        s->async->events |= COMEDI_CB_EOS;
1665
1666        if (err == 0)
1667                s->async->events |= COMEDI_CB_OVERFLOW;
1668
1669        comedi_event(dev, s);
1670
1671        return 0;
1672}
1673
1674/*
1675+----------------------------------------------------------------------------+
1676| Function name     : void v_APCI3120_InterruptDma(int irq, void *d)                                                                     |
1677|                                                                                                                |
1678+----------------------------------------------------------------------------+
1679| Task              : This is a handler for the DMA interrupt                |
1680|                         This function copies the data to Comedi Buffer.        |
1681|                         For continuous DMA it reinitializes the DMA operation. |
1682|                         For single mode DMA it stop the acquisition.           |
1683|                                                                                                                                |
1684+----------------------------------------------------------------------------+
1685| Input Parameters  : int irq, void *d                           |
1686|                                                                                                                                |
1687+----------------------------------------------------------------------------+
1688| Return Value      :  void                                                                      |
1689|                                                                                                                            |
1690+----------------------------------------------------------------------------+
1691*/
1692
1693void v_APCI3120_InterruptDma(int irq, void *d)
1694{
1695        struct comedi_device *dev = d;
1696        struct comedi_subdevice *s = dev->subdevices + 0;
1697        unsigned int next_dma_buf, samplesinbuf;
1698        unsigned long low_word, high_word, var;
1699
1700        unsigned int ui_Tmp;
1701        samplesinbuf =
1702                devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer] -
1703                inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_MWTC);
1704
1705        if (samplesinbuf <
1706                devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer]) {
1707                comedi_error(dev, "Interrupted DMA transfer!");
1708        }
1709        if (samplesinbuf & 1) {
1710                comedi_error(dev, "Odd count of bytes in DMA ring!");
1711                i_APCI3120_StopCyclicAcquisition(dev, s);
1712                devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1713
1714                return;
1715        }
1716        samplesinbuf = samplesinbuf >> 1;       /*  number of received samples */
1717        if (devpriv->b_DmaDoubleBuffer) {
1718                /*  switch DMA buffers if is used double buffering */
1719                next_dma_buf = 1 - devpriv->ui_DmaActualBuffer;
1720
1721                ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1722                outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
1723
1724                /*  changed  since 16 bit interface for add on */
1725                outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1726                outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1727                        devpriv->i_IobaseAddon + 2);
1728                outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1729                outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); /*  0x1000 is out putted in windows driver */
1730
1731                var = devpriv->ul_DmaBufferHw[next_dma_buf];
1732                low_word = var & 0xffff;
1733                var = devpriv->ul_DmaBufferHw[next_dma_buf];
1734                high_word = var / 65536;
1735
1736                /* DMA Start Adress Low */
1737                outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1738                outw(low_word, devpriv->i_IobaseAddon + 2);
1739
1740                /* DMA Start Adress High */
1741                outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1742                outw(high_word, devpriv->i_IobaseAddon + 2);
1743
1744                var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
1745                low_word = var & 0xffff;
1746                var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
1747                high_word = var / 65536;
1748
1749                /* Nbr of acquisition LOW */
1750                outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1751                outw(low_word, devpriv->i_IobaseAddon + 2);
1752
1753                /* Nbr of acquisition HIGH */
1754                outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1755                outw(high_word, devpriv->i_IobaseAddon + 2);
1756
1757/*
1758 * To configure A2P FIFO
1759 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1760 * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1761 */
1762                outw(3, devpriv->i_IobaseAddon + 4);
1763                /* initialise end of dma interrupt  AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
1764                outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1765                                APCI3120_ENABLE_WRITE_TC_INT),
1766                        devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1767
1768        }
1769        if (samplesinbuf) {
1770                v_APCI3120_InterruptDmaMoveBlock16bit(dev, s,
1771                        devpriv->ul_DmaBufferVirtual[devpriv->
1772                                ui_DmaActualBuffer], samplesinbuf);
1773
1774                if (!(devpriv->ui_AiFlags & TRIG_WAKE_EOS)) {
1775                        s->async->events |= COMEDI_CB_EOS;
1776                        comedi_event(dev, s);
1777                }
1778        }
1779        if (!devpriv->b_AiContinuous)
1780                if (devpriv->ui_AiActualScan >= devpriv->ui_AiNbrofScans) {
1781                        /*  all data sampled */
1782                        i_APCI3120_StopCyclicAcquisition(dev, s);
1783                        devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1784                        s->async->events |= COMEDI_CB_EOA;
1785                        comedi_event(dev, s);
1786                        return;
1787                }
1788
1789        if (devpriv->b_DmaDoubleBuffer) {       /*  switch dma buffers */
1790                devpriv->ui_DmaActualBuffer = 1 - devpriv->ui_DmaActualBuffer;
1791        } else {
1792/*
1793 * restart DMA if is not used double buffering
1794 * ADDED REINITIALISE THE DMA
1795 */
1796                ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1797                outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
1798
1799                /*  changed  since 16 bit interface for add on */
1800                outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1801                outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1802                        devpriv->i_IobaseAddon + 2);
1803                outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1804                outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); /*  */
1805/*
1806 * A2P FIFO MANAGEMENT
1807 * A2P fifo reset & transfer control enable
1808 */
1809                outl(APCI3120_A2P_FIFO_MANAGEMENT,
1810                        devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
1811
1812                var = devpriv->ul_DmaBufferHw[0];
1813                low_word = var & 0xffff;
1814                var = devpriv->ul_DmaBufferHw[0];
1815                high_word = var / 65536;
1816                outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1817                outw(low_word, devpriv->i_IobaseAddon + 2);
1818                outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1819                outw(high_word, devpriv->i_IobaseAddon + 2);
1820
1821                var = devpriv->ui_DmaBufferUsesize[0];
1822                low_word = var & 0xffff;        /* changed */
1823                var = devpriv->ui_DmaBufferUsesize[0];
1824                high_word = var / 65536;
1825                outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1826                outw(low_word, devpriv->i_IobaseAddon + 2);
1827                outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1828                outw(high_word, devpriv->i_IobaseAddon + 2);
1829
1830/*
1831 * To configure A2P FIFO
1832 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1833 * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1834 */
1835                outw(3, devpriv->i_IobaseAddon + 4);
1836                /* initialise end of dma interrupt  AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
1837                outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1838                                APCI3120_ENABLE_WRITE_TC_INT),
1839                        devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1840        }
1841}
1842
1843/*
1844+----------------------------------------------------------------------------+
1845| Function name     :void v_APCI3120_InterruptDmaMoveBlock16bit(comedi_device|
1846|*dev,struct comedi_subdevice *s,short *dma,short *data,int n)                               |
1847|                                                                                                                |
1848+----------------------------------------------------------------------------+
1849| Task              : This function copies the data from DMA buffer to the   |
1850|                                Comedi buffer                                                                           |
1851|                                                                                                                |
1852+----------------------------------------------------------------------------+
1853| Input Parameters  : struct comedi_device *dev                                                                  |
1854|                     struct comedi_subdevice *s                                                                         |
1855|                     short *dma                                                                                         |
1856|                     short *data,int n                                                          |
1857+----------------------------------------------------------------------------+
1858| Return Value      : void                                                                       |
1859|                                                                                                                            |
1860+----------------------------------------------------------------------------+
1861*/
1862
1863void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev,
1864        struct comedi_subdevice *s, short *dma_buffer, unsigned int num_samples)
1865{
1866        devpriv->ui_AiActualScan +=
1867                (s->async->cur_chan + num_samples) / devpriv->ui_AiScanLength;
1868        s->async->cur_chan += num_samples;
1869        s->async->cur_chan %= devpriv->ui_AiScanLength;
1870
1871        cfc_write_array_to_buffer(s, dma_buffer, num_samples * sizeof(short));
1872}
1873
1874/*
1875+----------------------------------------------------------------------------+
1876|                           TIMER SUBDEVICE                                      |
1877+----------------------------------------------------------------------------+
1878*/
1879
1880/*
1881+----------------------------------------------------------------------------+
1882| Function name     :int i_APCI3120_InsnConfigTimer(struct comedi_device *dev,          |
1883|       struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)                              |
1884|                                                                                                                |
1885+----------------------------------------------------------------------------+
1886| Task              :Configure Timer 2                                                                       |
1887|                                                                                                                |
1888+----------------------------------------------------------------------------+
1889| Input Parameters  : struct comedi_device *dev                                                                  |
1890|                     struct comedi_subdevice *s                                                                         |
1891|                     struct comedi_insn *insn                                      |
1892|                     unsigned int *data                                                                                 |
1893|                                                                                                                                |
1894|                      data[0]= TIMER  configure as timer                    |
1895|                                        = WATCHDOG configure as watchdog                                |
1896|                                 data[1] = Timer constant                                                       |
1897|                                 data[2] = Timer2 interrupt (1)enable or(0) disable |
1898|                                                                                                |
1899+----------------------------------------------------------------------------+
1900| Return Value      :                                                                            |
1901|                                                                                                                            |
1902+----------------------------------------------------------------------------+
1903*/
1904
1905int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, struct comedi_subdevice *s,
1906        struct comedi_insn *insn, unsigned int *data)
1907{
1908
1909        unsigned int ui_Timervalue2;
1910        unsigned short us_TmpValue;
1911        unsigned char b_Tmp;
1912
1913        if (!data[1])
1914                comedi_error(dev, "config:No timer constant !");
1915
1916        devpriv->b_Timer2Interrupt = (unsigned char) data[2];   /*  save info whether to enable or disable interrupt */
1917
1918        ui_Timervalue2 = data[1] / 1000;        /*  convert nano seconds  to u seconds */
1919
1920        /* this_board->i_hwdrv_InsnConfigTimer(dev, ui_Timervalue2,(unsigned char)data[0]); */
1921        us_TmpValue = (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
1922
1923/*
1924 * EL250804: Testing if board APCI3120 have the new Quartz or if it
1925 * is an APCI3001 and calculate the time value to set in the timer
1926 */
1927        if ((us_TmpValue & 0x00B0) == 0x00B0
1928                || !strcmp(this_board->pc_DriverName, "apci3001")) {
1929                /* Calculate the time value to set in the timer */
1930                ui_Timervalue2 = ui_Timervalue2 / 50;
1931        } else {
1932                /* Calculate the time value to set in the timer */
1933                ui_Timervalue2 = ui_Timervalue2 / 70;
1934        }
1935
1936        /* Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0) */
1937        devpriv->us_OutputRegister =
1938                devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER2;
1939        outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS);
1940
1941        /*  Disable TIMER Interrupt */
1942        devpriv->b_ModeSelectRegister =
1943                devpriv->
1944                b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT & 0xEF;
1945
1946        /*  Disable Eoc and Eos Interrupts */
1947        devpriv->b_ModeSelectRegister =
1948                devpriv->
1949                b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT &
1950                APCI3120_DISABLE_EOS_INT;
1951        outb(devpriv->b_ModeSelectRegister,
1952                devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
1953        if (data[0] == APCI3120_TIMER) {        /* initialize timer */
1954                /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister |
1955                 * APCI3120_ENABLE_TIMER_INT; */
1956
1957                /* outb(devpriv->b_ModeSelectRegister,devpriv->iobase+APCI3120_WRITE_MODE_SELECT); */
1958
1959                /* Set the Timer 2 in mode 2(Timer) */
1960                devpriv->b_TimerSelectMode =
1961                        (devpriv->
1962                        b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_2;
1963                outb(devpriv->b_TimerSelectMode,
1964                        devpriv->iobase + APCI3120_TIMER_CRT1);
1965
1966/*
1967 * Configure the timer 2 for writing the LOW unsigned short of timer
1968 * is Delay value You must make a b_tmp variable with
1969 * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
1970 * you can set the digital output and configure the timer 2,and if
1971 * you don't make this, digital output are erase (Set to 0)
1972 */
1973
1974                /* Writing LOW unsigned short */
1975                b_Tmp = ((devpriv->
1976                                b_DigitalOutputRegister) & 0xF0) |
1977                        APCI3120_SELECT_TIMER_2_LOW_WORD;
1978                outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1979                outw(LOWORD(ui_Timervalue2),
1980                        devpriv->iobase + APCI3120_TIMER_VALUE);
1981
1982                /* Writing HIGH unsigned short */
1983                b_Tmp = ((devpriv->
1984                                b_DigitalOutputRegister) & 0xF0) |
1985                        APCI3120_SELECT_TIMER_2_HIGH_WORD;
1986                outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1987                outw(HIWORD(ui_Timervalue2),
1988                        devpriv->iobase + APCI3120_TIMER_VALUE);
1989                /*  timer2 in Timer mode enabled */
1990                devpriv->b_Timer2Mode = APCI3120_TIMER;
1991
1992        } else {                        /*  Initialize Watch dog */
1993
1994                /* Set the Timer 2 in mode 5(Watchdog) */
1995
1996                devpriv->b_TimerSelectMode =
1997                        (devpriv->
1998                        b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_5;
1999                outb(devpriv->b_TimerSelectMode,
2000                        devpriv->iobase + APCI3120_TIMER_CRT1);
2001
2002/*
2003 * Configure the timer 2 for writing the LOW unsigned short of timer
2004 * is Delay value You must make a b_tmp variable with
2005 * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
2006 * you can set the digital output and configure the timer 2,and if
2007 * you don't make this, digital output are erase (Set to 0)
2008 */
2009
2010                /* Writing LOW unsigned short */
2011                b_Tmp = ((devpriv->
2012                                b_DigitalOutputRegister) & 0xF0) |
2013                        APCI3120_SELECT_TIMER_2_LOW_WORD;
2014                outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2015                outw(LOWORD(ui_Timervalue2),
2016                        devpriv->iobase + APCI3120_TIMER_VALUE);
2017
2018                /* Writing HIGH unsigned short */
2019                b_Tmp = ((devpriv->
2020                                b_DigitalOutputRegister) & 0xF0) |
2021                        APCI3120_SELECT_TIMER_2_HIGH_WORD;
2022                outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2023
2024                outw(HIWORD(ui_Timervalue2),
2025                        devpriv->iobase + APCI3120_TIMER_VALUE);
2026                /* watchdog enabled */
2027                devpriv->b_Timer2Mode = APCI3120_WATCHDOG;
2028
2029        }
2030
2031        return insn->n;
2032
2033}
2034
2035/*
2036+----------------------------------------------------------------------------+
2037| Function name     :int i_APCI3120_InsnWriteTimer(struct comedi_device *dev,           |
2038|                    struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data)  |
2039|                                                                                                |
2040+----------------------------------------------------------------------------+
2041| Task              :    To start and stop the timer                             |
2042+----------------------------------------------------------------------------+
2043| Input Parameters  : struct comedi_device *dev                                                                  |
2044|                     struct comedi_subdevice *s                                                                         |
2045|                     struct comedi_insn *insn                                      |
2046|                     unsigned int *data                                         |
2047|                                                                            |
2048|                               data[0] = 1 (start)                                  |
2049|                               data[0] = 0 (stop )                                  |
2050|                               data[0] = 2  (write new value)                       |
2051|                               data[1]= new value                                   |
2052|                                                                            |
2053|                               devpriv->b_Timer2Mode =  0 DISABLE                   |
2054|                                                                1 Timer                     |
2055|                                                                                2 Watch dog                         |
2056|                                                                                                |
2057+----------------------------------------------------------------------------+
2058| Return Value      :                                                                            |
2059|                                                                                                                            |
2060+----------------------------------------------------------------------------+
2061*/
2062
2063int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, struct comedi_subdevice *s,
2064        struct comedi_insn *insn, unsigned int *data)
2065{
2066
2067        unsigned int ui_Timervalue2 = 0;
2068        unsigned short us_TmpValue;
2069        unsigned char b_Tmp;
2070
2071        if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
2072                && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
2073                comedi_error(dev, "\nwrite:timer2  not configured ");
2074                return -EINVAL;
2075        }
2076
2077        if (data[0] == 2) {     /*  write new value */
2078                if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
2079                        comedi_error(dev,
2080                                "write :timer2  not configured  in TIMER MODE");
2081                        return -EINVAL;
2082                }
2083
2084                if (data[1])
2085                        ui_Timervalue2 = data[1];
2086                else
2087                        ui_Timervalue2 = 0;
2088        }
2089
2090        /* this_board->i_hwdrv_InsnWriteTimer(dev,data[0],ui_Timervalue2); */
2091
2092        switch (data[0]) {
2093        case APCI3120_START:
2094
2095                /*  Reset FC_TIMER BIT */
2096                inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2097                if (devpriv->b_Timer2Mode == APCI3120_TIMER) {  /* start timer */
2098                        /* Enable Timer */
2099                        devpriv->b_ModeSelectRegister =
2100                                devpriv->b_ModeSelectRegister & 0x0B;
2101                } else {                /* start watch dog */
2102                        /* Enable WatchDog */
2103                        devpriv->b_ModeSelectRegister =
2104                                (devpriv->
2105                                b_ModeSelectRegister & 0x0B) |
2106                                APCI3120_ENABLE_WATCHDOG;
2107                }
2108
2109                /* enable disable interrupt */
2110                if ((devpriv->b_Timer2Interrupt) == APCI3120_ENABLE) {
2111
2112                        devpriv->b_ModeSelectRegister =
2113                                devpriv->
2114                                b_ModeSelectRegister |
2115                                APCI3120_ENABLE_TIMER_INT;
2116                        /*  save the task structure to pass info to user */
2117                        devpriv->tsk_Current = current;
2118                } else {
2119
2120                        devpriv->b_ModeSelectRegister =
2121                                devpriv->
2122                                b_ModeSelectRegister &
2123                                APCI3120_DISABLE_TIMER_INT;
2124                }
2125                outb(devpriv->b_ModeSelectRegister,
2126                        devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
2127
2128                if (devpriv->b_Timer2Mode == APCI3120_TIMER) {  /* start timer */
2129                        /* For Timer mode is  Gate2 must be activated   **timer started */
2130                        devpriv->us_OutputRegister =
2131                                devpriv->
2132                                us_OutputRegister | APCI3120_ENABLE_TIMER2;
2133                        outw(devpriv->us_OutputRegister,
2134                                devpriv->iobase + APCI3120_WR_ADDRESS);
2135                }
2136
2137                break;
2138
2139        case APCI3120_STOP:
2140                if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
2141                        /* Disable timer */
2142                        devpriv->b_ModeSelectRegister =
2143                                devpriv->
2144                                b_ModeSelectRegister &
2145                                APCI3120_DISABLE_TIMER_COUNTER;
2146                } else {
2147                        /* Disable WatchDog */
2148                        devpriv->b_ModeSelectRegister =
2149                                devpriv->
2150                                b_ModeSelectRegister &
2151                                APCI3120_DISABLE_WATCHDOG;
2152                }
2153                /*  Disable timer interrupt */
2154                devpriv->b_ModeSelectRegister =
2155                        devpriv->
2156                        b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT;
2157
2158                /*  Write above states  to register */
2159                outb(devpriv->b_ModeSelectRegister,
2160                        devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
2161
2162                /*  Reset Gate 2 */
2163                devpriv->us_OutputRegister =
2164                        devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER_INT;
2165                outw(devpriv->us_OutputRegister,
2166                        devpriv->iobase + APCI3120_WR_ADDRESS);
2167
2168                /*  Reset FC_TIMER BIT */
2169                inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2170
2171                /* Disable timer */
2172                /* devpriv->b_Timer2Mode=APCI3120_DISABLE;  */
2173
2174                break;
2175
2176        case 2:         /* write new value to Timer */
2177                if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
2178                        comedi_error(dev,
2179                                "write :timer2  not configured  in TIMER MODE");
2180                        return -EINVAL;
2181                }
2182                /*  ui_Timervalue2=data[1]; // passed as argument */
2183                us_TmpValue =
2184                        (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
2185
2186/*
2187 * EL250804: Testing if board APCI3120 have the new Quartz or if it
2188 * is an APCI3001 and calculate the time value to set in the timer
2189 */
2190                if ((us_TmpValue & 0x00B0) == 0x00B0
2191                        || !strcmp(this_board->pc_DriverName, "apci3001")) {
2192                        /* Calculate the time value to set in the timer */
2193                        ui_Timervalue2 = ui_Timervalue2 / 50;
2194                } else {
2195                        /* Calculate the time value to set in the timer */
2196                        ui_Timervalue2 = ui_Timervalue2 / 70;
2197                }
2198                /* Writing LOW unsigned short */
2199                b_Tmp = ((devpriv->
2200                                b_DigitalOutputRegister) & 0xF0) |
2201                        APCI3120_SELECT_TIMER_2_LOW_WORD;
2202                outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2203
2204                outw(LOWORD(ui_Timervalue2),
2205                        devpriv->iobase + APCI3120_TIMER_VALUE);
2206
2207                /* Writing HIGH unsigned short */
2208                b_Tmp = ((devpriv->
2209                                b_DigitalOutputRegister) & 0xF0) |
2210                        APCI3120_SELECT_TIMER_2_HIGH_WORD;
2211                outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2212
2213                outw(HIWORD(ui_Timervalue2),
2214                        devpriv->iobase + APCI3120_TIMER_VALUE);
2215
2216                break;
2217        default:
2218                return -EINVAL; /*  Not a valid input */
2219        }
2220
2221        return insn->n;
2222}
2223
2224/*
2225+----------------------------------------------------------------------------+
2226| Function name     : int i_APCI3120_InsnReadTimer(struct comedi_device *dev,           |
2227|               struct comedi_subdevice *s,struct comedi_insn *insn, unsigned int *data)                 |
2228|                                                                                                                |
2229|                                                                                                |
2230+----------------------------------------------------------------------------+
2231| Task              : read the Timer value                                                       |
2232+----------------------------------------------------------------------------+
2233| Input Parameters  :   struct comedi_device *dev                                                                        |
2234|                     struct comedi_subdevice *s                                                                         |
2235|                     struct comedi_insn *insn                                      |
2236|                     unsigned int *data                                                                                 |
2237|                                                                                                                                |
2238+----------------------------------------------------------------------------+
2239| Return Value      :                                                                                                            |
2240|                       for Timer:      data[0]= Timer constant                                          |
2241|                                                                                                                                        |
2242|                       for watchdog: data[0]=0 (still running)                  |
2243|                                         data[0]=1  (run down)                                  |
2244|                                                                                                                            |
2245+----------------------------------------------------------------------------+
2246*/
2247int i_APCI3120_InsnReadTimer(struct comedi_device *dev, struct comedi_subdevice *s,
2248        struct comedi_insn *insn, unsigned int *data)
2249{
2250        unsigned char b_Tmp;
2251        unsigned short us_TmpValue, us_TmpValue_2, us_StatusValue;
2252
2253        if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
2254                && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
2255                comedi_error(dev, "\nread:timer2  not configured ");
2256        }
2257
2258        /* this_board->i_hwdrv_InsnReadTimer(dev,data); */
2259        if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
2260
2261                /* Read the LOW unsigned short of Timer 2 register */
2262                b_Tmp = ((devpriv->
2263                                b_DigitalOutputRegister) & 0xF0) |
2264                        APCI3120_SELECT_TIMER_2_LOW_WORD;
2265                outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2266
2267                us_TmpValue = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
2268
2269                /* Read the HIGH unsigned short of Timer 2 register */
2270                b_Tmp = ((devpriv->
2271                                b_DigitalOutputRegister) & 0xF0) |
2272                        APCI3120_SELECT_TIMER_2_HIGH_WORD;
2273                outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2274
2275                us_TmpValue_2 = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
2276
2277                /*  combining both words */
2278                data[0] = (unsigned int) ((us_TmpValue) | ((us_TmpValue_2) << 16));
2279
2280        } else {                        /*  Read watch dog status */
2281
2282                us_StatusValue = inw(devpriv->iobase + APCI3120_RD_STATUS);
2283                us_StatusValue =
2284                        ((us_StatusValue & APCI3120_FC_TIMER) >> 12) & 1;
2285                if (us_StatusValue == 1) {
2286                        /*  RESET FC_TIMER BIT */
2287                        inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2288                }
2289                data[0] = us_StatusValue;       /*  when data[0] = 1 then the watch dog has rundown */
2290        }
2291        return insn->n;
2292}
2293
2294/*
2295+----------------------------------------------------------------------------+
2296|                           DIGITAL INPUT SUBDEVICE                              |
2297+----------------------------------------------------------------------------+
2298*/
2299
2300/*
2301+----------------------------------------------------------------------------+
2302| Function name     :int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev,     |
2303|                       struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data)   |
2304|                                                                                                                |
2305|                                                                                                |
2306+----------------------------------------------------------------------------+
2307| Task              : Reads the value of the specified  Digital input channel|
2308|                                                                                                                |
2309+----------------------------------------------------------------------------+
2310| Input Parameters  : struct comedi_device *dev                                                                  |
2311|                     struct comedi_subdevice *s                                                                         |
2312|                     struct comedi_insn *insn                                      |
2313|                     unsigned int *data                                                                                 |
2314+----------------------------------------------------------------------------+
2315| Return Value      :                                                                            |
2316|                                                                                                                            |
2317+----------------------------------------------------------------------------+
2318*/
2319
2320int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev,
2321                                    struct comedi_subdevice *s,
2322                                    struct comedi_insn *insn,
2323                                    unsigned int *data)
2324{
2325        unsigned int ui_Chan, ui_TmpValue;
2326
2327        ui_Chan = CR_CHAN(insn->chanspec);      /*  channel specified */
2328
2329        /* this_board->i_hwdrv_InsnReadDigitalInput(dev,ui_Chan,data); */
2330        if (ui_Chan <= 3) {
2331                ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI3120_RD_STATUS);
2332
2333/*
2334 * since only 1 channel reqd to bring it to last bit it is rotated 8
2335 * +(chan - 1) times then ANDed with 1 for last bit.
2336 */
2337                *data = (ui_TmpValue >> (ui_Chan + 8)) & 1;
2338                /* return 0; */
2339        } else {
2340                /*       comedi_error(dev," chan spec wrong"); */
2341                return -EINVAL; /*  "sorry channel spec wrong " */
2342        }
2343        return insn->n;
2344
2345}
2346
2347/*
2348+----------------------------------------------------------------------------+
2349| Function name     :int i_APCI3120_InsnBitsDigitalInput(struct comedi_device *dev, |
2350|struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data)                      |
2351|                                                                                                                |
2352+----------------------------------------------------------------------------+
2353| Task              : Reads the value of the Digital input Port i.e.4channels|
2354|   value is returned in data[0]                                                                                         |
2355|                                                                                                                |
2356+----------------------------------------------------------------------------+
2357| Input Parameters  : struct comedi_device *dev                                                                  |
2358|                     struct comedi_subdevice *s                                                                         |
2359|                     struct comedi_insn *insn                                      |
2360|                     unsigned int *data                                                                                 |
2361+----------------------------------------------------------------------------+
2362| Return Value      :                                                                            |
2363|                                                                                                                            |
2364+----------------------------------------------------------------------------+
2365*/
2366int i_APCI3120_InsnBitsDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s,
2367        struct comedi_insn *insn, unsigned int *data)
2368{
2369        unsigned int ui_TmpValue;
2370        ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI3120_RD_STATUS);
2371        /*****  state of 4 channels  in the 11, 10, 9, 8   bits of status reg
2372                        rotated right 8 times to bring them to last four bits
2373                        ANDed with oxf for  value.
2374        *****/
2375
2376        *data = (ui_TmpValue >> 8) & 0xf;
2377        /* this_board->i_hwdrv_InsnBitsDigitalInput(dev,data); */
2378        return insn->n;
2379}
2380
2381/*
2382+----------------------------------------------------------------------------+
2383|                           DIGITAL OUTPUT SUBDEVICE                             |
2384+----------------------------------------------------------------------------+
2385*/
2386/*
2387+----------------------------------------------------------------------------+
2388| Function name     :int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device    |
2389| *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)                           |
2390|                                                                                                |
2391+----------------------------------------------------------------------------+
2392| Task              :Configure the output memory ON or OFF                                   |
2393|                                                                                                                |
2394+----------------------------------------------------------------------------+
2395| Input Parameters  :struct comedi_device *dev                                                                           |
2396|                     struct comedi_subdevice *s                                                                         |
2397|                     struct comedi_insn *insn                                      |
2398|                     unsigned int *data                                                                                 |
2399+----------------------------------------------------------------------------+
2400| Return Value      :                                                                            |
2401|                                                                                                                            |
2402+----------------------------------------------------------------------------+
2403*/
2404
2405int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device *dev,
2406        struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data)
2407{
2408
2409        if ((data[0] != 0) && (data[0] != 1)) {
2410                comedi_error(dev,
2411                        "Not a valid Data !!! ,Data should be 1 or 0\n");
2412                return -EINVAL;
2413        }
2414        if (data[0]) {
2415                devpriv->b_OutputMemoryStatus = APCI3120_ENABLE;
2416
2417        } else {
2418                devpriv->b_OutputMemoryStatus = APCI3120_DISABLE;
2419                devpriv->b_DigitalOutputRegister = 0;
2420        }
2421        if (!devpriv->b_OutputMemoryStatus)
2422                ui_Temp = 0;
2423                                /* if(!devpriv->b_OutputMemoryStatus ) */
2424
2425        return insn->n;
2426}
2427
2428/*
2429+----------------------------------------------------------------------------+
2430| Function name     :int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device *dev,    |
2431|               struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data)                 |
2432|                                                                                                                |
2433+----------------------------------------------------------------------------+
2434| Task              : write diatal output port                                                       |
2435|                                                                                                                |
2436+----------------------------------------------------------------------------+
2437| Input Parameters  : struct comedi_device *dev                                                                  |
2438|                     struct comedi_subdevice *s                                                                         |
2439|                     struct comedi_insn *insn                                      |
2440|                     unsigned int *data                                                                                 |
2441|                      data[0]     Value to be written
2442|                      data[1]    :1 Set digital o/p ON
2443|                      data[1]     2 Set digital o/p OFF with memory ON
2444+----------------------------------------------------------------------------+
2445| Return Value      :                                                                            |
2446|                                                                                                                            |
2447+----------------------------------------------------------------------------+
2448*/
2449
2450int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device *dev,
2451                                     struct comedi_subdevice *s,
2452                                     struct comedi_insn *insn,
2453                                     unsigned int *data)
2454{
2455        if ((data[0] > this_board->i_DoMaxdata) || (data[0] < 0)) {
2456
2457                comedi_error(dev, "Data is not valid !!! \n");
2458                return -EINVAL;
2459        }
2460
2461        switch (data[1]) {
2462        case 1:
2463                data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister;
2464                break;
2465
2466        case 2:
2467                data[0] = data[0];
2468                break;
2469        default:
2470                printk("\nThe parameter passed is in error \n");
2471                return -EINVAL;
2472        }                       /*  switch(data[1]) */
2473        outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
2474
2475        devpriv->b_DigitalOutputRegister = data[0] & 0xF0;
2476
2477        return insn->n;
2478
2479}
2480
2481/*
2482+----------------------------------------------------------------------------+
2483| Function name         :int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev,|
2484|struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)        |
2485|                                                                               |
2486+----------------------------------------------------------------------------+
2487| Task                  : Write digiatl output                                  |
2488|                                                                               |
2489+----------------------------------------------------------------------------+
2490| Input Parameters      : struct comedi_device *dev                             |
2491|                       struct comedi_subdevice *s                              |
2492|                       struct comedi_insn *insn                                |
2493|                       unsigned int *data                                      |
2494                        data[0]     Value to be written
2495                        data[1]    :1 Set digital o/p ON
2496                        data[1]     2 Set digital o/p OFF with memory ON
2497+----------------------------------------------------------------------------+
2498| Return Value          :                                                       |
2499|                                                                               |
2500+----------------------------------------------------------------------------+
2501*/
2502
2503int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev,
2504                                      struct comedi_subdevice *s,
2505                                      struct comedi_insn *insn,
2506                                      unsigned int *data)
2507{
2508
2509        unsigned int ui_Temp1;
2510
2511        unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec);  /*  get the channel */
2512
2513        if ((data[0] != 0) && (data[0] != 1)) {
2514                comedi_error(dev,
2515                        "Not a valid Data !!! ,Data should be 1 or 0\n");
2516                return -EINVAL;
2517        }
2518        if (ui_NoOfChannel > this_board->i_NbrDoChannel - 1) {
2519                comedi_error(dev,
2520                        "This board doesn't have specified channel !!! \n");
2521                return -EINVAL;
2522        }
2523
2524        switch (data[1]) {
2525        case 1:
2526                data[0] = (data[0] << ui_NoOfChannel);
2527/* ES05                   data[0]=(data[0]<<4)|ui_Temp; */
2528                data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister;
2529                break;
2530
2531        case 2:
2532                data[0] = ~data[0] & 0x1;
2533                ui_Temp1 = 1;
2534                ui_Temp1 = ui_Temp1 << ui_NoOfChannel;
2535                ui_Temp1 = ui_Temp1 << 4;
2536/* ES05                   ui_Temp=ui_Temp|ui_Temp1; */
2537                devpriv->b_DigitalOutputRegister =
2538                        devpriv->b_DigitalOutputRegister | ui_Temp1;
2539
2540                data[0] = (data[0] << ui_NoOfChannel) ^ 0xf;
2541                data[0] = data[0] << 4;
2542/* ES05                   data[0]=data[0]& ui_Temp; */
2543                data[0] = data[0] & devpriv->b_DigitalOutputRegister;
2544                break;
2545        default:
2546                printk("\nThe parameter passed is in error \n");
2547                return -EINVAL;
2548        }                       /*  switch(data[1]) */
2549        outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
2550
2551/* ES05        ui_Temp=data[0] & 0xf0; */
2552        devpriv->b_DigitalOutputRegister = data[0] & 0xf0;
2553        return insn->n;
2554
2555}
2556
2557/*
2558+----------------------------------------------------------------------------+
2559|                            ANALOG OUTPUT SUBDEVICE                         |
2560+----------------------------------------------------------------------------+
2561*/
2562
2563/*
2564+----------------------------------------------------------------------------+
2565| Function name     :int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,|
2566|struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data)                                    |
2567|                                                                                                                |
2568+----------------------------------------------------------------------------+
2569| Task              : Write  analog output                                                           |
2570|                                                                                                                |
2571+----------------------------------------------------------------------------+
2572| Input Parameters  : struct comedi_device *dev                                                                  |
2573|                     struct comedi_subdevice *s                                                                         |
2574|                     struct comedi_insn *insn                                      |
2575|                     unsigned int *data                                                                                 |
2576+----------------------------------------------------------------------------+
2577| Return Value      :                                                                            |
2578|                                                                                                                            |
2579+----------------------------------------------------------------------------+
2580*/
2581
2582int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,
2583                                     struct comedi_subdevice *s,
2584                                     struct comedi_insn *insn,
2585                                     unsigned int *data)
2586{
2587        unsigned int ui_Range, ui_Channel;
2588        unsigned short us_TmpValue;
2589
2590        ui_Range = CR_RANGE(insn->chanspec);
2591        ui_Channel = CR_CHAN(insn->chanspec);
2592
2593        /* this_board->i_hwdrv_InsnWriteAnalogOutput(dev, ui_Range, ui_Channel,data[0]); */
2594        if (ui_Range) {         /*  if 1 then unipolar */
2595
2596                if (data[0] != 0)
2597                        data[0] =
2598                                ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
2599                                        13) | (data[0] + 8191));
2600                else
2601                        data[0] =
2602                                ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
2603                                        13) | 8192);
2604
2605        } else {                        /*  if 0 then   bipolar */
2606                data[0] =
2607                        ((((ui_Channel & 0x03) << 14) & 0xC000) | (0 << 13) |
2608                        data[0]);
2609
2610        }
2611
2612/*
2613 * out put n values at the given channel. printk("\nwaiting for
2614 * DA_READY BIT");
2615 */
2616        do {                    /* Waiting of DA_READY BIT */
2617                us_TmpValue =
2618                        ((unsigned short) inw(devpriv->iobase +
2619                                APCI3120_RD_STATUS)) & 0x0001;
2620        } while (us_TmpValue != 0x0001);
2621
2622        if (ui_Channel <= 3)
2623/*
2624 * for channel 0-3 out at the register 1 (wrDac1-8) data[i]
2625 * typecasted to ushort since word write is to be done
2626 */
2627                outw((unsigned short) data[0],
2628                        devpriv->iobase + APCI3120_ANALOG_OUTPUT_1);
2629        else
2630/*
2631 * for channel 4-7 out at the register 2 (wrDac5-8) data[i]
2632 * typecasted to ushort since word write is to be done
2633 */
2634                outw((unsigned short) data[0],
2635                        devpriv->iobase + APCI3120_ANALOG_OUTPUT_2);
2636
2637        return insn->n;
2638}
2639
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.