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