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