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