hwdrv_apci3120.c revision a9fce7c9a3b796334916b216a618fd7586f10d76
1/**
2@verbatim
3
4Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
5
6        ADDI-DATA GmbH
7        Dieselstrasse 3
8        D-77833 Ottersweier
9        Tel: +19(0)7223/9493-0
10        Fax: +49(0)7223/9493-92
11        http://www.addi-data-com
12        info@addi-data.com
13
14This 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.
15
16This 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.
17
18You 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
19
20You shoud also find the complete GPL in the COPYING file accompanying this source code.
21
22@endverbatim
23*/
24/*
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  +-----------------------------------------------------------------------+
38  |                             UPDATE'S                                  |
39  +-----------------------------------------------------------------------+
40  |   Date   |   Author  |          Description of updates                |
41  +----------+-----------+------------------------------------------------+
42  |          | 		 | 						  |
43  |          |           |						  |
44  +----------+-----------+------------------------------------------------+
45*/
46
47#include "hwdrv_apci3120.h"
48static UINT ui_Temp = 0;
49
50// FUNCTION DEFINITIONS
51
52/*
53+----------------------------------------------------------------------------+
54|                           ANALOG INPUT SUBDEVICE   		                 |
55+----------------------------------------------------------------------------+
56*/
57
58/*
59+----------------------------------------------------------------------------+
60| Function name     :int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev,|
61|  struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)					 |
62|                                            						         |
63+----------------------------------------------------------------------------+
64| Task              : Calls card specific function  					     |
65|                     										                 |
66+----------------------------------------------------------------------------+
67| Input Parameters  : struct comedi_device *dev									 |
68|                     struct comedi_subdevice *s									 |
69|                     struct comedi_insn *insn                                      |
70|                     unsigned int *data      					         		 |
71+----------------------------------------------------------------------------+
72| Return Value      :              					                         |
73|                    													     |
74+----------------------------------------------------------------------------+
75*/
76
77int i_APCI3120_InsnConfigAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s,
78	struct comedi_insn * insn, unsigned int * data)
79{
80	UINT i;
81
82	if ((data[0] != APCI3120_EOC_MODE) && (data[0] != APCI3120_EOS_MODE))
83		return -1;
84
85	// Check for Conversion time to be added ??
86	devpriv->ui_EocEosConversionTime = data[2];
87
88	if (data[0] == APCI3120_EOS_MODE) {
89
90		//Test the number of the channel
91		for (i = 0; i < data[3]; i++) {
92
93			if (CR_CHAN(data[4 + i]) >= this_board->i_NbrAiChannel) {
94				printk("bad channel list\n");
95				return -2;
96			}
97		}
98
99		devpriv->b_InterruptMode = APCI3120_EOS_MODE;
100
101		if (data[1]) {
102			devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
103		} else
104			devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
105		// Copy channel list and Range List to devpriv
106
107		devpriv->ui_AiNbrofChannels = data[3];
108		for (i = 0; i < devpriv->ui_AiNbrofChannels; i++) {
109			devpriv->ui_AiChannelList[i] = data[4 + i];
110		}
111
112	} else			// EOC
113	{
114		devpriv->b_InterruptMode = APCI3120_EOC_MODE;
115		if (data[1]) {
116			devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
117		} else {
118			devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
119		}
120	}
121
122	return insn->n;
123}
124
125/*
126+----------------------------------------------------------------------------+
127| Function name     :int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev,  |
128|			struct comedi_subdevice *s,struct comedi_insn *insn, unsigned int *data)	 |
129|                                            						         |
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.					      				 |
136|                     										                 |
137+----------------------------------------------------------------------------+
138| Input Parameters  : struct comedi_device *dev									 |
139|                     struct comedi_subdevice *s									 |
140|                     struct comedi_insn *insn                                      |
141|                     unsigned int *data     									 |
142+----------------------------------------------------------------------------+
143| Return Value      :              					                         |
144|                    													     |
145+----------------------------------------------------------------------------+
146*/
147
148int i_APCI3120_InsnReadAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s,
149	struct comedi_insn * insn, unsigned int * data)
150{
151	unsigned short us_ConvertTiming, us_TmpValue, i;
152	unsigned char b_Tmp;
153
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;
158	} else
159		us_ConvertTiming = (unsigned short) (devpriv->ui_EocEosConversionTime / 1000);	// nano to useconds
160
161	// this_board->i_hwdrv_InsnReadAnalogInput(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]);
162
163	// Clear software registers
164	devpriv->b_TimerSelectMode = 0;
165	devpriv->b_ModeSelectRegister = 0;
166	devpriv->us_OutputRegister = 0;
167//        devpriv->b_DigitalOutputRegister=0;
168
169	if (insn->unused[0] == 222)	// second insn read
170	{
171
172		for (i = 0; i < insn->n; i++) {
173			data[i] = devpriv->ui_AiReadData[i];
174		}
175
176	} else {
177		devpriv->tsk_Current = current;	// Save the current process task structure
178		//Testing if board have the new Quartz and calculate the time value
179		//to set in the timer
180
181		us_TmpValue =
182			(unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
183
184		//EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001
185		if ((us_TmpValue & 0x00B0) == 0x00B0
186			|| !strcmp(this_board->pc_DriverName, "apci3001")) {
187			us_ConvertTiming = (us_ConvertTiming * 2) - 2;
188		} else {
189			us_ConvertTiming =
190				((us_ConvertTiming * 12926) / 10000) - 1;
191		}
192
193		us_TmpValue = (unsigned short) devpriv->b_InterruptMode;
194
195		switch (us_TmpValue) {
196
197		case APCI3120_EOC_MODE:
198
199			// Testing the interrupt flag and set the EOC bit
200			// Clears the FIFO
201			inw(devpriv->iobase + APCI3120_RESET_FIFO);
202
203			// Initialize the sequence array
204
205			//if (!i_APCI3120_SetupChannelList(dev,s,1,chanlist,0))  return -EINVAL;
206
207			if (!i_APCI3120_SetupChannelList(dev, s, 1,
208					&insn->chanspec, 0))
209				return -EINVAL;
210
211			//Initialize Timer 0 mode 4
212			devpriv->b_TimerSelectMode =
213				(devpriv->
214				b_TimerSelectMode & 0xFC) |
215				APCI3120_TIMER_0_MODE_4;
216			outb(devpriv->b_TimerSelectMode,
217				devpriv->iobase + APCI3120_TIMER_CRT1);
218
219			// Reset the scan bit and Disables the  EOS, DMA, EOC interrupt
220			devpriv->b_ModeSelectRegister =
221				devpriv->
222				b_ModeSelectRegister & APCI3120_DISABLE_SCAN;
223
224			if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
225
226				//Disables the EOS,DMA and enables the EOC interrupt
227				devpriv->b_ModeSelectRegister =
228					(devpriv->
229					b_ModeSelectRegister &
230					APCI3120_DISABLE_EOS_INT) |
231					APCI3120_ENABLE_EOC_INT;
232				inw(devpriv->iobase);
233
234			} else {
235				devpriv->b_ModeSelectRegister =
236					devpriv->
237					b_ModeSelectRegister &
238					APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER;
239			}
240
241			outb(devpriv->b_ModeSelectRegister,
242				devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
243
244			// Sets gate 0
245			devpriv->us_OutputRegister =
246				(devpriv->
247				us_OutputRegister & APCI3120_CLEAR_PA_PR) |
248				APCI3120_ENABLE_TIMER0;
249			outw(devpriv->us_OutputRegister,
250				devpriv->iobase + APCI3120_WR_ADDRESS);
251
252			// Select Timer 0
253			b_Tmp = ((devpriv->
254					b_DigitalOutputRegister) & 0xF0) |
255				APCI3120_SELECT_TIMER_0_WORD;
256			outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
257
258			//Set the convertion time
259			outw(us_ConvertTiming,
260				devpriv->iobase + APCI3120_TIMER_VALUE);
261
262			us_TmpValue =
263				(unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
264
265			if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
266
267				do {
268					// Waiting for the end of conversion
269					us_TmpValue =
270						inw(devpriv->iobase +
271						APCI3120_RD_STATUS);
272				} while ((us_TmpValue & APCI3120_EOC) ==
273					APCI3120_EOC);
274
275				//Read the result in FIFO  and put it in insn data pointer
276				us_TmpValue = inw(devpriv->iobase + 0);
277				*data = us_TmpValue;
278
279				inw(devpriv->iobase + APCI3120_RESET_FIFO);
280			}
281
282			break;
283
284		case APCI3120_EOS_MODE:
285
286			inw(devpriv->iobase);
287			// Clears the FIFO
288			inw(devpriv->iobase + APCI3120_RESET_FIFO);
289			// clear PA PR  and disable timer 0
290
291			devpriv->us_OutputRegister =
292				(devpriv->
293				us_OutputRegister & APCI3120_CLEAR_PA_PR) |
294				APCI3120_DISABLE_TIMER0;
295
296			outw(devpriv->us_OutputRegister,
297				devpriv->iobase + APCI3120_WR_ADDRESS);
298
299			if (!i_APCI3120_SetupChannelList(dev, s,
300					devpriv->ui_AiNbrofChannels,
301					devpriv->ui_AiChannelList, 0))
302				return -EINVAL;
303
304			//Initialize Timer 0 mode 2
305			devpriv->b_TimerSelectMode =
306				(devpriv->
307				b_TimerSelectMode & 0xFC) |
308				APCI3120_TIMER_0_MODE_2;
309			outb(devpriv->b_TimerSelectMode,
310				devpriv->iobase + APCI3120_TIMER_CRT1);
311
312			//Select Timer 0
313			b_Tmp = ((devpriv->
314					b_DigitalOutputRegister) & 0xF0) |
315				APCI3120_SELECT_TIMER_0_WORD;
316			outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
317
318			//Set the convertion time
319			outw(us_ConvertTiming,
320				devpriv->iobase + APCI3120_TIMER_VALUE);
321
322			//Set the scan bit
323			devpriv->b_ModeSelectRegister =
324				devpriv->
325				b_ModeSelectRegister | APCI3120_ENABLE_SCAN;
326			outb(devpriv->b_ModeSelectRegister,
327				devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
328
329			//If Interrupt function is loaded
330			if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
331				//Disables the EOC,DMA and enables the EOS interrupt
332				devpriv->b_ModeSelectRegister =
333					(devpriv->
334					b_ModeSelectRegister &
335					APCI3120_DISABLE_EOC_INT) |
336					APCI3120_ENABLE_EOS_INT;
337				inw(devpriv->iobase);
338
339			} else
340				devpriv->b_ModeSelectRegister =
341					devpriv->
342					b_ModeSelectRegister &
343					APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER;
344
345			outb(devpriv->b_ModeSelectRegister,
346				devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
347
348			inw(devpriv->iobase + APCI3120_RD_STATUS);
349
350			//Sets gate 0
351
352			devpriv->us_OutputRegister =
353				devpriv->
354				us_OutputRegister | APCI3120_ENABLE_TIMER0;
355			outw(devpriv->us_OutputRegister,
356				devpriv->iobase + APCI3120_WR_ADDRESS);
357
358			//Start conversion
359			outw(0, devpriv->iobase + APCI3120_START_CONVERSION);
360
361			//Waiting of end of convertion if interrupt is not installed
362			if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
363				//Waiting the end of convertion
364				do {
365					us_TmpValue =
366						inw(devpriv->iobase +
367						APCI3120_RD_STATUS);
368				}
369				while ((us_TmpValue & APCI3120_EOS) !=
370					APCI3120_EOS);
371
372				for (i = 0; i < devpriv->ui_AiNbrofChannels;
373					i++) {
374					//Read the result in FIFO and write them in shared memory
375					us_TmpValue = inw(devpriv->iobase);
376					data[i] = (UINT) us_TmpValue;
377				}
378
379				devpriv->b_InterruptMode = APCI3120_EOC_MODE;	// Restore defaults.
380			}
381			break;
382
383		default:
384			printk("inputs wrong\n");
385
386		}
387		devpriv->ui_EocEosConversionTime = 0;	// re initializing the variable;
388	}
389
390	return insn->n;
391
392}
393
394/*
395+----------------------------------------------------------------------------+
396| Function name     :int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev,|
397| 											     struct comedi_subdevice *s)|
398|                                        									 |
399+----------------------------------------------------------------------------+
400| Task              : Stops Cyclic acquisition  						     |
401|                     										                 |
402+----------------------------------------------------------------------------+
403| Input Parameters  : struct comedi_device *dev									 |
404|                     struct comedi_subdevice *s									 |
405|                                                 					         |
406+----------------------------------------------------------------------------+
407| Return Value      :0              					                     |
408|                    													     |
409+----------------------------------------------------------------------------+
410*/
411
412int i_APCI3120_StopCyclicAcquisition(struct comedi_device * dev, struct comedi_subdevice * s)
413{
414	// Disable A2P Fifo write and AMWEN signal
415	outw(0, devpriv->i_IobaseAddon + 4);
416
417	//Disable Bus Master ADD ON
418	outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
419	outw(0, devpriv->i_IobaseAddon + 2);
420	outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
421	outw(0, devpriv->i_IobaseAddon + 2);
422
423	//Disable BUS Master PCI
424	outl(0, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
425
426	//outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR)&(~AINT_WRITE_COMPL), devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR);    // stop amcc irqs
427	//outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR)&(~EN_A2P_TRANSFERS), devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR); // stop DMA
428
429	//Disable ext trigger
430	i_APCI3120_ExttrigDisable(dev);
431
432	devpriv->us_OutputRegister = 0;
433	//stop  counters
434	outw(devpriv->
435		us_OutputRegister & APCI3120_DISABLE_TIMER0 &
436		APCI3120_DISABLE_TIMER1, dev->iobase + APCI3120_WR_ADDRESS);
437
438	outw(APCI3120_DISABLE_ALL_TIMER, dev->iobase + APCI3120_WR_ADDRESS);
439
440	//DISABLE_ALL_INTERRUPT
441	outb(APCI3120_DISABLE_ALL_INTERRUPT,
442		dev->iobase + APCI3120_WRITE_MODE_SELECT);
443	//Flush FIFO
444	inb(dev->iobase + APCI3120_RESET_FIFO);
445	inw(dev->iobase + APCI3120_RD_STATUS);
446	devpriv->ui_AiActualScan = 0;
447	devpriv->ui_AiActualScanPosition = 0;
448	s->async->cur_chan = 0;
449	devpriv->ui_AiBufferPtr = 0;
450	devpriv->b_AiContinuous = 0;
451	devpriv->ui_DmaActualBuffer = 0;
452
453	devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
454	devpriv->b_InterruptMode = APCI3120_EOC_MODE;
455	devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
456	i_APCI3120_Reset(dev);
457	return 0;
458}
459
460/*
461+----------------------------------------------------------------------------+
462| Function name     :int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev|
463|			,struct comedi_subdevice *s,struct comedi_cmd *cmd)					 |
464|                                        									 |
465+----------------------------------------------------------------------------+
466| Task              : Test validity for a command for cyclic anlog input     |
467|                       acquisition  						     			 |
468|                     										                 |
469+----------------------------------------------------------------------------+
470| Input Parameters  : struct comedi_device *dev									 |
471|                     struct comedi_subdevice *s									 |
472|                     struct comedi_cmd *cmd              					         |
473+----------------------------------------------------------------------------+
474| Return Value      :0              					                     |
475|                    													     |
476+----------------------------------------------------------------------------+
477*/
478
479int i_APCI3120_CommandTestAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s,
480	struct comedi_cmd * cmd)
481{
482	int err = 0;
483	int tmp;		// divisor1,divisor2;
484
485	// step 1: make sure trigger sources are trivially valid
486
487	tmp = cmd->start_src;
488	cmd->start_src &= TRIG_NOW | TRIG_EXT;
489	if (!cmd->start_src || tmp != cmd->start_src)
490		err++;
491
492	tmp = cmd->scan_begin_src;
493	cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW;
494	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
495		err++;
496
497	tmp = cmd->convert_src;
498	cmd->convert_src &= TRIG_TIMER;
499	if (!cmd->convert_src || tmp != cmd->convert_src)
500		err++;
501
502	tmp = cmd->scan_end_src;
503	cmd->scan_end_src &= TRIG_COUNT;
504	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
505		err++;
506
507	tmp = cmd->stop_src;
508	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
509	if (!cmd->stop_src || tmp != cmd->stop_src)
510		err++;
511
512	if (err)
513		return 1;
514
515	//step 2: make sure trigger sources are unique and mutually compatible
516
517	if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) {
518		err++;
519	}
520
521	if (cmd->scan_begin_src != TRIG_TIMER &&
522		cmd->scan_begin_src != TRIG_FOLLOW)
523		err++;
524
525	if (cmd->convert_src != TRIG_TIMER)
526		err++;
527
528	if (cmd->scan_end_src != TRIG_COUNT) {
529		cmd->scan_end_src = TRIG_COUNT;
530		err++;
531	}
532
533	if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
534		err++;
535
536	if (err)
537		return 2;
538
539	// step 3: make sure arguments are trivially compatible
540
541	if (cmd->start_arg != 0) {
542		cmd->start_arg = 0;
543		err++;
544	}
545
546	if (cmd->scan_begin_src == TRIG_TIMER)	// Test Delay timing
547	{
548		if (cmd->scan_begin_arg < this_board->ui_MinDelaytimeNs) {
549			cmd->scan_begin_arg = this_board->ui_MinDelaytimeNs;
550			err++;
551		}
552	}
553
554	if (cmd->convert_src == TRIG_TIMER)	// Test Acquisition timing
555	{
556		if (cmd->scan_begin_src == TRIG_TIMER) {
557			if ((cmd->convert_arg)
558				&& (cmd->convert_arg <
559					this_board->ui_MinAcquisitiontimeNs)) {
560				cmd->convert_arg =
561					this_board->ui_MinAcquisitiontimeNs;
562				err++;
563			}
564		} else {
565			if (cmd->convert_arg <
566				this_board->ui_MinAcquisitiontimeNs) {
567				cmd->convert_arg =
568					this_board->ui_MinAcquisitiontimeNs;
569				err++;
570
571			}
572		}
573	}
574
575	if (!cmd->chanlist_len) {
576		cmd->chanlist_len = 1;
577		err++;
578	}
579	if (cmd->chanlist_len > this_board->i_AiChannelList) {
580		cmd->chanlist_len = this_board->i_AiChannelList;
581		err++;
582	}
583	if (cmd->stop_src == TRIG_COUNT) {
584		if (!cmd->stop_arg) {
585			cmd->stop_arg = 1;
586			err++;
587		}
588	} else {		// TRIG_NONE
589		if (cmd->stop_arg != 0) {
590			cmd->stop_arg = 0;
591			err++;
592		}
593	}
594
595	if (err)
596		return 3;
597
598	// step 4: fix up any arguments
599
600	if (cmd->convert_src == TRIG_TIMER) {
601
602		if (cmd->scan_begin_src == TRIG_TIMER &&
603			cmd->scan_begin_arg <
604			cmd->convert_arg * cmd->scan_end_arg) {
605			cmd->scan_begin_arg =
606				cmd->convert_arg * cmd->scan_end_arg;
607			err++;
608		}
609	}
610
611	if (err)
612		return 4;
613
614	return 0;
615}
616
617/*
618+----------------------------------------------------------------------------+
619| Function name     : int i_APCI3120_CommandAnalogInput(struct comedi_device *dev,  |
620|												struct comedi_subdevice *s) |
621|                                        									 |
622+----------------------------------------------------------------------------+
623| Task              : Does asynchronous acquisition                          |
624|                     Determines the mode 1 or 2.						     |
625|                     										                 |
626+----------------------------------------------------------------------------+
627| Input Parameters  : struct comedi_device *dev									 |
628|                     struct comedi_subdevice *s									 |
629|                     														 |
630+----------------------------------------------------------------------------+
631| Return Value      :              					                         |
632|                    													     |
633+----------------------------------------------------------------------------+
634*/
635
636int i_APCI3120_CommandAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s)
637{
638	struct comedi_cmd *cmd = &s->async->cmd;
639
640	//loading private structure with cmd structure inputs
641	devpriv->ui_AiFlags = cmd->flags;
642	devpriv->ui_AiNbrofChannels = cmd->chanlist_len;
643	devpriv->ui_AiScanLength = cmd->scan_end_arg;
644	devpriv->pui_AiChannelList = cmd->chanlist;
645
646	//UPDATE-0.7.57->0.7.68devpriv->AiData=s->async->data;
647	devpriv->AiData = s->async->prealloc_buf;
648	//UPDATE-0.7.57->0.7.68devpriv->ui_AiDataLength=s->async->data_len;
649	devpriv->ui_AiDataLength = s->async->prealloc_bufsz;
650
651	if (cmd->stop_src == TRIG_COUNT) {
652		devpriv->ui_AiNbrofScans = cmd->stop_arg;
653	} else {
654		devpriv->ui_AiNbrofScans = 0;
655	}
656
657	devpriv->ui_AiTimer0 = 0;	// variables changed to timer0,timer1
658	devpriv->ui_AiTimer1 = 0;
659	if ((devpriv->ui_AiNbrofScans == 0) || (devpriv->ui_AiNbrofScans == -1))
660		devpriv->b_AiContinuous = 1;	// user want neverending analog acquisition
661	// stopped using cancel
662
663	if (cmd->start_src == TRIG_EXT)
664		devpriv->b_ExttrigEnable = APCI3120_ENABLE;
665	else
666		devpriv->b_ExttrigEnable = APCI3120_DISABLE;
667
668	if (cmd->scan_begin_src == TRIG_FOLLOW) {
669		// mode 1 or 3
670		if (cmd->convert_src == TRIG_TIMER) {
671			// mode 1
672
673			devpriv->ui_AiTimer0 = cmd->convert_arg;	// timer constant in nano seconds
674			//return this_board->i_hwdrv_CommandAnalogInput(1,dev,s);
675			return i_APCI3120_CyclicAnalogInput(1, dev, s);
676		}
677
678	}
679	if ((cmd->scan_begin_src == TRIG_TIMER)
680		&& (cmd->convert_src == TRIG_TIMER)) {
681		// mode 2
682		devpriv->ui_AiTimer1 = cmd->scan_begin_arg;
683		devpriv->ui_AiTimer0 = cmd->convert_arg;	// variable changed timer2 to timer0
684		//return this_board->i_hwdrv_CommandAnalogInput(2,dev,s);
685		return i_APCI3120_CyclicAnalogInput(2, dev, s);
686	}
687	return -1;
688}
689
690/*
691+----------------------------------------------------------------------------+
692| Function name     :  int i_APCI3120_CyclicAnalogInput(int mode,            |
693|		 	   struct comedi_device * dev,struct comedi_subdevice * s)			 |
694+----------------------------------------------------------------------------+
695| Task              : This is used for analog input cyclic acquisition       |
696|			  Performs the command operations.                       |
697|			  If DMA is configured does DMA initialization           |
698|			  otherwise does the acquisition with EOS interrupt.     |
699|                     										                 |
700+----------------------------------------------------------------------------+
701| Input Parameters  : 														 |
702|                     														 |
703|                                                 					         |
704+----------------------------------------------------------------------------+
705| Return Value      :              					                         |
706|                    													     |
707+----------------------------------------------------------------------------+
708*/
709
710int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device * dev,
711	struct comedi_subdevice * s)
712{
713	unsigned char b_Tmp;
714	UINT ui_Tmp, ui_DelayTiming = 0, ui_TimerValue1 = 0, dmalen0 =
715		0, dmalen1 = 0, ui_TimerValue2 =
716		0, ui_TimerValue0, ui_ConvertTiming;
717	unsigned short us_TmpValue;
718
719	//BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
720	//devpriv->b_AiCyclicAcquisition=APCI3120_ENABLE;
721	//END JK 07.05.04: Comparison between WIN32 and Linux driver
722
723	/*******************/
724	/* Resets the FIFO */
725	/*******************/
726	inb(dev->iobase + APCI3120_RESET_FIFO);
727
728	//BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
729	//inw(dev->iobase+APCI3120_RD_STATUS);
730	//END JK 07.05.04: Comparison between WIN32 and Linux driver
731
732	/***************************/
733	/* Acquisition initialized */
734	/***************************/
735	//BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
736	devpriv->b_AiCyclicAcquisition = APCI3120_ENABLE;
737	//END JK 07.05.04: Comparison between WIN32 and Linux driver
738
739	// clear software  registers
740	devpriv->b_TimerSelectMode = 0;
741	devpriv->us_OutputRegister = 0;
742	devpriv->b_ModeSelectRegister = 0;
743	//devpriv->b_DigitalOutputRegister=0;
744
745	//COMMENT JK 07.05.04: Followings calls are in i_APCI3120_StartAnalogInputAcquisition
746
747   /****************************/
748	/* Clear Timer Write TC INT */
749   /****************************/
750	outl(APCI3120_CLEAR_WRITE_TC_INT,
751		devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_REG_INTCSR);
752
753   /************************************/
754	/* Clears the timer status register */
755   /************************************/
756	//BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
757	//inw(dev->iobase+APCI3120_TIMER_STATUS_REGISTER);
758	inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
759	//END JK 07.05.04: Comparison between WIN32 and Linux driver
760
761   /**************************/
762	/* Disables All Timer     */
763	/* Sets PR and PA to 0    */
764   /**************************/
765	devpriv->us_OutputRegister = devpriv->us_OutputRegister &
766		APCI3120_DISABLE_TIMER0 &
767		APCI3120_DISABLE_TIMER1 & APCI3120_CLEAR_PA_PR;
768
769	outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
770
771   /*******************/
772	/* Resets the FIFO */
773   /*******************/
774	//BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
775	inb(devpriv->iobase + APCI3120_RESET_FIFO);
776	//END JK 07.05.04: Comparison between WIN32 and Linux driver
777
778	devpriv->ui_AiActualScan = 0;
779	devpriv->ui_AiActualScanPosition = 0;
780	s->async->cur_chan = 0;
781	devpriv->ui_AiBufferPtr = 0;
782	devpriv->ui_DmaActualBuffer = 0;
783
784	// value for timer2  minus -2 has to be done .....dunno y??
785	ui_TimerValue2 = devpriv->ui_AiNbrofScans - 2;
786	ui_ConvertTiming = devpriv->ui_AiTimer0;
787
788	if (mode == 2)
789		ui_DelayTiming = devpriv->ui_AiTimer1;
790
791   /**********************************/
792	/* Initializes the sequence array */
793   /**********************************/
794	if (!i_APCI3120_SetupChannelList(dev, s, devpriv->ui_AiNbrofChannels,
795			devpriv->pui_AiChannelList, 0))
796		return -EINVAL;
797
798	us_TmpValue = (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
799/*** EL241003 : add this section in comment because floats must not be used
800	 if((us_TmpValue & 0x00B0)==0x00B0)
801	 {
802           f_ConvertValue=(((float)ui_ConvertTiming * 0.002) - 2);
803		ui_TimerValue0=(UINT)f_ConvertValue;
804		if (mode==2)
805		{
806			f_DelayValue     = (((float)ui_DelayTiming * 0.00002) - 2);
807			ui_TimerValue1  =   (UINT) f_DelayValue;
808		}
809	 }
810   	 else
811	 {
812		f_ConvertValue=(((float)ui_ConvertTiming * 0.0012926) - 1);
813		ui_TimerValue0=(UINT)f_ConvertValue;
814		if (mode == 2)
815		{
816		     f_DelayValue     = (((float)ui_DelayTiming * 0.000012926) - 1);
817		     ui_TimerValue1  =   (UINT) f_DelayValue;
818		}
819	}
820***********************************************************************************************/
821/*** EL241003 Begin : add this section to replace floats calculation by integer calculations **/
822	//EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001
823	if ((us_TmpValue & 0x00B0) == 0x00B0
824		|| !strcmp(this_board->pc_DriverName, "apci3001")) {
825		ui_TimerValue0 = ui_ConvertTiming * 2 - 2000;
826		ui_TimerValue0 = ui_TimerValue0 / 1000;
827
828		if (mode == 2) {
829			ui_DelayTiming = ui_DelayTiming / 1000;
830			ui_TimerValue1 = ui_DelayTiming * 2 - 200;
831			ui_TimerValue1 = ui_TimerValue1 / 100;
832		}
833	} else {
834		ui_ConvertTiming = ui_ConvertTiming / 1000;
835		ui_TimerValue0 = ui_ConvertTiming * 12926 - 10000;
836		ui_TimerValue0 = ui_TimerValue0 / 10000;
837
838		if (mode == 2) {
839			ui_DelayTiming = ui_DelayTiming / 1000;
840			ui_TimerValue1 = ui_DelayTiming * 12926 - 1;
841			ui_TimerValue1 = ui_TimerValue1 / 1000000;
842		}
843	}
844/*** EL241003 End ******************************************************************************/
845
846	if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) {
847		i_APCI3120_ExttrigEnable(dev);	// activate EXT trigger
848	}
849	switch (mode) {
850	case 1:
851		// init timer0 in mode 2
852		devpriv->b_TimerSelectMode =
853			(devpriv->
854			b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
855		outb(devpriv->b_TimerSelectMode,
856			dev->iobase + APCI3120_TIMER_CRT1);
857
858		//Select Timer 0
859		b_Tmp = ((devpriv->
860				b_DigitalOutputRegister) & 0xF0) |
861			APCI3120_SELECT_TIMER_0_WORD;
862		outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
863		//Set the convertion time
864		outw(((unsigned short) ui_TimerValue0),
865			dev->iobase + APCI3120_TIMER_VALUE);
866		break;
867
868	case 2:
869		// init timer1 in mode 2
870		devpriv->b_TimerSelectMode =
871			(devpriv->
872			b_TimerSelectMode & 0xF3) | APCI3120_TIMER_1_MODE_2;
873		outb(devpriv->b_TimerSelectMode,
874			dev->iobase + APCI3120_TIMER_CRT1);
875
876		//Select Timer 1
877		b_Tmp = ((devpriv->
878				b_DigitalOutputRegister) & 0xF0) |
879			APCI3120_SELECT_TIMER_1_WORD;
880		outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
881		//Set the convertion time
882		outw(((unsigned short) ui_TimerValue1),
883			dev->iobase + APCI3120_TIMER_VALUE);
884
885		// init timer0 in mode 2
886		devpriv->b_TimerSelectMode =
887			(devpriv->
888			b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
889		outb(devpriv->b_TimerSelectMode,
890			dev->iobase + APCI3120_TIMER_CRT1);
891
892		//Select Timer 0
893		b_Tmp = ((devpriv->
894				b_DigitalOutputRegister) & 0xF0) |
895			APCI3120_SELECT_TIMER_0_WORD;
896		outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
897
898		//Set the convertion time
899		outw(((unsigned short) ui_TimerValue0),
900			dev->iobase + APCI3120_TIMER_VALUE);
901		break;
902
903	}
904	//   ##########common for all modes#################
905
906	/***********************/
907	/* Clears the SCAN bit */
908	/***********************/
909	//BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
910	//devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister | APCI3120_DISABLE_SCAN;
911	devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
912		APCI3120_DISABLE_SCAN;
913	//END JK 07.05.04: Comparison between WIN32 and Linux driver
914	outb(devpriv->b_ModeSelectRegister,
915		dev->iobase + APCI3120_WRITE_MODE_SELECT);
916
917	// If DMA is disabled
918	if (devpriv->us_UseDma == APCI3120_DISABLE) {
919		// disable EOC and enable EOS
920		devpriv->b_InterruptMode = APCI3120_EOS_MODE;
921		devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
922
923		devpriv->b_ModeSelectRegister =
924			(devpriv->
925			b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT) |
926			APCI3120_ENABLE_EOS_INT;
927		outb(devpriv->b_ModeSelectRegister,
928			dev->iobase + APCI3120_WRITE_MODE_SELECT);
929
930		if (!devpriv->b_AiContinuous) {
931			// configure Timer2 For counting  EOS
932			//Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0)
933			devpriv->us_OutputRegister =
934				devpriv->
935				us_OutputRegister & APCI3120_DISABLE_TIMER2;
936			outw(devpriv->us_OutputRegister,
937				dev->iobase + APCI3120_WR_ADDRESS);
938
939			// DISABLE TIMER INTERRUPT
940			devpriv->b_ModeSelectRegister =
941				devpriv->
942				b_ModeSelectRegister &
943				APCI3120_DISABLE_TIMER_INT & 0xEF;
944			outb(devpriv->b_ModeSelectRegister,
945				dev->iobase + APCI3120_WRITE_MODE_SELECT);
946
947			//(1) Init timer 2 in mode 0 and write timer value
948			devpriv->b_TimerSelectMode =
949				(devpriv->
950				b_TimerSelectMode & 0x0F) |
951				APCI3120_TIMER_2_MODE_0;
952			outb(devpriv->b_TimerSelectMode,
953				dev->iobase + APCI3120_TIMER_CRT1);
954
955			//Writing LOW WORD
956			b_Tmp = ((devpriv->
957					b_DigitalOutputRegister) & 0xF0) |
958				APCI3120_SELECT_TIMER_2_LOW_WORD;
959			outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
960			outw(LOWORD(ui_TimerValue2),
961				dev->iobase + APCI3120_TIMER_VALUE);
962
963			//Writing HIGH WORD
964			b_Tmp = ((devpriv->
965					b_DigitalOutputRegister) & 0xF0) |
966				APCI3120_SELECT_TIMER_2_HIGH_WORD;
967			outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
968			outw(HIWORD(ui_TimerValue2),
969				dev->iobase + APCI3120_TIMER_VALUE);
970
971			//(2) Reset FC_TIMER BIT  Clearing timer status register
972			inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
973			// enable timer counter and disable watch dog
974			devpriv->b_ModeSelectRegister =
975				(devpriv->
976				b_ModeSelectRegister |
977				APCI3120_ENABLE_TIMER_COUNTER) &
978				APCI3120_DISABLE_WATCHDOG;
979			// select EOS clock input for timer 2
980			devpriv->b_ModeSelectRegister =
981				devpriv->
982				b_ModeSelectRegister |
983				APCI3120_TIMER2_SELECT_EOS;
984			// Enable timer2  interrupt
985			devpriv->b_ModeSelectRegister =
986				devpriv->
987				b_ModeSelectRegister |
988				APCI3120_ENABLE_TIMER_INT;
989			outb(devpriv->b_ModeSelectRegister,
990				dev->iobase + APCI3120_WRITE_MODE_SELECT);
991			devpriv->b_Timer2Mode = APCI3120_COUNTER;
992			devpriv->b_Timer2Interrupt = APCI3120_ENABLE;
993		}
994	} else {
995		// If DMA Enabled
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;
1000
1001      /************************************/
1002		/* Disables the EOC, EOS interrupt  */
1003	  /************************************/
1004		devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
1005			APCI3120_DISABLE_EOC_INT & APCI3120_DISABLE_EOS_INT;
1006
1007		outb(devpriv->b_ModeSelectRegister,
1008			dev->iobase + APCI3120_WRITE_MODE_SELECT);
1009
1010		dmalen0 = devpriv->ui_DmaBufferSize[0];
1011		dmalen1 = devpriv->ui_DmaBufferSize[1];
1012
1013		if (!devpriv->b_AiContinuous) {
1014
1015			if (dmalen0 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2)) {	// must we fill full first buffer?
1016				dmalen0 =
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?
1020				dmalen1 =
1021					devpriv->ui_AiNbrofScans *
1022					devpriv->ui_AiScanLength * 2 - dmalen0;
1023		}
1024
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)
1030					dmalen0 += 2;
1031			}
1032			if (dmalen1 > (devpriv->ui_AiScanLength * 2)) {
1033				dmalen1 = devpriv->ui_AiScanLength * 2;
1034				if (devpriv->ui_AiScanLength & 1)
1035					dmalen1 -= 2;
1036				if (dmalen1 < 4)
1037					dmalen1 = 4;
1038			}
1039		} else {	// isn't output buff smaller that our DMA buff?
1040			if (dmalen0 > (devpriv->ui_AiDataLength)) {
1041				dmalen0 = devpriv->ui_AiDataLength;
1042			}
1043			if (dmalen1 > (devpriv->ui_AiDataLength)) {
1044				dmalen1 = devpriv->ui_AiDataLength;
1045			}
1046		}
1047		devpriv->ui_DmaBufferUsesize[0] = dmalen0;
1048		devpriv->ui_DmaBufferUsesize[1] = dmalen1;
1049
1050		//Initialize DMA
1051
1052		// Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS register
1053		//1
1054		ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1055		outl(ui_Tmp, devpriv->i_IobaseAmcc + AMCC_OP_REG_AGCSTS);
1056
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);
1064
1065		outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1066		outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH,
1067			devpriv->i_IobaseAddon + 2);
1068
1069		// TO VERIFIED
1070		//BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
1071		outw(0x1000, devpriv->i_IobaseAddon + 2);
1072		//END JK 07.05.04: Comparison between WIN32 and Linux driver
1073
1074		//2  No change
1075		// A2P FIFO MANAGEMENT
1076		// A2P fifo reset  & transfer control enable
1077		 /***********************/
1078		/* A2P FIFO MANAGEMENT */
1079		 /***********************/
1080		outl(APCI3120_A2P_FIFO_MANAGEMENT, devpriv->i_IobaseAmcc +
1081			APCI3120_AMCC_OP_MCSR);
1082
1083		//3
1084		//beginning address of dma buf
1085		//The 32 bit address of dma buffer is converted into two 16 bit addresses
1086		// Can done by using _attach and put into into an array
1087		// array used may be for differnet pages
1088
1089		// DMA Start Adress Low
1090		outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1091		outw((devpriv->ul_DmaBufferHw[0] & 0xFFFF),
1092			devpriv->i_IobaseAddon + 2);
1093
1094		 /*************************/
1095		/* DMA Start Adress High */
1096		 /*************************/
1097		outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1098		outw((devpriv->ul_DmaBufferHw[0] / 65536),
1099			devpriv->i_IobaseAddon + 2);
1100
1101		//4
1102		// amount of bytes to be transfered  set transfer count
1103		// used ADDON MWTC register
1104		//commented testing             outl(devpriv->ui_DmaBufferUsesize[0], devpriv->i_IobaseAddon+AMCC_OP_REG_AMWTC);
1105
1106		 /**************************/
1107		/* Nbr of acquisition LOW */
1108		 /**************************/
1109		outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1110		outw((devpriv->ui_DmaBufferUsesize[0] & 0xFFFF),
1111			devpriv->i_IobaseAddon + 2);
1112
1113		 /***************************/
1114		/* Nbr of acquisition HIGH */
1115		 /***************************/
1116		outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1117		outw((devpriv->ui_DmaBufferUsesize[0] / 65536),
1118			devpriv->i_IobaseAddon + 2);
1119
1120		//5
1121		// To configure A2P FIFO
1122		// testing outl( FIFO_ADVANCE_ON_BYTE_2,devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR);
1123
1124		/******************/
1125		/* A2P FIFO RESET */
1126		/******************/
1127		// TO VERIFY
1128		//BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
1129		outl(0x04000000UL, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
1130		//END JK 07.05.04: Comparison between WIN32 and Linux driver
1131
1132		//6
1133		//ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1134		// AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1135		//BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
1136		//outw(3,devpriv->i_IobaseAddon + 4);
1137		//END JK 07.05.04: Comparison between WIN32 and Linux driver
1138
1139		//7
1140		//initialise end of dma interrupt  AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI)
1141		/***************************************************/
1142		/* A2P FIFO CONFIGURATE, END OF DMA INTERRUPT INIT */
1143		/***************************************************/
1144		outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1145				APCI3120_ENABLE_WRITE_TC_INT),
1146			devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1147
1148		//BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
1149		/******************************************/
1150		/* ENABLE A2P FIFO WRITE AND ENABLE AMWEN */
1151		/******************************************/
1152		outw(3, devpriv->i_IobaseAddon + 4);
1153		//END JK 07.05.04: Comparison between WIN32 and Linux driver
1154
1155		/******************/
1156		/* A2P FIFO RESET */
1157		/******************/
1158		//BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
1159		outl(0x04000000UL,
1160			devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_MCSR);
1161		//END JK 07.05.04: Comparison between WIN32 and Linux driver
1162	}
1163
1164	if ((devpriv->us_UseDma == APCI3120_DISABLE)
1165		&& !devpriv->b_AiContinuous) {
1166		// set gate 2   to start conversion
1167		devpriv->us_OutputRegister =
1168			devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER2;
1169		outw(devpriv->us_OutputRegister,
1170			dev->iobase + APCI3120_WR_ADDRESS);
1171	}
1172
1173	switch (mode) {
1174	case 1:
1175		// set gate 0   to start conversion
1176		devpriv->us_OutputRegister =
1177			devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
1178		outw(devpriv->us_OutputRegister,
1179			dev->iobase + APCI3120_WR_ADDRESS);
1180		break;
1181	case 2:
1182		// set  gate 0 and gate 1
1183		devpriv->us_OutputRegister =
1184			devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER1;
1185		devpriv->us_OutputRegister =
1186			devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
1187		outw(devpriv->us_OutputRegister,
1188			dev->iobase + APCI3120_WR_ADDRESS);
1189		break;
1190
1191	}
1192
1193	return 0;
1194
1195}
1196
1197/*
1198+----------------------------------------------------------------------------+
1199| 			INTERNAL FUNCTIONS						                 |
1200+----------------------------------------------------------------------------+
1201*/
1202
1203/*
1204+----------------------------------------------------------------------------+
1205| Function name     : int i_APCI3120_Reset(struct comedi_device *dev)               |
1206|                                        									 |
1207|                                            						         |
1208+----------------------------------------------------------------------------+
1209| Task              : Hardware reset function   						     |
1210|                     										                 |
1211+----------------------------------------------------------------------------+
1212| Input Parameters  : 	struct comedi_device *dev									 |
1213|                     														 |
1214|                                                 					         |
1215+----------------------------------------------------------------------------+
1216| Return Value      :              					                         |
1217|                    													     |
1218+----------------------------------------------------------------------------+
1219*/
1220
1221int i_APCI3120_Reset(struct comedi_device * dev)
1222{
1223	unsigned int i;
1224	unsigned short us_TmpValue;
1225
1226	devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1227	devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1228	devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1229	devpriv->ui_EocEosConversionTime = 0;	// set eoc eos conv time to 0
1230	devpriv->b_OutputMemoryStatus = 0;
1231
1232	// variables used in timer subdevice
1233	devpriv->b_Timer2Mode = 0;
1234	devpriv->b_Timer2Interrupt = 0;
1235	devpriv->b_ExttrigEnable = 0;	// Disable ext trigger
1236
1237	/* Disable all interrupts, watchdog for the anolog output */
1238	devpriv->b_ModeSelectRegister = 0;
1239	outb(devpriv->b_ModeSelectRegister,
1240		dev->iobase + APCI3120_WRITE_MODE_SELECT);
1241
1242	// Disables all counters, ext trigger and clears PA, PR
1243	devpriv->us_OutputRegister = 0;
1244	outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1245
1246	//Code to set the all anolog o/p channel to 0v
1247	//8191 is decimal value for zero(0 v)volt in bipolar mode(default)
1248	outw(8191 | APCI3120_ANALOG_OP_CHANNEL_1, dev->iobase + APCI3120_ANALOG_OUTPUT_1);	//channel 1
1249	outw(8191 | APCI3120_ANALOG_OP_CHANNEL_2, dev->iobase + APCI3120_ANALOG_OUTPUT_1);	//channel 2
1250	outw(8191 | APCI3120_ANALOG_OP_CHANNEL_3, dev->iobase + APCI3120_ANALOG_OUTPUT_1);	//channel 3
1251	outw(8191 | APCI3120_ANALOG_OP_CHANNEL_4, dev->iobase + APCI3120_ANALOG_OUTPUT_1);	//channel 4
1252
1253	outw(8191 | APCI3120_ANALOG_OP_CHANNEL_5, dev->iobase + APCI3120_ANALOG_OUTPUT_2);	//channel 5
1254	outw(8191 | APCI3120_ANALOG_OP_CHANNEL_6, dev->iobase + APCI3120_ANALOG_OUTPUT_2);	//channel 6
1255	outw(8191 | APCI3120_ANALOG_OP_CHANNEL_7, dev->iobase + APCI3120_ANALOG_OUTPUT_2);	//channel 7
1256	outw(8191 | APCI3120_ANALOG_OP_CHANNEL_8, dev->iobase + APCI3120_ANALOG_OUTPUT_2);	//channel 8
1257
1258	//  Reset digital output to L0W
1259
1260//ES05  outb(0x0,dev->iobase+APCI3120_DIGITAL_OUTPUT);
1261	udelay(10);
1262
1263	inw(dev->iobase + 0);	//make a dummy read
1264	inb(dev->iobase + APCI3120_RESET_FIFO);	// flush FIFO
1265	inw(dev->iobase + APCI3120_RD_STATUS);	// flush A/D status register
1266
1267	//code to reset the RAM sequence
1268	for (i = 0; i < 16; i++) {
1269		us_TmpValue = i << 8;	//select the location
1270		outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
1271	}
1272	return 0;
1273}
1274
1275/*
1276+----------------------------------------------------------------------------+
1277| Function name     : int i_APCI3120_SetupChannelList(struct comedi_device * dev,   |
1278|                     struct comedi_subdevice * s, int n_chan,unsigned int *chanlist|
1279|			  ,char check)											 |
1280|                                            						         |
1281+----------------------------------------------------------------------------+
1282| Task              :This function will first check channel list is ok or not|
1283|and then initialize the sequence RAM with the polarity, Gain,Channel number |
1284|If the last argument of function "check"is 1 then it only checks the channel|
1285|list is ok or not.												     		 |
1286|                     										                 |
1287+----------------------------------------------------------------------------+
1288| Input Parameters  : struct comedi_device * dev									 |
1289|                     struct comedi_subdevice * s									 |
1290|                     int n_chan                   					         |
1291			  unsigned int *chanlist
1292			  char check
1293+----------------------------------------------------------------------------+
1294| Return Value      :              					                         |
1295|                    													     |
1296+----------------------------------------------------------------------------+
1297*/
1298
1299int i_APCI3120_SetupChannelList(struct comedi_device * dev, struct comedi_subdevice * s,
1300	int n_chan, unsigned int *chanlist, char check)
1301{
1302	unsigned int i;		//, differencial=0, bipolar=0;
1303	unsigned int gain;
1304	unsigned short us_TmpValue;
1305
1306	/* correct channel and range number check itself comedi/range.c */
1307	if (n_chan < 1) {
1308		if (!check)
1309			comedi_error(dev, "range/channel list is empty!");
1310		return 0;
1311	}
1312	// All is ok, so we can setup channel/range list
1313	if (check)
1314		return 1;
1315
1316	//Code  to set the PA and PR...Here it set PA to 0..
1317	devpriv->us_OutputRegister =
1318		devpriv->us_OutputRegister & APCI3120_CLEAR_PA_PR;
1319	devpriv->us_OutputRegister = ((n_chan - 1) & 0xf) << 8;
1320	outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1321
1322	for (i = 0; i < n_chan; i++) {
1323		// store range list to card
1324		us_TmpValue = CR_CHAN(chanlist[i]);	// get channel number;
1325
1326		if (CR_RANGE(chanlist[i]) < APCI3120_BIPOLAR_RANGES) {
1327			us_TmpValue &= ((~APCI3120_UNIPOLAR) & 0xff);	// set bipolar
1328		} else {
1329			us_TmpValue |= APCI3120_UNIPOLAR;	// enable unipolar......
1330		}
1331
1332		gain = CR_RANGE(chanlist[i]);	// get gain number
1333		us_TmpValue |= ((gain & 0x03) << 4);	//<<4 for G0 and G1 bit in RAM
1334		us_TmpValue |= i << 8;	//To select the RAM LOCATION....
1335		outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
1336
1337		printk("\n Gain = %i",
1338			(((unsigned char)CR_RANGE(chanlist[i]) & 0x03) << 2));
1339		printk("\n Channel = %i", CR_CHAN(chanlist[i]));
1340		printk("\n Polarity = %i", us_TmpValue & APCI3120_UNIPOLAR);
1341	}
1342	return 1;		// we can serve this with scan logic
1343}
1344
1345/*
1346+----------------------------------------------------------------------------+
1347| Function name     :	int i_APCI3120_ExttrigEnable(struct comedi_device * dev)    |
1348|                                        									 |
1349|                                            						         |
1350+----------------------------------------------------------------------------+
1351| Task              : 	Enable the external trigger						     |
1352|                     										                 |
1353+----------------------------------------------------------------------------+
1354| Input Parameters  : 	struct comedi_device * dev									 |
1355|                     														 |
1356|                                                 					         |
1357+----------------------------------------------------------------------------+
1358| Return Value      :      0        					                         |
1359|                    													     |
1360+----------------------------------------------------------------------------+
1361*/
1362
1363int i_APCI3120_ExttrigEnable(struct comedi_device * dev)
1364{
1365
1366	devpriv->us_OutputRegister |= APCI3120_ENABLE_EXT_TRIGGER;
1367	outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1368	return 0;
1369}
1370
1371/*
1372+----------------------------------------------------------------------------+
1373| Function name     : 	int i_APCI3120_ExttrigDisable(struct comedi_device * dev)   |
1374|                                        									 |
1375+----------------------------------------------------------------------------+
1376| Task              : 	Disables the external trigger					     |
1377|                     										                 |
1378+----------------------------------------------------------------------------+
1379| Input Parameters  : 	struct comedi_device * dev									 |
1380|                     														 |
1381|                                                 					         |
1382+----------------------------------------------------------------------------+
1383| Return Value      :    0          					                         |
1384|                    													     |
1385+----------------------------------------------------------------------------+
1386*/
1387
1388int i_APCI3120_ExttrigDisable(struct comedi_device * dev)
1389{
1390	devpriv->us_OutputRegister &= ~APCI3120_ENABLE_EXT_TRIGGER;
1391	outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1392	return 0;
1393}
1394
1395/*
1396+----------------------------------------------------------------------------+
1397|                    INTERRUPT FUNCTIONS		    		                 |
1398+----------------------------------------------------------------------------+
1399*/
1400
1401/*
1402+----------------------------------------------------------------------------+
1403| Function name     : void v_APCI3120_Interrupt(int irq, void *d) 								 |
1404|                                        									 |
1405|                                            						         |
1406+----------------------------------------------------------------------------+
1407| Task              :Interrupt handler for APCI3120                        	 |
1408|			 When interrupt occurs this gets called.                 |
1409|			 First it finds which interrupt has been generated and   |
1410|			 handles  corresponding interrupt                        |
1411|                     										                 |
1412+----------------------------------------------------------------------------+
1413| Input Parameters  : 	int irq 											 |
1414|                        void *d											 |
1415|                                                 					         |
1416+----------------------------------------------------------------------------+
1417| Return Value      : void         					                         |
1418|                    													     |
1419+----------------------------------------------------------------------------+
1420*/
1421
1422void v_APCI3120_Interrupt(int irq, void *d)
1423{
1424	struct comedi_device *dev = d;
1425	unsigned short int_daq;
1426
1427	unsigned int int_amcc, ui_Check, i;
1428	unsigned short us_TmpValue;
1429	unsigned char b_DummyRead;
1430
1431	struct comedi_subdevice *s = dev->subdevices + 0;
1432	ui_Check = 1;
1433
1434	int_daq = inw(dev->iobase + APCI3120_RD_STATUS) & 0xf000;	// get IRQ reasons
1435	int_amcc = inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);	// get AMCC INT register
1436
1437	if ((!int_daq) && (!(int_amcc & ANY_S593X_INT))) {
1438		comedi_error(dev, "IRQ from unknow source");
1439		return;
1440	}
1441
1442	outl(int_amcc | 0x00ff0000, devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);	// shutdown IRQ reasons in AMCC
1443
1444	int_daq = (int_daq >> 12) & 0xF;
1445
1446	if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) {
1447		//Disable ext trigger
1448		i_APCI3120_ExttrigDisable(dev);
1449		devpriv->b_ExttrigEnable = APCI3120_DISABLE;
1450	}
1451	//clear the timer 2 interrupt
1452	inb(devpriv->i_IobaseAmcc + APCI3120_TIMER_STATUS_REGISTER);
1453
1454	if (int_amcc & MASTER_ABORT_INT)
1455		comedi_error(dev, "AMCC IRQ - MASTER DMA ABORT!");
1456	if (int_amcc & TARGET_ABORT_INT)
1457		comedi_error(dev, "AMCC IRQ - TARGET DMA ABORT!");
1458
1459	// Ckeck if EOC interrupt
1460	if (((int_daq & 0x8) == 0)
1461		&& (devpriv->b_InterruptMode == APCI3120_EOC_MODE)) {
1462		if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
1463
1464			// Read the AI Value
1465
1466			devpriv->ui_AiReadData[0] =
1467				(UINT) inw(devpriv->iobase + 0);
1468			devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1469			send_sig(SIGIO, devpriv->tsk_Current, 0);	// send signal to the sample
1470		} else {
1471			//Disable EOC Interrupt
1472			devpriv->b_ModeSelectRegister =
1473				devpriv->
1474				b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT;
1475			outb(devpriv->b_ModeSelectRegister,
1476				devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
1477
1478		}
1479	}
1480
1481	// Check If EOS interrupt
1482	if ((int_daq & 0x2) && (devpriv->b_InterruptMode == APCI3120_EOS_MODE)) {
1483
1484		if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE)	// enable this in without DMA ???
1485		{
1486
1487			if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
1488				ui_Check = 0;
1489				i_APCI3120_InterruptHandleEos(dev);
1490				devpriv->ui_AiActualScan++;
1491				devpriv->b_ModeSelectRegister =
1492					devpriv->
1493					b_ModeSelectRegister |
1494					APCI3120_ENABLE_EOS_INT;
1495				outb(devpriv->b_ModeSelectRegister,
1496					dev->iobase +
1497					APCI3120_WRITE_MODE_SELECT);
1498			} else {
1499				ui_Check = 0;
1500				for (i = 0; i < devpriv->ui_AiNbrofChannels;
1501					i++) {
1502					us_TmpValue = inw(devpriv->iobase + 0);
1503					devpriv->ui_AiReadData[i] =
1504						(UINT) us_TmpValue;
1505				}
1506				devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1507				devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1508
1509				send_sig(SIGIO, devpriv->tsk_Current, 0);	// send signal to the sample
1510
1511			}
1512
1513		} else {
1514			devpriv->b_ModeSelectRegister =
1515				devpriv->
1516				b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
1517			outb(devpriv->b_ModeSelectRegister,
1518				dev->iobase + APCI3120_WRITE_MODE_SELECT);
1519			devpriv->b_EocEosInterrupt = APCI3120_DISABLE;	//Default settings
1520			devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1521		}
1522
1523	}
1524	//Timer2 interrupt
1525	if (int_daq & 0x1) {
1526
1527		switch (devpriv->b_Timer2Mode) {
1528		case APCI3120_COUNTER:
1529
1530			devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1531			devpriv->b_ModeSelectRegister =
1532				devpriv->
1533				b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
1534			outb(devpriv->b_ModeSelectRegister,
1535				dev->iobase + APCI3120_WRITE_MODE_SELECT);
1536
1537			// stop timer 2
1538			devpriv->us_OutputRegister =
1539				devpriv->
1540				us_OutputRegister & APCI3120_DISABLE_ALL_TIMER;
1541			outw(devpriv->us_OutputRegister,
1542				dev->iobase + APCI3120_WR_ADDRESS);
1543
1544			//stop timer 0 and timer 1
1545			i_APCI3120_StopCyclicAcquisition(dev, s);
1546			devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1547
1548			//UPDATE-0.7.57->0.7.68comedi_done(dev,s);
1549			s->async->events |= COMEDI_CB_EOA;
1550			comedi_event(dev, s);
1551
1552			break;
1553
1554		case APCI3120_TIMER:
1555
1556			//Send a signal to from kernel to user space
1557			send_sig(SIGIO, devpriv->tsk_Current, 0);
1558			break;
1559
1560		case APCI3120_WATCHDOG:
1561
1562			//Send a signal to from kernel to user space
1563			send_sig(SIGIO, devpriv->tsk_Current, 0);
1564			break;
1565
1566		default:
1567
1568			// disable Timer Interrupt
1569
1570			devpriv->b_ModeSelectRegister =
1571				devpriv->
1572				b_ModeSelectRegister &
1573				APCI3120_DISABLE_TIMER_INT;
1574
1575			outb(devpriv->b_ModeSelectRegister,
1576				dev->iobase + APCI3120_WRITE_MODE_SELECT);
1577
1578		}
1579
1580		b_DummyRead = inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1581
1582	}
1583
1584	if ((int_daq & 0x4) && (devpriv->b_InterruptMode == APCI3120_DMA_MODE)) {
1585		if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
1586
1587			/****************************/
1588			/* Clear Timer Write TC INT */
1589			/****************************/
1590
1591			outl(APCI3120_CLEAR_WRITE_TC_INT,
1592				devpriv->i_IobaseAmcc +
1593				APCI3120_AMCC_OP_REG_INTCSR);
1594
1595			/************************************/
1596			/* Clears the timer status register */
1597			/************************************/
1598			inw(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1599			v_APCI3120_InterruptDma(irq, d);	// do some data transfer
1600		} else {
1601			/* Stops the Timer */
1602			outw(devpriv->
1603				us_OutputRegister & APCI3120_DISABLE_TIMER0 &
1604				APCI3120_DISABLE_TIMER1,
1605				dev->iobase + APCI3120_WR_ADDRESS);
1606		}
1607
1608	}
1609
1610	return;
1611}
1612
1613/*
1614+----------------------------------------------------------------------------+
1615| Function name     :int i_APCI3120_InterruptHandleEos(struct comedi_device *dev)   |
1616|                                        									 |
1617|                                            						         |
1618+----------------------------------------------------------------------------+
1619| Task              : This function handles EOS interrupt.                   |
1620|                     This function copies the acquired data(from FIFO)      |
1621|				to Comedi buffer.		 							 |
1622|                     										                 |
1623+----------------------------------------------------------------------------+
1624| Input Parameters  : struct comedi_device *dev									 |
1625|                     														 |
1626|                                                 					         |
1627+----------------------------------------------------------------------------+
1628| Return Value      : 0            					                         |
1629|                    													     |
1630+----------------------------------------------------------------------------+
1631*/
1632
1633/*
1634 * int i_APCI3120_InterruptHandleEos(struct comedi_device *dev)
1635{
1636       int n_chan,i;
1637       short *data;
1638       struct comedi_subdevice *s=dev->subdevices+0;
1639       struct comedi_async *async = s->async;
1640       data=async->data+async->buf_int_ptr;
1641        n_chan=devpriv->ui_AiNbrofChannels;
1642
1643       for(i=0;i<n_chan;i++)
1644         {
1645           data[i]=inw(dev->iobase+0);
1646         }
1647       async->buf_int_count+=n_chan*sizeof(short);
1648       async->buf_int_ptr+=n_chan*sizeof(short);
1649       comedi_eos(dev,s);
1650       if (s->async->buf_int_ptr>=s->async->data_len) //  for buffer rool over
1651		         {
1652*//* buffer rollover */
1653/*	        s->async->buf_int_ptr=0;
1654		comedi_eobuf(dev,s);
1655         }
1656 	return 0;
1657}*/
1658int i_APCI3120_InterruptHandleEos(struct comedi_device * dev)
1659{
1660	int n_chan, i;
1661	struct comedi_subdevice *s = dev->subdevices + 0;
1662	int err = 1;
1663
1664	n_chan = devpriv->ui_AiNbrofChannels;
1665
1666	s->async->events = 0;
1667
1668	for (i = 0; i < n_chan; i++)
1669		err &= comedi_buf_put(s->async, inw(dev->iobase + 0));
1670
1671	s->async->events |= COMEDI_CB_EOS;
1672
1673	if (err == 0)
1674		s->async->events |= COMEDI_CB_OVERFLOW;
1675
1676	comedi_event(dev, s);
1677
1678	return 0;
1679}
1680
1681/*
1682+----------------------------------------------------------------------------+
1683| Function name     : void v_APCI3120_InterruptDma(int irq, void *d) 									 |
1684|                                        									 |
1685+----------------------------------------------------------------------------+
1686| Task              : This is a handler for the DMA interrupt                |
1687|			  This function copies the data to Comedi Buffer.        |
1688|			  For continuous DMA it reinitializes the DMA operation. |
1689|			  For single mode DMA it stop the acquisition.           |
1690|													     			 |
1691+----------------------------------------------------------------------------+
1692| Input Parameters  : int irq, void *d				 |
1693|                     														 |
1694+----------------------------------------------------------------------------+
1695| Return Value      :  void        					                         |
1696|                    													     |
1697+----------------------------------------------------------------------------+
1698*/
1699
1700void v_APCI3120_InterruptDma(int irq, void *d)
1701{
1702	struct comedi_device *dev = d;
1703	struct comedi_subdevice *s = dev->subdevices + 0;
1704	unsigned int next_dma_buf, samplesinbuf;
1705	unsigned long low_word, high_word, var;
1706
1707	UINT ui_Tmp;
1708	samplesinbuf =
1709		devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer] -
1710		inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_MWTC);
1711
1712	if (samplesinbuf <
1713		devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer]) {
1714		comedi_error(dev, "Interrupted DMA transfer!");
1715	}
1716	if (samplesinbuf & 1) {
1717		comedi_error(dev, "Odd count of bytes in DMA ring!");
1718		i_APCI3120_StopCyclicAcquisition(dev, s);
1719		devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1720
1721		return;
1722	}
1723	samplesinbuf = samplesinbuf >> 1;	// number of received samples
1724	if (devpriv->b_DmaDoubleBuffer) {
1725		// switch DMA buffers if is used double buffering
1726		next_dma_buf = 1 - devpriv->ui_DmaActualBuffer;
1727
1728		ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1729		outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
1730
1731		// changed  since 16 bit interface for add on
1732		outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1733		outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1734			devpriv->i_IobaseAddon + 2);
1735		outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1736		outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2);	// 0x1000 is out putted in windows driver
1737
1738		var = devpriv->ul_DmaBufferHw[next_dma_buf];
1739		low_word = var & 0xffff;
1740		var = devpriv->ul_DmaBufferHw[next_dma_buf];
1741		high_word = var / 65536;
1742
1743		/* DMA Start Adress Low */
1744		outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1745		outw(low_word, devpriv->i_IobaseAddon + 2);
1746
1747		/* DMA Start Adress High */
1748		outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1749		outw(high_word, devpriv->i_IobaseAddon + 2);
1750
1751		var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
1752		low_word = var & 0xffff;
1753		var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
1754		high_word = var / 65536;
1755
1756		/* Nbr of acquisition LOW */
1757		outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1758		outw(low_word, devpriv->i_IobaseAddon + 2);
1759
1760		/* Nbr of acquisition HIGH */
1761		outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1762		outw(high_word, devpriv->i_IobaseAddon + 2);
1763
1764		// To configure A2P FIFO
1765		// ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1766		// AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1767		outw(3, devpriv->i_IobaseAddon + 4);
1768		//initialise end of dma interrupt  AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI)
1769		outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1770				APCI3120_ENABLE_WRITE_TC_INT),
1771			devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1772
1773	}
1774/*UPDATE-0.7.57->0.7.68
1775	ptr=(short *)devpriv->ul_DmaBufferVirtual[devpriv->ui_DmaActualBuffer];
1776
1777
1778	// if there is not enough space left in the buffer to copy all data contained in the DMABufferVirtual
1779	if(s->async->buf_int_ptr+samplesinbuf*sizeof(short)>=devpriv->ui_AiDataLength)
1780	{
1781		m=(devpriv->ui_AiDataLength-s->async->buf_int_ptr)/sizeof(short);
1782		v_APCI3120_InterruptDmaMoveBlock16bit(dev,s,(void *)ptr,((void *)(devpriv->AiData))+s->async->buf_int_ptr,m);
1783		s->async->buf_int_count+=m*sizeof(short);
1784		ptr+=m*sizeof(short);
1785                samplesinbuf-=m;
1786		s->async->buf_int_ptr=0;
1787		comedi_eobuf(dev,s);
1788	}
1789
1790	if (samplesinbuf)
1791	{
1792	        v_APCI3120_InterruptDmaMoveBlock16bit(dev,s,(void *)ptr,((void *)(devpriv->AiData))+s->async->buf_int_ptr,samplesinbuf);
1793
1794		s->async->buf_int_count+=samplesinbuf*sizeof(short);
1795		s->async->buf_int_ptr+=samplesinbuf*sizeof(short);
1796		if (!(devpriv->ui_AiFlags & TRIG_WAKE_EOS))
1797		{
1798			comedi_bufcheck(dev,s);
1799                }
1800	}
1801	if (!devpriv->b_AiContinuous)
1802	if ( devpriv->ui_AiActualScan>=devpriv->ui_AiNbrofScans )
1803	{
1804	    // all data sampled
1805	    i_APCI3120_StopCyclicAcquisition(dev,s);
1806            devpriv->b_AiCyclicAcquisition=APCI3120_DISABLE;
1807	    //DPRINTK("\n Single DMA completed..\n");
1808		comedi_done(dev,s);
1809            	return;
1810	}
1811*/
1812	if (samplesinbuf) {
1813		v_APCI3120_InterruptDmaMoveBlock16bit(dev, s,
1814			devpriv->ul_DmaBufferVirtual[devpriv->
1815				ui_DmaActualBuffer], samplesinbuf);
1816
1817		if (!(devpriv->ui_AiFlags & TRIG_WAKE_EOS)) {
1818			s->async->events |= COMEDI_CB_EOS;
1819			comedi_event(dev, s);
1820		}
1821	}
1822	if (!devpriv->b_AiContinuous)
1823		if (devpriv->ui_AiActualScan >= devpriv->ui_AiNbrofScans) {
1824			// all data sampled
1825			i_APCI3120_StopCyclicAcquisition(dev, s);
1826			devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1827			s->async->events |= COMEDI_CB_EOA;
1828			comedi_event(dev, s);
1829			return;
1830		}
1831
1832	if (devpriv->b_DmaDoubleBuffer) {	// switch dma buffers
1833		devpriv->ui_DmaActualBuffer = 1 - devpriv->ui_DmaActualBuffer;
1834	} else {
1835		// restart DMA if is not used double buffering
1836		//ADDED REINITIALISE THE DMA
1837		ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1838		outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
1839
1840		// changed  since 16 bit interface for add on
1841		outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1842		outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1843			devpriv->i_IobaseAddon + 2);
1844		outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1845		outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2);	//
1846		// A2P FIFO MANAGEMENT
1847		// A2P fifo reset  & transfer control enable
1848		outl(APCI3120_A2P_FIFO_MANAGEMENT,
1849			devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
1850
1851		var = devpriv->ul_DmaBufferHw[0];
1852		low_word = var & 0xffff;
1853		var = devpriv->ul_DmaBufferHw[0];
1854		high_word = var / 65536;
1855		outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1856		outw(low_word, devpriv->i_IobaseAddon + 2);
1857		outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1858		outw(high_word, devpriv->i_IobaseAddon + 2);
1859
1860		var = devpriv->ui_DmaBufferUsesize[0];
1861		low_word = var & 0xffff;	//changed
1862		var = devpriv->ui_DmaBufferUsesize[0];
1863		high_word = var / 65536;
1864		outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1865		outw(low_word, devpriv->i_IobaseAddon + 2);
1866		outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1867		outw(high_word, devpriv->i_IobaseAddon + 2);
1868
1869		// To configure A2P FIFO
1870		//ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1871		// AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1872		outw(3, devpriv->i_IobaseAddon + 4);
1873		//initialise end of dma interrupt  AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI)
1874		outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1875				APCI3120_ENABLE_WRITE_TC_INT),
1876			devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1877	}
1878}
1879
1880/*
1881+----------------------------------------------------------------------------+
1882| Function name     :void v_APCI3120_InterruptDmaMoveBlock16bit(comedi_device|
1883|*dev,struct comedi_subdevice *s,short *dma,short *data,int n)				     |
1884|                                        									 |
1885+----------------------------------------------------------------------------+
1886| Task              : This function copies the data from DMA buffer to the   |
1887|				 Comedi buffer  									 |
1888|                     										                 |
1889+----------------------------------------------------------------------------+
1890| Input Parameters  : struct comedi_device *dev									 |
1891|                     struct comedi_subdevice *s									 |
1892|                     short *dma											 |
1893|                     short *data,int n          					         |
1894+----------------------------------------------------------------------------+
1895| Return Value      : void         					                         |
1896|                    													     |
1897+----------------------------------------------------------------------------+
1898*/
1899
1900/*void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev,struct comedi_subdevice *s,short *dma,short *data,int n)
1901{
1902	int i,j,m;
1903
1904	j=s->async->cur_chan;
1905	m=devpriv->ui_AiActualScanPosition;
1906        for(i=0;i<n;i++)
1907	{
1908		*data=*dma;
1909   		data++; dma++;
1910		j++;
1911		if(j>=devpriv->ui_AiNbrofChannels)
1912		{
1913			m+=j;
1914			j=0;
1915			if(m>=devpriv->ui_AiScanLength)
1916			{
1917				m=0;
1918			        devpriv->ui_AiActualScan++;
1919				if (devpriv->ui_AiFlags & TRIG_WAKE_EOS)
1920;//UPDATE-0.7.57->0.7.68					comedi_eos(dev,s);
1921			}
1922		}
1923	}
1924        devpriv->ui_AiActualScanPosition=m;
1925	s->async->cur_chan=j;
1926
1927}
1928*/
1929void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device * dev,
1930	struct comedi_subdevice * s, short * dma_buffer, unsigned int num_samples)
1931{
1932	devpriv->ui_AiActualScan +=
1933		(s->async->cur_chan + num_samples) / devpriv->ui_AiScanLength;
1934	s->async->cur_chan += num_samples;
1935	s->async->cur_chan %= devpriv->ui_AiScanLength;
1936
1937	cfc_write_array_to_buffer(s, dma_buffer, num_samples * sizeof(short));
1938}
1939
1940/*
1941+----------------------------------------------------------------------------+
1942|                           TIMER SUBDEVICE   		                         |
1943+----------------------------------------------------------------------------+
1944*/
1945
1946/*
1947+----------------------------------------------------------------------------+
1948| Function name     :int i_APCI3120_InsnConfigTimer(struct comedi_device *dev,          |
1949|	struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) 			     |
1950|                                        									 |
1951+----------------------------------------------------------------------------+
1952| Task              :Configure Timer 2  								     |
1953|                     										                 |
1954+----------------------------------------------------------------------------+
1955| Input Parameters  : struct comedi_device *dev									 |
1956|                     struct comedi_subdevice *s									 |
1957|                     struct comedi_insn *insn                                      |
1958|                     unsigned int *data 										 |
1959|                     														 |
1960|                      data[0]= TIMER  configure as timer                    |
1961|              				 = WATCHDOG configure as watchdog				 |
1962|       			  data[1] = Timer constant							 |
1963|       			  data[2] = Timer2 interrupt (1)enable or(0) disable |
1964|                                                 					         |
1965+----------------------------------------------------------------------------+
1966| Return Value      :              					                         |
1967|                    													     |
1968+----------------------------------------------------------------------------+
1969*/
1970
1971int i_APCI3120_InsnConfigTimer(struct comedi_device * dev, struct comedi_subdevice * s,
1972	struct comedi_insn * insn, unsigned int * data)
1973{
1974
1975	UINT ui_Timervalue2;
1976	unsigned short us_TmpValue;
1977	unsigned char b_Tmp;
1978
1979	if (!data[1])
1980		comedi_error(dev, "config:No timer constant !");
1981
1982	devpriv->b_Timer2Interrupt = (unsigned char) data[2];	// save info whether to enable or disable interrupt
1983
1984	ui_Timervalue2 = data[1] / 1000;	// convert nano seconds  to u seconds
1985
1986	//this_board->i_hwdrv_InsnConfigTimer(dev, ui_Timervalue2,(unsigned char)data[0]);
1987	us_TmpValue = (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
1988
1989	//EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001
1990	// and calculate the time value to set in the timer
1991	if ((us_TmpValue & 0x00B0) == 0x00B0
1992		|| !strcmp(this_board->pc_DriverName, "apci3001")) {
1993		//Calculate the time value to set in the timer
1994		ui_Timervalue2 = ui_Timervalue2 / 50;
1995	} else {
1996		//Calculate the time value to set in the timer
1997		ui_Timervalue2 = ui_Timervalue2 / 70;
1998	}
1999
2000	//Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0)
2001	devpriv->us_OutputRegister =
2002		devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER2;
2003	outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS);
2004
2005	// Disable TIMER Interrupt
2006	devpriv->b_ModeSelectRegister =
2007		devpriv->
2008		b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT & 0xEF;
2009
2010	// Disable Eoc and Eos Interrupts
2011	devpriv->b_ModeSelectRegister =
2012		devpriv->
2013		b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT &
2014		APCI3120_DISABLE_EOS_INT;
2015	outb(devpriv->b_ModeSelectRegister,
2016		devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
2017	if (data[0] == APCI3120_TIMER)	//initialize timer
2018	{
2019
2020		//devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister| APCI3120_ENABLE_TIMER_INT ;
2021		//outb(devpriv->b_ModeSelectRegister,devpriv->iobase+APCI3120_WRITE_MODE_SELECT);
2022
2023		//Set the Timer 2 in mode 2(Timer)
2024		devpriv->b_TimerSelectMode =
2025			(devpriv->
2026			b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_2;
2027		outb(devpriv->b_TimerSelectMode,
2028			devpriv->iobase + APCI3120_TIMER_CRT1);
2029
2030		//Configure the timer 2 for writing the LOW WORD of timer is Delay value
2031		//You must make a b_tmp variable with DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
2032		//you can set the digital output and configure the timer 2,and if you don't make this, digital output
2033		//are erase (Set to 0)
2034
2035		//Writing LOW WORD
2036		b_Tmp = ((devpriv->
2037				b_DigitalOutputRegister) & 0xF0) |
2038			APCI3120_SELECT_TIMER_2_LOW_WORD;
2039		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2040		outw(LOWORD(ui_Timervalue2),
2041			devpriv->iobase + APCI3120_TIMER_VALUE);
2042
2043		//Writing HIGH WORD
2044		b_Tmp = ((devpriv->
2045				b_DigitalOutputRegister) & 0xF0) |
2046			APCI3120_SELECT_TIMER_2_HIGH_WORD;
2047		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2048		outw(HIWORD(ui_Timervalue2),
2049			devpriv->iobase + APCI3120_TIMER_VALUE);
2050		// timer2 in Timer mode enabled
2051		devpriv->b_Timer2Mode = APCI3120_TIMER;
2052
2053	} else			// Initialize Watch dog
2054	{
2055
2056		//Set the Timer 2 in mode 5(Watchdog)
2057
2058		devpriv->b_TimerSelectMode =
2059			(devpriv->
2060			b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_5;
2061		outb(devpriv->b_TimerSelectMode,
2062			devpriv->iobase + APCI3120_TIMER_CRT1);
2063
2064		//Configure the timer 2 for writing the LOW WORD of timer is Delay value
2065		//You must make a b_tmp variable with DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
2066		//you can set the digital output and configure the timer 2,and if you don't make this, digital output
2067		//are erase (Set to 0)
2068
2069		//Writing LOW WORD
2070		b_Tmp = ((devpriv->
2071				b_DigitalOutputRegister) & 0xF0) |
2072			APCI3120_SELECT_TIMER_2_LOW_WORD;
2073		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2074		outw(LOWORD(ui_Timervalue2),
2075			devpriv->iobase + APCI3120_TIMER_VALUE);
2076
2077		//Writing HIGH WORD
2078		b_Tmp = ((devpriv->
2079				b_DigitalOutputRegister) & 0xF0) |
2080			APCI3120_SELECT_TIMER_2_HIGH_WORD;
2081		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2082
2083		outw(HIWORD(ui_Timervalue2),
2084			devpriv->iobase + APCI3120_TIMER_VALUE);
2085		//watchdog enabled
2086		devpriv->b_Timer2Mode = APCI3120_WATCHDOG;
2087
2088	}
2089
2090	return insn->n;
2091
2092}
2093
2094/*
2095+----------------------------------------------------------------------------+
2096| Function name     :int i_APCI3120_InsnWriteTimer(struct comedi_device *dev,           |
2097|                    struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data)  |
2098|                                            						         |
2099+----------------------------------------------------------------------------+
2100| Task              :    To start and stop the timer		                 |
2101+----------------------------------------------------------------------------+
2102| Input Parameters  : struct comedi_device *dev									 |
2103|                     struct comedi_subdevice *s									 |
2104|                     struct comedi_insn *insn                                      |
2105|                     unsigned int *data                                         |
2106|                                                                            |
2107|				data[0] = 1 (start)                                  |
2108|				data[0] = 0 (stop )                                  |
2109|	 			data[0] = 2  (write new value)                       |
2110|	   			data[1]= new value                                   |
2111|                                                                            |
2112|    				devpriv->b_Timer2Mode =  0 DISABLE                   |
2113|	                     					 1 Timer                     |
2114|					 					 2 Watch dog			     |
2115|                                                 					         |
2116+----------------------------------------------------------------------------+
2117| Return Value      :              					                         |
2118|                    													     |
2119+----------------------------------------------------------------------------+
2120*/
2121
2122int i_APCI3120_InsnWriteTimer(struct comedi_device * dev, struct comedi_subdevice * s,
2123	struct comedi_insn * insn, unsigned int * data)
2124{
2125
2126	UINT ui_Timervalue2 = 0;
2127	unsigned short us_TmpValue;
2128	unsigned char b_Tmp;
2129
2130	if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
2131		&& (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
2132		comedi_error(dev, "\nwrite:timer2  not configured ");
2133		return -EINVAL;
2134	}
2135
2136	if (data[0] == 2)	// write new value
2137	{
2138		if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
2139			comedi_error(dev,
2140				"write :timer2  not configured  in TIMER MODE");
2141			return -EINVAL;
2142		}
2143
2144		if (data[1])
2145			ui_Timervalue2 = data[1];
2146		else
2147			ui_Timervalue2 = 0;
2148	}
2149
2150	//this_board->i_hwdrv_InsnWriteTimer(dev,data[0],ui_Timervalue2);
2151
2152	switch (data[0]) {
2153	case APCI3120_START:
2154
2155		// Reset FC_TIMER BIT
2156		inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2157		if (devpriv->b_Timer2Mode == APCI3120_TIMER)	//start timer
2158		{
2159			//Enable Timer
2160			devpriv->b_ModeSelectRegister =
2161				devpriv->b_ModeSelectRegister & 0x0B;
2162		} else		//start watch dog
2163		{
2164			//Enable WatchDog
2165			devpriv->b_ModeSelectRegister =
2166				(devpriv->
2167				b_ModeSelectRegister & 0x0B) |
2168				APCI3120_ENABLE_WATCHDOG;
2169		}
2170
2171		//enable disable interrupt
2172		if ((devpriv->b_Timer2Interrupt) == APCI3120_ENABLE) {
2173
2174			devpriv->b_ModeSelectRegister =
2175				devpriv->
2176				b_ModeSelectRegister |
2177				APCI3120_ENABLE_TIMER_INT;
2178			// save the task structure to pass info to user
2179			devpriv->tsk_Current = current;
2180		} else {
2181
2182			devpriv->b_ModeSelectRegister =
2183				devpriv->
2184				b_ModeSelectRegister &
2185				APCI3120_DISABLE_TIMER_INT;
2186		}
2187		outb(devpriv->b_ModeSelectRegister,
2188			devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
2189
2190		if (devpriv->b_Timer2Mode == APCI3120_TIMER)	//start timer
2191		{
2192			//For Timer mode is  Gate2 must be activated   **timer started
2193			devpriv->us_OutputRegister =
2194				devpriv->
2195				us_OutputRegister | APCI3120_ENABLE_TIMER2;
2196			outw(devpriv->us_OutputRegister,
2197				devpriv->iobase + APCI3120_WR_ADDRESS);
2198		}
2199
2200		break;
2201
2202	case APCI3120_STOP:
2203		if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
2204			//Disable timer
2205			devpriv->b_ModeSelectRegister =
2206				devpriv->
2207				b_ModeSelectRegister &
2208				APCI3120_DISABLE_TIMER_COUNTER;
2209		} else {
2210			//Disable WatchDog
2211			devpriv->b_ModeSelectRegister =
2212				devpriv->
2213				b_ModeSelectRegister &
2214				APCI3120_DISABLE_WATCHDOG;
2215		}
2216		// Disable timer interrupt
2217		devpriv->b_ModeSelectRegister =
2218			devpriv->
2219			b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT;
2220
2221		// Write above states  to register
2222		outb(devpriv->b_ModeSelectRegister,
2223			devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
2224
2225		// Reset Gate 2
2226		devpriv->us_OutputRegister =
2227			devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER_INT;
2228		outw(devpriv->us_OutputRegister,
2229			devpriv->iobase + APCI3120_WR_ADDRESS);
2230
2231		// Reset FC_TIMER BIT
2232		inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2233
2234		// Disable timer
2235		//devpriv->b_Timer2Mode=APCI3120_DISABLE;
2236
2237		break;
2238
2239	case 2:		//write new value to Timer
2240		if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
2241			comedi_error(dev,
2242				"write :timer2  not configured  in TIMER MODE");
2243			return -EINVAL;
2244		}
2245		// ui_Timervalue2=data[1]; // passed as argument
2246		us_TmpValue =
2247			(unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
2248
2249		//EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001
2250		// and calculate the time value to set in the timer
2251		if ((us_TmpValue & 0x00B0) == 0x00B0
2252			|| !strcmp(this_board->pc_DriverName, "apci3001")) {
2253			//Calculate the time value to set in the timer
2254			ui_Timervalue2 = ui_Timervalue2 / 50;
2255		} else {
2256			//Calculate the time value to set in the timer
2257			ui_Timervalue2 = ui_Timervalue2 / 70;
2258		}
2259		//Writing LOW WORD
2260		b_Tmp = ((devpriv->
2261				b_DigitalOutputRegister) & 0xF0) |
2262			APCI3120_SELECT_TIMER_2_LOW_WORD;
2263		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2264
2265		outw(LOWORD(ui_Timervalue2),
2266			devpriv->iobase + APCI3120_TIMER_VALUE);
2267
2268		//Writing HIGH WORD
2269		b_Tmp = ((devpriv->
2270				b_DigitalOutputRegister) & 0xF0) |
2271			APCI3120_SELECT_TIMER_2_HIGH_WORD;
2272		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2273
2274		outw(HIWORD(ui_Timervalue2),
2275			devpriv->iobase + APCI3120_TIMER_VALUE);
2276
2277		break;
2278	default:
2279		return -EINVAL;	// Not a valid input
2280	}
2281
2282	return insn->n;
2283}
2284
2285/*
2286+----------------------------------------------------------------------------+
2287| Function name     : int i_APCI3120_InsnReadTimer(struct comedi_device *dev,           |
2288|		struct comedi_subdevice *s,struct comedi_insn *insn, unsigned int *data) 		 |
2289|                                        									 |
2290|                                            						         |
2291+----------------------------------------------------------------------------+
2292| Task              : read the Timer value 				                 	 |
2293+----------------------------------------------------------------------------+
2294| Input Parameters  : 	struct comedi_device *dev									 |
2295|                     struct comedi_subdevice *s									 |
2296|                     struct comedi_insn *insn                                      |
2297|                     unsigned int *data 										 |
2298|                     														 |
2299+----------------------------------------------------------------------------+
2300| Return Value      :   													 |
2301|			for Timer:	data[0]= Timer constant						 |
2302|																	 |
2303|         		for watchdog: data[0]=0 (still running)                  |
2304|	               			  data[0]=1  (run down)            			 |
2305|                    													     |
2306+----------------------------------------------------------------------------+
2307*/
2308int i_APCI3120_InsnReadTimer(struct comedi_device * dev, struct comedi_subdevice * s,
2309	struct comedi_insn * insn, unsigned int * data)
2310{
2311	unsigned char b_Tmp;
2312	unsigned short us_TmpValue, us_TmpValue_2, us_StatusValue;
2313
2314	if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
2315		&& (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
2316		comedi_error(dev, "\nread:timer2  not configured ");
2317	}
2318
2319	//this_board->i_hwdrv_InsnReadTimer(dev,data);
2320	if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
2321
2322		//Read the LOW WORD of Timer 2 register
2323		b_Tmp = ((devpriv->
2324				b_DigitalOutputRegister) & 0xF0) |
2325			APCI3120_SELECT_TIMER_2_LOW_WORD;
2326		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2327
2328		us_TmpValue = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
2329
2330		//Read the HIGH WORD of Timer 2 register
2331		b_Tmp = ((devpriv->
2332				b_DigitalOutputRegister) & 0xF0) |
2333			APCI3120_SELECT_TIMER_2_HIGH_WORD;
2334		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2335
2336		us_TmpValue_2 = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
2337
2338		// combining both words
2339		data[0] = (UINT) ((us_TmpValue) | ((us_TmpValue_2) << 16));
2340
2341	} else			// Read watch dog status
2342	{
2343
2344		us_StatusValue = inw(devpriv->iobase + APCI3120_RD_STATUS);
2345		us_StatusValue =
2346			((us_StatusValue & APCI3120_FC_TIMER) >> 12) & 1;
2347		if (us_StatusValue == 1) {
2348			// RESET FC_TIMER BIT
2349			inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2350		}
2351		data[0] = us_StatusValue;	// when data[0] = 1 then the watch dog has rundown
2352	}
2353	return insn->n;
2354}
2355
2356/*
2357+----------------------------------------------------------------------------+
2358|                           DIGITAL INPUT SUBDEVICE   		                 |
2359+----------------------------------------------------------------------------+
2360*/
2361
2362/*
2363+----------------------------------------------------------------------------+
2364| Function name     :int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev,     |
2365|			struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data)   |
2366|                                        									 |
2367|                                            						         |
2368+----------------------------------------------------------------------------+
2369| Task              : Reads the value of the specified  Digital input channel|
2370|                     										                 |
2371+----------------------------------------------------------------------------+
2372| Input Parameters  : struct comedi_device *dev									 |
2373|                     struct comedi_subdevice *s									 |
2374|                     struct comedi_insn *insn                                      |
2375|                     unsigned int *data 										 |
2376+----------------------------------------------------------------------------+
2377| Return Value      :              					                         |
2378|                    													     |
2379+----------------------------------------------------------------------------+
2380*/
2381
2382int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev,
2383				    struct comedi_subdevice *s,
2384				    struct comedi_insn *insn,
2385				    unsigned int *data)
2386{
2387	UINT ui_Chan, ui_TmpValue;
2388
2389	ui_Chan = CR_CHAN(insn->chanspec);	// channel specified
2390
2391	//this_board->i_hwdrv_InsnReadDigitalInput(dev,ui_Chan,data);
2392	if (ui_Chan >= 0 && ui_Chan <= 3) {
2393		ui_TmpValue = (UINT) inw(devpriv->iobase + APCI3120_RD_STATUS);
2394
2395		//      since only 1 channel reqd  to bring it to last bit it is rotated
2396		//  8 +(chan - 1) times then ANDed with 1 for last bit.
2397		*data = (ui_TmpValue >> (ui_Chan + 8)) & 1;
2398		//return 0;
2399	} else {
2400		//      comedi_error(dev," chan spec wrong");
2401		return -EINVAL;	// "sorry channel spec wrong "
2402	}
2403	return insn->n;
2404
2405}
2406
2407/*
2408+----------------------------------------------------------------------------+
2409| Function name     :int i_APCI3120_InsnBitsDigitalInput(struct comedi_device *dev, |
2410|struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data)                      |
2411|                                        									 |
2412+----------------------------------------------------------------------------+
2413| Task              : Reads the value of the Digital input Port i.e.4channels|
2414|   value is returned in data[0]											 |
2415|                     										                 |
2416+----------------------------------------------------------------------------+
2417| Input Parameters  : struct comedi_device *dev									 |
2418|                     struct comedi_subdevice *s									 |
2419|                     struct comedi_insn *insn                                      |
2420|                     unsigned int *data 										 |
2421+----------------------------------------------------------------------------+
2422| Return Value      :              					                         |
2423|                    													     |
2424+----------------------------------------------------------------------------+
2425*/
2426int i_APCI3120_InsnBitsDigitalInput(struct comedi_device * dev, struct comedi_subdevice * s,
2427	struct comedi_insn * insn, unsigned int * data)
2428{
2429	UINT ui_TmpValue;
2430	ui_TmpValue = (UINT) inw(devpriv->iobase + APCI3120_RD_STATUS);
2431	/*****	state of 4 channels  in the 11, 10, 9, 8   bits of status reg
2432			rotated right 8 times to bring them to last four bits
2433			ANDed with oxf for  value.
2434	*****/
2435
2436	*data = (ui_TmpValue >> 8) & 0xf;
2437	//this_board->i_hwdrv_InsnBitsDigitalInput(dev,data);
2438	return insn->n;
2439}
2440
2441/*
2442+----------------------------------------------------------------------------+
2443|                           DIGITAL OUTPUT SUBDEVICE   		                 |
2444+----------------------------------------------------------------------------+
2445*/
2446/*
2447+----------------------------------------------------------------------------+
2448| Function name     :int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device    |
2449| *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)				 |
2450|                                            						         |
2451+----------------------------------------------------------------------------+
2452| Task              :Configure the output memory ON or OFF				     |
2453|                     										                 |
2454+----------------------------------------------------------------------------+
2455| Input Parameters  :struct comedi_device *dev									 	 |
2456|                     struct comedi_subdevice *s									 |
2457|                     struct comedi_insn *insn                                      |
2458|                     unsigned int *data 										 |
2459+----------------------------------------------------------------------------+
2460| Return Value      :              					                         |
2461|                    													     |
2462+----------------------------------------------------------------------------+
2463*/
2464
2465int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device * dev,
2466	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
2467{
2468
2469	if ((data[0] != 0) && (data[0] != 1)) {
2470		comedi_error(dev,
2471			"Not a valid Data !!! ,Data should be 1 or 0\n");
2472		return -EINVAL;
2473	}
2474	if (data[0]) {
2475		devpriv->b_OutputMemoryStatus = APCI3120_ENABLE;
2476
2477	} else {
2478		devpriv->b_OutputMemoryStatus = APCI3120_DISABLE;
2479		devpriv->b_DigitalOutputRegister = 0;
2480	}
2481	if (!devpriv->b_OutputMemoryStatus) {
2482		ui_Temp = 0;
2483
2484	}			//if(!devpriv->b_OutputMemoryStatus )
2485
2486	return insn->n;
2487}
2488
2489/*
2490+----------------------------------------------------------------------------+
2491| Function name     :int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device *dev,    |
2492|		struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) 		 |
2493|                                        									 |
2494+----------------------------------------------------------------------------+
2495| Task              : write diatal output port							     |
2496|                     										                 |
2497+----------------------------------------------------------------------------+
2498| Input Parameters  : struct comedi_device *dev									 |
2499|                     struct comedi_subdevice *s									 |
2500|                     struct comedi_insn *insn                                      |
2501|                     unsigned int *data 										 |
2502                      data[0]     Value to be written
2503                      data[1]    :1 Set digital o/p ON
2504                      data[1]     2 Set digital o/p OFF with memory ON
2505+----------------------------------------------------------------------------+
2506| Return Value      :              					                         |
2507|                    													     |
2508+----------------------------------------------------------------------------+
2509*/
2510
2511int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device * dev,
2512				     struct comedi_subdevice *s,
2513				     struct comedi_insn *insn,
2514				     unsigned int *data)
2515{
2516	if ((data[0] > this_board->i_DoMaxdata) || (data[0] < 0)) {
2517
2518		comedi_error(dev, "Data is not valid !!! \n");
2519		return -EINVAL;
2520	}
2521
2522	switch (data[1]) {
2523	case 1:
2524		data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister;
2525		break;
2526
2527	case 2:
2528		data[0] = data[0];
2529		break;
2530	default:
2531		printk("\nThe parameter passed is in error \n");
2532		return -EINVAL;
2533	}			// switch(data[1])
2534	outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
2535
2536	devpriv->b_DigitalOutputRegister = data[0] & 0xF0;
2537
2538	return insn->n;
2539
2540}
2541
2542/*
2543+----------------------------------------------------------------------------+
2544| Function name     :int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev,|
2545|struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) 			             |
2546|                                            						         |
2547+----------------------------------------------------------------------------+
2548| Task              : Write digiatl output								     |
2549|                     										                 |
2550+----------------------------------------------------------------------------+
2551| Input Parameters  : struct comedi_device *dev								 	 |
2552|                     struct comedi_subdevice *s									 |
2553|                     struct comedi_insn *insn                                      |
2554|                     unsigned int *data 										 |
2555                      data[0]     Value to be written
2556                      data[1]    :1 Set digital o/p ON
2557                      data[1]     2 Set digital o/p OFF with memory ON
2558+----------------------------------------------------------------------------+
2559| Return Value      :              					                         |
2560|                    													     |
2561+----------------------------------------------------------------------------+
2562*/
2563
2564int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev,
2565				      struct comedi_subdevice *s,
2566				      struct comedi_insn *insn,
2567				      unsigned int *data)
2568{
2569
2570	UINT ui_Temp1;
2571
2572	UINT ui_NoOfChannel = CR_CHAN(insn->chanspec);	// get the channel
2573
2574	if ((data[0] != 0) && (data[0] != 1)) {
2575		comedi_error(dev,
2576			"Not a valid Data !!! ,Data should be 1 or 0\n");
2577		return -EINVAL;
2578	}
2579	if ((ui_NoOfChannel > (this_board->i_NbrDoChannel - 1))
2580		|| (ui_NoOfChannel < 0)) {
2581		comedi_error(dev,
2582			"This board doesn't have specified channel !!! \n");
2583		return -EINVAL;
2584	}
2585
2586	switch (data[1]) {
2587	case 1:
2588		data[0] = (data[0] << ui_NoOfChannel);
2589//ES05                   data[0]=(data[0]<<4)|ui_Temp;
2590		data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister;
2591		break;
2592
2593	case 2:
2594		data[0] = ~data[0] & 0x1;
2595		ui_Temp1 = 1;
2596		ui_Temp1 = ui_Temp1 << ui_NoOfChannel;
2597		ui_Temp1 = ui_Temp1 << 4;
2598//ES05                   ui_Temp=ui_Temp|ui_Temp1;
2599		devpriv->b_DigitalOutputRegister =
2600			devpriv->b_DigitalOutputRegister | ui_Temp1;
2601
2602		data[0] = (data[0] << ui_NoOfChannel) ^ 0xf;
2603		data[0] = data[0] << 4;
2604//ES05                   data[0]=data[0]& ui_Temp;
2605		data[0] = data[0] & devpriv->b_DigitalOutputRegister;
2606		break;
2607	default:
2608		printk("\nThe parameter passed is in error \n");
2609		return -EINVAL;
2610	}			// switch(data[1])
2611	outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
2612
2613//ES05        ui_Temp=data[0] & 0xf0;
2614	devpriv->b_DigitalOutputRegister = data[0] & 0xf0;
2615	return (insn->n);
2616
2617}
2618
2619/*
2620+----------------------------------------------------------------------------+
2621|                            ANALOG OUTPUT SUBDEVICE                         |
2622+----------------------------------------------------------------------------+
2623*/
2624
2625/*
2626+----------------------------------------------------------------------------+
2627| Function name     :int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,|
2628|struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data)			             |
2629|                                        									 |
2630+----------------------------------------------------------------------------+
2631| Task              : Write  analog output   							     |
2632|                     										                 |
2633+----------------------------------------------------------------------------+
2634| Input Parameters  : struct comedi_device *dev									 |
2635|                     struct comedi_subdevice *s									 |
2636|                     struct comedi_insn *insn                                      |
2637|                     unsigned int *data  										 |
2638+----------------------------------------------------------------------------+
2639| Return Value      :              					                         |
2640|                    													     |
2641+----------------------------------------------------------------------------+
2642*/
2643
2644int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,
2645				     struct comedi_subdevice *s,
2646				     struct comedi_insn *insn,
2647				     unsigned int *data)
2648{
2649	UINT ui_Range, ui_Channel;
2650	unsigned short us_TmpValue;
2651
2652	ui_Range = CR_RANGE(insn->chanspec);
2653	ui_Channel = CR_CHAN(insn->chanspec);
2654
2655	//this_board->i_hwdrv_InsnWriteAnalogOutput(dev, ui_Range, ui_Channel,data[0]);
2656	if (ui_Range)		// if 1 then unipolar
2657	{
2658
2659		if (data[0] != 0)
2660			data[0] =
2661				((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
2662					13) | (data[0] + 8191));
2663		else
2664			data[0] =
2665				((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
2666					13) | 8192);
2667
2668	} else			// if 0 then   bipolar
2669	{
2670		data[0] =
2671			((((ui_Channel & 0x03) << 14) & 0xC000) | (0 << 13) |
2672			data[0]);
2673
2674	}
2675
2676	//out put n values at the given channel.
2677	// rt_printk("\nwaiting for DA_READY BIT");
2678	do			//Waiting of DA_READY BIT
2679	{
2680		us_TmpValue =
2681			((unsigned short) inw(devpriv->iobase +
2682				APCI3120_RD_STATUS)) & 0x0001;
2683	} while (us_TmpValue != 0x0001);
2684
2685	if (ui_Channel <= 3)
2686		// for channel 0-3 out at  the register 1 (wrDac1-8)
2687		// data[i] typecasted to ushort since  word write is to be done
2688		outw((unsigned short) data[0],
2689			devpriv->iobase + APCI3120_ANALOG_OUTPUT_1);
2690	else
2691		// for channel 4-7 out at the register 2 (wrDac5-8)
2692		//data[i] typecasted to ushort since  word write is to be done
2693		outw((unsigned short) data[0],
2694			devpriv->iobase + APCI3120_ANALOG_OUTPUT_2);
2695
2696	return insn->n;
2697}
2698