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 +
372 while ((us_TmpValue & APCI3120_EOS) !=
375 for (i = 0; i < devpriv->ui_AiNbrofChannels;
377 /* Read the result in FIFO and write them in shared memory */
378 us_TmpValue = inw(devpriv->iobase);
379 data[i] = (unsigned int) us_TmpValue;
382 devpriv->b_InterruptMode = APCI3120_EOC_MODE; /* Restore defaults. */
387 printk("inputs wrong\n");
390 devpriv->ui_EocEosConversionTime = 0; /* re initializing the variable; */
398 +----------------------------------------------------------------------------+
399 | Function name :int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev,|
400 | struct comedi_subdevice *s)|
402 +----------------------------------------------------------------------------+
403 | Task : Stops Cyclic acquisition |
405 +----------------------------------------------------------------------------+
406 | Input Parameters : struct comedi_device *dev |
407 | struct comedi_subdevice *s |
409 +----------------------------------------------------------------------------+
412 +----------------------------------------------------------------------------+
415 int i_APCI3120_StopCyclicAcquisition(struct comedi_device * dev, struct comedi_subdevice * s)
417 /* Disable A2P Fifo write and AMWEN signal */
418 outw(0, devpriv->i_IobaseAddon + 4);
420 /* Disable Bus Master ADD ON */
421 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
422 outw(0, devpriv->i_IobaseAddon + 2);
423 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
424 outw(0, devpriv->i_IobaseAddon + 2);
426 /* Disable BUS Master PCI */
427 outl(0, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
429 /* outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR)&(~AINT_WRITE_COMPL),
430 * devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR); stop amcc irqs */
432 /* outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR)&(~EN_A2P_TRANSFERS),
433 * devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR); stop DMA */
435 /* Disable ext trigger */
436 i_APCI3120_ExttrigDisable(dev);
438 devpriv->us_OutputRegister = 0;
441 us_OutputRegister & APCI3120_DISABLE_TIMER0 &
442 APCI3120_DISABLE_TIMER1, dev->iobase + APCI3120_WR_ADDRESS);
444 outw(APCI3120_DISABLE_ALL_TIMER, dev->iobase + APCI3120_WR_ADDRESS);
446 /* DISABLE_ALL_INTERRUPT */
447 outb(APCI3120_DISABLE_ALL_INTERRUPT,
448 dev->iobase + APCI3120_WRITE_MODE_SELECT);
450 inb(dev->iobase + APCI3120_RESET_FIFO);
451 inw(dev->iobase + APCI3120_RD_STATUS);
452 devpriv->ui_AiActualScan = 0;
453 devpriv->ui_AiActualScanPosition = 0;
454 s->async->cur_chan = 0;
455 devpriv->ui_AiBufferPtr = 0;
456 devpriv->b_AiContinuous = 0;
457 devpriv->ui_DmaActualBuffer = 0;
459 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
460 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
461 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
462 i_APCI3120_Reset(dev);
467 +----------------------------------------------------------------------------+
468 | Function name :int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev|
469 | ,struct comedi_subdevice *s,struct comedi_cmd *cmd) |
471 +----------------------------------------------------------------------------+
472 | Task : Test validity for a command for cyclic anlog input |
475 +----------------------------------------------------------------------------+
476 | Input Parameters : struct comedi_device *dev |
477 | struct comedi_subdevice *s |
478 | struct comedi_cmd *cmd |
479 +----------------------------------------------------------------------------+
482 +----------------------------------------------------------------------------+
485 int i_APCI3120_CommandTestAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s,
486 struct comedi_cmd * cmd)
489 int tmp; /* divisor1,divisor2; */
491 /* step 1: make sure trigger sources are trivially valid */
493 tmp = cmd->start_src;
494 cmd->start_src &= TRIG_NOW | TRIG_EXT;
495 if (!cmd->start_src || tmp != cmd->start_src)
498 tmp = cmd->scan_begin_src;
499 cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW;
500 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
503 tmp = cmd->convert_src;
504 cmd->convert_src &= TRIG_TIMER;
505 if (!cmd->convert_src || tmp != cmd->convert_src)
508 tmp = cmd->scan_end_src;
509 cmd->scan_end_src &= TRIG_COUNT;
510 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
514 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
515 if (!cmd->stop_src || tmp != cmd->stop_src)
521 /* step 2: make sure trigger sources are unique and mutually compatible */
523 if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) {
527 if (cmd->scan_begin_src != TRIG_TIMER &&
528 cmd->scan_begin_src != TRIG_FOLLOW)
531 if (cmd->convert_src != TRIG_TIMER)
534 if (cmd->scan_end_src != TRIG_COUNT) {
535 cmd->scan_end_src = TRIG_COUNT;
539 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
545 /* step 3: make sure arguments are trivially compatible */
547 if (cmd->start_arg != 0) {
552 if (cmd->scan_begin_src == TRIG_TIMER) /* Test Delay timing */
554 if (cmd->scan_begin_arg < this_board->ui_MinDelaytimeNs) {
555 cmd->scan_begin_arg = this_board->ui_MinDelaytimeNs;
560 if (cmd->convert_src == TRIG_TIMER) /* Test Acquisition timing */
562 if (cmd->scan_begin_src == TRIG_TIMER) {
563 if ((cmd->convert_arg)
564 && (cmd->convert_arg <
565 this_board->ui_MinAcquisitiontimeNs)) {
567 this_board->ui_MinAcquisitiontimeNs;
571 if (cmd->convert_arg <
572 this_board->ui_MinAcquisitiontimeNs) {
574 this_board->ui_MinAcquisitiontimeNs;
581 if (!cmd->chanlist_len) {
582 cmd->chanlist_len = 1;
585 if (cmd->chanlist_len > this_board->i_AiChannelList) {
586 cmd->chanlist_len = this_board->i_AiChannelList;
589 if (cmd->stop_src == TRIG_COUNT) {
590 if (!cmd->stop_arg) {
594 } else { /* TRIG_NONE */
595 if (cmd->stop_arg != 0) {
604 /* step 4: fix up any arguments */
606 if (cmd->convert_src == TRIG_TIMER) {
608 if (cmd->scan_begin_src == TRIG_TIMER &&
609 cmd->scan_begin_arg <
610 cmd->convert_arg * cmd->scan_end_arg) {
611 cmd->scan_begin_arg =
612 cmd->convert_arg * cmd->scan_end_arg;
624 +----------------------------------------------------------------------------+
625 | Function name : int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, |
626 | struct comedi_subdevice *s) |
628 +----------------------------------------------------------------------------+
629 | Task : Does asynchronous acquisition |
630 | Determines the mode 1 or 2. |
632 +----------------------------------------------------------------------------+
633 | Input Parameters : struct comedi_device *dev |
634 | struct comedi_subdevice *s |
636 +----------------------------------------------------------------------------+
639 +----------------------------------------------------------------------------+
642 int i_APCI3120_CommandAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s)
644 struct comedi_cmd *cmd = &s->async->cmd;
646 /* loading private structure with cmd structure inputs */
647 devpriv->ui_AiFlags = cmd->flags;
648 devpriv->ui_AiNbrofChannels = cmd->chanlist_len;
649 devpriv->ui_AiScanLength = cmd->scan_end_arg;
650 devpriv->pui_AiChannelList = cmd->chanlist;
652 /* UPDATE-0.7.57->0.7.68devpriv->AiData=s->async->data; */
653 devpriv->AiData = s->async->prealloc_buf;
654 /* UPDATE-0.7.57->0.7.68devpriv->ui_AiDataLength=s->async->data_len; */
655 devpriv->ui_AiDataLength = s->async->prealloc_bufsz;
657 if (cmd->stop_src == TRIG_COUNT) {
658 devpriv->ui_AiNbrofScans = cmd->stop_arg;
660 devpriv->ui_AiNbrofScans = 0;
663 devpriv->ui_AiTimer0 = 0; /* variables changed to timer0,timer1 */
664 devpriv->ui_AiTimer1 = 0;
665 if ((devpriv->ui_AiNbrofScans == 0) || (devpriv->ui_AiNbrofScans == -1))
666 devpriv->b_AiContinuous = 1; /* user want neverending analog acquisition */
667 /* stopped using cancel */
669 if (cmd->start_src == TRIG_EXT)
670 devpriv->b_ExttrigEnable = APCI3120_ENABLE;
672 devpriv->b_ExttrigEnable = APCI3120_DISABLE;
674 if (cmd->scan_begin_src == TRIG_FOLLOW) {
676 if (cmd->convert_src == TRIG_TIMER) {
679 devpriv->ui_AiTimer0 = cmd->convert_arg; /* timer constant in nano seconds */
680 /* return this_board->i_hwdrv_CommandAnalogInput(1,dev,s); */
681 return i_APCI3120_CyclicAnalogInput(1, dev, s);
685 if ((cmd->scan_begin_src == TRIG_TIMER)
686 && (cmd->convert_src == TRIG_TIMER)) {
688 devpriv->ui_AiTimer1 = cmd->scan_begin_arg;
689 devpriv->ui_AiTimer0 = cmd->convert_arg; /* variable changed timer2 to timer0 */
690 /* return this_board->i_hwdrv_CommandAnalogInput(2,dev,s); */
691 return i_APCI3120_CyclicAnalogInput(2, dev, s);
697 +----------------------------------------------------------------------------+
698 | Function name : int i_APCI3120_CyclicAnalogInput(int mode, |
699 | struct comedi_device * dev,struct comedi_subdevice * s) |
700 +----------------------------------------------------------------------------+
701 | Task : This is used for analog input cyclic acquisition |
702 | Performs the command operations. |
703 | If DMA is configured does DMA initialization |
704 | otherwise does the acquisition with EOS interrupt. |
706 +----------------------------------------------------------------------------+
707 | Input Parameters : |
710 +----------------------------------------------------------------------------+
713 +----------------------------------------------------------------------------+
716 int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device * dev,
717 struct comedi_subdevice * s)
720 unsigned int ui_Tmp, ui_DelayTiming = 0, ui_TimerValue1 = 0, dmalen0 =
721 0, dmalen1 = 0, ui_TimerValue2 =
722 0, ui_TimerValue0, ui_ConvertTiming;
723 unsigned short us_TmpValue;
725 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
726 /* devpriv->b_AiCyclicAcquisition=APCI3120_ENABLE; */
727 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
729 /*******************/
730 /* Resets the FIFO */
731 /*******************/
732 inb(dev->iobase + APCI3120_RESET_FIFO);
734 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
735 /* inw(dev->iobase+APCI3120_RD_STATUS); */
736 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
738 /***************************/
739 /* Acquisition initialized */
740 /***************************/
741 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
742 devpriv->b_AiCyclicAcquisition = APCI3120_ENABLE;
743 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
745 /* clear software registers */
746 devpriv->b_TimerSelectMode = 0;
747 devpriv->us_OutputRegister = 0;
748 devpriv->b_ModeSelectRegister = 0;
749 /* devpriv->b_DigitalOutputRegister=0; */
751 /* COMMENT JK 07.05.04: Followings calls are in i_APCI3120_StartAnalogInputAcquisition */
753 /****************************/
754 /* Clear Timer Write TC int */
755 /****************************/
756 outl(APCI3120_CLEAR_WRITE_TC_INT,
757 devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_REG_INTCSR);
759 /************************************/
760 /* Clears the timer status register */
761 /************************************/
763 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
764 /* inw(dev->iobase+APCI3120_TIMER_STATUS_REGISTER); */
765 /* inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); */
766 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
768 /**************************/
769 /* Disables All Timer */
770 /* Sets PR and PA to 0 */
771 /**************************/
772 devpriv->us_OutputRegister = devpriv->us_OutputRegister &
773 APCI3120_DISABLE_TIMER0 &
774 APCI3120_DISABLE_TIMER1 & APCI3120_CLEAR_PA_PR;
776 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
778 /*******************/
779 /* Resets the FIFO */
780 /*******************/
781 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
782 inb(devpriv->iobase + APCI3120_RESET_FIFO);
783 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
785 devpriv->ui_AiActualScan = 0;
786 devpriv->ui_AiActualScanPosition = 0;
787 s->async->cur_chan = 0;
788 devpriv->ui_AiBufferPtr = 0;
789 devpriv->ui_DmaActualBuffer = 0;
791 /* value for timer2 minus -2 has to be done .....dunno y?? */
792 ui_TimerValue2 = devpriv->ui_AiNbrofScans - 2;
793 ui_ConvertTiming = devpriv->ui_AiTimer0;
796 ui_DelayTiming = devpriv->ui_AiTimer1;
798 /**********************************/
799 /* Initializes the sequence array */
800 /**********************************/
801 if (!i_APCI3120_SetupChannelList(dev, s, devpriv->ui_AiNbrofChannels,
802 devpriv->pui_AiChannelList, 0))
805 us_TmpValue = (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
806 /*** EL241003 : add this section in comment because floats must not be used
807 if((us_TmpValue & 0x00B0)==0x00B0)
809 f_ConvertValue=(((float)ui_ConvertTiming * 0.002) - 2);
810 ui_TimerValue0=(unsigned int)f_ConvertValue;
813 f_DelayValue = (((float)ui_DelayTiming * 0.00002) - 2);
814 ui_TimerValue1 = (unsigned int) f_DelayValue;
819 f_ConvertValue=(((float)ui_ConvertTiming * 0.0012926) - 1);
820 ui_TimerValue0=(unsigned int)f_ConvertValue;
823 f_DelayValue = (((float)ui_DelayTiming * 0.000012926) - 1);
824 ui_TimerValue1 = (unsigned int) f_DelayValue;
827 ***********************************************************************************************/
828 /*** EL241003 Begin : add this section to replace floats calculation by integer calculations **/
829 /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */
830 if ((us_TmpValue & 0x00B0) == 0x00B0
831 || !strcmp(this_board->pc_DriverName, "apci3001")) {
832 ui_TimerValue0 = ui_ConvertTiming * 2 - 2000;
833 ui_TimerValue0 = ui_TimerValue0 / 1000;
836 ui_DelayTiming = ui_DelayTiming / 1000;
837 ui_TimerValue1 = ui_DelayTiming * 2 - 200;
838 ui_TimerValue1 = ui_TimerValue1 / 100;
841 ui_ConvertTiming = ui_ConvertTiming / 1000;
842 ui_TimerValue0 = ui_ConvertTiming * 12926 - 10000;
843 ui_TimerValue0 = ui_TimerValue0 / 10000;
846 ui_DelayTiming = ui_DelayTiming / 1000;
847 ui_TimerValue1 = ui_DelayTiming * 12926 - 1;
848 ui_TimerValue1 = ui_TimerValue1 / 1000000;
851 /*** EL241003 End ******************************************************************************/
853 if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) {
854 i_APCI3120_ExttrigEnable(dev); /* activate EXT trigger */
858 /* init timer0 in mode 2 */
859 devpriv->b_TimerSelectMode =
861 b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
862 outb(devpriv->b_TimerSelectMode,
863 dev->iobase + APCI3120_TIMER_CRT1);
867 b_DigitalOutputRegister) & 0xF0) |
868 APCI3120_SELECT_TIMER_0_WORD;
869 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
870 /* Set the convertion time */
871 outw(((unsigned short) ui_TimerValue0),
872 dev->iobase + APCI3120_TIMER_VALUE);
876 /* init timer1 in mode 2 */
877 devpriv->b_TimerSelectMode =
879 b_TimerSelectMode & 0xF3) | APCI3120_TIMER_1_MODE_2;
880 outb(devpriv->b_TimerSelectMode,
881 dev->iobase + APCI3120_TIMER_CRT1);
885 b_DigitalOutputRegister) & 0xF0) |
886 APCI3120_SELECT_TIMER_1_WORD;
887 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
888 /* Set the convertion time */
889 outw(((unsigned short) ui_TimerValue1),
890 dev->iobase + APCI3120_TIMER_VALUE);
892 /* init timer0 in mode 2 */
893 devpriv->b_TimerSelectMode =
895 b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
896 outb(devpriv->b_TimerSelectMode,
897 dev->iobase + APCI3120_TIMER_CRT1);
901 b_DigitalOutputRegister) & 0xF0) |
902 APCI3120_SELECT_TIMER_0_WORD;
903 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
905 /* Set the convertion time */
906 outw(((unsigned short) ui_TimerValue0),
907 dev->iobase + APCI3120_TIMER_VALUE);
911 /* ##########common for all modes################# */
913 /***********************/
914 /* Clears the SCAN bit */
915 /***********************/
917 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
918 /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister | APCI3120_DISABLE_SCAN; */
920 devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
921 APCI3120_DISABLE_SCAN;
922 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
924 outb(devpriv->b_ModeSelectRegister,
925 dev->iobase + APCI3120_WRITE_MODE_SELECT);
927 /* If DMA is disabled */
928 if (devpriv->us_UseDma == APCI3120_DISABLE) {
929 /* disable EOC and enable EOS */
930 devpriv->b_InterruptMode = APCI3120_EOS_MODE;
931 devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
933 devpriv->b_ModeSelectRegister =
935 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT) |
936 APCI3120_ENABLE_EOS_INT;
937 outb(devpriv->b_ModeSelectRegister,
938 dev->iobase + APCI3120_WRITE_MODE_SELECT);
940 if (!devpriv->b_AiContinuous) {
942 * configure Timer2 For counting EOS Reset gate 2 of Timer 2 to
943 * disable it (Set Bit D14 to 0)
945 devpriv->us_OutputRegister =
947 us_OutputRegister & APCI3120_DISABLE_TIMER2;
948 outw(devpriv->us_OutputRegister,
949 dev->iobase + APCI3120_WR_ADDRESS);
951 /* DISABLE TIMER intERRUPT */
952 devpriv->b_ModeSelectRegister =
954 b_ModeSelectRegister &
955 APCI3120_DISABLE_TIMER_INT & 0xEF;
956 outb(devpriv->b_ModeSelectRegister,
957 dev->iobase + APCI3120_WRITE_MODE_SELECT);
959 /* (1) Init timer 2 in mode 0 and write timer value */
960 devpriv->b_TimerSelectMode =
962 b_TimerSelectMode & 0x0F) |
963 APCI3120_TIMER_2_MODE_0;
964 outb(devpriv->b_TimerSelectMode,
965 dev->iobase + APCI3120_TIMER_CRT1);
967 /* Writing LOW unsigned short */
969 b_DigitalOutputRegister) & 0xF0) |
970 APCI3120_SELECT_TIMER_2_LOW_WORD;
971 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
972 outw(LOWORD(ui_TimerValue2),
973 dev->iobase + APCI3120_TIMER_VALUE);
975 /* Writing HIGH unsigned short */
977 b_DigitalOutputRegister) & 0xF0) |
978 APCI3120_SELECT_TIMER_2_HIGH_WORD;
979 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
980 outw(HIWORD(ui_TimerValue2),
981 dev->iobase + APCI3120_TIMER_VALUE);
983 /* (2) Reset FC_TIMER BIT Clearing timer status register */
984 inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
985 /* enable timer counter and disable watch dog */
986 devpriv->b_ModeSelectRegister =
988 b_ModeSelectRegister |
989 APCI3120_ENABLE_TIMER_COUNTER) &
990 APCI3120_DISABLE_WATCHDOG;
991 /* select EOS clock input for timer 2 */
992 devpriv->b_ModeSelectRegister =
994 b_ModeSelectRegister |
995 APCI3120_TIMER2_SELECT_EOS;
996 /* Enable timer2 interrupt */
997 devpriv->b_ModeSelectRegister =
999 b_ModeSelectRegister |
1000 APCI3120_ENABLE_TIMER_INT;
1001 outb(devpriv->b_ModeSelectRegister,
1002 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1003 devpriv->b_Timer2Mode = APCI3120_COUNTER;
1004 devpriv->b_Timer2Interrupt = APCI3120_ENABLE;
1007 /* If DMA Enabled */
1009 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1010 /* inw(dev->iobase+0); reset EOC bit */
1011 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1012 devpriv->b_InterruptMode = APCI3120_DMA_MODE;
1014 /************************************/
1015 /* Disables the EOC, EOS interrupt */
1016 /************************************/
1017 devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
1018 APCI3120_DISABLE_EOC_INT & APCI3120_DISABLE_EOS_INT;
1020 outb(devpriv->b_ModeSelectRegister,
1021 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1023 dmalen0 = devpriv->ui_DmaBufferSize[0];
1024 dmalen1 = devpriv->ui_DmaBufferSize[1];
1026 if (!devpriv->b_AiContinuous) {
1028 if (dmalen0 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2)) { /* must we fill full first buffer? */
1030 devpriv->ui_AiNbrofScans *
1031 devpriv->ui_AiScanLength * 2;
1032 } else if (dmalen1 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2 - dmalen0)) /* and must we fill full second buffer when first is once filled? */
1034 devpriv->ui_AiNbrofScans *
1035 devpriv->ui_AiScanLength * 2 - dmalen0;
1038 if (devpriv->ui_AiFlags & TRIG_WAKE_EOS) {
1039 /* don't we want wake up every scan? */
1040 if (dmalen0 > (devpriv->ui_AiScanLength * 2)) {
1041 dmalen0 = devpriv->ui_AiScanLength * 2;
1042 if (devpriv->ui_AiScanLength & 1)
1045 if (dmalen1 > (devpriv->ui_AiScanLength * 2)) {
1046 dmalen1 = devpriv->ui_AiScanLength * 2;
1047 if (devpriv->ui_AiScanLength & 1)
1052 } else { /* isn't output buff smaller that our DMA buff? */
1053 if (dmalen0 > (devpriv->ui_AiDataLength)) {
1054 dmalen0 = devpriv->ui_AiDataLength;
1056 if (dmalen1 > (devpriv->ui_AiDataLength)) {
1057 dmalen1 = devpriv->ui_AiDataLength;
1060 devpriv->ui_DmaBufferUsesize[0] = dmalen0;
1061 devpriv->ui_DmaBufferUsesize[1] = dmalen1;
1063 /* Initialize DMA */
1066 * Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS
1069 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1070 outl(ui_Tmp, devpriv->i_IobaseAmcc + AMCC_OP_REG_AGCSTS);
1072 /* changed since 16 bit interface for add on */
1073 /*********************/
1074 /* ENABLE BUS MASTER */
1075 /*********************/
1076 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1077 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1078 devpriv->i_IobaseAddon + 2);
1080 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1081 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH,
1082 devpriv->i_IobaseAddon + 2);
1085 * TO VERIFIED BEGIN JK 07.05.04: Comparison between WIN32 and Linux
1088 outw(0x1000, devpriv->i_IobaseAddon + 2);
1089 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1092 /* A2P FIFO MANAGEMENT */
1093 /* A2P fifo reset & transfer control enable */
1095 /***********************/
1096 /* A2P FIFO MANAGEMENT */
1097 /***********************/
1098 outl(APCI3120_A2P_FIFO_MANAGEMENT, devpriv->i_IobaseAmcc +
1099 APCI3120_AMCC_OP_MCSR);
1103 * beginning address of dma buf The 32 bit address of dma buffer
1104 * is converted into two 16 bit addresses Can done by using _attach
1105 * and put into into an array array used may be for differnet pages
1108 /* DMA Start Adress Low */
1109 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1110 outw((devpriv->ul_DmaBufferHw[0] & 0xFFFF),
1111 devpriv->i_IobaseAddon + 2);
1113 /*************************/
1114 /* DMA Start Adress High */
1115 /*************************/
1116 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1117 outw((devpriv->ul_DmaBufferHw[0] / 65536),
1118 devpriv->i_IobaseAddon + 2);
1122 * amount of bytes to be transfered set transfer count used ADDON
1123 * MWTC register commented testing
1124 * outl(devpriv->ui_DmaBufferUsesize[0],
1125 * devpriv->i_IobaseAddon+AMCC_OP_REG_AMWTC);
1128 /**************************/
1129 /* Nbr of acquisition LOW */
1130 /**************************/
1131 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1132 outw((devpriv->ui_DmaBufferUsesize[0] & 0xFFFF),
1133 devpriv->i_IobaseAddon + 2);
1135 /***************************/
1136 /* Nbr of acquisition HIGH */
1137 /***************************/
1138 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1139 outw((devpriv->ui_DmaBufferUsesize[0] / 65536),
1140 devpriv->i_IobaseAddon + 2);
1144 * To configure A2P FIFO testing outl(
1145 * FIFO_ADVANCE_ON_BYTE_2,devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR);
1148 /******************/
1149 /* A2P FIFO RESET */
1150 /******************/
1152 * TO VERIFY BEGIN JK 07.05.04: Comparison between WIN32 and Linux
1155 outl(0x04000000UL, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
1156 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1160 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN AMWEN_ENABLE |
1161 * A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1164 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1165 /* outw(3,devpriv->i_IobaseAddon + 4); */
1166 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1170 * initialise end of dma interrupt AINT_WRITE_COMPL =
1171 * ENABLE_WRITE_TC_INT(ADDI)
1173 /***************************************************/
1174 /* A2P FIFO CONFIGURATE, END OF DMA intERRUPT INIT */
1175 /***************************************************/
1176 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1177 APCI3120_ENABLE_WRITE_TC_INT),
1178 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1180 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1181 /******************************************/
1182 /* ENABLE A2P FIFO WRITE AND ENABLE AMWEN */
1183 /******************************************/
1184 outw(3, devpriv->i_IobaseAddon + 4);
1185 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1187 /******************/
1188 /* A2P FIFO RESET */
1189 /******************/
1190 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1192 devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_MCSR);
1193 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1196 if ((devpriv->us_UseDma == APCI3120_DISABLE)
1197 && !devpriv->b_AiContinuous) {
1198 /* set gate 2 to start conversion */
1199 devpriv->us_OutputRegister =
1200 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER2;
1201 outw(devpriv->us_OutputRegister,
1202 dev->iobase + APCI3120_WR_ADDRESS);
1207 /* set gate 0 to start conversion */
1208 devpriv->us_OutputRegister =
1209 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
1210 outw(devpriv->us_OutputRegister,
1211 dev->iobase + APCI3120_WR_ADDRESS);
1214 /* set gate 0 and gate 1 */
1215 devpriv->us_OutputRegister =
1216 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER1;
1217 devpriv->us_OutputRegister =
1218 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
1219 outw(devpriv->us_OutputRegister,
1220 dev->iobase + APCI3120_WR_ADDRESS);
1230 +----------------------------------------------------------------------------+
1231 | intERNAL FUNCTIONS |
1232 +----------------------------------------------------------------------------+
1236 +----------------------------------------------------------------------------+
1237 | Function name : int i_APCI3120_Reset(struct comedi_device *dev) |
1240 +----------------------------------------------------------------------------+
1241 | Task : Hardware reset function |
1243 +----------------------------------------------------------------------------+
1244 | Input Parameters : struct comedi_device *dev |
1247 +----------------------------------------------------------------------------+
1250 +----------------------------------------------------------------------------+
1253 int i_APCI3120_Reset(struct comedi_device * dev)
1256 unsigned short us_TmpValue;
1258 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1259 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1260 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1261 devpriv->ui_EocEosConversionTime = 0; /* set eoc eos conv time to 0 */
1262 devpriv->b_OutputMemoryStatus = 0;
1264 /* variables used in timer subdevice */
1265 devpriv->b_Timer2Mode = 0;
1266 devpriv->b_Timer2Interrupt = 0;
1267 devpriv->b_ExttrigEnable = 0; /* Disable ext trigger */
1269 /* Disable all interrupts, watchdog for the anolog output */
1270 devpriv->b_ModeSelectRegister = 0;
1271 outb(devpriv->b_ModeSelectRegister,
1272 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1274 /* Disables all counters, ext trigger and clears PA, PR */
1275 devpriv->us_OutputRegister = 0;
1276 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1279 * Code to set the all anolog o/p channel to 0v 8191 is decimal
1280 * value for zero(0 v)volt in bipolar mode(default)
1282 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_1, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 1 */
1283 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_2, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 2 */
1284 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_3, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 3 */
1285 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_4, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 4 */
1287 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_5, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 5 */
1288 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_6, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 6 */
1289 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_7, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 7 */
1290 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_8, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 8 */
1292 /* Reset digital output to L0W */
1294 /* ES05 outb(0x0,dev->iobase+APCI3120_DIGITAL_OUTPUT); */
1297 inw(dev->iobase + 0); /* make a dummy read */
1298 inb(dev->iobase + APCI3120_RESET_FIFO); /* flush FIFO */
1299 inw(dev->iobase + APCI3120_RD_STATUS); /* flush A/D status register */
1301 /* code to reset the RAM sequence */
1302 for (i = 0; i < 16; i++) {
1303 us_TmpValue = i << 8; /* select the location */
1304 outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
1310 +----------------------------------------------------------------------------+
1311 | Function name : int i_APCI3120_SetupChannelList(struct comedi_device * dev, |
1312 | struct comedi_subdevice * s, int n_chan,unsigned int *chanlist|
1315 +----------------------------------------------------------------------------+
1316 | Task :This function will first check channel list is ok or not|
1317 |and then initialize the sequence RAM with the polarity, Gain,Channel number |
1318 |If the last argument of function "check"is 1 then it only checks the channel|
1319 |list is ok or not. |
1321 +----------------------------------------------------------------------------+
1322 | Input Parameters : struct comedi_device * dev |
1323 | struct comedi_subdevice * s |
1325 unsigned int *chanlist
1327 +----------------------------------------------------------------------------+
1330 +----------------------------------------------------------------------------+
1333 int i_APCI3120_SetupChannelList(struct comedi_device * dev, struct comedi_subdevice * s,
1334 int n_chan, unsigned int *chanlist, char check)
1336 unsigned int i; /* , differencial=0, bipolar=0; */
1338 unsigned short us_TmpValue;
1340 /* correct channel and range number check itself comedi/range.c */
1343 comedi_error(dev, "range/channel list is empty!");
1346 /* All is ok, so we can setup channel/range list */
1350 /* Code to set the PA and PR...Here it set PA to 0.. */
1351 devpriv->us_OutputRegister =
1352 devpriv->us_OutputRegister & APCI3120_CLEAR_PA_PR;
1353 devpriv->us_OutputRegister = ((n_chan - 1) & 0xf) << 8;
1354 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1356 for (i = 0; i < n_chan; i++) {
1357 /* store range list to card */
1358 us_TmpValue = CR_CHAN(chanlist[i]); /* get channel number; */
1360 if (CR_RANGE(chanlist[i]) < APCI3120_BIPOLAR_RANGES) {
1361 us_TmpValue &= ((~APCI3120_UNIPOLAR) & 0xff); /* set bipolar */
1363 us_TmpValue |= APCI3120_UNIPOLAR; /* enable unipolar...... */
1366 gain = CR_RANGE(chanlist[i]); /* get gain number */
1367 us_TmpValue |= ((gain & 0x03) << 4); /* <<4 for G0 and G1 bit in RAM */
1368 us_TmpValue |= i << 8; /* To select the RAM LOCATION.... */
1369 outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
1371 printk("\n Gain = %i",
1372 (((unsigned char)CR_RANGE(chanlist[i]) & 0x03) << 2));
1373 printk("\n Channel = %i", CR_CHAN(chanlist[i]));
1374 printk("\n Polarity = %i", us_TmpValue & APCI3120_UNIPOLAR);
1376 return 1; /* we can serve this with scan logic */
1380 +----------------------------------------------------------------------------+
1381 | Function name : int i_APCI3120_ExttrigEnable(struct comedi_device * dev) |
1384 +----------------------------------------------------------------------------+
1385 | Task : Enable the external trigger |
1387 +----------------------------------------------------------------------------+
1388 | Input Parameters : struct comedi_device * dev |
1391 +----------------------------------------------------------------------------+
1392 | Return Value : 0 |
1394 +----------------------------------------------------------------------------+
1397 int i_APCI3120_ExttrigEnable(struct comedi_device * dev)
1400 devpriv->us_OutputRegister |= APCI3120_ENABLE_EXT_TRIGGER;
1401 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1406 +----------------------------------------------------------------------------+
1407 | Function name : int i_APCI3120_ExttrigDisable(struct comedi_device * dev) |
1409 +----------------------------------------------------------------------------+
1410 | Task : Disables the external trigger |
1412 +----------------------------------------------------------------------------+
1413 | Input Parameters : struct comedi_device * dev |
1416 +----------------------------------------------------------------------------+
1417 | Return Value : 0 |
1419 +----------------------------------------------------------------------------+
1422 int i_APCI3120_ExttrigDisable(struct comedi_device * dev)
1424 devpriv->us_OutputRegister &= ~APCI3120_ENABLE_EXT_TRIGGER;
1425 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1430 +----------------------------------------------------------------------------+
1431 | intERRUPT FUNCTIONS |
1432 +----------------------------------------------------------------------------+
1436 +----------------------------------------------------------------------------+
1437 | Function name : void v_APCI3120_Interrupt(int irq, void *d) |
1440 +----------------------------------------------------------------------------+
1441 | Task :Interrupt handler for APCI3120 |
1442 | When interrupt occurs this gets called. |
1443 | First it finds which interrupt has been generated and |
1444 | handles corresponding interrupt |
1446 +----------------------------------------------------------------------------+
1447 | Input Parameters : int irq |
1450 +----------------------------------------------------------------------------+
1451 | Return Value : void |
1453 +----------------------------------------------------------------------------+
1456 void v_APCI3120_Interrupt(int irq, void *d)
1458 struct comedi_device *dev = d;
1459 unsigned short int_daq;
1461 unsigned int int_amcc, ui_Check, i;
1462 unsigned short us_TmpValue;
1463 unsigned char b_DummyRead;
1465 struct comedi_subdevice *s = dev->subdevices + 0;
1468 int_daq = inw(dev->iobase + APCI3120_RD_STATUS) & 0xf000; /* get IRQ reasons */
1469 int_amcc = inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); /* get AMCC int register */
1471 if ((!int_daq) && (!(int_amcc & ANY_S593X_INT))) {
1472 comedi_error(dev, "IRQ from unknow source");
1476 outl(int_amcc | 0x00ff0000, devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); /* shutdown IRQ reasons in AMCC */
1478 int_daq = (int_daq >> 12) & 0xF;
1480 if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) {
1481 /* Disable ext trigger */
1482 i_APCI3120_ExttrigDisable(dev);
1483 devpriv->b_ExttrigEnable = APCI3120_DISABLE;
1485 /* clear the timer 2 interrupt */
1486 inb(devpriv->i_IobaseAmcc + APCI3120_TIMER_STATUS_REGISTER);
1488 if (int_amcc & MASTER_ABORT_INT)
1489 comedi_error(dev, "AMCC IRQ - MASTER DMA ABORT!");
1490 if (int_amcc & TARGET_ABORT_INT)
1491 comedi_error(dev, "AMCC IRQ - TARGET DMA ABORT!");
1493 /* Ckeck if EOC interrupt */
1494 if (((int_daq & 0x8) == 0)
1495 && (devpriv->b_InterruptMode == APCI3120_EOC_MODE)) {
1496 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
1498 /* Read the AI Value */
1500 devpriv->ui_AiReadData[0] =
1501 (unsigned int) inw(devpriv->iobase + 0);
1502 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1503 send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
1505 /* Disable EOC Interrupt */
1506 devpriv->b_ModeSelectRegister =
1508 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT;
1509 outb(devpriv->b_ModeSelectRegister,
1510 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
1515 /* Check If EOS interrupt */
1516 if ((int_daq & 0x2) && (devpriv->b_InterruptMode == APCI3120_EOS_MODE)) {
1518 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) /* enable this in without DMA ??? */
1521 if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
1523 i_APCI3120_InterruptHandleEos(dev);
1524 devpriv->ui_AiActualScan++;
1525 devpriv->b_ModeSelectRegister =
1527 b_ModeSelectRegister |
1528 APCI3120_ENABLE_EOS_INT;
1529 outb(devpriv->b_ModeSelectRegister,
1531 APCI3120_WRITE_MODE_SELECT);
1534 for (i = 0; i < devpriv->ui_AiNbrofChannels;
1536 us_TmpValue = inw(devpriv->iobase + 0);
1537 devpriv->ui_AiReadData[i] =
1538 (unsigned int) us_TmpValue;
1540 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1541 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1543 send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
1548 devpriv->b_ModeSelectRegister =
1550 b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
1551 outb(devpriv->b_ModeSelectRegister,
1552 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1553 devpriv->b_EocEosInterrupt = APCI3120_DISABLE; /* Default settings */
1554 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1558 /* Timer2 interrupt */
1559 if (int_daq & 0x1) {
1561 switch (devpriv->b_Timer2Mode) {
1562 case APCI3120_COUNTER:
1564 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1565 devpriv->b_ModeSelectRegister =
1567 b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
1568 outb(devpriv->b_ModeSelectRegister,
1569 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1572 devpriv->us_OutputRegister =
1574 us_OutputRegister & APCI3120_DISABLE_ALL_TIMER;
1575 outw(devpriv->us_OutputRegister,
1576 dev->iobase + APCI3120_WR_ADDRESS);
1578 /* stop timer 0 and timer 1 */
1579 i_APCI3120_StopCyclicAcquisition(dev, s);
1580 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1582 /* UPDATE-0.7.57->0.7.68comedi_done(dev,s); */
1583 s->async->events |= COMEDI_CB_EOA;
1584 comedi_event(dev, s);
1588 case APCI3120_TIMER:
1590 /* Send a signal to from kernel to user space */
1591 send_sig(SIGIO, devpriv->tsk_Current, 0);
1594 case APCI3120_WATCHDOG:
1596 /* Send a signal to from kernel to user space */
1597 send_sig(SIGIO, devpriv->tsk_Current, 0);
1602 /* disable Timer Interrupt */
1604 devpriv->b_ModeSelectRegister =
1606 b_ModeSelectRegister &
1607 APCI3120_DISABLE_TIMER_INT;
1609 outb(devpriv->b_ModeSelectRegister,
1610 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1614 b_DummyRead = inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1618 if ((int_daq & 0x4) && (devpriv->b_InterruptMode == APCI3120_DMA_MODE)) {
1619 if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
1621 /****************************/
1622 /* Clear Timer Write TC int */
1623 /****************************/
1625 outl(APCI3120_CLEAR_WRITE_TC_INT,
1626 devpriv->i_IobaseAmcc +
1627 APCI3120_AMCC_OP_REG_INTCSR);
1629 /************************************/
1630 /* Clears the timer status register */
1631 /************************************/
1632 inw(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1633 v_APCI3120_InterruptDma(irq, d); /* do some data transfer */
1635 /* Stops the Timer */
1637 us_OutputRegister & APCI3120_DISABLE_TIMER0 &
1638 APCI3120_DISABLE_TIMER1,
1639 dev->iobase + APCI3120_WR_ADDRESS);
1648 +----------------------------------------------------------------------------+
1649 | Function name :int i_APCI3120_InterruptHandleEos(struct comedi_device *dev) |
1652 +----------------------------------------------------------------------------+
1653 | Task : This function handles EOS interrupt. |
1654 | This function copies the acquired data(from FIFO) |
1655 | to Comedi buffer. |
1657 +----------------------------------------------------------------------------+
1658 | Input Parameters : struct comedi_device *dev |
1661 +----------------------------------------------------------------------------+
1662 | Return Value : 0 |
1664 +----------------------------------------------------------------------------+
1668 int i_APCI3120_InterruptHandleEos(struct comedi_device * dev)
1671 struct comedi_subdevice *s = dev->subdevices + 0;
1674 n_chan = devpriv->ui_AiNbrofChannels;
1676 s->async->events = 0;
1678 for (i = 0; i < n_chan; i++)
1679 err &= comedi_buf_put(s->async, inw(dev->iobase + 0));
1681 s->async->events |= COMEDI_CB_EOS;
1684 s->async->events |= COMEDI_CB_OVERFLOW;
1686 comedi_event(dev, s);
1692 +----------------------------------------------------------------------------+
1693 | Function name : void v_APCI3120_InterruptDma(int irq, void *d) |
1695 +----------------------------------------------------------------------------+
1696 | Task : This is a handler for the DMA interrupt |
1697 | This function copies the data to Comedi Buffer. |
1698 | For continuous DMA it reinitializes the DMA operation. |
1699 | For single mode DMA it stop the acquisition. |
1701 +----------------------------------------------------------------------------+
1702 | Input Parameters : int irq, void *d |
1704 +----------------------------------------------------------------------------+
1705 | Return Value : void |
1707 +----------------------------------------------------------------------------+
1710 void v_APCI3120_InterruptDma(int irq, void *d)
1712 struct comedi_device *dev = d;
1713 struct comedi_subdevice *s = dev->subdevices + 0;
1714 unsigned int next_dma_buf, samplesinbuf;
1715 unsigned long low_word, high_word, var;
1717 unsigned int ui_Tmp;
1719 devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer] -
1720 inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_MWTC);
1723 devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer]) {
1724 comedi_error(dev, "Interrupted DMA transfer!");
1726 if (samplesinbuf & 1) {
1727 comedi_error(dev, "Odd count of bytes in DMA ring!");
1728 i_APCI3120_StopCyclicAcquisition(dev, s);
1729 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1733 samplesinbuf = samplesinbuf >> 1; /* number of received samples */
1734 if (devpriv->b_DmaDoubleBuffer) {
1735 /* switch DMA buffers if is used double buffering */
1736 next_dma_buf = 1 - devpriv->ui_DmaActualBuffer;
1738 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1739 outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
1741 /* changed since 16 bit interface for add on */
1742 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1743 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1744 devpriv->i_IobaseAddon + 2);
1745 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1746 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); /* 0x1000 is out putted in windows driver */
1748 var = devpriv->ul_DmaBufferHw[next_dma_buf];
1749 low_word = var & 0xffff;
1750 var = devpriv->ul_DmaBufferHw[next_dma_buf];
1751 high_word = var / 65536;
1753 /* DMA Start Adress Low */
1754 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1755 outw(low_word, devpriv->i_IobaseAddon + 2);
1757 /* DMA Start Adress High */
1758 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1759 outw(high_word, devpriv->i_IobaseAddon + 2);
1761 var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
1762 low_word = var & 0xffff;
1763 var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
1764 high_word = var / 65536;
1766 /* Nbr of acquisition LOW */
1767 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1768 outw(low_word, devpriv->i_IobaseAddon + 2);
1770 /* Nbr of acquisition HIGH */
1771 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1772 outw(high_word, devpriv->i_IobaseAddon + 2);
1775 * To configure A2P FIFO
1776 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1777 * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1779 outw(3, devpriv->i_IobaseAddon + 4);
1780 /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
1781 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1782 APCI3120_ENABLE_WRITE_TC_INT),
1783 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1787 v_APCI3120_InterruptDmaMoveBlock16bit(dev, s,
1788 devpriv->ul_DmaBufferVirtual[devpriv->
1789 ui_DmaActualBuffer], samplesinbuf);
1791 if (!(devpriv->ui_AiFlags & TRIG_WAKE_EOS)) {
1792 s->async->events |= COMEDI_CB_EOS;
1793 comedi_event(dev, s);
1796 if (!devpriv->b_AiContinuous)
1797 if (devpriv->ui_AiActualScan >= devpriv->ui_AiNbrofScans) {
1798 /* all data sampled */
1799 i_APCI3120_StopCyclicAcquisition(dev, s);
1800 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1801 s->async->events |= COMEDI_CB_EOA;
1802 comedi_event(dev, s);
1806 if (devpriv->b_DmaDoubleBuffer) { /* switch dma buffers */
1807 devpriv->ui_DmaActualBuffer = 1 - devpriv->ui_DmaActualBuffer;
1810 * restart DMA if is not used double buffering
1811 * ADDED REINITIALISE THE DMA
1813 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1814 outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
1816 /* changed since 16 bit interface for add on */
1817 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1818 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1819 devpriv->i_IobaseAddon + 2);
1820 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1821 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); /* */
1823 * A2P FIFO MANAGEMENT
1824 * A2P fifo reset & transfer control enable
1826 outl(APCI3120_A2P_FIFO_MANAGEMENT,
1827 devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
1829 var = devpriv->ul_DmaBufferHw[0];
1830 low_word = var & 0xffff;
1831 var = devpriv->ul_DmaBufferHw[0];
1832 high_word = var / 65536;
1833 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1834 outw(low_word, devpriv->i_IobaseAddon + 2);
1835 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1836 outw(high_word, devpriv->i_IobaseAddon + 2);
1838 var = devpriv->ui_DmaBufferUsesize[0];
1839 low_word = var & 0xffff; /* changed */
1840 var = devpriv->ui_DmaBufferUsesize[0];
1841 high_word = var / 65536;
1842 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1843 outw(low_word, devpriv->i_IobaseAddon + 2);
1844 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1845 outw(high_word, devpriv->i_IobaseAddon + 2);
1848 * To configure A2P FIFO
1849 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1850 * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1852 outw(3, devpriv->i_IobaseAddon + 4);
1853 /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
1854 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1855 APCI3120_ENABLE_WRITE_TC_INT),
1856 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1861 +----------------------------------------------------------------------------+
1862 | Function name :void v_APCI3120_InterruptDmaMoveBlock16bit(comedi_device|
1863 |*dev,struct comedi_subdevice *s,short *dma,short *data,int n) |
1865 +----------------------------------------------------------------------------+
1866 | Task : This function copies the data from DMA buffer to the |
1869 +----------------------------------------------------------------------------+
1870 | Input Parameters : struct comedi_device *dev |
1871 | struct comedi_subdevice *s |
1873 | short *data,int n |
1874 +----------------------------------------------------------------------------+
1875 | Return Value : void |
1877 +----------------------------------------------------------------------------+
1880 void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device * dev,
1881 struct comedi_subdevice * s, short * dma_buffer, unsigned int num_samples)
1883 devpriv->ui_AiActualScan +=
1884 (s->async->cur_chan + num_samples) / devpriv->ui_AiScanLength;
1885 s->async->cur_chan += num_samples;
1886 s->async->cur_chan %= devpriv->ui_AiScanLength;
1888 cfc_write_array_to_buffer(s, dma_buffer, num_samples * sizeof(short));
1892 +----------------------------------------------------------------------------+
1894 +----------------------------------------------------------------------------+
1898 +----------------------------------------------------------------------------+
1899 | Function name :int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, |
1900 | struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
1902 +----------------------------------------------------------------------------+
1903 | Task :Configure Timer 2 |
1905 +----------------------------------------------------------------------------+
1906 | Input Parameters : struct comedi_device *dev |
1907 | struct comedi_subdevice *s |
1908 | struct comedi_insn *insn |
1909 | unsigned int *data |
1911 | data[0]= TIMER configure as timer |
1912 | = WATCHDOG configure as watchdog |
1913 | data[1] = Timer constant |
1914 | data[2] = Timer2 interrupt (1)enable or(0) disable |
1916 +----------------------------------------------------------------------------+
1919 +----------------------------------------------------------------------------+
1922 int i_APCI3120_InsnConfigTimer(struct comedi_device * dev, struct comedi_subdevice * s,
1923 struct comedi_insn * insn, unsigned int * data)
1926 unsigned int ui_Timervalue2;
1927 unsigned short us_TmpValue;
1928 unsigned char b_Tmp;
1931 comedi_error(dev, "config:No timer constant !");
1933 devpriv->b_Timer2Interrupt = (unsigned char) data[2]; /* save info whether to enable or disable interrupt */
1935 ui_Timervalue2 = data[1] / 1000; /* convert nano seconds to u seconds */
1937 /* this_board->i_hwdrv_InsnConfigTimer(dev, ui_Timervalue2,(unsigned char)data[0]); */
1938 us_TmpValue = (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
1941 * EL250804: Testing if board APCI3120 have the new Quartz or if it
1942 * is an APCI3001 and calculate the time value to set in the timer
1944 if ((us_TmpValue & 0x00B0) == 0x00B0
1945 || !strcmp(this_board->pc_DriverName, "apci3001")) {
1946 /* Calculate the time value to set in the timer */
1947 ui_Timervalue2 = ui_Timervalue2 / 50;
1949 /* Calculate the time value to set in the timer */
1950 ui_Timervalue2 = ui_Timervalue2 / 70;
1953 /* Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0) */
1954 devpriv->us_OutputRegister =
1955 devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER2;
1956 outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS);
1958 /* Disable TIMER Interrupt */
1959 devpriv->b_ModeSelectRegister =
1961 b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT & 0xEF;
1963 /* Disable Eoc and Eos Interrupts */
1964 devpriv->b_ModeSelectRegister =
1966 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT &
1967 APCI3120_DISABLE_EOS_INT;
1968 outb(devpriv->b_ModeSelectRegister,
1969 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
1970 if (data[0] == APCI3120_TIMER) /* initialize timer */
1972 /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister |
1973 * APCI3120_ENABLE_TIMER_INT; */
1975 /* outb(devpriv->b_ModeSelectRegister,devpriv->iobase+APCI3120_WRITE_MODE_SELECT); */
1977 /* Set the Timer 2 in mode 2(Timer) */
1978 devpriv->b_TimerSelectMode =
1980 b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_2;
1981 outb(devpriv->b_TimerSelectMode,
1982 devpriv->iobase + APCI3120_TIMER_CRT1);
1985 * Configure the timer 2 for writing the LOW unsigned short of timer
1986 * is Delay value You must make a b_tmp variable with
1987 * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
1988 * you can set the digital output and configure the timer 2,and if
1989 * you don't make this, digital output are erase (Set to 0)
1992 /* Writing LOW unsigned short */
1994 b_DigitalOutputRegister) & 0xF0) |
1995 APCI3120_SELECT_TIMER_2_LOW_WORD;
1996 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1997 outw(LOWORD(ui_Timervalue2),
1998 devpriv->iobase + APCI3120_TIMER_VALUE);
2000 /* Writing HIGH unsigned short */
2002 b_DigitalOutputRegister) & 0xF0) |
2003 APCI3120_SELECT_TIMER_2_HIGH_WORD;
2004 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2005 outw(HIWORD(ui_Timervalue2),
2006 devpriv->iobase + APCI3120_TIMER_VALUE);
2007 /* timer2 in Timer mode enabled */
2008 devpriv->b_Timer2Mode = APCI3120_TIMER;
2010 } else /* Initialize Watch dog */
2013 /* Set the Timer 2 in mode 5(Watchdog) */
2015 devpriv->b_TimerSelectMode =
2017 b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_5;
2018 outb(devpriv->b_TimerSelectMode,
2019 devpriv->iobase + APCI3120_TIMER_CRT1);
2022 * Configure the timer 2 for writing the LOW unsigned short of timer
2023 * is Delay value You must make a b_tmp variable with
2024 * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
2025 * you can set the digital output and configure the timer 2,and if
2026 * you don't make this, digital output are erase (Set to 0)
2029 /* Writing LOW unsigned short */
2031 b_DigitalOutputRegister) & 0xF0) |
2032 APCI3120_SELECT_TIMER_2_LOW_WORD;
2033 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2034 outw(LOWORD(ui_Timervalue2),
2035 devpriv->iobase + APCI3120_TIMER_VALUE);
2037 /* Writing HIGH unsigned short */
2039 b_DigitalOutputRegister) & 0xF0) |
2040 APCI3120_SELECT_TIMER_2_HIGH_WORD;
2041 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2043 outw(HIWORD(ui_Timervalue2),
2044 devpriv->iobase + APCI3120_TIMER_VALUE);
2045 /* watchdog enabled */
2046 devpriv->b_Timer2Mode = APCI3120_WATCHDOG;
2055 +----------------------------------------------------------------------------+
2056 | Function name :int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, |
2057 | struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
2059 +----------------------------------------------------------------------------+
2060 | Task : To start and stop the timer |
2061 +----------------------------------------------------------------------------+
2062 | Input Parameters : struct comedi_device *dev |
2063 | struct comedi_subdevice *s |
2064 | struct comedi_insn *insn |
2065 | unsigned int *data |
2067 | data[0] = 1 (start) |
2068 | data[0] = 0 (stop ) |
2069 | data[0] = 2 (write new value) |
2070 | data[1]= new value |
2072 | devpriv->b_Timer2Mode = 0 DISABLE |
2076 +----------------------------------------------------------------------------+
2079 +----------------------------------------------------------------------------+
2082 int i_APCI3120_InsnWriteTimer(struct comedi_device * dev, struct comedi_subdevice * s,
2083 struct comedi_insn * insn, unsigned int * data)
2086 unsigned int ui_Timervalue2 = 0;
2087 unsigned short us_TmpValue;
2088 unsigned char b_Tmp;
2090 if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
2091 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
2092 comedi_error(dev, "\nwrite:timer2 not configured ");
2096 if (data[0] == 2) /* write new value */
2098 if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
2100 "write :timer2 not configured in TIMER MODE");
2105 ui_Timervalue2 = data[1];
2110 /* this_board->i_hwdrv_InsnWriteTimer(dev,data[0],ui_Timervalue2); */
2113 case APCI3120_START:
2115 /* Reset FC_TIMER BIT */
2116 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2117 if (devpriv->b_Timer2Mode == APCI3120_TIMER) /* start timer */
2120 devpriv->b_ModeSelectRegister =
2121 devpriv->b_ModeSelectRegister & 0x0B;
2122 } else /* start watch dog */
2124 /* Enable WatchDog */
2125 devpriv->b_ModeSelectRegister =
2127 b_ModeSelectRegister & 0x0B) |
2128 APCI3120_ENABLE_WATCHDOG;
2131 /* enable disable interrupt */
2132 if ((devpriv->b_Timer2Interrupt) == APCI3120_ENABLE) {
2134 devpriv->b_ModeSelectRegister =
2136 b_ModeSelectRegister |
2137 APCI3120_ENABLE_TIMER_INT;
2138 /* save the task structure to pass info to user */
2139 devpriv->tsk_Current = current;
2142 devpriv->b_ModeSelectRegister =
2144 b_ModeSelectRegister &
2145 APCI3120_DISABLE_TIMER_INT;
2147 outb(devpriv->b_ModeSelectRegister,
2148 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
2150 if (devpriv->b_Timer2Mode == APCI3120_TIMER) /* start timer */
2152 /* For Timer mode is Gate2 must be activated **timer started */
2153 devpriv->us_OutputRegister =
2155 us_OutputRegister | APCI3120_ENABLE_TIMER2;
2156 outw(devpriv->us_OutputRegister,
2157 devpriv->iobase + APCI3120_WR_ADDRESS);
2163 if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
2165 devpriv->b_ModeSelectRegister =
2167 b_ModeSelectRegister &
2168 APCI3120_DISABLE_TIMER_COUNTER;
2170 /* Disable WatchDog */
2171 devpriv->b_ModeSelectRegister =
2173 b_ModeSelectRegister &
2174 APCI3120_DISABLE_WATCHDOG;
2176 /* Disable timer interrupt */
2177 devpriv->b_ModeSelectRegister =
2179 b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT;
2181 /* Write above states to register */
2182 outb(devpriv->b_ModeSelectRegister,
2183 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
2186 devpriv->us_OutputRegister =
2187 devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER_INT;
2188 outw(devpriv->us_OutputRegister,
2189 devpriv->iobase + APCI3120_WR_ADDRESS);
2191 /* Reset FC_TIMER BIT */
2192 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2195 /* devpriv->b_Timer2Mode=APCI3120_DISABLE; */
2199 case 2: /* write new value to Timer */
2200 if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
2202 "write :timer2 not configured in TIMER MODE");
2205 /* ui_Timervalue2=data[1]; // passed as argument */
2207 (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
2210 * EL250804: Testing if board APCI3120 have the new Quartz or if it
2211 * is an APCI3001 and calculate the time value to set in the timer
2213 if ((us_TmpValue & 0x00B0) == 0x00B0
2214 || !strcmp(this_board->pc_DriverName, "apci3001")) {
2215 /* Calculate the time value to set in the timer */
2216 ui_Timervalue2 = ui_Timervalue2 / 50;
2218 /* Calculate the time value to set in the timer */
2219 ui_Timervalue2 = ui_Timervalue2 / 70;
2221 /* Writing LOW unsigned short */
2223 b_DigitalOutputRegister) & 0xF0) |
2224 APCI3120_SELECT_TIMER_2_LOW_WORD;
2225 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2227 outw(LOWORD(ui_Timervalue2),
2228 devpriv->iobase + APCI3120_TIMER_VALUE);
2230 /* Writing HIGH unsigned short */
2232 b_DigitalOutputRegister) & 0xF0) |
2233 APCI3120_SELECT_TIMER_2_HIGH_WORD;
2234 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2236 outw(HIWORD(ui_Timervalue2),
2237 devpriv->iobase + APCI3120_TIMER_VALUE);
2241 return -EINVAL; /* Not a valid input */
2248 +----------------------------------------------------------------------------+
2249 | Function name : int i_APCI3120_InsnReadTimer(struct comedi_device *dev, |
2250 | struct comedi_subdevice *s,struct comedi_insn *insn, unsigned int *data) |
2253 +----------------------------------------------------------------------------+
2254 | Task : read the Timer value |
2255 +----------------------------------------------------------------------------+
2256 | Input Parameters : struct comedi_device *dev |
2257 | struct comedi_subdevice *s |
2258 | struct comedi_insn *insn |
2259 | unsigned int *data |
2261 +----------------------------------------------------------------------------+
2263 | for Timer: data[0]= Timer constant |
2265 | for watchdog: data[0]=0 (still running) |
2266 | data[0]=1 (run down) |
2268 +----------------------------------------------------------------------------+
2270 int i_APCI3120_InsnReadTimer(struct comedi_device * dev, struct comedi_subdevice * s,
2271 struct comedi_insn * insn, unsigned int * data)
2273 unsigned char b_Tmp;
2274 unsigned short us_TmpValue, us_TmpValue_2, us_StatusValue;
2276 if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
2277 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
2278 comedi_error(dev, "\nread:timer2 not configured ");
2281 /* this_board->i_hwdrv_InsnReadTimer(dev,data); */
2282 if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
2284 /* Read the LOW unsigned short of Timer 2 register */
2286 b_DigitalOutputRegister) & 0xF0) |
2287 APCI3120_SELECT_TIMER_2_LOW_WORD;
2288 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2290 us_TmpValue = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
2292 /* Read the HIGH unsigned short of Timer 2 register */
2294 b_DigitalOutputRegister) & 0xF0) |
2295 APCI3120_SELECT_TIMER_2_HIGH_WORD;
2296 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2298 us_TmpValue_2 = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
2300 /* combining both words */
2301 data[0] = (unsigned int) ((us_TmpValue) | ((us_TmpValue_2) << 16));
2303 } else /* Read watch dog status */
2306 us_StatusValue = inw(devpriv->iobase + APCI3120_RD_STATUS);
2308 ((us_StatusValue & APCI3120_FC_TIMER) >> 12) & 1;
2309 if (us_StatusValue == 1) {
2310 /* RESET FC_TIMER BIT */
2311 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2313 data[0] = us_StatusValue; /* when data[0] = 1 then the watch dog has rundown */
2319 +----------------------------------------------------------------------------+
2320 | DIGITAL INPUT SUBDEVICE |
2321 +----------------------------------------------------------------------------+
2325 +----------------------------------------------------------------------------+
2326 | Function name :int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev, |
2327 | struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
2330 +----------------------------------------------------------------------------+
2331 | Task : Reads the value of the specified Digital input channel|
2333 +----------------------------------------------------------------------------+
2334 | Input Parameters : struct comedi_device *dev |
2335 | struct comedi_subdevice *s |
2336 | struct comedi_insn *insn |
2337 | unsigned int *data |
2338 +----------------------------------------------------------------------------+
2341 +----------------------------------------------------------------------------+
2344 int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev,
2345 struct comedi_subdevice *s,
2346 struct comedi_insn *insn,
2349 unsigned int ui_Chan, ui_TmpValue;
2351 ui_Chan = CR_CHAN(insn->chanspec); /* channel specified */
2353 /* this_board->i_hwdrv_InsnReadDigitalInput(dev,ui_Chan,data); */
2354 if (ui_Chan >= 0 && ui_Chan <= 3) {
2355 ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI3120_RD_STATUS);
2358 * since only 1 channel reqd to bring it to last bit it is rotated 8
2359 * +(chan - 1) times then ANDed with 1 for last bit.
2361 *data = (ui_TmpValue >> (ui_Chan + 8)) & 1;
2364 /* comedi_error(dev," chan spec wrong"); */
2365 return -EINVAL; /* "sorry channel spec wrong " */
2372 +----------------------------------------------------------------------------+
2373 | Function name :int i_APCI3120_InsnBitsDigitalInput(struct comedi_device *dev, |
2374 |struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
2376 +----------------------------------------------------------------------------+
2377 | Task : Reads the value of the Digital input Port i.e.4channels|
2378 | value is returned in data[0] |
2380 +----------------------------------------------------------------------------+
2381 | Input Parameters : struct comedi_device *dev |
2382 | struct comedi_subdevice *s |
2383 | struct comedi_insn *insn |
2384 | unsigned int *data |
2385 +----------------------------------------------------------------------------+
2388 +----------------------------------------------------------------------------+
2390 int i_APCI3120_InsnBitsDigitalInput(struct comedi_device * dev, struct comedi_subdevice * s,
2391 struct comedi_insn * insn, unsigned int * data)
2393 unsigned int ui_TmpValue;
2394 ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI3120_RD_STATUS);
2395 /***** state of 4 channels in the 11, 10, 9, 8 bits of status reg
2396 rotated right 8 times to bring them to last four bits
2397 ANDed with oxf for value.
2400 *data = (ui_TmpValue >> 8) & 0xf;
2401 /* this_board->i_hwdrv_InsnBitsDigitalInput(dev,data); */
2406 +----------------------------------------------------------------------------+
2407 | DIGITAL OUTPUT SUBDEVICE |
2408 +----------------------------------------------------------------------------+
2411 +----------------------------------------------------------------------------+
2412 | Function name :int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device |
2413 | *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
2415 +----------------------------------------------------------------------------+
2416 | Task :Configure the output memory ON or OFF |
2418 +----------------------------------------------------------------------------+
2419 | Input Parameters :struct comedi_device *dev |
2420 | struct comedi_subdevice *s |
2421 | struct comedi_insn *insn |
2422 | unsigned int *data |
2423 +----------------------------------------------------------------------------+
2426 +----------------------------------------------------------------------------+
2429 int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device * dev,
2430 struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
2433 if ((data[0] != 0) && (data[0] != 1)) {
2435 "Not a valid Data !!! ,Data should be 1 or 0\n");
2439 devpriv->b_OutputMemoryStatus = APCI3120_ENABLE;
2442 devpriv->b_OutputMemoryStatus = APCI3120_DISABLE;
2443 devpriv->b_DigitalOutputRegister = 0;
2445 if (!devpriv->b_OutputMemoryStatus) {
2448 } /* if(!devpriv->b_OutputMemoryStatus ) */
2454 +----------------------------------------------------------------------------+
2455 | Function name :int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device *dev, |
2456 | struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
2458 +----------------------------------------------------------------------------+
2459 | Task : write diatal output port |
2461 +----------------------------------------------------------------------------+
2462 | Input Parameters : struct comedi_device *dev |
2463 | struct comedi_subdevice *s |
2464 | struct comedi_insn *insn |
2465 | unsigned int *data |
2466 data[0] Value to be written
2467 data[1] :1 Set digital o/p ON
2468 data[1] 2 Set digital o/p OFF with memory ON
2469 +----------------------------------------------------------------------------+
2472 +----------------------------------------------------------------------------+
2475 int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device * dev,
2476 struct comedi_subdevice *s,
2477 struct comedi_insn *insn,
2480 if ((data[0] > this_board->i_DoMaxdata) || (data[0] < 0)) {
2482 comedi_error(dev, "Data is not valid !!! \n");
2488 data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister;
2495 printk("\nThe parameter passed is in error \n");
2497 } /* switch(data[1]) */
2498 outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
2500 devpriv->b_DigitalOutputRegister = data[0] & 0xF0;
2507 +----------------------------------------------------------------------------+
2508 | Function name :int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev,|
2509 |struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
2511 +----------------------------------------------------------------------------+
2512 | Task : Write digiatl output |
2514 +----------------------------------------------------------------------------+
2515 | Input Parameters : struct comedi_device *dev |
2516 | struct comedi_subdevice *s |
2517 | struct comedi_insn *insn |
2518 | unsigned int *data |
2519 data[0] Value to be written
2520 data[1] :1 Set digital o/p ON
2521 data[1] 2 Set digital o/p OFF with memory ON
2522 +----------------------------------------------------------------------------+
2525 +----------------------------------------------------------------------------+
2528 int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev,
2529 struct comedi_subdevice *s,
2530 struct comedi_insn *insn,
2534 unsigned int ui_Temp1;
2536 unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */
2538 if ((data[0] != 0) && (data[0] != 1)) {
2540 "Not a valid Data !!! ,Data should be 1 or 0\n");
2543 if ((ui_NoOfChannel > (this_board->i_NbrDoChannel - 1))
2544 || (ui_NoOfChannel < 0)) {
2546 "This board doesn't have specified channel !!! \n");
2552 data[0] = (data[0] << ui_NoOfChannel);
2553 /* ES05 data[0]=(data[0]<<4)|ui_Temp; */
2554 data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister;
2558 data[0] = ~data[0] & 0x1;
2560 ui_Temp1 = ui_Temp1 << ui_NoOfChannel;
2561 ui_Temp1 = ui_Temp1 << 4;
2562 /* ES05 ui_Temp=ui_Temp|ui_Temp1; */
2563 devpriv->b_DigitalOutputRegister =
2564 devpriv->b_DigitalOutputRegister | ui_Temp1;
2566 data[0] = (data[0] << ui_NoOfChannel) ^ 0xf;
2567 data[0] = data[0] << 4;
2568 /* ES05 data[0]=data[0]& ui_Temp; */
2569 data[0] = data[0] & devpriv->b_DigitalOutputRegister;
2572 printk("\nThe parameter passed is in error \n");
2574 } /* switch(data[1]) */
2575 outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
2577 /* ES05 ui_Temp=data[0] & 0xf0; */
2578 devpriv->b_DigitalOutputRegister = data[0] & 0xf0;
2584 +----------------------------------------------------------------------------+
2585 | ANALOG OUTPUT SUBDEVICE |
2586 +----------------------------------------------------------------------------+
2590 +----------------------------------------------------------------------------+
2591 | Function name :int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,|
2592 |struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
2594 +----------------------------------------------------------------------------+
2595 | Task : Write analog output |
2597 +----------------------------------------------------------------------------+
2598 | Input Parameters : struct comedi_device *dev |
2599 | struct comedi_subdevice *s |
2600 | struct comedi_insn *insn |
2601 | unsigned int *data |
2602 +----------------------------------------------------------------------------+
2605 +----------------------------------------------------------------------------+
2608 int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,
2609 struct comedi_subdevice *s,
2610 struct comedi_insn *insn,
2613 unsigned int ui_Range, ui_Channel;
2614 unsigned short us_TmpValue;
2616 ui_Range = CR_RANGE(insn->chanspec);
2617 ui_Channel = CR_CHAN(insn->chanspec);
2619 /* this_board->i_hwdrv_InsnWriteAnalogOutput(dev, ui_Range, ui_Channel,data[0]); */
2620 if (ui_Range) /* if 1 then unipolar */
2625 ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
2626 13) | (data[0] + 8191));
2629 ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
2632 } else /* if 0 then bipolar */
2635 ((((ui_Channel & 0x03) << 14) & 0xC000) | (0 << 13) |
2641 * out put n values at the given channel. rt_printk("\nwaiting for
2644 do /* Waiting of DA_READY BIT */
2647 ((unsigned short) inw(devpriv->iobase +
2648 APCI3120_RD_STATUS)) & 0x0001;
2649 } while (us_TmpValue != 0x0001);
2651 if (ui_Channel <= 3)
2653 * for channel 0-3 out at the register 1 (wrDac1-8) data[i]
2654 * typecasted to ushort since word write is to be done
2656 outw((unsigned short) data[0],
2657 devpriv->iobase + APCI3120_ANALOG_OUTPUT_1);
2660 * for channel 4-7 out at the register 2 (wrDac5-8) data[i]
2661 * typecasted to ushort since word write is to be done
2663 outw((unsigned short) data[0],
2664 devpriv->iobase + APCI3120_ANALOG_OUTPUT_2);