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