hwdrv_apci3120.c revision fa567598f0294cbca84928201709fa26ecbe549a
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: check if arguments are trivially valid */ 771 772 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); 773 774 if (cmd->scan_begin_src == TRIG_TIMER) /* Test Delay timing */ 775 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 100000); 776 777 if (cmd->convert_src == TRIG_TIMER) { /* Test Acquisition timing */ 778 if (cmd->scan_begin_src == TRIG_TIMER) { 779 if (cmd->convert_arg) 780 err |= cfc_check_trigger_arg_min( 781 &cmd->convert_arg, 10000); 782 } else { 783 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 784 10000); 785 } 786 } 787 788 err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1); 789 err |= cfc_check_trigger_arg_max(&cmd->chanlist_len, 790 this_board->i_AiChannelList); 791 792 if (cmd->stop_src == TRIG_COUNT) 793 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); 794 else /* TRIG_NONE */ 795 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); 796 797 if (err) 798 return 3; 799 800 /* step 4: fix up any arguments */ 801 802 if (cmd->convert_src == TRIG_TIMER) { 803 804 if (cmd->scan_begin_src == TRIG_TIMER && 805 cmd->scan_begin_arg < 806 cmd->convert_arg * cmd->scan_end_arg) { 807 cmd->scan_begin_arg = 808 cmd->convert_arg * cmd->scan_end_arg; 809 err++; 810 } 811 } 812 813 if (err) 814 return 4; 815 816 return 0; 817} 818 819/* 820 * This is used for analog input cyclic acquisition. 821 * Performs the command operations. 822 * If DMA is configured does DMA initialization otherwise does the 823 * acquisition with EOS interrupt. 824 */ 825static int i_APCI3120_CyclicAnalogInput(int mode, 826 struct comedi_device *dev, 827 struct comedi_subdevice *s) 828{ 829 const struct addi_board *this_board = comedi_board(dev); 830 struct addi_private *devpriv = dev->private; 831 unsigned char b_Tmp; 832 unsigned int ui_Tmp, ui_DelayTiming = 0, ui_TimerValue1 = 0, dmalen0 = 833 0, dmalen1 = 0, ui_TimerValue2 = 834 0, ui_TimerValue0, ui_ConvertTiming; 835 unsigned short us_TmpValue; 836 837 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ 838 /* devpriv->b_AiCyclicAcquisition=APCI3120_ENABLE; */ 839 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ 840 841 /*******************/ 842 /* Resets the FIFO */ 843 /*******************/ 844 inb(dev->iobase + APCI3120_RESET_FIFO); 845 846 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ 847 /* inw(dev->iobase+APCI3120_RD_STATUS); */ 848 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ 849 850 /***************************/ 851 /* Acquisition initialized */ 852 /***************************/ 853 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ 854 devpriv->b_AiCyclicAcquisition = APCI3120_ENABLE; 855 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ 856 857 /* clear software registers */ 858 devpriv->b_TimerSelectMode = 0; 859 devpriv->us_OutputRegister = 0; 860 devpriv->b_ModeSelectRegister = 0; 861 /* devpriv->b_DigitalOutputRegister=0; */ 862 863 /* COMMENT JK 07.05.04: Followings calls are in i_APCI3120_StartAnalogInputAcquisition */ 864 865 /****************************/ 866 /* Clear Timer Write TC int */ 867 /****************************/ 868 outl(APCI3120_CLEAR_WRITE_TC_INT, 869 devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_REG_INTCSR); 870 871 /************************************/ 872 /* Clears the timer status register */ 873 /************************************/ 874 875 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ 876 /* inw(dev->iobase+APCI3120_TIMER_STATUS_REGISTER); */ 877 /* inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); */ 878 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ 879 880 /**************************/ 881 /* Disables All Timer */ 882 /* Sets PR and PA to 0 */ 883 /**************************/ 884 devpriv->us_OutputRegister = devpriv->us_OutputRegister & 885 APCI3120_DISABLE_TIMER0 & 886 APCI3120_DISABLE_TIMER1 & APCI3120_CLEAR_PA_PR; 887 888 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS); 889 890 /*******************/ 891 /* Resets the FIFO */ 892 /*******************/ 893 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ 894 inb(devpriv->iobase + APCI3120_RESET_FIFO); 895 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ 896 897 devpriv->ui_AiActualScan = 0; 898 devpriv->ui_AiActualScanPosition = 0; 899 s->async->cur_chan = 0; 900 devpriv->ui_AiBufferPtr = 0; 901 devpriv->ui_DmaActualBuffer = 0; 902 903 /* value for timer2 minus -2 has to be done .....dunno y?? */ 904 ui_TimerValue2 = devpriv->ui_AiNbrofScans - 2; 905 ui_ConvertTiming = devpriv->ui_AiTimer0; 906 907 if (mode == 2) 908 ui_DelayTiming = devpriv->ui_AiTimer1; 909 910 /**********************************/ 911 /* Initializes the sequence array */ 912 /**********************************/ 913 if (!i_APCI3120_SetupChannelList(dev, s, devpriv->ui_AiNbrofChannels, 914 devpriv->pui_AiChannelList, 0)) 915 return -EINVAL; 916 917 us_TmpValue = (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS); 918/*** EL241003 : add this section in comment because floats must not be used 919 if((us_TmpValue & 0x00B0)==0x00B0) 920 { 921 f_ConvertValue=(((float)ui_ConvertTiming * 0.002) - 2); 922 ui_TimerValue0=(unsigned int)f_ConvertValue; 923 if (mode==2) 924 { 925 f_DelayValue = (((float)ui_DelayTiming * 0.00002) - 2); 926 ui_TimerValue1 = (unsigned int) f_DelayValue; 927 } 928 } 929 else 930 { 931 f_ConvertValue=(((float)ui_ConvertTiming * 0.0012926) - 1); 932 ui_TimerValue0=(unsigned int)f_ConvertValue; 933 if (mode == 2) 934 { 935 f_DelayValue = (((float)ui_DelayTiming * 0.000012926) - 1); 936 ui_TimerValue1 = (unsigned int) f_DelayValue; 937 } 938 } 939***********************************************************************************************/ 940/*** EL241003 Begin : add this section to replace floats calculation by integer calculations **/ 941 /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */ 942 if ((us_TmpValue & 0x00B0) == 0x00B0 943 || !strcmp(this_board->pc_DriverName, "apci3001")) { 944 ui_TimerValue0 = ui_ConvertTiming * 2 - 2000; 945 ui_TimerValue0 = ui_TimerValue0 / 1000; 946 947 if (mode == 2) { 948 ui_DelayTiming = ui_DelayTiming / 1000; 949 ui_TimerValue1 = ui_DelayTiming * 2 - 200; 950 ui_TimerValue1 = ui_TimerValue1 / 100; 951 } 952 } else { 953 ui_ConvertTiming = ui_ConvertTiming / 1000; 954 ui_TimerValue0 = ui_ConvertTiming * 12926 - 10000; 955 ui_TimerValue0 = ui_TimerValue0 / 10000; 956 957 if (mode == 2) { 958 ui_DelayTiming = ui_DelayTiming / 1000; 959 ui_TimerValue1 = ui_DelayTiming * 12926 - 1; 960 ui_TimerValue1 = ui_TimerValue1 / 1000000; 961 } 962 } 963/*** EL241003 End ******************************************************************************/ 964 965 if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) 966 i_APCI3120_ExttrigEnable(dev); /* activate EXT trigger */ 967 switch (mode) { 968 case 1: 969 /* init timer0 in mode 2 */ 970 devpriv->b_TimerSelectMode = 971 (devpriv-> 972 b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2; 973 outb(devpriv->b_TimerSelectMode, 974 dev->iobase + APCI3120_TIMER_CRT1); 975 976 /* Select Timer 0 */ 977 b_Tmp = ((devpriv-> 978 b_DigitalOutputRegister) & 0xF0) | 979 APCI3120_SELECT_TIMER_0_WORD; 980 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0); 981 /* Set the conversion time */ 982 outw(((unsigned short) ui_TimerValue0), 983 dev->iobase + APCI3120_TIMER_VALUE); 984 break; 985 986 case 2: 987 /* init timer1 in mode 2 */ 988 devpriv->b_TimerSelectMode = 989 (devpriv-> 990 b_TimerSelectMode & 0xF3) | APCI3120_TIMER_1_MODE_2; 991 outb(devpriv->b_TimerSelectMode, 992 dev->iobase + APCI3120_TIMER_CRT1); 993 994 /* Select Timer 1 */ 995 b_Tmp = ((devpriv-> 996 b_DigitalOutputRegister) & 0xF0) | 997 APCI3120_SELECT_TIMER_1_WORD; 998 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0); 999 /* Set the conversion time */ 1000 outw(((unsigned short) ui_TimerValue1), 1001 dev->iobase + APCI3120_TIMER_VALUE); 1002 1003 /* init timer0 in mode 2 */ 1004 devpriv->b_TimerSelectMode = 1005 (devpriv-> 1006 b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2; 1007 outb(devpriv->b_TimerSelectMode, 1008 dev->iobase + APCI3120_TIMER_CRT1); 1009 1010 /* Select Timer 0 */ 1011 b_Tmp = ((devpriv-> 1012 b_DigitalOutputRegister) & 0xF0) | 1013 APCI3120_SELECT_TIMER_0_WORD; 1014 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0); 1015 1016 /* Set the conversion time */ 1017 outw(((unsigned short) ui_TimerValue0), 1018 dev->iobase + APCI3120_TIMER_VALUE); 1019 break; 1020 1021 } 1022 /* ##########common for all modes################# */ 1023 1024 /***********************/ 1025 /* Clears the SCAN bit */ 1026 /***********************/ 1027 1028 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ 1029 /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister | APCI3120_DISABLE_SCAN; */ 1030 1031 devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister & 1032 APCI3120_DISABLE_SCAN; 1033 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ 1034 1035 outb(devpriv->b_ModeSelectRegister, 1036 dev->iobase + APCI3120_WRITE_MODE_SELECT); 1037 1038 /* If DMA is disabled */ 1039 if (devpriv->us_UseDma == APCI3120_DISABLE) { 1040 /* disable EOC and enable EOS */ 1041 devpriv->b_InterruptMode = APCI3120_EOS_MODE; 1042 devpriv->b_EocEosInterrupt = APCI3120_ENABLE; 1043 1044 devpriv->b_ModeSelectRegister = 1045 (devpriv-> 1046 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT) | 1047 APCI3120_ENABLE_EOS_INT; 1048 outb(devpriv->b_ModeSelectRegister, 1049 dev->iobase + APCI3120_WRITE_MODE_SELECT); 1050 1051 if (!devpriv->b_AiContinuous) { 1052/* 1053 * configure Timer2 For counting EOS Reset gate 2 of Timer 2 to 1054 * disable it (Set Bit D14 to 0) 1055 */ 1056 devpriv->us_OutputRegister = 1057 devpriv-> 1058 us_OutputRegister & APCI3120_DISABLE_TIMER2; 1059 outw(devpriv->us_OutputRegister, 1060 dev->iobase + APCI3120_WR_ADDRESS); 1061 1062 /* DISABLE TIMER intERRUPT */ 1063 devpriv->b_ModeSelectRegister = 1064 devpriv-> 1065 b_ModeSelectRegister & 1066 APCI3120_DISABLE_TIMER_INT & 0xEF; 1067 outb(devpriv->b_ModeSelectRegister, 1068 dev->iobase + APCI3120_WRITE_MODE_SELECT); 1069 1070 /* (1) Init timer 2 in mode 0 and write timer value */ 1071 devpriv->b_TimerSelectMode = 1072 (devpriv-> 1073 b_TimerSelectMode & 0x0F) | 1074 APCI3120_TIMER_2_MODE_0; 1075 outb(devpriv->b_TimerSelectMode, 1076 dev->iobase + APCI3120_TIMER_CRT1); 1077 1078 /* Writing LOW unsigned short */ 1079 b_Tmp = ((devpriv-> 1080 b_DigitalOutputRegister) & 0xF0) | 1081 APCI3120_SELECT_TIMER_2_LOW_WORD; 1082 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0); 1083 outw(LOWORD(ui_TimerValue2), 1084 dev->iobase + APCI3120_TIMER_VALUE); 1085 1086 /* Writing HIGH unsigned short */ 1087 b_Tmp = ((devpriv-> 1088 b_DigitalOutputRegister) & 0xF0) | 1089 APCI3120_SELECT_TIMER_2_HIGH_WORD; 1090 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0); 1091 outw(HIWORD(ui_TimerValue2), 1092 dev->iobase + APCI3120_TIMER_VALUE); 1093 1094 /* (2) Reset FC_TIMER BIT Clearing timer status register */ 1095 inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); 1096 /* enable timer counter and disable watch dog */ 1097 devpriv->b_ModeSelectRegister = 1098 (devpriv-> 1099 b_ModeSelectRegister | 1100 APCI3120_ENABLE_TIMER_COUNTER) & 1101 APCI3120_DISABLE_WATCHDOG; 1102 /* select EOS clock input for timer 2 */ 1103 devpriv->b_ModeSelectRegister = 1104 devpriv-> 1105 b_ModeSelectRegister | 1106 APCI3120_TIMER2_SELECT_EOS; 1107 /* Enable timer2 interrupt */ 1108 devpriv->b_ModeSelectRegister = 1109 devpriv-> 1110 b_ModeSelectRegister | 1111 APCI3120_ENABLE_TIMER_INT; 1112 outb(devpriv->b_ModeSelectRegister, 1113 dev->iobase + APCI3120_WRITE_MODE_SELECT); 1114 devpriv->b_Timer2Mode = APCI3120_COUNTER; 1115 devpriv->b_Timer2Interrupt = APCI3120_ENABLE; 1116 } 1117 } else { 1118 /* If DMA Enabled */ 1119 1120 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ 1121 /* inw(dev->iobase+0); reset EOC bit */ 1122 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ 1123 devpriv->b_InterruptMode = APCI3120_DMA_MODE; 1124 1125 /************************************/ 1126 /* Disables the EOC, EOS interrupt */ 1127 /************************************/ 1128 devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister & 1129 APCI3120_DISABLE_EOC_INT & APCI3120_DISABLE_EOS_INT; 1130 1131 outb(devpriv->b_ModeSelectRegister, 1132 dev->iobase + APCI3120_WRITE_MODE_SELECT); 1133 1134 dmalen0 = devpriv->ui_DmaBufferSize[0]; 1135 dmalen1 = devpriv->ui_DmaBufferSize[1]; 1136 1137 if (!devpriv->b_AiContinuous) { 1138 1139 if (dmalen0 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2)) { /* must we fill full first buffer? */ 1140 dmalen0 = 1141 devpriv->ui_AiNbrofScans * 1142 devpriv->ui_AiScanLength * 2; 1143 } else if (dmalen1 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2 - dmalen0)) /* and must we fill full second buffer when first is once filled? */ 1144 dmalen1 = 1145 devpriv->ui_AiNbrofScans * 1146 devpriv->ui_AiScanLength * 2 - dmalen0; 1147 } 1148 1149 if (devpriv->ui_AiFlags & TRIG_WAKE_EOS) { 1150 /* don't we want wake up every scan? */ 1151 if (dmalen0 > (devpriv->ui_AiScanLength * 2)) { 1152 dmalen0 = devpriv->ui_AiScanLength * 2; 1153 if (devpriv->ui_AiScanLength & 1) 1154 dmalen0 += 2; 1155 } 1156 if (dmalen1 > (devpriv->ui_AiScanLength * 2)) { 1157 dmalen1 = devpriv->ui_AiScanLength * 2; 1158 if (devpriv->ui_AiScanLength & 1) 1159 dmalen1 -= 2; 1160 if (dmalen1 < 4) 1161 dmalen1 = 4; 1162 } 1163 } else { /* isn't output buff smaller that our DMA buff? */ 1164 if (dmalen0 > (devpriv->ui_AiDataLength)) 1165 dmalen0 = devpriv->ui_AiDataLength; 1166 if (dmalen1 > (devpriv->ui_AiDataLength)) 1167 dmalen1 = devpriv->ui_AiDataLength; 1168 } 1169 devpriv->ui_DmaBufferUsesize[0] = dmalen0; 1170 devpriv->ui_DmaBufferUsesize[1] = dmalen1; 1171 1172 /* Initialize DMA */ 1173 1174/* 1175 * Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS 1176 * register 1 1177 */ 1178 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO; 1179 outl(ui_Tmp, devpriv->i_IobaseAmcc + AMCC_OP_REG_AGCSTS); 1180 1181 /* changed since 16 bit interface for add on */ 1182 /*********************/ 1183 /* ENABLE BUS MASTER */ 1184 /*********************/ 1185 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0); 1186 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW, 1187 devpriv->i_IobaseAddon + 2); 1188 1189 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0); 1190 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, 1191 devpriv->i_IobaseAddon + 2); 1192 1193/* 1194 * TO VERIFIED BEGIN JK 07.05.04: Comparison between WIN32 and Linux 1195 * driver 1196 */ 1197 outw(0x1000, devpriv->i_IobaseAddon + 2); 1198 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ 1199 1200 /* 2 No change */ 1201 /* A2P FIFO MANAGEMENT */ 1202 /* A2P fifo reset & transfer control enable */ 1203 1204 /***********************/ 1205 /* A2P FIFO MANAGEMENT */ 1206 /***********************/ 1207 outl(APCI3120_A2P_FIFO_MANAGEMENT, devpriv->i_IobaseAmcc + 1208 APCI3120_AMCC_OP_MCSR); 1209 1210/* 1211 * 3 1212 * beginning address of dma buf The 32 bit address of dma buffer 1213 * is converted into two 16 bit addresses Can done by using _attach 1214 * and put into into an array array used may be for differnet pages 1215 */ 1216 1217 /* DMA Start Address Low */ 1218 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0); 1219 outw((devpriv->ul_DmaBufferHw[0] & 0xFFFF), 1220 devpriv->i_IobaseAddon + 2); 1221 1222 /*************************/ 1223 /* DMA Start Address High */ 1224 /*************************/ 1225 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0); 1226 outw((devpriv->ul_DmaBufferHw[0] / 65536), 1227 devpriv->i_IobaseAddon + 2); 1228 1229/* 1230 * 4 1231 * amount of bytes to be transferred set transfer count used ADDON 1232 * MWTC register commented testing 1233 * outl(devpriv->ui_DmaBufferUsesize[0], 1234 * devpriv->i_IobaseAddon+AMCC_OP_REG_AMWTC); 1235 */ 1236 1237 /**************************/ 1238 /* Nbr of acquisition LOW */ 1239 /**************************/ 1240 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0); 1241 outw((devpriv->ui_DmaBufferUsesize[0] & 0xFFFF), 1242 devpriv->i_IobaseAddon + 2); 1243 1244 /***************************/ 1245 /* Nbr of acquisition HIGH */ 1246 /***************************/ 1247 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0); 1248 outw((devpriv->ui_DmaBufferUsesize[0] / 65536), 1249 devpriv->i_IobaseAddon + 2); 1250 1251/* 1252 * 5 1253 * To configure A2P FIFO testing outl( 1254 * FIFO_ADVANCE_ON_BYTE_2,devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR); 1255 */ 1256 1257 /******************/ 1258 /* A2P FIFO RESET */ 1259 /******************/ 1260/* 1261 * TO VERIFY BEGIN JK 07.05.04: Comparison between WIN32 and Linux 1262 * driver 1263 */ 1264 outl(0x04000000UL, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR); 1265 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ 1266 1267/* 1268 * 6 1269 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN AMWEN_ENABLE | 1270 * A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03 1271 */ 1272 1273 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ 1274 /* outw(3,devpriv->i_IobaseAddon + 4); */ 1275 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ 1276 1277/* 1278 * 7 1279 * initialise end of dma interrupt AINT_WRITE_COMPL = 1280 * ENABLE_WRITE_TC_INT(ADDI) 1281 */ 1282 /***************************************************/ 1283 /* A2P FIFO CONFIGURATE, END OF DMA intERRUPT INIT */ 1284 /***************************************************/ 1285 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 | 1286 APCI3120_ENABLE_WRITE_TC_INT), 1287 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); 1288 1289 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ 1290 /******************************************/ 1291 /* ENABLE A2P FIFO WRITE AND ENABLE AMWEN */ 1292 /******************************************/ 1293 outw(3, devpriv->i_IobaseAddon + 4); 1294 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ 1295 1296 /******************/ 1297 /* A2P FIFO RESET */ 1298 /******************/ 1299 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ 1300 outl(0x04000000UL, 1301 devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_MCSR); 1302 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ 1303 } 1304 1305 if ((devpriv->us_UseDma == APCI3120_DISABLE) 1306 && !devpriv->b_AiContinuous) { 1307 /* set gate 2 to start conversion */ 1308 devpriv->us_OutputRegister = 1309 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER2; 1310 outw(devpriv->us_OutputRegister, 1311 dev->iobase + APCI3120_WR_ADDRESS); 1312 } 1313 1314 switch (mode) { 1315 case 1: 1316 /* set gate 0 to start conversion */ 1317 devpriv->us_OutputRegister = 1318 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0; 1319 outw(devpriv->us_OutputRegister, 1320 dev->iobase + APCI3120_WR_ADDRESS); 1321 break; 1322 case 2: 1323 /* set gate 0 and gate 1 */ 1324 devpriv->us_OutputRegister = 1325 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER1; 1326 devpriv->us_OutputRegister = 1327 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0; 1328 outw(devpriv->us_OutputRegister, 1329 dev->iobase + APCI3120_WR_ADDRESS); 1330 break; 1331 1332 } 1333 1334 return 0; 1335 1336} 1337 1338/* 1339 * Does asynchronous acquisition. 1340 * Determines the mode 1 or 2. 1341 */ 1342static int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, 1343 struct comedi_subdevice *s) 1344{ 1345 struct addi_private *devpriv = dev->private; 1346 struct comedi_cmd *cmd = &s->async->cmd; 1347 1348 /* loading private structure with cmd structure inputs */ 1349 devpriv->ui_AiFlags = cmd->flags; 1350 devpriv->ui_AiNbrofChannels = cmd->chanlist_len; 1351 devpriv->ui_AiScanLength = cmd->scan_end_arg; 1352 devpriv->pui_AiChannelList = cmd->chanlist; 1353 1354 /* UPDATE-0.7.57->0.7.68devpriv->AiData=s->async->data; */ 1355 devpriv->AiData = s->async->prealloc_buf; 1356 /* UPDATE-0.7.57->0.7.68devpriv->ui_AiDataLength=s->async->data_len; */ 1357 devpriv->ui_AiDataLength = s->async->prealloc_bufsz; 1358 1359 if (cmd->stop_src == TRIG_COUNT) 1360 devpriv->ui_AiNbrofScans = cmd->stop_arg; 1361 else 1362 devpriv->ui_AiNbrofScans = 0; 1363 1364 devpriv->ui_AiTimer0 = 0; /* variables changed to timer0,timer1 */ 1365 devpriv->ui_AiTimer1 = 0; 1366 if ((devpriv->ui_AiNbrofScans == 0) || (devpriv->ui_AiNbrofScans == -1)) 1367 devpriv->b_AiContinuous = 1; /* user want neverending analog acquisition */ 1368 /* stopped using cancel */ 1369 1370 if (cmd->start_src == TRIG_EXT) 1371 devpriv->b_ExttrigEnable = APCI3120_ENABLE; 1372 else 1373 devpriv->b_ExttrigEnable = APCI3120_DISABLE; 1374 1375 if (cmd->scan_begin_src == TRIG_FOLLOW) { 1376 /* mode 1 or 3 */ 1377 if (cmd->convert_src == TRIG_TIMER) { 1378 /* mode 1 */ 1379 1380 devpriv->ui_AiTimer0 = cmd->convert_arg; /* timer constant in nano seconds */ 1381 /* return this_board->ai_cmd(1,dev,s); */ 1382 return i_APCI3120_CyclicAnalogInput(1, dev, s); 1383 } 1384 1385 } 1386 if ((cmd->scan_begin_src == TRIG_TIMER) 1387 && (cmd->convert_src == TRIG_TIMER)) { 1388 /* mode 2 */ 1389 devpriv->ui_AiTimer1 = cmd->scan_begin_arg; 1390 devpriv->ui_AiTimer0 = cmd->convert_arg; /* variable changed timer2 to timer0 */ 1391 /* return this_board->ai_cmd(2,dev,s); */ 1392 return i_APCI3120_CyclicAnalogInput(2, dev, s); 1393 } 1394 return -1; 1395} 1396 1397/* 1398 * This function copies the data from DMA buffer to the Comedi buffer. 1399 */ 1400static void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev, 1401 struct comedi_subdevice *s, 1402 short *dma_buffer, 1403 unsigned int num_samples) 1404{ 1405 struct addi_private *devpriv = dev->private; 1406 1407 devpriv->ui_AiActualScan += 1408 (s->async->cur_chan + num_samples) / devpriv->ui_AiScanLength; 1409 s->async->cur_chan += num_samples; 1410 s->async->cur_chan %= devpriv->ui_AiScanLength; 1411 1412 cfc_write_array_to_buffer(s, dma_buffer, num_samples * sizeof(short)); 1413} 1414 1415/* 1416 * This is a handler for the DMA interrupt. 1417 * This function copies the data to Comedi Buffer. 1418 * For continuous DMA it reinitializes the DMA operation. 1419 * For single mode DMA it stop the acquisition. 1420 */ 1421static void v_APCI3120_InterruptDma(int irq, void *d) 1422{ 1423 struct comedi_device *dev = d; 1424 struct addi_private *devpriv = dev->private; 1425 struct comedi_subdevice *s = &dev->subdevices[0]; 1426 unsigned int next_dma_buf, samplesinbuf; 1427 unsigned long low_word, high_word, var; 1428 unsigned int ui_Tmp; 1429 1430 samplesinbuf = 1431 devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer] - 1432 inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_MWTC); 1433 1434 if (samplesinbuf < 1435 devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer]) { 1436 comedi_error(dev, "Interrupted DMA transfer!"); 1437 } 1438 if (samplesinbuf & 1) { 1439 comedi_error(dev, "Odd count of bytes in DMA ring!"); 1440 i_APCI3120_StopCyclicAcquisition(dev, s); 1441 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; 1442 1443 return; 1444 } 1445 samplesinbuf = samplesinbuf >> 1; /* number of received samples */ 1446 if (devpriv->b_DmaDoubleBuffer) { 1447 /* switch DMA buffers if is used double buffering */ 1448 next_dma_buf = 1 - devpriv->ui_DmaActualBuffer; 1449 1450 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO; 1451 outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS); 1452 1453 /* changed since 16 bit interface for add on */ 1454 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0); 1455 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW, 1456 devpriv->i_IobaseAddon + 2); 1457 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0); 1458 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); /* 0x1000 is out putted in windows driver */ 1459 1460 var = devpriv->ul_DmaBufferHw[next_dma_buf]; 1461 low_word = var & 0xffff; 1462 var = devpriv->ul_DmaBufferHw[next_dma_buf]; 1463 high_word = var / 65536; 1464 1465 /* DMA Start Address Low */ 1466 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0); 1467 outw(low_word, devpriv->i_IobaseAddon + 2); 1468 1469 /* DMA Start Address High */ 1470 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0); 1471 outw(high_word, devpriv->i_IobaseAddon + 2); 1472 1473 var = devpriv->ui_DmaBufferUsesize[next_dma_buf]; 1474 low_word = var & 0xffff; 1475 var = devpriv->ui_DmaBufferUsesize[next_dma_buf]; 1476 high_word = var / 65536; 1477 1478 /* Nbr of acquisition LOW */ 1479 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0); 1480 outw(low_word, devpriv->i_IobaseAddon + 2); 1481 1482 /* Nbr of acquisition HIGH */ 1483 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0); 1484 outw(high_word, devpriv->i_IobaseAddon + 2); 1485 1486/* 1487 * To configure A2P FIFO 1488 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN 1489 * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03 1490 */ 1491 outw(3, devpriv->i_IobaseAddon + 4); 1492 /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */ 1493 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 | 1494 APCI3120_ENABLE_WRITE_TC_INT), 1495 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); 1496 1497 } 1498 if (samplesinbuf) { 1499 v_APCI3120_InterruptDmaMoveBlock16bit(dev, s, 1500 devpriv->ul_DmaBufferVirtual[devpriv-> 1501 ui_DmaActualBuffer], samplesinbuf); 1502 1503 if (!(devpriv->ui_AiFlags & TRIG_WAKE_EOS)) { 1504 s->async->events |= COMEDI_CB_EOS; 1505 comedi_event(dev, s); 1506 } 1507 } 1508 if (!devpriv->b_AiContinuous) 1509 if (devpriv->ui_AiActualScan >= devpriv->ui_AiNbrofScans) { 1510 /* all data sampled */ 1511 i_APCI3120_StopCyclicAcquisition(dev, s); 1512 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; 1513 s->async->events |= COMEDI_CB_EOA; 1514 comedi_event(dev, s); 1515 return; 1516 } 1517 1518 if (devpriv->b_DmaDoubleBuffer) { /* switch dma buffers */ 1519 devpriv->ui_DmaActualBuffer = 1 - devpriv->ui_DmaActualBuffer; 1520 } else { 1521/* 1522 * restart DMA if is not used double buffering 1523 * ADDED REINITIALISE THE DMA 1524 */ 1525 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO; 1526 outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS); 1527 1528 /* changed since 16 bit interface for add on */ 1529 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0); 1530 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW, 1531 devpriv->i_IobaseAddon + 2); 1532 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0); 1533 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); /* */ 1534/* 1535 * A2P FIFO MANAGEMENT 1536 * A2P fifo reset & transfer control enable 1537 */ 1538 outl(APCI3120_A2P_FIFO_MANAGEMENT, 1539 devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR); 1540 1541 var = devpriv->ul_DmaBufferHw[0]; 1542 low_word = var & 0xffff; 1543 var = devpriv->ul_DmaBufferHw[0]; 1544 high_word = var / 65536; 1545 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0); 1546 outw(low_word, devpriv->i_IobaseAddon + 2); 1547 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0); 1548 outw(high_word, devpriv->i_IobaseAddon + 2); 1549 1550 var = devpriv->ui_DmaBufferUsesize[0]; 1551 low_word = var & 0xffff; /* changed */ 1552 var = devpriv->ui_DmaBufferUsesize[0]; 1553 high_word = var / 65536; 1554 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0); 1555 outw(low_word, devpriv->i_IobaseAddon + 2); 1556 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0); 1557 outw(high_word, devpriv->i_IobaseAddon + 2); 1558 1559/* 1560 * To configure A2P FIFO 1561 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN 1562 * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03 1563 */ 1564 outw(3, devpriv->i_IobaseAddon + 4); 1565 /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */ 1566 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 | 1567 APCI3120_ENABLE_WRITE_TC_INT), 1568 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); 1569 } 1570} 1571 1572/* 1573 * This function handles EOS interrupt. 1574 * This function copies the acquired data(from FIFO) to Comedi buffer. 1575 */ 1576static int i_APCI3120_InterruptHandleEos(struct comedi_device *dev) 1577{ 1578 struct addi_private *devpriv = dev->private; 1579 int n_chan, i; 1580 struct comedi_subdevice *s = &dev->subdevices[0]; 1581 int err = 1; 1582 1583 n_chan = devpriv->ui_AiNbrofChannels; 1584 1585 s->async->events = 0; 1586 1587 for (i = 0; i < n_chan; i++) 1588 err &= comedi_buf_put(s->async, inw(dev->iobase + 0)); 1589 1590 s->async->events |= COMEDI_CB_EOS; 1591 1592 if (err == 0) 1593 s->async->events |= COMEDI_CB_OVERFLOW; 1594 1595 comedi_event(dev, s); 1596 1597 return 0; 1598} 1599 1600static void v_APCI3120_Interrupt(int irq, void *d) 1601{ 1602 struct comedi_device *dev = d; 1603 struct addi_private *devpriv = dev->private; 1604 unsigned short int_daq; 1605 unsigned int int_amcc, ui_Check, i; 1606 unsigned short us_TmpValue; 1607 unsigned char b_DummyRead; 1608 struct comedi_subdevice *s = &dev->subdevices[0]; 1609 1610 ui_Check = 1; 1611 1612 int_daq = inw(dev->iobase + APCI3120_RD_STATUS) & 0xf000; /* get IRQ reasons */ 1613 int_amcc = inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); /* get AMCC int register */ 1614 1615 if ((!int_daq) && (!(int_amcc & ANY_S593X_INT))) { 1616 comedi_error(dev, "IRQ from unknown source"); 1617 return; 1618 } 1619 1620 outl(int_amcc | 0x00ff0000, devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); /* shutdown IRQ reasons in AMCC */ 1621 1622 int_daq = (int_daq >> 12) & 0xF; 1623 1624 if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) { 1625 /* Disable ext trigger */ 1626 i_APCI3120_ExttrigDisable(dev); 1627 devpriv->b_ExttrigEnable = APCI3120_DISABLE; 1628 } 1629 /* clear the timer 2 interrupt */ 1630 inb(devpriv->i_IobaseAmcc + APCI3120_TIMER_STATUS_REGISTER); 1631 1632 if (int_amcc & MASTER_ABORT_INT) 1633 comedi_error(dev, "AMCC IRQ - MASTER DMA ABORT!"); 1634 if (int_amcc & TARGET_ABORT_INT) 1635 comedi_error(dev, "AMCC IRQ - TARGET DMA ABORT!"); 1636 1637 /* Ckeck if EOC interrupt */ 1638 if (((int_daq & 0x8) == 0) 1639 && (devpriv->b_InterruptMode == APCI3120_EOC_MODE)) { 1640 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) { 1641 1642 /* Read the AI Value */ 1643 1644 devpriv->ui_AiReadData[0] = 1645 (unsigned int) inw(devpriv->iobase + 0); 1646 devpriv->b_EocEosInterrupt = APCI3120_DISABLE; 1647 send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ 1648 } else { 1649 /* Disable EOC Interrupt */ 1650 devpriv->b_ModeSelectRegister = 1651 devpriv-> 1652 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT; 1653 outb(devpriv->b_ModeSelectRegister, 1654 devpriv->iobase + APCI3120_WRITE_MODE_SELECT); 1655 1656 } 1657 } 1658 1659 /* Check If EOS interrupt */ 1660 if ((int_daq & 0x2) && (devpriv->b_InterruptMode == APCI3120_EOS_MODE)) { 1661 1662 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) { /* enable this in without DMA ??? */ 1663 1664 if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) { 1665 ui_Check = 0; 1666 i_APCI3120_InterruptHandleEos(dev); 1667 devpriv->ui_AiActualScan++; 1668 devpriv->b_ModeSelectRegister = 1669 devpriv-> 1670 b_ModeSelectRegister | 1671 APCI3120_ENABLE_EOS_INT; 1672 outb(devpriv->b_ModeSelectRegister, 1673 dev->iobase + 1674 APCI3120_WRITE_MODE_SELECT); 1675 } else { 1676 ui_Check = 0; 1677 for (i = 0; i < devpriv->ui_AiNbrofChannels; 1678 i++) { 1679 us_TmpValue = inw(devpriv->iobase + 0); 1680 devpriv->ui_AiReadData[i] = 1681 (unsigned int) us_TmpValue; 1682 } 1683 devpriv->b_EocEosInterrupt = APCI3120_DISABLE; 1684 devpriv->b_InterruptMode = APCI3120_EOC_MODE; 1685 1686 send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ 1687 1688 } 1689 1690 } else { 1691 devpriv->b_ModeSelectRegister = 1692 devpriv-> 1693 b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT; 1694 outb(devpriv->b_ModeSelectRegister, 1695 dev->iobase + APCI3120_WRITE_MODE_SELECT); 1696 devpriv->b_EocEosInterrupt = APCI3120_DISABLE; /* Default settings */ 1697 devpriv->b_InterruptMode = APCI3120_EOC_MODE; 1698 } 1699 1700 } 1701 /* Timer2 interrupt */ 1702 if (int_daq & 0x1) { 1703 1704 switch (devpriv->b_Timer2Mode) { 1705 case APCI3120_COUNTER: 1706 1707 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; 1708 devpriv->b_ModeSelectRegister = 1709 devpriv-> 1710 b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT; 1711 outb(devpriv->b_ModeSelectRegister, 1712 dev->iobase + APCI3120_WRITE_MODE_SELECT); 1713 1714 /* stop timer 2 */ 1715 devpriv->us_OutputRegister = 1716 devpriv-> 1717 us_OutputRegister & APCI3120_DISABLE_ALL_TIMER; 1718 outw(devpriv->us_OutputRegister, 1719 dev->iobase + APCI3120_WR_ADDRESS); 1720 1721 /* stop timer 0 and timer 1 */ 1722 i_APCI3120_StopCyclicAcquisition(dev, s); 1723 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; 1724 1725 /* UPDATE-0.7.57->0.7.68comedi_done(dev,s); */ 1726 s->async->events |= COMEDI_CB_EOA; 1727 comedi_event(dev, s); 1728 1729 break; 1730 1731 case APCI3120_TIMER: 1732 1733 /* Send a signal to from kernel to user space */ 1734 send_sig(SIGIO, devpriv->tsk_Current, 0); 1735 break; 1736 1737 case APCI3120_WATCHDOG: 1738 1739 /* Send a signal to from kernel to user space */ 1740 send_sig(SIGIO, devpriv->tsk_Current, 0); 1741 break; 1742 1743 default: 1744 1745 /* disable Timer Interrupt */ 1746 1747 devpriv->b_ModeSelectRegister = 1748 devpriv-> 1749 b_ModeSelectRegister & 1750 APCI3120_DISABLE_TIMER_INT; 1751 1752 outb(devpriv->b_ModeSelectRegister, 1753 dev->iobase + APCI3120_WRITE_MODE_SELECT); 1754 1755 } 1756 1757 b_DummyRead = inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); 1758 1759 } 1760 1761 if ((int_daq & 0x4) && (devpriv->b_InterruptMode == APCI3120_DMA_MODE)) { 1762 if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) { 1763 1764 /****************************/ 1765 /* Clear Timer Write TC int */ 1766 /****************************/ 1767 1768 outl(APCI3120_CLEAR_WRITE_TC_INT, 1769 devpriv->i_IobaseAmcc + 1770 APCI3120_AMCC_OP_REG_INTCSR); 1771 1772 /************************************/ 1773 /* Clears the timer status register */ 1774 /************************************/ 1775 inw(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); 1776 v_APCI3120_InterruptDma(irq, d); /* do some data transfer */ 1777 } else { 1778 /* Stops the Timer */ 1779 outw(devpriv-> 1780 us_OutputRegister & APCI3120_DISABLE_TIMER0 & 1781 APCI3120_DISABLE_TIMER1, 1782 dev->iobase + APCI3120_WR_ADDRESS); 1783 } 1784 1785 } 1786 1787 return; 1788} 1789 1790/* 1791 * Configure Timer 2 1792 * 1793 * data[0] = TIMER configure as timer 1794 * = WATCHDOG configure as watchdog 1795 * data[1] = Timer constant 1796 * data[2] = Timer2 interrupt (1)enable or(0) disable 1797 */ 1798static int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, 1799 struct comedi_subdevice *s, 1800 struct comedi_insn *insn, 1801 unsigned int *data) 1802{ 1803 const struct addi_board *this_board = comedi_board(dev); 1804 struct addi_private *devpriv = dev->private; 1805 unsigned int ui_Timervalue2; 1806 unsigned short us_TmpValue; 1807 unsigned char b_Tmp; 1808 1809 if (!data[1]) 1810 comedi_error(dev, "config:No timer constant !"); 1811 1812 devpriv->b_Timer2Interrupt = (unsigned char) data[2]; /* save info whether to enable or disable interrupt */ 1813 1814 ui_Timervalue2 = data[1] / 1000; /* convert nano seconds to u seconds */ 1815 1816 /* this_board->timer_config(dev, ui_Timervalue2,(unsigned char)data[0]); */ 1817 us_TmpValue = (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS); 1818 1819/* 1820 * EL250804: Testing if board APCI3120 have the new Quartz or if it 1821 * is an APCI3001 and calculate the time value to set in the timer 1822 */ 1823 if ((us_TmpValue & 0x00B0) == 0x00B0 1824 || !strcmp(this_board->pc_DriverName, "apci3001")) { 1825 /* Calculate the time value to set in the timer */ 1826 ui_Timervalue2 = ui_Timervalue2 / 50; 1827 } else { 1828 /* Calculate the time value to set in the timer */ 1829 ui_Timervalue2 = ui_Timervalue2 / 70; 1830 } 1831 1832 /* Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0) */ 1833 devpriv->us_OutputRegister = 1834 devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER2; 1835 outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS); 1836 1837 /* Disable TIMER Interrupt */ 1838 devpriv->b_ModeSelectRegister = 1839 devpriv-> 1840 b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT & 0xEF; 1841 1842 /* Disable Eoc and Eos Interrupts */ 1843 devpriv->b_ModeSelectRegister = 1844 devpriv-> 1845 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT & 1846 APCI3120_DISABLE_EOS_INT; 1847 outb(devpriv->b_ModeSelectRegister, 1848 devpriv->iobase + APCI3120_WRITE_MODE_SELECT); 1849 if (data[0] == APCI3120_TIMER) { /* initialize timer */ 1850 /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister | 1851 * APCI3120_ENABLE_TIMER_INT; */ 1852 1853 /* outb(devpriv->b_ModeSelectRegister,devpriv->iobase+APCI3120_WRITE_MODE_SELECT); */ 1854 1855 /* Set the Timer 2 in mode 2(Timer) */ 1856 devpriv->b_TimerSelectMode = 1857 (devpriv-> 1858 b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_2; 1859 outb(devpriv->b_TimerSelectMode, 1860 devpriv->iobase + APCI3120_TIMER_CRT1); 1861 1862/* 1863 * Configure the timer 2 for writing the LOW unsigned short of timer 1864 * is Delay value You must make a b_tmp variable with 1865 * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0 1866 * you can set the digital output and configure the timer 2,and if 1867 * you don't make this, digital output are erase (Set to 0) 1868 */ 1869 1870 /* Writing LOW unsigned short */ 1871 b_Tmp = ((devpriv-> 1872 b_DigitalOutputRegister) & 0xF0) | 1873 APCI3120_SELECT_TIMER_2_LOW_WORD; 1874 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); 1875 outw(LOWORD(ui_Timervalue2), 1876 devpriv->iobase + APCI3120_TIMER_VALUE); 1877 1878 /* Writing HIGH unsigned short */ 1879 b_Tmp = ((devpriv-> 1880 b_DigitalOutputRegister) & 0xF0) | 1881 APCI3120_SELECT_TIMER_2_HIGH_WORD; 1882 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); 1883 outw(HIWORD(ui_Timervalue2), 1884 devpriv->iobase + APCI3120_TIMER_VALUE); 1885 /* timer2 in Timer mode enabled */ 1886 devpriv->b_Timer2Mode = APCI3120_TIMER; 1887 1888 } else { /* Initialize Watch dog */ 1889 1890 /* Set the Timer 2 in mode 5(Watchdog) */ 1891 1892 devpriv->b_TimerSelectMode = 1893 (devpriv-> 1894 b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_5; 1895 outb(devpriv->b_TimerSelectMode, 1896 devpriv->iobase + APCI3120_TIMER_CRT1); 1897 1898/* 1899 * Configure the timer 2 for writing the LOW unsigned short of timer 1900 * is Delay value You must make a b_tmp variable with 1901 * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0 1902 * you can set the digital output and configure the timer 2,and if 1903 * you don't make this, digital output are erase (Set to 0) 1904 */ 1905 1906 /* Writing LOW unsigned short */ 1907 b_Tmp = ((devpriv-> 1908 b_DigitalOutputRegister) & 0xF0) | 1909 APCI3120_SELECT_TIMER_2_LOW_WORD; 1910 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); 1911 outw(LOWORD(ui_Timervalue2), 1912 devpriv->iobase + APCI3120_TIMER_VALUE); 1913 1914 /* Writing HIGH unsigned short */ 1915 b_Tmp = ((devpriv-> 1916 b_DigitalOutputRegister) & 0xF0) | 1917 APCI3120_SELECT_TIMER_2_HIGH_WORD; 1918 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); 1919 1920 outw(HIWORD(ui_Timervalue2), 1921 devpriv->iobase + APCI3120_TIMER_VALUE); 1922 /* watchdog enabled */ 1923 devpriv->b_Timer2Mode = APCI3120_WATCHDOG; 1924 1925 } 1926 1927 return insn->n; 1928 1929} 1930 1931/* 1932 * To start and stop the timer 1933 * 1934 * data[0] = 1 (start) 1935 * = 0 (stop) 1936 * = 2 (write new value) 1937 * data[1] = new value 1938 * 1939 * devpriv->b_Timer2Mode = 0 DISABLE 1940 * = 1 Timer 1941 * = 2 Watch dog 1942 */ 1943static int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, 1944 struct comedi_subdevice *s, 1945 struct comedi_insn *insn, 1946 unsigned int *data) 1947{ 1948 const struct addi_board *this_board = comedi_board(dev); 1949 struct addi_private *devpriv = dev->private; 1950 unsigned int ui_Timervalue2 = 0; 1951 unsigned short us_TmpValue; 1952 unsigned char b_Tmp; 1953 1954 if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG) 1955 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) { 1956 comedi_error(dev, "\nwrite:timer2 not configured "); 1957 return -EINVAL; 1958 } 1959 1960 if (data[0] == 2) { /* write new value */ 1961 if (devpriv->b_Timer2Mode != APCI3120_TIMER) { 1962 comedi_error(dev, 1963 "write :timer2 not configured in TIMER MODE"); 1964 return -EINVAL; 1965 } 1966 1967 if (data[1]) 1968 ui_Timervalue2 = data[1]; 1969 else 1970 ui_Timervalue2 = 0; 1971 } 1972 1973 /* this_board->timer_write(dev,data[0],ui_Timervalue2); */ 1974 1975 switch (data[0]) { 1976 case APCI3120_START: 1977 1978 /* Reset FC_TIMER BIT */ 1979 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER); 1980 if (devpriv->b_Timer2Mode == APCI3120_TIMER) { /* start timer */ 1981 /* Enable Timer */ 1982 devpriv->b_ModeSelectRegister = 1983 devpriv->b_ModeSelectRegister & 0x0B; 1984 } else { /* start watch dog */ 1985 /* Enable WatchDog */ 1986 devpriv->b_ModeSelectRegister = 1987 (devpriv-> 1988 b_ModeSelectRegister & 0x0B) | 1989 APCI3120_ENABLE_WATCHDOG; 1990 } 1991 1992 /* enable disable interrupt */ 1993 if ((devpriv->b_Timer2Interrupt) == APCI3120_ENABLE) { 1994 1995 devpriv->b_ModeSelectRegister = 1996 devpriv-> 1997 b_ModeSelectRegister | 1998 APCI3120_ENABLE_TIMER_INT; 1999 /* save the task structure to pass info to user */ 2000 devpriv->tsk_Current = current; 2001 } else { 2002 2003 devpriv->b_ModeSelectRegister = 2004 devpriv-> 2005 b_ModeSelectRegister & 2006 APCI3120_DISABLE_TIMER_INT; 2007 } 2008 outb(devpriv->b_ModeSelectRegister, 2009 devpriv->iobase + APCI3120_WRITE_MODE_SELECT); 2010 2011 if (devpriv->b_Timer2Mode == APCI3120_TIMER) { /* start timer */ 2012 /* For Timer mode is Gate2 must be activated **timer started */ 2013 devpriv->us_OutputRegister = 2014 devpriv-> 2015 us_OutputRegister | APCI3120_ENABLE_TIMER2; 2016 outw(devpriv->us_OutputRegister, 2017 devpriv->iobase + APCI3120_WR_ADDRESS); 2018 } 2019 2020 break; 2021 2022 case APCI3120_STOP: 2023 if (devpriv->b_Timer2Mode == APCI3120_TIMER) { 2024 /* Disable timer */ 2025 devpriv->b_ModeSelectRegister = 2026 devpriv-> 2027 b_ModeSelectRegister & 2028 APCI3120_DISABLE_TIMER_COUNTER; 2029 } else { 2030 /* Disable WatchDog */ 2031 devpriv->b_ModeSelectRegister = 2032 devpriv-> 2033 b_ModeSelectRegister & 2034 APCI3120_DISABLE_WATCHDOG; 2035 } 2036 /* Disable timer interrupt */ 2037 devpriv->b_ModeSelectRegister = 2038 devpriv-> 2039 b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT; 2040 2041 /* Write above states to register */ 2042 outb(devpriv->b_ModeSelectRegister, 2043 devpriv->iobase + APCI3120_WRITE_MODE_SELECT); 2044 2045 /* Reset Gate 2 */ 2046 devpriv->us_OutputRegister = 2047 devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER_INT; 2048 outw(devpriv->us_OutputRegister, 2049 devpriv->iobase + APCI3120_WR_ADDRESS); 2050 2051 /* Reset FC_TIMER BIT */ 2052 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER); 2053 2054 /* Disable timer */ 2055 /* devpriv->b_Timer2Mode=APCI3120_DISABLE; */ 2056 2057 break; 2058 2059 case 2: /* write new value to Timer */ 2060 if (devpriv->b_Timer2Mode != APCI3120_TIMER) { 2061 comedi_error(dev, 2062 "write :timer2 not configured in TIMER MODE"); 2063 return -EINVAL; 2064 } 2065 /* ui_Timervalue2=data[1]; // passed as argument */ 2066 us_TmpValue = 2067 (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS); 2068 2069/* 2070 * EL250804: Testing if board APCI3120 have the new Quartz or if it 2071 * is an APCI3001 and calculate the time value to set in the timer 2072 */ 2073 if ((us_TmpValue & 0x00B0) == 0x00B0 2074 || !strcmp(this_board->pc_DriverName, "apci3001")) { 2075 /* Calculate the time value to set in the timer */ 2076 ui_Timervalue2 = ui_Timervalue2 / 50; 2077 } else { 2078 /* Calculate the time value to set in the timer */ 2079 ui_Timervalue2 = ui_Timervalue2 / 70; 2080 } 2081 /* Writing LOW unsigned short */ 2082 b_Tmp = ((devpriv-> 2083 b_DigitalOutputRegister) & 0xF0) | 2084 APCI3120_SELECT_TIMER_2_LOW_WORD; 2085 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); 2086 2087 outw(LOWORD(ui_Timervalue2), 2088 devpriv->iobase + APCI3120_TIMER_VALUE); 2089 2090 /* Writing HIGH unsigned short */ 2091 b_Tmp = ((devpriv-> 2092 b_DigitalOutputRegister) & 0xF0) | 2093 APCI3120_SELECT_TIMER_2_HIGH_WORD; 2094 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); 2095 2096 outw(HIWORD(ui_Timervalue2), 2097 devpriv->iobase + APCI3120_TIMER_VALUE); 2098 2099 break; 2100 default: 2101 return -EINVAL; /* Not a valid input */ 2102 } 2103 2104 return insn->n; 2105} 2106 2107/* 2108 * Read the Timer value 2109 * 2110 * for Timer: data[0]= Timer constant 2111 * 2112 * for watchdog: data[0] = 0 (still running) 2113 * = 1 (run down) 2114 */ 2115static int i_APCI3120_InsnReadTimer(struct comedi_device *dev, 2116 struct comedi_subdevice *s, 2117 struct comedi_insn *insn, 2118 unsigned int *data) 2119{ 2120 struct addi_private *devpriv = dev->private; 2121 unsigned char b_Tmp; 2122 unsigned short us_TmpValue, us_TmpValue_2, us_StatusValue; 2123 2124 if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG) 2125 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) { 2126 comedi_error(dev, "\nread:timer2 not configured "); 2127 } 2128 2129 /* this_board->timer_read(dev,data); */ 2130 if (devpriv->b_Timer2Mode == APCI3120_TIMER) { 2131 2132 /* Read the LOW unsigned short of Timer 2 register */ 2133 b_Tmp = ((devpriv-> 2134 b_DigitalOutputRegister) & 0xF0) | 2135 APCI3120_SELECT_TIMER_2_LOW_WORD; 2136 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); 2137 2138 us_TmpValue = inw(devpriv->iobase + APCI3120_TIMER_VALUE); 2139 2140 /* Read the HIGH unsigned short of Timer 2 register */ 2141 b_Tmp = ((devpriv-> 2142 b_DigitalOutputRegister) & 0xF0) | 2143 APCI3120_SELECT_TIMER_2_HIGH_WORD; 2144 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); 2145 2146 us_TmpValue_2 = inw(devpriv->iobase + APCI3120_TIMER_VALUE); 2147 2148 /* combining both words */ 2149 data[0] = (unsigned int) ((us_TmpValue) | ((us_TmpValue_2) << 16)); 2150 2151 } else { /* Read watch dog status */ 2152 2153 us_StatusValue = inw(devpriv->iobase + APCI3120_RD_STATUS); 2154 us_StatusValue = 2155 ((us_StatusValue & APCI3120_FC_TIMER) >> 12) & 1; 2156 if (us_StatusValue == 1) { 2157 /* RESET FC_TIMER BIT */ 2158 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER); 2159 } 2160 data[0] = us_StatusValue; /* when data[0] = 1 then the watch dog has rundown */ 2161 } 2162 return insn->n; 2163} 2164 2165static int apci3120_di_insn_bits(struct comedi_device *dev, 2166 struct comedi_subdevice *s, 2167 struct comedi_insn *insn, 2168 unsigned int *data) 2169{ 2170 struct addi_private *devpriv = dev->private; 2171 unsigned int val; 2172 2173 /* the input channels are bits 11:8 of the status reg */ 2174 val = inw(devpriv->iobase + APCI3120_RD_STATUS); 2175 data[1] = (val >> 8) & 0xf; 2176 2177 return insn->n; 2178} 2179 2180static int apci3120_do_insn_bits(struct comedi_device *dev, 2181 struct comedi_subdevice *s, 2182 struct comedi_insn *insn, 2183 unsigned int *data) 2184{ 2185 struct addi_private *devpriv = dev->private; 2186 unsigned int mask = data[0]; 2187 unsigned int bits = data[1]; 2188 unsigned int val; 2189 2190 /* The do channels are bits 7:4 of the do register */ 2191 val = devpriv->b_DigitalOutputRegister >> 4; 2192 if (mask) { 2193 val &= ~mask; 2194 val |= (bits & mask); 2195 devpriv->b_DigitalOutputRegister = val << 4; 2196 2197 outb(val << 4, devpriv->iobase + APCI3120_DIGITAL_OUTPUT); 2198 } 2199 2200 data[1] = val; 2201 2202 return insn->n; 2203} 2204 2205static int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev, 2206 struct comedi_subdevice *s, 2207 struct comedi_insn *insn, 2208 unsigned int *data) 2209{ 2210 struct addi_private *devpriv = dev->private; 2211 unsigned int ui_Range, ui_Channel; 2212 unsigned short us_TmpValue; 2213 2214 ui_Range = CR_RANGE(insn->chanspec); 2215 ui_Channel = CR_CHAN(insn->chanspec); 2216 2217 /* this_board->ao_write(dev, ui_Range, ui_Channel,data[0]); */ 2218 if (ui_Range) { /* if 1 then unipolar */ 2219 2220 if (data[0] != 0) 2221 data[0] = 2222 ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 << 2223 13) | (data[0] + 8191)); 2224 else 2225 data[0] = 2226 ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 << 2227 13) | 8192); 2228 2229 } else { /* if 0 then bipolar */ 2230 data[0] = 2231 ((((ui_Channel & 0x03) << 14) & 0xC000) | (0 << 13) | 2232 data[0]); 2233 2234 } 2235 2236/* 2237 * out put n values at the given channel. printk("\nwaiting for 2238 * DA_READY BIT"); 2239 */ 2240 do { /* Waiting of DA_READY BIT */ 2241 us_TmpValue = 2242 ((unsigned short) inw(devpriv->iobase + 2243 APCI3120_RD_STATUS)) & 0x0001; 2244 } while (us_TmpValue != 0x0001); 2245 2246 if (ui_Channel <= 3) 2247/* 2248 * for channel 0-3 out at the register 1 (wrDac1-8) data[i] 2249 * typecasted to ushort since word write is to be done 2250 */ 2251 outw((unsigned short) data[0], 2252 devpriv->iobase + APCI3120_ANALOG_OUTPUT_1); 2253 else 2254/* 2255 * for channel 4-7 out at the register 2 (wrDac5-8) data[i] 2256 * typecasted to ushort since word write is to be done 2257 */ 2258 outw((unsigned short) data[0], 2259 devpriv->iobase + APCI3120_ANALOG_OUTPUT_2); 2260 2261 return insn->n; 2262} 2263