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