hwdrv_apci3120.c revision ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3f
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,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| 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 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,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| 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 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,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| 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 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, 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| 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 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,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| 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 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, 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| 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 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, 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| 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 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,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| 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, 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, 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| 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 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,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| 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 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, 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| 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 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