4 Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
10 Fax: +49(0)7223/9493-92
11 http://www.addi-data-com
14 This 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.
16 This 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.
18 You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 You shoud also find the complete GPL in the COPYING file accompanying this source code.
25 +-----------------------------------------------------------------------+
26 | (C) ADDI-DATA GmbH Dieselstrasse 3 D-77833 Ottersweier |
27 +-----------------------------------------------------------------------+
28 | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com |
29 | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com |
30 +-----------------------------------------------------------------------+
31 | Project : APCI-3120 | Compiler : GCC |
32 | Module name : hwdrv_apci3120.c| Version : 2.96 |
33 +-------------------------------+---------------------------------------+
34 | Project manager: Eric Stolz | Date : 02/12/2002 |
35 +-----------------------------------------------------------------------+
36 | Description :APCI3120 Module. Hardware abstraction Layer for APCI3120|
37 +-----------------------------------------------------------------------+
39 +-----------------------------------------------------------------------+
40 | Date | Author | Description of updates |
41 +----------+-----------+------------------------------------------------+
44 +----------+-----------+------------------------------------------------+
47 #include "hwdrv_apci3120.h"
48 static UINT ui_Temp = 0;
50 // FUNCTION DEFINITIONS
53 +----------------------------------------------------------------------------+
54 | ANALOG INPUT SUBDEVICE |
55 +----------------------------------------------------------------------------+
59 +----------------------------------------------------------------------------+
60 | Function name :int i_APCI3120_InsnConfigAnalogInput(comedi_device *dev,|
61 | comedi_subdevice *s,comedi_insn *insn,lsampl_t *data) |
63 +----------------------------------------------------------------------------+
64 | Task : Calls card specific function |
66 +----------------------------------------------------------------------------+
67 | Input Parameters : comedi_device *dev |
68 | comedi_subdevice *s |
71 +----------------------------------------------------------------------------+
74 +----------------------------------------------------------------------------+
77 int i_APCI3120_InsnConfigAnalogInput(comedi_device * dev, comedi_subdevice * s,
78 comedi_insn * insn, lsampl_t * data)
82 if ((data[0] != APCI3120_EOC_MODE) && (data[0] != APCI3120_EOS_MODE))
85 // Check for Conversion time to be added ??
86 devpriv->ui_EocEosConversionTime = data[2];
88 if (data[0] == APCI3120_EOS_MODE) {
90 //Test the number of the channel
91 for (i = 0; i < data[3]; i++) {
93 if (CR_CHAN(data[4 + i]) >= this_board->i_NbrAiChannel) {
94 printk("bad channel list\n");
99 devpriv->b_InterruptMode = APCI3120_EOS_MODE;
102 devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
104 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
105 // Copy channel list and Range List to devpriv
107 devpriv->ui_AiNbrofChannels = data[3];
108 for (i = 0; i < devpriv->ui_AiNbrofChannels; i++) {
109 devpriv->ui_AiChannelList[i] = data[4 + i];
114 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
116 devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
118 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
126 +----------------------------------------------------------------------------+
127 | Function name :int i_APCI3120_InsnReadAnalogInput(comedi_device *dev, |
128 | comedi_subdevice *s,comedi_insn *insn, lsampl_t *data) |
130 +----------------------------------------------------------------------------+
131 | Task : card specific function |
132 | Reads analog input in synchronous mode |
133 | EOC and EOS is selected as per configured |
134 | if no conversion time is set uses default conversion |
135 | time 10 microsec. |
137 +----------------------------------------------------------------------------+
138 | Input Parameters : comedi_device *dev |
139 | comedi_subdevice *s |
140 | comedi_insn *insn |
142 +----------------------------------------------------------------------------+
145 +----------------------------------------------------------------------------+
148 int i_APCI3120_InsnReadAnalogInput(comedi_device * dev, comedi_subdevice * s,
149 comedi_insn * insn, lsampl_t * data)
151 USHORT us_ConvertTiming, us_TmpValue, i;
154 // fix convertion time to 10 us
155 if (!devpriv->ui_EocEosConversionTime) {
156 printk("No timer0 Value using 10 us\n");
157 us_ConvertTiming = 10;
159 us_ConvertTiming = (USHORT) (devpriv->ui_EocEosConversionTime / 1000); // nano to useconds
161 // this_board->i_hwdrv_InsnReadAnalogInput(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]);
163 // Clear software registers
164 devpriv->b_TimerSelectMode = 0;
165 devpriv->b_ModeSelectRegister = 0;
166 devpriv->us_OutputRegister = 0;
167 // devpriv->b_DigitalOutputRegister=0;
169 if (insn->unused[0] == 222) // second insn read
172 for (i = 0; i < insn->n; i++) {
173 data[i] = devpriv->ui_AiReadData[i];
177 devpriv->tsk_Current = current; // Save the current process task structure
178 //Testing if board have the new Quartz and calculate the time value
179 //to set in the timer
182 (USHORT) inw(devpriv->iobase + APCI3120_RD_STATUS);
184 //EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001
185 if ((us_TmpValue & 0x00B0) == 0x00B0
186 || !strcmp(this_board->pc_DriverName, "apci3001")) {
187 us_ConvertTiming = (us_ConvertTiming * 2) - 2;
190 ((us_ConvertTiming * 12926) / 10000) - 1;
193 us_TmpValue = (USHORT) devpriv->b_InterruptMode;
195 switch (us_TmpValue) {
197 case APCI3120_EOC_MODE:
199 // Testing the interrupt flag and set the EOC bit
201 inw(devpriv->iobase + APCI3120_RESET_FIFO);
203 // Initialize the sequence array
205 //if (!i_APCI3120_SetupChannelList(dev,s,1,chanlist,0)) return -EINVAL;
207 if (!i_APCI3120_SetupChannelList(dev, s, 1,
211 //Initialize Timer 0 mode 4
212 devpriv->b_TimerSelectMode =
214 b_TimerSelectMode & 0xFC) |
215 APCI3120_TIMER_0_MODE_4;
216 outb(devpriv->b_TimerSelectMode,
217 devpriv->iobase + APCI3120_TIMER_CRT1);
219 // Reset the scan bit and Disables the EOS, DMA, EOC interrupt
220 devpriv->b_ModeSelectRegister =
222 b_ModeSelectRegister & APCI3120_DISABLE_SCAN;
224 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
226 //Disables the EOS,DMA and enables the EOC interrupt
227 devpriv->b_ModeSelectRegister =
229 b_ModeSelectRegister &
230 APCI3120_DISABLE_EOS_INT) |
231 APCI3120_ENABLE_EOC_INT;
232 inw(devpriv->iobase);
235 devpriv->b_ModeSelectRegister =
237 b_ModeSelectRegister &
238 APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER;
241 outb(devpriv->b_ModeSelectRegister,
242 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
245 devpriv->us_OutputRegister =
247 us_OutputRegister & APCI3120_CLEAR_PA_PR) |
248 APCI3120_ENABLE_TIMER0;
249 outw(devpriv->us_OutputRegister,
250 devpriv->iobase + APCI3120_WR_ADDRESS);
254 b_DigitalOutputRegister) & 0xF0) |
255 APCI3120_SELECT_TIMER_0_WORD;
256 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
258 //Set the convertion time
259 outw(us_ConvertTiming,
260 devpriv->iobase + APCI3120_TIMER_VALUE);
263 (USHORT) inw(dev->iobase + APCI3120_RD_STATUS);
265 if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
268 // Waiting for the end of conversion
270 inw(devpriv->iobase +
272 } while ((us_TmpValue & APCI3120_EOC) ==
275 //Read the result in FIFO and put it in insn data pointer
276 us_TmpValue = inw(devpriv->iobase + 0);
279 inw(devpriv->iobase + APCI3120_RESET_FIFO);
284 case APCI3120_EOS_MODE:
286 inw(devpriv->iobase);
288 inw(devpriv->iobase + APCI3120_RESET_FIFO);
289 // clear PA PR and disable timer 0
291 devpriv->us_OutputRegister =
293 us_OutputRegister & APCI3120_CLEAR_PA_PR) |
294 APCI3120_DISABLE_TIMER0;
296 outw(devpriv->us_OutputRegister,
297 devpriv->iobase + APCI3120_WR_ADDRESS);
299 if (!i_APCI3120_SetupChannelList(dev, s,
300 devpriv->ui_AiNbrofChannels,
301 devpriv->ui_AiChannelList, 0))
304 //Initialize Timer 0 mode 2
305 devpriv->b_TimerSelectMode =
307 b_TimerSelectMode & 0xFC) |
308 APCI3120_TIMER_0_MODE_2;
309 outb(devpriv->b_TimerSelectMode,
310 devpriv->iobase + APCI3120_TIMER_CRT1);
314 b_DigitalOutputRegister) & 0xF0) |
315 APCI3120_SELECT_TIMER_0_WORD;
316 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
318 //Set the convertion time
319 outw(us_ConvertTiming,
320 devpriv->iobase + APCI3120_TIMER_VALUE);
323 devpriv->b_ModeSelectRegister =
325 b_ModeSelectRegister | APCI3120_ENABLE_SCAN;
326 outb(devpriv->b_ModeSelectRegister,
327 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
329 //If Interrupt function is loaded
330 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
331 //Disables the EOC,DMA and enables the EOS interrupt
332 devpriv->b_ModeSelectRegister =
334 b_ModeSelectRegister &
335 APCI3120_DISABLE_EOC_INT) |
336 APCI3120_ENABLE_EOS_INT;
337 inw(devpriv->iobase);
340 devpriv->b_ModeSelectRegister =
342 b_ModeSelectRegister &
343 APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER;
345 outb(devpriv->b_ModeSelectRegister,
346 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
348 inw(devpriv->iobase + APCI3120_RD_STATUS);
352 devpriv->us_OutputRegister =
354 us_OutputRegister | APCI3120_ENABLE_TIMER0;
355 outw(devpriv->us_OutputRegister,
356 devpriv->iobase + APCI3120_WR_ADDRESS);
359 outw(0, devpriv->iobase + APCI3120_START_CONVERSION);
361 //Waiting of end of convertion if interrupt is not installed
362 if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
363 //Waiting the end of convertion
366 inw(devpriv->iobase +
369 while ((us_TmpValue & APCI3120_EOS) !=
372 for (i = 0; i < devpriv->ui_AiNbrofChannels;
374 //Read the result in FIFO and write them in shared memory
375 us_TmpValue = inw(devpriv->iobase);
376 data[i] = (UINT) us_TmpValue;
379 devpriv->b_InterruptMode = APCI3120_EOC_MODE; // Restore defaults.
384 printk("inputs wrong\n");
387 devpriv->ui_EocEosConversionTime = 0; // re initializing the variable;
395 +----------------------------------------------------------------------------+
396 | Function name :int i_APCI3120_StopCyclicAcquisition(comedi_device *dev,|
397 | comedi_subdevice *s)|
399 +----------------------------------------------------------------------------+
400 | Task : Stops Cyclic acquisition |
402 +----------------------------------------------------------------------------+
403 | Input Parameters : comedi_device *dev |
404 | comedi_subdevice *s |
406 +----------------------------------------------------------------------------+
409 +----------------------------------------------------------------------------+
412 int i_APCI3120_StopCyclicAcquisition(comedi_device * dev, comedi_subdevice * s)
414 // Disable A2P Fifo write and AMWEN signal
415 outw(0, devpriv->i_IobaseAddon + 4);
417 //Disable Bus Master ADD ON
418 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
419 outw(0, devpriv->i_IobaseAddon + 2);
420 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
421 outw(0, devpriv->i_IobaseAddon + 2);
423 //Disable BUS Master PCI
424 outl(0, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
426 //outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR)&(~AINT_WRITE_COMPL), devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR); // stop amcc irqs
427 //outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR)&(~EN_A2P_TRANSFERS), devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR); // stop DMA
429 //Disable ext trigger
430 i_APCI3120_ExttrigDisable(dev);
432 devpriv->us_OutputRegister = 0;
435 us_OutputRegister & APCI3120_DISABLE_TIMER0 &
436 APCI3120_DISABLE_TIMER1, dev->iobase + APCI3120_WR_ADDRESS);
438 outw(APCI3120_DISABLE_ALL_TIMER, dev->iobase + APCI3120_WR_ADDRESS);
440 //DISABLE_ALL_INTERRUPT
441 outb(APCI3120_DISABLE_ALL_INTERRUPT,
442 dev->iobase + APCI3120_WRITE_MODE_SELECT);
444 inb(dev->iobase + APCI3120_RESET_FIFO);
445 inw(dev->iobase + APCI3120_RD_STATUS);
446 devpriv->ui_AiActualScan = 0;
447 devpriv->ui_AiActualScanPosition = 0;
448 s->async->cur_chan = 0;
449 devpriv->ui_AiBufferPtr = 0;
450 devpriv->b_AiContinuous = 0;
451 devpriv->ui_DmaActualBuffer = 0;
453 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
454 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
455 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
456 i_APCI3120_Reset(dev);
461 +----------------------------------------------------------------------------+
462 | Function name :int i_APCI3120_CommandTestAnalogInput(comedi_device *dev|
463 | ,comedi_subdevice *s,comedi_cmd *cmd) |
465 +----------------------------------------------------------------------------+
466 | Task : Test validity for a command for cyclic anlog input |
469 +----------------------------------------------------------------------------+
470 | Input Parameters : comedi_device *dev |
471 | comedi_subdevice *s |
473 +----------------------------------------------------------------------------+
476 +----------------------------------------------------------------------------+
479 int i_APCI3120_CommandTestAnalogInput(comedi_device * dev, comedi_subdevice * s,
483 int tmp; // divisor1,divisor2;
485 // step 1: make sure trigger sources are trivially valid
487 tmp = cmd->start_src;
488 cmd->start_src &= TRIG_NOW | TRIG_EXT;
489 if (!cmd->start_src || tmp != cmd->start_src)
492 tmp = cmd->scan_begin_src;
493 cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW;
494 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
497 tmp = cmd->convert_src;
498 cmd->convert_src &= TRIG_TIMER;
499 if (!cmd->convert_src || tmp != cmd->convert_src)
502 tmp = cmd->scan_end_src;
503 cmd->scan_end_src &= TRIG_COUNT;
504 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
508 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
509 if (!cmd->stop_src || tmp != cmd->stop_src)
515 //step 2: make sure trigger sources are unique and mutually compatible
517 if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) {
521 if (cmd->scan_begin_src != TRIG_TIMER &&
522 cmd->scan_begin_src != TRIG_FOLLOW)
525 if (cmd->convert_src != TRIG_TIMER)
528 if (cmd->scan_end_src != TRIG_COUNT) {
529 cmd->scan_end_src = TRIG_COUNT;
533 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
539 // step 3: make sure arguments are trivially compatible
541 if (cmd->start_arg != 0) {
546 if (cmd->scan_begin_src == TRIG_TIMER) // Test Delay timing
548 if (cmd->scan_begin_arg < this_board->ui_MinDelaytimeNs) {
549 cmd->scan_begin_arg = this_board->ui_MinDelaytimeNs;
554 if (cmd->convert_src == TRIG_TIMER) // Test Acquisition timing
556 if (cmd->scan_begin_src == TRIG_TIMER) {
557 if ((cmd->convert_arg)
558 && (cmd->convert_arg <
559 this_board->ui_MinAcquisitiontimeNs)) {
561 this_board->ui_MinAcquisitiontimeNs;
565 if (cmd->convert_arg <
566 this_board->ui_MinAcquisitiontimeNs) {
568 this_board->ui_MinAcquisitiontimeNs;
575 if (!cmd->chanlist_len) {
576 cmd->chanlist_len = 1;
579 if (cmd->chanlist_len > this_board->i_AiChannelList) {
580 cmd->chanlist_len = this_board->i_AiChannelList;
583 if (cmd->stop_src == TRIG_COUNT) {
584 if (!cmd->stop_arg) {
588 } else { // TRIG_NONE
589 if (cmd->stop_arg != 0) {
598 // step 4: fix up any arguments
600 if (cmd->convert_src == TRIG_TIMER) {
602 if (cmd->scan_begin_src == TRIG_TIMER &&
603 cmd->scan_begin_arg <
604 cmd->convert_arg * cmd->scan_end_arg) {
605 cmd->scan_begin_arg =
606 cmd->convert_arg * cmd->scan_end_arg;
618 +----------------------------------------------------------------------------+
619 | Function name : int i_APCI3120_CommandAnalogInput(comedi_device *dev, |
620 | comedi_subdevice *s) |
622 +----------------------------------------------------------------------------+
623 | Task : Does asynchronous acquisition |
624 | Determines the mode 1 or 2. |
626 +----------------------------------------------------------------------------+
627 | Input Parameters : comedi_device *dev |
628 | comedi_subdevice *s |
630 +----------------------------------------------------------------------------+
633 +----------------------------------------------------------------------------+
636 int i_APCI3120_CommandAnalogInput(comedi_device * dev, comedi_subdevice * s)
638 comedi_cmd *cmd = &s->async->cmd;
640 //loading private structure with cmd structure inputs
641 devpriv->ui_AiFlags = cmd->flags;
642 devpriv->ui_AiNbrofChannels = cmd->chanlist_len;
643 devpriv->ui_AiScanLength = cmd->scan_end_arg;
644 devpriv->pui_AiChannelList = cmd->chanlist;
646 //UPDATE-0.7.57->0.7.68devpriv->AiData=s->async->data;
647 devpriv->AiData = s->async->prealloc_buf;
648 //UPDATE-0.7.57->0.7.68devpriv->ui_AiDataLength=s->async->data_len;
649 devpriv->ui_AiDataLength = s->async->prealloc_bufsz;
651 if (cmd->stop_src == TRIG_COUNT) {
652 devpriv->ui_AiNbrofScans = cmd->stop_arg;
654 devpriv->ui_AiNbrofScans = 0;
657 devpriv->ui_AiTimer0 = 0; // variables changed to timer0,timer1
658 devpriv->ui_AiTimer1 = 0;
659 if ((devpriv->ui_AiNbrofScans == 0) || (devpriv->ui_AiNbrofScans == -1))
660 devpriv->b_AiContinuous = 1; // user want neverending analog acquisition
661 // stopped using cancel
663 if (cmd->start_src == TRIG_EXT)
664 devpriv->b_ExttrigEnable = APCI3120_ENABLE;
666 devpriv->b_ExttrigEnable = APCI3120_DISABLE;
668 if (cmd->scan_begin_src == TRIG_FOLLOW) {
670 if (cmd->convert_src == TRIG_TIMER) {
673 devpriv->ui_AiTimer0 = cmd->convert_arg; // timer constant in nano seconds
674 //return this_board->i_hwdrv_CommandAnalogInput(1,dev,s);
675 return i_APCI3120_CyclicAnalogInput(1, dev, s);
679 if ((cmd->scan_begin_src == TRIG_TIMER)
680 && (cmd->convert_src == TRIG_TIMER)) {
682 devpriv->ui_AiTimer1 = cmd->scan_begin_arg;
683 devpriv->ui_AiTimer0 = cmd->convert_arg; // variable changed timer2 to timer0
684 //return this_board->i_hwdrv_CommandAnalogInput(2,dev,s);
685 return i_APCI3120_CyclicAnalogInput(2, dev, s);
691 +----------------------------------------------------------------------------+
692 | Function name : int i_APCI3120_CyclicAnalogInput(int mode, |
693 | comedi_device * dev,comedi_subdevice * s) |
694 +----------------------------------------------------------------------------+
695 | Task : This is used for analog input cyclic acquisition |
696 | Performs the command operations. |
697 | If DMA is configured does DMA initialization |
698 | otherwise does the acquisition with EOS interrupt. |
700 +----------------------------------------------------------------------------+
701 | Input Parameters : |
704 +----------------------------------------------------------------------------+
707 +----------------------------------------------------------------------------+
710 int i_APCI3120_CyclicAnalogInput(int mode, comedi_device * dev,
711 comedi_subdevice * s)
714 UINT ui_Tmp, ui_DelayTiming = 0, ui_TimerValue1 = 0, dmalen0 =
715 0, dmalen1 = 0, ui_TimerValue2 =
716 0, ui_TimerValue0, ui_ConvertTiming;
719 //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
720 //devpriv->b_AiCyclicAcquisition=APCI3120_ENABLE;
721 //END JK 07.05.04: Comparison between WIN32 and Linux driver
723 /*******************/
724 /* Resets the FIFO */
725 /*******************/
726 inb(dev->iobase + APCI3120_RESET_FIFO);
728 //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
729 //inw(dev->iobase+APCI3120_RD_STATUS);
730 //END JK 07.05.04: Comparison between WIN32 and Linux driver
732 /***************************/
733 /* Acquisition initialized */
734 /***************************/
735 //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
736 devpriv->b_AiCyclicAcquisition = APCI3120_ENABLE;
737 //END JK 07.05.04: Comparison between WIN32 and Linux driver
739 // clear software registers
740 devpriv->b_TimerSelectMode = 0;
741 devpriv->us_OutputRegister = 0;
742 devpriv->b_ModeSelectRegister = 0;
743 //devpriv->b_DigitalOutputRegister=0;
745 //COMMENT JK 07.05.04: Followings calls are in i_APCI3120_StartAnalogInputAcquisition
747 /****************************/
748 /* Clear Timer Write TC INT */
749 /****************************/
750 outl(APCI3120_CLEAR_WRITE_TC_INT,
751 devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_REG_INTCSR);
753 /************************************/
754 /* Clears the timer status register */
755 /************************************/
756 //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
757 //inw(dev->iobase+APCI3120_TIMER_STATUS_REGISTER);
758 inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
759 //END JK 07.05.04: Comparison between WIN32 and Linux driver
761 /**************************/
762 /* Disables All Timer */
763 /* Sets PR and PA to 0 */
764 /**************************/
765 devpriv->us_OutputRegister = devpriv->us_OutputRegister &
766 APCI3120_DISABLE_TIMER0 &
767 APCI3120_DISABLE_TIMER1 & APCI3120_CLEAR_PA_PR;
769 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
771 /*******************/
772 /* Resets the FIFO */
773 /*******************/
774 //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
775 inb(devpriv->iobase + APCI3120_RESET_FIFO);
776 //END JK 07.05.04: Comparison between WIN32 and Linux driver
778 devpriv->ui_AiActualScan = 0;
779 devpriv->ui_AiActualScanPosition = 0;
780 s->async->cur_chan = 0;
781 devpriv->ui_AiBufferPtr = 0;
782 devpriv->ui_DmaActualBuffer = 0;
784 // value for timer2 minus -2 has to be done .....dunno y??
785 ui_TimerValue2 = devpriv->ui_AiNbrofScans - 2;
786 ui_ConvertTiming = devpriv->ui_AiTimer0;
789 ui_DelayTiming = devpriv->ui_AiTimer1;
791 /**********************************/
792 /* Initializes the sequence array */
793 /**********************************/
794 if (!i_APCI3120_SetupChannelList(dev, s, devpriv->ui_AiNbrofChannels,
795 devpriv->pui_AiChannelList, 0))
798 us_TmpValue = (USHORT) inw(dev->iobase + APCI3120_RD_STATUS);
799 /*** EL241003 : add this section in comment because floats must not be used
800 if((us_TmpValue & 0x00B0)==0x00B0)
802 f_ConvertValue=(((float)ui_ConvertTiming * 0.002) - 2);
803 ui_TimerValue0=(UINT)f_ConvertValue;
806 f_DelayValue = (((float)ui_DelayTiming * 0.00002) - 2);
807 ui_TimerValue1 = (UINT) f_DelayValue;
812 f_ConvertValue=(((float)ui_ConvertTiming * 0.0012926) - 1);
813 ui_TimerValue0=(UINT)f_ConvertValue;
816 f_DelayValue = (((float)ui_DelayTiming * 0.000012926) - 1);
817 ui_TimerValue1 = (UINT) f_DelayValue;
820 ***********************************************************************************************/
821 /*** EL241003 Begin : add this section to replace floats calculation by integer calculations **/
822 //EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001
823 if ((us_TmpValue & 0x00B0) == 0x00B0
824 || !strcmp(this_board->pc_DriverName, "apci3001")) {
825 ui_TimerValue0 = ui_ConvertTiming * 2 - 2000;
826 ui_TimerValue0 = ui_TimerValue0 / 1000;
829 ui_DelayTiming = ui_DelayTiming / 1000;
830 ui_TimerValue1 = ui_DelayTiming * 2 - 200;
831 ui_TimerValue1 = ui_TimerValue1 / 100;
834 ui_ConvertTiming = ui_ConvertTiming / 1000;
835 ui_TimerValue0 = ui_ConvertTiming * 12926 - 10000;
836 ui_TimerValue0 = ui_TimerValue0 / 10000;
839 ui_DelayTiming = ui_DelayTiming / 1000;
840 ui_TimerValue1 = ui_DelayTiming * 12926 - 1;
841 ui_TimerValue1 = ui_TimerValue1 / 1000000;
844 /*** EL241003 End ******************************************************************************/
846 if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) {
847 i_APCI3120_ExttrigEnable(dev); // activate EXT trigger
851 // init timer0 in mode 2
852 devpriv->b_TimerSelectMode =
854 b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
855 outb(devpriv->b_TimerSelectMode,
856 dev->iobase + APCI3120_TIMER_CRT1);
860 b_DigitalOutputRegister) & 0xF0) |
861 APCI3120_SELECT_TIMER_0_WORD;
862 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
863 //Set the convertion time
864 outw(((USHORT) ui_TimerValue0),
865 dev->iobase + APCI3120_TIMER_VALUE);
869 // init timer1 in mode 2
870 devpriv->b_TimerSelectMode =
872 b_TimerSelectMode & 0xF3) | APCI3120_TIMER_1_MODE_2;
873 outb(devpriv->b_TimerSelectMode,
874 dev->iobase + APCI3120_TIMER_CRT1);
878 b_DigitalOutputRegister) & 0xF0) |
879 APCI3120_SELECT_TIMER_1_WORD;
880 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
881 //Set the convertion time
882 outw(((USHORT) ui_TimerValue1),
883 dev->iobase + APCI3120_TIMER_VALUE);
885 // init timer0 in mode 2
886 devpriv->b_TimerSelectMode =
888 b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
889 outb(devpriv->b_TimerSelectMode,
890 dev->iobase + APCI3120_TIMER_CRT1);
894 b_DigitalOutputRegister) & 0xF0) |
895 APCI3120_SELECT_TIMER_0_WORD;
896 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
898 //Set the convertion time
899 outw(((USHORT) ui_TimerValue0),
900 dev->iobase + APCI3120_TIMER_VALUE);
904 // ##########common for all modes#################
906 /***********************/
907 /* Clears the SCAN bit */
908 /***********************/
909 //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
910 //devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister | APCI3120_DISABLE_SCAN;
911 devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
912 APCI3120_DISABLE_SCAN;
913 //END JK 07.05.04: Comparison between WIN32 and Linux driver
914 outb(devpriv->b_ModeSelectRegister,
915 dev->iobase + APCI3120_WRITE_MODE_SELECT);
917 // If DMA is disabled
918 if (devpriv->us_UseDma == APCI3120_DISABLE) {
919 // disable EOC and enable EOS
920 devpriv->b_InterruptMode = APCI3120_EOS_MODE;
921 devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
923 devpriv->b_ModeSelectRegister =
925 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT) |
926 APCI3120_ENABLE_EOS_INT;
927 outb(devpriv->b_ModeSelectRegister,
928 dev->iobase + APCI3120_WRITE_MODE_SELECT);
930 if (!devpriv->b_AiContinuous) {
931 // configure Timer2 For counting EOS
932 //Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0)
933 devpriv->us_OutputRegister =
935 us_OutputRegister & APCI3120_DISABLE_TIMER2;
936 outw(devpriv->us_OutputRegister,
937 dev->iobase + APCI3120_WR_ADDRESS);
939 // DISABLE TIMER INTERRUPT
940 devpriv->b_ModeSelectRegister =
942 b_ModeSelectRegister &
943 APCI3120_DISABLE_TIMER_INT & 0xEF;
944 outb(devpriv->b_ModeSelectRegister,
945 dev->iobase + APCI3120_WRITE_MODE_SELECT);
947 //(1) Init timer 2 in mode 0 and write timer value
948 devpriv->b_TimerSelectMode =
950 b_TimerSelectMode & 0x0F) |
951 APCI3120_TIMER_2_MODE_0;
952 outb(devpriv->b_TimerSelectMode,
953 dev->iobase + APCI3120_TIMER_CRT1);
957 b_DigitalOutputRegister) & 0xF0) |
958 APCI3120_SELECT_TIMER_2_LOW_WORD;
959 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
960 outw(LOWORD(ui_TimerValue2),
961 dev->iobase + APCI3120_TIMER_VALUE);
965 b_DigitalOutputRegister) & 0xF0) |
966 APCI3120_SELECT_TIMER_2_HIGH_WORD;
967 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
968 outw(HIWORD(ui_TimerValue2),
969 dev->iobase + APCI3120_TIMER_VALUE);
971 //(2) Reset FC_TIMER BIT Clearing timer status register
972 inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
973 // enable timer counter and disable watch dog
974 devpriv->b_ModeSelectRegister =
976 b_ModeSelectRegister |
977 APCI3120_ENABLE_TIMER_COUNTER) &
978 APCI3120_DISABLE_WATCHDOG;
979 // select EOS clock input for timer 2
980 devpriv->b_ModeSelectRegister =
982 b_ModeSelectRegister |
983 APCI3120_TIMER2_SELECT_EOS;
984 // Enable timer2 interrupt
985 devpriv->b_ModeSelectRegister =
987 b_ModeSelectRegister |
988 APCI3120_ENABLE_TIMER_INT;
989 outb(devpriv->b_ModeSelectRegister,
990 dev->iobase + APCI3120_WRITE_MODE_SELECT);
991 devpriv->b_Timer2Mode = APCI3120_COUNTER;
992 devpriv->b_Timer2Interrupt = APCI3120_ENABLE;
996 //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
997 //inw(dev->iobase+0);// reset EOC bit
998 //END JK 07.05.04: Comparison between WIN32 and Linux driver
999 devpriv->b_InterruptMode = APCI3120_DMA_MODE;
1001 /************************************/
1002 /* Disables the EOC, EOS interrupt */
1003 /************************************/
1004 devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
1005 APCI3120_DISABLE_EOC_INT & APCI3120_DISABLE_EOS_INT;
1007 outb(devpriv->b_ModeSelectRegister,
1008 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1010 dmalen0 = devpriv->ui_DmaBufferSize[0];
1011 dmalen1 = devpriv->ui_DmaBufferSize[1];
1013 if (!devpriv->b_AiContinuous) {
1015 if (dmalen0 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2)) { // must we fill full first buffer?
1017 devpriv->ui_AiNbrofScans *
1018 devpriv->ui_AiScanLength * 2;
1019 } else if (dmalen1 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2 - dmalen0)) // and must we fill full second buffer when first is once filled?
1021 devpriv->ui_AiNbrofScans *
1022 devpriv->ui_AiScanLength * 2 - dmalen0;
1025 if (devpriv->ui_AiFlags & TRIG_WAKE_EOS) {
1026 // don't we want wake up every scan?
1027 if (dmalen0 > (devpriv->ui_AiScanLength * 2)) {
1028 dmalen0 = devpriv->ui_AiScanLength * 2;
1029 if (devpriv->ui_AiScanLength & 1)
1032 if (dmalen1 > (devpriv->ui_AiScanLength * 2)) {
1033 dmalen1 = devpriv->ui_AiScanLength * 2;
1034 if (devpriv->ui_AiScanLength & 1)
1039 } else { // isn't output buff smaller that our DMA buff?
1040 if (dmalen0 > (devpriv->ui_AiDataLength)) {
1041 dmalen0 = devpriv->ui_AiDataLength;
1043 if (dmalen1 > (devpriv->ui_AiDataLength)) {
1044 dmalen1 = devpriv->ui_AiDataLength;
1047 devpriv->ui_DmaBufferUsesize[0] = dmalen0;
1048 devpriv->ui_DmaBufferUsesize[1] = dmalen1;
1052 // Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS register
1054 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1055 outl(ui_Tmp, devpriv->i_IobaseAmcc + AMCC_OP_REG_AGCSTS);
1057 // changed since 16 bit interface for add on
1058 /*********************/
1059 /* ENABLE BUS MASTER */
1060 /*********************/
1061 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1062 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1063 devpriv->i_IobaseAddon + 2);
1065 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1066 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH,
1067 devpriv->i_IobaseAddon + 2);
1070 //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
1071 outw(0x1000, devpriv->i_IobaseAddon + 2);
1072 //END JK 07.05.04: Comparison between WIN32 and Linux driver
1075 // A2P FIFO MANAGEMENT
1076 // A2P fifo reset & transfer control enable
1077 /***********************/
1078 /* A2P FIFO MANAGEMENT */
1079 /***********************/
1080 outl(APCI3120_A2P_FIFO_MANAGEMENT, devpriv->i_IobaseAmcc +
1081 APCI3120_AMCC_OP_MCSR);
1084 //beginning address of dma buf
1085 //The 32 bit address of dma buffer is converted into two 16 bit addresses
1086 // Can done by using _attach and put into into an array
1087 // array used may be for differnet pages
1089 // DMA Start Adress Low
1090 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1091 outw((devpriv->ul_DmaBufferHw[0] & 0xFFFF),
1092 devpriv->i_IobaseAddon + 2);
1094 /*************************/
1095 /* DMA Start Adress High */
1096 /*************************/
1097 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1098 outw((devpriv->ul_DmaBufferHw[0] / 65536),
1099 devpriv->i_IobaseAddon + 2);
1102 // amount of bytes to be transfered set transfer count
1103 // used ADDON MWTC register
1104 //commented testing outl(devpriv->ui_DmaBufferUsesize[0], devpriv->i_IobaseAddon+AMCC_OP_REG_AMWTC);
1106 /**************************/
1107 /* Nbr of acquisition LOW */
1108 /**************************/
1109 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1110 outw((devpriv->ui_DmaBufferUsesize[0] & 0xFFFF),
1111 devpriv->i_IobaseAddon + 2);
1113 /***************************/
1114 /* Nbr of acquisition HIGH */
1115 /***************************/
1116 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1117 outw((devpriv->ui_DmaBufferUsesize[0] / 65536),
1118 devpriv->i_IobaseAddon + 2);
1121 // To configure A2P FIFO
1122 // testing outl( FIFO_ADVANCE_ON_BYTE_2,devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR);
1124 /******************/
1125 /* A2P FIFO RESET */
1126 /******************/
1128 //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
1129 outl(0x04000000UL, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
1130 //END JK 07.05.04: Comparison between WIN32 and Linux driver
1133 //ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1134 // AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1135 //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
1136 //outw(3,devpriv->i_IobaseAddon + 4);
1137 //END JK 07.05.04: Comparison between WIN32 and Linux driver
1140 //initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI)
1141 /***************************************************/
1142 /* A2P FIFO CONFIGURATE, END OF DMA INTERRUPT INIT */
1143 /***************************************************/
1144 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1145 APCI3120_ENABLE_WRITE_TC_INT),
1146 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1148 //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
1149 /******************************************/
1150 /* ENABLE A2P FIFO WRITE AND ENABLE AMWEN */
1151 /******************************************/
1152 outw(3, devpriv->i_IobaseAddon + 4);
1153 //END JK 07.05.04: Comparison between WIN32 and Linux driver
1155 /******************/
1156 /* A2P FIFO RESET */
1157 /******************/
1158 //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
1160 devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_MCSR);
1161 //END JK 07.05.04: Comparison between WIN32 and Linux driver
1164 if ((devpriv->us_UseDma == APCI3120_DISABLE)
1165 && !devpriv->b_AiContinuous) {
1166 // set gate 2 to start conversion
1167 devpriv->us_OutputRegister =
1168 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER2;
1169 outw(devpriv->us_OutputRegister,
1170 dev->iobase + APCI3120_WR_ADDRESS);
1175 // set gate 0 to start conversion
1176 devpriv->us_OutputRegister =
1177 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
1178 outw(devpriv->us_OutputRegister,
1179 dev->iobase + APCI3120_WR_ADDRESS);
1182 // set gate 0 and gate 1
1183 devpriv->us_OutputRegister =
1184 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER1;
1185 devpriv->us_OutputRegister =
1186 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
1187 outw(devpriv->us_OutputRegister,
1188 dev->iobase + APCI3120_WR_ADDRESS);
1198 +----------------------------------------------------------------------------+
1199 | INTERNAL FUNCTIONS |
1200 +----------------------------------------------------------------------------+
1204 +----------------------------------------------------------------------------+
1205 | Function name : int i_APCI3120_Reset(comedi_device *dev) |
1208 +----------------------------------------------------------------------------+
1209 | Task : Hardware reset function |
1211 +----------------------------------------------------------------------------+
1212 | Input Parameters : comedi_device *dev |
1215 +----------------------------------------------------------------------------+
1218 +----------------------------------------------------------------------------+
1221 int i_APCI3120_Reset(comedi_device * dev)
1224 unsigned short us_TmpValue;
1226 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1227 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1228 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1229 devpriv->ui_EocEosConversionTime = 0; // set eoc eos conv time to 0
1230 devpriv->b_OutputMemoryStatus = 0;
1232 // variables used in timer subdevice
1233 devpriv->b_Timer2Mode = 0;
1234 devpriv->b_Timer2Interrupt = 0;
1235 devpriv->b_ExttrigEnable = 0; // Disable ext trigger
1237 /* Disable all interrupts, watchdog for the anolog output */
1238 devpriv->b_ModeSelectRegister = 0;
1239 outb(devpriv->b_ModeSelectRegister,
1240 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1242 // Disables all counters, ext trigger and clears PA, PR
1243 devpriv->us_OutputRegister = 0;
1244 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1246 //Code to set the all anolog o/p channel to 0v
1247 //8191 is decimal value for zero(0 v)volt in bipolar mode(default)
1248 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_1, dev->iobase + APCI3120_ANALOG_OUTPUT_1); //channel 1
1249 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_2, dev->iobase + APCI3120_ANALOG_OUTPUT_1); //channel 2
1250 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_3, dev->iobase + APCI3120_ANALOG_OUTPUT_1); //channel 3
1251 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_4, dev->iobase + APCI3120_ANALOG_OUTPUT_1); //channel 4
1253 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_5, dev->iobase + APCI3120_ANALOG_OUTPUT_2); //channel 5
1254 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_6, dev->iobase + APCI3120_ANALOG_OUTPUT_2); //channel 6
1255 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_7, dev->iobase + APCI3120_ANALOG_OUTPUT_2); //channel 7
1256 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_8, dev->iobase + APCI3120_ANALOG_OUTPUT_2); //channel 8
1258 // Reset digital output to L0W
1260 //ES05 outb(0x0,dev->iobase+APCI3120_DIGITAL_OUTPUT);
1263 inw(dev->iobase + 0); //make a dummy read
1264 inb(dev->iobase + APCI3120_RESET_FIFO); // flush FIFO
1265 inw(dev->iobase + APCI3120_RD_STATUS); // flush A/D status register
1267 //code to reset the RAM sequence
1268 for (i = 0; i < 16; i++) {
1269 us_TmpValue = i << 8; //select the location
1270 outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
1276 +----------------------------------------------------------------------------+
1277 | Function name : int i_APCI3120_SetupChannelList(comedi_device * dev, |
1278 | comedi_subdevice * s, int n_chan,unsigned int *chanlist|
1281 +----------------------------------------------------------------------------+
1282 | Task :This function will first check channel list is ok or not|
1283 |and then initialize the sequence RAM with the polarity, Gain,Channel number |
1284 |If the last argument of function "check"is 1 then it only checks the channel|
1285 |list is ok or not. |
1287 +----------------------------------------------------------------------------+
1288 | Input Parameters : comedi_device * dev |
1289 | comedi_subdevice * s |
1291 unsigned int *chanlist
1293 +----------------------------------------------------------------------------+
1296 +----------------------------------------------------------------------------+
1299 int i_APCI3120_SetupChannelList(comedi_device * dev, comedi_subdevice * s,
1300 int n_chan, unsigned int *chanlist, char check)
1302 unsigned int i; //, differencial=0, bipolar=0;
1304 unsigned short us_TmpValue;
1306 /* correct channel and range number check itself comedi/range.c */
1309 comedi_error(dev, "range/channel list is empty!");
1312 // All is ok, so we can setup channel/range list
1316 //Code to set the PA and PR...Here it set PA to 0..
1317 devpriv->us_OutputRegister =
1318 devpriv->us_OutputRegister & APCI3120_CLEAR_PA_PR;
1319 devpriv->us_OutputRegister = ((n_chan - 1) & 0xf) << 8;
1320 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1322 for (i = 0; i < n_chan; i++) {
1323 // store range list to card
1324 us_TmpValue = CR_CHAN(chanlist[i]); // get channel number;
1326 if (CR_RANGE(chanlist[i]) < APCI3120_BIPOLAR_RANGES) {
1327 us_TmpValue &= ((~APCI3120_UNIPOLAR) & 0xff); // set bipolar
1329 us_TmpValue |= APCI3120_UNIPOLAR; // enable unipolar......
1332 gain = CR_RANGE(chanlist[i]); // get gain number
1333 us_TmpValue |= ((gain & 0x03) << 4); //<<4 for G0 and G1 bit in RAM
1334 us_TmpValue |= i << 8; //To select the RAM LOCATION....
1335 outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
1337 printk("\n Gain = %i",
1338 (((unsigned char)CR_RANGE(chanlist[i]) & 0x03) << 2));
1339 printk("\n Channel = %i", CR_CHAN(chanlist[i]));
1340 printk("\n Polarity = %i", us_TmpValue & APCI3120_UNIPOLAR);
1342 return 1; // we can serve this with scan logic
1346 +----------------------------------------------------------------------------+
1347 | Function name : int i_APCI3120_ExttrigEnable(comedi_device * dev) |
1350 +----------------------------------------------------------------------------+
1351 | Task : Enable the external trigger |
1353 +----------------------------------------------------------------------------+
1354 | Input Parameters : comedi_device * dev |
1357 +----------------------------------------------------------------------------+
1358 | Return Value : 0 |
1360 +----------------------------------------------------------------------------+
1363 int i_APCI3120_ExttrigEnable(comedi_device * dev)
1366 devpriv->us_OutputRegister |= APCI3120_ENABLE_EXT_TRIGGER;
1367 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1372 +----------------------------------------------------------------------------+
1373 | Function name : int i_APCI3120_ExttrigDisable(comedi_device * dev) |
1375 +----------------------------------------------------------------------------+
1376 | Task : Disables the external trigger |
1378 +----------------------------------------------------------------------------+
1379 | Input Parameters : comedi_device * dev |
1382 +----------------------------------------------------------------------------+
1383 | Return Value : 0 |
1385 +----------------------------------------------------------------------------+
1388 int i_APCI3120_ExttrigDisable(comedi_device * dev)
1390 devpriv->us_OutputRegister &= ~APCI3120_ENABLE_EXT_TRIGGER;
1391 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1396 +----------------------------------------------------------------------------+
1397 | INTERRUPT FUNCTIONS |
1398 +----------------------------------------------------------------------------+
1402 +----------------------------------------------------------------------------+
1403 | Function name : void v_APCI3120_Interrupt(int irq, void *d) |
1406 +----------------------------------------------------------------------------+
1407 | Task :Interrupt handler for APCI3120 |
1408 | When interrupt occurs this gets called. |
1409 | First it finds which interrupt has been generated and |
1410 | handles corresponding interrupt |
1412 +----------------------------------------------------------------------------+
1413 | Input Parameters : int irq |
1416 +----------------------------------------------------------------------------+
1417 | Return Value : void |
1419 +----------------------------------------------------------------------------+
1422 void v_APCI3120_Interrupt(int irq, void *d)
1424 comedi_device *dev = d;
1427 unsigned int int_amcc, ui_Check, i;
1431 comedi_subdevice *s = dev->subdevices + 0;
1434 int_daq = inw(dev->iobase + APCI3120_RD_STATUS) & 0xf000; // get IRQ reasons
1435 int_amcc = inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); // get AMCC INT register
1437 if ((!int_daq) && (!(int_amcc & ANY_S593X_INT))) {
1438 comedi_error(dev, "IRQ from unknow source");
1442 outl(int_amcc | 0x00ff0000, devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); // shutdown IRQ reasons in AMCC
1444 int_daq = (int_daq >> 12) & 0xF;
1446 if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) {
1447 //Disable ext trigger
1448 i_APCI3120_ExttrigDisable(dev);
1449 devpriv->b_ExttrigEnable = APCI3120_DISABLE;
1451 //clear the timer 2 interrupt
1452 inb(devpriv->i_IobaseAmcc + APCI3120_TIMER_STATUS_REGISTER);
1454 if (int_amcc & MASTER_ABORT_INT)
1455 comedi_error(dev, "AMCC IRQ - MASTER DMA ABORT!");
1456 if (int_amcc & TARGET_ABORT_INT)
1457 comedi_error(dev, "AMCC IRQ - TARGET DMA ABORT!");
1459 // Ckeck if EOC interrupt
1460 if (((int_daq & 0x8) == 0)
1461 && (devpriv->b_InterruptMode == APCI3120_EOC_MODE)) {
1462 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
1464 // Read the AI Value
1466 devpriv->ui_AiReadData[0] =
1467 (UINT) inw(devpriv->iobase + 0);
1468 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1469 send_sig(SIGIO, devpriv->tsk_Current, 0); // send signal to the sample
1471 //Disable EOC Interrupt
1472 devpriv->b_ModeSelectRegister =
1474 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT;
1475 outb(devpriv->b_ModeSelectRegister,
1476 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
1481 // Check If EOS interrupt
1482 if ((int_daq & 0x2) && (devpriv->b_InterruptMode == APCI3120_EOS_MODE)) {
1484 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) // enable this in without DMA ???
1487 if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
1489 i_APCI3120_InterruptHandleEos(dev);
1490 devpriv->ui_AiActualScan++;
1491 devpriv->b_ModeSelectRegister =
1493 b_ModeSelectRegister |
1494 APCI3120_ENABLE_EOS_INT;
1495 outb(devpriv->b_ModeSelectRegister,
1497 APCI3120_WRITE_MODE_SELECT);
1500 for (i = 0; i < devpriv->ui_AiNbrofChannels;
1502 us_TmpValue = inw(devpriv->iobase + 0);
1503 devpriv->ui_AiReadData[i] =
1506 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1507 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1509 send_sig(SIGIO, devpriv->tsk_Current, 0); // send signal to the sample
1514 devpriv->b_ModeSelectRegister =
1516 b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
1517 outb(devpriv->b_ModeSelectRegister,
1518 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1519 devpriv->b_EocEosInterrupt = APCI3120_DISABLE; //Default settings
1520 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1525 if (int_daq & 0x1) {
1527 switch (devpriv->b_Timer2Mode) {
1528 case APCI3120_COUNTER:
1530 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1531 devpriv->b_ModeSelectRegister =
1533 b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
1534 outb(devpriv->b_ModeSelectRegister,
1535 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1538 devpriv->us_OutputRegister =
1540 us_OutputRegister & APCI3120_DISABLE_ALL_TIMER;
1541 outw(devpriv->us_OutputRegister,
1542 dev->iobase + APCI3120_WR_ADDRESS);
1544 //stop timer 0 and timer 1
1545 i_APCI3120_StopCyclicAcquisition(dev, s);
1546 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1548 //UPDATE-0.7.57->0.7.68comedi_done(dev,s);
1549 s->async->events |= COMEDI_CB_EOA;
1550 comedi_event(dev, s);
1554 case APCI3120_TIMER:
1556 //Send a signal to from kernel to user space
1557 send_sig(SIGIO, devpriv->tsk_Current, 0);
1560 case APCI3120_WATCHDOG:
1562 //Send a signal to from kernel to user space
1563 send_sig(SIGIO, devpriv->tsk_Current, 0);
1568 // disable Timer Interrupt
1570 devpriv->b_ModeSelectRegister =
1572 b_ModeSelectRegister &
1573 APCI3120_DISABLE_TIMER_INT;
1575 outb(devpriv->b_ModeSelectRegister,
1576 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1580 b_DummyRead = inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1584 if ((int_daq & 0x4) && (devpriv->b_InterruptMode == APCI3120_DMA_MODE)) {
1585 if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
1587 /****************************/
1588 /* Clear Timer Write TC INT */
1589 /****************************/
1591 outl(APCI3120_CLEAR_WRITE_TC_INT,
1592 devpriv->i_IobaseAmcc +
1593 APCI3120_AMCC_OP_REG_INTCSR);
1595 /************************************/
1596 /* Clears the timer status register */
1597 /************************************/
1598 inw(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1599 v_APCI3120_InterruptDma(irq, d); // do some data transfer
1601 /* Stops the Timer */
1603 us_OutputRegister & APCI3120_DISABLE_TIMER0 &
1604 APCI3120_DISABLE_TIMER1,
1605 dev->iobase + APCI3120_WR_ADDRESS);
1614 +----------------------------------------------------------------------------+
1615 | Function name :int i_APCI3120_InterruptHandleEos(comedi_device *dev) |
1618 +----------------------------------------------------------------------------+
1619 | Task : This function handles EOS interrupt. |
1620 | This function copies the acquired data(from FIFO) |
1621 | to Comedi buffer. |
1623 +----------------------------------------------------------------------------+
1624 | Input Parameters : comedi_device *dev |
1627 +----------------------------------------------------------------------------+
1628 | Return Value : 0 |
1630 +----------------------------------------------------------------------------+
1633 /*int i_APCI3120_InterruptHandleEos(comedi_device *dev)
1637 comedi_subdevice *s=dev->subdevices+0;
1638 comedi_async *async = s->async;
1639 data=async->data+async->buf_int_ptr;//new samples added from here onwards
1640 n_chan=devpriv->ui_AiNbrofChannels;
1642 for(i=0;i<n_chan;i++)
1644 data[i]=inw(dev->iobase+0);
1646 async->buf_int_count+=n_chan*sizeof(sampl_t);
1647 async->buf_int_ptr+=n_chan*sizeof(sampl_t);
1649 if (s->async->buf_int_ptr>=s->async->data_len) // for buffer rool over
1651 *//* buffer rollover */
1652 /* s->async->buf_int_ptr=0;
1653 comedi_eobuf(dev,s);
1657 int i_APCI3120_InterruptHandleEos(comedi_device * dev)
1660 comedi_subdevice *s = dev->subdevices + 0;
1663 n_chan = devpriv->ui_AiNbrofChannels;
1665 s->async->events = 0;
1667 for (i = 0; i < n_chan; i++)
1668 err &= comedi_buf_put(s->async, inw(dev->iobase + 0));
1670 s->async->events |= COMEDI_CB_EOS;
1673 s->async->events |= COMEDI_CB_OVERFLOW;
1675 comedi_event(dev, s);
1681 +----------------------------------------------------------------------------+
1682 | Function name : void v_APCI3120_InterruptDma(int irq, void *d) |
1684 +----------------------------------------------------------------------------+
1685 | Task : This is a handler for the DMA interrupt |
1686 | This function copies the data to Comedi Buffer. |
1687 | For continuous DMA it reinitializes the DMA operation. |
1688 | For single mode DMA it stop the acquisition. |
1690 +----------------------------------------------------------------------------+
1691 | Input Parameters : int irq, void *d |
1693 +----------------------------------------------------------------------------+
1694 | Return Value : void |
1696 +----------------------------------------------------------------------------+
1699 void v_APCI3120_InterruptDma(int irq, void *d)
1701 comedi_device *dev = d;
1702 comedi_subdevice *s = dev->subdevices + 0;
1703 unsigned int next_dma_buf, samplesinbuf;
1704 unsigned long low_word, high_word, var;
1708 devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer] -
1709 inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_MWTC);
1712 devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer]) {
1713 comedi_error(dev, "Interrupted DMA transfer!");
1715 if (samplesinbuf & 1) {
1716 comedi_error(dev, "Odd count of bytes in DMA ring!");
1717 i_APCI3120_StopCyclicAcquisition(dev, s);
1718 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1722 samplesinbuf = samplesinbuf >> 1; // number of received samples
1723 if (devpriv->b_DmaDoubleBuffer) {
1724 // switch DMA buffers if is used double buffering
1725 next_dma_buf = 1 - devpriv->ui_DmaActualBuffer;
1727 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1728 outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
1730 // changed since 16 bit interface for add on
1731 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1732 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1733 devpriv->i_IobaseAddon + 2);
1734 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1735 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); // 0x1000 is out putted in windows driver
1737 var = devpriv->ul_DmaBufferHw[next_dma_buf];
1738 low_word = var & 0xffff;
1739 var = devpriv->ul_DmaBufferHw[next_dma_buf];
1740 high_word = var / 65536;
1742 /* DMA Start Adress Low */
1743 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1744 outw(low_word, devpriv->i_IobaseAddon + 2);
1746 /* DMA Start Adress High */
1747 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1748 outw(high_word, devpriv->i_IobaseAddon + 2);
1750 var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
1751 low_word = var & 0xffff;
1752 var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
1753 high_word = var / 65536;
1755 /* Nbr of acquisition LOW */
1756 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1757 outw(low_word, devpriv->i_IobaseAddon + 2);
1759 /* Nbr of acquisition HIGH */
1760 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1761 outw(high_word, devpriv->i_IobaseAddon + 2);
1763 // To configure A2P FIFO
1764 // ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1765 // AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1766 outw(3, devpriv->i_IobaseAddon + 4);
1767 //initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI)
1768 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1769 APCI3120_ENABLE_WRITE_TC_INT),
1770 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1773 /*UPDATE-0.7.57->0.7.68
1774 ptr=(sampl_t *)devpriv->ul_DmaBufferVirtual[devpriv->ui_DmaActualBuffer];
1777 // if there is not enough space left in the buffer to copy all data contained in the DMABufferVirtual
1778 if(s->async->buf_int_ptr+samplesinbuf*sizeof(sampl_t)>=devpriv->ui_AiDataLength)
1780 m=(devpriv->ui_AiDataLength-s->async->buf_int_ptr)/sizeof(sampl_t);
1781 v_APCI3120_InterruptDmaMoveBlock16bit(dev,s,(void *)ptr,((void *)(devpriv->AiData))+s->async->buf_int_ptr,m);
1782 s->async->buf_int_count+=m*sizeof(sampl_t);
1783 ptr+=m*sizeof(sampl_t);
1785 s->async->buf_int_ptr=0;
1786 comedi_eobuf(dev,s);
1791 v_APCI3120_InterruptDmaMoveBlock16bit(dev,s,(void *)ptr,((void *)(devpriv->AiData))+s->async->buf_int_ptr,samplesinbuf);
1793 s->async->buf_int_count+=samplesinbuf*sizeof(sampl_t);
1794 s->async->buf_int_ptr+=samplesinbuf*sizeof(sampl_t);
1795 if (!(devpriv->ui_AiFlags & TRIG_WAKE_EOS))
1797 comedi_bufcheck(dev,s);
1800 if (!devpriv->b_AiContinuous)
1801 if ( devpriv->ui_AiActualScan>=devpriv->ui_AiNbrofScans )
1804 i_APCI3120_StopCyclicAcquisition(dev,s);
1805 devpriv->b_AiCyclicAcquisition=APCI3120_DISABLE;
1806 //DPRINTK("\n Single DMA completed..\n");
1812 v_APCI3120_InterruptDmaMoveBlock16bit(dev, s,
1813 devpriv->ul_DmaBufferVirtual[devpriv->
1814 ui_DmaActualBuffer], samplesinbuf);
1816 if (!(devpriv->ui_AiFlags & TRIG_WAKE_EOS)) {
1817 s->async->events |= COMEDI_CB_EOS;
1818 comedi_event(dev, s);
1821 if (!devpriv->b_AiContinuous)
1822 if (devpriv->ui_AiActualScan >= devpriv->ui_AiNbrofScans) {
1824 i_APCI3120_StopCyclicAcquisition(dev, s);
1825 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1826 s->async->events |= COMEDI_CB_EOA;
1827 comedi_event(dev, s);
1831 if (devpriv->b_DmaDoubleBuffer) { // switch dma buffers
1832 devpriv->ui_DmaActualBuffer = 1 - devpriv->ui_DmaActualBuffer;
1834 // restart DMA if is not used double buffering
1835 //ADDED REINITIALISE THE DMA
1836 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1837 outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
1839 // changed since 16 bit interface for add on
1840 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1841 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1842 devpriv->i_IobaseAddon + 2);
1843 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1844 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); //
1845 // A2P FIFO MANAGEMENT
1846 // A2P fifo reset & transfer control enable
1847 outl(APCI3120_A2P_FIFO_MANAGEMENT,
1848 devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
1850 var = devpriv->ul_DmaBufferHw[0];
1851 low_word = var & 0xffff;
1852 var = devpriv->ul_DmaBufferHw[0];
1853 high_word = var / 65536;
1854 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1855 outw(low_word, devpriv->i_IobaseAddon + 2);
1856 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1857 outw(high_word, devpriv->i_IobaseAddon + 2);
1859 var = devpriv->ui_DmaBufferUsesize[0];
1860 low_word = var & 0xffff; //changed
1861 var = devpriv->ui_DmaBufferUsesize[0];
1862 high_word = var / 65536;
1863 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1864 outw(low_word, devpriv->i_IobaseAddon + 2);
1865 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1866 outw(high_word, devpriv->i_IobaseAddon + 2);
1868 // To configure A2P FIFO
1869 //ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1870 // AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1871 outw(3, devpriv->i_IobaseAddon + 4);
1872 //initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI)
1873 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1874 APCI3120_ENABLE_WRITE_TC_INT),
1875 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1880 +----------------------------------------------------------------------------+
1881 | Function name :void v_APCI3120_InterruptDmaMoveBlock16bit(comedi_device|
1882 |*dev,comedi_subdevice *s,sampl_t *dma,sampl_t *data,int n) |
1884 +----------------------------------------------------------------------------+
1885 | Task : This function copies the data from DMA buffer to the |
1888 +----------------------------------------------------------------------------+
1889 | Input Parameters : comedi_device *dev |
1890 | comedi_subdevice *s |
1892 | sampl_t *data,int n |
1893 +----------------------------------------------------------------------------+
1894 | Return Value : void |
1896 +----------------------------------------------------------------------------+
1899 /*void v_APCI3120_InterruptDmaMoveBlock16bit(comedi_device *dev,comedi_subdevice *s,sampl_t *dma,sampl_t *data,int n)
1903 j=s->async->cur_chan;
1904 m=devpriv->ui_AiActualScanPosition;
1910 if(j>=devpriv->ui_AiNbrofChannels)
1914 if(m>=devpriv->ui_AiScanLength)
1917 devpriv->ui_AiActualScan++;
1918 if (devpriv->ui_AiFlags & TRIG_WAKE_EOS)
1919 ;//UPDATE-0.7.57->0.7.68 comedi_eos(dev,s);
1923 devpriv->ui_AiActualScanPosition=m;
1924 s->async->cur_chan=j;
1928 void v_APCI3120_InterruptDmaMoveBlock16bit(comedi_device * dev,
1929 comedi_subdevice * s, sampl_t * dma_buffer, unsigned int num_samples)
1931 devpriv->ui_AiActualScan +=
1932 (s->async->cur_chan + num_samples) / devpriv->ui_AiScanLength;
1933 s->async->cur_chan += num_samples;
1934 s->async->cur_chan %= devpriv->ui_AiScanLength;
1936 cfc_write_array_to_buffer(s, dma_buffer, num_samples * sizeof(sampl_t));
1940 +----------------------------------------------------------------------------+
1942 +----------------------------------------------------------------------------+
1946 +----------------------------------------------------------------------------+
1947 | Function name :int i_APCI3120_InsnConfigTimer(comedi_device *dev, |
1948 | comedi_subdevice *s,comedi_insn *insn,lsampl_t *data) |
1950 +----------------------------------------------------------------------------+
1951 | Task :Configure Timer 2 |
1953 +----------------------------------------------------------------------------+
1954 | Input Parameters : comedi_device *dev |
1955 | comedi_subdevice *s |
1956 | comedi_insn *insn |
1959 | data[0]= TIMER configure as timer |
1960 | = WATCHDOG configure as watchdog |
1961 | data[1] = Timer constant |
1962 | data[2] = Timer2 interrupt (1)enable or(0) disable |
1964 +----------------------------------------------------------------------------+
1967 +----------------------------------------------------------------------------+
1970 int i_APCI3120_InsnConfigTimer(comedi_device * dev, comedi_subdevice * s,
1971 comedi_insn * insn, lsampl_t * data)
1974 UINT ui_Timervalue2;
1979 comedi_error(dev, "config:No timer constant !");
1981 devpriv->b_Timer2Interrupt = (BYTE) data[2]; // save info whether to enable or disable interrupt
1983 ui_Timervalue2 = data[1] / 1000; // convert nano seconds to u seconds
1985 //this_board->i_hwdrv_InsnConfigTimer(dev, ui_Timervalue2,(BYTE)data[0]);
1986 us_TmpValue = (USHORT) inw(devpriv->iobase + APCI3120_RD_STATUS);
1988 //EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001
1989 // and calculate the time value to set in the timer
1990 if ((us_TmpValue & 0x00B0) == 0x00B0
1991 || !strcmp(this_board->pc_DriverName, "apci3001")) {
1992 //Calculate the time value to set in the timer
1993 ui_Timervalue2 = ui_Timervalue2 / 50;
1995 //Calculate the time value to set in the timer
1996 ui_Timervalue2 = ui_Timervalue2 / 70;
1999 //Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0)
2000 devpriv->us_OutputRegister =
2001 devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER2;
2002 outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS);
2004 // Disable TIMER Interrupt
2005 devpriv->b_ModeSelectRegister =
2007 b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT & 0xEF;
2009 // Disable Eoc and Eos Interrupts
2010 devpriv->b_ModeSelectRegister =
2012 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT &
2013 APCI3120_DISABLE_EOS_INT;
2014 outb(devpriv->b_ModeSelectRegister,
2015 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
2016 if (data[0] == APCI3120_TIMER) //initialize timer
2019 //devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister| APCI3120_ENABLE_TIMER_INT ;
2020 //outb(devpriv->b_ModeSelectRegister,devpriv->iobase+APCI3120_WRITE_MODE_SELECT);
2022 //Set the Timer 2 in mode 2(Timer)
2023 devpriv->b_TimerSelectMode =
2025 b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_2;
2026 outb(devpriv->b_TimerSelectMode,
2027 devpriv->iobase + APCI3120_TIMER_CRT1);
2029 //Configure the timer 2 for writing the LOW WORD of timer is Delay value
2030 //You must make a b_tmp variable with DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
2031 //you can set the digital output and configure the timer 2,and if you don't make this, digital output
2032 //are erase (Set to 0)
2036 b_DigitalOutputRegister) & 0xF0) |
2037 APCI3120_SELECT_TIMER_2_LOW_WORD;
2038 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2039 outw(LOWORD(ui_Timervalue2),
2040 devpriv->iobase + APCI3120_TIMER_VALUE);
2044 b_DigitalOutputRegister) & 0xF0) |
2045 APCI3120_SELECT_TIMER_2_HIGH_WORD;
2046 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2047 outw(HIWORD(ui_Timervalue2),
2048 devpriv->iobase + APCI3120_TIMER_VALUE);
2049 // timer2 in Timer mode enabled
2050 devpriv->b_Timer2Mode = APCI3120_TIMER;
2052 } else // Initialize Watch dog
2055 //Set the Timer 2 in mode 5(Watchdog)
2057 devpriv->b_TimerSelectMode =
2059 b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_5;
2060 outb(devpriv->b_TimerSelectMode,
2061 devpriv->iobase + APCI3120_TIMER_CRT1);
2063 //Configure the timer 2 for writing the LOW WORD of timer is Delay value
2064 //You must make a b_tmp variable with DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
2065 //you can set the digital output and configure the timer 2,and if you don't make this, digital output
2066 //are erase (Set to 0)
2070 b_DigitalOutputRegister) & 0xF0) |
2071 APCI3120_SELECT_TIMER_2_LOW_WORD;
2072 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2073 outw(LOWORD(ui_Timervalue2),
2074 devpriv->iobase + APCI3120_TIMER_VALUE);
2078 b_DigitalOutputRegister) & 0xF0) |
2079 APCI3120_SELECT_TIMER_2_HIGH_WORD;
2080 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2082 outw(HIWORD(ui_Timervalue2),
2083 devpriv->iobase + APCI3120_TIMER_VALUE);
2085 devpriv->b_Timer2Mode = APCI3120_WATCHDOG;
2094 +----------------------------------------------------------------------------+
2095 | Function name :int i_APCI3120_InsnWriteTimer(comedi_device *dev, |
2096 | comedi_subdevice *s, comedi_insn *insn,lsampl_t *data) |
2098 +----------------------------------------------------------------------------+
2099 | Task : To start and stop the timer |
2100 +----------------------------------------------------------------------------+
2101 | Input Parameters : comedi_device *dev |
2102 | comedi_subdevice *s |
2103 | comedi_insn *insn |
2106 | data[0] = 1 (start) |
2107 | data[0] = 0 (stop ) |
2108 | data[0] = 2 (write new value) |
2109 | data[1]= new value |
2111 | devpriv->b_Timer2Mode = 0 DISABLE |
2115 +----------------------------------------------------------------------------+
2118 +----------------------------------------------------------------------------+
2121 int i_APCI3120_InsnWriteTimer(comedi_device * dev, comedi_subdevice * s,
2122 comedi_insn * insn, lsampl_t * data)
2125 UINT ui_Timervalue2 = 0;
2129 if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
2130 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
2131 comedi_error(dev, "\nwrite:timer2 not configured ");
2135 if (data[0] == 2) // write new value
2137 if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
2139 "write :timer2 not configured in TIMER MODE");
2144 ui_Timervalue2 = data[1];
2149 //this_board->i_hwdrv_InsnWriteTimer(dev,data[0],ui_Timervalue2);
2152 case APCI3120_START:
2154 // Reset FC_TIMER BIT
2155 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2156 if (devpriv->b_Timer2Mode == APCI3120_TIMER) //start timer
2159 devpriv->b_ModeSelectRegister =
2160 devpriv->b_ModeSelectRegister & 0x0B;
2161 } else //start watch dog
2164 devpriv->b_ModeSelectRegister =
2166 b_ModeSelectRegister & 0x0B) |
2167 APCI3120_ENABLE_WATCHDOG;
2170 //enable disable interrupt
2171 if ((devpriv->b_Timer2Interrupt) == APCI3120_ENABLE) {
2173 devpriv->b_ModeSelectRegister =
2175 b_ModeSelectRegister |
2176 APCI3120_ENABLE_TIMER_INT;
2177 // save the task structure to pass info to user
2178 devpriv->tsk_Current = current;
2181 devpriv->b_ModeSelectRegister =
2183 b_ModeSelectRegister &
2184 APCI3120_DISABLE_TIMER_INT;
2186 outb(devpriv->b_ModeSelectRegister,
2187 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
2189 if (devpriv->b_Timer2Mode == APCI3120_TIMER) //start timer
2191 //For Timer mode is Gate2 must be activated **timer started
2192 devpriv->us_OutputRegister =
2194 us_OutputRegister | APCI3120_ENABLE_TIMER2;
2195 outw(devpriv->us_OutputRegister,
2196 devpriv->iobase + APCI3120_WR_ADDRESS);
2202 if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
2204 devpriv->b_ModeSelectRegister =
2206 b_ModeSelectRegister &
2207 APCI3120_DISABLE_TIMER_COUNTER;
2210 devpriv->b_ModeSelectRegister =
2212 b_ModeSelectRegister &
2213 APCI3120_DISABLE_WATCHDOG;
2215 // Disable timer interrupt
2216 devpriv->b_ModeSelectRegister =
2218 b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT;
2220 // Write above states to register
2221 outb(devpriv->b_ModeSelectRegister,
2222 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
2225 devpriv->us_OutputRegister =
2226 devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER_INT;
2227 outw(devpriv->us_OutputRegister,
2228 devpriv->iobase + APCI3120_WR_ADDRESS);
2230 // Reset FC_TIMER BIT
2231 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2234 //devpriv->b_Timer2Mode=APCI3120_DISABLE;
2238 case 2: //write new value to Timer
2239 if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
2241 "write :timer2 not configured in TIMER MODE");
2244 // ui_Timervalue2=data[1]; // passed as argument
2246 (USHORT) inw(devpriv->iobase + APCI3120_RD_STATUS);
2248 //EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001
2249 // and calculate the time value to set in the timer
2250 if ((us_TmpValue & 0x00B0) == 0x00B0
2251 || !strcmp(this_board->pc_DriverName, "apci3001")) {
2252 //Calculate the time value to set in the timer
2253 ui_Timervalue2 = ui_Timervalue2 / 50;
2255 //Calculate the time value to set in the timer
2256 ui_Timervalue2 = ui_Timervalue2 / 70;
2260 b_DigitalOutputRegister) & 0xF0) |
2261 APCI3120_SELECT_TIMER_2_LOW_WORD;
2262 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2264 outw(LOWORD(ui_Timervalue2),
2265 devpriv->iobase + APCI3120_TIMER_VALUE);
2269 b_DigitalOutputRegister) & 0xF0) |
2270 APCI3120_SELECT_TIMER_2_HIGH_WORD;
2271 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2273 outw(HIWORD(ui_Timervalue2),
2274 devpriv->iobase + APCI3120_TIMER_VALUE);
2278 return -EINVAL; // Not a valid input
2285 +----------------------------------------------------------------------------+
2286 | Function name : int i_APCI3120_InsnReadTimer(comedi_device *dev, |
2287 | comedi_subdevice *s,comedi_insn *insn, lsampl_t *data) |
2290 +----------------------------------------------------------------------------+
2291 | Task : read the Timer value |
2292 +----------------------------------------------------------------------------+
2293 | Input Parameters : comedi_device *dev |
2294 | comedi_subdevice *s |
2295 | comedi_insn *insn |
2298 +----------------------------------------------------------------------------+
2300 | for Timer: data[0]= Timer constant |
2302 | for watchdog: data[0]=0 (still running) |
2303 | data[0]=1 (run down) |
2305 +----------------------------------------------------------------------------+
2307 int i_APCI3120_InsnReadTimer(comedi_device * dev, comedi_subdevice * s,
2308 comedi_insn * insn, lsampl_t * data)
2311 USHORT us_TmpValue, us_TmpValue_2, us_StatusValue;
2313 if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
2314 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
2315 comedi_error(dev, "\nread:timer2 not configured ");
2318 //this_board->i_hwdrv_InsnReadTimer(dev,data);
2319 if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
2321 //Read the LOW WORD of Timer 2 register
2323 b_DigitalOutputRegister) & 0xF0) |
2324 APCI3120_SELECT_TIMER_2_LOW_WORD;
2325 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2327 us_TmpValue = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
2329 //Read the HIGH WORD of Timer 2 register
2331 b_DigitalOutputRegister) & 0xF0) |
2332 APCI3120_SELECT_TIMER_2_HIGH_WORD;
2333 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2335 us_TmpValue_2 = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
2337 // combining both words
2338 data[0] = (UINT) ((us_TmpValue) | ((us_TmpValue_2) << 16));
2340 } else // Read watch dog status
2343 us_StatusValue = inw(devpriv->iobase + APCI3120_RD_STATUS);
2345 ((us_StatusValue & APCI3120_FC_TIMER) >> 12) & 1;
2346 if (us_StatusValue == 1) {
2347 // RESET FC_TIMER BIT
2348 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2350 data[0] = us_StatusValue; // when data[0] = 1 then the watch dog has rundown
2356 +----------------------------------------------------------------------------+
2357 | DIGITAL INPUT SUBDEVICE |
2358 +----------------------------------------------------------------------------+
2362 +----------------------------------------------------------------------------+
2363 | Function name :int i_APCI3120_InsnReadDigitalInput(comedi_device *dev, |
2364 | comedi_subdevice *s, comedi_insn *insn,lsampl_t *data) |
2367 +----------------------------------------------------------------------------+
2368 | Task : Reads the value of the specified Digital input channel|
2370 +----------------------------------------------------------------------------+
2371 | Input Parameters : comedi_device *dev |
2372 | comedi_subdevice *s |
2373 | comedi_insn *insn |
2375 +----------------------------------------------------------------------------+
2378 +----------------------------------------------------------------------------+
2381 int i_APCI3120_InsnReadDigitalInput(comedi_device * dev, comedi_subdevice
2382 * s, comedi_insn * insn, lsampl_t * data)
2384 UINT ui_Chan, ui_TmpValue;
2386 ui_Chan = CR_CHAN(insn->chanspec); // channel specified
2388 //this_board->i_hwdrv_InsnReadDigitalInput(dev,ui_Chan,data);
2389 if (ui_Chan >= 0 && ui_Chan <= 3) {
2390 ui_TmpValue = (UINT) inw(devpriv->iobase + APCI3120_RD_STATUS);
2392 // since only 1 channel reqd to bring it to last bit it is rotated
2393 // 8 +(chan - 1) times then ANDed with 1 for last bit.
2394 *data = (ui_TmpValue >> (ui_Chan + 8)) & 1;
2397 // comedi_error(dev," chan spec wrong");
2398 return -EINVAL; // "sorry channel spec wrong "
2405 +----------------------------------------------------------------------------+
2406 | Function name :int i_APCI3120_InsnBitsDigitalInput(comedi_device *dev, |
2407 |comedi_subdevice *s, comedi_insn *insn,lsampl_t *data) |
2409 +----------------------------------------------------------------------------+
2410 | Task : Reads the value of the Digital input Port i.e.4channels|
2411 | value is returned in data[0] |
2413 +----------------------------------------------------------------------------+
2414 | Input Parameters : comedi_device *dev |
2415 | comedi_subdevice *s |
2416 | comedi_insn *insn |
2418 +----------------------------------------------------------------------------+
2421 +----------------------------------------------------------------------------+
2423 int i_APCI3120_InsnBitsDigitalInput(comedi_device * dev, comedi_subdevice * s,
2424 comedi_insn * insn, lsampl_t * data)
2427 ui_TmpValue = (UINT) inw(devpriv->iobase + APCI3120_RD_STATUS);
2428 /***** state of 4 channels in the 11, 10, 9, 8 bits of status reg
2429 rotated right 8 times to bring them to last four bits
2430 ANDed with oxf for value.
2433 *data = (ui_TmpValue >> 8) & 0xf;
2434 //this_board->i_hwdrv_InsnBitsDigitalInput(dev,data);
2439 +----------------------------------------------------------------------------+
2440 | DIGITAL OUTPUT SUBDEVICE |
2441 +----------------------------------------------------------------------------+
2444 +----------------------------------------------------------------------------+
2445 | Function name :int i_APCI3120_InsnConfigDigitalOutput(comedi_device |
2446 | *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data) |
2448 +----------------------------------------------------------------------------+
2449 | Task :Configure the output memory ON or OFF |
2451 +----------------------------------------------------------------------------+
2452 | Input Parameters :comedi_device *dev |
2453 | comedi_subdevice *s |
2454 | comedi_insn *insn |
2456 +----------------------------------------------------------------------------+
2459 +----------------------------------------------------------------------------+
2462 int i_APCI3120_InsnConfigDigitalOutput(comedi_device * dev,
2463 comedi_subdevice * s, comedi_insn * insn, lsampl_t * data)
2466 if ((data[0] != 0) && (data[0] != 1)) {
2468 "Not a valid Data !!! ,Data should be 1 or 0\n");
2472 devpriv->b_OutputMemoryStatus = APCI3120_ENABLE;
2475 devpriv->b_OutputMemoryStatus = APCI3120_DISABLE;
2476 devpriv->b_DigitalOutputRegister = 0;
2478 if (!devpriv->b_OutputMemoryStatus) {
2481 } //if(!devpriv->b_OutputMemoryStatus )
2487 +----------------------------------------------------------------------------+
2488 | Function name :int i_APCI3120_InsnBitsDigitalOutput(comedi_device *dev, |
2489 | comedi_subdevice *s, comedi_insn *insn,lsampl_t *data) |
2491 +----------------------------------------------------------------------------+
2492 | Task : write diatal output port |
2494 +----------------------------------------------------------------------------+
2495 | Input Parameters : comedi_device *dev |
2496 | comedi_subdevice *s |
2497 | comedi_insn *insn |
2499 data[0] Value to be written
2500 data[1] :1 Set digital o/p ON
2501 data[1] 2 Set digital o/p OFF with memory ON
2502 +----------------------------------------------------------------------------+
2505 +----------------------------------------------------------------------------+
2508 int i_APCI3120_InsnBitsDigitalOutput(comedi_device * dev, comedi_subdevice
2509 * s, comedi_insn * insn, lsampl_t * data)
2511 if ((data[0] > this_board->i_DoMaxdata) || (data[0] < 0)) {
2513 comedi_error(dev, "Data is not valid !!! \n");
2519 data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister;
2526 printk("\nThe parameter passed is in error \n");
2528 } // switch(data[1])
2529 outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
2531 devpriv->b_DigitalOutputRegister = data[0] & 0xF0;
2538 +----------------------------------------------------------------------------+
2539 | Function name :int i_APCI3120_InsnWriteDigitalOutput(comedi_device *dev,|
2540 |comedi_subdevice *s,comedi_insn *insn,lsampl_t *data) |
2542 +----------------------------------------------------------------------------+
2543 | Task : Write digiatl output |
2545 +----------------------------------------------------------------------------+
2546 | Input Parameters : comedi_device *dev |
2547 | comedi_subdevice *s |
2548 | comedi_insn *insn |
2550 data[0] Value to be written
2551 data[1] :1 Set digital o/p ON
2552 data[1] 2 Set digital o/p OFF with memory ON
2553 +----------------------------------------------------------------------------+
2556 +----------------------------------------------------------------------------+
2559 int i_APCI3120_InsnWriteDigitalOutput(comedi_device * dev, comedi_subdevice
2560 * s, comedi_insn * insn, lsampl_t * data)
2565 UINT ui_NoOfChannel = CR_CHAN(insn->chanspec); // get the channel
2567 if ((data[0] != 0) && (data[0] != 1)) {
2569 "Not a valid Data !!! ,Data should be 1 or 0\n");
2572 if ((ui_NoOfChannel > (this_board->i_NbrDoChannel - 1))
2573 || (ui_NoOfChannel < 0)) {
2575 "This board doesn't have specified channel !!! \n");
2581 data[0] = (data[0] << ui_NoOfChannel);
2582 //ES05 data[0]=(data[0]<<4)|ui_Temp;
2583 data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister;
2587 data[0] = ~data[0] & 0x1;
2589 ui_Temp1 = ui_Temp1 << ui_NoOfChannel;
2590 ui_Temp1 = ui_Temp1 << 4;
2591 //ES05 ui_Temp=ui_Temp|ui_Temp1;
2592 devpriv->b_DigitalOutputRegister =
2593 devpriv->b_DigitalOutputRegister | ui_Temp1;
2595 data[0] = (data[0] << ui_NoOfChannel) ^ 0xf;
2596 data[0] = data[0] << 4;
2597 //ES05 data[0]=data[0]& ui_Temp;
2598 data[0] = data[0] & devpriv->b_DigitalOutputRegister;
2601 printk("\nThe parameter passed is in error \n");
2603 } // switch(data[1])
2604 outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
2606 //ES05 ui_Temp=data[0] & 0xf0;
2607 devpriv->b_DigitalOutputRegister = data[0] & 0xf0;
2613 +----------------------------------------------------------------------------+
2614 | ANALOG OUTPUT SUBDEVICE |
2615 +----------------------------------------------------------------------------+
2619 +----------------------------------------------------------------------------+
2620 | Function name :int i_APCI3120_InsnWriteAnalogOutput(comedi_device *dev,|
2621 |comedi_subdevice *s, comedi_insn *insn,lsampl_t *data) |
2623 +----------------------------------------------------------------------------+
2624 | Task : Write analog output |
2626 +----------------------------------------------------------------------------+
2627 | Input Parameters : comedi_device *dev |
2628 | comedi_subdevice *s |
2629 | comedi_insn *insn |
2631 +----------------------------------------------------------------------------+
2634 +----------------------------------------------------------------------------+
2637 int i_APCI3120_InsnWriteAnalogOutput(comedi_device * dev, comedi_subdevice
2638 * s, comedi_insn * insn, lsampl_t * data)
2640 UINT ui_Range, ui_Channel;
2643 ui_Range = CR_RANGE(insn->chanspec);
2644 ui_Channel = CR_CHAN(insn->chanspec);
2646 //this_board->i_hwdrv_InsnWriteAnalogOutput(dev, ui_Range, ui_Channel,data[0]);
2647 if (ui_Range) // if 1 then unipolar
2652 ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
2653 13) | (data[0] + 8191));
2656 ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
2659 } else // if 0 then bipolar
2662 ((((ui_Channel & 0x03) << 14) & 0xC000) | (0 << 13) |
2667 //out put n values at the given channel.
2668 // rt_printk("\nwaiting for DA_READY BIT");
2669 do //Waiting of DA_READY BIT
2672 ((USHORT) inw(devpriv->iobase +
2673 APCI3120_RD_STATUS)) & 0x0001;
2674 } while (us_TmpValue != 0x0001);
2676 if (ui_Channel <= 3)
2677 // for channel 0-3 out at the register 1 (wrDac1-8)
2678 // data[i] typecasted to ushort since word write is to be done
2679 outw((USHORT) data[0],
2680 devpriv->iobase + APCI3120_ANALOG_OUTPUT_1);
2682 // for channel 4-7 out at the register 2 (wrDac5-8)
2683 //data[i] typecasted to ushort since word write is to be done
2684 outw((USHORT) data[0],
2685 devpriv->iobase + APCI3120_ANALOG_OUTPUT_2);