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