[go: nahoru, domu]

1/**
2@verbatim
3
4Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
5
6	ADDI-DATA GmbH
7	Dieselstrasse 3
8	D-77833 Ottersweier
9	Tel: +19(0)7223/9493-0
10	Fax: +49(0)7223/9493-92
11	http://www.addi-data.com
12	info@addi-data.com
13
14This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
15
16This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17
18@endverbatim
19*/
20/*
21  +-----------------------------------------------------------------------+
22  | (C) ADDI-DATA GmbH          Dieselstrasse 3      D-77833 Ottersweier  |
23  +-----------------------------------------------------------------------+
24  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
25  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
26  +-----------------------------------------------------------------------+
27  | Project     : APCI-3120       | Compiler   : GCC                      |
28  | Module name : hwdrv_apci3120.c| Version    : 2.96                     |
29  +-------------------------------+---------------------------------------+
30  | Project manager: Eric Stolz   | Date       :  02/12/2002              |
31  +-----------------------------------------------------------------------+
32  | Description :APCI3120 Module.  Hardware abstraction Layer for APCI3120|
33  +-----------------------------------------------------------------------+
34  |                             UPDATE'S                                  |
35  +-----------------------------------------------------------------------+
36  |   Date   |   Author  |          Description of updates                |
37  +----------+-----------+------------------------------------------------+
38  |          | 		 | 						  |
39  |          |           |						  |
40  +----------+-----------+------------------------------------------------+
41*/
42
43#include <linux/delay.h>
44
45/*
46 * ADDON RELATED ADDITIONS
47 */
48/* Constant */
49#define APCI3120_ENABLE_TRANSFER_ADD_ON_LOW		0x00
50#define APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH		0x1200
51#define APCI3120_A2P_FIFO_MANAGEMENT			0x04000400L
52#define APCI3120_AMWEN_ENABLE				0x02
53#define APCI3120_A2P_FIFO_WRITE_ENABLE			0x01
54#define APCI3120_FIFO_ADVANCE_ON_BYTE_2			0x20000000L
55#define APCI3120_ENABLE_WRITE_TC_INT			0x00004000L
56#define APCI3120_CLEAR_WRITE_TC_INT			0x00040000L
57#define APCI3120_DISABLE_AMWEN_AND_A2P_FIFO_WRITE	0x0
58#define APCI3120_DISABLE_BUS_MASTER_ADD_ON		0x0
59#define APCI3120_DISABLE_BUS_MASTER_PCI			0x0
60
61/* ADD_ON ::: this needed since apci supports 16 bit interface to add on */
62#define APCI3120_ADD_ON_AGCSTS_LOW	0x3C
63#define APCI3120_ADD_ON_AGCSTS_HIGH	(APCI3120_ADD_ON_AGCSTS_LOW + 2)
64#define APCI3120_ADD_ON_MWAR_LOW	0x24
65#define APCI3120_ADD_ON_MWAR_HIGH	(APCI3120_ADD_ON_MWAR_LOW + 2)
66#define APCI3120_ADD_ON_MWTC_LOW	0x058
67#define APCI3120_ADD_ON_MWTC_HIGH	(APCI3120_ADD_ON_MWTC_LOW + 2)
68
69/* AMCC */
70#define APCI3120_AMCC_OP_MCSR		0x3C
71#define APCI3120_AMCC_OP_REG_INTCSR	0x38
72
73/* for transfer count enable bit */
74#define AGCSTS_TC_ENABLE	0x10000000
75
76/* used for test on mixture of BIP/UNI ranges */
77#define APCI3120_BIPOLAR_RANGES		4
78
79#define APCI3120_ADDRESS_RANGE		16
80
81#define APCI3120_DISABLE		0
82#define APCI3120_ENABLE			1
83
84#define APCI3120_START			1
85#define APCI3120_STOP			0
86
87#define APCI3120_EOC_MODE		1
88#define APCI3120_EOS_MODE		2
89#define APCI3120_DMA_MODE		3
90
91/* DIGITAL INPUT-OUTPUT DEFINE */
92
93#define APCI3120_DIGITAL_OUTPUT		0x0d
94#define APCI3120_RD_STATUS		0x02
95#define APCI3120_RD_FIFO		0x00
96
97/* digital output insn_write ON /OFF selection */
98#define	APCI3120_SET4DIGITALOUTPUTON	1
99#define APCI3120_SET4DIGITALOUTPUTOFF	0
100
101/* analog output SELECT BIT */
102#define APCI3120_ANALOG_OP_CHANNEL_1	0x0000
103#define APCI3120_ANALOG_OP_CHANNEL_2	0x4000
104#define APCI3120_ANALOG_OP_CHANNEL_3	0x8000
105#define APCI3120_ANALOG_OP_CHANNEL_4	0xc000
106#define APCI3120_ANALOG_OP_CHANNEL_5	0x0000
107#define APCI3120_ANALOG_OP_CHANNEL_6	0x4000
108#define APCI3120_ANALOG_OP_CHANNEL_7	0x8000
109#define APCI3120_ANALOG_OP_CHANNEL_8	0xc000
110
111/* Enable external trigger bit in nWrAddress */
112#define APCI3120_ENABLE_EXT_TRIGGER	0x8000
113
114/* ANALOG OUTPUT AND INPUT DEFINE */
115#define APCI3120_UNIPOLAR		0x80
116#define APCI3120_BIPOLAR		0x00
117#define APCI3120_ANALOG_OUTPUT_1	0x08
118#define APCI3120_ANALOG_OUTPUT_2	0x0a
119#define APCI3120_1_GAIN			0x00
120#define APCI3120_2_GAIN			0x10
121#define APCI3120_5_GAIN			0x20
122#define APCI3120_10_GAIN		0x30
123#define APCI3120_SEQ_RAM_ADDRESS	0x06
124#define APCI3120_RESET_FIFO		0x0c
125#define APCI3120_TIMER_0_MODE_2		0x01
126#define APCI3120_TIMER_0_MODE_4		0x2
127#define APCI3120_SELECT_TIMER_0_WORD	0x00
128#define APCI3120_ENABLE_TIMER0		0x1000
129#define APCI3120_CLEAR_PR		0xf0ff
130#define APCI3120_CLEAR_PA		0xfff0
131#define APCI3120_CLEAR_PA_PR		(APCI3120_CLEAR_PR & APCI3120_CLEAR_PA)
132
133/* nWrMode_Select */
134#define APCI3120_ENABLE_SCAN		0x8
135#define APCI3120_DISABLE_SCAN		(~APCI3120_ENABLE_SCAN)
136#define APCI3120_ENABLE_EOS_INT		0x2
137
138#define APCI3120_DISABLE_EOS_INT	(~APCI3120_ENABLE_EOS_INT)
139#define APCI3120_ENABLE_EOC_INT		0x1
140#define APCI3120_DISABLE_EOC_INT	(~APCI3120_ENABLE_EOC_INT)
141#define APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER	\
142	(APCI3120_DISABLE_EOS_INT & APCI3120_DISABLE_EOC_INT)
143#define APCI3120_DISABLE_ALL_INTERRUPT			\
144	(APCI3120_DISABLE_TIMER_INT & APCI3120_DISABLE_EOS_INT & APCI3120_DISABLE_EOC_INT)
145
146/* status register bits */
147#define APCI3120_EOC			0x8000
148#define APCI3120_EOS			0x2000
149
150/* software trigger dummy register */
151#define APCI3120_START_CONVERSION	0x02
152
153/* TIMER DEFINE */
154#define APCI3120_QUARTZ_A		70
155#define APCI3120_QUARTZ_B		50
156#define APCI3120_TIMER			1
157#define APCI3120_WATCHDOG		2
158#define APCI3120_TIMER_DISABLE		0
159#define APCI3120_TIMER_ENABLE		1
160#define APCI3120_ENABLE_TIMER2		0x4000
161#define APCI3120_DISABLE_TIMER2		(~APCI3120_ENABLE_TIMER2)
162#define APCI3120_ENABLE_TIMER_INT	0x04
163#define APCI3120_DISABLE_TIMER_INT	(~APCI3120_ENABLE_TIMER_INT)
164#define APCI3120_WRITE_MODE_SELECT	0x0e
165#define APCI3120_SELECT_TIMER_0_WORD	0x00
166#define APCI3120_SELECT_TIMER_1_WORD	0x01
167#define APCI3120_TIMER_1_MODE_2		0x4
168
169/* $$ BIT FOR MODE IN nCsTimerCtr1 */
170#define APCI3120_TIMER_2_MODE_0		0x0
171#define APCI3120_TIMER_2_MODE_2		0x10
172#define APCI3120_TIMER_2_MODE_5		0x30
173
174/* $$ BIT FOR MODE IN nCsTimerCtr0 */
175#define APCI3120_SELECT_TIMER_2_LOW_WORD	0x02
176#define APCI3120_SELECT_TIMER_2_HIGH_WORD	0x03
177
178#define APCI3120_TIMER_CRT0		0x0d
179#define APCI3120_TIMER_CRT1		0x0c
180
181#define APCI3120_TIMER_VALUE		0x04
182#define APCI3120_TIMER_STATUS_REGISTER	0x0d
183#define APCI3120_RD_STATUS		0x02
184#define APCI3120_WR_ADDRESS		0x00
185#define APCI3120_ENABLE_WATCHDOG	0x20
186#define APCI3120_DISABLE_WATCHDOG	(~APCI3120_ENABLE_WATCHDOG)
187#define APCI3120_ENABLE_TIMER_COUNTER	0x10
188#define APCI3120_DISABLE_TIMER_COUNTER	(~APCI3120_ENABLE_TIMER_COUNTER)
189#define APCI3120_FC_TIMER		0x1000
190#define APCI3120_ENABLE_TIMER0		0x1000
191#define APCI3120_ENABLE_TIMER1		0x2000
192#define APCI3120_ENABLE_TIMER2		0x4000
193#define APCI3120_DISABLE_TIMER0		(~APCI3120_ENABLE_TIMER0)
194#define APCI3120_DISABLE_TIMER1		(~APCI3120_ENABLE_TIMER1)
195#define APCI3120_DISABLE_TIMER2		(~APCI3120_ENABLE_TIMER2)
196
197#define APCI3120_TIMER2_SELECT_EOS	0xc0
198#define APCI3120_COUNTER		3
199#define APCI3120_DISABLE_ALL_TIMER	(APCI3120_DISABLE_TIMER0 &	\
200					 APCI3120_DISABLE_TIMER1 &	\
201					 APCI3120_DISABLE_TIMER2)
202
203#define MAX_ANALOGINPUT_CHANNELS	32
204
205struct str_AnalogReadInformation {
206	/* EOC or EOS */
207	unsigned char b_Type;
208	/* Interrupt use or not */
209	unsigned char b_InterruptFlag;
210	/* Selection of the conversion time */
211	unsigned int ui_ConvertTiming;
212	/* Number of channel to read */
213	unsigned char b_NbrOfChannel;
214	/* Number of the channel to be read */
215	unsigned int ui_ChannelList[MAX_ANALOGINPUT_CHANNELS];
216	/* Gain of each channel */
217	unsigned int ui_RangeList[MAX_ANALOGINPUT_CHANNELS];
218};
219
220/* ANALOG INPUT RANGE */
221static const struct comedi_lrange range_apci3120_ai = {
222	8, {
223		BIP_RANGE(10),
224		BIP_RANGE(5),
225		BIP_RANGE(2),
226		BIP_RANGE(1),
227		UNI_RANGE(10),
228		UNI_RANGE(5),
229		UNI_RANGE(2),
230		UNI_RANGE(1)
231	}
232};
233
234/* ANALOG OUTPUT RANGE */
235static const struct comedi_lrange range_apci3120_ao = {
236	2, {
237		BIP_RANGE(10),
238		UNI_RANGE(10)
239	}
240};
241
242
243/* FUNCTION DEFINITIONS */
244static 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 */
299static 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 */
349static 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
589static 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
642static 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
651static 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
660static 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
705static 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 */
780static 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 */
1204static 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 */
1227static 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 */
1249static 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 */
1402static 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
1424static 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 */
1611static 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 */
1749static 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 */
1915static 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
1963static 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
1978static 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
1998static 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