hwdrv_apci3120.c revision c995fe9475e062bab6f5a45ed28cd2d3d955ef43
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(comedi_device *dev,|
61|  comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)					 |
62|                                            						         |
63+----------------------------------------------------------------------------+
64| Task              : Calls card specific function  					     |
65|                     										                 |
66+----------------------------------------------------------------------------+
67| Input Parameters  : comedi_device *dev									 |
68|                     comedi_subdevice *s									 |
69|                     comedi_insn *insn                                      |
70|                     lsampl_t *data      					         		 |
71+----------------------------------------------------------------------------+
72| Return Value      :              					                         |
73|                    													     |
74+----------------------------------------------------------------------------+
75*/
76
77int i_APCI3120_InsnConfigAnalogInput(comedi_device * dev, comedi_subdevice * s,
78	comedi_insn * insn, lsampl_t * 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(comedi_device *dev,  |
128|			comedi_subdevice *s,comedi_insn *insn, lsampl_t *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  : comedi_device *dev									 |
139|                     comedi_subdevice *s									 |
140|                     comedi_insn *insn                                      |
141|                     lsampl_t *data     									 |
142+----------------------------------------------------------------------------+
143| Return Value      :              					                         |
144|                    													     |
145+----------------------------------------------------------------------------+
146*/
147
148int i_APCI3120_InsnReadAnalogInput(comedi_device * dev, comedi_subdevice * s,
149	comedi_insn * insn, lsampl_t * data)
150{
151	USHORT us_ConvertTiming, us_TmpValue, i;
152	BYTE 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 = (USHORT) (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			(USHORT) 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 = (USHORT) 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				(USHORT) 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(comedi_device *dev,|
397| 											     comedi_subdevice *s)|
398|                                        									 |
399+----------------------------------------------------------------------------+
400| Task              : Stops Cyclic acquisition  						     |
401|                     										                 |
402+----------------------------------------------------------------------------+
403| Input Parameters  : comedi_device *dev									 |
404|                     comedi_subdevice *s									 |
405|                                                 					         |
406+----------------------------------------------------------------------------+
407| Return Value      :0              					                     |
408|                    													     |
409+----------------------------------------------------------------------------+
410*/
411
412int i_APCI3120_StopCyclicAcquisition(comedi_device * dev, 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(comedi_device *dev|
463|			,comedi_subdevice *s,comedi_cmd *cmd)					 |
464|                                        									 |
465+----------------------------------------------------------------------------+
466| Task              : Test validity for a command for cyclic anlog input     |
467|                       acquisition  						     			 |
468|                     										                 |
469+----------------------------------------------------------------------------+
470| Input Parameters  : comedi_device *dev									 |
471|                     comedi_subdevice *s									 |
472|                     comedi_cmd *cmd              					         |
473+----------------------------------------------------------------------------+
474| Return Value      :0              					                     |
475|                    													     |
476+----------------------------------------------------------------------------+
477*/
478
479int i_APCI3120_CommandTestAnalogInput(comedi_device * dev, comedi_subdevice * s,
480	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(comedi_device *dev,  |
620|												comedi_subdevice *s) |
621|                                        									 |
622+----------------------------------------------------------------------------+
623| Task              : Does asynchronous acquisition                          |
624|                     Determines the mode 1 or 2.						     |
625|                     										                 |
626+----------------------------------------------------------------------------+
627| Input Parameters  : comedi_device *dev									 |
628|                     comedi_subdevice *s									 |
629|                     														 |
630+----------------------------------------------------------------------------+
631| Return Value      :              					                         |
632|                    													     |
633+----------------------------------------------------------------------------+
634*/
635
636int i_APCI3120_CommandAnalogInput(comedi_device * dev, comedi_subdevice * s)
637{
638	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|		 	   comedi_device * dev,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, comedi_device * dev,
711	comedi_subdevice * s)
712{
713	BYTE 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	USHORT 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 = (USHORT) inw(dev->iobase + APCI3120_RD_STATUS);
799/*** EL241003 : add this section in comment because floats must not be used
800	 if((us_TmpValue & 0x00B0)==0x00B0)
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(((USHORT) 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(((USHORT) 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(((USHORT) 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(comedi_device *dev)               |
1206|                                        									 |
1207|                                            						         |
1208+----------------------------------------------------------------------------+
1209| Task              : Hardware reset function   						     |
1210|                     										                 |
1211+----------------------------------------------------------------------------+
1212| Input Parameters  : 	comedi_device *dev									 |
1213|                     														 |
1214|                                                 					         |
1215+----------------------------------------------------------------------------+
1216| Return Value      :              					                         |
1217|                    													     |
1218+----------------------------------------------------------------------------+
1219*/
1220
1221int i_APCI3120_Reset(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(comedi_device * dev,   |
1278|                     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  : comedi_device * dev									 |
1289|                     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(comedi_device * dev, 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(comedi_device * dev)    |
1348|                                        									 |
1349|                                            						         |
1350+----------------------------------------------------------------------------+
1351| Task              : 	Enable the external trigger						     |
1352|                     										                 |
1353+----------------------------------------------------------------------------+
1354| Input Parameters  : 	comedi_device * dev									 |
1355|                     														 |
1356|                                                 					         |
1357+----------------------------------------------------------------------------+
1358| Return Value      :      0        					                         |
1359|                    													     |
1360+----------------------------------------------------------------------------+
1361*/
1362
1363int i_APCI3120_ExttrigEnable(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(comedi_device * dev)   |
1374|                                        									 |
1375+----------------------------------------------------------------------------+
1376| Task              : 	Disables the external trigger					     |
1377|                     										                 |
1378+----------------------------------------------------------------------------+
1379| Input Parameters  : 	comedi_device * dev									 |
1380|                     														 |
1381|                                                 					         |
1382+----------------------------------------------------------------------------+
1383| Return Value      :    0          					                         |
1384|                    													     |
1385+----------------------------------------------------------------------------+
1386*/
1387
1388int i_APCI3120_ExttrigDisable(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	comedi_device *dev = d;
1425	USHORT int_daq;
1426
1427	unsigned int int_amcc, ui_Check, i;
1428	USHORT us_TmpValue;
1429	BYTE b_DummyRead;
1430
1431	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(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  : comedi_device *dev									 |
1625|                     														 |
1626|                                                 					         |
1627+----------------------------------------------------------------------------+
1628| Return Value      : 0            					                         |
1629|                    													     |
1630+----------------------------------------------------------------------------+
1631*/
1632
1633/*int i_APCI3120_InterruptHandleEos(comedi_device *dev)
1634{
1635       int n_chan,i;
1636       sampl_t *data;
1637       comedi_subdevice *s=dev->subdevices+0;
1638       comedi_async *async = s->async;
1639       data=async->data+async->buf_int_ptr;//new samples added from here onwards
1640       n_chan=devpriv->ui_AiNbrofChannels;
1641
1642       for(i=0;i<n_chan;i++)
1643         {
1644           data[i]=inw(dev->iobase+0);
1645         }
1646       async->buf_int_count+=n_chan*sizeof(sampl_t);
1647       async->buf_int_ptr+=n_chan*sizeof(sampl_t);
1648       comedi_eos(dev,s);
1649       if (s->async->buf_int_ptr>=s->async->data_len) //  for buffer rool over
1650		         {
1651*//* buffer rollover */
1652/*	        s->async->buf_int_ptr=0;
1653		comedi_eobuf(dev,s);
1654         }
1655 	return 0;
1656}*/
1657int i_APCI3120_InterruptHandleEos(comedi_device * dev)
1658{
1659	int n_chan, i;
1660	comedi_subdevice *s = dev->subdevices + 0;
1661	int err = 1;
1662
1663	n_chan = devpriv->ui_AiNbrofChannels;
1664
1665	s->async->events = 0;
1666
1667	for (i = 0; i < n_chan; i++)
1668		err &= comedi_buf_put(s->async, inw(dev->iobase + 0));
1669
1670	s->async->events |= COMEDI_CB_EOS;
1671
1672	if (err == 0)
1673		s->async->events |= COMEDI_CB_OVERFLOW;
1674
1675	comedi_event(dev, s);
1676
1677	return 0;
1678}
1679
1680/*
1681+----------------------------------------------------------------------------+
1682| Function name     : void v_APCI3120_InterruptDma(int irq, void *d) 									 |
1683|                                        									 |
1684+----------------------------------------------------------------------------+
1685| Task              : This is a handler for the DMA interrupt                |
1686|			  This function copies the data to Comedi Buffer.        |
1687|			  For continuous DMA it reinitializes the DMA operation. |
1688|			  For single mode DMA it stop the acquisition.           |
1689|													     			 |
1690+----------------------------------------------------------------------------+
1691| Input Parameters  : int irq, void *d				 |
1692|                     														 |
1693+----------------------------------------------------------------------------+
1694| Return Value      :  void        					                         |
1695|                    													     |
1696+----------------------------------------------------------------------------+
1697*/
1698
1699void v_APCI3120_InterruptDma(int irq, void *d)
1700{
1701	comedi_device *dev = d;
1702	comedi_subdevice *s = dev->subdevices + 0;
1703	unsigned int next_dma_buf, samplesinbuf;
1704	unsigned long low_word, high_word, var;
1705
1706	UINT ui_Tmp;
1707	samplesinbuf =
1708		devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer] -
1709		inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_MWTC);
1710
1711	if (samplesinbuf <
1712		devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer]) {
1713		comedi_error(dev, "Interrupted DMA transfer!");
1714	}
1715	if (samplesinbuf & 1) {
1716		comedi_error(dev, "Odd count of bytes in DMA ring!");
1717		i_APCI3120_StopCyclicAcquisition(dev, s);
1718		devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1719
1720		return;
1721	}
1722	samplesinbuf = samplesinbuf >> 1;	// number of received samples
1723	if (devpriv->b_DmaDoubleBuffer) {
1724		// switch DMA buffers if is used double buffering
1725		next_dma_buf = 1 - devpriv->ui_DmaActualBuffer;
1726
1727		ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1728		outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
1729
1730		// changed  since 16 bit interface for add on
1731		outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1732		outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1733			devpriv->i_IobaseAddon + 2);
1734		outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1735		outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2);	// 0x1000 is out putted in windows driver
1736
1737		var = devpriv->ul_DmaBufferHw[next_dma_buf];
1738		low_word = var & 0xffff;
1739		var = devpriv->ul_DmaBufferHw[next_dma_buf];
1740		high_word = var / 65536;
1741
1742		/* DMA Start Adress Low */
1743		outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1744		outw(low_word, devpriv->i_IobaseAddon + 2);
1745
1746		/* DMA Start Adress High */
1747		outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1748		outw(high_word, devpriv->i_IobaseAddon + 2);
1749
1750		var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
1751		low_word = var & 0xffff;
1752		var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
1753		high_word = var / 65536;
1754
1755		/* Nbr of acquisition LOW */
1756		outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1757		outw(low_word, devpriv->i_IobaseAddon + 2);
1758
1759		/* Nbr of acquisition HIGH */
1760		outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1761		outw(high_word, devpriv->i_IobaseAddon + 2);
1762
1763		// To configure A2P FIFO
1764		// ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1765		// AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1766		outw(3, devpriv->i_IobaseAddon + 4);
1767		//initialise end of dma interrupt  AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI)
1768		outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1769				APCI3120_ENABLE_WRITE_TC_INT),
1770			devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1771
1772	}
1773/*UPDATE-0.7.57->0.7.68
1774	ptr=(sampl_t *)devpriv->ul_DmaBufferVirtual[devpriv->ui_DmaActualBuffer];
1775
1776
1777	// if there is not enough space left in the buffer to copy all data contained in the DMABufferVirtual
1778	if(s->async->buf_int_ptr+samplesinbuf*sizeof(sampl_t)>=devpriv->ui_AiDataLength)
1779	{
1780		m=(devpriv->ui_AiDataLength-s->async->buf_int_ptr)/sizeof(sampl_t);
1781		v_APCI3120_InterruptDmaMoveBlock16bit(dev,s,(void *)ptr,((void *)(devpriv->AiData))+s->async->buf_int_ptr,m);
1782		s->async->buf_int_count+=m*sizeof(sampl_t);
1783		ptr+=m*sizeof(sampl_t);
1784                samplesinbuf-=m;
1785		s->async->buf_int_ptr=0;
1786		comedi_eobuf(dev,s);
1787	}
1788
1789	if (samplesinbuf)
1790	{
1791	        v_APCI3120_InterruptDmaMoveBlock16bit(dev,s,(void *)ptr,((void *)(devpriv->AiData))+s->async->buf_int_ptr,samplesinbuf);
1792
1793		s->async->buf_int_count+=samplesinbuf*sizeof(sampl_t);
1794		s->async->buf_int_ptr+=samplesinbuf*sizeof(sampl_t);
1795		if (!(devpriv->ui_AiFlags & TRIG_WAKE_EOS))
1796		{
1797			comedi_bufcheck(dev,s);
1798                }
1799	}
1800	if (!devpriv->b_AiContinuous)
1801	if ( devpriv->ui_AiActualScan>=devpriv->ui_AiNbrofScans )
1802	{
1803	    // all data sampled
1804	    i_APCI3120_StopCyclicAcquisition(dev,s);
1805            devpriv->b_AiCyclicAcquisition=APCI3120_DISABLE;
1806	    //DPRINTK("\n Single DMA completed..\n");
1807		comedi_done(dev,s);
1808            	return;
1809	}
1810*/
1811	if (samplesinbuf) {
1812		v_APCI3120_InterruptDmaMoveBlock16bit(dev, s,
1813			devpriv->ul_DmaBufferVirtual[devpriv->
1814				ui_DmaActualBuffer], samplesinbuf);
1815
1816		if (!(devpriv->ui_AiFlags & TRIG_WAKE_EOS)) {
1817			s->async->events |= COMEDI_CB_EOS;
1818			comedi_event(dev, s);
1819		}
1820	}
1821	if (!devpriv->b_AiContinuous)
1822		if (devpriv->ui_AiActualScan >= devpriv->ui_AiNbrofScans) {
1823			// all data sampled
1824			i_APCI3120_StopCyclicAcquisition(dev, s);
1825			devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1826			s->async->events |= COMEDI_CB_EOA;
1827			comedi_event(dev, s);
1828			return;
1829		}
1830
1831	if (devpriv->b_DmaDoubleBuffer) {	// switch dma buffers
1832		devpriv->ui_DmaActualBuffer = 1 - devpriv->ui_DmaActualBuffer;
1833	} else {
1834		// restart DMA if is not used double buffering
1835		//ADDED REINITIALISE THE DMA
1836		ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1837		outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
1838
1839		// changed  since 16 bit interface for add on
1840		outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1841		outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1842			devpriv->i_IobaseAddon + 2);
1843		outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1844		outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2);	//
1845		// A2P FIFO MANAGEMENT
1846		// A2P fifo reset  & transfer control enable
1847		outl(APCI3120_A2P_FIFO_MANAGEMENT,
1848			devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
1849
1850		var = devpriv->ul_DmaBufferHw[0];
1851		low_word = var & 0xffff;
1852		var = devpriv->ul_DmaBufferHw[0];
1853		high_word = var / 65536;
1854		outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1855		outw(low_word, devpriv->i_IobaseAddon + 2);
1856		outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1857		outw(high_word, devpriv->i_IobaseAddon + 2);
1858
1859		var = devpriv->ui_DmaBufferUsesize[0];
1860		low_word = var & 0xffff;	//changed
1861		var = devpriv->ui_DmaBufferUsesize[0];
1862		high_word = var / 65536;
1863		outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1864		outw(low_word, devpriv->i_IobaseAddon + 2);
1865		outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1866		outw(high_word, devpriv->i_IobaseAddon + 2);
1867
1868		// To configure A2P FIFO
1869		//ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1870		// AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1871		outw(3, devpriv->i_IobaseAddon + 4);
1872		//initialise end of dma interrupt  AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI)
1873		outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1874				APCI3120_ENABLE_WRITE_TC_INT),
1875			devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1876	}
1877}
1878
1879/*
1880+----------------------------------------------------------------------------+
1881| Function name     :void v_APCI3120_InterruptDmaMoveBlock16bit(comedi_device|
1882|*dev,comedi_subdevice *s,sampl_t *dma,sampl_t *data,int n)				     |
1883|                                        									 |
1884+----------------------------------------------------------------------------+
1885| Task              : This function copies the data from DMA buffer to the   |
1886|				 Comedi buffer  									 |
1887|                     										                 |
1888+----------------------------------------------------------------------------+
1889| Input Parameters  : comedi_device *dev									 |
1890|                     comedi_subdevice *s									 |
1891|                     sampl_t *dma											 |
1892|                     sampl_t *data,int n          					         |
1893+----------------------------------------------------------------------------+
1894| Return Value      : void         					                         |
1895|                    													     |
1896+----------------------------------------------------------------------------+
1897*/
1898
1899/*void v_APCI3120_InterruptDmaMoveBlock16bit(comedi_device *dev,comedi_subdevice *s,sampl_t *dma,sampl_t *data,int n)
1900{
1901	int i,j,m;
1902
1903	j=s->async->cur_chan;
1904	m=devpriv->ui_AiActualScanPosition;
1905        for(i=0;i<n;i++)
1906	{
1907		*data=*dma;
1908   		data++; dma++;
1909		j++;
1910		if(j>=devpriv->ui_AiNbrofChannels)
1911		{
1912			m+=j;
1913			j=0;
1914			if(m>=devpriv->ui_AiScanLength)
1915			{
1916				m=0;
1917			        devpriv->ui_AiActualScan++;
1918				if (devpriv->ui_AiFlags & TRIG_WAKE_EOS)
1919;//UPDATE-0.7.57->0.7.68					comedi_eos(dev,s);
1920			}
1921		}
1922	}
1923        devpriv->ui_AiActualScanPosition=m;
1924	s->async->cur_chan=j;
1925
1926}
1927*/
1928void v_APCI3120_InterruptDmaMoveBlock16bit(comedi_device * dev,
1929	comedi_subdevice * s, sampl_t * dma_buffer, unsigned int num_samples)
1930{
1931	devpriv->ui_AiActualScan +=
1932		(s->async->cur_chan + num_samples) / devpriv->ui_AiScanLength;
1933	s->async->cur_chan += num_samples;
1934	s->async->cur_chan %= devpriv->ui_AiScanLength;
1935
1936	cfc_write_array_to_buffer(s, dma_buffer, num_samples * sizeof(sampl_t));
1937}
1938
1939/*
1940+----------------------------------------------------------------------------+
1941|                           TIMER SUBDEVICE   		                         |
1942+----------------------------------------------------------------------------+
1943*/
1944
1945/*
1946+----------------------------------------------------------------------------+
1947| Function name     :int i_APCI3120_InsnConfigTimer(comedi_device *dev,          |
1948|	comedi_subdevice *s,comedi_insn *insn,lsampl_t *data) 			     |
1949|                                        									 |
1950+----------------------------------------------------------------------------+
1951| Task              :Configure Timer 2  								     |
1952|                     										                 |
1953+----------------------------------------------------------------------------+
1954| Input Parameters  : comedi_device *dev									 |
1955|                     comedi_subdevice *s									 |
1956|                     comedi_insn *insn                                      |
1957|                     lsampl_t *data 										 |
1958|                     														 |
1959|                      data[0]= TIMER  configure as timer                    |
1960|              				 = WATCHDOG configure as watchdog				 |
1961|       			  data[1] = Timer constant							 |
1962|       			  data[2] = Timer2 interrupt (1)enable or(0) disable |
1963|                                                 					         |
1964+----------------------------------------------------------------------------+
1965| Return Value      :              					                         |
1966|                    													     |
1967+----------------------------------------------------------------------------+
1968*/
1969
1970int i_APCI3120_InsnConfigTimer(comedi_device * dev, comedi_subdevice * s,
1971	comedi_insn * insn, lsampl_t * data)
1972{
1973
1974	UINT ui_Timervalue2;
1975	USHORT us_TmpValue;
1976	BYTE b_Tmp;
1977
1978	if (!data[1])
1979		comedi_error(dev, "config:No timer constant !");
1980
1981	devpriv->b_Timer2Interrupt = (BYTE) data[2];	// save info whether to enable or disable interrupt
1982
1983	ui_Timervalue2 = data[1] / 1000;	// convert nano seconds  to u seconds
1984
1985	//this_board->i_hwdrv_InsnConfigTimer(dev, ui_Timervalue2,(BYTE)data[0]);
1986	us_TmpValue = (USHORT) inw(devpriv->iobase + APCI3120_RD_STATUS);
1987
1988	//EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001
1989	// and calculate the time value to set in the timer
1990	if ((us_TmpValue & 0x00B0) == 0x00B0
1991		|| !strcmp(this_board->pc_DriverName, "apci3001")) {
1992		//Calculate the time value to set in the timer
1993		ui_Timervalue2 = ui_Timervalue2 / 50;
1994	} else {
1995		//Calculate the time value to set in the timer
1996		ui_Timervalue2 = ui_Timervalue2 / 70;
1997	}
1998
1999	//Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0)
2000	devpriv->us_OutputRegister =
2001		devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER2;
2002	outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS);
2003
2004	// Disable TIMER Interrupt
2005	devpriv->b_ModeSelectRegister =
2006		devpriv->
2007		b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT & 0xEF;
2008
2009	// Disable Eoc and Eos Interrupts
2010	devpriv->b_ModeSelectRegister =
2011		devpriv->
2012		b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT &
2013		APCI3120_DISABLE_EOS_INT;
2014	outb(devpriv->b_ModeSelectRegister,
2015		devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
2016	if (data[0] == APCI3120_TIMER)	//initialize timer
2017	{
2018
2019		//devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister| APCI3120_ENABLE_TIMER_INT ;
2020		//outb(devpriv->b_ModeSelectRegister,devpriv->iobase+APCI3120_WRITE_MODE_SELECT);
2021
2022		//Set the Timer 2 in mode 2(Timer)
2023		devpriv->b_TimerSelectMode =
2024			(devpriv->
2025			b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_2;
2026		outb(devpriv->b_TimerSelectMode,
2027			devpriv->iobase + APCI3120_TIMER_CRT1);
2028
2029		//Configure the timer 2 for writing the LOW WORD of timer is Delay value
2030		//You must make a b_tmp variable with DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
2031		//you can set the digital output and configure the timer 2,and if you don't make this, digital output
2032		//are erase (Set to 0)
2033
2034		//Writing LOW WORD
2035		b_Tmp = ((devpriv->
2036				b_DigitalOutputRegister) & 0xF0) |
2037			APCI3120_SELECT_TIMER_2_LOW_WORD;
2038		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2039		outw(LOWORD(ui_Timervalue2),
2040			devpriv->iobase + APCI3120_TIMER_VALUE);
2041
2042		//Writing HIGH WORD
2043		b_Tmp = ((devpriv->
2044				b_DigitalOutputRegister) & 0xF0) |
2045			APCI3120_SELECT_TIMER_2_HIGH_WORD;
2046		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2047		outw(HIWORD(ui_Timervalue2),
2048			devpriv->iobase + APCI3120_TIMER_VALUE);
2049		// timer2 in Timer mode enabled
2050		devpriv->b_Timer2Mode = APCI3120_TIMER;
2051
2052	} else			// Initialize Watch dog
2053	{
2054
2055		//Set the Timer 2 in mode 5(Watchdog)
2056
2057		devpriv->b_TimerSelectMode =
2058			(devpriv->
2059			b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_5;
2060		outb(devpriv->b_TimerSelectMode,
2061			devpriv->iobase + APCI3120_TIMER_CRT1);
2062
2063		//Configure the timer 2 for writing the LOW WORD of timer is Delay value
2064		//You must make a b_tmp variable with DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
2065		//you can set the digital output and configure the timer 2,and if you don't make this, digital output
2066		//are erase (Set to 0)
2067
2068		//Writing LOW WORD
2069		b_Tmp = ((devpriv->
2070				b_DigitalOutputRegister) & 0xF0) |
2071			APCI3120_SELECT_TIMER_2_LOW_WORD;
2072		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2073		outw(LOWORD(ui_Timervalue2),
2074			devpriv->iobase + APCI3120_TIMER_VALUE);
2075
2076		//Writing HIGH WORD
2077		b_Tmp = ((devpriv->
2078				b_DigitalOutputRegister) & 0xF0) |
2079			APCI3120_SELECT_TIMER_2_HIGH_WORD;
2080		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2081
2082		outw(HIWORD(ui_Timervalue2),
2083			devpriv->iobase + APCI3120_TIMER_VALUE);
2084		//watchdog enabled
2085		devpriv->b_Timer2Mode = APCI3120_WATCHDOG;
2086
2087	}
2088
2089	return insn->n;
2090
2091}
2092
2093/*
2094+----------------------------------------------------------------------------+
2095| Function name     :int i_APCI3120_InsnWriteTimer(comedi_device *dev,           |
2096|                    comedi_subdevice *s, comedi_insn *insn,lsampl_t *data)  |
2097|                                            						         |
2098+----------------------------------------------------------------------------+
2099| Task              :    To start and stop the timer		                 |
2100+----------------------------------------------------------------------------+
2101| Input Parameters  : comedi_device *dev									 |
2102|                     comedi_subdevice *s									 |
2103|                     comedi_insn *insn                                      |
2104|                     lsampl_t *data                                         |
2105|                                                                            |
2106|				data[0] = 1 (start)                                  |
2107|				data[0] = 0 (stop )                                  |
2108|	 			data[0] = 2  (write new value)                       |
2109|	   			data[1]= new value                                   |
2110|                                                                            |
2111|    				devpriv->b_Timer2Mode =  0 DISABLE                   |
2112|	                     					 1 Timer                     |
2113|					 					 2 Watch dog			     |
2114|                                                 					         |
2115+----------------------------------------------------------------------------+
2116| Return Value      :              					                         |
2117|                    													     |
2118+----------------------------------------------------------------------------+
2119*/
2120
2121int i_APCI3120_InsnWriteTimer(comedi_device * dev, comedi_subdevice * s,
2122	comedi_insn * insn, lsampl_t * data)
2123{
2124
2125	UINT ui_Timervalue2 = 0;
2126	USHORT us_TmpValue;
2127	BYTE b_Tmp;
2128
2129	if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
2130		&& (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
2131		comedi_error(dev, "\nwrite:timer2  not configured ");
2132		return -EINVAL;
2133	}
2134
2135	if (data[0] == 2)	// write new value
2136	{
2137		if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
2138			comedi_error(dev,
2139				"write :timer2  not configured  in TIMER MODE");
2140			return -EINVAL;
2141		}
2142
2143		if (data[1])
2144			ui_Timervalue2 = data[1];
2145		else
2146			ui_Timervalue2 = 0;
2147	}
2148
2149	//this_board->i_hwdrv_InsnWriteTimer(dev,data[0],ui_Timervalue2);
2150
2151	switch (data[0]) {
2152	case APCI3120_START:
2153
2154		// Reset FC_TIMER BIT
2155		inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2156		if (devpriv->b_Timer2Mode == APCI3120_TIMER)	//start timer
2157		{
2158			//Enable Timer
2159			devpriv->b_ModeSelectRegister =
2160				devpriv->b_ModeSelectRegister & 0x0B;
2161		} else		//start watch dog
2162		{
2163			//Enable WatchDog
2164			devpriv->b_ModeSelectRegister =
2165				(devpriv->
2166				b_ModeSelectRegister & 0x0B) |
2167				APCI3120_ENABLE_WATCHDOG;
2168		}
2169
2170		//enable disable interrupt
2171		if ((devpriv->b_Timer2Interrupt) == APCI3120_ENABLE) {
2172
2173			devpriv->b_ModeSelectRegister =
2174				devpriv->
2175				b_ModeSelectRegister |
2176				APCI3120_ENABLE_TIMER_INT;
2177			// save the task structure to pass info to user
2178			devpriv->tsk_Current = current;
2179		} else {
2180
2181			devpriv->b_ModeSelectRegister =
2182				devpriv->
2183				b_ModeSelectRegister &
2184				APCI3120_DISABLE_TIMER_INT;
2185		}
2186		outb(devpriv->b_ModeSelectRegister,
2187			devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
2188
2189		if (devpriv->b_Timer2Mode == APCI3120_TIMER)	//start timer
2190		{
2191			//For Timer mode is  Gate2 must be activated   **timer started
2192			devpriv->us_OutputRegister =
2193				devpriv->
2194				us_OutputRegister | APCI3120_ENABLE_TIMER2;
2195			outw(devpriv->us_OutputRegister,
2196				devpriv->iobase + APCI3120_WR_ADDRESS);
2197		}
2198
2199		break;
2200
2201	case APCI3120_STOP:
2202		if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
2203			//Disable timer
2204			devpriv->b_ModeSelectRegister =
2205				devpriv->
2206				b_ModeSelectRegister &
2207				APCI3120_DISABLE_TIMER_COUNTER;
2208		} else {
2209			//Disable WatchDog
2210			devpriv->b_ModeSelectRegister =
2211				devpriv->
2212				b_ModeSelectRegister &
2213				APCI3120_DISABLE_WATCHDOG;
2214		}
2215		// Disable timer interrupt
2216		devpriv->b_ModeSelectRegister =
2217			devpriv->
2218			b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT;
2219
2220		// Write above states  to register
2221		outb(devpriv->b_ModeSelectRegister,
2222			devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
2223
2224		// Reset Gate 2
2225		devpriv->us_OutputRegister =
2226			devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER_INT;
2227		outw(devpriv->us_OutputRegister,
2228			devpriv->iobase + APCI3120_WR_ADDRESS);
2229
2230		// Reset FC_TIMER BIT
2231		inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2232
2233		// Disable timer
2234		//devpriv->b_Timer2Mode=APCI3120_DISABLE;
2235
2236		break;
2237
2238	case 2:		//write new value to Timer
2239		if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
2240			comedi_error(dev,
2241				"write :timer2  not configured  in TIMER MODE");
2242			return -EINVAL;
2243		}
2244		// ui_Timervalue2=data[1]; // passed as argument
2245		us_TmpValue =
2246			(USHORT) inw(devpriv->iobase + APCI3120_RD_STATUS);
2247
2248		//EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001
2249		// and calculate the time value to set in the timer
2250		if ((us_TmpValue & 0x00B0) == 0x00B0
2251			|| !strcmp(this_board->pc_DriverName, "apci3001")) {
2252			//Calculate the time value to set in the timer
2253			ui_Timervalue2 = ui_Timervalue2 / 50;
2254		} else {
2255			//Calculate the time value to set in the timer
2256			ui_Timervalue2 = ui_Timervalue2 / 70;
2257		}
2258		//Writing LOW WORD
2259		b_Tmp = ((devpriv->
2260				b_DigitalOutputRegister) & 0xF0) |
2261			APCI3120_SELECT_TIMER_2_LOW_WORD;
2262		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2263
2264		outw(LOWORD(ui_Timervalue2),
2265			devpriv->iobase + APCI3120_TIMER_VALUE);
2266
2267		//Writing HIGH WORD
2268		b_Tmp = ((devpriv->
2269				b_DigitalOutputRegister) & 0xF0) |
2270			APCI3120_SELECT_TIMER_2_HIGH_WORD;
2271		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2272
2273		outw(HIWORD(ui_Timervalue2),
2274			devpriv->iobase + APCI3120_TIMER_VALUE);
2275
2276		break;
2277	default:
2278		return -EINVAL;	// Not a valid input
2279	}
2280
2281	return insn->n;
2282}
2283
2284/*
2285+----------------------------------------------------------------------------+
2286| Function name     : int i_APCI3120_InsnReadTimer(comedi_device *dev,           |
2287|		comedi_subdevice *s,comedi_insn *insn, lsampl_t *data) 		 |
2288|                                        									 |
2289|                                            						         |
2290+----------------------------------------------------------------------------+
2291| Task              : read the Timer value 				                 	 |
2292+----------------------------------------------------------------------------+
2293| Input Parameters  : 	comedi_device *dev									 |
2294|                     comedi_subdevice *s									 |
2295|                     comedi_insn *insn                                      |
2296|                     lsampl_t *data 										 |
2297|                     														 |
2298+----------------------------------------------------------------------------+
2299| Return Value      :   													 |
2300|			for Timer:	data[0]= Timer constant						 |
2301|																	 |
2302|         		for watchdog: data[0]=0 (still running)                  |
2303|	               			  data[0]=1  (run down)            			 |
2304|                    													     |
2305+----------------------------------------------------------------------------+
2306*/
2307int i_APCI3120_InsnReadTimer(comedi_device * dev, comedi_subdevice * s,
2308	comedi_insn * insn, lsampl_t * data)
2309{
2310	BYTE b_Tmp;
2311	USHORT us_TmpValue, us_TmpValue_2, us_StatusValue;
2312
2313	if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
2314		&& (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
2315		comedi_error(dev, "\nread:timer2  not configured ");
2316	}
2317
2318	//this_board->i_hwdrv_InsnReadTimer(dev,data);
2319	if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
2320
2321		//Read the LOW WORD of Timer 2 register
2322		b_Tmp = ((devpriv->
2323				b_DigitalOutputRegister) & 0xF0) |
2324			APCI3120_SELECT_TIMER_2_LOW_WORD;
2325		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2326
2327		us_TmpValue = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
2328
2329		//Read the HIGH WORD of Timer 2 register
2330		b_Tmp = ((devpriv->
2331				b_DigitalOutputRegister) & 0xF0) |
2332			APCI3120_SELECT_TIMER_2_HIGH_WORD;
2333		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2334
2335		us_TmpValue_2 = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
2336
2337		// combining both words
2338		data[0] = (UINT) ((us_TmpValue) | ((us_TmpValue_2) << 16));
2339
2340	} else			// Read watch dog status
2341	{
2342
2343		us_StatusValue = inw(devpriv->iobase + APCI3120_RD_STATUS);
2344		us_StatusValue =
2345			((us_StatusValue & APCI3120_FC_TIMER) >> 12) & 1;
2346		if (us_StatusValue == 1) {
2347			// RESET FC_TIMER BIT
2348			inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2349		}
2350		data[0] = us_StatusValue;	// when data[0] = 1 then the watch dog has rundown
2351	}
2352	return insn->n;
2353}
2354
2355/*
2356+----------------------------------------------------------------------------+
2357|                           DIGITAL INPUT SUBDEVICE   		                 |
2358+----------------------------------------------------------------------------+
2359*/
2360
2361/*
2362+----------------------------------------------------------------------------+
2363| Function name     :int i_APCI3120_InsnReadDigitalInput(comedi_device *dev,     |
2364|			comedi_subdevice *s, comedi_insn *insn,lsampl_t *data)   |
2365|                                        									 |
2366|                                            						         |
2367+----------------------------------------------------------------------------+
2368| Task              : Reads the value of the specified  Digital input channel|
2369|                     										                 |
2370+----------------------------------------------------------------------------+
2371| Input Parameters  : comedi_device *dev									 |
2372|                     comedi_subdevice *s									 |
2373|                     comedi_insn *insn                                      |
2374|                     lsampl_t *data 										 |
2375+----------------------------------------------------------------------------+
2376| Return Value      :              					                         |
2377|                    													     |
2378+----------------------------------------------------------------------------+
2379*/
2380
2381int i_APCI3120_InsnReadDigitalInput(comedi_device * dev, comedi_subdevice
2382	* s, comedi_insn * insn, lsampl_t * data)
2383{
2384	UINT ui_Chan, ui_TmpValue;
2385
2386	ui_Chan = CR_CHAN(insn->chanspec);	// channel specified
2387
2388	//this_board->i_hwdrv_InsnReadDigitalInput(dev,ui_Chan,data);
2389	if (ui_Chan >= 0 && ui_Chan <= 3) {
2390		ui_TmpValue = (UINT) inw(devpriv->iobase + APCI3120_RD_STATUS);
2391
2392		//      since only 1 channel reqd  to bring it to last bit it is rotated
2393		//  8 +(chan - 1) times then ANDed with 1 for last bit.
2394		*data = (ui_TmpValue >> (ui_Chan + 8)) & 1;
2395		//return 0;
2396	} else {
2397		//      comedi_error(dev," chan spec wrong");
2398		return -EINVAL;	// "sorry channel spec wrong "
2399	}
2400	return insn->n;
2401
2402}
2403
2404/*
2405+----------------------------------------------------------------------------+
2406| Function name     :int i_APCI3120_InsnBitsDigitalInput(comedi_device *dev, |
2407|comedi_subdevice *s, comedi_insn *insn,lsampl_t *data)                      |
2408|                                        									 |
2409+----------------------------------------------------------------------------+
2410| Task              : Reads the value of the Digital input Port i.e.4channels|
2411|   value is returned in data[0]											 |
2412|                     										                 |
2413+----------------------------------------------------------------------------+
2414| Input Parameters  : comedi_device *dev									 |
2415|                     comedi_subdevice *s									 |
2416|                     comedi_insn *insn                                      |
2417|                     lsampl_t *data 										 |
2418+----------------------------------------------------------------------------+
2419| Return Value      :              					                         |
2420|                    													     |
2421+----------------------------------------------------------------------------+
2422*/
2423int i_APCI3120_InsnBitsDigitalInput(comedi_device * dev, comedi_subdevice * s,
2424	comedi_insn * insn, lsampl_t * data)
2425{
2426	UINT ui_TmpValue;
2427	ui_TmpValue = (UINT) inw(devpriv->iobase + APCI3120_RD_STATUS);
2428	/*****	state of 4 channels  in the 11, 10, 9, 8   bits of status reg
2429			rotated right 8 times to bring them to last four bits
2430			ANDed with oxf for  value.
2431	*****/
2432
2433	*data = (ui_TmpValue >> 8) & 0xf;
2434	//this_board->i_hwdrv_InsnBitsDigitalInput(dev,data);
2435	return insn->n;
2436}
2437
2438/*
2439+----------------------------------------------------------------------------+
2440|                           DIGITAL OUTPUT SUBDEVICE   		                 |
2441+----------------------------------------------------------------------------+
2442*/
2443/*
2444+----------------------------------------------------------------------------+
2445| Function name     :int i_APCI3120_InsnConfigDigitalOutput(comedi_device    |
2446| *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)				 |
2447|                                            						         |
2448+----------------------------------------------------------------------------+
2449| Task              :Configure the output memory ON or OFF				     |
2450|                     										                 |
2451+----------------------------------------------------------------------------+
2452| Input Parameters  :comedi_device *dev									 	 |
2453|                     comedi_subdevice *s									 |
2454|                     comedi_insn *insn                                      |
2455|                     lsampl_t *data 										 |
2456+----------------------------------------------------------------------------+
2457| Return Value      :              					                         |
2458|                    													     |
2459+----------------------------------------------------------------------------+
2460*/
2461
2462int i_APCI3120_InsnConfigDigitalOutput(comedi_device * dev,
2463	comedi_subdevice * s, comedi_insn * insn, lsampl_t * data)
2464{
2465
2466	if ((data[0] != 0) && (data[0] != 1)) {
2467		comedi_error(dev,
2468			"Not a valid Data !!! ,Data should be 1 or 0\n");
2469		return -EINVAL;
2470	}
2471	if (data[0]) {
2472		devpriv->b_OutputMemoryStatus = APCI3120_ENABLE;
2473
2474	} else {
2475		devpriv->b_OutputMemoryStatus = APCI3120_DISABLE;
2476		devpriv->b_DigitalOutputRegister = 0;
2477	}
2478	if (!devpriv->b_OutputMemoryStatus) {
2479		ui_Temp = 0;
2480
2481	}			//if(!devpriv->b_OutputMemoryStatus )
2482
2483	return insn->n;
2484}
2485
2486/*
2487+----------------------------------------------------------------------------+
2488| Function name     :int i_APCI3120_InsnBitsDigitalOutput(comedi_device *dev,    |
2489|		comedi_subdevice *s, comedi_insn *insn,lsampl_t *data) 		 |
2490|                                        									 |
2491+----------------------------------------------------------------------------+
2492| Task              : write diatal output port							     |
2493|                     										                 |
2494+----------------------------------------------------------------------------+
2495| Input Parameters  : comedi_device *dev									 |
2496|                     comedi_subdevice *s									 |
2497|                     comedi_insn *insn                                      |
2498|                     lsampl_t *data 										 |
2499                      data[0]     Value to be written
2500                      data[1]    :1 Set digital o/p ON
2501                      data[1]     2 Set digital o/p OFF with memory ON
2502+----------------------------------------------------------------------------+
2503| Return Value      :              					                         |
2504|                    													     |
2505+----------------------------------------------------------------------------+
2506*/
2507
2508int i_APCI3120_InsnBitsDigitalOutput(comedi_device * dev, comedi_subdevice
2509	* s, comedi_insn * insn, lsampl_t * data)
2510{
2511	if ((data[0] > this_board->i_DoMaxdata) || (data[0] < 0)) {
2512
2513		comedi_error(dev, "Data is not valid !!! \n");
2514		return -EINVAL;
2515	}
2516
2517	switch (data[1]) {
2518	case 1:
2519		data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister;
2520		break;
2521
2522	case 2:
2523		data[0] = data[0];
2524		break;
2525	default:
2526		printk("\nThe parameter passed is in error \n");
2527		return -EINVAL;
2528	}			// switch(data[1])
2529	outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
2530
2531	devpriv->b_DigitalOutputRegister = data[0] & 0xF0;
2532
2533	return insn->n;
2534
2535}
2536
2537/*
2538+----------------------------------------------------------------------------+
2539| Function name     :int i_APCI3120_InsnWriteDigitalOutput(comedi_device *dev,|
2540|comedi_subdevice *s,comedi_insn *insn,lsampl_t *data) 			             |
2541|                                            						         |
2542+----------------------------------------------------------------------------+
2543| Task              : Write digiatl output								     |
2544|                     										                 |
2545+----------------------------------------------------------------------------+
2546| Input Parameters  : comedi_device *dev								 	 |
2547|                     comedi_subdevice *s									 |
2548|                     comedi_insn *insn                                      |
2549|                     lsampl_t *data 										 |
2550                      data[0]     Value to be written
2551                      data[1]    :1 Set digital o/p ON
2552                      data[1]     2 Set digital o/p OFF with memory ON
2553+----------------------------------------------------------------------------+
2554| Return Value      :              					                         |
2555|                    													     |
2556+----------------------------------------------------------------------------+
2557*/
2558
2559int i_APCI3120_InsnWriteDigitalOutput(comedi_device * dev, comedi_subdevice
2560	* s, comedi_insn * insn, lsampl_t * data)
2561{
2562
2563	UINT ui_Temp1;
2564
2565	UINT ui_NoOfChannel = CR_CHAN(insn->chanspec);	// get the channel
2566
2567	if ((data[0] != 0) && (data[0] != 1)) {
2568		comedi_error(dev,
2569			"Not a valid Data !!! ,Data should be 1 or 0\n");
2570		return -EINVAL;
2571	}
2572	if ((ui_NoOfChannel > (this_board->i_NbrDoChannel - 1))
2573		|| (ui_NoOfChannel < 0)) {
2574		comedi_error(dev,
2575			"This board doesn't have specified channel !!! \n");
2576		return -EINVAL;
2577	}
2578
2579	switch (data[1]) {
2580	case 1:
2581		data[0] = (data[0] << ui_NoOfChannel);
2582//ES05                   data[0]=(data[0]<<4)|ui_Temp;
2583		data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister;
2584		break;
2585
2586	case 2:
2587		data[0] = ~data[0] & 0x1;
2588		ui_Temp1 = 1;
2589		ui_Temp1 = ui_Temp1 << ui_NoOfChannel;
2590		ui_Temp1 = ui_Temp1 << 4;
2591//ES05                   ui_Temp=ui_Temp|ui_Temp1;
2592		devpriv->b_DigitalOutputRegister =
2593			devpriv->b_DigitalOutputRegister | ui_Temp1;
2594
2595		data[0] = (data[0] << ui_NoOfChannel) ^ 0xf;
2596		data[0] = data[0] << 4;
2597//ES05                   data[0]=data[0]& ui_Temp;
2598		data[0] = data[0] & devpriv->b_DigitalOutputRegister;
2599		break;
2600	default:
2601		printk("\nThe parameter passed is in error \n");
2602		return -EINVAL;
2603	}			// switch(data[1])
2604	outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
2605
2606//ES05        ui_Temp=data[0] & 0xf0;
2607	devpriv->b_DigitalOutputRegister = data[0] & 0xf0;
2608	return (insn->n);
2609
2610}
2611
2612/*
2613+----------------------------------------------------------------------------+
2614|                            ANALOG OUTPUT SUBDEVICE                         |
2615+----------------------------------------------------------------------------+
2616*/
2617
2618/*
2619+----------------------------------------------------------------------------+
2620| Function name     :int i_APCI3120_InsnWriteAnalogOutput(comedi_device *dev,|
2621|comedi_subdevice *s, comedi_insn *insn,lsampl_t *data)			             |
2622|                                        									 |
2623+----------------------------------------------------------------------------+
2624| Task              : Write  analog output   							     |
2625|                     										                 |
2626+----------------------------------------------------------------------------+
2627| Input Parameters  : comedi_device *dev									 |
2628|                     comedi_subdevice *s									 |
2629|                     comedi_insn *insn                                      |
2630|                     lsampl_t *data  										 |
2631+----------------------------------------------------------------------------+
2632| Return Value      :              					                         |
2633|                    													     |
2634+----------------------------------------------------------------------------+
2635*/
2636
2637int i_APCI3120_InsnWriteAnalogOutput(comedi_device * dev, comedi_subdevice
2638	* s, comedi_insn * insn, lsampl_t * data)
2639{
2640	UINT ui_Range, ui_Channel;
2641	USHORT us_TmpValue;
2642
2643	ui_Range = CR_RANGE(insn->chanspec);
2644	ui_Channel = CR_CHAN(insn->chanspec);
2645
2646	//this_board->i_hwdrv_InsnWriteAnalogOutput(dev, ui_Range, ui_Channel,data[0]);
2647	if (ui_Range)		// if 1 then unipolar
2648	{
2649
2650		if (data[0] != 0)
2651			data[0] =
2652				((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
2653					13) | (data[0] + 8191));
2654		else
2655			data[0] =
2656				((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
2657					13) | 8192);
2658
2659	} else			// if 0 then   bipolar
2660	{
2661		data[0] =
2662			((((ui_Channel & 0x03) << 14) & 0xC000) | (0 << 13) |
2663			data[0]);
2664
2665	}
2666
2667	//out put n values at the given channel.
2668	// rt_printk("\nwaiting for DA_READY BIT");
2669	do			//Waiting of DA_READY BIT
2670	{
2671		us_TmpValue =
2672			((USHORT) inw(devpriv->iobase +
2673				APCI3120_RD_STATUS)) & 0x0001;
2674	} while (us_TmpValue != 0x0001);
2675
2676	if (ui_Channel <= 3)
2677		// for channel 0-3 out at  the register 1 (wrDac1-8)
2678		// data[i] typecasted to ushort since  word write is to be done
2679		outw((USHORT) data[0],
2680			devpriv->iobase + APCI3120_ANALOG_OUTPUT_1);
2681	else
2682		// for channel 4-7 out at the register 2 (wrDac5-8)
2683		//data[i] typecasted to ushort since  word write is to be done
2684		outw((USHORT) data[0],
2685			devpriv->iobase + APCI3120_ANALOG_OUTPUT_2);
2686
2687	return insn->n;
2688}
2689