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