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