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