hwdrv_apci3120.c revision 71b5f4f11971dea972832ad63a994c7e5b45db6b
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| comedi_subdevice *s,comedi_insn *insn,unsigned int *data) | 62| | 63+----------------------------------------------------------------------------+ 64| Task : Calls card specific function | 65| | 66+----------------------------------------------------------------------------+ 67| Input Parameters : struct comedi_device *dev | 68| comedi_subdevice *s | 69| comedi_insn *insn | 70| unsigned int *data | 71+----------------------------------------------------------------------------+ 72| Return Value : | 73| | 74+----------------------------------------------------------------------------+ 75*/ 76 77int i_APCI3120_InsnConfigAnalogInput(struct comedi_device * dev, comedi_subdevice * s, 78 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| comedi_subdevice *s,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| comedi_subdevice *s | 140| comedi_insn *insn | 141| unsigned int *data | 142+----------------------------------------------------------------------------+ 143| Return Value : | 144| | 145+----------------------------------------------------------------------------+ 146*/ 147 148int i_APCI3120_InsnReadAnalogInput(struct comedi_device * dev, comedi_subdevice * s, 149 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| comedi_subdevice *s)| 398| | 399+----------------------------------------------------------------------------+ 400| Task : Stops Cyclic acquisition | 401| | 402+----------------------------------------------------------------------------+ 403| Input Parameters : struct comedi_device *dev | 404| comedi_subdevice *s | 405| | 406+----------------------------------------------------------------------------+ 407| Return Value :0 | 408| | 409+----------------------------------------------------------------------------+ 410*/ 411 412int i_APCI3120_StopCyclicAcquisition(struct comedi_device * dev, 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| ,comedi_subdevice *s,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| comedi_subdevice *s | 472| comedi_cmd *cmd | 473+----------------------------------------------------------------------------+ 474| Return Value :0 | 475| | 476+----------------------------------------------------------------------------+ 477*/ 478 479int i_APCI3120_CommandTestAnalogInput(struct comedi_device * dev, comedi_subdevice * s, 480 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| 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| comedi_subdevice *s | 629| | 630+----------------------------------------------------------------------------+ 631| Return Value : | 632| | 633+----------------------------------------------------------------------------+ 634*/ 635 636int i_APCI3120_CommandAnalogInput(struct comedi_device * dev, comedi_subdevice * s) 637{ 638 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,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 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| 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| 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, 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 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/*int i_APCI3120_InterruptHandleEos(struct comedi_device *dev) 1634{ 1635 int n_chan,i; 1636 short *data; 1637 comedi_subdevice *s=dev->subdevices+0; 1638 comedi_async *async = s->async; 1639 data=async->data+async->buf_int_ptr;//new samples added from here onwards 1640 n_chan=devpriv->ui_AiNbrofChannels; 1641 1642 for(i=0;i<n_chan;i++) 1643 { 1644 data[i]=inw(dev->iobase+0); 1645 } 1646 async->buf_int_count+=n_chan*sizeof(short); 1647 async->buf_int_ptr+=n_chan*sizeof(short); 1648 comedi_eos(dev,s); 1649 if (s->async->buf_int_ptr>=s->async->data_len) // for buffer rool over 1650 { 1651*//* buffer rollover */ 1652/* s->async->buf_int_ptr=0; 1653 comedi_eobuf(dev,s); 1654 } 1655 return 0; 1656}*/ 1657int i_APCI3120_InterruptHandleEos(struct comedi_device * dev) 1658{ 1659 int n_chan, i; 1660 comedi_subdevice *s = dev->subdevices + 0; 1661 int err = 1; 1662 1663 n_chan = devpriv->ui_AiNbrofChannels; 1664 1665 s->async->events = 0; 1666 1667 for (i = 0; i < n_chan; i++) 1668 err &= comedi_buf_put(s->async, inw(dev->iobase + 0)); 1669 1670 s->async->events |= COMEDI_CB_EOS; 1671 1672 if (err == 0) 1673 s->async->events |= COMEDI_CB_OVERFLOW; 1674 1675 comedi_event(dev, s); 1676 1677 return 0; 1678} 1679 1680/* 1681+----------------------------------------------------------------------------+ 1682| Function name : void v_APCI3120_InterruptDma(int irq, void *d) | 1683| | 1684+----------------------------------------------------------------------------+ 1685| Task : This is a handler for the DMA interrupt | 1686| This function copies the data to Comedi Buffer. | 1687| For continuous DMA it reinitializes the DMA operation. | 1688| For single mode DMA it stop the acquisition. | 1689| | 1690+----------------------------------------------------------------------------+ 1691| Input Parameters : int irq, void *d | 1692| | 1693+----------------------------------------------------------------------------+ 1694| Return Value : void | 1695| | 1696+----------------------------------------------------------------------------+ 1697*/ 1698 1699void v_APCI3120_InterruptDma(int irq, void *d) 1700{ 1701 struct comedi_device *dev = d; 1702 comedi_subdevice *s = dev->subdevices + 0; 1703 unsigned int next_dma_buf, samplesinbuf; 1704 unsigned long low_word, high_word, var; 1705 1706 UINT ui_Tmp; 1707 samplesinbuf = 1708 devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer] - 1709 inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_MWTC); 1710 1711 if (samplesinbuf < 1712 devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer]) { 1713 comedi_error(dev, "Interrupted DMA transfer!"); 1714 } 1715 if (samplesinbuf & 1) { 1716 comedi_error(dev, "Odd count of bytes in DMA ring!"); 1717 i_APCI3120_StopCyclicAcquisition(dev, s); 1718 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; 1719 1720 return; 1721 } 1722 samplesinbuf = samplesinbuf >> 1; // number of received samples 1723 if (devpriv->b_DmaDoubleBuffer) { 1724 // switch DMA buffers if is used double buffering 1725 next_dma_buf = 1 - devpriv->ui_DmaActualBuffer; 1726 1727 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO; 1728 outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS); 1729 1730 // changed since 16 bit interface for add on 1731 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0); 1732 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW, 1733 devpriv->i_IobaseAddon + 2); 1734 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0); 1735 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); // 0x1000 is out putted in windows driver 1736 1737 var = devpriv->ul_DmaBufferHw[next_dma_buf]; 1738 low_word = var & 0xffff; 1739 var = devpriv->ul_DmaBufferHw[next_dma_buf]; 1740 high_word = var / 65536; 1741 1742 /* DMA Start Adress Low */ 1743 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0); 1744 outw(low_word, devpriv->i_IobaseAddon + 2); 1745 1746 /* DMA Start Adress High */ 1747 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0); 1748 outw(high_word, devpriv->i_IobaseAddon + 2); 1749 1750 var = devpriv->ui_DmaBufferUsesize[next_dma_buf]; 1751 low_word = var & 0xffff; 1752 var = devpriv->ui_DmaBufferUsesize[next_dma_buf]; 1753 high_word = var / 65536; 1754 1755 /* Nbr of acquisition LOW */ 1756 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0); 1757 outw(low_word, devpriv->i_IobaseAddon + 2); 1758 1759 /* Nbr of acquisition HIGH */ 1760 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0); 1761 outw(high_word, devpriv->i_IobaseAddon + 2); 1762 1763 // To configure A2P FIFO 1764 // ENABLE A2P FIFO WRITE AND ENABLE AMWEN 1765 // AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03 1766 outw(3, devpriv->i_IobaseAddon + 4); 1767 //initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) 1768 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 | 1769 APCI3120_ENABLE_WRITE_TC_INT), 1770 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); 1771 1772 } 1773/*UPDATE-0.7.57->0.7.68 1774 ptr=(short *)devpriv->ul_DmaBufferVirtual[devpriv->ui_DmaActualBuffer]; 1775 1776 1777 // if there is not enough space left in the buffer to copy all data contained in the DMABufferVirtual 1778 if(s->async->buf_int_ptr+samplesinbuf*sizeof(short)>=devpriv->ui_AiDataLength) 1779 { 1780 m=(devpriv->ui_AiDataLength-s->async->buf_int_ptr)/sizeof(short); 1781 v_APCI3120_InterruptDmaMoveBlock16bit(dev,s,(void *)ptr,((void *)(devpriv->AiData))+s->async->buf_int_ptr,m); 1782 s->async->buf_int_count+=m*sizeof(short); 1783 ptr+=m*sizeof(short); 1784 samplesinbuf-=m; 1785 s->async->buf_int_ptr=0; 1786 comedi_eobuf(dev,s); 1787 } 1788 1789 if (samplesinbuf) 1790 { 1791 v_APCI3120_InterruptDmaMoveBlock16bit(dev,s,(void *)ptr,((void *)(devpriv->AiData))+s->async->buf_int_ptr,samplesinbuf); 1792 1793 s->async->buf_int_count+=samplesinbuf*sizeof(short); 1794 s->async->buf_int_ptr+=samplesinbuf*sizeof(short); 1795 if (!(devpriv->ui_AiFlags & TRIG_WAKE_EOS)) 1796 { 1797 comedi_bufcheck(dev,s); 1798 } 1799 } 1800 if (!devpriv->b_AiContinuous) 1801 if ( devpriv->ui_AiActualScan>=devpriv->ui_AiNbrofScans ) 1802 { 1803 // all data sampled 1804 i_APCI3120_StopCyclicAcquisition(dev,s); 1805 devpriv->b_AiCyclicAcquisition=APCI3120_DISABLE; 1806 //DPRINTK("\n Single DMA completed..\n"); 1807 comedi_done(dev,s); 1808 return; 1809 } 1810*/ 1811 if (samplesinbuf) { 1812 v_APCI3120_InterruptDmaMoveBlock16bit(dev, s, 1813 devpriv->ul_DmaBufferVirtual[devpriv-> 1814 ui_DmaActualBuffer], samplesinbuf); 1815 1816 if (!(devpriv->ui_AiFlags & TRIG_WAKE_EOS)) { 1817 s->async->events |= COMEDI_CB_EOS; 1818 comedi_event(dev, s); 1819 } 1820 } 1821 if (!devpriv->b_AiContinuous) 1822 if (devpriv->ui_AiActualScan >= devpriv->ui_AiNbrofScans) { 1823 // all data sampled 1824 i_APCI3120_StopCyclicAcquisition(dev, s); 1825 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; 1826 s->async->events |= COMEDI_CB_EOA; 1827 comedi_event(dev, s); 1828 return; 1829 } 1830 1831 if (devpriv->b_DmaDoubleBuffer) { // switch dma buffers 1832 devpriv->ui_DmaActualBuffer = 1 - devpriv->ui_DmaActualBuffer; 1833 } else { 1834 // restart DMA if is not used double buffering 1835 //ADDED REINITIALISE THE DMA 1836 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO; 1837 outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS); 1838 1839 // changed since 16 bit interface for add on 1840 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0); 1841 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW, 1842 devpriv->i_IobaseAddon + 2); 1843 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0); 1844 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); // 1845 // A2P FIFO MANAGEMENT 1846 // A2P fifo reset & transfer control enable 1847 outl(APCI3120_A2P_FIFO_MANAGEMENT, 1848 devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR); 1849 1850 var = devpriv->ul_DmaBufferHw[0]; 1851 low_word = var & 0xffff; 1852 var = devpriv->ul_DmaBufferHw[0]; 1853 high_word = var / 65536; 1854 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0); 1855 outw(low_word, devpriv->i_IobaseAddon + 2); 1856 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0); 1857 outw(high_word, devpriv->i_IobaseAddon + 2); 1858 1859 var = devpriv->ui_DmaBufferUsesize[0]; 1860 low_word = var & 0xffff; //changed 1861 var = devpriv->ui_DmaBufferUsesize[0]; 1862 high_word = var / 65536; 1863 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0); 1864 outw(low_word, devpriv->i_IobaseAddon + 2); 1865 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0); 1866 outw(high_word, devpriv->i_IobaseAddon + 2); 1867 1868 // To configure A2P FIFO 1869 //ENABLE A2P FIFO WRITE AND ENABLE AMWEN 1870 // AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03 1871 outw(3, devpriv->i_IobaseAddon + 4); 1872 //initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) 1873 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 | 1874 APCI3120_ENABLE_WRITE_TC_INT), 1875 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); 1876 } 1877} 1878 1879/* 1880+----------------------------------------------------------------------------+ 1881| Function name :void v_APCI3120_InterruptDmaMoveBlock16bit(comedi_device| 1882|*dev,comedi_subdevice *s,short *dma,short *data,int n) | 1883| | 1884+----------------------------------------------------------------------------+ 1885| Task : This function copies the data from DMA buffer to the | 1886| Comedi buffer | 1887| | 1888+----------------------------------------------------------------------------+ 1889| Input Parameters : struct comedi_device *dev | 1890| comedi_subdevice *s | 1891| short *dma | 1892| short *data,int n | 1893+----------------------------------------------------------------------------+ 1894| Return Value : void | 1895| | 1896+----------------------------------------------------------------------------+ 1897*/ 1898 1899/*void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev,comedi_subdevice *s,short *dma,short *data,int n) 1900{ 1901 int i,j,m; 1902 1903 j=s->async->cur_chan; 1904 m=devpriv->ui_AiActualScanPosition; 1905 for(i=0;i<n;i++) 1906 { 1907 *data=*dma; 1908 data++; dma++; 1909 j++; 1910 if(j>=devpriv->ui_AiNbrofChannels) 1911 { 1912 m+=j; 1913 j=0; 1914 if(m>=devpriv->ui_AiScanLength) 1915 { 1916 m=0; 1917 devpriv->ui_AiActualScan++; 1918 if (devpriv->ui_AiFlags & TRIG_WAKE_EOS) 1919;//UPDATE-0.7.57->0.7.68 comedi_eos(dev,s); 1920 } 1921 } 1922 } 1923 devpriv->ui_AiActualScanPosition=m; 1924 s->async->cur_chan=j; 1925 1926} 1927*/ 1928void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device * dev, 1929 comedi_subdevice * s, short * dma_buffer, unsigned int num_samples) 1930{ 1931 devpriv->ui_AiActualScan += 1932 (s->async->cur_chan + num_samples) / devpriv->ui_AiScanLength; 1933 s->async->cur_chan += num_samples; 1934 s->async->cur_chan %= devpriv->ui_AiScanLength; 1935 1936 cfc_write_array_to_buffer(s, dma_buffer, num_samples * sizeof(short)); 1937} 1938 1939/* 1940+----------------------------------------------------------------------------+ 1941| TIMER SUBDEVICE | 1942+----------------------------------------------------------------------------+ 1943*/ 1944 1945/* 1946+----------------------------------------------------------------------------+ 1947| Function name :int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, | 1948| comedi_subdevice *s,comedi_insn *insn,unsigned int *data) | 1949| | 1950+----------------------------------------------------------------------------+ 1951| Task :Configure Timer 2 | 1952| | 1953+----------------------------------------------------------------------------+ 1954| Input Parameters : struct comedi_device *dev | 1955| comedi_subdevice *s | 1956| comedi_insn *insn | 1957| unsigned int *data | 1958| | 1959| data[0]= TIMER configure as timer | 1960| = WATCHDOG configure as watchdog | 1961| data[1] = Timer constant | 1962| data[2] = Timer2 interrupt (1)enable or(0) disable | 1963| | 1964+----------------------------------------------------------------------------+ 1965| Return Value : | 1966| | 1967+----------------------------------------------------------------------------+ 1968*/ 1969 1970int i_APCI3120_InsnConfigTimer(struct comedi_device * dev, comedi_subdevice * s, 1971 comedi_insn * insn, unsigned int * data) 1972{ 1973 1974 UINT ui_Timervalue2; 1975 USHORT us_TmpValue; 1976 BYTE b_Tmp; 1977 1978 if (!data[1]) 1979 comedi_error(dev, "config:No timer constant !"); 1980 1981 devpriv->b_Timer2Interrupt = (BYTE) data[2]; // save info whether to enable or disable interrupt 1982 1983 ui_Timervalue2 = data[1] / 1000; // convert nano seconds to u seconds 1984 1985 //this_board->i_hwdrv_InsnConfigTimer(dev, ui_Timervalue2,(BYTE)data[0]); 1986 us_TmpValue = (USHORT) inw(devpriv->iobase + APCI3120_RD_STATUS); 1987 1988 //EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 1989 // and calculate the time value to set in the timer 1990 if ((us_TmpValue & 0x00B0) == 0x00B0 1991 || !strcmp(this_board->pc_DriverName, "apci3001")) { 1992 //Calculate the time value to set in the timer 1993 ui_Timervalue2 = ui_Timervalue2 / 50; 1994 } else { 1995 //Calculate the time value to set in the timer 1996 ui_Timervalue2 = ui_Timervalue2 / 70; 1997 } 1998 1999 //Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0) 2000 devpriv->us_OutputRegister = 2001 devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER2; 2002 outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS); 2003 2004 // Disable TIMER Interrupt 2005 devpriv->b_ModeSelectRegister = 2006 devpriv-> 2007 b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT & 0xEF; 2008 2009 // Disable Eoc and Eos Interrupts 2010 devpriv->b_ModeSelectRegister = 2011 devpriv-> 2012 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT & 2013 APCI3120_DISABLE_EOS_INT; 2014 outb(devpriv->b_ModeSelectRegister, 2015 devpriv->iobase + APCI3120_WRITE_MODE_SELECT); 2016 if (data[0] == APCI3120_TIMER) //initialize timer 2017 { 2018 2019 //devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister| APCI3120_ENABLE_TIMER_INT ; 2020 //outb(devpriv->b_ModeSelectRegister,devpriv->iobase+APCI3120_WRITE_MODE_SELECT); 2021 2022 //Set the Timer 2 in mode 2(Timer) 2023 devpriv->b_TimerSelectMode = 2024 (devpriv-> 2025 b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_2; 2026 outb(devpriv->b_TimerSelectMode, 2027 devpriv->iobase + APCI3120_TIMER_CRT1); 2028 2029 //Configure the timer 2 for writing the LOW WORD of timer is Delay value 2030 //You must make a b_tmp variable with DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0 2031 //you can set the digital output and configure the timer 2,and if you don't make this, digital output 2032 //are erase (Set to 0) 2033 2034 //Writing LOW WORD 2035 b_Tmp = ((devpriv-> 2036 b_DigitalOutputRegister) & 0xF0) | 2037 APCI3120_SELECT_TIMER_2_LOW_WORD; 2038 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); 2039 outw(LOWORD(ui_Timervalue2), 2040 devpriv->iobase + APCI3120_TIMER_VALUE); 2041 2042 //Writing HIGH WORD 2043 b_Tmp = ((devpriv-> 2044 b_DigitalOutputRegister) & 0xF0) | 2045 APCI3120_SELECT_TIMER_2_HIGH_WORD; 2046 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); 2047 outw(HIWORD(ui_Timervalue2), 2048 devpriv->iobase + APCI3120_TIMER_VALUE); 2049 // timer2 in Timer mode enabled 2050 devpriv->b_Timer2Mode = APCI3120_TIMER; 2051 2052 } else // Initialize Watch dog 2053 { 2054 2055 //Set the Timer 2 in mode 5(Watchdog) 2056 2057 devpriv->b_TimerSelectMode = 2058 (devpriv-> 2059 b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_5; 2060 outb(devpriv->b_TimerSelectMode, 2061 devpriv->iobase + APCI3120_TIMER_CRT1); 2062 2063 //Configure the timer 2 for writing the LOW WORD of timer is Delay value 2064 //You must make a b_tmp variable with DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0 2065 //you can set the digital output and configure the timer 2,and if you don't make this, digital output 2066 //are erase (Set to 0) 2067 2068 //Writing LOW WORD 2069 b_Tmp = ((devpriv-> 2070 b_DigitalOutputRegister) & 0xF0) | 2071 APCI3120_SELECT_TIMER_2_LOW_WORD; 2072 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); 2073 outw(LOWORD(ui_Timervalue2), 2074 devpriv->iobase + APCI3120_TIMER_VALUE); 2075 2076 //Writing HIGH WORD 2077 b_Tmp = ((devpriv-> 2078 b_DigitalOutputRegister) & 0xF0) | 2079 APCI3120_SELECT_TIMER_2_HIGH_WORD; 2080 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); 2081 2082 outw(HIWORD(ui_Timervalue2), 2083 devpriv->iobase + APCI3120_TIMER_VALUE); 2084 //watchdog enabled 2085 devpriv->b_Timer2Mode = APCI3120_WATCHDOG; 2086 2087 } 2088 2089 return insn->n; 2090 2091} 2092 2093/* 2094+----------------------------------------------------------------------------+ 2095| Function name :int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, | 2096| comedi_subdevice *s, comedi_insn *insn,unsigned int *data) | 2097| | 2098+----------------------------------------------------------------------------+ 2099| Task : To start and stop the timer | 2100+----------------------------------------------------------------------------+ 2101| Input Parameters : struct comedi_device *dev | 2102| comedi_subdevice *s | 2103| comedi_insn *insn | 2104| unsigned int *data | 2105| | 2106| data[0] = 1 (start) | 2107| data[0] = 0 (stop ) | 2108| data[0] = 2 (write new value) | 2109| data[1]= new value | 2110| | 2111| devpriv->b_Timer2Mode = 0 DISABLE | 2112| 1 Timer | 2113| 2 Watch dog | 2114| | 2115+----------------------------------------------------------------------------+ 2116| Return Value : | 2117| | 2118+----------------------------------------------------------------------------+ 2119*/ 2120 2121int i_APCI3120_InsnWriteTimer(struct comedi_device * dev, comedi_subdevice * s, 2122 comedi_insn * insn, unsigned int * data) 2123{ 2124 2125 UINT ui_Timervalue2 = 0; 2126 USHORT us_TmpValue; 2127 BYTE b_Tmp; 2128 2129 if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG) 2130 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) { 2131 comedi_error(dev, "\nwrite:timer2 not configured "); 2132 return -EINVAL; 2133 } 2134 2135 if (data[0] == 2) // write new value 2136 { 2137 if (devpriv->b_Timer2Mode != APCI3120_TIMER) { 2138 comedi_error(dev, 2139 "write :timer2 not configured in TIMER MODE"); 2140 return -EINVAL; 2141 } 2142 2143 if (data[1]) 2144 ui_Timervalue2 = data[1]; 2145 else 2146 ui_Timervalue2 = 0; 2147 } 2148 2149 //this_board->i_hwdrv_InsnWriteTimer(dev,data[0],ui_Timervalue2); 2150 2151 switch (data[0]) { 2152 case APCI3120_START: 2153 2154 // Reset FC_TIMER BIT 2155 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER); 2156 if (devpriv->b_Timer2Mode == APCI3120_TIMER) //start timer 2157 { 2158 //Enable Timer 2159 devpriv->b_ModeSelectRegister = 2160 devpriv->b_ModeSelectRegister & 0x0B; 2161 } else //start watch dog 2162 { 2163 //Enable WatchDog 2164 devpriv->b_ModeSelectRegister = 2165 (devpriv-> 2166 b_ModeSelectRegister & 0x0B) | 2167 APCI3120_ENABLE_WATCHDOG; 2168 } 2169 2170 //enable disable interrupt 2171 if ((devpriv->b_Timer2Interrupt) == APCI3120_ENABLE) { 2172 2173 devpriv->b_ModeSelectRegister = 2174 devpriv-> 2175 b_ModeSelectRegister | 2176 APCI3120_ENABLE_TIMER_INT; 2177 // save the task structure to pass info to user 2178 devpriv->tsk_Current = current; 2179 } else { 2180 2181 devpriv->b_ModeSelectRegister = 2182 devpriv-> 2183 b_ModeSelectRegister & 2184 APCI3120_DISABLE_TIMER_INT; 2185 } 2186 outb(devpriv->b_ModeSelectRegister, 2187 devpriv->iobase + APCI3120_WRITE_MODE_SELECT); 2188 2189 if (devpriv->b_Timer2Mode == APCI3120_TIMER) //start timer 2190 { 2191 //For Timer mode is Gate2 must be activated **timer started 2192 devpriv->us_OutputRegister = 2193 devpriv-> 2194 us_OutputRegister | APCI3120_ENABLE_TIMER2; 2195 outw(devpriv->us_OutputRegister, 2196 devpriv->iobase + APCI3120_WR_ADDRESS); 2197 } 2198 2199 break; 2200 2201 case APCI3120_STOP: 2202 if (devpriv->b_Timer2Mode == APCI3120_TIMER) { 2203 //Disable timer 2204 devpriv->b_ModeSelectRegister = 2205 devpriv-> 2206 b_ModeSelectRegister & 2207 APCI3120_DISABLE_TIMER_COUNTER; 2208 } else { 2209 //Disable WatchDog 2210 devpriv->b_ModeSelectRegister = 2211 devpriv-> 2212 b_ModeSelectRegister & 2213 APCI3120_DISABLE_WATCHDOG; 2214 } 2215 // Disable timer interrupt 2216 devpriv->b_ModeSelectRegister = 2217 devpriv-> 2218 b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT; 2219 2220 // Write above states to register 2221 outb(devpriv->b_ModeSelectRegister, 2222 devpriv->iobase + APCI3120_WRITE_MODE_SELECT); 2223 2224 // Reset Gate 2 2225 devpriv->us_OutputRegister = 2226 devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER_INT; 2227 outw(devpriv->us_OutputRegister, 2228 devpriv->iobase + APCI3120_WR_ADDRESS); 2229 2230 // Reset FC_TIMER BIT 2231 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER); 2232 2233 // Disable timer 2234 //devpriv->b_Timer2Mode=APCI3120_DISABLE; 2235 2236 break; 2237 2238 case 2: //write new value to Timer 2239 if (devpriv->b_Timer2Mode != APCI3120_TIMER) { 2240 comedi_error(dev, 2241 "write :timer2 not configured in TIMER MODE"); 2242 return -EINVAL; 2243 } 2244 // ui_Timervalue2=data[1]; // passed as argument 2245 us_TmpValue = 2246 (USHORT) inw(devpriv->iobase + APCI3120_RD_STATUS); 2247 2248 //EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 2249 // and calculate the time value to set in the timer 2250 if ((us_TmpValue & 0x00B0) == 0x00B0 2251 || !strcmp(this_board->pc_DriverName, "apci3001")) { 2252 //Calculate the time value to set in the timer 2253 ui_Timervalue2 = ui_Timervalue2 / 50; 2254 } else { 2255 //Calculate the time value to set in the timer 2256 ui_Timervalue2 = ui_Timervalue2 / 70; 2257 } 2258 //Writing LOW WORD 2259 b_Tmp = ((devpriv-> 2260 b_DigitalOutputRegister) & 0xF0) | 2261 APCI3120_SELECT_TIMER_2_LOW_WORD; 2262 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); 2263 2264 outw(LOWORD(ui_Timervalue2), 2265 devpriv->iobase + APCI3120_TIMER_VALUE); 2266 2267 //Writing HIGH WORD 2268 b_Tmp = ((devpriv-> 2269 b_DigitalOutputRegister) & 0xF0) | 2270 APCI3120_SELECT_TIMER_2_HIGH_WORD; 2271 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); 2272 2273 outw(HIWORD(ui_Timervalue2), 2274 devpriv->iobase + APCI3120_TIMER_VALUE); 2275 2276 break; 2277 default: 2278 return -EINVAL; // Not a valid input 2279 } 2280 2281 return insn->n; 2282} 2283 2284/* 2285+----------------------------------------------------------------------------+ 2286| Function name : int i_APCI3120_InsnReadTimer(struct comedi_device *dev, | 2287| comedi_subdevice *s,comedi_insn *insn, unsigned int *data) | 2288| | 2289| | 2290+----------------------------------------------------------------------------+ 2291| Task : read the Timer value | 2292+----------------------------------------------------------------------------+ 2293| Input Parameters : struct comedi_device *dev | 2294| comedi_subdevice *s | 2295| comedi_insn *insn | 2296| unsigned int *data | 2297| | 2298+----------------------------------------------------------------------------+ 2299| Return Value : | 2300| for Timer: data[0]= Timer constant | 2301| | 2302| for watchdog: data[0]=0 (still running) | 2303| data[0]=1 (run down) | 2304| | 2305+----------------------------------------------------------------------------+ 2306*/ 2307int i_APCI3120_InsnReadTimer(struct comedi_device * dev, comedi_subdevice * s, 2308 comedi_insn * insn, unsigned int * data) 2309{ 2310 BYTE b_Tmp; 2311 USHORT us_TmpValue, us_TmpValue_2, us_StatusValue; 2312 2313 if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG) 2314 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) { 2315 comedi_error(dev, "\nread:timer2 not configured "); 2316 } 2317 2318 //this_board->i_hwdrv_InsnReadTimer(dev,data); 2319 if (devpriv->b_Timer2Mode == APCI3120_TIMER) { 2320 2321 //Read the LOW WORD of Timer 2 register 2322 b_Tmp = ((devpriv-> 2323 b_DigitalOutputRegister) & 0xF0) | 2324 APCI3120_SELECT_TIMER_2_LOW_WORD; 2325 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); 2326 2327 us_TmpValue = inw(devpriv->iobase + APCI3120_TIMER_VALUE); 2328 2329 //Read the HIGH WORD of Timer 2 register 2330 b_Tmp = ((devpriv-> 2331 b_DigitalOutputRegister) & 0xF0) | 2332 APCI3120_SELECT_TIMER_2_HIGH_WORD; 2333 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); 2334 2335 us_TmpValue_2 = inw(devpriv->iobase + APCI3120_TIMER_VALUE); 2336 2337 // combining both words 2338 data[0] = (UINT) ((us_TmpValue) | ((us_TmpValue_2) << 16)); 2339 2340 } else // Read watch dog status 2341 { 2342 2343 us_StatusValue = inw(devpriv->iobase + APCI3120_RD_STATUS); 2344 us_StatusValue = 2345 ((us_StatusValue & APCI3120_FC_TIMER) >> 12) & 1; 2346 if (us_StatusValue == 1) { 2347 // RESET FC_TIMER BIT 2348 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER); 2349 } 2350 data[0] = us_StatusValue; // when data[0] = 1 then the watch dog has rundown 2351 } 2352 return insn->n; 2353} 2354 2355/* 2356+----------------------------------------------------------------------------+ 2357| DIGITAL INPUT SUBDEVICE | 2358+----------------------------------------------------------------------------+ 2359*/ 2360 2361/* 2362+----------------------------------------------------------------------------+ 2363| Function name :int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev, | 2364| comedi_subdevice *s, comedi_insn *insn,unsigned int *data) | 2365| | 2366| | 2367+----------------------------------------------------------------------------+ 2368| Task : Reads the value of the specified Digital input channel| 2369| | 2370+----------------------------------------------------------------------------+ 2371| Input Parameters : struct comedi_device *dev | 2372| comedi_subdevice *s | 2373| comedi_insn *insn | 2374| unsigned int *data | 2375+----------------------------------------------------------------------------+ 2376| Return Value : | 2377| | 2378+----------------------------------------------------------------------------+ 2379*/ 2380 2381int i_APCI3120_InsnReadDigitalInput(struct comedi_device * dev, comedi_subdevice 2382 * s, comedi_insn * insn, unsigned int * data) 2383{ 2384 UINT ui_Chan, ui_TmpValue; 2385 2386 ui_Chan = CR_CHAN(insn->chanspec); // channel specified 2387 2388 //this_board->i_hwdrv_InsnReadDigitalInput(dev,ui_Chan,data); 2389 if (ui_Chan >= 0 && ui_Chan <= 3) { 2390 ui_TmpValue = (UINT) inw(devpriv->iobase + APCI3120_RD_STATUS); 2391 2392 // since only 1 channel reqd to bring it to last bit it is rotated 2393 // 8 +(chan - 1) times then ANDed with 1 for last bit. 2394 *data = (ui_TmpValue >> (ui_Chan + 8)) & 1; 2395 //return 0; 2396 } else { 2397 // comedi_error(dev," chan spec wrong"); 2398 return -EINVAL; // "sorry channel spec wrong " 2399 } 2400 return insn->n; 2401 2402} 2403 2404/* 2405+----------------------------------------------------------------------------+ 2406| Function name :int i_APCI3120_InsnBitsDigitalInput(struct comedi_device *dev, | 2407|comedi_subdevice *s, comedi_insn *insn,unsigned int *data) | 2408| | 2409+----------------------------------------------------------------------------+ 2410| Task : Reads the value of the Digital input Port i.e.4channels| 2411| value is returned in data[0] | 2412| | 2413+----------------------------------------------------------------------------+ 2414| Input Parameters : struct comedi_device *dev | 2415| comedi_subdevice *s | 2416| comedi_insn *insn | 2417| unsigned int *data | 2418+----------------------------------------------------------------------------+ 2419| Return Value : | 2420| | 2421+----------------------------------------------------------------------------+ 2422*/ 2423int i_APCI3120_InsnBitsDigitalInput(struct comedi_device * dev, comedi_subdevice * s, 2424 comedi_insn * insn, unsigned int * data) 2425{ 2426 UINT ui_TmpValue; 2427 ui_TmpValue = (UINT) inw(devpriv->iobase + APCI3120_RD_STATUS); 2428 /***** state of 4 channels in the 11, 10, 9, 8 bits of status reg 2429 rotated right 8 times to bring them to last four bits 2430 ANDed with oxf for value. 2431 *****/ 2432 2433 *data = (ui_TmpValue >> 8) & 0xf; 2434 //this_board->i_hwdrv_InsnBitsDigitalInput(dev,data); 2435 return insn->n; 2436} 2437 2438/* 2439+----------------------------------------------------------------------------+ 2440| DIGITAL OUTPUT SUBDEVICE | 2441+----------------------------------------------------------------------------+ 2442*/ 2443/* 2444+----------------------------------------------------------------------------+ 2445| Function name :int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device | 2446| *dev,comedi_subdevice *s,comedi_insn *insn,unsigned int *data) | 2447| | 2448+----------------------------------------------------------------------------+ 2449| Task :Configure the output memory ON or OFF | 2450| | 2451+----------------------------------------------------------------------------+ 2452| Input Parameters :struct comedi_device *dev | 2453| comedi_subdevice *s | 2454| comedi_insn *insn | 2455| unsigned int *data | 2456+----------------------------------------------------------------------------+ 2457| Return Value : | 2458| | 2459+----------------------------------------------------------------------------+ 2460*/ 2461 2462int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device * dev, 2463 comedi_subdevice * s, comedi_insn * insn, unsigned int * data) 2464{ 2465 2466 if ((data[0] != 0) && (data[0] != 1)) { 2467 comedi_error(dev, 2468 "Not a valid Data !!! ,Data should be 1 or 0\n"); 2469 return -EINVAL; 2470 } 2471 if (data[0]) { 2472 devpriv->b_OutputMemoryStatus = APCI3120_ENABLE; 2473 2474 } else { 2475 devpriv->b_OutputMemoryStatus = APCI3120_DISABLE; 2476 devpriv->b_DigitalOutputRegister = 0; 2477 } 2478 if (!devpriv->b_OutputMemoryStatus) { 2479 ui_Temp = 0; 2480 2481 } //if(!devpriv->b_OutputMemoryStatus ) 2482 2483 return insn->n; 2484} 2485 2486/* 2487+----------------------------------------------------------------------------+ 2488| Function name :int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device *dev, | 2489| comedi_subdevice *s, comedi_insn *insn,unsigned int *data) | 2490| | 2491+----------------------------------------------------------------------------+ 2492| Task : write diatal output port | 2493| | 2494+----------------------------------------------------------------------------+ 2495| Input Parameters : struct comedi_device *dev | 2496| comedi_subdevice *s | 2497| comedi_insn *insn | 2498| unsigned int *data | 2499 data[0] Value to be written 2500 data[1] :1 Set digital o/p ON 2501 data[1] 2 Set digital o/p OFF with memory ON 2502+----------------------------------------------------------------------------+ 2503| Return Value : | 2504| | 2505+----------------------------------------------------------------------------+ 2506*/ 2507 2508int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device * dev, comedi_subdevice 2509 * s, comedi_insn * insn, unsigned int * data) 2510{ 2511 if ((data[0] > this_board->i_DoMaxdata) || (data[0] < 0)) { 2512 2513 comedi_error(dev, "Data is not valid !!! \n"); 2514 return -EINVAL; 2515 } 2516 2517 switch (data[1]) { 2518 case 1: 2519 data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister; 2520 break; 2521 2522 case 2: 2523 data[0] = data[0]; 2524 break; 2525 default: 2526 printk("\nThe parameter passed is in error \n"); 2527 return -EINVAL; 2528 } // switch(data[1]) 2529 outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT); 2530 2531 devpriv->b_DigitalOutputRegister = data[0] & 0xF0; 2532 2533 return insn->n; 2534 2535} 2536 2537/* 2538+----------------------------------------------------------------------------+ 2539| Function name :int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev,| 2540|comedi_subdevice *s,comedi_insn *insn,unsigned int *data) | 2541| | 2542+----------------------------------------------------------------------------+ 2543| Task : Write digiatl output | 2544| | 2545+----------------------------------------------------------------------------+ 2546| Input Parameters : struct comedi_device *dev | 2547| comedi_subdevice *s | 2548| comedi_insn *insn | 2549| unsigned int *data | 2550 data[0] Value to be written 2551 data[1] :1 Set digital o/p ON 2552 data[1] 2 Set digital o/p OFF with memory ON 2553+----------------------------------------------------------------------------+ 2554| Return Value : | 2555| | 2556+----------------------------------------------------------------------------+ 2557*/ 2558 2559int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device * dev, comedi_subdevice 2560 * s, comedi_insn * insn, unsigned int * data) 2561{ 2562 2563 UINT ui_Temp1; 2564 2565 UINT ui_NoOfChannel = CR_CHAN(insn->chanspec); // get the channel 2566 2567 if ((data[0] != 0) && (data[0] != 1)) { 2568 comedi_error(dev, 2569 "Not a valid Data !!! ,Data should be 1 or 0\n"); 2570 return -EINVAL; 2571 } 2572 if ((ui_NoOfChannel > (this_board->i_NbrDoChannel - 1)) 2573 || (ui_NoOfChannel < 0)) { 2574 comedi_error(dev, 2575 "This board doesn't have specified channel !!! \n"); 2576 return -EINVAL; 2577 } 2578 2579 switch (data[1]) { 2580 case 1: 2581 data[0] = (data[0] << ui_NoOfChannel); 2582//ES05 data[0]=(data[0]<<4)|ui_Temp; 2583 data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister; 2584 break; 2585 2586 case 2: 2587 data[0] = ~data[0] & 0x1; 2588 ui_Temp1 = 1; 2589 ui_Temp1 = ui_Temp1 << ui_NoOfChannel; 2590 ui_Temp1 = ui_Temp1 << 4; 2591//ES05 ui_Temp=ui_Temp|ui_Temp1; 2592 devpriv->b_DigitalOutputRegister = 2593 devpriv->b_DigitalOutputRegister | ui_Temp1; 2594 2595 data[0] = (data[0] << ui_NoOfChannel) ^ 0xf; 2596 data[0] = data[0] << 4; 2597//ES05 data[0]=data[0]& ui_Temp; 2598 data[0] = data[0] & devpriv->b_DigitalOutputRegister; 2599 break; 2600 default: 2601 printk("\nThe parameter passed is in error \n"); 2602 return -EINVAL; 2603 } // switch(data[1]) 2604 outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT); 2605 2606//ES05 ui_Temp=data[0] & 0xf0; 2607 devpriv->b_DigitalOutputRegister = data[0] & 0xf0; 2608 return (insn->n); 2609 2610} 2611 2612/* 2613+----------------------------------------------------------------------------+ 2614| ANALOG OUTPUT SUBDEVICE | 2615+----------------------------------------------------------------------------+ 2616*/ 2617 2618/* 2619+----------------------------------------------------------------------------+ 2620| Function name :int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,| 2621|comedi_subdevice *s, comedi_insn *insn,unsigned int *data) | 2622| | 2623+----------------------------------------------------------------------------+ 2624| Task : Write analog output | 2625| | 2626+----------------------------------------------------------------------------+ 2627| Input Parameters : struct comedi_device *dev | 2628| comedi_subdevice *s | 2629| comedi_insn *insn | 2630| unsigned int *data | 2631+----------------------------------------------------------------------------+ 2632| Return Value : | 2633| | 2634+----------------------------------------------------------------------------+ 2635*/ 2636 2637int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device * dev, comedi_subdevice 2638 * s, comedi_insn * insn, unsigned int * data) 2639{ 2640 UINT ui_Range, ui_Channel; 2641 USHORT us_TmpValue; 2642 2643 ui_Range = CR_RANGE(insn->chanspec); 2644 ui_Channel = CR_CHAN(insn->chanspec); 2645 2646 //this_board->i_hwdrv_InsnWriteAnalogOutput(dev, ui_Range, ui_Channel,data[0]); 2647 if (ui_Range) // if 1 then unipolar 2648 { 2649 2650 if (data[0] != 0) 2651 data[0] = 2652 ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 << 2653 13) | (data[0] + 8191)); 2654 else 2655 data[0] = 2656 ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 << 2657 13) | 8192); 2658 2659 } else // if 0 then bipolar 2660 { 2661 data[0] = 2662 ((((ui_Channel & 0x03) << 14) & 0xC000) | (0 << 13) | 2663 data[0]); 2664 2665 } 2666 2667 //out put n values at the given channel. 2668 // rt_printk("\nwaiting for DA_READY BIT"); 2669 do //Waiting of DA_READY BIT 2670 { 2671 us_TmpValue = 2672 ((USHORT) inw(devpriv->iobase + 2673 APCI3120_RD_STATUS)) & 0x0001; 2674 } while (us_TmpValue != 0x0001); 2675 2676 if (ui_Channel <= 3) 2677 // for channel 0-3 out at the register 1 (wrDac1-8) 2678 // data[i] typecasted to ushort since word write is to be done 2679 outw((USHORT) data[0], 2680 devpriv->iobase + APCI3120_ANALOG_OUTPUT_1); 2681 else 2682 // for channel 4-7 out at the register 2 (wrDac5-8) 2683 //data[i] typecasted to ushort since word write is to be done 2684 outw((USHORT) data[0], 2685 devpriv->iobase + APCI3120_ANALOG_OUTPUT_2); 2686 2687 return insn->n; 2688} 2689