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