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