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