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