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