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