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 unsigned int ui_Temp = 0;
50 /* FUNCTION DEFINITIONS */
53 +----------------------------------------------------------------------------+
54 | ANALOG INPUT SUBDEVICE |
55 +----------------------------------------------------------------------------+
59 +----------------------------------------------------------------------------+
60 | Function name :int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev,|
61 | struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
63 +----------------------------------------------------------------------------+
64 | Task : Calls card specific function |
66 +----------------------------------------------------------------------------+
67 | Input Parameters : struct comedi_device *dev |
68 | struct comedi_subdevice *s |
69 | struct comedi_insn *insn |
70 | unsigned int *data |
71 +----------------------------------------------------------------------------+
74 +----------------------------------------------------------------------------+
77 int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s,
78 struct comedi_insn *insn, unsigned int *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(struct comedi_device *dev, |
128 | struct comedi_subdevice *s,struct comedi_insn *insn, unsigned int *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 : struct comedi_device *dev |
139 | struct comedi_subdevice *s |
140 | struct comedi_insn *insn |
141 | unsigned int *data |
142 +----------------------------------------------------------------------------+
145 +----------------------------------------------------------------------------+
148 int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s,
149 struct comedi_insn *insn, unsigned int *data)
151 unsigned short 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 = (unsigned short) (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 */
179 * Testing if board have the new Quartz and calculate the time value
180 * to set in the timer
184 (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
186 /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */
187 if ((us_TmpValue & 0x00B0) == 0x00B0
188 || !strcmp(this_board->pc_DriverName, "apci3001")) {
189 us_ConvertTiming = (us_ConvertTiming * 2) - 2;
192 ((us_ConvertTiming * 12926) / 10000) - 1;
195 us_TmpValue = (unsigned short) devpriv->b_InterruptMode;
197 switch (us_TmpValue) {
199 case APCI3120_EOC_MODE:
202 * Testing the interrupt flag and set the EOC bit Clears the FIFO
204 inw(devpriv->iobase + APCI3120_RESET_FIFO);
206 /* Initialize the sequence array */
208 /* if (!i_APCI3120_SetupChannelList(dev,s,1,chanlist,0)) return -EINVAL; */
210 if (!i_APCI3120_SetupChannelList(dev, s, 1,
214 /* Initialize Timer 0 mode 4 */
215 devpriv->b_TimerSelectMode =
217 b_TimerSelectMode & 0xFC) |
218 APCI3120_TIMER_0_MODE_4;
219 outb(devpriv->b_TimerSelectMode,
220 devpriv->iobase + APCI3120_TIMER_CRT1);
222 /* Reset the scan bit and Disables the EOS, DMA, EOC interrupt */
223 devpriv->b_ModeSelectRegister =
225 b_ModeSelectRegister & APCI3120_DISABLE_SCAN;
227 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
229 /* Disables the EOS,DMA and enables the EOC interrupt */
230 devpriv->b_ModeSelectRegister =
232 b_ModeSelectRegister &
233 APCI3120_DISABLE_EOS_INT) |
234 APCI3120_ENABLE_EOC_INT;
235 inw(devpriv->iobase);
238 devpriv->b_ModeSelectRegister =
240 b_ModeSelectRegister &
241 APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER;
244 outb(devpriv->b_ModeSelectRegister,
245 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
248 devpriv->us_OutputRegister =
250 us_OutputRegister & APCI3120_CLEAR_PA_PR) |
251 APCI3120_ENABLE_TIMER0;
252 outw(devpriv->us_OutputRegister,
253 devpriv->iobase + APCI3120_WR_ADDRESS);
257 b_DigitalOutputRegister) & 0xF0) |
258 APCI3120_SELECT_TIMER_0_WORD;
259 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
261 /* Set the convertion time */
262 outw(us_ConvertTiming,
263 devpriv->iobase + APCI3120_TIMER_VALUE);
266 (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
268 if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
271 /* Waiting for the end of conversion */
273 inw(devpriv->iobase +
275 } while ((us_TmpValue & APCI3120_EOC) ==
278 /* Read the result in FIFO and put it in insn data pointer */
279 us_TmpValue = inw(devpriv->iobase + 0);
282 inw(devpriv->iobase + APCI3120_RESET_FIFO);
287 case APCI3120_EOS_MODE:
289 inw(devpriv->iobase);
290 /* Clears the FIFO */
291 inw(devpriv->iobase + APCI3120_RESET_FIFO);
292 /* clear PA PR and disable timer 0 */
294 devpriv->us_OutputRegister =
296 us_OutputRegister & APCI3120_CLEAR_PA_PR) |
297 APCI3120_DISABLE_TIMER0;
299 outw(devpriv->us_OutputRegister,
300 devpriv->iobase + APCI3120_WR_ADDRESS);
302 if (!i_APCI3120_SetupChannelList(dev, s,
303 devpriv->ui_AiNbrofChannels,
304 devpriv->ui_AiChannelList, 0))
307 /* Initialize Timer 0 mode 2 */
308 devpriv->b_TimerSelectMode =
310 b_TimerSelectMode & 0xFC) |
311 APCI3120_TIMER_0_MODE_2;
312 outb(devpriv->b_TimerSelectMode,
313 devpriv->iobase + APCI3120_TIMER_CRT1);
317 b_DigitalOutputRegister) & 0xF0) |
318 APCI3120_SELECT_TIMER_0_WORD;
319 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
321 /* Set the convertion time */
322 outw(us_ConvertTiming,
323 devpriv->iobase + APCI3120_TIMER_VALUE);
325 /* Set the scan bit */
326 devpriv->b_ModeSelectRegister =
328 b_ModeSelectRegister | APCI3120_ENABLE_SCAN;
329 outb(devpriv->b_ModeSelectRegister,
330 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
332 /* If Interrupt function is loaded */
333 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
334 /* Disables the EOC,DMA and enables the EOS interrupt */
335 devpriv->b_ModeSelectRegister =
337 b_ModeSelectRegister &
338 APCI3120_DISABLE_EOC_INT) |
339 APCI3120_ENABLE_EOS_INT;
340 inw(devpriv->iobase);
343 devpriv->b_ModeSelectRegister =
345 b_ModeSelectRegister &
346 APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER;
348 outb(devpriv->b_ModeSelectRegister,
349 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
351 inw(devpriv->iobase + APCI3120_RD_STATUS);
355 devpriv->us_OutputRegister =
357 us_OutputRegister | APCI3120_ENABLE_TIMER0;
358 outw(devpriv->us_OutputRegister,
359 devpriv->iobase + APCI3120_WR_ADDRESS);
361 /* Start conversion */
362 outw(0, devpriv->iobase + APCI3120_START_CONVERSION);
364 /* Waiting of end of convertion if interrupt is not installed */
365 if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
366 /* Waiting the end of convertion */
369 inw(devpriv->iobase +
371 } while ((us_TmpValue & APCI3120_EOS) !=
374 for (i = 0; i < devpriv->ui_AiNbrofChannels;
376 /* Read the result in FIFO and write them in shared memory */
377 us_TmpValue = inw(devpriv->iobase);
378 data[i] = (unsigned int) us_TmpValue;
381 devpriv->b_InterruptMode = APCI3120_EOC_MODE; /* Restore defaults. */
386 printk("inputs wrong\n");
389 devpriv->ui_EocEosConversionTime = 0; /* re initializing the variable; */
397 +----------------------------------------------------------------------------+
398 | Function name :int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev,|
399 | struct comedi_subdevice *s)|
401 +----------------------------------------------------------------------------+
402 | Task : Stops Cyclic acquisition |
404 +----------------------------------------------------------------------------+
405 | Input Parameters : struct comedi_device *dev |
406 | struct comedi_subdevice *s |
408 +----------------------------------------------------------------------------+
411 +----------------------------------------------------------------------------+
414 int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev, struct comedi_subdevice *s)
416 /* Disable A2P Fifo write and AMWEN signal */
417 outw(0, devpriv->i_IobaseAddon + 4);
419 /* Disable Bus Master ADD ON */
420 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
421 outw(0, devpriv->i_IobaseAddon + 2);
422 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
423 outw(0, devpriv->i_IobaseAddon + 2);
425 /* Disable BUS Master PCI */
426 outl(0, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
428 /* outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR)&(~AINT_WRITE_COMPL),
429 * devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR); stop amcc irqs */
431 /* outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR)&(~EN_A2P_TRANSFERS),
432 * devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR); stop DMA */
434 /* Disable ext trigger */
435 i_APCI3120_ExttrigDisable(dev);
437 devpriv->us_OutputRegister = 0;
440 us_OutputRegister & APCI3120_DISABLE_TIMER0 &
441 APCI3120_DISABLE_TIMER1, dev->iobase + APCI3120_WR_ADDRESS);
443 outw(APCI3120_DISABLE_ALL_TIMER, dev->iobase + APCI3120_WR_ADDRESS);
445 /* DISABLE_ALL_INTERRUPT */
446 outb(APCI3120_DISABLE_ALL_INTERRUPT,
447 dev->iobase + APCI3120_WRITE_MODE_SELECT);
449 inb(dev->iobase + APCI3120_RESET_FIFO);
450 inw(dev->iobase + APCI3120_RD_STATUS);
451 devpriv->ui_AiActualScan = 0;
452 devpriv->ui_AiActualScanPosition = 0;
453 s->async->cur_chan = 0;
454 devpriv->ui_AiBufferPtr = 0;
455 devpriv->b_AiContinuous = 0;
456 devpriv->ui_DmaActualBuffer = 0;
458 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
459 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
460 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
461 i_APCI3120_Reset(dev);
466 +----------------------------------------------------------------------------+
467 | Function name :int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev|
468 | ,struct comedi_subdevice *s,struct comedi_cmd *cmd) |
470 +----------------------------------------------------------------------------+
471 | Task : Test validity for a command for cyclic anlog input |
474 +----------------------------------------------------------------------------+
475 | Input Parameters : struct comedi_device *dev |
476 | struct comedi_subdevice *s |
477 | struct comedi_cmd *cmd |
478 +----------------------------------------------------------------------------+
481 +----------------------------------------------------------------------------+
484 int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s,
485 struct comedi_cmd *cmd)
488 int tmp; /* divisor1,divisor2; */
490 /* step 1: make sure trigger sources are trivially valid */
492 tmp = cmd->start_src;
493 cmd->start_src &= TRIG_NOW | TRIG_EXT;
494 if (!cmd->start_src || tmp != cmd->start_src)
497 tmp = cmd->scan_begin_src;
498 cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW;
499 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
502 tmp = cmd->convert_src;
503 cmd->convert_src &= TRIG_TIMER;
504 if (!cmd->convert_src || tmp != cmd->convert_src)
507 tmp = cmd->scan_end_src;
508 cmd->scan_end_src &= TRIG_COUNT;
509 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
513 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
514 if (!cmd->stop_src || tmp != cmd->stop_src)
520 /* step 2: make sure trigger sources are unique and mutually compatible */
522 if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) {
526 if (cmd->scan_begin_src != TRIG_TIMER &&
527 cmd->scan_begin_src != TRIG_FOLLOW)
530 if (cmd->convert_src != TRIG_TIMER)
533 if (cmd->scan_end_src != TRIG_COUNT) {
534 cmd->scan_end_src = TRIG_COUNT;
538 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
544 /* step 3: make sure arguments are trivially compatible */
546 if (cmd->start_arg != 0) {
551 if (cmd->scan_begin_src == TRIG_TIMER) /* Test Delay timing */
553 if (cmd->scan_begin_arg < this_board->ui_MinDelaytimeNs) {
554 cmd->scan_begin_arg = this_board->ui_MinDelaytimeNs;
559 if (cmd->convert_src == TRIG_TIMER) /* Test Acquisition timing */
561 if (cmd->scan_begin_src == TRIG_TIMER) {
562 if ((cmd->convert_arg)
563 && (cmd->convert_arg <
564 this_board->ui_MinAcquisitiontimeNs)) {
566 this_board->ui_MinAcquisitiontimeNs;
570 if (cmd->convert_arg <
571 this_board->ui_MinAcquisitiontimeNs) {
573 this_board->ui_MinAcquisitiontimeNs;
580 if (!cmd->chanlist_len) {
581 cmd->chanlist_len = 1;
584 if (cmd->chanlist_len > this_board->i_AiChannelList) {
585 cmd->chanlist_len = this_board->i_AiChannelList;
588 if (cmd->stop_src == TRIG_COUNT) {
589 if (!cmd->stop_arg) {
593 } else { /* TRIG_NONE */
594 if (cmd->stop_arg != 0) {
603 /* step 4: fix up any arguments */
605 if (cmd->convert_src == TRIG_TIMER) {
607 if (cmd->scan_begin_src == TRIG_TIMER &&
608 cmd->scan_begin_arg <
609 cmd->convert_arg * cmd->scan_end_arg) {
610 cmd->scan_begin_arg =
611 cmd->convert_arg * cmd->scan_end_arg;
623 +----------------------------------------------------------------------------+
624 | Function name : int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, |
625 | struct comedi_subdevice *s) |
627 +----------------------------------------------------------------------------+
628 | Task : Does asynchronous acquisition |
629 | Determines the mode 1 or 2. |
631 +----------------------------------------------------------------------------+
632 | Input Parameters : struct comedi_device *dev |
633 | struct comedi_subdevice *s |
635 +----------------------------------------------------------------------------+
638 +----------------------------------------------------------------------------+
641 int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s)
643 struct comedi_cmd *cmd = &s->async->cmd;
645 /* loading private structure with cmd structure inputs */
646 devpriv->ui_AiFlags = cmd->flags;
647 devpriv->ui_AiNbrofChannels = cmd->chanlist_len;
648 devpriv->ui_AiScanLength = cmd->scan_end_arg;
649 devpriv->pui_AiChannelList = cmd->chanlist;
651 /* UPDATE-0.7.57->0.7.68devpriv->AiData=s->async->data; */
652 devpriv->AiData = s->async->prealloc_buf;
653 /* UPDATE-0.7.57->0.7.68devpriv->ui_AiDataLength=s->async->data_len; */
654 devpriv->ui_AiDataLength = s->async->prealloc_bufsz;
656 if (cmd->stop_src == TRIG_COUNT) {
657 devpriv->ui_AiNbrofScans = cmd->stop_arg;
659 devpriv->ui_AiNbrofScans = 0;
662 devpriv->ui_AiTimer0 = 0; /* variables changed to timer0,timer1 */
663 devpriv->ui_AiTimer1 = 0;
664 if ((devpriv->ui_AiNbrofScans == 0) || (devpriv->ui_AiNbrofScans == -1))
665 devpriv->b_AiContinuous = 1; /* user want neverending analog acquisition */
666 /* stopped using cancel */
668 if (cmd->start_src == TRIG_EXT)
669 devpriv->b_ExttrigEnable = APCI3120_ENABLE;
671 devpriv->b_ExttrigEnable = APCI3120_DISABLE;
673 if (cmd->scan_begin_src == TRIG_FOLLOW) {
675 if (cmd->convert_src == TRIG_TIMER) {
678 devpriv->ui_AiTimer0 = cmd->convert_arg; /* timer constant in nano seconds */
679 /* return this_board->i_hwdrv_CommandAnalogInput(1,dev,s); */
680 return i_APCI3120_CyclicAnalogInput(1, dev, s);
684 if ((cmd->scan_begin_src == TRIG_TIMER)
685 && (cmd->convert_src == TRIG_TIMER)) {
687 devpriv->ui_AiTimer1 = cmd->scan_begin_arg;
688 devpriv->ui_AiTimer0 = cmd->convert_arg; /* variable changed timer2 to timer0 */
689 /* return this_board->i_hwdrv_CommandAnalogInput(2,dev,s); */
690 return i_APCI3120_CyclicAnalogInput(2, dev, s);
696 +----------------------------------------------------------------------------+
697 | Function name : int i_APCI3120_CyclicAnalogInput(int mode, |
698 | struct comedi_device * dev,struct comedi_subdevice * s) |
699 +----------------------------------------------------------------------------+
700 | Task : This is used for analog input cyclic acquisition |
701 | Performs the command operations. |
702 | If DMA is configured does DMA initialization |
703 | otherwise does the acquisition with EOS interrupt. |
705 +----------------------------------------------------------------------------+
706 | Input Parameters : |
709 +----------------------------------------------------------------------------+
712 +----------------------------------------------------------------------------+
715 int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device *dev,
716 struct comedi_subdevice *s)
719 unsigned int ui_Tmp, ui_DelayTiming = 0, ui_TimerValue1 = 0, dmalen0 =
720 0, dmalen1 = 0, ui_TimerValue2 =
721 0, ui_TimerValue0, ui_ConvertTiming;
722 unsigned short us_TmpValue;
724 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
725 /* devpriv->b_AiCyclicAcquisition=APCI3120_ENABLE; */
726 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
728 /*******************/
729 /* Resets the FIFO */
730 /*******************/
731 inb(dev->iobase + APCI3120_RESET_FIFO);
733 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
734 /* inw(dev->iobase+APCI3120_RD_STATUS); */
735 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
737 /***************************/
738 /* Acquisition initialized */
739 /***************************/
740 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
741 devpriv->b_AiCyclicAcquisition = APCI3120_ENABLE;
742 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
744 /* clear software registers */
745 devpriv->b_TimerSelectMode = 0;
746 devpriv->us_OutputRegister = 0;
747 devpriv->b_ModeSelectRegister = 0;
748 /* devpriv->b_DigitalOutputRegister=0; */
750 /* COMMENT JK 07.05.04: Followings calls are in i_APCI3120_StartAnalogInputAcquisition */
752 /****************************/
753 /* Clear Timer Write TC int */
754 /****************************/
755 outl(APCI3120_CLEAR_WRITE_TC_INT,
756 devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_REG_INTCSR);
758 /************************************/
759 /* Clears the timer status register */
760 /************************************/
762 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
763 /* inw(dev->iobase+APCI3120_TIMER_STATUS_REGISTER); */
764 /* inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); */
765 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
767 /**************************/
768 /* Disables All Timer */
769 /* Sets PR and PA to 0 */
770 /**************************/
771 devpriv->us_OutputRegister = devpriv->us_OutputRegister &
772 APCI3120_DISABLE_TIMER0 &
773 APCI3120_DISABLE_TIMER1 & APCI3120_CLEAR_PA_PR;
775 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
777 /*******************/
778 /* Resets the FIFO */
779 /*******************/
780 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
781 inb(devpriv->iobase + APCI3120_RESET_FIFO);
782 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
784 devpriv->ui_AiActualScan = 0;
785 devpriv->ui_AiActualScanPosition = 0;
786 s->async->cur_chan = 0;
787 devpriv->ui_AiBufferPtr = 0;
788 devpriv->ui_DmaActualBuffer = 0;
790 /* value for timer2 minus -2 has to be done .....dunno y?? */
791 ui_TimerValue2 = devpriv->ui_AiNbrofScans - 2;
792 ui_ConvertTiming = devpriv->ui_AiTimer0;
795 ui_DelayTiming = devpriv->ui_AiTimer1;
797 /**********************************/
798 /* Initializes the sequence array */
799 /**********************************/
800 if (!i_APCI3120_SetupChannelList(dev, s, devpriv->ui_AiNbrofChannels,
801 devpriv->pui_AiChannelList, 0))
804 us_TmpValue = (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
805 /*** EL241003 : add this section in comment because floats must not be used
806 if((us_TmpValue & 0x00B0)==0x00B0)
808 f_ConvertValue=(((float)ui_ConvertTiming * 0.002) - 2);
809 ui_TimerValue0=(unsigned int)f_ConvertValue;
812 f_DelayValue = (((float)ui_DelayTiming * 0.00002) - 2);
813 ui_TimerValue1 = (unsigned int) f_DelayValue;
818 f_ConvertValue=(((float)ui_ConvertTiming * 0.0012926) - 1);
819 ui_TimerValue0=(unsigned int)f_ConvertValue;
822 f_DelayValue = (((float)ui_DelayTiming * 0.000012926) - 1);
823 ui_TimerValue1 = (unsigned int) f_DelayValue;
826 ***********************************************************************************************/
827 /*** EL241003 Begin : add this section to replace floats calculation by integer calculations **/
828 /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */
829 if ((us_TmpValue & 0x00B0) == 0x00B0
830 || !strcmp(this_board->pc_DriverName, "apci3001")) {
831 ui_TimerValue0 = ui_ConvertTiming * 2 - 2000;
832 ui_TimerValue0 = ui_TimerValue0 / 1000;
835 ui_DelayTiming = ui_DelayTiming / 1000;
836 ui_TimerValue1 = ui_DelayTiming * 2 - 200;
837 ui_TimerValue1 = ui_TimerValue1 / 100;
840 ui_ConvertTiming = ui_ConvertTiming / 1000;
841 ui_TimerValue0 = ui_ConvertTiming * 12926 - 10000;
842 ui_TimerValue0 = ui_TimerValue0 / 10000;
845 ui_DelayTiming = ui_DelayTiming / 1000;
846 ui_TimerValue1 = ui_DelayTiming * 12926 - 1;
847 ui_TimerValue1 = ui_TimerValue1 / 1000000;
850 /*** EL241003 End ******************************************************************************/
852 if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) {
853 i_APCI3120_ExttrigEnable(dev); /* activate EXT trigger */
857 /* init timer0 in mode 2 */
858 devpriv->b_TimerSelectMode =
860 b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
861 outb(devpriv->b_TimerSelectMode,
862 dev->iobase + APCI3120_TIMER_CRT1);
866 b_DigitalOutputRegister) & 0xF0) |
867 APCI3120_SELECT_TIMER_0_WORD;
868 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
869 /* Set the convertion time */
870 outw(((unsigned short) ui_TimerValue0),
871 dev->iobase + APCI3120_TIMER_VALUE);
875 /* init timer1 in mode 2 */
876 devpriv->b_TimerSelectMode =
878 b_TimerSelectMode & 0xF3) | APCI3120_TIMER_1_MODE_2;
879 outb(devpriv->b_TimerSelectMode,
880 dev->iobase + APCI3120_TIMER_CRT1);
884 b_DigitalOutputRegister) & 0xF0) |
885 APCI3120_SELECT_TIMER_1_WORD;
886 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
887 /* Set the convertion time */
888 outw(((unsigned short) ui_TimerValue1),
889 dev->iobase + APCI3120_TIMER_VALUE);
891 /* init timer0 in mode 2 */
892 devpriv->b_TimerSelectMode =
894 b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
895 outb(devpriv->b_TimerSelectMode,
896 dev->iobase + APCI3120_TIMER_CRT1);
900 b_DigitalOutputRegister) & 0xF0) |
901 APCI3120_SELECT_TIMER_0_WORD;
902 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
904 /* Set the convertion time */
905 outw(((unsigned short) ui_TimerValue0),
906 dev->iobase + APCI3120_TIMER_VALUE);
910 /* ##########common for all modes################# */
912 /***********************/
913 /* Clears the SCAN bit */
914 /***********************/
916 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
917 /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister | APCI3120_DISABLE_SCAN; */
919 devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
920 APCI3120_DISABLE_SCAN;
921 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
923 outb(devpriv->b_ModeSelectRegister,
924 dev->iobase + APCI3120_WRITE_MODE_SELECT);
926 /* If DMA is disabled */
927 if (devpriv->us_UseDma == APCI3120_DISABLE) {
928 /* disable EOC and enable EOS */
929 devpriv->b_InterruptMode = APCI3120_EOS_MODE;
930 devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
932 devpriv->b_ModeSelectRegister =
934 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT) |
935 APCI3120_ENABLE_EOS_INT;
936 outb(devpriv->b_ModeSelectRegister,
937 dev->iobase + APCI3120_WRITE_MODE_SELECT);
939 if (!devpriv->b_AiContinuous) {
941 * configure Timer2 For counting EOS Reset gate 2 of Timer 2 to
942 * disable it (Set Bit D14 to 0)
944 devpriv->us_OutputRegister =
946 us_OutputRegister & APCI3120_DISABLE_TIMER2;
947 outw(devpriv->us_OutputRegister,
948 dev->iobase + APCI3120_WR_ADDRESS);
950 /* DISABLE TIMER intERRUPT */
951 devpriv->b_ModeSelectRegister =
953 b_ModeSelectRegister &
954 APCI3120_DISABLE_TIMER_INT & 0xEF;
955 outb(devpriv->b_ModeSelectRegister,
956 dev->iobase + APCI3120_WRITE_MODE_SELECT);
958 /* (1) Init timer 2 in mode 0 and write timer value */
959 devpriv->b_TimerSelectMode =
961 b_TimerSelectMode & 0x0F) |
962 APCI3120_TIMER_2_MODE_0;
963 outb(devpriv->b_TimerSelectMode,
964 dev->iobase + APCI3120_TIMER_CRT1);
966 /* Writing LOW unsigned short */
968 b_DigitalOutputRegister) & 0xF0) |
969 APCI3120_SELECT_TIMER_2_LOW_WORD;
970 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
971 outw(LOWORD(ui_TimerValue2),
972 dev->iobase + APCI3120_TIMER_VALUE);
974 /* Writing HIGH unsigned short */
976 b_DigitalOutputRegister) & 0xF0) |
977 APCI3120_SELECT_TIMER_2_HIGH_WORD;
978 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
979 outw(HIWORD(ui_TimerValue2),
980 dev->iobase + APCI3120_TIMER_VALUE);
982 /* (2) Reset FC_TIMER BIT Clearing timer status register */
983 inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
984 /* enable timer counter and disable watch dog */
985 devpriv->b_ModeSelectRegister =
987 b_ModeSelectRegister |
988 APCI3120_ENABLE_TIMER_COUNTER) &
989 APCI3120_DISABLE_WATCHDOG;
990 /* select EOS clock input for timer 2 */
991 devpriv->b_ModeSelectRegister =
993 b_ModeSelectRegister |
994 APCI3120_TIMER2_SELECT_EOS;
995 /* Enable timer2 interrupt */
996 devpriv->b_ModeSelectRegister =
998 b_ModeSelectRegister |
999 APCI3120_ENABLE_TIMER_INT;
1000 outb(devpriv->b_ModeSelectRegister,
1001 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1002 devpriv->b_Timer2Mode = APCI3120_COUNTER;
1003 devpriv->b_Timer2Interrupt = APCI3120_ENABLE;
1006 /* If DMA Enabled */
1008 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1009 /* inw(dev->iobase+0); reset EOC bit */
1010 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1011 devpriv->b_InterruptMode = APCI3120_DMA_MODE;
1013 /************************************/
1014 /* Disables the EOC, EOS interrupt */
1015 /************************************/
1016 devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
1017 APCI3120_DISABLE_EOC_INT & APCI3120_DISABLE_EOS_INT;
1019 outb(devpriv->b_ModeSelectRegister,
1020 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1022 dmalen0 = devpriv->ui_DmaBufferSize[0];
1023 dmalen1 = devpriv->ui_DmaBufferSize[1];
1025 if (!devpriv->b_AiContinuous) {
1027 if (dmalen0 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2)) { /* must we fill full first buffer? */
1029 devpriv->ui_AiNbrofScans *
1030 devpriv->ui_AiScanLength * 2;
1031 } else if (dmalen1 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2 - dmalen0)) /* and must we fill full second buffer when first is once filled? */
1033 devpriv->ui_AiNbrofScans *
1034 devpriv->ui_AiScanLength * 2 - dmalen0;
1037 if (devpriv->ui_AiFlags & TRIG_WAKE_EOS) {
1038 /* don't we want wake up every scan? */
1039 if (dmalen0 > (devpriv->ui_AiScanLength * 2)) {
1040 dmalen0 = devpriv->ui_AiScanLength * 2;
1041 if (devpriv->ui_AiScanLength & 1)
1044 if (dmalen1 > (devpriv->ui_AiScanLength * 2)) {
1045 dmalen1 = devpriv->ui_AiScanLength * 2;
1046 if (devpriv->ui_AiScanLength & 1)
1051 } else { /* isn't output buff smaller that our DMA buff? */
1052 if (dmalen0 > (devpriv->ui_AiDataLength)) {
1053 dmalen0 = devpriv->ui_AiDataLength;
1055 if (dmalen1 > (devpriv->ui_AiDataLength)) {
1056 dmalen1 = devpriv->ui_AiDataLength;
1059 devpriv->ui_DmaBufferUsesize[0] = dmalen0;
1060 devpriv->ui_DmaBufferUsesize[1] = dmalen1;
1062 /* Initialize DMA */
1065 * Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS
1068 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1069 outl(ui_Tmp, devpriv->i_IobaseAmcc + AMCC_OP_REG_AGCSTS);
1071 /* changed since 16 bit interface for add on */
1072 /*********************/
1073 /* ENABLE BUS MASTER */
1074 /*********************/
1075 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1076 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1077 devpriv->i_IobaseAddon + 2);
1079 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1080 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH,
1081 devpriv->i_IobaseAddon + 2);
1084 * TO VERIFIED BEGIN JK 07.05.04: Comparison between WIN32 and Linux
1087 outw(0x1000, devpriv->i_IobaseAddon + 2);
1088 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1091 /* A2P FIFO MANAGEMENT */
1092 /* A2P fifo reset & transfer control enable */
1094 /***********************/
1095 /* A2P FIFO MANAGEMENT */
1096 /***********************/
1097 outl(APCI3120_A2P_FIFO_MANAGEMENT, devpriv->i_IobaseAmcc +
1098 APCI3120_AMCC_OP_MCSR);
1102 * beginning address of dma buf The 32 bit address of dma buffer
1103 * is converted into two 16 bit addresses Can done by using _attach
1104 * and put into into an array array used may be for differnet pages
1107 /* DMA Start Adress Low */
1108 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1109 outw((devpriv->ul_DmaBufferHw[0] & 0xFFFF),
1110 devpriv->i_IobaseAddon + 2);
1112 /*************************/
1113 /* DMA Start Adress High */
1114 /*************************/
1115 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1116 outw((devpriv->ul_DmaBufferHw[0] / 65536),
1117 devpriv->i_IobaseAddon + 2);
1121 * amount of bytes to be transfered set transfer count used ADDON
1122 * MWTC register commented testing
1123 * outl(devpriv->ui_DmaBufferUsesize[0],
1124 * devpriv->i_IobaseAddon+AMCC_OP_REG_AMWTC);
1127 /**************************/
1128 /* Nbr of acquisition LOW */
1129 /**************************/
1130 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1131 outw((devpriv->ui_DmaBufferUsesize[0] & 0xFFFF),
1132 devpriv->i_IobaseAddon + 2);
1134 /***************************/
1135 /* Nbr of acquisition HIGH */
1136 /***************************/
1137 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1138 outw((devpriv->ui_DmaBufferUsesize[0] / 65536),
1139 devpriv->i_IobaseAddon + 2);
1143 * To configure A2P FIFO testing outl(
1144 * FIFO_ADVANCE_ON_BYTE_2,devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR);
1147 /******************/
1148 /* A2P FIFO RESET */
1149 /******************/
1151 * TO VERIFY BEGIN JK 07.05.04: Comparison between WIN32 and Linux
1154 outl(0x04000000UL, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
1155 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1159 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN AMWEN_ENABLE |
1160 * A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1163 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1164 /* outw(3,devpriv->i_IobaseAddon + 4); */
1165 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1169 * initialise end of dma interrupt AINT_WRITE_COMPL =
1170 * ENABLE_WRITE_TC_INT(ADDI)
1172 /***************************************************/
1173 /* A2P FIFO CONFIGURATE, END OF DMA intERRUPT INIT */
1174 /***************************************************/
1175 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1176 APCI3120_ENABLE_WRITE_TC_INT),
1177 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1179 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1180 /******************************************/
1181 /* ENABLE A2P FIFO WRITE AND ENABLE AMWEN */
1182 /******************************************/
1183 outw(3, devpriv->i_IobaseAddon + 4);
1184 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1186 /******************/
1187 /* A2P FIFO RESET */
1188 /******************/
1189 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1191 devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_MCSR);
1192 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1195 if ((devpriv->us_UseDma == APCI3120_DISABLE)
1196 && !devpriv->b_AiContinuous) {
1197 /* set gate 2 to start conversion */
1198 devpriv->us_OutputRegister =
1199 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER2;
1200 outw(devpriv->us_OutputRegister,
1201 dev->iobase + APCI3120_WR_ADDRESS);
1206 /* set gate 0 to start conversion */
1207 devpriv->us_OutputRegister =
1208 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
1209 outw(devpriv->us_OutputRegister,
1210 dev->iobase + APCI3120_WR_ADDRESS);
1213 /* set gate 0 and gate 1 */
1214 devpriv->us_OutputRegister =
1215 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER1;
1216 devpriv->us_OutputRegister =
1217 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
1218 outw(devpriv->us_OutputRegister,
1219 dev->iobase + APCI3120_WR_ADDRESS);
1229 +----------------------------------------------------------------------------+
1230 | intERNAL FUNCTIONS |
1231 +----------------------------------------------------------------------------+
1235 +----------------------------------------------------------------------------+
1236 | Function name : int i_APCI3120_Reset(struct comedi_device *dev) |
1239 +----------------------------------------------------------------------------+
1240 | Task : Hardware reset function |
1242 +----------------------------------------------------------------------------+
1243 | Input Parameters : struct comedi_device *dev |
1246 +----------------------------------------------------------------------------+
1249 +----------------------------------------------------------------------------+
1252 int i_APCI3120_Reset(struct comedi_device *dev)
1255 unsigned short us_TmpValue;
1257 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1258 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1259 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1260 devpriv->ui_EocEosConversionTime = 0; /* set eoc eos conv time to 0 */
1261 devpriv->b_OutputMemoryStatus = 0;
1263 /* variables used in timer subdevice */
1264 devpriv->b_Timer2Mode = 0;
1265 devpriv->b_Timer2Interrupt = 0;
1266 devpriv->b_ExttrigEnable = 0; /* Disable ext trigger */
1268 /* Disable all interrupts, watchdog for the anolog output */
1269 devpriv->b_ModeSelectRegister = 0;
1270 outb(devpriv->b_ModeSelectRegister,
1271 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1273 /* Disables all counters, ext trigger and clears PA, PR */
1274 devpriv->us_OutputRegister = 0;
1275 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1278 * Code to set the all anolog o/p channel to 0v 8191 is decimal
1279 * value for zero(0 v)volt in bipolar mode(default)
1281 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_1, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 1 */
1282 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_2, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 2 */
1283 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_3, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 3 */
1284 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_4, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 4 */
1286 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_5, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 5 */
1287 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_6, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 6 */
1288 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_7, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 7 */
1289 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_8, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 8 */
1291 /* Reset digital output to L0W */
1293 /* ES05 outb(0x0,dev->iobase+APCI3120_DIGITAL_OUTPUT); */
1296 inw(dev->iobase + 0); /* make a dummy read */
1297 inb(dev->iobase + APCI3120_RESET_FIFO); /* flush FIFO */
1298 inw(dev->iobase + APCI3120_RD_STATUS); /* flush A/D status register */
1300 /* code to reset the RAM sequence */
1301 for (i = 0; i < 16; i++) {
1302 us_TmpValue = i << 8; /* select the location */
1303 outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
1309 +----------------------------------------------------------------------------+
1310 | Function name : int i_APCI3120_SetupChannelList(struct comedi_device * dev, |
1311 | struct comedi_subdevice * s, int n_chan,unsigned int *chanlist|
1314 +----------------------------------------------------------------------------+
1315 | Task :This function will first check channel list is ok or not|
1316 |and then initialize the sequence RAM with the polarity, Gain,Channel number |
1317 |If the last argument of function "check"is 1 then it only checks the channel|
1318 |list is ok or not. |
1320 +----------------------------------------------------------------------------+
1321 | Input Parameters : struct comedi_device * dev |
1322 | struct comedi_subdevice * s |
1324 unsigned int *chanlist
1326 +----------------------------------------------------------------------------+
1329 +----------------------------------------------------------------------------+
1332 int i_APCI3120_SetupChannelList(struct comedi_device *dev, struct comedi_subdevice *s,
1333 int n_chan, unsigned int *chanlist, char check)
1335 unsigned int i; /* , differencial=0, bipolar=0; */
1337 unsigned short us_TmpValue;
1339 /* correct channel and range number check itself comedi/range.c */
1342 comedi_error(dev, "range/channel list is empty!");
1345 /* All is ok, so we can setup channel/range list */
1349 /* Code to set the PA and PR...Here it set PA to 0.. */
1350 devpriv->us_OutputRegister =
1351 devpriv->us_OutputRegister & APCI3120_CLEAR_PA_PR;
1352 devpriv->us_OutputRegister = ((n_chan - 1) & 0xf) << 8;
1353 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1355 for (i = 0; i < n_chan; i++) {
1356 /* store range list to card */
1357 us_TmpValue = CR_CHAN(chanlist[i]); /* get channel number; */
1359 if (CR_RANGE(chanlist[i]) < APCI3120_BIPOLAR_RANGES) {
1360 us_TmpValue &= ((~APCI3120_UNIPOLAR) & 0xff); /* set bipolar */
1362 us_TmpValue |= APCI3120_UNIPOLAR; /* enable unipolar...... */
1365 gain = CR_RANGE(chanlist[i]); /* get gain number */
1366 us_TmpValue |= ((gain & 0x03) << 4); /* <<4 for G0 and G1 bit in RAM */
1367 us_TmpValue |= i << 8; /* To select the RAM LOCATION.... */
1368 outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
1370 printk("\n Gain = %i",
1371 (((unsigned char)CR_RANGE(chanlist[i]) & 0x03) << 2));
1372 printk("\n Channel = %i", CR_CHAN(chanlist[i]));
1373 printk("\n Polarity = %i", us_TmpValue & APCI3120_UNIPOLAR);
1375 return 1; /* we can serve this with scan logic */
1379 +----------------------------------------------------------------------------+
1380 | Function name : int i_APCI3120_ExttrigEnable(struct comedi_device * dev) |
1383 +----------------------------------------------------------------------------+
1384 | Task : Enable the external trigger |
1386 +----------------------------------------------------------------------------+
1387 | Input Parameters : struct comedi_device * dev |
1390 +----------------------------------------------------------------------------+
1391 | Return Value : 0 |
1393 +----------------------------------------------------------------------------+
1396 int i_APCI3120_ExttrigEnable(struct comedi_device *dev)
1399 devpriv->us_OutputRegister |= APCI3120_ENABLE_EXT_TRIGGER;
1400 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1405 +----------------------------------------------------------------------------+
1406 | Function name : int i_APCI3120_ExttrigDisable(struct comedi_device * dev) |
1408 +----------------------------------------------------------------------------+
1409 | Task : Disables the external trigger |
1411 +----------------------------------------------------------------------------+
1412 | Input Parameters : struct comedi_device * dev |
1415 +----------------------------------------------------------------------------+
1416 | Return Value : 0 |
1418 +----------------------------------------------------------------------------+
1421 int i_APCI3120_ExttrigDisable(struct comedi_device *dev)
1423 devpriv->us_OutputRegister &= ~APCI3120_ENABLE_EXT_TRIGGER;
1424 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1429 +----------------------------------------------------------------------------+
1430 | intERRUPT FUNCTIONS |
1431 +----------------------------------------------------------------------------+
1435 +----------------------------------------------------------------------------+
1436 | Function name : void v_APCI3120_Interrupt(int irq, void *d) |
1439 +----------------------------------------------------------------------------+
1440 | Task :Interrupt handler for APCI3120 |
1441 | When interrupt occurs this gets called. |
1442 | First it finds which interrupt has been generated and |
1443 | handles corresponding interrupt |
1445 +----------------------------------------------------------------------------+
1446 | Input Parameters : int irq |
1449 +----------------------------------------------------------------------------+
1450 | Return Value : void |
1452 +----------------------------------------------------------------------------+
1455 void v_APCI3120_Interrupt(int irq, void *d)
1457 struct comedi_device *dev = d;
1458 unsigned short int_daq;
1460 unsigned int int_amcc, ui_Check, i;
1461 unsigned short us_TmpValue;
1462 unsigned char b_DummyRead;
1464 struct comedi_subdevice *s = dev->subdevices + 0;
1467 int_daq = inw(dev->iobase + APCI3120_RD_STATUS) & 0xf000; /* get IRQ reasons */
1468 int_amcc = inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); /* get AMCC int register */
1470 if ((!int_daq) && (!(int_amcc & ANY_S593X_INT))) {
1471 comedi_error(dev, "IRQ from unknow source");
1475 outl(int_amcc | 0x00ff0000, devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); /* shutdown IRQ reasons in AMCC */
1477 int_daq = (int_daq >> 12) & 0xF;
1479 if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) {
1480 /* Disable ext trigger */
1481 i_APCI3120_ExttrigDisable(dev);
1482 devpriv->b_ExttrigEnable = APCI3120_DISABLE;
1484 /* clear the timer 2 interrupt */
1485 inb(devpriv->i_IobaseAmcc + APCI3120_TIMER_STATUS_REGISTER);
1487 if (int_amcc & MASTER_ABORT_INT)
1488 comedi_error(dev, "AMCC IRQ - MASTER DMA ABORT!");
1489 if (int_amcc & TARGET_ABORT_INT)
1490 comedi_error(dev, "AMCC IRQ - TARGET DMA ABORT!");
1492 /* Ckeck if EOC interrupt */
1493 if (((int_daq & 0x8) == 0)
1494 && (devpriv->b_InterruptMode == APCI3120_EOC_MODE)) {
1495 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
1497 /* Read the AI Value */
1499 devpriv->ui_AiReadData[0] =
1500 (unsigned int) inw(devpriv->iobase + 0);
1501 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1502 send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
1504 /* Disable EOC Interrupt */
1505 devpriv->b_ModeSelectRegister =
1507 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT;
1508 outb(devpriv->b_ModeSelectRegister,
1509 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
1514 /* Check If EOS interrupt */
1515 if ((int_daq & 0x2) && (devpriv->b_InterruptMode == APCI3120_EOS_MODE)) {
1517 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) /* enable this in without DMA ??? */
1520 if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
1522 i_APCI3120_InterruptHandleEos(dev);
1523 devpriv->ui_AiActualScan++;
1524 devpriv->b_ModeSelectRegister =
1526 b_ModeSelectRegister |
1527 APCI3120_ENABLE_EOS_INT;
1528 outb(devpriv->b_ModeSelectRegister,
1530 APCI3120_WRITE_MODE_SELECT);
1533 for (i = 0; i < devpriv->ui_AiNbrofChannels;
1535 us_TmpValue = inw(devpriv->iobase + 0);
1536 devpriv->ui_AiReadData[i] =
1537 (unsigned int) us_TmpValue;
1539 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1540 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1542 send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
1547 devpriv->b_ModeSelectRegister =
1549 b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
1550 outb(devpriv->b_ModeSelectRegister,
1551 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1552 devpriv->b_EocEosInterrupt = APCI3120_DISABLE; /* Default settings */
1553 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1557 /* Timer2 interrupt */
1558 if (int_daq & 0x1) {
1560 switch (devpriv->b_Timer2Mode) {
1561 case APCI3120_COUNTER:
1563 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1564 devpriv->b_ModeSelectRegister =
1566 b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
1567 outb(devpriv->b_ModeSelectRegister,
1568 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1571 devpriv->us_OutputRegister =
1573 us_OutputRegister & APCI3120_DISABLE_ALL_TIMER;
1574 outw(devpriv->us_OutputRegister,
1575 dev->iobase + APCI3120_WR_ADDRESS);
1577 /* stop timer 0 and timer 1 */
1578 i_APCI3120_StopCyclicAcquisition(dev, s);
1579 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1581 /* UPDATE-0.7.57->0.7.68comedi_done(dev,s); */
1582 s->async->events |= COMEDI_CB_EOA;
1583 comedi_event(dev, s);
1587 case APCI3120_TIMER:
1589 /* Send a signal to from kernel to user space */
1590 send_sig(SIGIO, devpriv->tsk_Current, 0);
1593 case APCI3120_WATCHDOG:
1595 /* Send a signal to from kernel to user space */
1596 send_sig(SIGIO, devpriv->tsk_Current, 0);
1601 /* disable Timer Interrupt */
1603 devpriv->b_ModeSelectRegister =
1605 b_ModeSelectRegister &
1606 APCI3120_DISABLE_TIMER_INT;
1608 outb(devpriv->b_ModeSelectRegister,
1609 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1613 b_DummyRead = inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1617 if ((int_daq & 0x4) && (devpriv->b_InterruptMode == APCI3120_DMA_MODE)) {
1618 if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
1620 /****************************/
1621 /* Clear Timer Write TC int */
1622 /****************************/
1624 outl(APCI3120_CLEAR_WRITE_TC_INT,
1625 devpriv->i_IobaseAmcc +
1626 APCI3120_AMCC_OP_REG_INTCSR);
1628 /************************************/
1629 /* Clears the timer status register */
1630 /************************************/
1631 inw(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1632 v_APCI3120_InterruptDma(irq, d); /* do some data transfer */
1634 /* Stops the Timer */
1636 us_OutputRegister & APCI3120_DISABLE_TIMER0 &
1637 APCI3120_DISABLE_TIMER1,
1638 dev->iobase + APCI3120_WR_ADDRESS);
1647 +----------------------------------------------------------------------------+
1648 | Function name :int i_APCI3120_InterruptHandleEos(struct comedi_device *dev) |
1651 +----------------------------------------------------------------------------+
1652 | Task : This function handles EOS interrupt. |
1653 | This function copies the acquired data(from FIFO) |
1654 | to Comedi buffer. |
1656 +----------------------------------------------------------------------------+
1657 | Input Parameters : struct comedi_device *dev |
1660 +----------------------------------------------------------------------------+
1661 | Return Value : 0 |
1663 +----------------------------------------------------------------------------+
1667 int i_APCI3120_InterruptHandleEos(struct comedi_device *dev)
1670 struct comedi_subdevice *s = dev->subdevices + 0;
1673 n_chan = devpriv->ui_AiNbrofChannels;
1675 s->async->events = 0;
1677 for (i = 0; i < n_chan; i++)
1678 err &= comedi_buf_put(s->async, inw(dev->iobase + 0));
1680 s->async->events |= COMEDI_CB_EOS;
1683 s->async->events |= COMEDI_CB_OVERFLOW;
1685 comedi_event(dev, s);
1691 +----------------------------------------------------------------------------+
1692 | Function name : void v_APCI3120_InterruptDma(int irq, void *d) |
1694 +----------------------------------------------------------------------------+
1695 | Task : This is a handler for the DMA interrupt |
1696 | This function copies the data to Comedi Buffer. |
1697 | For continuous DMA it reinitializes the DMA operation. |
1698 | For single mode DMA it stop the acquisition. |
1700 +----------------------------------------------------------------------------+
1701 | Input Parameters : int irq, void *d |
1703 +----------------------------------------------------------------------------+
1704 | Return Value : void |
1706 +----------------------------------------------------------------------------+
1709 void v_APCI3120_InterruptDma(int irq, void *d)
1711 struct comedi_device *dev = d;
1712 struct comedi_subdevice *s = dev->subdevices + 0;
1713 unsigned int next_dma_buf, samplesinbuf;
1714 unsigned long low_word, high_word, var;
1716 unsigned int ui_Tmp;
1718 devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer] -
1719 inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_MWTC);
1722 devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer]) {
1723 comedi_error(dev, "Interrupted DMA transfer!");
1725 if (samplesinbuf & 1) {
1726 comedi_error(dev, "Odd count of bytes in DMA ring!");
1727 i_APCI3120_StopCyclicAcquisition(dev, s);
1728 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1732 samplesinbuf = samplesinbuf >> 1; /* number of received samples */
1733 if (devpriv->b_DmaDoubleBuffer) {
1734 /* switch DMA buffers if is used double buffering */
1735 next_dma_buf = 1 - devpriv->ui_DmaActualBuffer;
1737 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1738 outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
1740 /* changed since 16 bit interface for add on */
1741 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1742 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1743 devpriv->i_IobaseAddon + 2);
1744 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1745 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); /* 0x1000 is out putted in windows driver */
1747 var = devpriv->ul_DmaBufferHw[next_dma_buf];
1748 low_word = var & 0xffff;
1749 var = devpriv->ul_DmaBufferHw[next_dma_buf];
1750 high_word = var / 65536;
1752 /* DMA Start Adress Low */
1753 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1754 outw(low_word, devpriv->i_IobaseAddon + 2);
1756 /* DMA Start Adress High */
1757 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1758 outw(high_word, devpriv->i_IobaseAddon + 2);
1760 var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
1761 low_word = var & 0xffff;
1762 var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
1763 high_word = var / 65536;
1765 /* Nbr of acquisition LOW */
1766 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1767 outw(low_word, devpriv->i_IobaseAddon + 2);
1769 /* Nbr of acquisition HIGH */
1770 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1771 outw(high_word, devpriv->i_IobaseAddon + 2);
1774 * To configure A2P FIFO
1775 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1776 * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1778 outw(3, devpriv->i_IobaseAddon + 4);
1779 /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
1780 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1781 APCI3120_ENABLE_WRITE_TC_INT),
1782 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1786 v_APCI3120_InterruptDmaMoveBlock16bit(dev, s,
1787 devpriv->ul_DmaBufferVirtual[devpriv->
1788 ui_DmaActualBuffer], samplesinbuf);
1790 if (!(devpriv->ui_AiFlags & TRIG_WAKE_EOS)) {
1791 s->async->events |= COMEDI_CB_EOS;
1792 comedi_event(dev, s);
1795 if (!devpriv->b_AiContinuous)
1796 if (devpriv->ui_AiActualScan >= devpriv->ui_AiNbrofScans) {
1797 /* all data sampled */
1798 i_APCI3120_StopCyclicAcquisition(dev, s);
1799 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1800 s->async->events |= COMEDI_CB_EOA;
1801 comedi_event(dev, s);
1805 if (devpriv->b_DmaDoubleBuffer) { /* switch dma buffers */
1806 devpriv->ui_DmaActualBuffer = 1 - devpriv->ui_DmaActualBuffer;
1809 * restart DMA if is not used double buffering
1810 * ADDED REINITIALISE THE DMA
1812 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1813 outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
1815 /* changed since 16 bit interface for add on */
1816 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1817 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1818 devpriv->i_IobaseAddon + 2);
1819 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1820 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); /* */
1822 * A2P FIFO MANAGEMENT
1823 * A2P fifo reset & transfer control enable
1825 outl(APCI3120_A2P_FIFO_MANAGEMENT,
1826 devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
1828 var = devpriv->ul_DmaBufferHw[0];
1829 low_word = var & 0xffff;
1830 var = devpriv->ul_DmaBufferHw[0];
1831 high_word = var / 65536;
1832 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1833 outw(low_word, devpriv->i_IobaseAddon + 2);
1834 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1835 outw(high_word, devpriv->i_IobaseAddon + 2);
1837 var = devpriv->ui_DmaBufferUsesize[0];
1838 low_word = var & 0xffff; /* changed */
1839 var = devpriv->ui_DmaBufferUsesize[0];
1840 high_word = var / 65536;
1841 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1842 outw(low_word, devpriv->i_IobaseAddon + 2);
1843 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1844 outw(high_word, devpriv->i_IobaseAddon + 2);
1847 * To configure A2P FIFO
1848 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1849 * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1851 outw(3, devpriv->i_IobaseAddon + 4);
1852 /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
1853 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1854 APCI3120_ENABLE_WRITE_TC_INT),
1855 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1860 +----------------------------------------------------------------------------+
1861 | Function name :void v_APCI3120_InterruptDmaMoveBlock16bit(comedi_device|
1862 |*dev,struct comedi_subdevice *s,short *dma,short *data,int n) |
1864 +----------------------------------------------------------------------------+
1865 | Task : This function copies the data from DMA buffer to the |
1868 +----------------------------------------------------------------------------+
1869 | Input Parameters : struct comedi_device *dev |
1870 | struct comedi_subdevice *s |
1872 | short *data,int n |
1873 +----------------------------------------------------------------------------+
1874 | Return Value : void |
1876 +----------------------------------------------------------------------------+
1879 void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev,
1880 struct comedi_subdevice *s, short *dma_buffer, unsigned int num_samples)
1882 devpriv->ui_AiActualScan +=
1883 (s->async->cur_chan + num_samples) / devpriv->ui_AiScanLength;
1884 s->async->cur_chan += num_samples;
1885 s->async->cur_chan %= devpriv->ui_AiScanLength;
1887 cfc_write_array_to_buffer(s, dma_buffer, num_samples * sizeof(short));
1891 +----------------------------------------------------------------------------+
1893 +----------------------------------------------------------------------------+
1897 +----------------------------------------------------------------------------+
1898 | Function name :int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, |
1899 | struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
1901 +----------------------------------------------------------------------------+
1902 | Task :Configure Timer 2 |
1904 +----------------------------------------------------------------------------+
1905 | Input Parameters : struct comedi_device *dev |
1906 | struct comedi_subdevice *s |
1907 | struct comedi_insn *insn |
1908 | unsigned int *data |
1910 | data[0]= TIMER configure as timer |
1911 | = WATCHDOG configure as watchdog |
1912 | data[1] = Timer constant |
1913 | data[2] = Timer2 interrupt (1)enable or(0) disable |
1915 +----------------------------------------------------------------------------+
1918 +----------------------------------------------------------------------------+
1921 int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, struct comedi_subdevice *s,
1922 struct comedi_insn *insn, unsigned int *data)
1925 unsigned int ui_Timervalue2;
1926 unsigned short us_TmpValue;
1927 unsigned char b_Tmp;
1930 comedi_error(dev, "config:No timer constant !");
1932 devpriv->b_Timer2Interrupt = (unsigned char) data[2]; /* save info whether to enable or disable interrupt */
1934 ui_Timervalue2 = data[1] / 1000; /* convert nano seconds to u seconds */
1936 /* this_board->i_hwdrv_InsnConfigTimer(dev, ui_Timervalue2,(unsigned char)data[0]); */
1937 us_TmpValue = (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
1940 * EL250804: Testing if board APCI3120 have the new Quartz or if it
1941 * is an APCI3001 and calculate the time value to set in the timer
1943 if ((us_TmpValue & 0x00B0) == 0x00B0
1944 || !strcmp(this_board->pc_DriverName, "apci3001")) {
1945 /* Calculate the time value to set in the timer */
1946 ui_Timervalue2 = ui_Timervalue2 / 50;
1948 /* Calculate the time value to set in the timer */
1949 ui_Timervalue2 = ui_Timervalue2 / 70;
1952 /* Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0) */
1953 devpriv->us_OutputRegister =
1954 devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER2;
1955 outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS);
1957 /* Disable TIMER Interrupt */
1958 devpriv->b_ModeSelectRegister =
1960 b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT & 0xEF;
1962 /* Disable Eoc and Eos Interrupts */
1963 devpriv->b_ModeSelectRegister =
1965 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT &
1966 APCI3120_DISABLE_EOS_INT;
1967 outb(devpriv->b_ModeSelectRegister,
1968 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
1969 if (data[0] == APCI3120_TIMER) /* initialize timer */
1971 /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister |
1972 * APCI3120_ENABLE_TIMER_INT; */
1974 /* outb(devpriv->b_ModeSelectRegister,devpriv->iobase+APCI3120_WRITE_MODE_SELECT); */
1976 /* Set the Timer 2 in mode 2(Timer) */
1977 devpriv->b_TimerSelectMode =
1979 b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_2;
1980 outb(devpriv->b_TimerSelectMode,
1981 devpriv->iobase + APCI3120_TIMER_CRT1);
1984 * Configure the timer 2 for writing the LOW unsigned short of timer
1985 * is Delay value You must make a b_tmp variable with
1986 * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
1987 * you can set the digital output and configure the timer 2,and if
1988 * you don't make this, digital output are erase (Set to 0)
1991 /* Writing LOW unsigned short */
1993 b_DigitalOutputRegister) & 0xF0) |
1994 APCI3120_SELECT_TIMER_2_LOW_WORD;
1995 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1996 outw(LOWORD(ui_Timervalue2),
1997 devpriv->iobase + APCI3120_TIMER_VALUE);
1999 /* Writing HIGH unsigned short */
2001 b_DigitalOutputRegister) & 0xF0) |
2002 APCI3120_SELECT_TIMER_2_HIGH_WORD;
2003 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2004 outw(HIWORD(ui_Timervalue2),
2005 devpriv->iobase + APCI3120_TIMER_VALUE);
2006 /* timer2 in Timer mode enabled */
2007 devpriv->b_Timer2Mode = APCI3120_TIMER;
2009 } else /* Initialize Watch dog */
2012 /* Set the Timer 2 in mode 5(Watchdog) */
2014 devpriv->b_TimerSelectMode =
2016 b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_5;
2017 outb(devpriv->b_TimerSelectMode,
2018 devpriv->iobase + APCI3120_TIMER_CRT1);
2021 * Configure the timer 2 for writing the LOW unsigned short of timer
2022 * is Delay value You must make a b_tmp variable with
2023 * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
2024 * you can set the digital output and configure the timer 2,and if
2025 * you don't make this, digital output are erase (Set to 0)
2028 /* Writing LOW unsigned short */
2030 b_DigitalOutputRegister) & 0xF0) |
2031 APCI3120_SELECT_TIMER_2_LOW_WORD;
2032 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2033 outw(LOWORD(ui_Timervalue2),
2034 devpriv->iobase + APCI3120_TIMER_VALUE);
2036 /* Writing HIGH unsigned short */
2038 b_DigitalOutputRegister) & 0xF0) |
2039 APCI3120_SELECT_TIMER_2_HIGH_WORD;
2040 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2042 outw(HIWORD(ui_Timervalue2),
2043 devpriv->iobase + APCI3120_TIMER_VALUE);
2044 /* watchdog enabled */
2045 devpriv->b_Timer2Mode = APCI3120_WATCHDOG;
2054 +----------------------------------------------------------------------------+
2055 | Function name :int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, |
2056 | struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
2058 +----------------------------------------------------------------------------+
2059 | Task : To start and stop the timer |
2060 +----------------------------------------------------------------------------+
2061 | Input Parameters : struct comedi_device *dev |
2062 | struct comedi_subdevice *s |
2063 | struct comedi_insn *insn |
2064 | unsigned int *data |
2066 | data[0] = 1 (start) |
2067 | data[0] = 0 (stop ) |
2068 | data[0] = 2 (write new value) |
2069 | data[1]= new value |
2071 | devpriv->b_Timer2Mode = 0 DISABLE |
2075 +----------------------------------------------------------------------------+
2078 +----------------------------------------------------------------------------+
2081 int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, struct comedi_subdevice *s,
2082 struct comedi_insn *insn, unsigned int *data)
2085 unsigned int ui_Timervalue2 = 0;
2086 unsigned short us_TmpValue;
2087 unsigned char b_Tmp;
2089 if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
2090 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
2091 comedi_error(dev, "\nwrite:timer2 not configured ");
2095 if (data[0] == 2) /* write new value */
2097 if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
2099 "write :timer2 not configured in TIMER MODE");
2104 ui_Timervalue2 = data[1];
2109 /* this_board->i_hwdrv_InsnWriteTimer(dev,data[0],ui_Timervalue2); */
2112 case APCI3120_START:
2114 /* Reset FC_TIMER BIT */
2115 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2116 if (devpriv->b_Timer2Mode == APCI3120_TIMER) /* start timer */
2119 devpriv->b_ModeSelectRegister =
2120 devpriv->b_ModeSelectRegister & 0x0B;
2121 } else /* start watch dog */
2123 /* Enable WatchDog */
2124 devpriv->b_ModeSelectRegister =
2126 b_ModeSelectRegister & 0x0B) |
2127 APCI3120_ENABLE_WATCHDOG;
2130 /* enable disable interrupt */
2131 if ((devpriv->b_Timer2Interrupt) == APCI3120_ENABLE) {
2133 devpriv->b_ModeSelectRegister =
2135 b_ModeSelectRegister |
2136 APCI3120_ENABLE_TIMER_INT;
2137 /* save the task structure to pass info to user */
2138 devpriv->tsk_Current = current;
2141 devpriv->b_ModeSelectRegister =
2143 b_ModeSelectRegister &
2144 APCI3120_DISABLE_TIMER_INT;
2146 outb(devpriv->b_ModeSelectRegister,
2147 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
2149 if (devpriv->b_Timer2Mode == APCI3120_TIMER) /* start timer */
2151 /* For Timer mode is Gate2 must be activated **timer started */
2152 devpriv->us_OutputRegister =
2154 us_OutputRegister | APCI3120_ENABLE_TIMER2;
2155 outw(devpriv->us_OutputRegister,
2156 devpriv->iobase + APCI3120_WR_ADDRESS);
2162 if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
2164 devpriv->b_ModeSelectRegister =
2166 b_ModeSelectRegister &
2167 APCI3120_DISABLE_TIMER_COUNTER;
2169 /* Disable WatchDog */
2170 devpriv->b_ModeSelectRegister =
2172 b_ModeSelectRegister &
2173 APCI3120_DISABLE_WATCHDOG;
2175 /* Disable timer interrupt */
2176 devpriv->b_ModeSelectRegister =
2178 b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT;
2180 /* Write above states to register */
2181 outb(devpriv->b_ModeSelectRegister,
2182 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
2185 devpriv->us_OutputRegister =
2186 devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER_INT;
2187 outw(devpriv->us_OutputRegister,
2188 devpriv->iobase + APCI3120_WR_ADDRESS);
2190 /* Reset FC_TIMER BIT */
2191 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2194 /* devpriv->b_Timer2Mode=APCI3120_DISABLE; */
2198 case 2: /* write new value to Timer */
2199 if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
2201 "write :timer2 not configured in TIMER MODE");
2204 /* ui_Timervalue2=data[1]; // passed as argument */
2206 (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
2209 * EL250804: Testing if board APCI3120 have the new Quartz or if it
2210 * is an APCI3001 and calculate the time value to set in the timer
2212 if ((us_TmpValue & 0x00B0) == 0x00B0
2213 || !strcmp(this_board->pc_DriverName, "apci3001")) {
2214 /* Calculate the time value to set in the timer */
2215 ui_Timervalue2 = ui_Timervalue2 / 50;
2217 /* Calculate the time value to set in the timer */
2218 ui_Timervalue2 = ui_Timervalue2 / 70;
2220 /* Writing LOW unsigned short */
2222 b_DigitalOutputRegister) & 0xF0) |
2223 APCI3120_SELECT_TIMER_2_LOW_WORD;
2224 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2226 outw(LOWORD(ui_Timervalue2),
2227 devpriv->iobase + APCI3120_TIMER_VALUE);
2229 /* Writing HIGH unsigned short */
2231 b_DigitalOutputRegister) & 0xF0) |
2232 APCI3120_SELECT_TIMER_2_HIGH_WORD;
2233 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2235 outw(HIWORD(ui_Timervalue2),
2236 devpriv->iobase + APCI3120_TIMER_VALUE);
2240 return -EINVAL; /* Not a valid input */
2247 +----------------------------------------------------------------------------+
2248 | Function name : int i_APCI3120_InsnReadTimer(struct comedi_device *dev, |
2249 | struct comedi_subdevice *s,struct comedi_insn *insn, unsigned int *data) |
2252 +----------------------------------------------------------------------------+
2253 | Task : read the Timer value |
2254 +----------------------------------------------------------------------------+
2255 | Input Parameters : struct comedi_device *dev |
2256 | struct comedi_subdevice *s |
2257 | struct comedi_insn *insn |
2258 | unsigned int *data |
2260 +----------------------------------------------------------------------------+
2262 | for Timer: data[0]= Timer constant |
2264 | for watchdog: data[0]=0 (still running) |
2265 | data[0]=1 (run down) |
2267 +----------------------------------------------------------------------------+
2269 int i_APCI3120_InsnReadTimer(struct comedi_device *dev, struct comedi_subdevice *s,
2270 struct comedi_insn *insn, unsigned int *data)
2272 unsigned char b_Tmp;
2273 unsigned short us_TmpValue, us_TmpValue_2, us_StatusValue;
2275 if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
2276 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
2277 comedi_error(dev, "\nread:timer2 not configured ");
2280 /* this_board->i_hwdrv_InsnReadTimer(dev,data); */
2281 if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
2283 /* Read the LOW unsigned short of Timer 2 register */
2285 b_DigitalOutputRegister) & 0xF0) |
2286 APCI3120_SELECT_TIMER_2_LOW_WORD;
2287 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2289 us_TmpValue = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
2291 /* Read the HIGH unsigned short of Timer 2 register */
2293 b_DigitalOutputRegister) & 0xF0) |
2294 APCI3120_SELECT_TIMER_2_HIGH_WORD;
2295 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2297 us_TmpValue_2 = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
2299 /* combining both words */
2300 data[0] = (unsigned int) ((us_TmpValue) | ((us_TmpValue_2) << 16));
2302 } else /* Read watch dog status */
2305 us_StatusValue = inw(devpriv->iobase + APCI3120_RD_STATUS);
2307 ((us_StatusValue & APCI3120_FC_TIMER) >> 12) & 1;
2308 if (us_StatusValue == 1) {
2309 /* RESET FC_TIMER BIT */
2310 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2312 data[0] = us_StatusValue; /* when data[0] = 1 then the watch dog has rundown */
2318 +----------------------------------------------------------------------------+
2319 | DIGITAL INPUT SUBDEVICE |
2320 +----------------------------------------------------------------------------+
2324 +----------------------------------------------------------------------------+
2325 | Function name :int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev, |
2326 | struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
2329 +----------------------------------------------------------------------------+
2330 | Task : Reads the value of the specified Digital input channel|
2332 +----------------------------------------------------------------------------+
2333 | Input Parameters : struct comedi_device *dev |
2334 | struct comedi_subdevice *s |
2335 | struct comedi_insn *insn |
2336 | unsigned int *data |
2337 +----------------------------------------------------------------------------+
2340 +----------------------------------------------------------------------------+
2343 int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev,
2344 struct comedi_subdevice *s,
2345 struct comedi_insn *insn,
2348 unsigned int ui_Chan, ui_TmpValue;
2350 ui_Chan = CR_CHAN(insn->chanspec); /* channel specified */
2352 /* this_board->i_hwdrv_InsnReadDigitalInput(dev,ui_Chan,data); */
2354 ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI3120_RD_STATUS);
2357 * since only 1 channel reqd to bring it to last bit it is rotated 8
2358 * +(chan - 1) times then ANDed with 1 for last bit.
2360 *data = (ui_TmpValue >> (ui_Chan + 8)) & 1;
2363 /* comedi_error(dev," chan spec wrong"); */
2364 return -EINVAL; /* "sorry channel spec wrong " */
2371 +----------------------------------------------------------------------------+
2372 | Function name :int i_APCI3120_InsnBitsDigitalInput(struct comedi_device *dev, |
2373 |struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
2375 +----------------------------------------------------------------------------+
2376 | Task : Reads the value of the Digital input Port i.e.4channels|
2377 | value is returned in data[0] |
2379 +----------------------------------------------------------------------------+
2380 | Input Parameters : struct comedi_device *dev |
2381 | struct comedi_subdevice *s |
2382 | struct comedi_insn *insn |
2383 | unsigned int *data |
2384 +----------------------------------------------------------------------------+
2387 +----------------------------------------------------------------------------+
2389 int i_APCI3120_InsnBitsDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s,
2390 struct comedi_insn *insn, unsigned int *data)
2392 unsigned int ui_TmpValue;
2393 ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI3120_RD_STATUS);
2394 /***** state of 4 channels in the 11, 10, 9, 8 bits of status reg
2395 rotated right 8 times to bring them to last four bits
2396 ANDed with oxf for value.
2399 *data = (ui_TmpValue >> 8) & 0xf;
2400 /* this_board->i_hwdrv_InsnBitsDigitalInput(dev,data); */
2405 +----------------------------------------------------------------------------+
2406 | DIGITAL OUTPUT SUBDEVICE |
2407 +----------------------------------------------------------------------------+
2410 +----------------------------------------------------------------------------+
2411 | Function name :int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device |
2412 | *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
2414 +----------------------------------------------------------------------------+
2415 | Task :Configure the output memory ON or OFF |
2417 +----------------------------------------------------------------------------+
2418 | Input Parameters :struct comedi_device *dev |
2419 | struct comedi_subdevice *s |
2420 | struct comedi_insn *insn |
2421 | unsigned int *data |
2422 +----------------------------------------------------------------------------+
2425 +----------------------------------------------------------------------------+
2428 int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device *dev,
2429 struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data)
2432 if ((data[0] != 0) && (data[0] != 1)) {
2434 "Not a valid Data !!! ,Data should be 1 or 0\n");
2438 devpriv->b_OutputMemoryStatus = APCI3120_ENABLE;
2441 devpriv->b_OutputMemoryStatus = APCI3120_DISABLE;
2442 devpriv->b_DigitalOutputRegister = 0;
2444 if (!devpriv->b_OutputMemoryStatus) {
2447 } /* if(!devpriv->b_OutputMemoryStatus ) */
2453 +----------------------------------------------------------------------------+
2454 | Function name :int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device *dev, |
2455 | struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
2457 +----------------------------------------------------------------------------+
2458 | Task : write diatal output port |
2460 +----------------------------------------------------------------------------+
2461 | Input Parameters : struct comedi_device *dev |
2462 | struct comedi_subdevice *s |
2463 | struct comedi_insn *insn |
2464 | unsigned int *data |
2465 | data[0] Value to be written
2466 | data[1] :1 Set digital o/p ON
2467 | data[1] 2 Set digital o/p OFF with memory ON
2468 +----------------------------------------------------------------------------+
2471 +----------------------------------------------------------------------------+
2474 int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device *dev,
2475 struct comedi_subdevice *s,
2476 struct comedi_insn *insn,
2479 if ((data[0] > this_board->i_DoMaxdata) || (data[0] < 0)) {
2481 comedi_error(dev, "Data is not valid !!! \n");
2487 data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister;
2494 printk("\nThe parameter passed is in error \n");
2496 } /* switch(data[1]) */
2497 outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
2499 devpriv->b_DigitalOutputRegister = data[0] & 0xF0;
2506 +----------------------------------------------------------------------------+
2507 | Function name :int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev,|
2508 |struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
2510 +----------------------------------------------------------------------------+
2511 | Task : Write digiatl output |
2513 +----------------------------------------------------------------------------+
2514 | Input Parameters : struct comedi_device *dev |
2515 | struct comedi_subdevice *s |
2516 | struct comedi_insn *insn |
2517 | unsigned int *data |
2518 data[0] Value to be written
2519 data[1] :1 Set digital o/p ON
2520 data[1] 2 Set digital o/p OFF with memory ON
2521 +----------------------------------------------------------------------------+
2524 +----------------------------------------------------------------------------+
2527 int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev,
2528 struct comedi_subdevice *s,
2529 struct comedi_insn *insn,
2533 unsigned int ui_Temp1;
2535 unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */
2537 if ((data[0] != 0) && (data[0] != 1)) {
2539 "Not a valid Data !!! ,Data should be 1 or 0\n");
2542 if (ui_NoOfChannel > this_board->i_NbrDoChannel - 1) {
2544 "This board doesn't have specified channel !!! \n");
2550 data[0] = (data[0] << ui_NoOfChannel);
2551 /* ES05 data[0]=(data[0]<<4)|ui_Temp; */
2552 data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister;
2556 data[0] = ~data[0] & 0x1;
2558 ui_Temp1 = ui_Temp1 << ui_NoOfChannel;
2559 ui_Temp1 = ui_Temp1 << 4;
2560 /* ES05 ui_Temp=ui_Temp|ui_Temp1; */
2561 devpriv->b_DigitalOutputRegister =
2562 devpriv->b_DigitalOutputRegister | ui_Temp1;
2564 data[0] = (data[0] << ui_NoOfChannel) ^ 0xf;
2565 data[0] = data[0] << 4;
2566 /* ES05 data[0]=data[0]& ui_Temp; */
2567 data[0] = data[0] & devpriv->b_DigitalOutputRegister;
2570 printk("\nThe parameter passed is in error \n");
2572 } /* switch(data[1]) */
2573 outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
2575 /* ES05 ui_Temp=data[0] & 0xf0; */
2576 devpriv->b_DigitalOutputRegister = data[0] & 0xf0;
2582 +----------------------------------------------------------------------------+
2583 | ANALOG OUTPUT SUBDEVICE |
2584 +----------------------------------------------------------------------------+
2588 +----------------------------------------------------------------------------+
2589 | Function name :int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,|
2590 |struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
2592 +----------------------------------------------------------------------------+
2593 | Task : Write analog output |
2595 +----------------------------------------------------------------------------+
2596 | Input Parameters : struct comedi_device *dev |
2597 | struct comedi_subdevice *s |
2598 | struct comedi_insn *insn |
2599 | unsigned int *data |
2600 +----------------------------------------------------------------------------+
2603 +----------------------------------------------------------------------------+
2606 int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,
2607 struct comedi_subdevice *s,
2608 struct comedi_insn *insn,
2611 unsigned int ui_Range, ui_Channel;
2612 unsigned short us_TmpValue;
2614 ui_Range = CR_RANGE(insn->chanspec);
2615 ui_Channel = CR_CHAN(insn->chanspec);
2617 /* this_board->i_hwdrv_InsnWriteAnalogOutput(dev, ui_Range, ui_Channel,data[0]); */
2618 if (ui_Range) /* if 1 then unipolar */
2623 ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
2624 13) | (data[0] + 8191));
2627 ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
2630 } else /* if 0 then bipolar */
2633 ((((ui_Channel & 0x03) << 14) & 0xC000) | (0 << 13) |
2639 * out put n values at the given channel. printk("\nwaiting for
2642 do /* Waiting of DA_READY BIT */
2645 ((unsigned short) inw(devpriv->iobase +
2646 APCI3120_RD_STATUS)) & 0x0001;
2647 } while (us_TmpValue != 0x0001);
2649 if (ui_Channel <= 3)
2651 * for channel 0-3 out at the register 1 (wrDac1-8) data[i]
2652 * typecasted to ushort since word write is to be done
2654 outw((unsigned short) data[0],
2655 devpriv->iobase + APCI3120_ANALOG_OUTPUT_1);
2658 * for channel 4-7 out at the register 2 (wrDac5-8) data[i]
2659 * typecasted to ushort since word write is to be done
2661 outw((unsigned short) data[0],
2662 devpriv->iobase + APCI3120_ANALOG_OUTPUT_2);