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