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