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