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