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