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