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