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 should 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
;
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
];
112 devpriv
->b_InterruptMode
= APCI3120_EOC_MODE
;
114 devpriv
->b_EocEosInterrupt
= APCI3120_ENABLE
;
116 devpriv
->b_EocEosInterrupt
= APCI3120_DISABLE
;
123 +----------------------------------------------------------------------------+
124 | Function name :int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, |
125 | struct comedi_subdevice *s,struct comedi_insn *insn, unsigned int *data) |
127 +----------------------------------------------------------------------------+
128 | Task : card specific function |
129 | Reads analog input in synchronous mode |
130 | EOC and EOS is selected as per configured |
131 | if no conversion time is set uses default conversion |
132 | time 10 microsec. |
134 +----------------------------------------------------------------------------+
135 | Input Parameters : struct comedi_device *dev |
136 | struct comedi_subdevice *s |
137 | struct comedi_insn *insn |
138 | unsigned int *data |
139 +----------------------------------------------------------------------------+
142 +----------------------------------------------------------------------------+
145 int i_APCI3120_InsnReadAnalogInput(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
146 struct comedi_insn
*insn
, unsigned int *data
)
148 unsigned short us_ConvertTiming
, us_TmpValue
, i
;
151 /* fix conversion time to 10 us */
152 if (!devpriv
->ui_EocEosConversionTime
) {
153 printk("No timer0 Value using 10 us\n");
154 us_ConvertTiming
= 10;
156 us_ConvertTiming
= (unsigned short) (devpriv
->ui_EocEosConversionTime
/ 1000); /* nano to useconds */
158 /* this_board->i_hwdrv_InsnReadAnalogInput(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]); */
160 /* Clear software registers */
161 devpriv
->b_TimerSelectMode
= 0;
162 devpriv
->b_ModeSelectRegister
= 0;
163 devpriv
->us_OutputRegister
= 0;
164 /* devpriv->b_DigitalOutputRegister=0; */
166 if (insn
->unused
[0] == 222) { /* second insn read */
167 for (i
= 0; i
< insn
->n
; i
++)
168 data
[i
] = devpriv
->ui_AiReadData
[i
];
170 devpriv
->tsk_Current
= current
; /* Save the current process task structure */
172 * Testing if board have the new Quartz and calculate the time value
173 * to set in the timer
177 (unsigned short) inw(devpriv
->iobase
+ APCI3120_RD_STATUS
);
179 /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */
180 if ((us_TmpValue
& 0x00B0) == 0x00B0
181 || !strcmp(this_board
->pc_DriverName
, "apci3001")) {
182 us_ConvertTiming
= (us_ConvertTiming
* 2) - 2;
185 ((us_ConvertTiming
* 12926) / 10000) - 1;
188 us_TmpValue
= (unsigned short) devpriv
->b_InterruptMode
;
190 switch (us_TmpValue
) {
192 case APCI3120_EOC_MODE
:
195 * Testing the interrupt flag and set the EOC bit Clears the FIFO
197 inw(devpriv
->iobase
+ APCI3120_RESET_FIFO
);
199 /* Initialize the sequence array */
201 /* if (!i_APCI3120_SetupChannelList(dev,s,1,chanlist,0)) return -EINVAL; */
203 if (!i_APCI3120_SetupChannelList(dev
, s
, 1,
207 /* Initialize Timer 0 mode 4 */
208 devpriv
->b_TimerSelectMode
=
210 b_TimerSelectMode
& 0xFC) |
211 APCI3120_TIMER_0_MODE_4
;
212 outb(devpriv
->b_TimerSelectMode
,
213 devpriv
->iobase
+ APCI3120_TIMER_CRT1
);
215 /* Reset the scan bit and Disables the EOS, DMA, EOC interrupt */
216 devpriv
->b_ModeSelectRegister
=
218 b_ModeSelectRegister
& APCI3120_DISABLE_SCAN
;
220 if (devpriv
->b_EocEosInterrupt
== APCI3120_ENABLE
) {
222 /* Disables the EOS,DMA and enables the EOC interrupt */
223 devpriv
->b_ModeSelectRegister
=
225 b_ModeSelectRegister
&
226 APCI3120_DISABLE_EOS_INT
) |
227 APCI3120_ENABLE_EOC_INT
;
228 inw(devpriv
->iobase
);
231 devpriv
->b_ModeSelectRegister
=
233 b_ModeSelectRegister
&
234 APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER
;
237 outb(devpriv
->b_ModeSelectRegister
,
238 devpriv
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
241 devpriv
->us_OutputRegister
=
243 us_OutputRegister
& APCI3120_CLEAR_PA_PR
) |
244 APCI3120_ENABLE_TIMER0
;
245 outw(devpriv
->us_OutputRegister
,
246 devpriv
->iobase
+ APCI3120_WR_ADDRESS
);
250 b_DigitalOutputRegister
) & 0xF0) |
251 APCI3120_SELECT_TIMER_0_WORD
;
252 outb(b_Tmp
, devpriv
->iobase
+ APCI3120_TIMER_CRT0
);
254 /* Set the conversion time */
255 outw(us_ConvertTiming
,
256 devpriv
->iobase
+ APCI3120_TIMER_VALUE
);
259 (unsigned short) inw(dev
->iobase
+ APCI3120_RD_STATUS
);
261 if (devpriv
->b_EocEosInterrupt
== APCI3120_DISABLE
) {
264 /* Waiting for the end of conversion */
266 inw(devpriv
->iobase
+
268 } while ((us_TmpValue
& APCI3120_EOC
) ==
271 /* Read the result in FIFO and put it in insn data pointer */
272 us_TmpValue
= inw(devpriv
->iobase
+ 0);
275 inw(devpriv
->iobase
+ APCI3120_RESET_FIFO
);
280 case APCI3120_EOS_MODE
:
282 inw(devpriv
->iobase
);
283 /* Clears the FIFO */
284 inw(devpriv
->iobase
+ APCI3120_RESET_FIFO
);
285 /* clear PA PR and disable timer 0 */
287 devpriv
->us_OutputRegister
=
289 us_OutputRegister
& APCI3120_CLEAR_PA_PR
) |
290 APCI3120_DISABLE_TIMER0
;
292 outw(devpriv
->us_OutputRegister
,
293 devpriv
->iobase
+ APCI3120_WR_ADDRESS
);
295 if (!i_APCI3120_SetupChannelList(dev
, s
,
296 devpriv
->ui_AiNbrofChannels
,
297 devpriv
->ui_AiChannelList
, 0))
300 /* Initialize Timer 0 mode 2 */
301 devpriv
->b_TimerSelectMode
=
303 b_TimerSelectMode
& 0xFC) |
304 APCI3120_TIMER_0_MODE_2
;
305 outb(devpriv
->b_TimerSelectMode
,
306 devpriv
->iobase
+ APCI3120_TIMER_CRT1
);
310 b_DigitalOutputRegister
) & 0xF0) |
311 APCI3120_SELECT_TIMER_0_WORD
;
312 outb(b_Tmp
, devpriv
->iobase
+ APCI3120_TIMER_CRT0
);
314 /* Set the conversion time */
315 outw(us_ConvertTiming
,
316 devpriv
->iobase
+ APCI3120_TIMER_VALUE
);
318 /* Set the scan bit */
319 devpriv
->b_ModeSelectRegister
=
321 b_ModeSelectRegister
| APCI3120_ENABLE_SCAN
;
322 outb(devpriv
->b_ModeSelectRegister
,
323 devpriv
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
325 /* If Interrupt function is loaded */
326 if (devpriv
->b_EocEosInterrupt
== APCI3120_ENABLE
) {
327 /* Disables the EOC,DMA and enables the EOS interrupt */
328 devpriv
->b_ModeSelectRegister
=
330 b_ModeSelectRegister
&
331 APCI3120_DISABLE_EOC_INT
) |
332 APCI3120_ENABLE_EOS_INT
;
333 inw(devpriv
->iobase
);
336 devpriv
->b_ModeSelectRegister
=
338 b_ModeSelectRegister
&
339 APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER
;
341 outb(devpriv
->b_ModeSelectRegister
,
342 devpriv
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
344 inw(devpriv
->iobase
+ APCI3120_RD_STATUS
);
348 devpriv
->us_OutputRegister
=
350 us_OutputRegister
| APCI3120_ENABLE_TIMER0
;
351 outw(devpriv
->us_OutputRegister
,
352 devpriv
->iobase
+ APCI3120_WR_ADDRESS
);
354 /* Start conversion */
355 outw(0, devpriv
->iobase
+ APCI3120_START_CONVERSION
);
357 /* Waiting of end of conversion if interrupt is not installed */
358 if (devpriv
->b_EocEosInterrupt
== APCI3120_DISABLE
) {
359 /* Waiting the end of conversion */
362 inw(devpriv
->iobase
+
364 } while ((us_TmpValue
& APCI3120_EOS
) !=
367 for (i
= 0; i
< devpriv
->ui_AiNbrofChannels
;
369 /* Read the result in FIFO and write them in shared memory */
370 us_TmpValue
= inw(devpriv
->iobase
);
371 data
[i
] = (unsigned int) us_TmpValue
;
374 devpriv
->b_InterruptMode
= APCI3120_EOC_MODE
; /* Restore defaults. */
379 printk("inputs wrong\n");
382 devpriv
->ui_EocEosConversionTime
= 0; /* re initializing the variable; */
390 +----------------------------------------------------------------------------+
391 | Function name :int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev,|
392 | struct comedi_subdevice *s)|
394 +----------------------------------------------------------------------------+
395 | Task : Stops Cyclic acquisition |
397 +----------------------------------------------------------------------------+
398 | Input Parameters : struct comedi_device *dev |
399 | struct comedi_subdevice *s |
401 +----------------------------------------------------------------------------+
404 +----------------------------------------------------------------------------+
407 int i_APCI3120_StopCyclicAcquisition(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
409 /* Disable A2P Fifo write and AMWEN signal */
410 outw(0, devpriv
->i_IobaseAddon
+ 4);
412 /* Disable Bus Master ADD ON */
413 outw(APCI3120_ADD_ON_AGCSTS_LOW
, devpriv
->i_IobaseAddon
+ 0);
414 outw(0, devpriv
->i_IobaseAddon
+ 2);
415 outw(APCI3120_ADD_ON_AGCSTS_HIGH
, devpriv
->i_IobaseAddon
+ 0);
416 outw(0, devpriv
->i_IobaseAddon
+ 2);
418 /* Disable BUS Master PCI */
419 outl(0, devpriv
->i_IobaseAmcc
+ AMCC_OP_REG_MCSR
);
421 /* outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR)&(~AINT_WRITE_COMPL),
422 * devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR); stop amcc irqs */
424 /* outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR)&(~EN_A2P_TRANSFERS),
425 * devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR); stop DMA */
427 /* Disable ext trigger */
428 i_APCI3120_ExttrigDisable(dev
);
430 devpriv
->us_OutputRegister
= 0;
433 us_OutputRegister
& APCI3120_DISABLE_TIMER0
&
434 APCI3120_DISABLE_TIMER1
, dev
->iobase
+ APCI3120_WR_ADDRESS
);
436 outw(APCI3120_DISABLE_ALL_TIMER
, dev
->iobase
+ APCI3120_WR_ADDRESS
);
438 /* DISABLE_ALL_INTERRUPT */
439 outb(APCI3120_DISABLE_ALL_INTERRUPT
,
440 dev
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
442 inb(dev
->iobase
+ APCI3120_RESET_FIFO
);
443 inw(dev
->iobase
+ APCI3120_RD_STATUS
);
444 devpriv
->ui_AiActualScan
= 0;
445 devpriv
->ui_AiActualScanPosition
= 0;
446 s
->async
->cur_chan
= 0;
447 devpriv
->ui_AiBufferPtr
= 0;
448 devpriv
->b_AiContinuous
= 0;
449 devpriv
->ui_DmaActualBuffer
= 0;
451 devpriv
->b_AiCyclicAcquisition
= APCI3120_DISABLE
;
452 devpriv
->b_InterruptMode
= APCI3120_EOC_MODE
;
453 devpriv
->b_EocEosInterrupt
= APCI3120_DISABLE
;
454 i_APCI3120_Reset(dev
);
459 +----------------------------------------------------------------------------+
460 | Function name :int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev|
461 | ,struct comedi_subdevice *s,struct comedi_cmd *cmd) |
463 +----------------------------------------------------------------------------+
464 | Task : Test validity for a command for cyclic anlog input |
467 +----------------------------------------------------------------------------+
468 | Input Parameters : struct comedi_device *dev |
469 | struct comedi_subdevice *s |
470 | struct comedi_cmd *cmd |
471 +----------------------------------------------------------------------------+
474 +----------------------------------------------------------------------------+
477 int i_APCI3120_CommandTestAnalogInput(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
478 struct comedi_cmd
*cmd
)
481 int tmp
; /* divisor1,divisor2; */
483 /* step 1: make sure trigger sources are trivially valid */
485 tmp
= cmd
->start_src
;
486 cmd
->start_src
&= TRIG_NOW
| TRIG_EXT
;
487 if (!cmd
->start_src
|| tmp
!= cmd
->start_src
)
490 tmp
= cmd
->scan_begin_src
;
491 cmd
->scan_begin_src
&= TRIG_TIMER
| TRIG_FOLLOW
;
492 if (!cmd
->scan_begin_src
|| tmp
!= cmd
->scan_begin_src
)
495 tmp
= cmd
->convert_src
;
496 cmd
->convert_src
&= TRIG_TIMER
;
497 if (!cmd
->convert_src
|| tmp
!= cmd
->convert_src
)
500 tmp
= cmd
->scan_end_src
;
501 cmd
->scan_end_src
&= TRIG_COUNT
;
502 if (!cmd
->scan_end_src
|| tmp
!= cmd
->scan_end_src
)
506 cmd
->stop_src
&= TRIG_COUNT
| TRIG_NONE
;
507 if (!cmd
->stop_src
|| tmp
!= cmd
->stop_src
)
513 /* step 2: make sure trigger sources are unique and mutually compatible */
515 if (cmd
->start_src
!= TRIG_NOW
&& cmd
->start_src
!= TRIG_EXT
)
518 if (cmd
->scan_begin_src
!= TRIG_TIMER
&&
519 cmd
->scan_begin_src
!= TRIG_FOLLOW
)
522 if (cmd
->convert_src
!= TRIG_TIMER
)
525 if (cmd
->scan_end_src
!= TRIG_COUNT
) {
526 cmd
->scan_end_src
= TRIG_COUNT
;
530 if (cmd
->stop_src
!= TRIG_NONE
&& cmd
->stop_src
!= TRIG_COUNT
)
536 /* step 3: make sure arguments are trivially compatible */
538 if (cmd
->start_arg
!= 0) {
543 if (cmd
->scan_begin_src
== TRIG_TIMER
) { /* Test Delay timing */
544 if (cmd
->scan_begin_arg
< this_board
->ui_MinDelaytimeNs
) {
545 cmd
->scan_begin_arg
= this_board
->ui_MinDelaytimeNs
;
550 if (cmd
->convert_src
== TRIG_TIMER
) { /* Test Acquisition timing */
551 if (cmd
->scan_begin_src
== TRIG_TIMER
) {
552 if ((cmd
->convert_arg
)
553 && (cmd
->convert_arg
<
554 this_board
->ui_MinAcquisitiontimeNs
)) {
556 this_board
->ui_MinAcquisitiontimeNs
;
560 if (cmd
->convert_arg
<
561 this_board
->ui_MinAcquisitiontimeNs
) {
563 this_board
->ui_MinAcquisitiontimeNs
;
570 if (!cmd
->chanlist_len
) {
571 cmd
->chanlist_len
= 1;
574 if (cmd
->chanlist_len
> this_board
->i_AiChannelList
) {
575 cmd
->chanlist_len
= this_board
->i_AiChannelList
;
578 if (cmd
->stop_src
== TRIG_COUNT
) {
579 if (!cmd
->stop_arg
) {
583 } else { /* TRIG_NONE */
584 if (cmd
->stop_arg
!= 0) {
593 /* step 4: fix up any arguments */
595 if (cmd
->convert_src
== TRIG_TIMER
) {
597 if (cmd
->scan_begin_src
== TRIG_TIMER
&&
598 cmd
->scan_begin_arg
<
599 cmd
->convert_arg
* cmd
->scan_end_arg
) {
600 cmd
->scan_begin_arg
=
601 cmd
->convert_arg
* cmd
->scan_end_arg
;
613 +----------------------------------------------------------------------------+
614 | Function name : int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, |
615 | struct comedi_subdevice *s) |
617 +----------------------------------------------------------------------------+
618 | Task : Does asynchronous acquisition |
619 | Determines the mode 1 or 2. |
621 +----------------------------------------------------------------------------+
622 | Input Parameters : struct comedi_device *dev |
623 | struct comedi_subdevice *s |
625 +----------------------------------------------------------------------------+
628 +----------------------------------------------------------------------------+
631 int i_APCI3120_CommandAnalogInput(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
633 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
635 /* loading private structure with cmd structure inputs */
636 devpriv
->ui_AiFlags
= cmd
->flags
;
637 devpriv
->ui_AiNbrofChannels
= cmd
->chanlist_len
;
638 devpriv
->ui_AiScanLength
= cmd
->scan_end_arg
;
639 devpriv
->pui_AiChannelList
= cmd
->chanlist
;
641 /* UPDATE-0.7.57->0.7.68devpriv->AiData=s->async->data; */
642 devpriv
->AiData
= s
->async
->prealloc_buf
;
643 /* UPDATE-0.7.57->0.7.68devpriv->ui_AiDataLength=s->async->data_len; */
644 devpriv
->ui_AiDataLength
= s
->async
->prealloc_bufsz
;
646 if (cmd
->stop_src
== TRIG_COUNT
)
647 devpriv
->ui_AiNbrofScans
= cmd
->stop_arg
;
649 devpriv
->ui_AiNbrofScans
= 0;
651 devpriv
->ui_AiTimer0
= 0; /* variables changed to timer0,timer1 */
652 devpriv
->ui_AiTimer1
= 0;
653 if ((devpriv
->ui_AiNbrofScans
== 0) || (devpriv
->ui_AiNbrofScans
== -1))
654 devpriv
->b_AiContinuous
= 1; /* user want neverending analog acquisition */
655 /* stopped using cancel */
657 if (cmd
->start_src
== TRIG_EXT
)
658 devpriv
->b_ExttrigEnable
= APCI3120_ENABLE
;
660 devpriv
->b_ExttrigEnable
= APCI3120_DISABLE
;
662 if (cmd
->scan_begin_src
== TRIG_FOLLOW
) {
664 if (cmd
->convert_src
== TRIG_TIMER
) {
667 devpriv
->ui_AiTimer0
= cmd
->convert_arg
; /* timer constant in nano seconds */
668 /* return this_board->i_hwdrv_CommandAnalogInput(1,dev,s); */
669 return i_APCI3120_CyclicAnalogInput(1, dev
, s
);
673 if ((cmd
->scan_begin_src
== TRIG_TIMER
)
674 && (cmd
->convert_src
== TRIG_TIMER
)) {
676 devpriv
->ui_AiTimer1
= cmd
->scan_begin_arg
;
677 devpriv
->ui_AiTimer0
= cmd
->convert_arg
; /* variable changed timer2 to timer0 */
678 /* return this_board->i_hwdrv_CommandAnalogInput(2,dev,s); */
679 return i_APCI3120_CyclicAnalogInput(2, dev
, s
);
685 +----------------------------------------------------------------------------+
686 | Function name : int i_APCI3120_CyclicAnalogInput(int mode, |
687 | struct comedi_device * dev,struct comedi_subdevice * s) |
688 +----------------------------------------------------------------------------+
689 | Task : This is used for analog input cyclic acquisition |
690 | Performs the command operations. |
691 | If DMA is configured does DMA initialization |
692 | otherwise does the acquisition with EOS interrupt. |
694 +----------------------------------------------------------------------------+
695 | Input Parameters : |
698 +----------------------------------------------------------------------------+
701 +----------------------------------------------------------------------------+
704 int i_APCI3120_CyclicAnalogInput(int mode
, struct comedi_device
*dev
,
705 struct comedi_subdevice
*s
)
708 unsigned int ui_Tmp
, ui_DelayTiming
= 0, ui_TimerValue1
= 0, dmalen0
=
709 0, dmalen1
= 0, ui_TimerValue2
=
710 0, ui_TimerValue0
, ui_ConvertTiming
;
711 unsigned short us_TmpValue
;
713 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
714 /* devpriv->b_AiCyclicAcquisition=APCI3120_ENABLE; */
715 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
717 /*******************/
718 /* Resets the FIFO */
719 /*******************/
720 inb(dev
->iobase
+ APCI3120_RESET_FIFO
);
722 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
723 /* inw(dev->iobase+APCI3120_RD_STATUS); */
724 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
726 /***************************/
727 /* Acquisition initialized */
728 /***************************/
729 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
730 devpriv
->b_AiCyclicAcquisition
= APCI3120_ENABLE
;
731 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
733 /* clear software registers */
734 devpriv
->b_TimerSelectMode
= 0;
735 devpriv
->us_OutputRegister
= 0;
736 devpriv
->b_ModeSelectRegister
= 0;
737 /* devpriv->b_DigitalOutputRegister=0; */
739 /* COMMENT JK 07.05.04: Followings calls are in i_APCI3120_StartAnalogInputAcquisition */
741 /****************************/
742 /* Clear Timer Write TC int */
743 /****************************/
744 outl(APCI3120_CLEAR_WRITE_TC_INT
,
745 devpriv
->i_IobaseAmcc
+ APCI3120_AMCC_OP_REG_INTCSR
);
747 /************************************/
748 /* Clears the timer status register */
749 /************************************/
751 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
752 /* inw(dev->iobase+APCI3120_TIMER_STATUS_REGISTER); */
753 /* inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); */
754 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
756 /**************************/
757 /* Disables All Timer */
758 /* Sets PR and PA to 0 */
759 /**************************/
760 devpriv
->us_OutputRegister
= devpriv
->us_OutputRegister
&
761 APCI3120_DISABLE_TIMER0
&
762 APCI3120_DISABLE_TIMER1
& APCI3120_CLEAR_PA_PR
;
764 outw(devpriv
->us_OutputRegister
, dev
->iobase
+ APCI3120_WR_ADDRESS
);
766 /*******************/
767 /* Resets the FIFO */
768 /*******************/
769 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
770 inb(devpriv
->iobase
+ APCI3120_RESET_FIFO
);
771 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
773 devpriv
->ui_AiActualScan
= 0;
774 devpriv
->ui_AiActualScanPosition
= 0;
775 s
->async
->cur_chan
= 0;
776 devpriv
->ui_AiBufferPtr
= 0;
777 devpriv
->ui_DmaActualBuffer
= 0;
779 /* value for timer2 minus -2 has to be done .....dunno y?? */
780 ui_TimerValue2
= devpriv
->ui_AiNbrofScans
- 2;
781 ui_ConvertTiming
= devpriv
->ui_AiTimer0
;
784 ui_DelayTiming
= devpriv
->ui_AiTimer1
;
786 /**********************************/
787 /* Initializes the sequence array */
788 /**********************************/
789 if (!i_APCI3120_SetupChannelList(dev
, s
, devpriv
->ui_AiNbrofChannels
,
790 devpriv
->pui_AiChannelList
, 0))
793 us_TmpValue
= (unsigned short) inw(dev
->iobase
+ APCI3120_RD_STATUS
);
794 /*** EL241003 : add this section in comment because floats must not be used
795 if((us_TmpValue & 0x00B0)==0x00B0)
797 f_ConvertValue=(((float)ui_ConvertTiming * 0.002) - 2);
798 ui_TimerValue0=(unsigned int)f_ConvertValue;
801 f_DelayValue = (((float)ui_DelayTiming * 0.00002) - 2);
802 ui_TimerValue1 = (unsigned int) f_DelayValue;
807 f_ConvertValue=(((float)ui_ConvertTiming * 0.0012926) - 1);
808 ui_TimerValue0=(unsigned int)f_ConvertValue;
811 f_DelayValue = (((float)ui_DelayTiming * 0.000012926) - 1);
812 ui_TimerValue1 = (unsigned int) f_DelayValue;
815 ***********************************************************************************************/
816 /*** EL241003 Begin : add this section to replace floats calculation by integer calculations **/
817 /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */
818 if ((us_TmpValue
& 0x00B0) == 0x00B0
819 || !strcmp(this_board
->pc_DriverName
, "apci3001")) {
820 ui_TimerValue0
= ui_ConvertTiming
* 2 - 2000;
821 ui_TimerValue0
= ui_TimerValue0
/ 1000;
824 ui_DelayTiming
= ui_DelayTiming
/ 1000;
825 ui_TimerValue1
= ui_DelayTiming
* 2 - 200;
826 ui_TimerValue1
= ui_TimerValue1
/ 100;
829 ui_ConvertTiming
= ui_ConvertTiming
/ 1000;
830 ui_TimerValue0
= ui_ConvertTiming
* 12926 - 10000;
831 ui_TimerValue0
= ui_TimerValue0
/ 10000;
834 ui_DelayTiming
= ui_DelayTiming
/ 1000;
835 ui_TimerValue1
= ui_DelayTiming
* 12926 - 1;
836 ui_TimerValue1
= ui_TimerValue1
/ 1000000;
839 /*** EL241003 End ******************************************************************************/
841 if (devpriv
->b_ExttrigEnable
== APCI3120_ENABLE
)
842 i_APCI3120_ExttrigEnable(dev
); /* activate EXT trigger */
845 /* init timer0 in mode 2 */
846 devpriv
->b_TimerSelectMode
=
848 b_TimerSelectMode
& 0xFC) | APCI3120_TIMER_0_MODE_2
;
849 outb(devpriv
->b_TimerSelectMode
,
850 dev
->iobase
+ APCI3120_TIMER_CRT1
);
854 b_DigitalOutputRegister
) & 0xF0) |
855 APCI3120_SELECT_TIMER_0_WORD
;
856 outb(b_Tmp
, dev
->iobase
+ APCI3120_TIMER_CRT0
);
857 /* Set the conversion time */
858 outw(((unsigned short) ui_TimerValue0
),
859 dev
->iobase
+ APCI3120_TIMER_VALUE
);
863 /* init timer1 in mode 2 */
864 devpriv
->b_TimerSelectMode
=
866 b_TimerSelectMode
& 0xF3) | APCI3120_TIMER_1_MODE_2
;
867 outb(devpriv
->b_TimerSelectMode
,
868 dev
->iobase
+ APCI3120_TIMER_CRT1
);
872 b_DigitalOutputRegister
) & 0xF0) |
873 APCI3120_SELECT_TIMER_1_WORD
;
874 outb(b_Tmp
, dev
->iobase
+ APCI3120_TIMER_CRT0
);
875 /* Set the conversion time */
876 outw(((unsigned short) ui_TimerValue1
),
877 dev
->iobase
+ APCI3120_TIMER_VALUE
);
879 /* init timer0 in mode 2 */
880 devpriv
->b_TimerSelectMode
=
882 b_TimerSelectMode
& 0xFC) | APCI3120_TIMER_0_MODE_2
;
883 outb(devpriv
->b_TimerSelectMode
,
884 dev
->iobase
+ APCI3120_TIMER_CRT1
);
888 b_DigitalOutputRegister
) & 0xF0) |
889 APCI3120_SELECT_TIMER_0_WORD
;
890 outb(b_Tmp
, dev
->iobase
+ APCI3120_TIMER_CRT0
);
892 /* Set the conversion time */
893 outw(((unsigned short) ui_TimerValue0
),
894 dev
->iobase
+ APCI3120_TIMER_VALUE
);
898 /* ##########common for all modes################# */
900 /***********************/
901 /* Clears the SCAN bit */
902 /***********************/
904 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
905 /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister | APCI3120_DISABLE_SCAN; */
907 devpriv
->b_ModeSelectRegister
= devpriv
->b_ModeSelectRegister
&
908 APCI3120_DISABLE_SCAN
;
909 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
911 outb(devpriv
->b_ModeSelectRegister
,
912 dev
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
914 /* If DMA is disabled */
915 if (devpriv
->us_UseDma
== APCI3120_DISABLE
) {
916 /* disable EOC and enable EOS */
917 devpriv
->b_InterruptMode
= APCI3120_EOS_MODE
;
918 devpriv
->b_EocEosInterrupt
= APCI3120_ENABLE
;
920 devpriv
->b_ModeSelectRegister
=
922 b_ModeSelectRegister
& APCI3120_DISABLE_EOC_INT
) |
923 APCI3120_ENABLE_EOS_INT
;
924 outb(devpriv
->b_ModeSelectRegister
,
925 dev
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
927 if (!devpriv
->b_AiContinuous
) {
929 * configure Timer2 For counting EOS Reset gate 2 of Timer 2 to
930 * disable it (Set Bit D14 to 0)
932 devpriv
->us_OutputRegister
=
934 us_OutputRegister
& APCI3120_DISABLE_TIMER2
;
935 outw(devpriv
->us_OutputRegister
,
936 dev
->iobase
+ APCI3120_WR_ADDRESS
);
938 /* DISABLE TIMER intERRUPT */
939 devpriv
->b_ModeSelectRegister
=
941 b_ModeSelectRegister
&
942 APCI3120_DISABLE_TIMER_INT
& 0xEF;
943 outb(devpriv
->b_ModeSelectRegister
,
944 dev
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
946 /* (1) Init timer 2 in mode 0 and write timer value */
947 devpriv
->b_TimerSelectMode
=
949 b_TimerSelectMode
& 0x0F) |
950 APCI3120_TIMER_2_MODE_0
;
951 outb(devpriv
->b_TimerSelectMode
,
952 dev
->iobase
+ APCI3120_TIMER_CRT1
);
954 /* Writing LOW unsigned short */
956 b_DigitalOutputRegister
) & 0xF0) |
957 APCI3120_SELECT_TIMER_2_LOW_WORD
;
958 outb(b_Tmp
, dev
->iobase
+ APCI3120_TIMER_CRT0
);
959 outw(LOWORD(ui_TimerValue2
),
960 dev
->iobase
+ APCI3120_TIMER_VALUE
);
962 /* Writing HIGH unsigned short */
964 b_DigitalOutputRegister
) & 0xF0) |
965 APCI3120_SELECT_TIMER_2_HIGH_WORD
;
966 outb(b_Tmp
, dev
->iobase
+ APCI3120_TIMER_CRT0
);
967 outw(HIWORD(ui_TimerValue2
),
968 dev
->iobase
+ APCI3120_TIMER_VALUE
);
970 /* (2) Reset FC_TIMER BIT Clearing timer status register */
971 inb(dev
->iobase
+ APCI3120_TIMER_STATUS_REGISTER
);
972 /* enable timer counter and disable watch dog */
973 devpriv
->b_ModeSelectRegister
=
975 b_ModeSelectRegister
|
976 APCI3120_ENABLE_TIMER_COUNTER
) &
977 APCI3120_DISABLE_WATCHDOG
;
978 /* select EOS clock input for timer 2 */
979 devpriv
->b_ModeSelectRegister
=
981 b_ModeSelectRegister
|
982 APCI3120_TIMER2_SELECT_EOS
;
983 /* Enable timer2 interrupt */
984 devpriv
->b_ModeSelectRegister
=
986 b_ModeSelectRegister
|
987 APCI3120_ENABLE_TIMER_INT
;
988 outb(devpriv
->b_ModeSelectRegister
,
989 dev
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
990 devpriv
->b_Timer2Mode
= APCI3120_COUNTER
;
991 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
;
1042 if (dmalen1
> (devpriv
->ui_AiDataLength
))
1043 dmalen1
= devpriv
->ui_AiDataLength
;
1045 devpriv
->ui_DmaBufferUsesize
[0] = dmalen0
;
1046 devpriv
->ui_DmaBufferUsesize
[1] = dmalen1
;
1048 /* Initialize DMA */
1051 * Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS
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 * TO VERIFIED BEGIN JK 07.05.04: Comparison between WIN32 and Linux
1073 outw(0x1000, devpriv
->i_IobaseAddon
+ 2);
1074 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1077 /* A2P FIFO MANAGEMENT */
1078 /* A2P fifo reset & transfer control enable */
1080 /***********************/
1081 /* A2P FIFO MANAGEMENT */
1082 /***********************/
1083 outl(APCI3120_A2P_FIFO_MANAGEMENT
, devpriv
->i_IobaseAmcc
+
1084 APCI3120_AMCC_OP_MCSR
);
1088 * beginning address of dma buf The 32 bit address of dma buffer
1089 * is converted into two 16 bit addresses Can done by using _attach
1090 * and put into into an array array used may be for differnet pages
1093 /* DMA Start Address Low */
1094 outw(APCI3120_ADD_ON_MWAR_LOW
, devpriv
->i_IobaseAddon
+ 0);
1095 outw((devpriv
->ul_DmaBufferHw
[0] & 0xFFFF),
1096 devpriv
->i_IobaseAddon
+ 2);
1098 /*************************/
1099 /* DMA Start Address High */
1100 /*************************/
1101 outw(APCI3120_ADD_ON_MWAR_HIGH
, devpriv
->i_IobaseAddon
+ 0);
1102 outw((devpriv
->ul_DmaBufferHw
[0] / 65536),
1103 devpriv
->i_IobaseAddon
+ 2);
1107 * amount of bytes to be transferred set transfer count used ADDON
1108 * MWTC register commented testing
1109 * outl(devpriv->ui_DmaBufferUsesize[0],
1110 * devpriv->i_IobaseAddon+AMCC_OP_REG_AMWTC);
1113 /**************************/
1114 /* Nbr of acquisition LOW */
1115 /**************************/
1116 outw(APCI3120_ADD_ON_MWTC_LOW
, devpriv
->i_IobaseAddon
+ 0);
1117 outw((devpriv
->ui_DmaBufferUsesize
[0] & 0xFFFF),
1118 devpriv
->i_IobaseAddon
+ 2);
1120 /***************************/
1121 /* Nbr of acquisition HIGH */
1122 /***************************/
1123 outw(APCI3120_ADD_ON_MWTC_HIGH
, devpriv
->i_IobaseAddon
+ 0);
1124 outw((devpriv
->ui_DmaBufferUsesize
[0] / 65536),
1125 devpriv
->i_IobaseAddon
+ 2);
1129 * To configure A2P FIFO testing outl(
1130 * FIFO_ADVANCE_ON_BYTE_2,devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR);
1133 /******************/
1134 /* A2P FIFO RESET */
1135 /******************/
1137 * TO VERIFY BEGIN JK 07.05.04: Comparison between WIN32 and Linux
1140 outl(0x04000000UL
, devpriv
->i_IobaseAmcc
+ AMCC_OP_REG_MCSR
);
1141 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1145 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN AMWEN_ENABLE |
1146 * A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1149 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1150 /* outw(3,devpriv->i_IobaseAddon + 4); */
1151 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1155 * initialise end of dma interrupt AINT_WRITE_COMPL =
1156 * ENABLE_WRITE_TC_INT(ADDI)
1158 /***************************************************/
1159 /* A2P FIFO CONFIGURATE, END OF DMA intERRUPT INIT */
1160 /***************************************************/
1161 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2
|
1162 APCI3120_ENABLE_WRITE_TC_INT
),
1163 devpriv
->i_IobaseAmcc
+ AMCC_OP_REG_INTCSR
);
1165 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1166 /******************************************/
1167 /* ENABLE A2P FIFO WRITE AND ENABLE AMWEN */
1168 /******************************************/
1169 outw(3, devpriv
->i_IobaseAddon
+ 4);
1170 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1172 /******************/
1173 /* A2P FIFO RESET */
1174 /******************/
1175 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1177 devpriv
->i_IobaseAmcc
+ APCI3120_AMCC_OP_MCSR
);
1178 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1181 if ((devpriv
->us_UseDma
== APCI3120_DISABLE
)
1182 && !devpriv
->b_AiContinuous
) {
1183 /* set gate 2 to start conversion */
1184 devpriv
->us_OutputRegister
=
1185 devpriv
->us_OutputRegister
| APCI3120_ENABLE_TIMER2
;
1186 outw(devpriv
->us_OutputRegister
,
1187 dev
->iobase
+ APCI3120_WR_ADDRESS
);
1192 /* set gate 0 to start conversion */
1193 devpriv
->us_OutputRegister
=
1194 devpriv
->us_OutputRegister
| APCI3120_ENABLE_TIMER0
;
1195 outw(devpriv
->us_OutputRegister
,
1196 dev
->iobase
+ APCI3120_WR_ADDRESS
);
1199 /* set gate 0 and gate 1 */
1200 devpriv
->us_OutputRegister
=
1201 devpriv
->us_OutputRegister
| APCI3120_ENABLE_TIMER1
;
1202 devpriv
->us_OutputRegister
=
1203 devpriv
->us_OutputRegister
| APCI3120_ENABLE_TIMER0
;
1204 outw(devpriv
->us_OutputRegister
,
1205 dev
->iobase
+ APCI3120_WR_ADDRESS
);
1215 +----------------------------------------------------------------------------+
1216 | intERNAL FUNCTIONS |
1217 +----------------------------------------------------------------------------+
1221 +----------------------------------------------------------------------------+
1222 | Function name : int i_APCI3120_Reset(struct comedi_device *dev) |
1225 +----------------------------------------------------------------------------+
1226 | Task : Hardware reset function |
1228 +----------------------------------------------------------------------------+
1229 | Input Parameters : struct comedi_device *dev |
1232 +----------------------------------------------------------------------------+
1235 +----------------------------------------------------------------------------+
1238 int i_APCI3120_Reset(struct comedi_device
*dev
)
1241 unsigned short us_TmpValue
;
1243 devpriv
->b_AiCyclicAcquisition
= APCI3120_DISABLE
;
1244 devpriv
->b_EocEosInterrupt
= APCI3120_DISABLE
;
1245 devpriv
->b_InterruptMode
= APCI3120_EOC_MODE
;
1246 devpriv
->ui_EocEosConversionTime
= 0; /* set eoc eos conv time to 0 */
1247 devpriv
->b_OutputMemoryStatus
= 0;
1249 /* variables used in timer subdevice */
1250 devpriv
->b_Timer2Mode
= 0;
1251 devpriv
->b_Timer2Interrupt
= 0;
1252 devpriv
->b_ExttrigEnable
= 0; /* Disable ext trigger */
1254 /* Disable all interrupts, watchdog for the anolog output */
1255 devpriv
->b_ModeSelectRegister
= 0;
1256 outb(devpriv
->b_ModeSelectRegister
,
1257 dev
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
1259 /* Disables all counters, ext trigger and clears PA, PR */
1260 devpriv
->us_OutputRegister
= 0;
1261 outw(devpriv
->us_OutputRegister
, dev
->iobase
+ APCI3120_WR_ADDRESS
);
1264 * Code to set the all anolog o/p channel to 0v 8191 is decimal
1265 * value for zero(0 v)volt in bipolar mode(default)
1267 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_1
, dev
->iobase
+ APCI3120_ANALOG_OUTPUT_1
); /* channel 1 */
1268 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_2
, dev
->iobase
+ APCI3120_ANALOG_OUTPUT_1
); /* channel 2 */
1269 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_3
, dev
->iobase
+ APCI3120_ANALOG_OUTPUT_1
); /* channel 3 */
1270 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_4
, dev
->iobase
+ APCI3120_ANALOG_OUTPUT_1
); /* channel 4 */
1272 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_5
, dev
->iobase
+ APCI3120_ANALOG_OUTPUT_2
); /* channel 5 */
1273 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_6
, dev
->iobase
+ APCI3120_ANALOG_OUTPUT_2
); /* channel 6 */
1274 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_7
, dev
->iobase
+ APCI3120_ANALOG_OUTPUT_2
); /* channel 7 */
1275 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_8
, dev
->iobase
+ APCI3120_ANALOG_OUTPUT_2
); /* channel 8 */
1277 /* Reset digital output to L0W */
1279 /* ES05 outb(0x0,dev->iobase+APCI3120_DIGITAL_OUTPUT); */
1282 inw(dev
->iobase
+ 0); /* make a dummy read */
1283 inb(dev
->iobase
+ APCI3120_RESET_FIFO
); /* flush FIFO */
1284 inw(dev
->iobase
+ APCI3120_RD_STATUS
); /* flush A/D status register */
1286 /* code to reset the RAM sequence */
1287 for (i
= 0; i
< 16; i
++) {
1288 us_TmpValue
= i
<< 8; /* select the location */
1289 outw(us_TmpValue
, dev
->iobase
+ APCI3120_SEQ_RAM_ADDRESS
);
1295 +----------------------------------------------------------------------------+
1296 | Function name : int i_APCI3120_SetupChannelList(struct comedi_device * dev, |
1297 | struct comedi_subdevice * s, int n_chan,unsigned int *chanlist|
1300 +----------------------------------------------------------------------------+
1301 | Task :This function will first check channel list is ok or not|
1302 |and then initialize the sequence RAM with the polarity, Gain,Channel number |
1303 |If the last argument of function "check"is 1 then it only checks the channel|
1304 |list is ok or not. |
1306 +----------------------------------------------------------------------------+
1307 | Input Parameters : struct comedi_device * dev |
1308 | struct comedi_subdevice * s |
1310 unsigned int *chanlist
1312 +----------------------------------------------------------------------------+
1315 +----------------------------------------------------------------------------+
1318 int i_APCI3120_SetupChannelList(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
1319 int n_chan
, unsigned int *chanlist
, char check
)
1321 unsigned int i
; /* , differencial=0, bipolar=0; */
1323 unsigned short us_TmpValue
;
1325 /* correct channel and range number check itself comedi/range.c */
1328 comedi_error(dev
, "range/channel list is empty!");
1331 /* All is ok, so we can setup channel/range list */
1335 /* Code to set the PA and PR...Here it set PA to 0.. */
1336 devpriv
->us_OutputRegister
=
1337 devpriv
->us_OutputRegister
& APCI3120_CLEAR_PA_PR
;
1338 devpriv
->us_OutputRegister
= ((n_chan
- 1) & 0xf) << 8;
1339 outw(devpriv
->us_OutputRegister
, dev
->iobase
+ APCI3120_WR_ADDRESS
);
1341 for (i
= 0; i
< n_chan
; i
++) {
1342 /* store range list to card */
1343 us_TmpValue
= CR_CHAN(chanlist
[i
]); /* get channel number; */
1345 if (CR_RANGE(chanlist
[i
]) < APCI3120_BIPOLAR_RANGES
)
1346 us_TmpValue
&= ((~APCI3120_UNIPOLAR
) & 0xff); /* set bipolar */
1348 us_TmpValue
|= APCI3120_UNIPOLAR
; /* enable unipolar...... */
1350 gain
= CR_RANGE(chanlist
[i
]); /* get gain number */
1351 us_TmpValue
|= ((gain
& 0x03) << 4); /* <<4 for G0 and G1 bit in RAM */
1352 us_TmpValue
|= i
<< 8; /* To select the RAM LOCATION.... */
1353 outw(us_TmpValue
, dev
->iobase
+ APCI3120_SEQ_RAM_ADDRESS
);
1355 printk("\n Gain = %i",
1356 (((unsigned char)CR_RANGE(chanlist
[i
]) & 0x03) << 2));
1357 printk("\n Channel = %i", CR_CHAN(chanlist
[i
]));
1358 printk("\n Polarity = %i", us_TmpValue
& APCI3120_UNIPOLAR
);
1360 return 1; /* we can serve this with scan logic */
1364 +----------------------------------------------------------------------------+
1365 | Function name : int i_APCI3120_ExttrigEnable(struct comedi_device * dev) |
1368 +----------------------------------------------------------------------------+
1369 | Task : Enable the external trigger |
1371 +----------------------------------------------------------------------------+
1372 | Input Parameters : struct comedi_device * dev |
1375 +----------------------------------------------------------------------------+
1376 | Return Value : 0 |
1378 +----------------------------------------------------------------------------+
1381 int i_APCI3120_ExttrigEnable(struct comedi_device
*dev
)
1384 devpriv
->us_OutputRegister
|= APCI3120_ENABLE_EXT_TRIGGER
;
1385 outw(devpriv
->us_OutputRegister
, dev
->iobase
+ APCI3120_WR_ADDRESS
);
1390 +----------------------------------------------------------------------------+
1391 | Function name : int i_APCI3120_ExttrigDisable(struct comedi_device * dev) |
1393 +----------------------------------------------------------------------------+
1394 | Task : Disables the external trigger |
1396 +----------------------------------------------------------------------------+
1397 | Input Parameters : struct comedi_device * dev |
1400 +----------------------------------------------------------------------------+
1401 | Return Value : 0 |
1403 +----------------------------------------------------------------------------+
1406 int i_APCI3120_ExttrigDisable(struct comedi_device
*dev
)
1408 devpriv
->us_OutputRegister
&= ~APCI3120_ENABLE_EXT_TRIGGER
;
1409 outw(devpriv
->us_OutputRegister
, dev
->iobase
+ APCI3120_WR_ADDRESS
);
1414 +----------------------------------------------------------------------------+
1415 | intERRUPT FUNCTIONS |
1416 +----------------------------------------------------------------------------+
1420 +----------------------------------------------------------------------------+
1421 | Function name : void v_APCI3120_Interrupt(int irq, void *d) |
1424 +----------------------------------------------------------------------------+
1425 | Task :Interrupt handler for APCI3120 |
1426 | When interrupt occurs this gets called. |
1427 | First it finds which interrupt has been generated and |
1428 | handles corresponding interrupt |
1430 +----------------------------------------------------------------------------+
1431 | Input Parameters : int irq |
1434 +----------------------------------------------------------------------------+
1435 | Return Value : void |
1437 +----------------------------------------------------------------------------+
1440 void v_APCI3120_Interrupt(int irq
, void *d
)
1442 struct comedi_device
*dev
= d
;
1443 unsigned short int_daq
;
1445 unsigned int int_amcc
, ui_Check
, i
;
1446 unsigned short us_TmpValue
;
1447 unsigned char b_DummyRead
;
1449 struct comedi_subdevice
*s
= dev
->subdevices
+ 0;
1452 int_daq
= inw(dev
->iobase
+ APCI3120_RD_STATUS
) & 0xf000; /* get IRQ reasons */
1453 int_amcc
= inl(devpriv
->i_IobaseAmcc
+ AMCC_OP_REG_INTCSR
); /* get AMCC int register */
1455 if ((!int_daq
) && (!(int_amcc
& ANY_S593X_INT
))) {
1456 comedi_error(dev
, "IRQ from unknown source");
1460 outl(int_amcc
| 0x00ff0000, devpriv
->i_IobaseAmcc
+ AMCC_OP_REG_INTCSR
); /* shutdown IRQ reasons in AMCC */
1462 int_daq
= (int_daq
>> 12) & 0xF;
1464 if (devpriv
->b_ExttrigEnable
== APCI3120_ENABLE
) {
1465 /* Disable ext trigger */
1466 i_APCI3120_ExttrigDisable(dev
);
1467 devpriv
->b_ExttrigEnable
= APCI3120_DISABLE
;
1469 /* clear the timer 2 interrupt */
1470 inb(devpriv
->i_IobaseAmcc
+ APCI3120_TIMER_STATUS_REGISTER
);
1472 if (int_amcc
& MASTER_ABORT_INT
)
1473 comedi_error(dev
, "AMCC IRQ - MASTER DMA ABORT!");
1474 if (int_amcc
& TARGET_ABORT_INT
)
1475 comedi_error(dev
, "AMCC IRQ - TARGET DMA ABORT!");
1477 /* Ckeck if EOC interrupt */
1478 if (((int_daq
& 0x8) == 0)
1479 && (devpriv
->b_InterruptMode
== APCI3120_EOC_MODE
)) {
1480 if (devpriv
->b_EocEosInterrupt
== APCI3120_ENABLE
) {
1482 /* Read the AI Value */
1484 devpriv
->ui_AiReadData
[0] =
1485 (unsigned int) inw(devpriv
->iobase
+ 0);
1486 devpriv
->b_EocEosInterrupt
= APCI3120_DISABLE
;
1487 send_sig(SIGIO
, devpriv
->tsk_Current
, 0); /* send signal to the sample */
1489 /* Disable EOC Interrupt */
1490 devpriv
->b_ModeSelectRegister
=
1492 b_ModeSelectRegister
& APCI3120_DISABLE_EOC_INT
;
1493 outb(devpriv
->b_ModeSelectRegister
,
1494 devpriv
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
1499 /* Check If EOS interrupt */
1500 if ((int_daq
& 0x2) && (devpriv
->b_InterruptMode
== APCI3120_EOS_MODE
)) {
1502 if (devpriv
->b_EocEosInterrupt
== APCI3120_ENABLE
) { /* enable this in without DMA ??? */
1504 if (devpriv
->b_AiCyclicAcquisition
== APCI3120_ENABLE
) {
1506 i_APCI3120_InterruptHandleEos(dev
);
1507 devpriv
->ui_AiActualScan
++;
1508 devpriv
->b_ModeSelectRegister
=
1510 b_ModeSelectRegister
|
1511 APCI3120_ENABLE_EOS_INT
;
1512 outb(devpriv
->b_ModeSelectRegister
,
1514 APCI3120_WRITE_MODE_SELECT
);
1517 for (i
= 0; i
< devpriv
->ui_AiNbrofChannels
;
1519 us_TmpValue
= inw(devpriv
->iobase
+ 0);
1520 devpriv
->ui_AiReadData
[i
] =
1521 (unsigned int) us_TmpValue
;
1523 devpriv
->b_EocEosInterrupt
= APCI3120_DISABLE
;
1524 devpriv
->b_InterruptMode
= APCI3120_EOC_MODE
;
1526 send_sig(SIGIO
, devpriv
->tsk_Current
, 0); /* send signal to the sample */
1531 devpriv
->b_ModeSelectRegister
=
1533 b_ModeSelectRegister
& APCI3120_DISABLE_EOS_INT
;
1534 outb(devpriv
->b_ModeSelectRegister
,
1535 dev
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
1536 devpriv
->b_EocEosInterrupt
= APCI3120_DISABLE
; /* Default settings */
1537 devpriv
->b_InterruptMode
= APCI3120_EOC_MODE
;
1541 /* Timer2 interrupt */
1542 if (int_daq
& 0x1) {
1544 switch (devpriv
->b_Timer2Mode
) {
1545 case APCI3120_COUNTER
:
1547 devpriv
->b_AiCyclicAcquisition
= APCI3120_DISABLE
;
1548 devpriv
->b_ModeSelectRegister
=
1550 b_ModeSelectRegister
& APCI3120_DISABLE_EOS_INT
;
1551 outb(devpriv
->b_ModeSelectRegister
,
1552 dev
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
1555 devpriv
->us_OutputRegister
=
1557 us_OutputRegister
& APCI3120_DISABLE_ALL_TIMER
;
1558 outw(devpriv
->us_OutputRegister
,
1559 dev
->iobase
+ APCI3120_WR_ADDRESS
);
1561 /* stop timer 0 and timer 1 */
1562 i_APCI3120_StopCyclicAcquisition(dev
, s
);
1563 devpriv
->b_AiCyclicAcquisition
= APCI3120_DISABLE
;
1565 /* UPDATE-0.7.57->0.7.68comedi_done(dev,s); */
1566 s
->async
->events
|= COMEDI_CB_EOA
;
1567 comedi_event(dev
, s
);
1571 case APCI3120_TIMER
:
1573 /* Send a signal to from kernel to user space */
1574 send_sig(SIGIO
, devpriv
->tsk_Current
, 0);
1577 case APCI3120_WATCHDOG
:
1579 /* Send a signal to from kernel to user space */
1580 send_sig(SIGIO
, devpriv
->tsk_Current
, 0);
1585 /* disable Timer Interrupt */
1587 devpriv
->b_ModeSelectRegister
=
1589 b_ModeSelectRegister
&
1590 APCI3120_DISABLE_TIMER_INT
;
1592 outb(devpriv
->b_ModeSelectRegister
,
1593 dev
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
1597 b_DummyRead
= inb(dev
->iobase
+ APCI3120_TIMER_STATUS_REGISTER
);
1601 if ((int_daq
& 0x4) && (devpriv
->b_InterruptMode
== APCI3120_DMA_MODE
)) {
1602 if (devpriv
->b_AiCyclicAcquisition
== APCI3120_ENABLE
) {
1604 /****************************/
1605 /* Clear Timer Write TC int */
1606 /****************************/
1608 outl(APCI3120_CLEAR_WRITE_TC_INT
,
1609 devpriv
->i_IobaseAmcc
+
1610 APCI3120_AMCC_OP_REG_INTCSR
);
1612 /************************************/
1613 /* Clears the timer status register */
1614 /************************************/
1615 inw(dev
->iobase
+ APCI3120_TIMER_STATUS_REGISTER
);
1616 v_APCI3120_InterruptDma(irq
, d
); /* do some data transfer */
1618 /* Stops the Timer */
1620 us_OutputRegister
& APCI3120_DISABLE_TIMER0
&
1621 APCI3120_DISABLE_TIMER1
,
1622 dev
->iobase
+ APCI3120_WR_ADDRESS
);
1631 +----------------------------------------------------------------------------+
1632 | Function name :int i_APCI3120_InterruptHandleEos(struct comedi_device *dev) |
1635 +----------------------------------------------------------------------------+
1636 | Task : This function handles EOS interrupt. |
1637 | This function copies the acquired data(from FIFO) |
1638 | to Comedi buffer. |
1640 +----------------------------------------------------------------------------+
1641 | Input Parameters : struct comedi_device *dev |
1644 +----------------------------------------------------------------------------+
1645 | Return Value : 0 |
1647 +----------------------------------------------------------------------------+
1651 int i_APCI3120_InterruptHandleEos(struct comedi_device
*dev
)
1654 struct comedi_subdevice
*s
= dev
->subdevices
+ 0;
1657 n_chan
= devpriv
->ui_AiNbrofChannels
;
1659 s
->async
->events
= 0;
1661 for (i
= 0; i
< n_chan
; i
++)
1662 err
&= comedi_buf_put(s
->async
, inw(dev
->iobase
+ 0));
1664 s
->async
->events
|= COMEDI_CB_EOS
;
1667 s
->async
->events
|= COMEDI_CB_OVERFLOW
;
1669 comedi_event(dev
, s
);
1675 +----------------------------------------------------------------------------+
1676 | Function name : void v_APCI3120_InterruptDma(int irq, void *d) |
1678 +----------------------------------------------------------------------------+
1679 | Task : This is a handler for the DMA interrupt |
1680 | This function copies the data to Comedi Buffer. |
1681 | For continuous DMA it reinitializes the DMA operation. |
1682 | For single mode DMA it stop the acquisition. |
1684 +----------------------------------------------------------------------------+
1685 | Input Parameters : int irq, void *d |
1687 +----------------------------------------------------------------------------+
1688 | Return Value : void |
1690 +----------------------------------------------------------------------------+
1693 void v_APCI3120_InterruptDma(int irq
, void *d
)
1695 struct comedi_device
*dev
= d
;
1696 struct comedi_subdevice
*s
= dev
->subdevices
+ 0;
1697 unsigned int next_dma_buf
, samplesinbuf
;
1698 unsigned long low_word
, high_word
, var
;
1700 unsigned int ui_Tmp
;
1702 devpriv
->ui_DmaBufferUsesize
[devpriv
->ui_DmaActualBuffer
] -
1703 inl(devpriv
->i_IobaseAmcc
+ AMCC_OP_REG_MWTC
);
1706 devpriv
->ui_DmaBufferUsesize
[devpriv
->ui_DmaActualBuffer
]) {
1707 comedi_error(dev
, "Interrupted DMA transfer!");
1709 if (samplesinbuf
& 1) {
1710 comedi_error(dev
, "Odd count of bytes in DMA ring!");
1711 i_APCI3120_StopCyclicAcquisition(dev
, s
);
1712 devpriv
->b_AiCyclicAcquisition
= APCI3120_DISABLE
;
1716 samplesinbuf
= samplesinbuf
>> 1; /* number of received samples */
1717 if (devpriv
->b_DmaDoubleBuffer
) {
1718 /* switch DMA buffers if is used double buffering */
1719 next_dma_buf
= 1 - devpriv
->ui_DmaActualBuffer
;
1721 ui_Tmp
= AGCSTS_TC_ENABLE
| AGCSTS_RESET_A2P_FIFO
;
1722 outl(ui_Tmp
, devpriv
->i_IobaseAddon
+ AMCC_OP_REG_AGCSTS
);
1724 /* changed since 16 bit interface for add on */
1725 outw(APCI3120_ADD_ON_AGCSTS_LOW
, devpriv
->i_IobaseAddon
+ 0);
1726 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW
,
1727 devpriv
->i_IobaseAddon
+ 2);
1728 outw(APCI3120_ADD_ON_AGCSTS_HIGH
, devpriv
->i_IobaseAddon
+ 0);
1729 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH
, devpriv
->i_IobaseAddon
+ 2); /* 0x1000 is out putted in windows driver */
1731 var
= devpriv
->ul_DmaBufferHw
[next_dma_buf
];
1732 low_word
= var
& 0xffff;
1733 var
= devpriv
->ul_DmaBufferHw
[next_dma_buf
];
1734 high_word
= var
/ 65536;
1736 /* DMA Start Address Low */
1737 outw(APCI3120_ADD_ON_MWAR_LOW
, devpriv
->i_IobaseAddon
+ 0);
1738 outw(low_word
, devpriv
->i_IobaseAddon
+ 2);
1740 /* DMA Start Address High */
1741 outw(APCI3120_ADD_ON_MWAR_HIGH
, devpriv
->i_IobaseAddon
+ 0);
1742 outw(high_word
, devpriv
->i_IobaseAddon
+ 2);
1744 var
= devpriv
->ui_DmaBufferUsesize
[next_dma_buf
];
1745 low_word
= var
& 0xffff;
1746 var
= devpriv
->ui_DmaBufferUsesize
[next_dma_buf
];
1747 high_word
= var
/ 65536;
1749 /* Nbr of acquisition LOW */
1750 outw(APCI3120_ADD_ON_MWTC_LOW
, devpriv
->i_IobaseAddon
+ 0);
1751 outw(low_word
, devpriv
->i_IobaseAddon
+ 2);
1753 /* Nbr of acquisition HIGH */
1754 outw(APCI3120_ADD_ON_MWTC_HIGH
, devpriv
->i_IobaseAddon
+ 0);
1755 outw(high_word
, devpriv
->i_IobaseAddon
+ 2);
1758 * To configure A2P FIFO
1759 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1760 * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1762 outw(3, devpriv
->i_IobaseAddon
+ 4);
1763 /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
1764 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2
|
1765 APCI3120_ENABLE_WRITE_TC_INT
),
1766 devpriv
->i_IobaseAmcc
+ AMCC_OP_REG_INTCSR
);
1770 v_APCI3120_InterruptDmaMoveBlock16bit(dev
, s
,
1771 devpriv
->ul_DmaBufferVirtual
[devpriv
->
1772 ui_DmaActualBuffer
], samplesinbuf
);
1774 if (!(devpriv
->ui_AiFlags
& TRIG_WAKE_EOS
)) {
1775 s
->async
->events
|= COMEDI_CB_EOS
;
1776 comedi_event(dev
, s
);
1779 if (!devpriv
->b_AiContinuous
)
1780 if (devpriv
->ui_AiActualScan
>= devpriv
->ui_AiNbrofScans
) {
1781 /* all data sampled */
1782 i_APCI3120_StopCyclicAcquisition(dev
, s
);
1783 devpriv
->b_AiCyclicAcquisition
= APCI3120_DISABLE
;
1784 s
->async
->events
|= COMEDI_CB_EOA
;
1785 comedi_event(dev
, s
);
1789 if (devpriv
->b_DmaDoubleBuffer
) { /* switch dma buffers */
1790 devpriv
->ui_DmaActualBuffer
= 1 - devpriv
->ui_DmaActualBuffer
;
1793 * restart DMA if is not used double buffering
1794 * ADDED REINITIALISE THE DMA
1796 ui_Tmp
= AGCSTS_TC_ENABLE
| AGCSTS_RESET_A2P_FIFO
;
1797 outl(ui_Tmp
, devpriv
->i_IobaseAddon
+ AMCC_OP_REG_AGCSTS
);
1799 /* changed since 16 bit interface for add on */
1800 outw(APCI3120_ADD_ON_AGCSTS_LOW
, devpriv
->i_IobaseAddon
+ 0);
1801 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW
,
1802 devpriv
->i_IobaseAddon
+ 2);
1803 outw(APCI3120_ADD_ON_AGCSTS_HIGH
, devpriv
->i_IobaseAddon
+ 0);
1804 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH
, devpriv
->i_IobaseAddon
+ 2); /* */
1806 * A2P FIFO MANAGEMENT
1807 * A2P fifo reset & transfer control enable
1809 outl(APCI3120_A2P_FIFO_MANAGEMENT
,
1810 devpriv
->i_IobaseAmcc
+ AMCC_OP_REG_MCSR
);
1812 var
= devpriv
->ul_DmaBufferHw
[0];
1813 low_word
= var
& 0xffff;
1814 var
= devpriv
->ul_DmaBufferHw
[0];
1815 high_word
= var
/ 65536;
1816 outw(APCI3120_ADD_ON_MWAR_LOW
, devpriv
->i_IobaseAddon
+ 0);
1817 outw(low_word
, devpriv
->i_IobaseAddon
+ 2);
1818 outw(APCI3120_ADD_ON_MWAR_HIGH
, devpriv
->i_IobaseAddon
+ 0);
1819 outw(high_word
, devpriv
->i_IobaseAddon
+ 2);
1821 var
= devpriv
->ui_DmaBufferUsesize
[0];
1822 low_word
= var
& 0xffff; /* changed */
1823 var
= devpriv
->ui_DmaBufferUsesize
[0];
1824 high_word
= var
/ 65536;
1825 outw(APCI3120_ADD_ON_MWTC_LOW
, devpriv
->i_IobaseAddon
+ 0);
1826 outw(low_word
, devpriv
->i_IobaseAddon
+ 2);
1827 outw(APCI3120_ADD_ON_MWTC_HIGH
, devpriv
->i_IobaseAddon
+ 0);
1828 outw(high_word
, devpriv
->i_IobaseAddon
+ 2);
1831 * To configure A2P FIFO
1832 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1833 * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1835 outw(3, devpriv
->i_IobaseAddon
+ 4);
1836 /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
1837 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2
|
1838 APCI3120_ENABLE_WRITE_TC_INT
),
1839 devpriv
->i_IobaseAmcc
+ AMCC_OP_REG_INTCSR
);
1844 +----------------------------------------------------------------------------+
1845 | Function name :void v_APCI3120_InterruptDmaMoveBlock16bit(comedi_device|
1846 |*dev,struct comedi_subdevice *s,short *dma,short *data,int n) |
1848 +----------------------------------------------------------------------------+
1849 | Task : This function copies the data from DMA buffer to the |
1852 +----------------------------------------------------------------------------+
1853 | Input Parameters : struct comedi_device *dev |
1854 | struct comedi_subdevice *s |
1856 | short *data,int n |
1857 +----------------------------------------------------------------------------+
1858 | Return Value : void |
1860 +----------------------------------------------------------------------------+
1863 void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device
*dev
,
1864 struct comedi_subdevice
*s
, short *dma_buffer
, unsigned int num_samples
)
1866 devpriv
->ui_AiActualScan
+=
1867 (s
->async
->cur_chan
+ num_samples
) / devpriv
->ui_AiScanLength
;
1868 s
->async
->cur_chan
+= num_samples
;
1869 s
->async
->cur_chan
%= devpriv
->ui_AiScanLength
;
1871 cfc_write_array_to_buffer(s
, dma_buffer
, num_samples
* sizeof(short));
1875 +----------------------------------------------------------------------------+
1877 +----------------------------------------------------------------------------+
1881 +----------------------------------------------------------------------------+
1882 | Function name :int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, |
1883 | struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
1885 +----------------------------------------------------------------------------+
1886 | Task :Configure Timer 2 |
1888 +----------------------------------------------------------------------------+
1889 | Input Parameters : struct comedi_device *dev |
1890 | struct comedi_subdevice *s |
1891 | struct comedi_insn *insn |
1892 | unsigned int *data |
1894 | data[0]= TIMER configure as timer |
1895 | = WATCHDOG configure as watchdog |
1896 | data[1] = Timer constant |
1897 | data[2] = Timer2 interrupt (1)enable or(0) disable |
1899 +----------------------------------------------------------------------------+
1902 +----------------------------------------------------------------------------+
1905 int i_APCI3120_InsnConfigTimer(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
1906 struct comedi_insn
*insn
, unsigned int *data
)
1909 unsigned int ui_Timervalue2
;
1910 unsigned short us_TmpValue
;
1911 unsigned char b_Tmp
;
1914 comedi_error(dev
, "config:No timer constant !");
1916 devpriv
->b_Timer2Interrupt
= (unsigned char) data
[2]; /* save info whether to enable or disable interrupt */
1918 ui_Timervalue2
= data
[1] / 1000; /* convert nano seconds to u seconds */
1920 /* this_board->i_hwdrv_InsnConfigTimer(dev, ui_Timervalue2,(unsigned char)data[0]); */
1921 us_TmpValue
= (unsigned short) inw(devpriv
->iobase
+ APCI3120_RD_STATUS
);
1924 * EL250804: Testing if board APCI3120 have the new Quartz or if it
1925 * is an APCI3001 and calculate the time value to set in the timer
1927 if ((us_TmpValue
& 0x00B0) == 0x00B0
1928 || !strcmp(this_board
->pc_DriverName
, "apci3001")) {
1929 /* Calculate the time value to set in the timer */
1930 ui_Timervalue2
= ui_Timervalue2
/ 50;
1932 /* Calculate the time value to set in the timer */
1933 ui_Timervalue2
= ui_Timervalue2
/ 70;
1936 /* Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0) */
1937 devpriv
->us_OutputRegister
=
1938 devpriv
->us_OutputRegister
& APCI3120_DISABLE_TIMER2
;
1939 outw(devpriv
->us_OutputRegister
, devpriv
->iobase
+ APCI3120_WR_ADDRESS
);
1941 /* Disable TIMER Interrupt */
1942 devpriv
->b_ModeSelectRegister
=
1944 b_ModeSelectRegister
& APCI3120_DISABLE_TIMER_INT
& 0xEF;
1946 /* Disable Eoc and Eos Interrupts */
1947 devpriv
->b_ModeSelectRegister
=
1949 b_ModeSelectRegister
& APCI3120_DISABLE_EOC_INT
&
1950 APCI3120_DISABLE_EOS_INT
;
1951 outb(devpriv
->b_ModeSelectRegister
,
1952 devpriv
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
1953 if (data
[0] == APCI3120_TIMER
) { /* initialize timer */
1954 /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister |
1955 * APCI3120_ENABLE_TIMER_INT; */
1957 /* outb(devpriv->b_ModeSelectRegister,devpriv->iobase+APCI3120_WRITE_MODE_SELECT); */
1959 /* Set the Timer 2 in mode 2(Timer) */
1960 devpriv
->b_TimerSelectMode
=
1962 b_TimerSelectMode
& 0x0F) | APCI3120_TIMER_2_MODE_2
;
1963 outb(devpriv
->b_TimerSelectMode
,
1964 devpriv
->iobase
+ APCI3120_TIMER_CRT1
);
1967 * Configure the timer 2 for writing the LOW unsigned short of timer
1968 * is Delay value You must make a b_tmp variable with
1969 * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
1970 * you can set the digital output and configure the timer 2,and if
1971 * you don't make this, digital output are erase (Set to 0)
1974 /* Writing LOW unsigned short */
1976 b_DigitalOutputRegister
) & 0xF0) |
1977 APCI3120_SELECT_TIMER_2_LOW_WORD
;
1978 outb(b_Tmp
, devpriv
->iobase
+ APCI3120_TIMER_CRT0
);
1979 outw(LOWORD(ui_Timervalue2
),
1980 devpriv
->iobase
+ APCI3120_TIMER_VALUE
);
1982 /* Writing HIGH unsigned short */
1984 b_DigitalOutputRegister
) & 0xF0) |
1985 APCI3120_SELECT_TIMER_2_HIGH_WORD
;
1986 outb(b_Tmp
, devpriv
->iobase
+ APCI3120_TIMER_CRT0
);
1987 outw(HIWORD(ui_Timervalue2
),
1988 devpriv
->iobase
+ APCI3120_TIMER_VALUE
);
1989 /* timer2 in Timer mode enabled */
1990 devpriv
->b_Timer2Mode
= APCI3120_TIMER
;
1992 } else { /* Initialize Watch dog */
1994 /* Set the Timer 2 in mode 5(Watchdog) */
1996 devpriv
->b_TimerSelectMode
=
1998 b_TimerSelectMode
& 0x0F) | APCI3120_TIMER_2_MODE_5
;
1999 outb(devpriv
->b_TimerSelectMode
,
2000 devpriv
->iobase
+ APCI3120_TIMER_CRT1
);
2003 * Configure the timer 2 for writing the LOW unsigned short of timer
2004 * is Delay value You must make a b_tmp variable with
2005 * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
2006 * you can set the digital output and configure the timer 2,and if
2007 * you don't make this, digital output are erase (Set to 0)
2010 /* Writing LOW unsigned short */
2012 b_DigitalOutputRegister
) & 0xF0) |
2013 APCI3120_SELECT_TIMER_2_LOW_WORD
;
2014 outb(b_Tmp
, devpriv
->iobase
+ APCI3120_TIMER_CRT0
);
2015 outw(LOWORD(ui_Timervalue2
),
2016 devpriv
->iobase
+ APCI3120_TIMER_VALUE
);
2018 /* Writing HIGH unsigned short */
2020 b_DigitalOutputRegister
) & 0xF0) |
2021 APCI3120_SELECT_TIMER_2_HIGH_WORD
;
2022 outb(b_Tmp
, devpriv
->iobase
+ APCI3120_TIMER_CRT0
);
2024 outw(HIWORD(ui_Timervalue2
),
2025 devpriv
->iobase
+ APCI3120_TIMER_VALUE
);
2026 /* watchdog enabled */
2027 devpriv
->b_Timer2Mode
= APCI3120_WATCHDOG
;
2036 +----------------------------------------------------------------------------+
2037 | Function name :int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, |
2038 | struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
2040 +----------------------------------------------------------------------------+
2041 | Task : To start and stop the timer |
2042 +----------------------------------------------------------------------------+
2043 | Input Parameters : struct comedi_device *dev |
2044 | struct comedi_subdevice *s |
2045 | struct comedi_insn *insn |
2046 | unsigned int *data |
2048 | data[0] = 1 (start) |
2049 | data[0] = 0 (stop ) |
2050 | data[0] = 2 (write new value) |
2051 | data[1]= new value |
2053 | devpriv->b_Timer2Mode = 0 DISABLE |
2057 +----------------------------------------------------------------------------+
2060 +----------------------------------------------------------------------------+
2063 int i_APCI3120_InsnWriteTimer(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
2064 struct comedi_insn
*insn
, unsigned int *data
)
2067 unsigned int ui_Timervalue2
= 0;
2068 unsigned short us_TmpValue
;
2069 unsigned char b_Tmp
;
2071 if ((devpriv
->b_Timer2Mode
!= APCI3120_WATCHDOG
)
2072 && (devpriv
->b_Timer2Mode
!= APCI3120_TIMER
)) {
2073 comedi_error(dev
, "\nwrite:timer2 not configured ");
2077 if (data
[0] == 2) { /* write new value */
2078 if (devpriv
->b_Timer2Mode
!= APCI3120_TIMER
) {
2080 "write :timer2 not configured in TIMER MODE");
2085 ui_Timervalue2
= data
[1];
2090 /* this_board->i_hwdrv_InsnWriteTimer(dev,data[0],ui_Timervalue2); */
2093 case APCI3120_START
:
2095 /* Reset FC_TIMER BIT */
2096 inb(devpriv
->iobase
+ APCI3120_TIMER_STATUS_REGISTER
);
2097 if (devpriv
->b_Timer2Mode
== APCI3120_TIMER
) { /* start timer */
2099 devpriv
->b_ModeSelectRegister
=
2100 devpriv
->b_ModeSelectRegister
& 0x0B;
2101 } else { /* start watch dog */
2102 /* Enable WatchDog */
2103 devpriv
->b_ModeSelectRegister
=
2105 b_ModeSelectRegister
& 0x0B) |
2106 APCI3120_ENABLE_WATCHDOG
;
2109 /* enable disable interrupt */
2110 if ((devpriv
->b_Timer2Interrupt
) == APCI3120_ENABLE
) {
2112 devpriv
->b_ModeSelectRegister
=
2114 b_ModeSelectRegister
|
2115 APCI3120_ENABLE_TIMER_INT
;
2116 /* save the task structure to pass info to user */
2117 devpriv
->tsk_Current
= current
;
2120 devpriv
->b_ModeSelectRegister
=
2122 b_ModeSelectRegister
&
2123 APCI3120_DISABLE_TIMER_INT
;
2125 outb(devpriv
->b_ModeSelectRegister
,
2126 devpriv
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
2128 if (devpriv
->b_Timer2Mode
== APCI3120_TIMER
) { /* start timer */
2129 /* For Timer mode is Gate2 must be activated **timer started */
2130 devpriv
->us_OutputRegister
=
2132 us_OutputRegister
| APCI3120_ENABLE_TIMER2
;
2133 outw(devpriv
->us_OutputRegister
,
2134 devpriv
->iobase
+ APCI3120_WR_ADDRESS
);
2140 if (devpriv
->b_Timer2Mode
== APCI3120_TIMER
) {
2142 devpriv
->b_ModeSelectRegister
=
2144 b_ModeSelectRegister
&
2145 APCI3120_DISABLE_TIMER_COUNTER
;
2147 /* Disable WatchDog */
2148 devpriv
->b_ModeSelectRegister
=
2150 b_ModeSelectRegister
&
2151 APCI3120_DISABLE_WATCHDOG
;
2153 /* Disable timer interrupt */
2154 devpriv
->b_ModeSelectRegister
=
2156 b_ModeSelectRegister
& APCI3120_DISABLE_TIMER_INT
;
2158 /* Write above states to register */
2159 outb(devpriv
->b_ModeSelectRegister
,
2160 devpriv
->iobase
+ APCI3120_WRITE_MODE_SELECT
);
2163 devpriv
->us_OutputRegister
=
2164 devpriv
->us_OutputRegister
& APCI3120_DISABLE_TIMER_INT
;
2165 outw(devpriv
->us_OutputRegister
,
2166 devpriv
->iobase
+ APCI3120_WR_ADDRESS
);
2168 /* Reset FC_TIMER BIT */
2169 inb(devpriv
->iobase
+ APCI3120_TIMER_STATUS_REGISTER
);
2172 /* devpriv->b_Timer2Mode=APCI3120_DISABLE; */
2176 case 2: /* write new value to Timer */
2177 if (devpriv
->b_Timer2Mode
!= APCI3120_TIMER
) {
2179 "write :timer2 not configured in TIMER MODE");
2182 /* ui_Timervalue2=data[1]; // passed as argument */
2184 (unsigned short) inw(devpriv
->iobase
+ APCI3120_RD_STATUS
);
2187 * EL250804: Testing if board APCI3120 have the new Quartz or if it
2188 * is an APCI3001 and calculate the time value to set in the timer
2190 if ((us_TmpValue
& 0x00B0) == 0x00B0
2191 || !strcmp(this_board
->pc_DriverName
, "apci3001")) {
2192 /* Calculate the time value to set in the timer */
2193 ui_Timervalue2
= ui_Timervalue2
/ 50;
2195 /* Calculate the time value to set in the timer */
2196 ui_Timervalue2
= ui_Timervalue2
/ 70;
2198 /* Writing LOW unsigned short */
2200 b_DigitalOutputRegister
) & 0xF0) |
2201 APCI3120_SELECT_TIMER_2_LOW_WORD
;
2202 outb(b_Tmp
, devpriv
->iobase
+ APCI3120_TIMER_CRT0
);
2204 outw(LOWORD(ui_Timervalue2
),
2205 devpriv
->iobase
+ APCI3120_TIMER_VALUE
);
2207 /* Writing HIGH unsigned short */
2209 b_DigitalOutputRegister
) & 0xF0) |
2210 APCI3120_SELECT_TIMER_2_HIGH_WORD
;
2211 outb(b_Tmp
, devpriv
->iobase
+ APCI3120_TIMER_CRT0
);
2213 outw(HIWORD(ui_Timervalue2
),
2214 devpriv
->iobase
+ APCI3120_TIMER_VALUE
);
2218 return -EINVAL
; /* Not a valid input */
2225 +----------------------------------------------------------------------------+
2226 | Function name : int i_APCI3120_InsnReadTimer(struct comedi_device *dev, |
2227 | struct comedi_subdevice *s,struct comedi_insn *insn, unsigned int *data) |
2230 +----------------------------------------------------------------------------+
2231 | Task : read the Timer value |
2232 +----------------------------------------------------------------------------+
2233 | Input Parameters : struct comedi_device *dev |
2234 | struct comedi_subdevice *s |
2235 | struct comedi_insn *insn |
2236 | unsigned int *data |
2238 +----------------------------------------------------------------------------+
2240 | for Timer: data[0]= Timer constant |
2242 | for watchdog: data[0]=0 (still running) |
2243 | data[0]=1 (run down) |
2245 +----------------------------------------------------------------------------+
2247 int i_APCI3120_InsnReadTimer(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
2248 struct comedi_insn
*insn
, unsigned int *data
)
2250 unsigned char b_Tmp
;
2251 unsigned short us_TmpValue
, us_TmpValue_2
, us_StatusValue
;
2253 if ((devpriv
->b_Timer2Mode
!= APCI3120_WATCHDOG
)
2254 && (devpriv
->b_Timer2Mode
!= APCI3120_TIMER
)) {
2255 comedi_error(dev
, "\nread:timer2 not configured ");
2258 /* this_board->i_hwdrv_InsnReadTimer(dev,data); */
2259 if (devpriv
->b_Timer2Mode
== APCI3120_TIMER
) {
2261 /* Read the LOW unsigned short of Timer 2 register */
2263 b_DigitalOutputRegister
) & 0xF0) |
2264 APCI3120_SELECT_TIMER_2_LOW_WORD
;
2265 outb(b_Tmp
, devpriv
->iobase
+ APCI3120_TIMER_CRT0
);
2267 us_TmpValue
= inw(devpriv
->iobase
+ APCI3120_TIMER_VALUE
);
2269 /* Read the HIGH unsigned short of Timer 2 register */
2271 b_DigitalOutputRegister
) & 0xF0) |
2272 APCI3120_SELECT_TIMER_2_HIGH_WORD
;
2273 outb(b_Tmp
, devpriv
->iobase
+ APCI3120_TIMER_CRT0
);
2275 us_TmpValue_2
= inw(devpriv
->iobase
+ APCI3120_TIMER_VALUE
);
2277 /* combining both words */
2278 data
[0] = (unsigned int) ((us_TmpValue
) | ((us_TmpValue_2
) << 16));
2280 } else { /* Read watch dog status */
2282 us_StatusValue
= inw(devpriv
->iobase
+ APCI3120_RD_STATUS
);
2284 ((us_StatusValue
& APCI3120_FC_TIMER
) >> 12) & 1;
2285 if (us_StatusValue
== 1) {
2286 /* RESET FC_TIMER BIT */
2287 inb(devpriv
->iobase
+ APCI3120_TIMER_STATUS_REGISTER
);
2289 data
[0] = us_StatusValue
; /* when data[0] = 1 then the watch dog has rundown */
2295 +----------------------------------------------------------------------------+
2296 | DIGITAL INPUT SUBDEVICE |
2297 +----------------------------------------------------------------------------+
2301 +----------------------------------------------------------------------------+
2302 | Function name :int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev, |
2303 | struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
2306 +----------------------------------------------------------------------------+
2307 | Task : Reads the value of the specified Digital input channel|
2309 +----------------------------------------------------------------------------+
2310 | Input Parameters : struct comedi_device *dev |
2311 | struct comedi_subdevice *s |
2312 | struct comedi_insn *insn |
2313 | unsigned int *data |
2314 +----------------------------------------------------------------------------+
2317 +----------------------------------------------------------------------------+
2320 int i_APCI3120_InsnReadDigitalInput(struct comedi_device
*dev
,
2321 struct comedi_subdevice
*s
,
2322 struct comedi_insn
*insn
,
2325 unsigned int ui_Chan
, ui_TmpValue
;
2327 ui_Chan
= CR_CHAN(insn
->chanspec
); /* channel specified */
2329 /* this_board->i_hwdrv_InsnReadDigitalInput(dev,ui_Chan,data); */
2331 ui_TmpValue
= (unsigned int) inw(devpriv
->iobase
+ APCI3120_RD_STATUS
);
2334 * since only 1 channel reqd to bring it to last bit it is rotated 8
2335 * +(chan - 1) times then ANDed with 1 for last bit.
2337 *data
= (ui_TmpValue
>> (ui_Chan
+ 8)) & 1;
2340 /* comedi_error(dev," chan spec wrong"); */
2341 return -EINVAL
; /* "sorry channel spec wrong " */
2348 +----------------------------------------------------------------------------+
2349 | Function name :int i_APCI3120_InsnBitsDigitalInput(struct comedi_device *dev, |
2350 |struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
2352 +----------------------------------------------------------------------------+
2353 | Task : Reads the value of the Digital input Port i.e.4channels|
2354 | value is returned in data[0] |
2356 +----------------------------------------------------------------------------+
2357 | Input Parameters : struct comedi_device *dev |
2358 | struct comedi_subdevice *s |
2359 | struct comedi_insn *insn |
2360 | unsigned int *data |
2361 +----------------------------------------------------------------------------+
2364 +----------------------------------------------------------------------------+
2366 int i_APCI3120_InsnBitsDigitalInput(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
2367 struct comedi_insn
*insn
, unsigned int *data
)
2369 unsigned int ui_TmpValue
;
2370 ui_TmpValue
= (unsigned int) inw(devpriv
->iobase
+ APCI3120_RD_STATUS
);
2371 /***** state of 4 channels in the 11, 10, 9, 8 bits of status reg
2372 rotated right 8 times to bring them to last four bits
2373 ANDed with oxf for value.
2376 *data
= (ui_TmpValue
>> 8) & 0xf;
2377 /* this_board->i_hwdrv_InsnBitsDigitalInput(dev,data); */
2382 +----------------------------------------------------------------------------+
2383 | DIGITAL OUTPUT SUBDEVICE |
2384 +----------------------------------------------------------------------------+
2387 +----------------------------------------------------------------------------+
2388 | Function name :int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device |
2389 | *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
2391 +----------------------------------------------------------------------------+
2392 | Task :Configure the output memory ON or OFF |
2394 +----------------------------------------------------------------------------+
2395 | Input Parameters :struct comedi_device *dev |
2396 | struct comedi_subdevice *s |
2397 | struct comedi_insn *insn |
2398 | unsigned int *data |
2399 +----------------------------------------------------------------------------+
2402 +----------------------------------------------------------------------------+
2405 int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device
*dev
,
2406 struct comedi_subdevice
*s
, struct comedi_insn
*insn
, unsigned int *data
)
2409 if ((data
[0] != 0) && (data
[0] != 1)) {
2411 "Not a valid Data !!! ,Data should be 1 or 0\n");
2415 devpriv
->b_OutputMemoryStatus
= APCI3120_ENABLE
;
2418 devpriv
->b_OutputMemoryStatus
= APCI3120_DISABLE
;
2419 devpriv
->b_DigitalOutputRegister
= 0;
2421 if (!devpriv
->b_OutputMemoryStatus
)
2423 /* if(!devpriv->b_OutputMemoryStatus ) */
2429 +----------------------------------------------------------------------------+
2430 | Function name :int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device *dev, |
2431 | struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
2433 +----------------------------------------------------------------------------+
2434 | Task : write diatal output port |
2436 +----------------------------------------------------------------------------+
2437 | Input Parameters : struct comedi_device *dev |
2438 | struct comedi_subdevice *s |
2439 | struct comedi_insn *insn |
2440 | unsigned int *data |
2441 | data[0] Value to be written
2442 | data[1] :1 Set digital o/p ON
2443 | data[1] 2 Set digital o/p OFF with memory ON
2444 +----------------------------------------------------------------------------+
2447 +----------------------------------------------------------------------------+
2450 int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device
*dev
,
2451 struct comedi_subdevice
*s
,
2452 struct comedi_insn
*insn
,
2455 if ((data
[0] > this_board
->i_DoMaxdata
) || (data
[0] < 0)) {
2457 comedi_error(dev
, "Data is not valid !!! \n");
2463 data
[0] = (data
[0] << 4) | devpriv
->b_DigitalOutputRegister
;
2470 printk("\nThe parameter passed is in error \n");
2472 } /* switch(data[1]) */
2473 outb(data
[0], devpriv
->iobase
+ APCI3120_DIGITAL_OUTPUT
);
2475 devpriv
->b_DigitalOutputRegister
= data
[0] & 0xF0;
2482 +----------------------------------------------------------------------------+
2483 | Function name :int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev,|
2484 |struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
2486 +----------------------------------------------------------------------------+
2487 | Task : Write digiatl output |
2489 +----------------------------------------------------------------------------+
2490 | Input Parameters : struct comedi_device *dev |
2491 | struct comedi_subdevice *s |
2492 | struct comedi_insn *insn |
2493 | unsigned int *data |
2494 data[0] Value to be written
2495 data[1] :1 Set digital o/p ON
2496 data[1] 2 Set digital o/p OFF with memory ON
2497 +----------------------------------------------------------------------------+
2500 +----------------------------------------------------------------------------+
2503 int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device
*dev
,
2504 struct comedi_subdevice
*s
,
2505 struct comedi_insn
*insn
,
2509 unsigned int ui_Temp1
;
2511 unsigned int ui_NoOfChannel
= CR_CHAN(insn
->chanspec
); /* get the channel */
2513 if ((data
[0] != 0) && (data
[0] != 1)) {
2515 "Not a valid Data !!! ,Data should be 1 or 0\n");
2518 if (ui_NoOfChannel
> this_board
->i_NbrDoChannel
- 1) {
2520 "This board doesn't have specified channel !!! \n");
2526 data
[0] = (data
[0] << ui_NoOfChannel
);
2527 /* ES05 data[0]=(data[0]<<4)|ui_Temp; */
2528 data
[0] = (data
[0] << 4) | devpriv
->b_DigitalOutputRegister
;
2532 data
[0] = ~data
[0] & 0x1;
2534 ui_Temp1
= ui_Temp1
<< ui_NoOfChannel
;
2535 ui_Temp1
= ui_Temp1
<< 4;
2536 /* ES05 ui_Temp=ui_Temp|ui_Temp1; */
2537 devpriv
->b_DigitalOutputRegister
=
2538 devpriv
->b_DigitalOutputRegister
| ui_Temp1
;
2540 data
[0] = (data
[0] << ui_NoOfChannel
) ^ 0xf;
2541 data
[0] = data
[0] << 4;
2542 /* ES05 data[0]=data[0]& ui_Temp; */
2543 data
[0] = data
[0] & devpriv
->b_DigitalOutputRegister
;
2546 printk("\nThe parameter passed is in error \n");
2548 } /* switch(data[1]) */
2549 outb(data
[0], devpriv
->iobase
+ APCI3120_DIGITAL_OUTPUT
);
2551 /* ES05 ui_Temp=data[0] & 0xf0; */
2552 devpriv
->b_DigitalOutputRegister
= data
[0] & 0xf0;
2558 +----------------------------------------------------------------------------+
2559 | ANALOG OUTPUT SUBDEVICE |
2560 +----------------------------------------------------------------------------+
2564 +----------------------------------------------------------------------------+
2565 | Function name :int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,|
2566 |struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
2568 +----------------------------------------------------------------------------+
2569 | Task : Write analog output |
2571 +----------------------------------------------------------------------------+
2572 | Input Parameters : struct comedi_device *dev |
2573 | struct comedi_subdevice *s |
2574 | struct comedi_insn *insn |
2575 | unsigned int *data |
2576 +----------------------------------------------------------------------------+
2579 +----------------------------------------------------------------------------+
2582 int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device
*dev
,
2583 struct comedi_subdevice
*s
,
2584 struct comedi_insn
*insn
,
2587 unsigned int ui_Range
, ui_Channel
;
2588 unsigned short us_TmpValue
;
2590 ui_Range
= CR_RANGE(insn
->chanspec
);
2591 ui_Channel
= CR_CHAN(insn
->chanspec
);
2593 /* this_board->i_hwdrv_InsnWriteAnalogOutput(dev, ui_Range, ui_Channel,data[0]); */
2594 if (ui_Range
) { /* if 1 then unipolar */
2598 ((((ui_Channel
& 0x03) << 14) & 0xC000) | (1 <<
2599 13) | (data
[0] + 8191));
2602 ((((ui_Channel
& 0x03) << 14) & 0xC000) | (1 <<
2605 } else { /* if 0 then bipolar */
2607 ((((ui_Channel
& 0x03) << 14) & 0xC000) | (0 << 13) |
2613 * out put n values at the given channel. printk("\nwaiting for
2616 do { /* Waiting of DA_READY BIT */
2618 ((unsigned short) inw(devpriv
->iobase
+
2619 APCI3120_RD_STATUS
)) & 0x0001;
2620 } while (us_TmpValue
!= 0x0001);
2622 if (ui_Channel
<= 3)
2624 * for channel 0-3 out at the register 1 (wrDac1-8) data[i]
2625 * typecasted to ushort since word write is to be done
2627 outw((unsigned short) data
[0],
2628 devpriv
->iobase
+ APCI3120_ANALOG_OUTPUT_1
);
2631 * for channel 4-7 out at the register 2 (wrDac5-8) data[i]
2632 * typecasted to ushort since word write is to be done
2634 outw((unsigned short) data
[0],
2635 devpriv
->iobase
+ APCI3120_ANALOG_OUTPUT_2
);