hwdrv_apci3120.c revision 156041e9e432eaa97999c976be4203416038c9f6
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	s->async->events = 0;
1578
1579	for (i = 0; i < n_chan; i++)
1580		err &= comedi_buf_put(s->async, inw(dev->iobase + 0));
1581
1582	s->async->events |= COMEDI_CB_EOS;
1583
1584	if (err == 0)
1585		s->async->events |= COMEDI_CB_OVERFLOW;
1586
1587	comedi_event(dev, s);
1588
1589	return 0;
1590}
1591
1592static void v_APCI3120_Interrupt(int irq, void *d)
1593{
1594	struct comedi_device *dev = d;
1595	struct addi_private *devpriv = dev->private;
1596	struct comedi_subdevice *s = dev->read_subdev;
1597	unsigned short int_daq;
1598	unsigned int int_amcc, ui_Check, i;
1599	unsigned short us_TmpValue;
1600	unsigned char b_DummyRead;
1601
1602	ui_Check = 1;
1603
1604	int_daq = inw(dev->iobase + APCI3120_RD_STATUS) & 0xf000;	/*  get IRQ reasons */
1605	int_amcc = inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);	/*  get AMCC int register */
1606
1607	if ((!int_daq) && (!(int_amcc & ANY_S593X_INT))) {
1608		comedi_error(dev, "IRQ from unknown source");
1609		return;
1610	}
1611
1612	outl(int_amcc | 0x00ff0000, devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);	/*  shutdown IRQ reasons in AMCC */
1613
1614	int_daq = (int_daq >> 12) & 0xF;
1615
1616	if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) {
1617		/* Disable ext trigger */
1618		i_APCI3120_ExttrigDisable(dev);
1619		devpriv->b_ExttrigEnable = APCI3120_DISABLE;
1620	}
1621	/* clear the timer 2 interrupt */
1622	inb(devpriv->i_IobaseAmcc + APCI3120_TIMER_STATUS_REGISTER);
1623
1624	if (int_amcc & MASTER_ABORT_INT)
1625		comedi_error(dev, "AMCC IRQ - MASTER DMA ABORT!");
1626	if (int_amcc & TARGET_ABORT_INT)
1627		comedi_error(dev, "AMCC IRQ - TARGET DMA ABORT!");
1628
1629	/*  Ckeck if EOC interrupt */
1630	if (((int_daq & 0x8) == 0)
1631		&& (devpriv->b_InterruptMode == APCI3120_EOC_MODE)) {
1632		if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
1633
1634			/*  Read the AI Value */
1635
1636			devpriv->ui_AiReadData[0] =
1637				(unsigned int) inw(devpriv->iobase + 0);
1638			devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1639			send_sig(SIGIO, devpriv->tsk_Current, 0);	/*  send signal to the sample */
1640		} else {
1641			/* Disable EOC Interrupt */
1642			devpriv->b_ModeSelectRegister =
1643				devpriv->
1644				b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT;
1645			outb(devpriv->b_ModeSelectRegister,
1646				devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
1647
1648		}
1649	}
1650
1651	/*  Check If EOS interrupt */
1652	if ((int_daq & 0x2) && (devpriv->b_InterruptMode == APCI3120_EOS_MODE)) {
1653
1654		if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {	/*  enable this in without DMA ??? */
1655
1656			if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
1657				ui_Check = 0;
1658				i_APCI3120_InterruptHandleEos(dev);
1659				devpriv->ui_AiActualScan++;
1660				devpriv->b_ModeSelectRegister =
1661					devpriv->
1662					b_ModeSelectRegister |
1663					APCI3120_ENABLE_EOS_INT;
1664				outb(devpriv->b_ModeSelectRegister,
1665					dev->iobase +
1666					APCI3120_WRITE_MODE_SELECT);
1667			} else {
1668				ui_Check = 0;
1669				for (i = 0; i < devpriv->ui_AiNbrofChannels;
1670					i++) {
1671					us_TmpValue = inw(devpriv->iobase + 0);
1672					devpriv->ui_AiReadData[i] =
1673						(unsigned int) us_TmpValue;
1674				}
1675				devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1676				devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1677
1678				send_sig(SIGIO, devpriv->tsk_Current, 0);	/*  send signal to the sample */
1679
1680			}
1681
1682		} else {
1683			devpriv->b_ModeSelectRegister =
1684				devpriv->
1685				b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
1686			outb(devpriv->b_ModeSelectRegister,
1687				dev->iobase + APCI3120_WRITE_MODE_SELECT);
1688			devpriv->b_EocEosInterrupt = APCI3120_DISABLE;	/* Default settings */
1689			devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1690		}
1691
1692	}
1693	/* Timer2 interrupt */
1694	if (int_daq & 0x1) {
1695
1696		switch (devpriv->b_Timer2Mode) {
1697		case APCI3120_COUNTER:
1698
1699			devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1700			devpriv->b_ModeSelectRegister =
1701				devpriv->
1702				b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
1703			outb(devpriv->b_ModeSelectRegister,
1704				dev->iobase + APCI3120_WRITE_MODE_SELECT);
1705
1706			/*  stop timer 2 */
1707			devpriv->us_OutputRegister =
1708				devpriv->
1709				us_OutputRegister & APCI3120_DISABLE_ALL_TIMER;
1710			outw(devpriv->us_OutputRegister,
1711				dev->iobase + APCI3120_WR_ADDRESS);
1712
1713			/* stop timer 0 and timer 1 */
1714			i_APCI3120_StopCyclicAcquisition(dev, s);
1715			devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1716
1717			/* UPDATE-0.7.57->0.7.68comedi_done(dev,s); */
1718			s->async->events |= COMEDI_CB_EOA;
1719			comedi_event(dev, s);
1720
1721			break;
1722
1723		case APCI3120_TIMER:
1724
1725			/* Send a signal to from kernel to user space */
1726			send_sig(SIGIO, devpriv->tsk_Current, 0);
1727			break;
1728
1729		case APCI3120_WATCHDOG:
1730
1731			/* Send a signal to from kernel to user space */
1732			send_sig(SIGIO, devpriv->tsk_Current, 0);
1733			break;
1734
1735		default:
1736
1737			/*  disable Timer Interrupt */
1738
1739			devpriv->b_ModeSelectRegister =
1740				devpriv->
1741				b_ModeSelectRegister &
1742				APCI3120_DISABLE_TIMER_INT;
1743
1744			outb(devpriv->b_ModeSelectRegister,
1745				dev->iobase + APCI3120_WRITE_MODE_SELECT);
1746
1747		}
1748
1749		b_DummyRead = inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1750
1751	}
1752
1753	if ((int_daq & 0x4) && (devpriv->b_InterruptMode == APCI3120_DMA_MODE)) {
1754		if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
1755
1756			/****************************/
1757			/* Clear Timer Write TC int */
1758			/****************************/
1759
1760			outl(APCI3120_CLEAR_WRITE_TC_INT,
1761				devpriv->i_IobaseAmcc +
1762				APCI3120_AMCC_OP_REG_INTCSR);
1763
1764			/************************************/
1765			/* Clears the timer status register */
1766			/************************************/
1767			inw(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1768			v_APCI3120_InterruptDma(irq, d);	/*  do some data transfer */
1769		} else {
1770			/* Stops the Timer */
1771			outw(devpriv->
1772				us_OutputRegister & APCI3120_DISABLE_TIMER0 &
1773				APCI3120_DISABLE_TIMER1,
1774				dev->iobase + APCI3120_WR_ADDRESS);
1775		}
1776
1777	}
1778
1779	return;
1780}
1781
1782/*
1783 * Configure Timer 2
1784 *
1785 * data[0] = TIMER configure as timer
1786 *	   = WATCHDOG configure as watchdog
1787 * data[1] = Timer constant
1788 * data[2] = Timer2 interrupt (1)enable or(0) disable
1789 */
1790static int i_APCI3120_InsnConfigTimer(struct comedi_device *dev,
1791				      struct comedi_subdevice *s,
1792				      struct comedi_insn *insn,
1793				      unsigned int *data)
1794{
1795	const struct addi_board *this_board = comedi_board(dev);
1796	struct addi_private *devpriv = dev->private;
1797	unsigned int ui_Timervalue2;
1798	unsigned short us_TmpValue;
1799	unsigned char b_Tmp;
1800
1801	if (!data[1])
1802		comedi_error(dev, "config:No timer constant !");
1803
1804	devpriv->b_Timer2Interrupt = (unsigned char) data[2];	/*  save info whether to enable or disable interrupt */
1805
1806	ui_Timervalue2 = data[1] / 1000;	/*  convert nano seconds  to u seconds */
1807
1808	/* this_board->timer_config(dev, ui_Timervalue2,(unsigned char)data[0]); */
1809	us_TmpValue = (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
1810
1811/*
1812 * EL250804: Testing if board APCI3120 have the new Quartz or if it
1813 * is an APCI3001 and calculate the time value to set in the timer
1814 */
1815	if ((us_TmpValue & 0x00B0) == 0x00B0
1816		|| !strcmp(this_board->pc_DriverName, "apci3001")) {
1817		/* Calculate the time value to set in the timer */
1818		ui_Timervalue2 = ui_Timervalue2 / 50;
1819	} else {
1820		/* Calculate the time value to set in the timer */
1821		ui_Timervalue2 = ui_Timervalue2 / 70;
1822	}
1823
1824	/* Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0) */
1825	devpriv->us_OutputRegister =
1826		devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER2;
1827	outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS);
1828
1829	/*  Disable TIMER Interrupt */
1830	devpriv->b_ModeSelectRegister =
1831		devpriv->
1832		b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT & 0xEF;
1833
1834	/*  Disable Eoc and Eos Interrupts */
1835	devpriv->b_ModeSelectRegister =
1836		devpriv->
1837		b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT &
1838		APCI3120_DISABLE_EOS_INT;
1839	outb(devpriv->b_ModeSelectRegister,
1840		devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
1841	if (data[0] == APCI3120_TIMER) {	/* initialize timer */
1842		/* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister |
1843		 * APCI3120_ENABLE_TIMER_INT; */
1844
1845		/* outb(devpriv->b_ModeSelectRegister,devpriv->iobase+APCI3120_WRITE_MODE_SELECT); */
1846
1847		/* Set the Timer 2 in mode 2(Timer) */
1848		devpriv->b_TimerSelectMode =
1849			(devpriv->
1850			b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_2;
1851		outb(devpriv->b_TimerSelectMode,
1852			devpriv->iobase + APCI3120_TIMER_CRT1);
1853
1854/*
1855 * Configure the timer 2 for writing the LOW unsigned short of timer
1856 * is Delay value You must make a b_tmp variable with
1857 * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
1858 * you can set the digital output and configure the timer 2,and if
1859 * you don't make this, digital output are erase (Set to 0)
1860 */
1861
1862		/* Writing LOW unsigned short */
1863		b_Tmp = ((devpriv->
1864				b_DigitalOutputRegister) & 0xF0) |
1865			APCI3120_SELECT_TIMER_2_LOW_WORD;
1866		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1867		outw(LOWORD(ui_Timervalue2),
1868			devpriv->iobase + APCI3120_TIMER_VALUE);
1869
1870		/* Writing HIGH unsigned short */
1871		b_Tmp = ((devpriv->
1872				b_DigitalOutputRegister) & 0xF0) |
1873			APCI3120_SELECT_TIMER_2_HIGH_WORD;
1874		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1875		outw(HIWORD(ui_Timervalue2),
1876			devpriv->iobase + APCI3120_TIMER_VALUE);
1877		/*  timer2 in Timer mode enabled */
1878		devpriv->b_Timer2Mode = APCI3120_TIMER;
1879
1880	} else {			/*  Initialize Watch dog */
1881
1882		/* Set the Timer 2 in mode 5(Watchdog) */
1883
1884		devpriv->b_TimerSelectMode =
1885			(devpriv->
1886			b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_5;
1887		outb(devpriv->b_TimerSelectMode,
1888			devpriv->iobase + APCI3120_TIMER_CRT1);
1889
1890/*
1891 * Configure the timer 2 for writing the LOW unsigned short of timer
1892 * is Delay value You must make a b_tmp variable with
1893 * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
1894 * you can set the digital output and configure the timer 2,and if
1895 * you don't make this, digital output are erase (Set to 0)
1896 */
1897
1898		/* Writing LOW unsigned short */
1899		b_Tmp = ((devpriv->
1900				b_DigitalOutputRegister) & 0xF0) |
1901			APCI3120_SELECT_TIMER_2_LOW_WORD;
1902		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1903		outw(LOWORD(ui_Timervalue2),
1904			devpriv->iobase + APCI3120_TIMER_VALUE);
1905
1906		/* Writing HIGH unsigned short */
1907		b_Tmp = ((devpriv->
1908				b_DigitalOutputRegister) & 0xF0) |
1909			APCI3120_SELECT_TIMER_2_HIGH_WORD;
1910		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1911
1912		outw(HIWORD(ui_Timervalue2),
1913			devpriv->iobase + APCI3120_TIMER_VALUE);
1914		/* watchdog enabled */
1915		devpriv->b_Timer2Mode = APCI3120_WATCHDOG;
1916
1917	}
1918
1919	return insn->n;
1920
1921}
1922
1923/*
1924 * To start and stop the timer
1925 *
1926 * data[0] = 1 (start)
1927 *	   = 0 (stop)
1928 *	   = 2 (write new value)
1929 * data[1] = new value
1930 *
1931 * devpriv->b_Timer2Mode = 0 DISABLE
1932 *			 = 1 Timer
1933 *			 = 2 Watch dog
1934 */
1935static int i_APCI3120_InsnWriteTimer(struct comedi_device *dev,
1936				     struct comedi_subdevice *s,
1937				     struct comedi_insn *insn,
1938				     unsigned int *data)
1939{
1940	const struct addi_board *this_board = comedi_board(dev);
1941	struct addi_private *devpriv = dev->private;
1942	unsigned int ui_Timervalue2 = 0;
1943	unsigned short us_TmpValue;
1944	unsigned char b_Tmp;
1945
1946	if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
1947		&& (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
1948		comedi_error(dev, "\nwrite:timer2  not configured ");
1949		return -EINVAL;
1950	}
1951
1952	if (data[0] == 2) {	/*  write new value */
1953		if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
1954			comedi_error(dev,
1955				"write :timer2  not configured  in TIMER MODE");
1956			return -EINVAL;
1957		}
1958
1959		if (data[1])
1960			ui_Timervalue2 = data[1];
1961		else
1962			ui_Timervalue2 = 0;
1963	}
1964
1965	/* this_board->timer_write(dev,data[0],ui_Timervalue2); */
1966
1967	switch (data[0]) {
1968	case APCI3120_START:
1969
1970		/*  Reset FC_TIMER BIT */
1971		inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
1972		if (devpriv->b_Timer2Mode == APCI3120_TIMER) {	/* start timer */
1973			/* Enable Timer */
1974			devpriv->b_ModeSelectRegister =
1975				devpriv->b_ModeSelectRegister & 0x0B;
1976		} else {		/* start watch dog */
1977			/* Enable WatchDog */
1978			devpriv->b_ModeSelectRegister =
1979				(devpriv->
1980				b_ModeSelectRegister & 0x0B) |
1981				APCI3120_ENABLE_WATCHDOG;
1982		}
1983
1984		/* enable disable interrupt */
1985		if ((devpriv->b_Timer2Interrupt) == APCI3120_ENABLE) {
1986
1987			devpriv->b_ModeSelectRegister =
1988				devpriv->
1989				b_ModeSelectRegister |
1990				APCI3120_ENABLE_TIMER_INT;
1991			/*  save the task structure to pass info to user */
1992			devpriv->tsk_Current = current;
1993		} else {
1994
1995			devpriv->b_ModeSelectRegister =
1996				devpriv->
1997				b_ModeSelectRegister &
1998				APCI3120_DISABLE_TIMER_INT;
1999		}
2000		outb(devpriv->b_ModeSelectRegister,
2001			devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
2002
2003		if (devpriv->b_Timer2Mode == APCI3120_TIMER) {	/* start timer */
2004			/* For Timer mode is  Gate2 must be activated   **timer started */
2005			devpriv->us_OutputRegister =
2006				devpriv->
2007				us_OutputRegister | APCI3120_ENABLE_TIMER2;
2008			outw(devpriv->us_OutputRegister,
2009				devpriv->iobase + APCI3120_WR_ADDRESS);
2010		}
2011
2012		break;
2013
2014	case APCI3120_STOP:
2015		if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
2016			/* Disable timer */
2017			devpriv->b_ModeSelectRegister =
2018				devpriv->
2019				b_ModeSelectRegister &
2020				APCI3120_DISABLE_TIMER_COUNTER;
2021		} else {
2022			/* Disable WatchDog */
2023			devpriv->b_ModeSelectRegister =
2024				devpriv->
2025				b_ModeSelectRegister &
2026				APCI3120_DISABLE_WATCHDOG;
2027		}
2028		/*  Disable timer interrupt */
2029		devpriv->b_ModeSelectRegister =
2030			devpriv->
2031			b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT;
2032
2033		/*  Write above states  to register */
2034		outb(devpriv->b_ModeSelectRegister,
2035			devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
2036
2037		/*  Reset Gate 2 */
2038		devpriv->us_OutputRegister =
2039			devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER_INT;
2040		outw(devpriv->us_OutputRegister,
2041			devpriv->iobase + APCI3120_WR_ADDRESS);
2042
2043		/*  Reset FC_TIMER BIT */
2044		inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2045
2046		/* Disable timer */
2047		/* devpriv->b_Timer2Mode=APCI3120_DISABLE;  */
2048
2049		break;
2050
2051	case 2:		/* write new value to Timer */
2052		if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
2053			comedi_error(dev,
2054				"write :timer2  not configured  in TIMER MODE");
2055			return -EINVAL;
2056		}
2057		/*  ui_Timervalue2=data[1]; // passed as argument */
2058		us_TmpValue =
2059			(unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
2060
2061/*
2062 * EL250804: Testing if board APCI3120 have the new Quartz or if it
2063 * is an APCI3001 and calculate the time value to set in the timer
2064 */
2065		if ((us_TmpValue & 0x00B0) == 0x00B0
2066			|| !strcmp(this_board->pc_DriverName, "apci3001")) {
2067			/* Calculate the time value to set in the timer */
2068			ui_Timervalue2 = ui_Timervalue2 / 50;
2069		} else {
2070			/* Calculate the time value to set in the timer */
2071			ui_Timervalue2 = ui_Timervalue2 / 70;
2072		}
2073		/* Writing LOW unsigned short */
2074		b_Tmp = ((devpriv->
2075				b_DigitalOutputRegister) & 0xF0) |
2076			APCI3120_SELECT_TIMER_2_LOW_WORD;
2077		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2078
2079		outw(LOWORD(ui_Timervalue2),
2080			devpriv->iobase + APCI3120_TIMER_VALUE);
2081
2082		/* Writing HIGH unsigned short */
2083		b_Tmp = ((devpriv->
2084				b_DigitalOutputRegister) & 0xF0) |
2085			APCI3120_SELECT_TIMER_2_HIGH_WORD;
2086		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2087
2088		outw(HIWORD(ui_Timervalue2),
2089			devpriv->iobase + APCI3120_TIMER_VALUE);
2090
2091		break;
2092	default:
2093		return -EINVAL;	/*  Not a valid input */
2094	}
2095
2096	return insn->n;
2097}
2098
2099/*
2100 * Read the Timer value
2101 *
2102 * for Timer: data[0]= Timer constant
2103 *
2104 * for watchdog: data[0] = 0 (still running)
2105 *			 = 1 (run down)
2106 */
2107static int i_APCI3120_InsnReadTimer(struct comedi_device *dev,
2108				    struct comedi_subdevice *s,
2109				    struct comedi_insn *insn,
2110				    unsigned int *data)
2111{
2112	struct addi_private *devpriv = dev->private;
2113	unsigned char b_Tmp;
2114	unsigned short us_TmpValue, us_TmpValue_2, us_StatusValue;
2115
2116	if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
2117		&& (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
2118		comedi_error(dev, "\nread:timer2  not configured ");
2119	}
2120
2121	/* this_board->timer_read(dev,data); */
2122	if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
2123
2124		/* Read the LOW unsigned short of Timer 2 register */
2125		b_Tmp = ((devpriv->
2126				b_DigitalOutputRegister) & 0xF0) |
2127			APCI3120_SELECT_TIMER_2_LOW_WORD;
2128		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2129
2130		us_TmpValue = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
2131
2132		/* Read the HIGH unsigned short of Timer 2 register */
2133		b_Tmp = ((devpriv->
2134				b_DigitalOutputRegister) & 0xF0) |
2135			APCI3120_SELECT_TIMER_2_HIGH_WORD;
2136		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2137
2138		us_TmpValue_2 = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
2139
2140		/*  combining both words */
2141		data[0] = (unsigned int) ((us_TmpValue) | ((us_TmpValue_2) << 16));
2142
2143	} else {			/*  Read watch dog status */
2144
2145		us_StatusValue = inw(devpriv->iobase + APCI3120_RD_STATUS);
2146		us_StatusValue =
2147			((us_StatusValue & APCI3120_FC_TIMER) >> 12) & 1;
2148		if (us_StatusValue == 1) {
2149			/*  RESET FC_TIMER BIT */
2150			inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2151		}
2152		data[0] = us_StatusValue;	/*  when data[0] = 1 then the watch dog has rundown */
2153	}
2154	return insn->n;
2155}
2156
2157static int apci3120_di_insn_bits(struct comedi_device *dev,
2158				 struct comedi_subdevice *s,
2159				 struct comedi_insn *insn,
2160				 unsigned int *data)
2161{
2162	struct addi_private *devpriv = dev->private;
2163	unsigned int val;
2164
2165	/* the input channels are bits 11:8 of the status reg */
2166	val = inw(devpriv->iobase + APCI3120_RD_STATUS);
2167	data[1] = (val >> 8) & 0xf;
2168
2169	return insn->n;
2170}
2171
2172static int apci3120_do_insn_bits(struct comedi_device *dev,
2173				 struct comedi_subdevice *s,
2174				 struct comedi_insn *insn,
2175				 unsigned int *data)
2176{
2177	struct addi_private *devpriv = dev->private;
2178
2179	if (comedi_dio_update_state(s, data)) {
2180		/* The do channels are bits 7:4 of the do register */
2181		devpriv->b_DigitalOutputRegister = s->state << 4;
2182
2183		outb(devpriv->b_DigitalOutputRegister,
2184		     devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
2185	}
2186
2187	data[1] = s->state;
2188
2189	return insn->n;
2190}
2191
2192static int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,
2193					    struct comedi_subdevice *s,
2194					    struct comedi_insn *insn,
2195					    unsigned int *data)
2196{
2197	struct addi_private *devpriv = dev->private;
2198	unsigned int ui_Range, ui_Channel;
2199	unsigned short us_TmpValue;
2200
2201	ui_Range = CR_RANGE(insn->chanspec);
2202	ui_Channel = CR_CHAN(insn->chanspec);
2203
2204	/* this_board->ao_write(dev, ui_Range, ui_Channel,data[0]); */
2205	if (ui_Range) {		/*  if 1 then unipolar */
2206
2207		if (data[0] != 0)
2208			data[0] =
2209				((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
2210					13) | (data[0] + 8191));
2211		else
2212			data[0] =
2213				((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
2214					13) | 8192);
2215
2216	} else {			/*  if 0 then   bipolar */
2217		data[0] =
2218			((((ui_Channel & 0x03) << 14) & 0xC000) | (0 << 13) |
2219			data[0]);
2220
2221	}
2222
2223/*
2224 * out put n values at the given channel. printk("\nwaiting for
2225 * DA_READY BIT");
2226 */
2227	do {			/* Waiting of DA_READY BIT */
2228		us_TmpValue =
2229			((unsigned short) inw(devpriv->iobase +
2230				APCI3120_RD_STATUS)) & 0x0001;
2231	} while (us_TmpValue != 0x0001);
2232
2233	if (ui_Channel <= 3)
2234/*
2235 * for channel 0-3 out at the register 1 (wrDac1-8) data[i]
2236 * typecasted to ushort since word write is to be done
2237 */
2238		outw((unsigned short) data[0],
2239			devpriv->iobase + APCI3120_ANALOG_OUTPUT_1);
2240	else
2241/*
2242 * for channel 4-7 out at the register 2 (wrDac5-8) data[i]
2243 * typecasted to ushort since word write is to be done
2244 */
2245		outw((unsigned short) data[0],
2246			devpriv->iobase + APCI3120_ANALOG_OUTPUT_2);
2247
2248	return insn->n;
2249}
2250