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