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