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