4 Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
10 Fax: +49(0)7223/9493-92
11 http://www.addi-data-com
14 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
16 This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 You shoud also find the complete GPL in the COPYING file accompanying this source code.
25 +-----------------------------------------------------------------------+
26 | (C) ADDI-DATA GmbH Dieselstrasse 3 D-77833 Ottersweier |
27 +-----------------------------------------------------------------------+
28 | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com |
29 | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com |
30 +-----------------------------------------------------------------------+
31 | Project : APCI-3120 | Compiler : GCC |
32 | Module name : hwdrv_apci3120.c| Version : 2.96 |
33 +-------------------------------+---------------------------------------+
34 | Project manager: Eric Stolz | Date : 02/12/2002 |
35 +-----------------------------------------------------------------------+
36 | Description :APCI3120 Module. Hardware abstraction Layer for APCI3120|
37 +-----------------------------------------------------------------------+
39 +-----------------------------------------------------------------------+
40 | Date | Author | Description of updates |
41 +----------+-----------+------------------------------------------------+
44 +----------+-----------+------------------------------------------------+
47 #include "hwdrv_apci3120.h"
48 static UINT ui_Temp
= 0;
50 // FUNCTION DEFINITIONS
53 +----------------------------------------------------------------------------+
54 | ANALOG INPUT SUBDEVICE |
55 +----------------------------------------------------------------------------+
59 +----------------------------------------------------------------------------+
60 | Function name :int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev,|
61 | struct comedi_subdevice *s,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 |
70 | unsigned int *data |
71 +----------------------------------------------------------------------------+
74 +----------------------------------------------------------------------------+
77 int i_APCI3120_InsnConfigAnalogInput(struct comedi_device
* dev
, struct comedi_subdevice
* s
,
78 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,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 | comedi_insn *insn |
141 | unsigned int *data |
142 +----------------------------------------------------------------------------+
145 +----------------------------------------------------------------------------+
148 int i_APCI3120_InsnReadAnalogInput(struct comedi_device
* dev
, struct comedi_subdevice
* s
,
149 comedi_insn
* insn
, unsigned int * data
)
151 USHORT us_ConvertTiming
, us_TmpValue
, i
;
154 // fix convertion time to 10 us
155 if (!devpriv
->ui_EocEosConversionTime
) {
156 printk("No timer0 Value using 10 us\n");
157 us_ConvertTiming
= 10;
159 us_ConvertTiming
= (USHORT
) (devpriv
->ui_EocEosConversionTime
/ 1000); // nano to useconds
161 // this_board->i_hwdrv_InsnReadAnalogInput(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]);
163 // Clear software registers
164 devpriv
->b_TimerSelectMode
= 0;
165 devpriv
->b_ModeSelectRegister
= 0;
166 devpriv
->us_OutputRegister
= 0;
167 // devpriv->b_DigitalOutputRegister=0;
169 if (insn
->unused
[0] == 222) // second insn read
172 for (i
= 0; i
< insn
->n
; i
++) {
173 data
[i
] = devpriv
->ui_AiReadData
[i
];
177 devpriv
->tsk_Current
= current
; // Save the current process task structure
178 //Testing if board have the new Quartz and calculate the time value
179 //to set in the timer
182 (USHORT
) inw(devpriv
->iobase
+ APCI3120_RD_STATUS
);
184 //EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001
185 if ((us_TmpValue
& 0x00B0) == 0x00B0
186 || !strcmp(this_board
->pc_DriverName
, "apci3001")) {
187 us_ConvertTiming
= (us_ConvertTiming
* 2) - 2;
190 ((us_ConvertTiming
* 12926) / 10000) - 1;
193 us_TmpValue
= (USHORT
) devpriv
->b_InterruptMode
;
195 switch (us_TmpValue
) {
197 case APCI3120_EOC_MODE
:
199 // Testing the interrupt flag and set the EOC bit
201 inw(devpriv
->iobase
+ APCI3120_RESET_FIFO
);
203 // Initialize the sequence array
205 //if (!i_APCI3120_SetupChannelList(dev,s,1,chanlist,0)) return -EINVAL;
207 if (!i_APCI3120_SetupChannelList(dev
, s
, 1,
211 //Initialize Timer 0 mode 4
212 devpriv
->b_TimerSelectMode
=
214 b_TimerSelectMode
& 0xFC) |
215 APCI3120_TIMER_0_MODE_4
;
216 outb(devpriv
->b_TimerSelectMode
,
217 devpriv
->iobase
+ APCI3120_TIMER_CRT1
);
219 // Reset the scan bit and Disables the EOS, DMA, EOC interrupt
220 devpriv
->b_ModeSelectRegister
=
222 b_ModeSelectRegister
& APCI3120_DISABLE_SCAN
;
224 if (devpriv
->b_EocEosInterrupt
== APCI3120_ENABLE
) {
226 //Disables the EOS,DMA and enables the EOC interrupt
227 devpriv
->b_ModeSelectRegister
=
229 b_ModeSelectRegister
&
230 APCI3120_DISABLE_EOS_INT
) |
231 APCI3120_ENABLE_EOC_INT
;
232 inw(devpriv
->iobase
);
235 devpriv
->b_ModeSelectRegister
=
237 b_ModeSelectRegister
&
238 APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER
;
241 outb(devpriv
->b_ModeSelectRegister
,
242 devpriv
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
245 devpriv
->us_OutputRegister
=
247 us_OutputRegister
& APCI3120_CLEAR_PA_PR
) |
248 APCI3120_ENABLE_TIMER0
;
249 outw(devpriv
->us_OutputRegister
,
250 devpriv
->iobase
+ APCI3120_WR_ADDRESS
);
254 b_DigitalOutputRegister
) & 0xF0) |
255 APCI3120_SELECT_TIMER_0_WORD
;
256 outb(b_Tmp
, devpriv
->iobase
+ APCI3120_TIMER_CRT0
);
258 //Set the convertion time
259 outw(us_ConvertTiming
,
260 devpriv
->iobase
+ APCI3120_TIMER_VALUE
);
263 (USHORT
) inw(dev
->iobase
+ APCI3120_RD_STATUS
);
265 if (devpriv
->b_EocEosInterrupt
== APCI3120_DISABLE
) {
268 // Waiting for the end of conversion
270 inw(devpriv
->iobase
+
272 } while ((us_TmpValue
& APCI3120_EOC
) ==
275 //Read the result in FIFO and put it in insn data pointer
276 us_TmpValue
= inw(devpriv
->iobase
+ 0);
279 inw(devpriv
->iobase
+ APCI3120_RESET_FIFO
);
284 case APCI3120_EOS_MODE
:
286 inw(devpriv
->iobase
);
288 inw(devpriv
->iobase
+ APCI3120_RESET_FIFO
);
289 // clear PA PR and disable timer 0
291 devpriv
->us_OutputRegister
=
293 us_OutputRegister
& APCI3120_CLEAR_PA_PR
) |
294 APCI3120_DISABLE_TIMER0
;
296 outw(devpriv
->us_OutputRegister
,
297 devpriv
->iobase
+ APCI3120_WR_ADDRESS
);
299 if (!i_APCI3120_SetupChannelList(dev
, s
,
300 devpriv
->ui_AiNbrofChannels
,
301 devpriv
->ui_AiChannelList
, 0))
304 //Initialize Timer 0 mode 2
305 devpriv
->b_TimerSelectMode
=
307 b_TimerSelectMode
& 0xFC) |
308 APCI3120_TIMER_0_MODE_2
;
309 outb(devpriv
->b_TimerSelectMode
,
310 devpriv
->iobase
+ APCI3120_TIMER_CRT1
);
314 b_DigitalOutputRegister
) & 0xF0) |
315 APCI3120_SELECT_TIMER_0_WORD
;
316 outb(b_Tmp
, devpriv
->iobase
+ APCI3120_TIMER_CRT0
);
318 //Set the convertion time
319 outw(us_ConvertTiming
,
320 devpriv
->iobase
+ APCI3120_TIMER_VALUE
);
323 devpriv
->b_ModeSelectRegister
=
325 b_ModeSelectRegister
| APCI3120_ENABLE_SCAN
;
326 outb(devpriv
->b_ModeSelectRegister
,
327 devpriv
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
329 //If Interrupt function is loaded
330 if (devpriv
->b_EocEosInterrupt
== APCI3120_ENABLE
) {
331 //Disables the EOC,DMA and enables the EOS interrupt
332 devpriv
->b_ModeSelectRegister
=
334 b_ModeSelectRegister
&
335 APCI3120_DISABLE_EOC_INT
) |
336 APCI3120_ENABLE_EOS_INT
;
337 inw(devpriv
->iobase
);
340 devpriv
->b_ModeSelectRegister
=
342 b_ModeSelectRegister
&
343 APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER
;
345 outb(devpriv
->b_ModeSelectRegister
,
346 devpriv
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
348 inw(devpriv
->iobase
+ APCI3120_RD_STATUS
);
352 devpriv
->us_OutputRegister
=
354 us_OutputRegister
| APCI3120_ENABLE_TIMER0
;
355 outw(devpriv
->us_OutputRegister
,
356 devpriv
->iobase
+ APCI3120_WR_ADDRESS
);
359 outw(0, devpriv
->iobase
+ APCI3120_START_CONVERSION
);
361 //Waiting of end of convertion if interrupt is not installed
362 if (devpriv
->b_EocEosInterrupt
== APCI3120_DISABLE
) {
363 //Waiting the end of convertion
366 inw(devpriv
->iobase
+
369 while ((us_TmpValue
& APCI3120_EOS
) !=
372 for (i
= 0; i
< devpriv
->ui_AiNbrofChannels
;
374 //Read the result in FIFO and write them in shared memory
375 us_TmpValue
= inw(devpriv
->iobase
);
376 data
[i
] = (UINT
) us_TmpValue
;
379 devpriv
->b_InterruptMode
= APCI3120_EOC_MODE
; // Restore defaults.
384 printk("inputs wrong\n");
387 devpriv
->ui_EocEosConversionTime
= 0; // re initializing the variable;
395 +----------------------------------------------------------------------------+
396 | Function name :int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev,|
397 | struct comedi_subdevice *s)|
399 +----------------------------------------------------------------------------+
400 | Task : Stops Cyclic acquisition |
402 +----------------------------------------------------------------------------+
403 | Input Parameters : struct comedi_device *dev |
404 | struct comedi_subdevice *s |
406 +----------------------------------------------------------------------------+
409 +----------------------------------------------------------------------------+
412 int i_APCI3120_StopCyclicAcquisition(struct comedi_device
* dev
, struct comedi_subdevice
* s
)
414 // Disable A2P Fifo write and AMWEN signal
415 outw(0, devpriv
->i_IobaseAddon
+ 4);
417 //Disable Bus Master ADD ON
418 outw(APCI3120_ADD_ON_AGCSTS_LOW
, devpriv
->i_IobaseAddon
+ 0);
419 outw(0, devpriv
->i_IobaseAddon
+ 2);
420 outw(APCI3120_ADD_ON_AGCSTS_HIGH
, devpriv
->i_IobaseAddon
+ 0);
421 outw(0, devpriv
->i_IobaseAddon
+ 2);
423 //Disable BUS Master PCI
424 outl(0, devpriv
->i_IobaseAmcc
+ AMCC_OP_REG_MCSR
);
426 //outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR)&(~AINT_WRITE_COMPL), devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR); // stop amcc irqs
427 //outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR)&(~EN_A2P_TRANSFERS), devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR); // stop DMA
429 //Disable ext trigger
430 i_APCI3120_ExttrigDisable(dev
);
432 devpriv
->us_OutputRegister
= 0;
435 us_OutputRegister
& APCI3120_DISABLE_TIMER0
&
436 APCI3120_DISABLE_TIMER1
, dev
->iobase
+ APCI3120_WR_ADDRESS
);
438 outw(APCI3120_DISABLE_ALL_TIMER
, dev
->iobase
+ APCI3120_WR_ADDRESS
);
440 //DISABLE_ALL_INTERRUPT
441 outb(APCI3120_DISABLE_ALL_INTERRUPT
,
442 dev
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
444 inb(dev
->iobase
+ APCI3120_RESET_FIFO
);
445 inw(dev
->iobase
+ APCI3120_RD_STATUS
);
446 devpriv
->ui_AiActualScan
= 0;
447 devpriv
->ui_AiActualScanPosition
= 0;
448 s
->async
->cur_chan
= 0;
449 devpriv
->ui_AiBufferPtr
= 0;
450 devpriv
->b_AiContinuous
= 0;
451 devpriv
->ui_DmaActualBuffer
= 0;
453 devpriv
->b_AiCyclicAcquisition
= APCI3120_DISABLE
;
454 devpriv
->b_InterruptMode
= APCI3120_EOC_MODE
;
455 devpriv
->b_EocEosInterrupt
= APCI3120_DISABLE
;
456 i_APCI3120_Reset(dev
);
461 +----------------------------------------------------------------------------+
462 | Function name :int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev|
463 | ,struct comedi_subdevice *s,struct comedi_cmd *cmd) |
465 +----------------------------------------------------------------------------+
466 | Task : Test validity for a command for cyclic anlog input |
469 +----------------------------------------------------------------------------+
470 | Input Parameters : struct comedi_device *dev |
471 | struct comedi_subdevice *s |
472 | struct comedi_cmd *cmd |
473 +----------------------------------------------------------------------------+
476 +----------------------------------------------------------------------------+
479 int i_APCI3120_CommandTestAnalogInput(struct comedi_device
* dev
, struct comedi_subdevice
* s
,
480 struct comedi_cmd
* cmd
)
483 int tmp
; // divisor1,divisor2;
485 // step 1: make sure trigger sources are trivially valid
487 tmp
= cmd
->start_src
;
488 cmd
->start_src
&= TRIG_NOW
| TRIG_EXT
;
489 if (!cmd
->start_src
|| tmp
!= cmd
->start_src
)
492 tmp
= cmd
->scan_begin_src
;
493 cmd
->scan_begin_src
&= TRIG_TIMER
| TRIG_FOLLOW
;
494 if (!cmd
->scan_begin_src
|| tmp
!= cmd
->scan_begin_src
)
497 tmp
= cmd
->convert_src
;
498 cmd
->convert_src
&= TRIG_TIMER
;
499 if (!cmd
->convert_src
|| tmp
!= cmd
->convert_src
)
502 tmp
= cmd
->scan_end_src
;
503 cmd
->scan_end_src
&= TRIG_COUNT
;
504 if (!cmd
->scan_end_src
|| tmp
!= cmd
->scan_end_src
)
508 cmd
->stop_src
&= TRIG_COUNT
| TRIG_NONE
;
509 if (!cmd
->stop_src
|| tmp
!= cmd
->stop_src
)
515 //step 2: make sure trigger sources are unique and mutually compatible
517 if (cmd
->start_src
!= TRIG_NOW
&& cmd
->start_src
!= TRIG_EXT
) {
521 if (cmd
->scan_begin_src
!= TRIG_TIMER
&&
522 cmd
->scan_begin_src
!= TRIG_FOLLOW
)
525 if (cmd
->convert_src
!= TRIG_TIMER
)
528 if (cmd
->scan_end_src
!= TRIG_COUNT
) {
529 cmd
->scan_end_src
= TRIG_COUNT
;
533 if (cmd
->stop_src
!= TRIG_NONE
&& cmd
->stop_src
!= TRIG_COUNT
)
539 // step 3: make sure arguments are trivially compatible
541 if (cmd
->start_arg
!= 0) {
546 if (cmd
->scan_begin_src
== TRIG_TIMER
) // Test Delay timing
548 if (cmd
->scan_begin_arg
< this_board
->ui_MinDelaytimeNs
) {
549 cmd
->scan_begin_arg
= this_board
->ui_MinDelaytimeNs
;
554 if (cmd
->convert_src
== TRIG_TIMER
) // Test Acquisition timing
556 if (cmd
->scan_begin_src
== TRIG_TIMER
) {
557 if ((cmd
->convert_arg
)
558 && (cmd
->convert_arg
<
559 this_board
->ui_MinAcquisitiontimeNs
)) {
561 this_board
->ui_MinAcquisitiontimeNs
;
565 if (cmd
->convert_arg
<
566 this_board
->ui_MinAcquisitiontimeNs
) {
568 this_board
->ui_MinAcquisitiontimeNs
;
575 if (!cmd
->chanlist_len
) {
576 cmd
->chanlist_len
= 1;
579 if (cmd
->chanlist_len
> this_board
->i_AiChannelList
) {
580 cmd
->chanlist_len
= this_board
->i_AiChannelList
;
583 if (cmd
->stop_src
== TRIG_COUNT
) {
584 if (!cmd
->stop_arg
) {
588 } else { // TRIG_NONE
589 if (cmd
->stop_arg
!= 0) {
598 // step 4: fix up any arguments
600 if (cmd
->convert_src
== TRIG_TIMER
) {
602 if (cmd
->scan_begin_src
== TRIG_TIMER
&&
603 cmd
->scan_begin_arg
<
604 cmd
->convert_arg
* cmd
->scan_end_arg
) {
605 cmd
->scan_begin_arg
=
606 cmd
->convert_arg
* cmd
->scan_end_arg
;
618 +----------------------------------------------------------------------------+
619 | Function name : int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, |
620 | struct comedi_subdevice *s) |
622 +----------------------------------------------------------------------------+
623 | Task : Does asynchronous acquisition |
624 | Determines the mode 1 or 2. |
626 +----------------------------------------------------------------------------+
627 | Input Parameters : struct comedi_device *dev |
628 | struct comedi_subdevice *s |
630 +----------------------------------------------------------------------------+
633 +----------------------------------------------------------------------------+
636 int i_APCI3120_CommandAnalogInput(struct comedi_device
* dev
, struct comedi_subdevice
* s
)
638 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
640 //loading private structure with cmd structure inputs
641 devpriv
->ui_AiFlags
= cmd
->flags
;
642 devpriv
->ui_AiNbrofChannels
= cmd
->chanlist_len
;
643 devpriv
->ui_AiScanLength
= cmd
->scan_end_arg
;
644 devpriv
->pui_AiChannelList
= cmd
->chanlist
;
646 //UPDATE-0.7.57->0.7.68devpriv->AiData=s->async->data;
647 devpriv
->AiData
= s
->async
->prealloc_buf
;
648 //UPDATE-0.7.57->0.7.68devpriv->ui_AiDataLength=s->async->data_len;
649 devpriv
->ui_AiDataLength
= s
->async
->prealloc_bufsz
;
651 if (cmd
->stop_src
== TRIG_COUNT
) {
652 devpriv
->ui_AiNbrofScans
= cmd
->stop_arg
;
654 devpriv
->ui_AiNbrofScans
= 0;
657 devpriv
->ui_AiTimer0
= 0; // variables changed to timer0,timer1
658 devpriv
->ui_AiTimer1
= 0;
659 if ((devpriv
->ui_AiNbrofScans
== 0) || (devpriv
->ui_AiNbrofScans
== -1))
660 devpriv
->b_AiContinuous
= 1; // user want neverending analog acquisition
661 // stopped using cancel
663 if (cmd
->start_src
== TRIG_EXT
)
664 devpriv
->b_ExttrigEnable
= APCI3120_ENABLE
;
666 devpriv
->b_ExttrigEnable
= APCI3120_DISABLE
;
668 if (cmd
->scan_begin_src
== TRIG_FOLLOW
) {
670 if (cmd
->convert_src
== TRIG_TIMER
) {
673 devpriv
->ui_AiTimer0
= cmd
->convert_arg
; // timer constant in nano seconds
674 //return this_board->i_hwdrv_CommandAnalogInput(1,dev,s);
675 return i_APCI3120_CyclicAnalogInput(1, dev
, s
);
679 if ((cmd
->scan_begin_src
== TRIG_TIMER
)
680 && (cmd
->convert_src
== TRIG_TIMER
)) {
682 devpriv
->ui_AiTimer1
= cmd
->scan_begin_arg
;
683 devpriv
->ui_AiTimer0
= cmd
->convert_arg
; // variable changed timer2 to timer0
684 //return this_board->i_hwdrv_CommandAnalogInput(2,dev,s);
685 return i_APCI3120_CyclicAnalogInput(2, dev
, s
);
691 +----------------------------------------------------------------------------+
692 | Function name : int i_APCI3120_CyclicAnalogInput(int mode, |
693 | struct comedi_device * dev,struct comedi_subdevice * s) |
694 +----------------------------------------------------------------------------+
695 | Task : This is used for analog input cyclic acquisition |
696 | Performs the command operations. |
697 | If DMA is configured does DMA initialization |
698 | otherwise does the acquisition with EOS interrupt. |
700 +----------------------------------------------------------------------------+
701 | Input Parameters : |
704 +----------------------------------------------------------------------------+
707 +----------------------------------------------------------------------------+
710 int i_APCI3120_CyclicAnalogInput(int mode
, struct comedi_device
* dev
,
711 struct comedi_subdevice
* s
)
714 UINT ui_Tmp
, ui_DelayTiming
= 0, ui_TimerValue1
= 0, dmalen0
=
715 0, dmalen1
= 0, ui_TimerValue2
=
716 0, ui_TimerValue0
, ui_ConvertTiming
;
719 //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
720 //devpriv->b_AiCyclicAcquisition=APCI3120_ENABLE;
721 //END JK 07.05.04: Comparison between WIN32 and Linux driver
723 /*******************/
724 /* Resets the FIFO */
725 /*******************/
726 inb(dev
->iobase
+ APCI3120_RESET_FIFO
);
728 //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
729 //inw(dev->iobase+APCI3120_RD_STATUS);
730 //END JK 07.05.04: Comparison between WIN32 and Linux driver
732 /***************************/
733 /* Acquisition initialized */
734 /***************************/
735 //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
736 devpriv
->b_AiCyclicAcquisition
= APCI3120_ENABLE
;
737 //END JK 07.05.04: Comparison between WIN32 and Linux driver
739 // clear software registers
740 devpriv
->b_TimerSelectMode
= 0;
741 devpriv
->us_OutputRegister
= 0;
742 devpriv
->b_ModeSelectRegister
= 0;
743 //devpriv->b_DigitalOutputRegister=0;
745 //COMMENT JK 07.05.04: Followings calls are in i_APCI3120_StartAnalogInputAcquisition
747 /****************************/
748 /* Clear Timer Write TC INT */
749 /****************************/
750 outl(APCI3120_CLEAR_WRITE_TC_INT
,
751 devpriv
->i_IobaseAmcc
+ APCI3120_AMCC_OP_REG_INTCSR
);
753 /************************************/
754 /* Clears the timer status register */
755 /************************************/
756 //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
757 //inw(dev->iobase+APCI3120_TIMER_STATUS_REGISTER);
758 inb(dev
->iobase
+ APCI3120_TIMER_STATUS_REGISTER
);
759 //END JK 07.05.04: Comparison between WIN32 and Linux driver
761 /**************************/
762 /* Disables All Timer */
763 /* Sets PR and PA to 0 */
764 /**************************/
765 devpriv
->us_OutputRegister
= devpriv
->us_OutputRegister
&
766 APCI3120_DISABLE_TIMER0
&
767 APCI3120_DISABLE_TIMER1
& APCI3120_CLEAR_PA_PR
;
769 outw(devpriv
->us_OutputRegister
, dev
->iobase
+ APCI3120_WR_ADDRESS
);
771 /*******************/
772 /* Resets the FIFO */
773 /*******************/
774 //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
775 inb(devpriv
->iobase
+ APCI3120_RESET_FIFO
);
776 //END JK 07.05.04: Comparison between WIN32 and Linux driver
778 devpriv
->ui_AiActualScan
= 0;
779 devpriv
->ui_AiActualScanPosition
= 0;
780 s
->async
->cur_chan
= 0;
781 devpriv
->ui_AiBufferPtr
= 0;
782 devpriv
->ui_DmaActualBuffer
= 0;
784 // value for timer2 minus -2 has to be done .....dunno y??
785 ui_TimerValue2
= devpriv
->ui_AiNbrofScans
- 2;
786 ui_ConvertTiming
= devpriv
->ui_AiTimer0
;
789 ui_DelayTiming
= devpriv
->ui_AiTimer1
;
791 /**********************************/
792 /* Initializes the sequence array */
793 /**********************************/
794 if (!i_APCI3120_SetupChannelList(dev
, s
, devpriv
->ui_AiNbrofChannels
,
795 devpriv
->pui_AiChannelList
, 0))
798 us_TmpValue
= (USHORT
) inw(dev
->iobase
+ APCI3120_RD_STATUS
);
799 /*** EL241003 : add this section in comment because floats must not be used
800 if((us_TmpValue & 0x00B0)==0x00B0)
802 f_ConvertValue=(((float)ui_ConvertTiming * 0.002) - 2);
803 ui_TimerValue0=(UINT)f_ConvertValue;
806 f_DelayValue = (((float)ui_DelayTiming * 0.00002) - 2);
807 ui_TimerValue1 = (UINT) f_DelayValue;
812 f_ConvertValue=(((float)ui_ConvertTiming * 0.0012926) - 1);
813 ui_TimerValue0=(UINT)f_ConvertValue;
816 f_DelayValue = (((float)ui_DelayTiming * 0.000012926) - 1);
817 ui_TimerValue1 = (UINT) f_DelayValue;
820 ***********************************************************************************************/
821 /*** EL241003 Begin : add this section to replace floats calculation by integer calculations **/
822 //EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001
823 if ((us_TmpValue
& 0x00B0) == 0x00B0
824 || !strcmp(this_board
->pc_DriverName
, "apci3001")) {
825 ui_TimerValue0
= ui_ConvertTiming
* 2 - 2000;
826 ui_TimerValue0
= ui_TimerValue0
/ 1000;
829 ui_DelayTiming
= ui_DelayTiming
/ 1000;
830 ui_TimerValue1
= ui_DelayTiming
* 2 - 200;
831 ui_TimerValue1
= ui_TimerValue1
/ 100;
834 ui_ConvertTiming
= ui_ConvertTiming
/ 1000;
835 ui_TimerValue0
= ui_ConvertTiming
* 12926 - 10000;
836 ui_TimerValue0
= ui_TimerValue0
/ 10000;
839 ui_DelayTiming
= ui_DelayTiming
/ 1000;
840 ui_TimerValue1
= ui_DelayTiming
* 12926 - 1;
841 ui_TimerValue1
= ui_TimerValue1
/ 1000000;
844 /*** EL241003 End ******************************************************************************/
846 if (devpriv
->b_ExttrigEnable
== APCI3120_ENABLE
) {
847 i_APCI3120_ExttrigEnable(dev
); // activate EXT trigger
851 // init timer0 in mode 2
852 devpriv
->b_TimerSelectMode
=
854 b_TimerSelectMode
& 0xFC) | APCI3120_TIMER_0_MODE_2
;
855 outb(devpriv
->b_TimerSelectMode
,
856 dev
->iobase
+ APCI3120_TIMER_CRT1
);
860 b_DigitalOutputRegister
) & 0xF0) |
861 APCI3120_SELECT_TIMER_0_WORD
;
862 outb(b_Tmp
, dev
->iobase
+ APCI3120_TIMER_CRT0
);
863 //Set the convertion time
864 outw(((USHORT
) ui_TimerValue0
),
865 dev
->iobase
+ APCI3120_TIMER_VALUE
);
869 // init timer1 in mode 2
870 devpriv
->b_TimerSelectMode
=
872 b_TimerSelectMode
& 0xF3) | APCI3120_TIMER_1_MODE_2
;
873 outb(devpriv
->b_TimerSelectMode
,
874 dev
->iobase
+ APCI3120_TIMER_CRT1
);
878 b_DigitalOutputRegister
) & 0xF0) |
879 APCI3120_SELECT_TIMER_1_WORD
;
880 outb(b_Tmp
, dev
->iobase
+ APCI3120_TIMER_CRT0
);
881 //Set the convertion time
882 outw(((USHORT
) ui_TimerValue1
),
883 dev
->iobase
+ APCI3120_TIMER_VALUE
);
885 // init timer0 in mode 2
886 devpriv
->b_TimerSelectMode
=
888 b_TimerSelectMode
& 0xFC) | APCI3120_TIMER_0_MODE_2
;
889 outb(devpriv
->b_TimerSelectMode
,
890 dev
->iobase
+ APCI3120_TIMER_CRT1
);
894 b_DigitalOutputRegister
) & 0xF0) |
895 APCI3120_SELECT_TIMER_0_WORD
;
896 outb(b_Tmp
, dev
->iobase
+ APCI3120_TIMER_CRT0
);
898 //Set the convertion time
899 outw(((USHORT
) ui_TimerValue0
),
900 dev
->iobase
+ APCI3120_TIMER_VALUE
);
904 // ##########common for all modes#################
906 /***********************/
907 /* Clears the SCAN bit */
908 /***********************/
909 //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
910 //devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister | APCI3120_DISABLE_SCAN;
911 devpriv
->b_ModeSelectRegister
= devpriv
->b_ModeSelectRegister
&
912 APCI3120_DISABLE_SCAN
;
913 //END JK 07.05.04: Comparison between WIN32 and Linux driver
914 outb(devpriv
->b_ModeSelectRegister
,
915 dev
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
917 // If DMA is disabled
918 if (devpriv
->us_UseDma
== APCI3120_DISABLE
) {
919 // disable EOC and enable EOS
920 devpriv
->b_InterruptMode
= APCI3120_EOS_MODE
;
921 devpriv
->b_EocEosInterrupt
= APCI3120_ENABLE
;
923 devpriv
->b_ModeSelectRegister
=
925 b_ModeSelectRegister
& APCI3120_DISABLE_EOC_INT
) |
926 APCI3120_ENABLE_EOS_INT
;
927 outb(devpriv
->b_ModeSelectRegister
,
928 dev
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
930 if (!devpriv
->b_AiContinuous
) {
931 // configure Timer2 For counting EOS
932 //Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0)
933 devpriv
->us_OutputRegister
=
935 us_OutputRegister
& APCI3120_DISABLE_TIMER2
;
936 outw(devpriv
->us_OutputRegister
,
937 dev
->iobase
+ APCI3120_WR_ADDRESS
);
939 // DISABLE TIMER INTERRUPT
940 devpriv
->b_ModeSelectRegister
=
942 b_ModeSelectRegister
&
943 APCI3120_DISABLE_TIMER_INT
& 0xEF;
944 outb(devpriv
->b_ModeSelectRegister
,
945 dev
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
947 //(1) Init timer 2 in mode 0 and write timer value
948 devpriv
->b_TimerSelectMode
=
950 b_TimerSelectMode
& 0x0F) |
951 APCI3120_TIMER_2_MODE_0
;
952 outb(devpriv
->b_TimerSelectMode
,
953 dev
->iobase
+ APCI3120_TIMER_CRT1
);
957 b_DigitalOutputRegister
) & 0xF0) |
958 APCI3120_SELECT_TIMER_2_LOW_WORD
;
959 outb(b_Tmp
, dev
->iobase
+ APCI3120_TIMER_CRT0
);
960 outw(LOWORD(ui_TimerValue2
),
961 dev
->iobase
+ APCI3120_TIMER_VALUE
);
965 b_DigitalOutputRegister
) & 0xF0) |
966 APCI3120_SELECT_TIMER_2_HIGH_WORD
;
967 outb(b_Tmp
, dev
->iobase
+ APCI3120_TIMER_CRT0
);
968 outw(HIWORD(ui_TimerValue2
),
969 dev
->iobase
+ APCI3120_TIMER_VALUE
);
971 //(2) Reset FC_TIMER BIT Clearing timer status register
972 inb(dev
->iobase
+ APCI3120_TIMER_STATUS_REGISTER
);
973 // enable timer counter and disable watch dog
974 devpriv
->b_ModeSelectRegister
=
976 b_ModeSelectRegister
|
977 APCI3120_ENABLE_TIMER_COUNTER
) &
978 APCI3120_DISABLE_WATCHDOG
;
979 // select EOS clock input for timer 2
980 devpriv
->b_ModeSelectRegister
=
982 b_ModeSelectRegister
|
983 APCI3120_TIMER2_SELECT_EOS
;
984 // Enable timer2 interrupt
985 devpriv
->b_ModeSelectRegister
=
987 b_ModeSelectRegister
|
988 APCI3120_ENABLE_TIMER_INT
;
989 outb(devpriv
->b_ModeSelectRegister
,
990 dev
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
991 devpriv
->b_Timer2Mode
= APCI3120_COUNTER
;
992 devpriv
->b_Timer2Interrupt
= APCI3120_ENABLE
;
996 //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
997 //inw(dev->iobase+0);// reset EOC bit
998 //END JK 07.05.04: Comparison between WIN32 and Linux driver
999 devpriv
->b_InterruptMode
= APCI3120_DMA_MODE
;
1001 /************************************/
1002 /* Disables the EOC, EOS interrupt */
1003 /************************************/
1004 devpriv
->b_ModeSelectRegister
= devpriv
->b_ModeSelectRegister
&
1005 APCI3120_DISABLE_EOC_INT
& APCI3120_DISABLE_EOS_INT
;
1007 outb(devpriv
->b_ModeSelectRegister
,
1008 dev
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
1010 dmalen0
= devpriv
->ui_DmaBufferSize
[0];
1011 dmalen1
= devpriv
->ui_DmaBufferSize
[1];
1013 if (!devpriv
->b_AiContinuous
) {
1015 if (dmalen0
> (devpriv
->ui_AiNbrofScans
* devpriv
->ui_AiScanLength
* 2)) { // must we fill full first buffer?
1017 devpriv
->ui_AiNbrofScans
*
1018 devpriv
->ui_AiScanLength
* 2;
1019 } else if (dmalen1
> (devpriv
->ui_AiNbrofScans
* devpriv
->ui_AiScanLength
* 2 - dmalen0
)) // and must we fill full second buffer when first is once filled?
1021 devpriv
->ui_AiNbrofScans
*
1022 devpriv
->ui_AiScanLength
* 2 - dmalen0
;
1025 if (devpriv
->ui_AiFlags
& TRIG_WAKE_EOS
) {
1026 // don't we want wake up every scan?
1027 if (dmalen0
> (devpriv
->ui_AiScanLength
* 2)) {
1028 dmalen0
= devpriv
->ui_AiScanLength
* 2;
1029 if (devpriv
->ui_AiScanLength
& 1)
1032 if (dmalen1
> (devpriv
->ui_AiScanLength
* 2)) {
1033 dmalen1
= devpriv
->ui_AiScanLength
* 2;
1034 if (devpriv
->ui_AiScanLength
& 1)
1039 } else { // isn't output buff smaller that our DMA buff?
1040 if (dmalen0
> (devpriv
->ui_AiDataLength
)) {
1041 dmalen0
= devpriv
->ui_AiDataLength
;
1043 if (dmalen1
> (devpriv
->ui_AiDataLength
)) {
1044 dmalen1
= devpriv
->ui_AiDataLength
;
1047 devpriv
->ui_DmaBufferUsesize
[0] = dmalen0
;
1048 devpriv
->ui_DmaBufferUsesize
[1] = dmalen1
;
1052 // Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS register
1054 ui_Tmp
= AGCSTS_TC_ENABLE
| AGCSTS_RESET_A2P_FIFO
;
1055 outl(ui_Tmp
, devpriv
->i_IobaseAmcc
+ AMCC_OP_REG_AGCSTS
);
1057 // changed since 16 bit interface for add on
1058 /*********************/
1059 /* ENABLE BUS MASTER */
1060 /*********************/
1061 outw(APCI3120_ADD_ON_AGCSTS_LOW
, devpriv
->i_IobaseAddon
+ 0);
1062 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW
,
1063 devpriv
->i_IobaseAddon
+ 2);
1065 outw(APCI3120_ADD_ON_AGCSTS_HIGH
, devpriv
->i_IobaseAddon
+ 0);
1066 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH
,
1067 devpriv
->i_IobaseAddon
+ 2);
1070 //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
1071 outw(0x1000, devpriv
->i_IobaseAddon
+ 2);
1072 //END JK 07.05.04: Comparison between WIN32 and Linux driver
1075 // A2P FIFO MANAGEMENT
1076 // A2P fifo reset & transfer control enable
1077 /***********************/
1078 /* A2P FIFO MANAGEMENT */
1079 /***********************/
1080 outl(APCI3120_A2P_FIFO_MANAGEMENT
, devpriv
->i_IobaseAmcc
+
1081 APCI3120_AMCC_OP_MCSR
);
1084 //beginning address of dma buf
1085 //The 32 bit address of dma buffer is converted into two 16 bit addresses
1086 // Can done by using _attach and put into into an array
1087 // array used may be for differnet pages
1089 // DMA Start Adress Low
1090 outw(APCI3120_ADD_ON_MWAR_LOW
, devpriv
->i_IobaseAddon
+ 0);
1091 outw((devpriv
->ul_DmaBufferHw
[0] & 0xFFFF),
1092 devpriv
->i_IobaseAddon
+ 2);
1094 /*************************/
1095 /* DMA Start Adress High */
1096 /*************************/
1097 outw(APCI3120_ADD_ON_MWAR_HIGH
, devpriv
->i_IobaseAddon
+ 0);
1098 outw((devpriv
->ul_DmaBufferHw
[0] / 65536),
1099 devpriv
->i_IobaseAddon
+ 2);
1102 // amount of bytes to be transfered set transfer count
1103 // used ADDON MWTC register
1104 //commented testing outl(devpriv->ui_DmaBufferUsesize[0], devpriv->i_IobaseAddon+AMCC_OP_REG_AMWTC);
1106 /**************************/
1107 /* Nbr of acquisition LOW */
1108 /**************************/
1109 outw(APCI3120_ADD_ON_MWTC_LOW
, devpriv
->i_IobaseAddon
+ 0);
1110 outw((devpriv
->ui_DmaBufferUsesize
[0] & 0xFFFF),
1111 devpriv
->i_IobaseAddon
+ 2);
1113 /***************************/
1114 /* Nbr of acquisition HIGH */
1115 /***************************/
1116 outw(APCI3120_ADD_ON_MWTC_HIGH
, devpriv
->i_IobaseAddon
+ 0);
1117 outw((devpriv
->ui_DmaBufferUsesize
[0] / 65536),
1118 devpriv
->i_IobaseAddon
+ 2);
1121 // To configure A2P FIFO
1122 // testing outl( FIFO_ADVANCE_ON_BYTE_2,devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR);
1124 /******************/
1125 /* A2P FIFO RESET */
1126 /******************/
1128 //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
1129 outl(0x04000000UL
, devpriv
->i_IobaseAmcc
+ AMCC_OP_REG_MCSR
);
1130 //END JK 07.05.04: Comparison between WIN32 and Linux driver
1133 //ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1134 // AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1135 //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
1136 //outw(3,devpriv->i_IobaseAddon + 4);
1137 //END JK 07.05.04: Comparison between WIN32 and Linux driver
1140 //initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI)
1141 /***************************************************/
1142 /* A2P FIFO CONFIGURATE, END OF DMA INTERRUPT INIT */
1143 /***************************************************/
1144 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2
|
1145 APCI3120_ENABLE_WRITE_TC_INT
),
1146 devpriv
->i_IobaseAmcc
+ AMCC_OP_REG_INTCSR
);
1148 //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
1149 /******************************************/
1150 /* ENABLE A2P FIFO WRITE AND ENABLE AMWEN */
1151 /******************************************/
1152 outw(3, devpriv
->i_IobaseAddon
+ 4);
1153 //END JK 07.05.04: Comparison between WIN32 and Linux driver
1155 /******************/
1156 /* A2P FIFO RESET */
1157 /******************/
1158 //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
1160 devpriv
->i_IobaseAmcc
+ APCI3120_AMCC_OP_MCSR
);
1161 //END JK 07.05.04: Comparison between WIN32 and Linux driver
1164 if ((devpriv
->us_UseDma
== APCI3120_DISABLE
)
1165 && !devpriv
->b_AiContinuous
) {
1166 // set gate 2 to start conversion
1167 devpriv
->us_OutputRegister
=
1168 devpriv
->us_OutputRegister
| APCI3120_ENABLE_TIMER2
;
1169 outw(devpriv
->us_OutputRegister
,
1170 dev
->iobase
+ APCI3120_WR_ADDRESS
);
1175 // set gate 0 to start conversion
1176 devpriv
->us_OutputRegister
=
1177 devpriv
->us_OutputRegister
| APCI3120_ENABLE_TIMER0
;
1178 outw(devpriv
->us_OutputRegister
,
1179 dev
->iobase
+ APCI3120_WR_ADDRESS
);
1182 // set gate 0 and gate 1
1183 devpriv
->us_OutputRegister
=
1184 devpriv
->us_OutputRegister
| APCI3120_ENABLE_TIMER1
;
1185 devpriv
->us_OutputRegister
=
1186 devpriv
->us_OutputRegister
| APCI3120_ENABLE_TIMER0
;
1187 outw(devpriv
->us_OutputRegister
,
1188 dev
->iobase
+ APCI3120_WR_ADDRESS
);
1198 +----------------------------------------------------------------------------+
1199 | INTERNAL FUNCTIONS |
1200 +----------------------------------------------------------------------------+
1204 +----------------------------------------------------------------------------+
1205 | Function name : int i_APCI3120_Reset(struct comedi_device *dev) |
1208 +----------------------------------------------------------------------------+
1209 | Task : Hardware reset function |
1211 +----------------------------------------------------------------------------+
1212 | Input Parameters : struct comedi_device *dev |
1215 +----------------------------------------------------------------------------+
1218 +----------------------------------------------------------------------------+
1221 int i_APCI3120_Reset(struct comedi_device
* dev
)
1224 unsigned short us_TmpValue
;
1226 devpriv
->b_AiCyclicAcquisition
= APCI3120_DISABLE
;
1227 devpriv
->b_EocEosInterrupt
= APCI3120_DISABLE
;
1228 devpriv
->b_InterruptMode
= APCI3120_EOC_MODE
;
1229 devpriv
->ui_EocEosConversionTime
= 0; // set eoc eos conv time to 0
1230 devpriv
->b_OutputMemoryStatus
= 0;
1232 // variables used in timer subdevice
1233 devpriv
->b_Timer2Mode
= 0;
1234 devpriv
->b_Timer2Interrupt
= 0;
1235 devpriv
->b_ExttrigEnable
= 0; // Disable ext trigger
1237 /* Disable all interrupts, watchdog for the anolog output */
1238 devpriv
->b_ModeSelectRegister
= 0;
1239 outb(devpriv
->b_ModeSelectRegister
,
1240 dev
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
1242 // Disables all counters, ext trigger and clears PA, PR
1243 devpriv
->us_OutputRegister
= 0;
1244 outw(devpriv
->us_OutputRegister
, dev
->iobase
+ APCI3120_WR_ADDRESS
);
1246 //Code to set the all anolog o/p channel to 0v
1247 //8191 is decimal value for zero(0 v)volt in bipolar mode(default)
1248 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_1
, dev
->iobase
+ APCI3120_ANALOG_OUTPUT_1
); //channel 1
1249 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_2
, dev
->iobase
+ APCI3120_ANALOG_OUTPUT_1
); //channel 2
1250 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_3
, dev
->iobase
+ APCI3120_ANALOG_OUTPUT_1
); //channel 3
1251 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_4
, dev
->iobase
+ APCI3120_ANALOG_OUTPUT_1
); //channel 4
1253 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_5
, dev
->iobase
+ APCI3120_ANALOG_OUTPUT_2
); //channel 5
1254 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_6
, dev
->iobase
+ APCI3120_ANALOG_OUTPUT_2
); //channel 6
1255 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_7
, dev
->iobase
+ APCI3120_ANALOG_OUTPUT_2
); //channel 7
1256 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_8
, dev
->iobase
+ APCI3120_ANALOG_OUTPUT_2
); //channel 8
1258 // Reset digital output to L0W
1260 //ES05 outb(0x0,dev->iobase+APCI3120_DIGITAL_OUTPUT);
1263 inw(dev
->iobase
+ 0); //make a dummy read
1264 inb(dev
->iobase
+ APCI3120_RESET_FIFO
); // flush FIFO
1265 inw(dev
->iobase
+ APCI3120_RD_STATUS
); // flush A/D status register
1267 //code to reset the RAM sequence
1268 for (i
= 0; i
< 16; i
++) {
1269 us_TmpValue
= i
<< 8; //select the location
1270 outw(us_TmpValue
, dev
->iobase
+ APCI3120_SEQ_RAM_ADDRESS
);
1276 +----------------------------------------------------------------------------+
1277 | Function name : int i_APCI3120_SetupChannelList(struct comedi_device * dev, |
1278 | struct comedi_subdevice * s, int n_chan,unsigned int *chanlist|
1281 +----------------------------------------------------------------------------+
1282 | Task :This function will first check channel list is ok or not|
1283 |and then initialize the sequence RAM with the polarity, Gain,Channel number |
1284 |If the last argument of function "check"is 1 then it only checks the channel|
1285 |list is ok or not. |
1287 +----------------------------------------------------------------------------+
1288 | Input Parameters : struct comedi_device * dev |
1289 | struct comedi_subdevice * s |
1291 unsigned int *chanlist
1293 +----------------------------------------------------------------------------+
1296 +----------------------------------------------------------------------------+
1299 int i_APCI3120_SetupChannelList(struct comedi_device
* dev
, struct comedi_subdevice
* s
,
1300 int n_chan
, unsigned int *chanlist
, char check
)
1302 unsigned int i
; //, differencial=0, bipolar=0;
1304 unsigned short us_TmpValue
;
1306 /* correct channel and range number check itself comedi/range.c */
1309 comedi_error(dev
, "range/channel list is empty!");
1312 // All is ok, so we can setup channel/range list
1316 //Code to set the PA and PR...Here it set PA to 0..
1317 devpriv
->us_OutputRegister
=
1318 devpriv
->us_OutputRegister
& APCI3120_CLEAR_PA_PR
;
1319 devpriv
->us_OutputRegister
= ((n_chan
- 1) & 0xf) << 8;
1320 outw(devpriv
->us_OutputRegister
, dev
->iobase
+ APCI3120_WR_ADDRESS
);
1322 for (i
= 0; i
< n_chan
; i
++) {
1323 // store range list to card
1324 us_TmpValue
= CR_CHAN(chanlist
[i
]); // get channel number;
1326 if (CR_RANGE(chanlist
[i
]) < APCI3120_BIPOLAR_RANGES
) {
1327 us_TmpValue
&= ((~APCI3120_UNIPOLAR
) & 0xff); // set bipolar
1329 us_TmpValue
|= APCI3120_UNIPOLAR
; // enable unipolar......
1332 gain
= CR_RANGE(chanlist
[i
]); // get gain number
1333 us_TmpValue
|= ((gain
& 0x03) << 4); //<<4 for G0 and G1 bit in RAM
1334 us_TmpValue
|= i
<< 8; //To select the RAM LOCATION....
1335 outw(us_TmpValue
, dev
->iobase
+ APCI3120_SEQ_RAM_ADDRESS
);
1337 printk("\n Gain = %i",
1338 (((unsigned char)CR_RANGE(chanlist
[i
]) & 0x03) << 2));
1339 printk("\n Channel = %i", CR_CHAN(chanlist
[i
]));
1340 printk("\n Polarity = %i", us_TmpValue
& APCI3120_UNIPOLAR
);
1342 return 1; // we can serve this with scan logic
1346 +----------------------------------------------------------------------------+
1347 | Function name : int i_APCI3120_ExttrigEnable(struct comedi_device * dev) |
1350 +----------------------------------------------------------------------------+
1351 | Task : Enable the external trigger |
1353 +----------------------------------------------------------------------------+
1354 | Input Parameters : struct comedi_device * dev |
1357 +----------------------------------------------------------------------------+
1358 | Return Value : 0 |
1360 +----------------------------------------------------------------------------+
1363 int i_APCI3120_ExttrigEnable(struct comedi_device
* dev
)
1366 devpriv
->us_OutputRegister
|= APCI3120_ENABLE_EXT_TRIGGER
;
1367 outw(devpriv
->us_OutputRegister
, dev
->iobase
+ APCI3120_WR_ADDRESS
);
1372 +----------------------------------------------------------------------------+
1373 | Function name : int i_APCI3120_ExttrigDisable(struct comedi_device * dev) |
1375 +----------------------------------------------------------------------------+
1376 | Task : Disables the external trigger |
1378 +----------------------------------------------------------------------------+
1379 | Input Parameters : struct comedi_device * dev |
1382 +----------------------------------------------------------------------------+
1383 | Return Value : 0 |
1385 +----------------------------------------------------------------------------+
1388 int i_APCI3120_ExttrigDisable(struct comedi_device
* dev
)
1390 devpriv
->us_OutputRegister
&= ~APCI3120_ENABLE_EXT_TRIGGER
;
1391 outw(devpriv
->us_OutputRegister
, dev
->iobase
+ APCI3120_WR_ADDRESS
);
1396 +----------------------------------------------------------------------------+
1397 | INTERRUPT FUNCTIONS |
1398 +----------------------------------------------------------------------------+
1402 +----------------------------------------------------------------------------+
1403 | Function name : void v_APCI3120_Interrupt(int irq, void *d) |
1406 +----------------------------------------------------------------------------+
1407 | Task :Interrupt handler for APCI3120 |
1408 | When interrupt occurs this gets called. |
1409 | First it finds which interrupt has been generated and |
1410 | handles corresponding interrupt |
1412 +----------------------------------------------------------------------------+
1413 | Input Parameters : int irq |
1416 +----------------------------------------------------------------------------+
1417 | Return Value : void |
1419 +----------------------------------------------------------------------------+
1422 void v_APCI3120_Interrupt(int irq
, void *d
)
1424 struct comedi_device
*dev
= d
;
1427 unsigned int int_amcc
, ui_Check
, i
;
1431 struct comedi_subdevice
*s
= dev
->subdevices
+ 0;
1434 int_daq
= inw(dev
->iobase
+ APCI3120_RD_STATUS
) & 0xf000; // get IRQ reasons
1435 int_amcc
= inl(devpriv
->i_IobaseAmcc
+ AMCC_OP_REG_INTCSR
); // get AMCC INT register
1437 if ((!int_daq
) && (!(int_amcc
& ANY_S593X_INT
))) {
1438 comedi_error(dev
, "IRQ from unknow source");
1442 outl(int_amcc
| 0x00ff0000, devpriv
->i_IobaseAmcc
+ AMCC_OP_REG_INTCSR
); // shutdown IRQ reasons in AMCC
1444 int_daq
= (int_daq
>> 12) & 0xF;
1446 if (devpriv
->b_ExttrigEnable
== APCI3120_ENABLE
) {
1447 //Disable ext trigger
1448 i_APCI3120_ExttrigDisable(dev
);
1449 devpriv
->b_ExttrigEnable
= APCI3120_DISABLE
;
1451 //clear the timer 2 interrupt
1452 inb(devpriv
->i_IobaseAmcc
+ APCI3120_TIMER_STATUS_REGISTER
);
1454 if (int_amcc
& MASTER_ABORT_INT
)
1455 comedi_error(dev
, "AMCC IRQ - MASTER DMA ABORT!");
1456 if (int_amcc
& TARGET_ABORT_INT
)
1457 comedi_error(dev
, "AMCC IRQ - TARGET DMA ABORT!");
1459 // Ckeck if EOC interrupt
1460 if (((int_daq
& 0x8) == 0)
1461 && (devpriv
->b_InterruptMode
== APCI3120_EOC_MODE
)) {
1462 if (devpriv
->b_EocEosInterrupt
== APCI3120_ENABLE
) {
1464 // Read the AI Value
1466 devpriv
->ui_AiReadData
[0] =
1467 (UINT
) inw(devpriv
->iobase
+ 0);
1468 devpriv
->b_EocEosInterrupt
= APCI3120_DISABLE
;
1469 send_sig(SIGIO
, devpriv
->tsk_Current
, 0); // send signal to the sample
1471 //Disable EOC Interrupt
1472 devpriv
->b_ModeSelectRegister
=
1474 b_ModeSelectRegister
& APCI3120_DISABLE_EOC_INT
;
1475 outb(devpriv
->b_ModeSelectRegister
,
1476 devpriv
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
1481 // Check If EOS interrupt
1482 if ((int_daq
& 0x2) && (devpriv
->b_InterruptMode
== APCI3120_EOS_MODE
)) {
1484 if (devpriv
->b_EocEosInterrupt
== APCI3120_ENABLE
) // enable this in without DMA ???
1487 if (devpriv
->b_AiCyclicAcquisition
== APCI3120_ENABLE
) {
1489 i_APCI3120_InterruptHandleEos(dev
);
1490 devpriv
->ui_AiActualScan
++;
1491 devpriv
->b_ModeSelectRegister
=
1493 b_ModeSelectRegister
|
1494 APCI3120_ENABLE_EOS_INT
;
1495 outb(devpriv
->b_ModeSelectRegister
,
1497 APCI3120_WRITE_MODE_SELECT
);
1500 for (i
= 0; i
< devpriv
->ui_AiNbrofChannels
;
1502 us_TmpValue
= inw(devpriv
->iobase
+ 0);
1503 devpriv
->ui_AiReadData
[i
] =
1506 devpriv
->b_EocEosInterrupt
= APCI3120_DISABLE
;
1507 devpriv
->b_InterruptMode
= APCI3120_EOC_MODE
;
1509 send_sig(SIGIO
, devpriv
->tsk_Current
, 0); // send signal to the sample
1514 devpriv
->b_ModeSelectRegister
=
1516 b_ModeSelectRegister
& APCI3120_DISABLE_EOS_INT
;
1517 outb(devpriv
->b_ModeSelectRegister
,
1518 dev
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
1519 devpriv
->b_EocEosInterrupt
= APCI3120_DISABLE
; //Default settings
1520 devpriv
->b_InterruptMode
= APCI3120_EOC_MODE
;
1525 if (int_daq
& 0x1) {
1527 switch (devpriv
->b_Timer2Mode
) {
1528 case APCI3120_COUNTER
:
1530 devpriv
->b_AiCyclicAcquisition
= APCI3120_DISABLE
;
1531 devpriv
->b_ModeSelectRegister
=
1533 b_ModeSelectRegister
& APCI3120_DISABLE_EOS_INT
;
1534 outb(devpriv
->b_ModeSelectRegister
,
1535 dev
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
1538 devpriv
->us_OutputRegister
=
1540 us_OutputRegister
& APCI3120_DISABLE_ALL_TIMER
;
1541 outw(devpriv
->us_OutputRegister
,
1542 dev
->iobase
+ APCI3120_WR_ADDRESS
);
1544 //stop timer 0 and timer 1
1545 i_APCI3120_StopCyclicAcquisition(dev
, s
);
1546 devpriv
->b_AiCyclicAcquisition
= APCI3120_DISABLE
;
1548 //UPDATE-0.7.57->0.7.68comedi_done(dev,s);
1549 s
->async
->events
|= COMEDI_CB_EOA
;
1550 comedi_event(dev
, s
);
1554 case APCI3120_TIMER
:
1556 //Send a signal to from kernel to user space
1557 send_sig(SIGIO
, devpriv
->tsk_Current
, 0);
1560 case APCI3120_WATCHDOG
:
1562 //Send a signal to from kernel to user space
1563 send_sig(SIGIO
, devpriv
->tsk_Current
, 0);
1568 // disable Timer Interrupt
1570 devpriv
->b_ModeSelectRegister
=
1572 b_ModeSelectRegister
&
1573 APCI3120_DISABLE_TIMER_INT
;
1575 outb(devpriv
->b_ModeSelectRegister
,
1576 dev
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
1580 b_DummyRead
= inb(dev
->iobase
+ APCI3120_TIMER_STATUS_REGISTER
);
1584 if ((int_daq
& 0x4) && (devpriv
->b_InterruptMode
== APCI3120_DMA_MODE
)) {
1585 if (devpriv
->b_AiCyclicAcquisition
== APCI3120_ENABLE
) {
1587 /****************************/
1588 /* Clear Timer Write TC INT */
1589 /****************************/
1591 outl(APCI3120_CLEAR_WRITE_TC_INT
,
1592 devpriv
->i_IobaseAmcc
+
1593 APCI3120_AMCC_OP_REG_INTCSR
);
1595 /************************************/
1596 /* Clears the timer status register */
1597 /************************************/
1598 inw(dev
->iobase
+ APCI3120_TIMER_STATUS_REGISTER
);
1599 v_APCI3120_InterruptDma(irq
, d
); // do some data transfer
1601 /* Stops the Timer */
1603 us_OutputRegister
& APCI3120_DISABLE_TIMER0
&
1604 APCI3120_DISABLE_TIMER1
,
1605 dev
->iobase
+ APCI3120_WR_ADDRESS
);
1614 +----------------------------------------------------------------------------+
1615 | Function name :int i_APCI3120_InterruptHandleEos(struct comedi_device *dev) |
1618 +----------------------------------------------------------------------------+
1619 | Task : This function handles EOS interrupt. |
1620 | This function copies the acquired data(from FIFO) |
1621 | to Comedi buffer. |
1623 +----------------------------------------------------------------------------+
1624 | Input Parameters : struct comedi_device *dev |
1627 +----------------------------------------------------------------------------+
1628 | Return Value : 0 |
1630 +----------------------------------------------------------------------------+
1634 * int i_APCI3120_InterruptHandleEos(struct comedi_device *dev)
1638 struct comedi_subdevice *s=dev->subdevices+0;
1639 struct comedi_async *async = s->async;
1640 data=async->data+async->buf_int_ptr;
1641 n_chan=devpriv->ui_AiNbrofChannels;
1643 for(i=0;i<n_chan;i++)
1645 data[i]=inw(dev->iobase+0);
1647 async->buf_int_count+=n_chan*sizeof(short);
1648 async->buf_int_ptr+=n_chan*sizeof(short);
1650 if (s->async->buf_int_ptr>=s->async->data_len) // for buffer rool over
1652 *//* buffer rollover */
1653 /* s->async->buf_int_ptr=0;
1654 comedi_eobuf(dev,s);
1658 int i_APCI3120_InterruptHandleEos(struct comedi_device
* dev
)
1661 struct comedi_subdevice
*s
= dev
->subdevices
+ 0;
1664 n_chan
= devpriv
->ui_AiNbrofChannels
;
1666 s
->async
->events
= 0;
1668 for (i
= 0; i
< n_chan
; i
++)
1669 err
&= comedi_buf_put(s
->async
, inw(dev
->iobase
+ 0));
1671 s
->async
->events
|= COMEDI_CB_EOS
;
1674 s
->async
->events
|= COMEDI_CB_OVERFLOW
;
1676 comedi_event(dev
, s
);
1682 +----------------------------------------------------------------------------+
1683 | Function name : void v_APCI3120_InterruptDma(int irq, void *d) |
1685 +----------------------------------------------------------------------------+
1686 | Task : This is a handler for the DMA interrupt |
1687 | This function copies the data to Comedi Buffer. |
1688 | For continuous DMA it reinitializes the DMA operation. |
1689 | For single mode DMA it stop the acquisition. |
1691 +----------------------------------------------------------------------------+
1692 | Input Parameters : int irq, void *d |
1694 +----------------------------------------------------------------------------+
1695 | Return Value : void |
1697 +----------------------------------------------------------------------------+
1700 void v_APCI3120_InterruptDma(int irq
, void *d
)
1702 struct comedi_device
*dev
= d
;
1703 struct comedi_subdevice
*s
= dev
->subdevices
+ 0;
1704 unsigned int next_dma_buf
, samplesinbuf
;
1705 unsigned long low_word
, high_word
, var
;
1709 devpriv
->ui_DmaBufferUsesize
[devpriv
->ui_DmaActualBuffer
] -
1710 inl(devpriv
->i_IobaseAmcc
+ AMCC_OP_REG_MWTC
);
1713 devpriv
->ui_DmaBufferUsesize
[devpriv
->ui_DmaActualBuffer
]) {
1714 comedi_error(dev
, "Interrupted DMA transfer!");
1716 if (samplesinbuf
& 1) {
1717 comedi_error(dev
, "Odd count of bytes in DMA ring!");
1718 i_APCI3120_StopCyclicAcquisition(dev
, s
);
1719 devpriv
->b_AiCyclicAcquisition
= APCI3120_DISABLE
;
1723 samplesinbuf
= samplesinbuf
>> 1; // number of received samples
1724 if (devpriv
->b_DmaDoubleBuffer
) {
1725 // switch DMA buffers if is used double buffering
1726 next_dma_buf
= 1 - devpriv
->ui_DmaActualBuffer
;
1728 ui_Tmp
= AGCSTS_TC_ENABLE
| AGCSTS_RESET_A2P_FIFO
;
1729 outl(ui_Tmp
, devpriv
->i_IobaseAddon
+ AMCC_OP_REG_AGCSTS
);
1731 // changed since 16 bit interface for add on
1732 outw(APCI3120_ADD_ON_AGCSTS_LOW
, devpriv
->i_IobaseAddon
+ 0);
1733 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW
,
1734 devpriv
->i_IobaseAddon
+ 2);
1735 outw(APCI3120_ADD_ON_AGCSTS_HIGH
, devpriv
->i_IobaseAddon
+ 0);
1736 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH
, devpriv
->i_IobaseAddon
+ 2); // 0x1000 is out putted in windows driver
1738 var
= devpriv
->ul_DmaBufferHw
[next_dma_buf
];
1739 low_word
= var
& 0xffff;
1740 var
= devpriv
->ul_DmaBufferHw
[next_dma_buf
];
1741 high_word
= var
/ 65536;
1743 /* DMA Start Adress Low */
1744 outw(APCI3120_ADD_ON_MWAR_LOW
, devpriv
->i_IobaseAddon
+ 0);
1745 outw(low_word
, devpriv
->i_IobaseAddon
+ 2);
1747 /* DMA Start Adress High */
1748 outw(APCI3120_ADD_ON_MWAR_HIGH
, devpriv
->i_IobaseAddon
+ 0);
1749 outw(high_word
, devpriv
->i_IobaseAddon
+ 2);
1751 var
= devpriv
->ui_DmaBufferUsesize
[next_dma_buf
];
1752 low_word
= var
& 0xffff;
1753 var
= devpriv
->ui_DmaBufferUsesize
[next_dma_buf
];
1754 high_word
= var
/ 65536;
1756 /* Nbr of acquisition LOW */
1757 outw(APCI3120_ADD_ON_MWTC_LOW
, devpriv
->i_IobaseAddon
+ 0);
1758 outw(low_word
, devpriv
->i_IobaseAddon
+ 2);
1760 /* Nbr of acquisition HIGH */
1761 outw(APCI3120_ADD_ON_MWTC_HIGH
, devpriv
->i_IobaseAddon
+ 0);
1762 outw(high_word
, devpriv
->i_IobaseAddon
+ 2);
1764 // To configure A2P FIFO
1765 // ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1766 // AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1767 outw(3, devpriv
->i_IobaseAddon
+ 4);
1768 //initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI)
1769 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2
|
1770 APCI3120_ENABLE_WRITE_TC_INT
),
1771 devpriv
->i_IobaseAmcc
+ AMCC_OP_REG_INTCSR
);
1774 /*UPDATE-0.7.57->0.7.68
1775 ptr=(short *)devpriv->ul_DmaBufferVirtual[devpriv->ui_DmaActualBuffer];
1778 // if there is not enough space left in the buffer to copy all data contained in the DMABufferVirtual
1779 if(s->async->buf_int_ptr+samplesinbuf*sizeof(short)>=devpriv->ui_AiDataLength)
1781 m=(devpriv->ui_AiDataLength-s->async->buf_int_ptr)/sizeof(short);
1782 v_APCI3120_InterruptDmaMoveBlock16bit(dev,s,(void *)ptr,((void *)(devpriv->AiData))+s->async->buf_int_ptr,m);
1783 s->async->buf_int_count+=m*sizeof(short);
1784 ptr+=m*sizeof(short);
1786 s->async->buf_int_ptr=0;
1787 comedi_eobuf(dev,s);
1792 v_APCI3120_InterruptDmaMoveBlock16bit(dev,s,(void *)ptr,((void *)(devpriv->AiData))+s->async->buf_int_ptr,samplesinbuf);
1794 s->async->buf_int_count+=samplesinbuf*sizeof(short);
1795 s->async->buf_int_ptr+=samplesinbuf*sizeof(short);
1796 if (!(devpriv->ui_AiFlags & TRIG_WAKE_EOS))
1798 comedi_bufcheck(dev,s);
1801 if (!devpriv->b_AiContinuous)
1802 if ( devpriv->ui_AiActualScan>=devpriv->ui_AiNbrofScans )
1805 i_APCI3120_StopCyclicAcquisition(dev,s);
1806 devpriv->b_AiCyclicAcquisition=APCI3120_DISABLE;
1807 //DPRINTK("\n Single DMA completed..\n");
1813 v_APCI3120_InterruptDmaMoveBlock16bit(dev
, s
,
1814 devpriv
->ul_DmaBufferVirtual
[devpriv
->
1815 ui_DmaActualBuffer
], samplesinbuf
);
1817 if (!(devpriv
->ui_AiFlags
& TRIG_WAKE_EOS
)) {
1818 s
->async
->events
|= COMEDI_CB_EOS
;
1819 comedi_event(dev
, s
);
1822 if (!devpriv
->b_AiContinuous
)
1823 if (devpriv
->ui_AiActualScan
>= devpriv
->ui_AiNbrofScans
) {
1825 i_APCI3120_StopCyclicAcquisition(dev
, s
);
1826 devpriv
->b_AiCyclicAcquisition
= APCI3120_DISABLE
;
1827 s
->async
->events
|= COMEDI_CB_EOA
;
1828 comedi_event(dev
, s
);
1832 if (devpriv
->b_DmaDoubleBuffer
) { // switch dma buffers
1833 devpriv
->ui_DmaActualBuffer
= 1 - devpriv
->ui_DmaActualBuffer
;
1835 // restart DMA if is not used double buffering
1836 //ADDED REINITIALISE THE DMA
1837 ui_Tmp
= AGCSTS_TC_ENABLE
| AGCSTS_RESET_A2P_FIFO
;
1838 outl(ui_Tmp
, devpriv
->i_IobaseAddon
+ AMCC_OP_REG_AGCSTS
);
1840 // changed since 16 bit interface for add on
1841 outw(APCI3120_ADD_ON_AGCSTS_LOW
, devpriv
->i_IobaseAddon
+ 0);
1842 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW
,
1843 devpriv
->i_IobaseAddon
+ 2);
1844 outw(APCI3120_ADD_ON_AGCSTS_HIGH
, devpriv
->i_IobaseAddon
+ 0);
1845 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH
, devpriv
->i_IobaseAddon
+ 2); //
1846 // A2P FIFO MANAGEMENT
1847 // A2P fifo reset & transfer control enable
1848 outl(APCI3120_A2P_FIFO_MANAGEMENT
,
1849 devpriv
->i_IobaseAmcc
+ AMCC_OP_REG_MCSR
);
1851 var
= devpriv
->ul_DmaBufferHw
[0];
1852 low_word
= var
& 0xffff;
1853 var
= devpriv
->ul_DmaBufferHw
[0];
1854 high_word
= var
/ 65536;
1855 outw(APCI3120_ADD_ON_MWAR_LOW
, devpriv
->i_IobaseAddon
+ 0);
1856 outw(low_word
, devpriv
->i_IobaseAddon
+ 2);
1857 outw(APCI3120_ADD_ON_MWAR_HIGH
, devpriv
->i_IobaseAddon
+ 0);
1858 outw(high_word
, devpriv
->i_IobaseAddon
+ 2);
1860 var
= devpriv
->ui_DmaBufferUsesize
[0];
1861 low_word
= var
& 0xffff; //changed
1862 var
= devpriv
->ui_DmaBufferUsesize
[0];
1863 high_word
= var
/ 65536;
1864 outw(APCI3120_ADD_ON_MWTC_LOW
, devpriv
->i_IobaseAddon
+ 0);
1865 outw(low_word
, devpriv
->i_IobaseAddon
+ 2);
1866 outw(APCI3120_ADD_ON_MWTC_HIGH
, devpriv
->i_IobaseAddon
+ 0);
1867 outw(high_word
, devpriv
->i_IobaseAddon
+ 2);
1869 // To configure A2P FIFO
1870 //ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1871 // AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1872 outw(3, devpriv
->i_IobaseAddon
+ 4);
1873 //initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI)
1874 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2
|
1875 APCI3120_ENABLE_WRITE_TC_INT
),
1876 devpriv
->i_IobaseAmcc
+ AMCC_OP_REG_INTCSR
);
1881 +----------------------------------------------------------------------------+
1882 | Function name :void v_APCI3120_InterruptDmaMoveBlock16bit(comedi_device|
1883 |*dev,struct comedi_subdevice *s,short *dma,short *data,int n) |
1885 +----------------------------------------------------------------------------+
1886 | Task : This function copies the data from DMA buffer to the |
1889 +----------------------------------------------------------------------------+
1890 | Input Parameters : struct comedi_device *dev |
1891 | struct comedi_subdevice *s |
1893 | short *data,int n |
1894 +----------------------------------------------------------------------------+
1895 | Return Value : void |
1897 +----------------------------------------------------------------------------+
1900 /*void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev,struct comedi_subdevice *s,short *dma,short *data,int n)
1904 j=s->async->cur_chan;
1905 m=devpriv->ui_AiActualScanPosition;
1911 if(j>=devpriv->ui_AiNbrofChannels)
1915 if(m>=devpriv->ui_AiScanLength)
1918 devpriv->ui_AiActualScan++;
1919 if (devpriv->ui_AiFlags & TRIG_WAKE_EOS)
1920 ;//UPDATE-0.7.57->0.7.68 comedi_eos(dev,s);
1924 devpriv->ui_AiActualScanPosition=m;
1925 s->async->cur_chan=j;
1929 void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device
* dev
,
1930 struct comedi_subdevice
* s
, short * dma_buffer
, unsigned int num_samples
)
1932 devpriv
->ui_AiActualScan
+=
1933 (s
->async
->cur_chan
+ num_samples
) / devpriv
->ui_AiScanLength
;
1934 s
->async
->cur_chan
+= num_samples
;
1935 s
->async
->cur_chan
%= devpriv
->ui_AiScanLength
;
1937 cfc_write_array_to_buffer(s
, dma_buffer
, num_samples
* sizeof(short));
1941 +----------------------------------------------------------------------------+
1943 +----------------------------------------------------------------------------+
1947 +----------------------------------------------------------------------------+
1948 | Function name :int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, |
1949 | struct comedi_subdevice *s,comedi_insn *insn,unsigned int *data) |
1951 +----------------------------------------------------------------------------+
1952 | Task :Configure Timer 2 |
1954 +----------------------------------------------------------------------------+
1955 | Input Parameters : struct comedi_device *dev |
1956 | struct comedi_subdevice *s |
1957 | comedi_insn *insn |
1958 | unsigned int *data |
1960 | data[0]= TIMER configure as timer |
1961 | = WATCHDOG configure as watchdog |
1962 | data[1] = Timer constant |
1963 | data[2] = Timer2 interrupt (1)enable or(0) disable |
1965 +----------------------------------------------------------------------------+
1968 +----------------------------------------------------------------------------+
1971 int i_APCI3120_InsnConfigTimer(struct comedi_device
* dev
, struct comedi_subdevice
* s
,
1972 comedi_insn
* insn
, unsigned int * data
)
1975 UINT ui_Timervalue2
;
1980 comedi_error(dev
, "config:No timer constant !");
1982 devpriv
->b_Timer2Interrupt
= (BYTE
) data
[2]; // save info whether to enable or disable interrupt
1984 ui_Timervalue2
= data
[1] / 1000; // convert nano seconds to u seconds
1986 //this_board->i_hwdrv_InsnConfigTimer(dev, ui_Timervalue2,(BYTE)data[0]);
1987 us_TmpValue
= (USHORT
) inw(devpriv
->iobase
+ APCI3120_RD_STATUS
);
1989 //EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001
1990 // and calculate the time value to set in the timer
1991 if ((us_TmpValue
& 0x00B0) == 0x00B0
1992 || !strcmp(this_board
->pc_DriverName
, "apci3001")) {
1993 //Calculate the time value to set in the timer
1994 ui_Timervalue2
= ui_Timervalue2
/ 50;
1996 //Calculate the time value to set in the timer
1997 ui_Timervalue2
= ui_Timervalue2
/ 70;
2000 //Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0)
2001 devpriv
->us_OutputRegister
=
2002 devpriv
->us_OutputRegister
& APCI3120_DISABLE_TIMER2
;
2003 outw(devpriv
->us_OutputRegister
, devpriv
->iobase
+ APCI3120_WR_ADDRESS
);
2005 // Disable TIMER Interrupt
2006 devpriv
->b_ModeSelectRegister
=
2008 b_ModeSelectRegister
& APCI3120_DISABLE_TIMER_INT
& 0xEF;
2010 // Disable Eoc and Eos Interrupts
2011 devpriv
->b_ModeSelectRegister
=
2013 b_ModeSelectRegister
& APCI3120_DISABLE_EOC_INT
&
2014 APCI3120_DISABLE_EOS_INT
;
2015 outb(devpriv
->b_ModeSelectRegister
,
2016 devpriv
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
2017 if (data
[0] == APCI3120_TIMER
) //initialize timer
2020 //devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister| APCI3120_ENABLE_TIMER_INT ;
2021 //outb(devpriv->b_ModeSelectRegister,devpriv->iobase+APCI3120_WRITE_MODE_SELECT);
2023 //Set the Timer 2 in mode 2(Timer)
2024 devpriv
->b_TimerSelectMode
=
2026 b_TimerSelectMode
& 0x0F) | APCI3120_TIMER_2_MODE_2
;
2027 outb(devpriv
->b_TimerSelectMode
,
2028 devpriv
->iobase
+ APCI3120_TIMER_CRT1
);
2030 //Configure the timer 2 for writing the LOW WORD of timer is Delay value
2031 //You must make a b_tmp variable with DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
2032 //you can set the digital output and configure the timer 2,and if you don't make this, digital output
2033 //are erase (Set to 0)
2037 b_DigitalOutputRegister
) & 0xF0) |
2038 APCI3120_SELECT_TIMER_2_LOW_WORD
;
2039 outb(b_Tmp
, devpriv
->iobase
+ APCI3120_TIMER_CRT0
);
2040 outw(LOWORD(ui_Timervalue2
),
2041 devpriv
->iobase
+ APCI3120_TIMER_VALUE
);
2045 b_DigitalOutputRegister
) & 0xF0) |
2046 APCI3120_SELECT_TIMER_2_HIGH_WORD
;
2047 outb(b_Tmp
, devpriv
->iobase
+ APCI3120_TIMER_CRT0
);
2048 outw(HIWORD(ui_Timervalue2
),
2049 devpriv
->iobase
+ APCI3120_TIMER_VALUE
);
2050 // timer2 in Timer mode enabled
2051 devpriv
->b_Timer2Mode
= APCI3120_TIMER
;
2053 } else // Initialize Watch dog
2056 //Set the Timer 2 in mode 5(Watchdog)
2058 devpriv
->b_TimerSelectMode
=
2060 b_TimerSelectMode
& 0x0F) | APCI3120_TIMER_2_MODE_5
;
2061 outb(devpriv
->b_TimerSelectMode
,
2062 devpriv
->iobase
+ APCI3120_TIMER_CRT1
);
2064 //Configure the timer 2 for writing the LOW WORD of timer is Delay value
2065 //You must make a b_tmp variable with DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
2066 //you can set the digital output and configure the timer 2,and if you don't make this, digital output
2067 //are erase (Set to 0)
2071 b_DigitalOutputRegister
) & 0xF0) |
2072 APCI3120_SELECT_TIMER_2_LOW_WORD
;
2073 outb(b_Tmp
, devpriv
->iobase
+ APCI3120_TIMER_CRT0
);
2074 outw(LOWORD(ui_Timervalue2
),
2075 devpriv
->iobase
+ APCI3120_TIMER_VALUE
);
2079 b_DigitalOutputRegister
) & 0xF0) |
2080 APCI3120_SELECT_TIMER_2_HIGH_WORD
;
2081 outb(b_Tmp
, devpriv
->iobase
+ APCI3120_TIMER_CRT0
);
2083 outw(HIWORD(ui_Timervalue2
),
2084 devpriv
->iobase
+ APCI3120_TIMER_VALUE
);
2086 devpriv
->b_Timer2Mode
= APCI3120_WATCHDOG
;
2095 +----------------------------------------------------------------------------+
2096 | Function name :int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, |
2097 | struct comedi_subdevice *s, comedi_insn *insn,unsigned int *data) |
2099 +----------------------------------------------------------------------------+
2100 | Task : To start and stop the timer |
2101 +----------------------------------------------------------------------------+
2102 | Input Parameters : struct comedi_device *dev |
2103 | struct comedi_subdevice *s |
2104 | comedi_insn *insn |
2105 | unsigned int *data |
2107 | data[0] = 1 (start) |
2108 | data[0] = 0 (stop ) |
2109 | data[0] = 2 (write new value) |
2110 | data[1]= new value |
2112 | devpriv->b_Timer2Mode = 0 DISABLE |
2116 +----------------------------------------------------------------------------+
2119 +----------------------------------------------------------------------------+
2122 int i_APCI3120_InsnWriteTimer(struct comedi_device
* dev
, struct comedi_subdevice
* s
,
2123 comedi_insn
* insn
, unsigned int * data
)
2126 UINT ui_Timervalue2
= 0;
2130 if ((devpriv
->b_Timer2Mode
!= APCI3120_WATCHDOG
)
2131 && (devpriv
->b_Timer2Mode
!= APCI3120_TIMER
)) {
2132 comedi_error(dev
, "\nwrite:timer2 not configured ");
2136 if (data
[0] == 2) // write new value
2138 if (devpriv
->b_Timer2Mode
!= APCI3120_TIMER
) {
2140 "write :timer2 not configured in TIMER MODE");
2145 ui_Timervalue2
= data
[1];
2150 //this_board->i_hwdrv_InsnWriteTimer(dev,data[0],ui_Timervalue2);
2153 case APCI3120_START
:
2155 // Reset FC_TIMER BIT
2156 inb(devpriv
->iobase
+ APCI3120_TIMER_STATUS_REGISTER
);
2157 if (devpriv
->b_Timer2Mode
== APCI3120_TIMER
) //start timer
2160 devpriv
->b_ModeSelectRegister
=
2161 devpriv
->b_ModeSelectRegister
& 0x0B;
2162 } else //start watch dog
2165 devpriv
->b_ModeSelectRegister
=
2167 b_ModeSelectRegister
& 0x0B) |
2168 APCI3120_ENABLE_WATCHDOG
;
2171 //enable disable interrupt
2172 if ((devpriv
->b_Timer2Interrupt
) == APCI3120_ENABLE
) {
2174 devpriv
->b_ModeSelectRegister
=
2176 b_ModeSelectRegister
|
2177 APCI3120_ENABLE_TIMER_INT
;
2178 // save the task structure to pass info to user
2179 devpriv
->tsk_Current
= current
;
2182 devpriv
->b_ModeSelectRegister
=
2184 b_ModeSelectRegister
&
2185 APCI3120_DISABLE_TIMER_INT
;
2187 outb(devpriv
->b_ModeSelectRegister
,
2188 devpriv
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
2190 if (devpriv
->b_Timer2Mode
== APCI3120_TIMER
) //start timer
2192 //For Timer mode is Gate2 must be activated **timer started
2193 devpriv
->us_OutputRegister
=
2195 us_OutputRegister
| APCI3120_ENABLE_TIMER2
;
2196 outw(devpriv
->us_OutputRegister
,
2197 devpriv
->iobase
+ APCI3120_WR_ADDRESS
);
2203 if (devpriv
->b_Timer2Mode
== APCI3120_TIMER
) {
2205 devpriv
->b_ModeSelectRegister
=
2207 b_ModeSelectRegister
&
2208 APCI3120_DISABLE_TIMER_COUNTER
;
2211 devpriv
->b_ModeSelectRegister
=
2213 b_ModeSelectRegister
&
2214 APCI3120_DISABLE_WATCHDOG
;
2216 // Disable timer interrupt
2217 devpriv
->b_ModeSelectRegister
=
2219 b_ModeSelectRegister
& APCI3120_DISABLE_TIMER_INT
;
2221 // Write above states to register
2222 outb(devpriv
->b_ModeSelectRegister
,
2223 devpriv
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
2226 devpriv
->us_OutputRegister
=
2227 devpriv
->us_OutputRegister
& APCI3120_DISABLE_TIMER_INT
;
2228 outw(devpriv
->us_OutputRegister
,
2229 devpriv
->iobase
+ APCI3120_WR_ADDRESS
);
2231 // Reset FC_TIMER BIT
2232 inb(devpriv
->iobase
+ APCI3120_TIMER_STATUS_REGISTER
);
2235 //devpriv->b_Timer2Mode=APCI3120_DISABLE;
2239 case 2: //write new value to Timer
2240 if (devpriv
->b_Timer2Mode
!= APCI3120_TIMER
) {
2242 "write :timer2 not configured in TIMER MODE");
2245 // ui_Timervalue2=data[1]; // passed as argument
2247 (USHORT
) inw(devpriv
->iobase
+ APCI3120_RD_STATUS
);
2249 //EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001
2250 // and calculate the time value to set in the timer
2251 if ((us_TmpValue
& 0x00B0) == 0x00B0
2252 || !strcmp(this_board
->pc_DriverName
, "apci3001")) {
2253 //Calculate the time value to set in the timer
2254 ui_Timervalue2
= ui_Timervalue2
/ 50;
2256 //Calculate the time value to set in the timer
2257 ui_Timervalue2
= ui_Timervalue2
/ 70;
2261 b_DigitalOutputRegister
) & 0xF0) |
2262 APCI3120_SELECT_TIMER_2_LOW_WORD
;
2263 outb(b_Tmp
, devpriv
->iobase
+ APCI3120_TIMER_CRT0
);
2265 outw(LOWORD(ui_Timervalue2
),
2266 devpriv
->iobase
+ APCI3120_TIMER_VALUE
);
2270 b_DigitalOutputRegister
) & 0xF0) |
2271 APCI3120_SELECT_TIMER_2_HIGH_WORD
;
2272 outb(b_Tmp
, devpriv
->iobase
+ APCI3120_TIMER_CRT0
);
2274 outw(HIWORD(ui_Timervalue2
),
2275 devpriv
->iobase
+ APCI3120_TIMER_VALUE
);
2279 return -EINVAL
; // Not a valid input
2286 +----------------------------------------------------------------------------+
2287 | Function name : int i_APCI3120_InsnReadTimer(struct comedi_device *dev, |
2288 | struct comedi_subdevice *s,comedi_insn *insn, unsigned int *data) |
2291 +----------------------------------------------------------------------------+
2292 | Task : read the Timer value |
2293 +----------------------------------------------------------------------------+
2294 | Input Parameters : struct comedi_device *dev |
2295 | struct comedi_subdevice *s |
2296 | comedi_insn *insn |
2297 | unsigned int *data |
2299 +----------------------------------------------------------------------------+
2301 | for Timer: data[0]= Timer constant |
2303 | for watchdog: data[0]=0 (still running) |
2304 | data[0]=1 (run down) |
2306 +----------------------------------------------------------------------------+
2308 int i_APCI3120_InsnReadTimer(struct comedi_device
* dev
, struct comedi_subdevice
* s
,
2309 comedi_insn
* insn
, unsigned int * data
)
2312 USHORT us_TmpValue
, us_TmpValue_2
, us_StatusValue
;
2314 if ((devpriv
->b_Timer2Mode
!= APCI3120_WATCHDOG
)
2315 && (devpriv
->b_Timer2Mode
!= APCI3120_TIMER
)) {
2316 comedi_error(dev
, "\nread:timer2 not configured ");
2319 //this_board->i_hwdrv_InsnReadTimer(dev,data);
2320 if (devpriv
->b_Timer2Mode
== APCI3120_TIMER
) {
2322 //Read the LOW WORD of Timer 2 register
2324 b_DigitalOutputRegister
) & 0xF0) |
2325 APCI3120_SELECT_TIMER_2_LOW_WORD
;
2326 outb(b_Tmp
, devpriv
->iobase
+ APCI3120_TIMER_CRT0
);
2328 us_TmpValue
= inw(devpriv
->iobase
+ APCI3120_TIMER_VALUE
);
2330 //Read the HIGH WORD of Timer 2 register
2332 b_DigitalOutputRegister
) & 0xF0) |
2333 APCI3120_SELECT_TIMER_2_HIGH_WORD
;
2334 outb(b_Tmp
, devpriv
->iobase
+ APCI3120_TIMER_CRT0
);
2336 us_TmpValue_2
= inw(devpriv
->iobase
+ APCI3120_TIMER_VALUE
);
2338 // combining both words
2339 data
[0] = (UINT
) ((us_TmpValue
) | ((us_TmpValue_2
) << 16));
2341 } else // Read watch dog status
2344 us_StatusValue
= inw(devpriv
->iobase
+ APCI3120_RD_STATUS
);
2346 ((us_StatusValue
& APCI3120_FC_TIMER
) >> 12) & 1;
2347 if (us_StatusValue
== 1) {
2348 // RESET FC_TIMER BIT
2349 inb(devpriv
->iobase
+ APCI3120_TIMER_STATUS_REGISTER
);
2351 data
[0] = us_StatusValue
; // when data[0] = 1 then the watch dog has rundown
2357 +----------------------------------------------------------------------------+
2358 | DIGITAL INPUT SUBDEVICE |
2359 +----------------------------------------------------------------------------+
2363 +----------------------------------------------------------------------------+
2364 | Function name :int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev, |
2365 | struct comedi_subdevice *s, comedi_insn *insn,unsigned int *data) |
2368 +----------------------------------------------------------------------------+
2369 | Task : Reads the value of the specified Digital input channel|
2371 +----------------------------------------------------------------------------+
2372 | Input Parameters : struct comedi_device *dev |
2373 | struct comedi_subdevice *s |
2374 | comedi_insn *insn |
2375 | unsigned int *data |
2376 +----------------------------------------------------------------------------+
2379 +----------------------------------------------------------------------------+
2382 int i_APCI3120_InsnReadDigitalInput(struct comedi_device
*dev
,
2383 struct comedi_subdevice
*s
,
2387 UINT ui_Chan
, ui_TmpValue
;
2389 ui_Chan
= CR_CHAN(insn
->chanspec
); // channel specified
2391 //this_board->i_hwdrv_InsnReadDigitalInput(dev,ui_Chan,data);
2392 if (ui_Chan
>= 0 && ui_Chan
<= 3) {
2393 ui_TmpValue
= (UINT
) inw(devpriv
->iobase
+ APCI3120_RD_STATUS
);
2395 // since only 1 channel reqd to bring it to last bit it is rotated
2396 // 8 +(chan - 1) times then ANDed with 1 for last bit.
2397 *data
= (ui_TmpValue
>> (ui_Chan
+ 8)) & 1;
2400 // comedi_error(dev," chan spec wrong");
2401 return -EINVAL
; // "sorry channel spec wrong "
2408 +----------------------------------------------------------------------------+
2409 | Function name :int i_APCI3120_InsnBitsDigitalInput(struct comedi_device *dev, |
2410 |struct comedi_subdevice *s, comedi_insn *insn,unsigned int *data) |
2412 +----------------------------------------------------------------------------+
2413 | Task : Reads the value of the Digital input Port i.e.4channels|
2414 | value is returned in data[0] |
2416 +----------------------------------------------------------------------------+
2417 | Input Parameters : struct comedi_device *dev |
2418 | struct comedi_subdevice *s |
2419 | comedi_insn *insn |
2420 | unsigned int *data |
2421 +----------------------------------------------------------------------------+
2424 +----------------------------------------------------------------------------+
2426 int i_APCI3120_InsnBitsDigitalInput(struct comedi_device
* dev
, struct comedi_subdevice
* s
,
2427 comedi_insn
* insn
, unsigned int * data
)
2430 ui_TmpValue
= (UINT
) inw(devpriv
->iobase
+ APCI3120_RD_STATUS
);
2431 /***** state of 4 channels in the 11, 10, 9, 8 bits of status reg
2432 rotated right 8 times to bring them to last four bits
2433 ANDed with oxf for value.
2436 *data
= (ui_TmpValue
>> 8) & 0xf;
2437 //this_board->i_hwdrv_InsnBitsDigitalInput(dev,data);
2442 +----------------------------------------------------------------------------+
2443 | DIGITAL OUTPUT SUBDEVICE |
2444 +----------------------------------------------------------------------------+
2447 +----------------------------------------------------------------------------+
2448 | Function name :int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device |
2449 | *dev,struct comedi_subdevice *s,comedi_insn *insn,unsigned int *data) |
2451 +----------------------------------------------------------------------------+
2452 | Task :Configure the output memory ON or OFF |
2454 +----------------------------------------------------------------------------+
2455 | Input Parameters :struct comedi_device *dev |
2456 | struct comedi_subdevice *s |
2457 | comedi_insn *insn |
2458 | unsigned int *data |
2459 +----------------------------------------------------------------------------+
2462 +----------------------------------------------------------------------------+
2465 int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device
* dev
,
2466 struct comedi_subdevice
* s
, comedi_insn
* insn
, unsigned int * data
)
2469 if ((data
[0] != 0) && (data
[0] != 1)) {
2471 "Not a valid Data !!! ,Data should be 1 or 0\n");
2475 devpriv
->b_OutputMemoryStatus
= APCI3120_ENABLE
;
2478 devpriv
->b_OutputMemoryStatus
= APCI3120_DISABLE
;
2479 devpriv
->b_DigitalOutputRegister
= 0;
2481 if (!devpriv
->b_OutputMemoryStatus
) {
2484 } //if(!devpriv->b_OutputMemoryStatus )
2490 +----------------------------------------------------------------------------+
2491 | Function name :int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device *dev, |
2492 | struct comedi_subdevice *s, comedi_insn *insn,unsigned int *data) |
2494 +----------------------------------------------------------------------------+
2495 | Task : write diatal output port |
2497 +----------------------------------------------------------------------------+
2498 | Input Parameters : struct comedi_device *dev |
2499 | struct comedi_subdevice *s |
2500 | comedi_insn *insn |
2501 | unsigned int *data |
2502 data[0] Value to be written
2503 data[1] :1 Set digital o/p ON
2504 data[1] 2 Set digital o/p OFF with memory ON
2505 +----------------------------------------------------------------------------+
2508 +----------------------------------------------------------------------------+
2511 int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device
* dev
,
2512 struct comedi_subdevice
*s
,
2516 if ((data
[0] > this_board
->i_DoMaxdata
) || (data
[0] < 0)) {
2518 comedi_error(dev
, "Data is not valid !!! \n");
2524 data
[0] = (data
[0] << 4) | devpriv
->b_DigitalOutputRegister
;
2531 printk("\nThe parameter passed is in error \n");
2533 } // switch(data[1])
2534 outb(data
[0], devpriv
->iobase
+ APCI3120_DIGITAL_OUTPUT
);
2536 devpriv
->b_DigitalOutputRegister
= data
[0] & 0xF0;
2543 +----------------------------------------------------------------------------+
2544 | Function name :int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev,|
2545 |struct comedi_subdevice *s,comedi_insn *insn,unsigned int *data) |
2547 +----------------------------------------------------------------------------+
2548 | Task : Write digiatl output |
2550 +----------------------------------------------------------------------------+
2551 | Input Parameters : struct comedi_device *dev |
2552 | struct comedi_subdevice *s |
2553 | comedi_insn *insn |
2554 | unsigned int *data |
2555 data[0] Value to be written
2556 data[1] :1 Set digital o/p ON
2557 data[1] 2 Set digital o/p OFF with memory ON
2558 +----------------------------------------------------------------------------+
2561 +----------------------------------------------------------------------------+
2564 int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device
*dev
,
2565 struct comedi_subdevice
*s
,
2572 UINT ui_NoOfChannel
= CR_CHAN(insn
->chanspec
); // get the channel
2574 if ((data
[0] != 0) && (data
[0] != 1)) {
2576 "Not a valid Data !!! ,Data should be 1 or 0\n");
2579 if ((ui_NoOfChannel
> (this_board
->i_NbrDoChannel
- 1))
2580 || (ui_NoOfChannel
< 0)) {
2582 "This board doesn't have specified channel !!! \n");
2588 data
[0] = (data
[0] << ui_NoOfChannel
);
2589 //ES05 data[0]=(data[0]<<4)|ui_Temp;
2590 data
[0] = (data
[0] << 4) | devpriv
->b_DigitalOutputRegister
;
2594 data
[0] = ~data
[0] & 0x1;
2596 ui_Temp1
= ui_Temp1
<< ui_NoOfChannel
;
2597 ui_Temp1
= ui_Temp1
<< 4;
2598 //ES05 ui_Temp=ui_Temp|ui_Temp1;
2599 devpriv
->b_DigitalOutputRegister
=
2600 devpriv
->b_DigitalOutputRegister
| ui_Temp1
;
2602 data
[0] = (data
[0] << ui_NoOfChannel
) ^ 0xf;
2603 data
[0] = data
[0] << 4;
2604 //ES05 data[0]=data[0]& ui_Temp;
2605 data
[0] = data
[0] & devpriv
->b_DigitalOutputRegister
;
2608 printk("\nThe parameter passed is in error \n");
2610 } // switch(data[1])
2611 outb(data
[0], devpriv
->iobase
+ APCI3120_DIGITAL_OUTPUT
);
2613 //ES05 ui_Temp=data[0] & 0xf0;
2614 devpriv
->b_DigitalOutputRegister
= data
[0] & 0xf0;
2620 +----------------------------------------------------------------------------+
2621 | ANALOG OUTPUT SUBDEVICE |
2622 +----------------------------------------------------------------------------+
2626 +----------------------------------------------------------------------------+
2627 | Function name :int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,|
2628 |struct comedi_subdevice *s, comedi_insn *insn,unsigned int *data) |
2630 +----------------------------------------------------------------------------+
2631 | Task : Write analog output |
2633 +----------------------------------------------------------------------------+
2634 | Input Parameters : struct comedi_device *dev |
2635 | struct comedi_subdevice *s |
2636 | comedi_insn *insn |
2637 | unsigned int *data |
2638 +----------------------------------------------------------------------------+
2641 +----------------------------------------------------------------------------+
2644 int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device
*dev
,
2645 struct comedi_subdevice
*s
,
2649 UINT ui_Range
, ui_Channel
;
2652 ui_Range
= CR_RANGE(insn
->chanspec
);
2653 ui_Channel
= CR_CHAN(insn
->chanspec
);
2655 //this_board->i_hwdrv_InsnWriteAnalogOutput(dev, ui_Range, ui_Channel,data[0]);
2656 if (ui_Range
) // if 1 then unipolar
2661 ((((ui_Channel
& 0x03) << 14) & 0xC000) | (1 <<
2662 13) | (data
[0] + 8191));
2665 ((((ui_Channel
& 0x03) << 14) & 0xC000) | (1 <<
2668 } else // if 0 then bipolar
2671 ((((ui_Channel
& 0x03) << 14) & 0xC000) | (0 << 13) |
2676 //out put n values at the given channel.
2677 // rt_printk("\nwaiting for DA_READY BIT");
2678 do //Waiting of DA_READY BIT
2681 ((USHORT
) inw(devpriv
->iobase
+
2682 APCI3120_RD_STATUS
)) & 0x0001;
2683 } while (us_TmpValue
!= 0x0001);
2685 if (ui_Channel
<= 3)
2686 // for channel 0-3 out at the register 1 (wrDac1-8)
2687 // data[i] typecasted to ushort since word write is to be done
2688 outw((USHORT
) data
[0],
2689 devpriv
->iobase
+ APCI3120_ANALOG_OUTPUT_1
);
2691 // for channel 4-7 out at the register 2 (wrDac5-8)
2692 //data[i] typecasted to ushort since word write is to be done
2693 outw((USHORT
) data
[0],
2694 devpriv
->iobase
+ APCI3120_ANALOG_OUTPUT_2
);