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