hwdrv_apci3xxx.c revision 4e4b592cb51342878166a2ea2bcf6151f0a3a29d
1/**
2@verbatim
3
4Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
5
6	ADDI-DATA GmbH
7	Dieselstrasse 3
8	D-77833 Ottersweier
9	Tel: +19(0)7223/9493-0
10	Fax: +49(0)7223/9493-92
11	http://www.addi-data-com
12	info@addi-data.com
13
14This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
15
16This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20You should also find the complete GPL in the COPYING file accompanying this source code.
21
22@endverbatim
23*/
24/*
25  +-----------------------------------------------------------------------+
26  | (C) ADDI-DATA GmbH          Dieselstrasse 3      D-77833 Ottersweier  |
27  +-----------------------------------------------------------------------+
28  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
29  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
30  +-----------------------------------------------------------------------+
31  | Project     : APCI-3XXX       | Compiler   : GCC                      |
32  | Module name : hwdrv_apci3xxx.c| Version    : 2.96                     |
33  +-------------------------------+---------------------------------------+
34  | Project manager: S. Weber     | Date       :  15/09/2005              |
35  +-----------------------------------------------------------------------+
36  | Description :APCI3XXX Module.  Hardware abstraction Layer for APCI3XXX|
37  +-----------------------------------------------------------------------+
38  |                             UPDATE'S                                  |
39  +-----------------------------------------------------------------------+
40  |   Date   |   Author  |          Description of updates                |
41  +----------+-----------+------------------------------------------------+
42  |          | 		 | 						  |
43  |          |           |						  |
44  +----------+-----------+------------------------------------------------+
45*/
46
47#include "hwdrv_apci3xxx.h"
48
49/*
50+----------------------------------------------------------------------------+
51|                         ANALOG INPUT FUNCTIONS                             |
52+----------------------------------------------------------------------------+
53*/
54
55/*
56+----------------------------------------------------------------------------+
57| Function Name     : int   i_APCI3XXX_TestConversionStarted                 |
58|                          (struct comedi_device    *dev)                           |
59+----------------------------------------------------------------------------+
60| Task                Test if any conversion started                         |
61+----------------------------------------------------------------------------+
62| Input Parameters  : -                                                      |
63+----------------------------------------------------------------------------+
64| Output Parameters : -                                                      |
65+----------------------------------------------------------------------------+
66| Return Value      : 0 : Conversion not started                             |
67|                     1 : Conversion started                                 |
68+----------------------------------------------------------------------------+
69*/
70static int i_APCI3XXX_TestConversionStarted(struct comedi_device *dev)
71{
72	if ((readl(devpriv->dw_AiBase + 8) & 0x80000UL) == 0x80000UL)
73		return 1;
74	else
75		return 0;
76
77}
78
79/*
80+----------------------------------------------------------------------------+
81| Function Name     : int   i_APCI3XXX_AnalogInputConfigOperatingMode        |
82|                          (struct comedi_device    *dev,                           |
83|                           struct comedi_subdevice *s,                             |
84|                           struct comedi_insn      *insn,                          |
85|                           unsigned int         *data)                          |
86+----------------------------------------------------------------------------+
87| Task           Converting mode and convert time selection                  |
88+----------------------------------------------------------------------------+
89| Input Parameters  : b_SingleDiff  = (unsigned char)  data[1];                       |
90|                     b_TimeBase    = (unsigned char)  data[2]; (0: ns, 1:micros 2:ms)|
91|                    dw_ReloadValue = (unsigned int) data[3];                       |
92|                     ........                                               |
93+----------------------------------------------------------------------------+
94| Output Parameters : -                                                      |
95+----------------------------------------------------------------------------+
96| Return Value      :>0 : No error                                           |
97|                    -1 : Single/Diff selection error                        |
98|                    -2 : Convert time base unity selection error            |
99|                    -3 : Convert time value selection error                 |
100|                    -10: Any conversion started                             |
101|                    ....                                                    |
102|                    -100 : Config command error                             |
103|                    -101 : Data size error                                  |
104+----------------------------------------------------------------------------+
105*/
106static int i_APCI3XXX_AnalogInputConfigOperatingMode(struct comedi_device *dev,
107						     struct comedi_subdevice *s,
108						     struct comedi_insn *insn,
109						     unsigned int *data)
110{
111	int i_ReturnValue = insn->n;
112	unsigned char b_TimeBase = 0;
113	unsigned char b_SingleDiff = 0;
114	unsigned int dw_ReloadValue = 0;
115	unsigned int dw_TestReloadValue = 0;
116
117	/************************/
118	/* Test the buffer size */
119	/************************/
120
121	if (insn->n == 4) {
122	   /****************************/
123		/* Get the Singel/Diff flag */
124	   /****************************/
125
126		b_SingleDiff = (unsigned char) data[1];
127
128	   /****************************/
129		/* Get the time base unitiy */
130	   /****************************/
131
132		b_TimeBase = (unsigned char) data[2];
133
134	   /*************************************/
135		/* Get the convert time reload value */
136	   /*************************************/
137
138		dw_ReloadValue = (unsigned int) data[3];
139
140	   /**********************/
141		/* Test the time base */
142	   /**********************/
143
144		if ((devpriv->ps_BoardInfo->
145				b_AvailableConvertUnit & (1 << b_TimeBase)) !=
146			0) {
147	      /*******************************/
148			/* Test the convert time value */
149	      /*******************************/
150
151			if (dw_ReloadValue <= 65535) {
152				dw_TestReloadValue = dw_ReloadValue;
153
154				if (b_TimeBase == 1) {
155					dw_TestReloadValue =
156						dw_TestReloadValue * 1000UL;
157				}
158				if (b_TimeBase == 2) {
159					dw_TestReloadValue =
160						dw_TestReloadValue * 1000000UL;
161				}
162
163		 /*******************************/
164				/* Test the convert time value */
165		 /*******************************/
166
167				if (dw_TestReloadValue >=
168					devpriv->ps_BoardInfo->
169					ui_MinAcquisitiontimeNs) {
170					if ((b_SingleDiff == APCI3XXX_SINGLE)
171						|| (b_SingleDiff ==
172							APCI3XXX_DIFF)) {
173						if (((b_SingleDiff == APCI3XXX_SINGLE) && (devpriv->ps_BoardInfo->i_NbrAiChannel == 0)) || ((b_SingleDiff == APCI3XXX_DIFF) && (devpriv->ps_BoardInfo->i_NbrAiChannelDiff == 0))) {
174			   /*******************************/
175							/* Single/Diff selection error */
176			   /*******************************/
177
178							printk("Single/Diff selection error\n");
179							i_ReturnValue = -1;
180						} else {
181			   /**********************************/
182							/* Test if conversion not started */
183			   /**********************************/
184
185							if (i_APCI3XXX_TestConversionStarted(dev) == 0) {
186								devpriv->
187									ui_EocEosConversionTime
188									=
189									(unsigned int)
190									dw_ReloadValue;
191								devpriv->
192									b_EocEosConversionTimeBase
193									=
194									b_TimeBase;
195								devpriv->
196									b_SingelDiff
197									=
198									b_SingleDiff;
199								devpriv->
200									b_AiInitialisation
201									= 1;
202
203			      /*******************************/
204								/* Set the convert timing unit */
205			      /*******************************/
206
207								writel((unsigned int)b_TimeBase,
208									devpriv->dw_AiBase + 36);
209
210			      /**************************/
211								/* Set the convert timing */
212			      /*************************/
213
214								writel(dw_ReloadValue, devpriv->dw_AiBase + 32);
215							} else {
216			      /**************************/
217								/* Any conversion started */
218			      /**************************/
219
220								printk("Any conversion started\n");
221								i_ReturnValue =
222									-10;
223							}
224						}
225					} else {
226		       /*******************************/
227						/* Single/Diff selection error */
228		       /*******************************/
229
230						printk("Single/Diff selection error\n");
231						i_ReturnValue = -1;
232					}
233				} else {
234		    /************************/
235					/* Time selection error */
236		    /************************/
237
238					printk("Convert time value selection error\n");
239					i_ReturnValue = -3;
240				}
241			} else {
242		 /************************/
243				/* Time selection error */
244		 /************************/
245
246				printk("Convert time value selection error\n");
247				i_ReturnValue = -3;
248			}
249		} else {
250	      /*****************************/
251			/* Time base selection error */
252	      /*****************************/
253
254			printk("Convert time base unity selection error\n");
255			i_ReturnValue = -2;
256		}
257	} else {
258	   /*******************/
259		/* Data size error */
260	   /*******************/
261
262		printk("Buffer size error\n");
263		i_ReturnValue = -101;
264	}
265
266	return i_ReturnValue;
267}
268
269/*
270+----------------------------------------------------------------------------+
271| Function Name     : int   i_APCI3XXX_InsnConfigAnalogInput                 |
272|                          (struct comedi_device    *dev,                           |
273|                           struct comedi_subdevice *s,                             |
274|                           struct comedi_insn      *insn,                          |
275|                           unsigned int         *data)                          |
276+----------------------------------------------------------------------------+
277| Task           Converting mode and convert time selection                  |
278+----------------------------------------------------------------------------+
279| Input Parameters  : b_ConvertMode = (unsigned char)  data[0];                       |
280|                     b_TimeBase    = (unsigned char)  data[1]; (0: ns, 1:micros 2:ms)|
281|                    dw_ReloadValue = (unsigned int) data[2];                       |
282|                     ........                                               |
283+----------------------------------------------------------------------------+
284| Output Parameters : -                                                      |
285+----------------------------------------------------------------------------+
286| Return Value      :>0: No error                                            |
287|                    ....                                                    |
288|                    -100 : Config command error                             |
289|                    -101 : Data size error                                  |
290+----------------------------------------------------------------------------+
291*/
292static int i_APCI3XXX_InsnConfigAnalogInput(struct comedi_device *dev,
293					    struct comedi_subdevice *s,
294					    struct comedi_insn *insn,
295					    unsigned int *data)
296{
297	int i_ReturnValue = insn->n;
298
299	/************************/
300	/* Test the buffer size */
301	/************************/
302
303	if (insn->n >= 1) {
304		switch ((unsigned char) data[0]) {
305		case APCI3XXX_CONFIGURATION:
306			i_ReturnValue =
307				i_APCI3XXX_AnalogInputConfigOperatingMode(dev,
308				s, insn, data);
309			break;
310
311		default:
312			i_ReturnValue = -100;
313			printk("Config command error %d\n", data[0]);
314			break;
315		}
316	} else {
317	   /*******************/
318		/* Data size error */
319	   /*******************/
320
321		printk("Buffer size error\n");
322		i_ReturnValue = -101;
323	}
324
325	return i_ReturnValue;
326}
327
328/*
329+----------------------------------------------------------------------------+
330| Function Name     : int   i_APCI3XXX_InsnReadAnalogInput                   |
331|                          (struct comedi_device    *dev,                           |
332|                           struct comedi_subdevice *s,                             |
333|                           struct comedi_insn      *insn,                          |
334|                           unsigned int         *data)                          |
335+----------------------------------------------------------------------------+
336| Task                Read 1 analog input                                    |
337+----------------------------------------------------------------------------+
338| Input Parameters  : b_Range             = CR_RANGE(insn->chanspec);        |
339|                     b_Channel           = CR_CHAN(insn->chanspec);         |
340|                     dw_NbrOfAcquisition = insn->n;                         |
341+----------------------------------------------------------------------------+
342| Output Parameters : -                                                      |
343+----------------------------------------------------------------------------+
344| Return Value      :>0: No error                                            |
345|                    -3 : Channel selection error                            |
346|                    -4 : Configuration selelection error                    |
347|                    -10: Any conversion started                             |
348|                    ....                                                    |
349|                    -100 : Config command error                             |
350|                    -101 : Data size error                                  |
351+----------------------------------------------------------------------------+
352*/
353static int i_APCI3XXX_InsnReadAnalogInput(struct comedi_device *dev,
354					  struct comedi_subdevice *s,
355					  struct comedi_insn *insn,
356					  unsigned int *data)
357{
358	int i_ReturnValue = insn->n;
359	unsigned char b_Configuration = (unsigned char) CR_RANGE(insn->chanspec);
360	unsigned char b_Channel = (unsigned char) CR_CHAN(insn->chanspec);
361	unsigned int dw_Temp = 0;
362	unsigned int dw_Configuration = 0;
363	unsigned int dw_AcquisitionCpt = 0;
364	unsigned char b_Interrupt = 0;
365
366	/*************************************/
367	/* Test if operating mode configured */
368	/*************************************/
369
370	if (devpriv->b_AiInitialisation) {
371	   /***************************/
372		/* Test the channel number */
373	   /***************************/
374
375		if (((b_Channel < devpriv->ps_BoardInfo->i_NbrAiChannel)
376				&& (devpriv->b_SingelDiff == APCI3XXX_SINGLE))
377			|| ((b_Channel < devpriv->ps_BoardInfo->
378					i_NbrAiChannelDiff)
379				&& (devpriv->b_SingelDiff == APCI3XXX_DIFF))) {
380	      /**********************************/
381			/* Test the channel configuration */
382	      /**********************************/
383
384			if (b_Configuration > 7) {
385		 /***************************/
386				/* Channel not initialised */
387		 /***************************/
388
389				i_ReturnValue = -4;
390				printk("Channel %d range %d selection error\n",
391					b_Channel, b_Configuration);
392			}
393		} else {
394	      /***************************/
395			/* Channel selection error */
396	      /***************************/
397
398			i_ReturnValue = -3;
399			printk("Channel %d selection error\n", b_Channel);
400		}
401
402	   /**************************/
403		/* Test if no error occur */
404	   /**************************/
405
406		if (i_ReturnValue >= 0) {
407	      /************************/
408			/* Test the buffer size */
409	      /************************/
410
411			if ((b_Interrupt != 0) || ((b_Interrupt == 0)
412					&& (insn->n >= 1))) {
413		 /**********************************/
414				/* Test if conversion not started */
415		 /**********************************/
416
417				if (i_APCI3XXX_TestConversionStarted(dev) == 0) {
418		    /******************/
419					/* Clear the FIFO */
420		    /******************/
421
422					writel(0x10000UL, devpriv->dw_AiBase + 12);
423
424		    /*******************************/
425					/* Get and save the delay mode */
426		    /*******************************/
427
428					dw_Temp = readl(devpriv->dw_AiBase + 4);
429					dw_Temp = dw_Temp & 0xFFFFFEF0UL;
430
431		    /***********************************/
432					/* Channel configuration selection */
433		    /***********************************/
434
435					writel(dw_Temp, devpriv->dw_AiBase + 4);
436
437		    /**************************/
438					/* Make the configuration */
439		    /**************************/
440
441					dw_Configuration =
442						(b_Configuration & 3) |
443						((unsigned int) (b_Configuration >> 2)
444						<< 6) | ((unsigned int) devpriv->
445						b_SingelDiff << 7);
446
447		    /***************************/
448					/* Write the configuration */
449		    /***************************/
450
451					writel(dw_Configuration,
452					       devpriv->dw_AiBase + 0);
453
454		    /*********************/
455					/* Channel selection */
456		    /*********************/
457
458					writel(dw_Temp | 0x100UL,
459					       devpriv->dw_AiBase + 4);
460					writel((unsigned int) b_Channel,
461					       devpriv->dw_AiBase + 0);
462
463		    /***********************/
464					/* Restaure delay mode */
465		    /***********************/
466
467					writel(dw_Temp, devpriv->dw_AiBase + 4);
468
469		    /***********************************/
470					/* Set the number of sequence to 1 */
471		    /***********************************/
472
473					writel(1, devpriv->dw_AiBase + 48);
474
475		    /***************************/
476					/* Save the interrupt flag */
477		    /***************************/
478
479					devpriv->b_EocEosInterrupt =
480						b_Interrupt;
481
482		    /*******************************/
483					/* Save the number of channels */
484		    /*******************************/
485
486					devpriv->ui_AiNbrofChannels = 1;
487
488		    /******************************/
489					/* Test if interrupt not used */
490		    /******************************/
491
492					if (b_Interrupt == 0) {
493						for (dw_AcquisitionCpt = 0;
494							dw_AcquisitionCpt <
495							insn->n;
496							dw_AcquisitionCpt++) {
497			  /************************/
498							/* Start the conversion */
499			  /************************/
500
501							writel(0x80000UL, devpriv->dw_AiBase + 8);
502
503			  /****************/
504							/* Wait the EOS */
505			  /****************/
506
507							do {
508								dw_Temp = readl(devpriv->dw_AiBase + 20);
509								dw_Temp = dw_Temp & 1;
510							} while (dw_Temp != 1);
511
512			  /*************************/
513							/* Read the analog value */
514			  /*************************/
515
516							data[dw_AcquisitionCpt] = (unsigned int)readl(devpriv->dw_AiBase + 28);
517						}
518					} else {
519		       /************************/
520						/* Start the conversion */
521		       /************************/
522
523						writel(0x180000UL, devpriv->dw_AiBase + 8);
524					}
525				} else {
526		    /**************************/
527					/* Any conversion started */
528		    /**************************/
529
530					printk("Any conversion started\n");
531					i_ReturnValue = -10;
532				}
533			} else {
534		 /*******************/
535				/* Data size error */
536		 /*******************/
537
538				printk("Buffer size error\n");
539				i_ReturnValue = -101;
540			}
541		}
542	} else {
543	   /***************************/
544		/* Channel selection error */
545	   /***************************/
546
547		printk("Operating mode not configured\n");
548		i_ReturnValue = -1;
549	}
550	return i_ReturnValue;
551}
552
553/*
554+----------------------------------------------------------------------------+
555| Function name     : void v_APCI3XXX_Interrupt (int            irq,         |
556|                                                void           *d)       |
557+----------------------------------------------------------------------------+
558| Task              :Interrupt handler for APCI3XXX                          |
559|                    When interrupt occurs this gets called.                 |
560|                    First it finds which interrupt has been generated and   |
561|                    handles  corresponding interrupt                        |
562+----------------------------------------------------------------------------+
563| Input Parameters  : -                                                      |
564+----------------------------------------------------------------------------+
565| Return Value      : -                                                      |
566+----------------------------------------------------------------------------+
567*/
568
569static void v_APCI3XXX_Interrupt(int irq, void *d)
570{
571	struct comedi_device *dev = d;
572	unsigned char b_CopyCpt = 0;
573	unsigned int dw_Status = 0;
574
575	/***************************/
576	/* Test if interrupt occur */
577	/***************************/
578
579	dw_Status = readl(devpriv->dw_AiBase + 16);
580	if ( (dw_Status & 0x2UL) == 0x2UL) {
581	   /***********************/
582		/* Reset the interrupt */
583	   /***********************/
584
585		writel(dw_Status, devpriv->dw_AiBase + 16);
586
587	   /*****************************/
588		/* Test if interrupt enabled */
589	   /*****************************/
590
591		if (devpriv->b_EocEosInterrupt == 1) {
592	      /********************************/
593			/* Read all analog inputs value */
594	      /********************************/
595
596			for (b_CopyCpt = 0;
597				b_CopyCpt < devpriv->ui_AiNbrofChannels;
598				b_CopyCpt++) {
599				devpriv->ui_AiReadData[b_CopyCpt] =
600					(unsigned int)readl(devpriv->dw_AiBase + 28);
601			}
602
603	      /**************************/
604			/* Set the interrupt flag */
605	      /**************************/
606
607			devpriv->b_EocEosInterrupt = 2;
608
609	      /**********************************************/
610			/* Send a signal to from kernel to user space */
611	      /**********************************************/
612
613			send_sig(SIGIO, devpriv->tsk_Current, 0);
614		}
615	}
616}
617
618/*
619+----------------------------------------------------------------------------+
620|                            ANALOG OUTPUT SUBDEVICE                         |
621+----------------------------------------------------------------------------+
622*/
623
624/*
625+----------------------------------------------------------------------------+
626| Function Name     : int   i_APCI3XXX_InsnWriteAnalogOutput                 |
627|                          (struct comedi_device    *dev,                           |
628|                           struct comedi_subdevice *s,                             |
629|                           struct comedi_insn      *insn,                          |
630|                           unsigned int         *data)                          |
631+----------------------------------------------------------------------------+
632| Task                Read 1 analog input                                    |
633+----------------------------------------------------------------------------+
634| Input Parameters  : b_Range    = CR_RANGE(insn->chanspec);                 |
635|                     b_Channel  = CR_CHAN(insn->chanspec);                  |
636|                     data[0]    = analog value;                             |
637+----------------------------------------------------------------------------+
638| Output Parameters : -                                                      |
639+----------------------------------------------------------------------------+
640| Return Value      :>0: No error                                            |
641|                    -3 : Channel selection error                            |
642|                    -4 : Configuration selelection error                    |
643|                    ....                                                    |
644|                    -101 : Data size error                                  |
645+----------------------------------------------------------------------------+
646*/
647static int i_APCI3XXX_InsnWriteAnalogOutput(struct comedi_device *dev,
648					    struct comedi_subdevice *s,
649					    struct comedi_insn *insn,
650					    unsigned int *data)
651{
652	unsigned char b_Range = (unsigned char) CR_RANGE(insn->chanspec);
653	unsigned char b_Channel = (unsigned char) CR_CHAN(insn->chanspec);
654	unsigned int dw_Status = 0;
655	int i_ReturnValue = insn->n;
656
657	/************************/
658	/* Test the buffer size */
659	/************************/
660
661	if (insn->n >= 1) {
662	   /***************************/
663		/* Test the channel number */
664	   /***************************/
665
666		if (b_Channel < devpriv->ps_BoardInfo->i_NbrAoChannel) {
667	      /**********************************/
668			/* Test the channel configuration */
669	      /**********************************/
670
671			if (b_Range < 2) {
672		 /***************************/
673				/* Set the range selection */
674		 /***************************/
675
676				writel(b_Range, devpriv->dw_AiBase + 96);
677
678		 /**************************************************/
679				/* Write the analog value to the selected channel */
680		 /**************************************************/
681
682				writel((data[0] << 8) | b_Channel,
683					devpriv->dw_AiBase + 100);
684
685		 /****************************/
686				/* Wait the end of transfer */
687		 /****************************/
688
689				do {
690					dw_Status = readl(devpriv->dw_AiBase + 96);
691				} while ((dw_Status & 0x100) != 0x100);
692			} else {
693		 /***************************/
694				/* Channel not initialised */
695		 /***************************/
696
697				i_ReturnValue = -4;
698				printk("Channel %d range %d selection error\n",
699					b_Channel, b_Range);
700			}
701		} else {
702	      /***************************/
703			/* Channel selection error */
704	      /***************************/
705
706			i_ReturnValue = -3;
707			printk("Channel %d selection error\n", b_Channel);
708		}
709	} else {
710	   /*******************/
711		/* Data size error */
712	   /*******************/
713
714		printk("Buffer size error\n");
715		i_ReturnValue = -101;
716	}
717
718	return i_ReturnValue;
719}
720
721/*
722+----------------------------------------------------------------------------+
723|                              TTL FUNCTIONS                                 |
724+----------------------------------------------------------------------------+
725*/
726
727/*
728+----------------------------------------------------------------------------+
729| Function Name     : int   i_APCI3XXX_InsnConfigInitTTLIO                   |
730|                          (struct comedi_device    *dev,                           |
731|                           struct comedi_subdevice *s,                             |
732|                           struct comedi_insn      *insn,                          |
733|                           unsigned int         *data)                          |
734+----------------------------------------------------------------------------+
735| Task           You must calling this function be                           |
736|                for you call any other function witch access of TTL.        |
737|                APCI3XXX_TTL_INIT_DIRECTION_PORT2(user inputs for direction)|
738+----------------------------------------------------------------------------+
739| Input Parameters  : b_InitType    = (unsigned char) data[0];                        |
740|                     b_Port2Mode   = (unsigned char) data[1];                        |
741+----------------------------------------------------------------------------+
742| Output Parameters : -                                                      |
743+----------------------------------------------------------------------------+
744| Return Value      :>0: No error                                            |
745|                    -1: Port 2 mode selection is wrong                      |
746|                    ....                                                    |
747|                    -100 : Config command error                             |
748|                    -101 : Data size error                                  |
749+----------------------------------------------------------------------------+
750*/
751static int i_APCI3XXX_InsnConfigInitTTLIO(struct comedi_device *dev,
752					  struct comedi_subdevice *s,
753					  struct comedi_insn *insn,
754					  unsigned int *data)
755{
756	int i_ReturnValue = insn->n;
757	unsigned char b_Command = 0;
758
759	/************************/
760	/* Test the buffer size */
761	/************************/
762
763	if (insn->n >= 1) {
764	   /*******************/
765		/* Get the command */
766		/* **************** */
767
768		b_Command = (unsigned char) data[0];
769
770	   /********************/
771		/* Test the command */
772	   /********************/
773
774		if (b_Command == APCI3XXX_TTL_INIT_DIRECTION_PORT2) {
775	      /***************************************/
776			/* Test the initialisation buffer size */
777	      /***************************************/
778
779			if ((b_Command == APCI3XXX_TTL_INIT_DIRECTION_PORT2)
780				&& (insn->n != 2)) {
781		 /*******************/
782				/* Data size error */
783		 /*******************/
784
785				printk("Buffer size error\n");
786				i_ReturnValue = -101;
787			}
788		} else {
789	      /************************/
790			/* Config command error */
791	      /************************/
792
793			printk("Command selection error\n");
794			i_ReturnValue = -100;
795		}
796	} else {
797	   /*******************/
798		/* Data size error */
799	   /*******************/
800
801		printk("Buffer size error\n");
802		i_ReturnValue = -101;
803	}
804
805	/*********************************************************************************/
806	/* Test if no error occur and APCI3XXX_TTL_INIT_DIRECTION_PORT2 command selected */
807	/*********************************************************************************/
808
809	if ((i_ReturnValue >= 0)
810		&& (b_Command == APCI3XXX_TTL_INIT_DIRECTION_PORT2)) {
811	   /**********************/
812		/* Test the direction */
813	   /**********************/
814
815		if ((data[1] == 0) || (data[1] == 0xFF)) {
816	      /**************************/
817			/* Save the configuration */
818	      /**************************/
819
820			devpriv->ul_TTLPortConfiguration[0] =
821				devpriv->ul_TTLPortConfiguration[0] | data[1];
822		} else {
823	      /************************/
824			/* Port direction error */
825	      /************************/
826
827			printk("Port 2 direction selection error\n");
828			i_ReturnValue = -1;
829		}
830	}
831
832	/**************************/
833	/* Test if no error occur */
834	/**************************/
835
836	if (i_ReturnValue >= 0) {
837	   /***********************************/
838		/* Test if TTL port initilaisation */
839	   /***********************************/
840
841		if (b_Command == APCI3XXX_TTL_INIT_DIRECTION_PORT2) {
842	      /*************************/
843			/* Set the configuration */
844	      /*************************/
845
846			outl(data[1], devpriv->iobase + 224);
847		}
848	}
849
850	return i_ReturnValue;
851}
852
853/*
854+----------------------------------------------------------------------------+
855|                        TTL INPUT FUNCTIONS                                 |
856+----------------------------------------------------------------------------+
857*/
858
859/*
860+----------------------------------------------------------------------------+
861| Function Name     : int     i_APCI3XXX_InsnBitsTTLIO                       |
862|                          (struct comedi_device    *dev,                           |
863|                           struct comedi_subdevice *s,                             |
864|                           struct comedi_insn      *insn,                          |
865|                           unsigned int         *data)                          |
866+----------------------------------------------------------------------------+
867| Task              : Write the selected output mask and read the status from|
868|                     all TTL channles                                       |
869+----------------------------------------------------------------------------+
870| Input Parameters  : dw_ChannelMask = data [0];                             |
871|                     dw_BitMask     = data [1];                             |
872+----------------------------------------------------------------------------+
873| Output Parameters : data[1] : All TTL channles states                      |
874+----------------------------------------------------------------------------+
875| Return Value      : >0  : No error                                         |
876|                    -4   : Channel mask error                               |
877|                    -101 : Data size error                                  |
878+----------------------------------------------------------------------------+
879*/
880static int i_APCI3XXX_InsnBitsTTLIO(struct comedi_device *dev,
881				    struct comedi_subdevice *s,
882				    struct comedi_insn *insn,
883				    unsigned int *data)
884{
885	int i_ReturnValue = insn->n;
886	unsigned char b_ChannelCpt = 0;
887	unsigned int dw_ChannelMask = 0;
888	unsigned int dw_BitMask = 0;
889	unsigned int dw_Status = 0;
890
891	/************************/
892	/* Test the buffer size */
893	/************************/
894
895	if (insn->n >= 2) {
896	   /*******************************/
897		/* Get the channe and bit mask */
898	   /*******************************/
899
900		dw_ChannelMask = data[0];
901		dw_BitMask = data[1];
902
903	   /*************************/
904		/* Test the channel mask */
905	   /*************************/
906
907		if (((dw_ChannelMask & 0XFF00FF00) == 0) &&
908			(((devpriv->ul_TTLPortConfiguration[0] & 0xFF) == 0xFF)
909				|| (((devpriv->ul_TTLPortConfiguration[0] &
910							0xFF) == 0)
911					&& ((dw_ChannelMask & 0XFF0000) ==
912						0)))) {
913	      /*********************************/
914			/* Test if set/reset any channel */
915	      /*********************************/
916
917			if (dw_ChannelMask) {
918		 /****************************************/
919				/* Test if set/rest any port 0 channels */
920		 /****************************************/
921
922				if (dw_ChannelMask & 0xFF) {
923		    /*******************************************/
924					/* Read port 0 (first digital output port) */
925		    /*******************************************/
926
927					dw_Status = inl(devpriv->iobase + 80);
928
929					for (b_ChannelCpt = 0; b_ChannelCpt < 8;
930						b_ChannelCpt++) {
931						if ((dw_ChannelMask >>
932								b_ChannelCpt) &
933							1) {
934							dw_Status =
935								(dw_Status &
936								(0xFF - (1 << b_ChannelCpt))) | (dw_BitMask & (1 << b_ChannelCpt));
937						}
938					}
939
940					outl(dw_Status, devpriv->iobase + 80);
941				}
942
943		 /****************************************/
944				/* Test if set/rest any port 2 channels */
945		 /****************************************/
946
947				if (dw_ChannelMask & 0xFF0000) {
948					dw_BitMask = dw_BitMask >> 16;
949					dw_ChannelMask = dw_ChannelMask >> 16;
950
951		    /********************************************/
952					/* Read port 2 (second digital output port) */
953		    /********************************************/
954
955					dw_Status = inl(devpriv->iobase + 112);
956
957					for (b_ChannelCpt = 0; b_ChannelCpt < 8;
958						b_ChannelCpt++) {
959						if ((dw_ChannelMask >>
960								b_ChannelCpt) &
961							1) {
962							dw_Status =
963								(dw_Status &
964								(0xFF - (1 << b_ChannelCpt))) | (dw_BitMask & (1 << b_ChannelCpt));
965						}
966					}
967
968					outl(dw_Status, devpriv->iobase + 112);
969				}
970			}
971
972	      /*******************************************/
973			/* Read port 0 (first digital output port) */
974	      /*******************************************/
975
976			data[1] = inl(devpriv->iobase + 80);
977
978	      /******************************************/
979			/* Read port 1 (first digital input port) */
980	      /******************************************/
981
982			data[1] = data[1] | (inl(devpriv->iobase + 64) << 8);
983
984	      /************************/
985			/* Test if port 2 input */
986	      /************************/
987
988			if ((devpriv->ul_TTLPortConfiguration[0] & 0xFF) == 0) {
989				data[1] =
990					data[1] | (inl(devpriv->iobase +
991						96) << 16);
992			} else {
993				data[1] =
994					data[1] | (inl(devpriv->iobase +
995						112) << 16);
996			}
997		} else {
998	      /************************/
999			/* Config command error */
1000	      /************************/
1001
1002			printk("Channel mask error\n");
1003			i_ReturnValue = -4;
1004		}
1005	} else {
1006	   /*******************/
1007		/* Data size error */
1008	   /*******************/
1009
1010		printk("Buffer size error\n");
1011		i_ReturnValue = -101;
1012	}
1013
1014	return i_ReturnValue;
1015}
1016
1017/*
1018+----------------------------------------------------------------------------+
1019| Function Name     : int i_APCI3XXX_InsnReadTTLIO                           |
1020|                          (struct comedi_device    *dev,                           |
1021|                           struct comedi_subdevice *s,                             |
1022|                           struct comedi_insn      *insn,                          |
1023|                           unsigned int         *data)                          |
1024+----------------------------------------------------------------------------+
1025| Task              : Read the status from selected channel                  |
1026+----------------------------------------------------------------------------+
1027| Input Parameters  : b_Channel = CR_CHAN(insn->chanspec)                    |
1028+----------------------------------------------------------------------------+
1029| Output Parameters : data[0] : Selected TTL channel state                   |
1030+----------------------------------------------------------------------------+
1031| Return Value      : 0   : No error                                         |
1032|                    -3   : Channel selection error                          |
1033|                    -101 : Data size error                                  |
1034+----------------------------------------------------------------------------+
1035*/
1036static int i_APCI3XXX_InsnReadTTLIO(struct comedi_device *dev,
1037				    struct comedi_subdevice *s,
1038				    struct comedi_insn *insn,
1039				    unsigned int *data)
1040{
1041	unsigned char b_Channel = (unsigned char) CR_CHAN(insn->chanspec);
1042	int i_ReturnValue = insn->n;
1043	unsigned int *pls_ReadData = data;
1044
1045	/************************/
1046	/* Test the buffer size */
1047	/************************/
1048
1049	if (insn->n >= 1) {
1050	   /***********************/
1051		/* Test if read port 0 */
1052	   /***********************/
1053
1054		if (b_Channel < 8) {
1055	      /*******************************************/
1056			/* Read port 0 (first digital output port) */
1057	      /*******************************************/
1058
1059			pls_ReadData[0] = inl(devpriv->iobase + 80);
1060			pls_ReadData[0] = (pls_ReadData[0] >> b_Channel) & 1;
1061		} else {
1062	      /***********************/
1063			/* Test if read port 1 */
1064	      /***********************/
1065
1066			if ((b_Channel > 7) && (b_Channel < 16)) {
1067		 /******************************************/
1068				/* Read port 1 (first digital input port) */
1069		 /******************************************/
1070
1071				pls_ReadData[0] = inl(devpriv->iobase + 64);
1072				pls_ReadData[0] =
1073					(pls_ReadData[0] >> (b_Channel -
1074						8)) & 1;
1075			} else {
1076		 /***********************/
1077				/* Test if read port 2 */
1078		 /***********************/
1079
1080				if ((b_Channel > 15) && (b_Channel < 24)) {
1081		    /************************/
1082					/* Test if port 2 input */
1083		    /************************/
1084
1085					if ((devpriv->ul_TTLPortConfiguration[0]
1086							& 0xFF) == 0) {
1087						pls_ReadData[0] =
1088							inl(devpriv->iobase +
1089							96);
1090						pls_ReadData[0] =
1091							(pls_ReadData[0] >>
1092							(b_Channel - 16)) & 1;
1093					} else {
1094						pls_ReadData[0] =
1095							inl(devpriv->iobase +
1096							112);
1097						pls_ReadData[0] =
1098							(pls_ReadData[0] >>
1099							(b_Channel - 16)) & 1;
1100					}
1101				} else {
1102		    /***************************/
1103					/* Channel selection error */
1104		    /***************************/
1105
1106					i_ReturnValue = -3;
1107					printk("Channel %d selection error\n",
1108						b_Channel);
1109				}
1110			}
1111		}
1112	} else {
1113	   /*******************/
1114		/* Data size error */
1115	   /*******************/
1116
1117		printk("Buffer size error\n");
1118		i_ReturnValue = -101;
1119	}
1120
1121	return i_ReturnValue;
1122}
1123
1124/*
1125+----------------------------------------------------------------------------+
1126|                        TTL OUTPUT FUNCTIONS                                |
1127+----------------------------------------------------------------------------+
1128*/
1129
1130/*
1131+----------------------------------------------------------------------------+
1132| Function Name     : int     i_APCI3XXX_InsnWriteTTLIO                      |
1133|                          (struct comedi_device    *dev,                           |
1134|                           struct comedi_subdevice *s,                             |
1135|                           struct comedi_insn      *insn,                          |
1136|                           unsigned int         *data)                          |
1137+----------------------------------------------------------------------------+
1138| Task              : Set the state from TTL output channel                  |
1139+----------------------------------------------------------------------------+
1140| Input Parameters  : b_Channel = CR_CHAN(insn->chanspec)                    |
1141|                     b_State   = data [0]                                   |
1142+----------------------------------------------------------------------------+
1143| Output Parameters : -                                                      |
1144+----------------------------------------------------------------------------+
1145| Return Value      : 0   : No error                                         |
1146|                    -3   : Channel selection error                          |
1147|                    -101 : Data size error                                  |
1148+----------------------------------------------------------------------------+
1149*/
1150static int i_APCI3XXX_InsnWriteTTLIO(struct comedi_device *dev,
1151				     struct comedi_subdevice *s,
1152				     struct comedi_insn *insn,
1153				     unsigned int *data)
1154{
1155	int i_ReturnValue = insn->n;
1156	unsigned char b_Channel = (unsigned char) CR_CHAN(insn->chanspec);
1157	unsigned char b_State = 0;
1158	unsigned int dw_Status = 0;
1159
1160	/************************/
1161	/* Test the buffer size */
1162	/************************/
1163
1164	if (insn->n >= 1) {
1165		b_State = (unsigned char) data[0];
1166
1167	   /***********************/
1168		/* Test if read port 0 */
1169	   /***********************/
1170
1171		if (b_Channel < 8) {
1172	      /*****************************************************************************/
1173			/* Read port 0 (first digital output port) and set/reset the selected channel */
1174	      /*****************************************************************************/
1175
1176			dw_Status = inl(devpriv->iobase + 80);
1177			dw_Status =
1178				(dw_Status & (0xFF -
1179					(1 << b_Channel))) | ((b_State & 1) <<
1180				b_Channel);
1181			outl(dw_Status, devpriv->iobase + 80);
1182		} else {
1183	      /***********************/
1184			/* Test if read port 2 */
1185	      /***********************/
1186
1187			if ((b_Channel > 15) && (b_Channel < 24)) {
1188		 /*************************/
1189				/* Test if port 2 output */
1190		 /*************************/
1191
1192				if ((devpriv->ul_TTLPortConfiguration[0] & 0xFF)
1193					== 0xFF) {
1194		    /*****************************************************************************/
1195					/* Read port 2 (first digital output port) and set/reset the selected channel */
1196		    /*****************************************************************************/
1197
1198					dw_Status = inl(devpriv->iobase + 112);
1199					dw_Status =
1200						(dw_Status & (0xFF -
1201							(1 << (b_Channel -
1202									16)))) |
1203						((b_State & 1) << (b_Channel -
1204							16));
1205					outl(dw_Status, devpriv->iobase + 112);
1206				} else {
1207		    /***************************/
1208					/* Channel selection error */
1209		    /***************************/
1210
1211					i_ReturnValue = -3;
1212					printk("Channel %d selection error\n",
1213						b_Channel);
1214				}
1215			} else {
1216		 /***************************/
1217				/* Channel selection error */
1218		 /***************************/
1219
1220				i_ReturnValue = -3;
1221				printk("Channel %d selection error\n",
1222					b_Channel);
1223			}
1224		}
1225	} else {
1226	   /*******************/
1227		/* Data size error */
1228	   /*******************/
1229
1230		printk("Buffer size error\n");
1231		i_ReturnValue = -101;
1232	}
1233
1234	return i_ReturnValue;
1235}
1236
1237/*
1238+----------------------------------------------------------------------------+
1239|                           DIGITAL INPUT SUBDEVICE                          |
1240+----------------------------------------------------------------------------+
1241*/
1242
1243/*
1244+----------------------------------------------------------------------------+
1245| Function name     :int i_APCI3XXX_InsnReadDigitalInput                     |
1246|                                          (struct comedi_device *dev,              |
1247|                                           struct comedi_subdevice *s,             |
1248|                                           struct comedi_insn *insn,               |
1249|                                           unsigned int *data)                  |
1250+----------------------------------------------------------------------------+
1251| Task              : Reads the value of the specified Digital input channel |
1252+----------------------------------------------------------------------------+
1253| Input Parameters  : b_Channel = CR_CHAN(insn->chanspec) (0 to 3)           |
1254+----------------------------------------------------------------------------+
1255| Output Parameters : data[0] : Channel value                                |
1256+----------------------------------------------------------------------------+
1257| Return Value      : 0   : No error                                         |
1258|                    -3   : Channel selection error                          |
1259|                    -101 : Data size error                                  |
1260+----------------------------------------------------------------------------+
1261*/
1262
1263static int i_APCI3XXX_InsnReadDigitalInput(struct comedi_device *dev,
1264					   struct comedi_subdevice *s,
1265					   struct comedi_insn *insn,
1266					   unsigned int *data)
1267{
1268	int i_ReturnValue = insn->n;
1269	unsigned char b_Channel = (unsigned char) CR_CHAN(insn->chanspec);
1270	unsigned int dw_Temp = 0;
1271
1272	/***************************/
1273	/* Test the channel number */
1274	/***************************/
1275
1276	if (b_Channel <= devpriv->ps_BoardInfo->i_NbrDiChannel) {
1277	   /************************/
1278		/* Test the buffer size */
1279	   /************************/
1280
1281		if (insn->n >= 1) {
1282			dw_Temp = inl(devpriv->iobase + 32);
1283			*data = (dw_Temp >> b_Channel) & 1;
1284		} else {
1285	      /*******************/
1286			/* Data size error */
1287	      /*******************/
1288
1289			printk("Buffer size error\n");
1290			i_ReturnValue = -101;
1291		}
1292	} else {
1293	   /***************************/
1294		/* Channel selection error */
1295	   /***************************/
1296
1297		printk("Channel selection error\n");
1298		i_ReturnValue = -3;
1299	}
1300
1301	return i_ReturnValue;
1302}
1303
1304/*
1305+----------------------------------------------------------------------------+
1306| Function name     :int i_APCI3XXX_InsnBitsDigitalInput                     |
1307|                                          (struct comedi_device *dev,              |
1308|                                           struct comedi_subdevice *s,             |
1309|                                           struct comedi_insn *insn,               |
1310|                                           unsigned int *data)                  |
1311+----------------------------------------------------------------------------+
1312| Task              : Reads the value of the Digital input Port i.e.4channels|
1313+----------------------------------------------------------------------------+
1314| Input Parameters  : -                                                      |
1315+----------------------------------------------------------------------------+
1316| Output Parameters : data[0] : Port value                                   |
1317+----------------------------------------------------------------------------+
1318| Return Value      :>0: No error                                            |
1319|                    ....                                                    |
1320|                    -101 : Data size error                                  |
1321+----------------------------------------------------------------------------+
1322*/
1323static int i_APCI3XXX_InsnBitsDigitalInput(struct comedi_device *dev,
1324					   struct comedi_subdevice *s,
1325					   struct comedi_insn *insn,
1326					   unsigned int *data)
1327{
1328	int i_ReturnValue = insn->n;
1329	unsigned int dw_Temp = 0;
1330
1331	/************************/
1332	/* Test the buffer size */
1333	/************************/
1334
1335	if (insn->n >= 1) {
1336		dw_Temp = inl(devpriv->iobase + 32);
1337		*data = dw_Temp & 0xf;
1338	} else {
1339	   /*******************/
1340		/* Data size error */
1341	   /*******************/
1342
1343		printk("Buffer size error\n");
1344		i_ReturnValue = -101;
1345	}
1346
1347	return i_ReturnValue;
1348}
1349
1350/*
1351+----------------------------------------------------------------------------+
1352|                           DIGITAL OUTPUT SUBDEVICE                         |
1353+----------------------------------------------------------------------------+
1354
1355*/
1356
1357/*
1358+----------------------------------------------------------------------------+
1359| Function name     :int i_APCI3XXX_InsnBitsDigitalOutput                    |
1360|                                          (struct comedi_device *dev,              |
1361|                                           struct comedi_subdevice *s,             |
1362|                                           struct comedi_insn *insn,               |
1363|                                           unsigned int *data)                  |
1364+----------------------------------------------------------------------------+
1365| Task              : Write the selected output mask and read the status from|
1366|                     all digital output channles                            |
1367+----------------------------------------------------------------------------+
1368| Input Parameters  : dw_ChannelMask = data [0];                             |
1369|                     dw_BitMask     = data [1];                             |
1370+----------------------------------------------------------------------------+
1371| Output Parameters : data[1] : All digital output channles states           |
1372+----------------------------------------------------------------------------+
1373| Return Value      : >0  : No error                                         |
1374|                    -4   : Channel mask error                               |
1375|                    -101 : Data size error                                  |
1376+----------------------------------------------------------------------------+
1377*/
1378static int i_APCI3XXX_InsnBitsDigitalOutput(struct comedi_device *dev,
1379					    struct comedi_subdevice *s,
1380					    struct comedi_insn *insn,
1381					    unsigned int *data)
1382{
1383	int i_ReturnValue = insn->n;
1384	unsigned char b_ChannelCpt = 0;
1385	unsigned int dw_ChannelMask = 0;
1386	unsigned int dw_BitMask = 0;
1387	unsigned int dw_Status = 0;
1388
1389	/************************/
1390	/* Test the buffer size */
1391	/************************/
1392
1393	if (insn->n >= 2) {
1394	   /*******************************/
1395		/* Get the channe and bit mask */
1396	   /*******************************/
1397
1398		dw_ChannelMask = data[0];
1399		dw_BitMask = data[1];
1400
1401	   /*************************/
1402		/* Test the channel mask */
1403	   /*************************/
1404
1405		if ((dw_ChannelMask & 0XFFFFFFF0) == 0) {
1406	      /*********************************/
1407			/* Test if set/reset any channel */
1408	      /*********************************/
1409
1410			if (dw_ChannelMask & 0xF) {
1411		 /********************************/
1412				/* Read the digital output port */
1413		 /********************************/
1414
1415				dw_Status = inl(devpriv->iobase + 48);
1416
1417				for (b_ChannelCpt = 0; b_ChannelCpt < 4;
1418					b_ChannelCpt++) {
1419					if ((dw_ChannelMask >> b_ChannelCpt) &
1420						1) {
1421						dw_Status =
1422							(dw_Status & (0xF -
1423								(1 << b_ChannelCpt))) | (dw_BitMask & (1 << b_ChannelCpt));
1424					}
1425				}
1426
1427				outl(dw_Status, devpriv->iobase + 48);
1428			}
1429
1430	      /********************************/
1431			/* Read the digital output port */
1432	      /********************************/
1433
1434			data[1] = inl(devpriv->iobase + 48);
1435		} else {
1436	      /************************/
1437			/* Config command error */
1438	      /************************/
1439
1440			printk("Channel mask error\n");
1441			i_ReturnValue = -4;
1442		}
1443	} else {
1444	   /*******************/
1445		/* Data size error */
1446	   /*******************/
1447
1448		printk("Buffer size error\n");
1449		i_ReturnValue = -101;
1450	}
1451
1452	return i_ReturnValue;
1453}
1454
1455/*
1456+----------------------------------------------------------------------------+
1457| Function name     :int i_APCI3XXX_InsnWriteDigitalOutput                   |
1458|                                          (struct comedi_device *dev,              |
1459|                                           struct comedi_subdevice *s,             |
1460|                                           struct comedi_insn *insn,               |
1461|                                           unsigned int *data)                  |
1462+----------------------------------------------------------------------------+
1463| Task              : Set the state from digital output channel              |
1464+----------------------------------------------------------------------------+
1465| Input Parameters  : b_Channel = CR_CHAN(insn->chanspec)                    |
1466|                     b_State   = data [0]                                   |
1467+----------------------------------------------------------------------------+
1468| Output Parameters : -                                                      |
1469+----------------------------------------------------------------------------+
1470| Return Value      : >0  : No error                                         |
1471|                    -3   : Channel selection error                          |
1472|                    -101 : Data size error                                  |
1473+----------------------------------------------------------------------------+
1474*/
1475
1476static int i_APCI3XXX_InsnWriteDigitalOutput(struct comedi_device *dev,
1477					     struct comedi_subdevice *s,
1478					     struct comedi_insn *insn,
1479					     unsigned int *data)
1480{
1481	int i_ReturnValue = insn->n;
1482	unsigned char b_Channel = CR_CHAN(insn->chanspec);
1483	unsigned char b_State = 0;
1484	unsigned int dw_Status = 0;
1485
1486	/************************/
1487	/* Test the buffer size */
1488	/************************/
1489
1490	if (insn->n >= 1) {
1491	   /***************************/
1492		/* Test the channel number */
1493	   /***************************/
1494
1495		if (b_Channel < devpriv->ps_BoardInfo->i_NbrDoChannel) {
1496	      /*******************/
1497			/* Get the command */
1498	      /*******************/
1499
1500			b_State = (unsigned char) data[0];
1501
1502	      /********************************/
1503			/* Read the digital output port */
1504	      /********************************/
1505
1506			dw_Status = inl(devpriv->iobase + 48);
1507
1508			dw_Status =
1509				(dw_Status & (0xF -
1510					(1 << b_Channel))) | ((b_State & 1) <<
1511				b_Channel);
1512			outl(dw_Status, devpriv->iobase + 48);
1513		} else {
1514	      /***************************/
1515			/* Channel selection error */
1516	      /***************************/
1517
1518			printk("Channel selection error\n");
1519			i_ReturnValue = -3;
1520		}
1521	} else {
1522	   /*******************/
1523		/* Data size error */
1524	   /*******************/
1525
1526		printk("Buffer size error\n");
1527		i_ReturnValue = -101;
1528	}
1529
1530	return i_ReturnValue;
1531}
1532
1533/*
1534+----------------------------------------------------------------------------+
1535| Function name     :int i_APCI3XXX_InsnReadDigitalOutput                    |
1536|                                          (struct comedi_device *dev,              |
1537|                                           struct comedi_subdevice *s,             |
1538|                                           struct comedi_insn *insn,               |
1539|                                           unsigned int *data)                  |
1540+----------------------------------------------------------------------------+
1541| Task              : Read the state from digital output channel             |
1542+----------------------------------------------------------------------------+
1543| Input Parameters  : b_Channel = CR_CHAN(insn->chanspec)                    |
1544+----------------------------------------------------------------------------+
1545| Output Parameters : b_State   = data [0]                                   |
1546+----------------------------------------------------------------------------+
1547| Return Value      : >0  : No error                                         |
1548|                    -3   : Channel selection error                          |
1549|                    -101 : Data size error                                  |
1550+----------------------------------------------------------------------------+
1551*/
1552
1553static int i_APCI3XXX_InsnReadDigitalOutput(struct comedi_device *dev,
1554					    struct comedi_subdevice *s,
1555					    struct comedi_insn *insn,
1556					    unsigned int *data)
1557{
1558	int i_ReturnValue = insn->n;
1559	unsigned char b_Channel = CR_CHAN(insn->chanspec);
1560	unsigned int dw_Status = 0;
1561
1562	/************************/
1563	/* Test the buffer size */
1564	/************************/
1565
1566	if (insn->n >= 1) {
1567	   /***************************/
1568		/* Test the channel number */
1569	   /***************************/
1570
1571		if (b_Channel < devpriv->ps_BoardInfo->i_NbrDoChannel) {
1572	      /********************************/
1573			/* Read the digital output port */
1574	      /********************************/
1575
1576			dw_Status = inl(devpriv->iobase + 48);
1577
1578			dw_Status = (dw_Status >> b_Channel) & 1;
1579			*data = dw_Status;
1580		} else {
1581	      /***************************/
1582			/* Channel selection error */
1583	      /***************************/
1584
1585			printk("Channel selection error\n");
1586			i_ReturnValue = -3;
1587		}
1588	} else {
1589	   /*******************/
1590		/* Data size error */
1591	   /*******************/
1592
1593		printk("Buffer size error\n");
1594		i_ReturnValue = -101;
1595	}
1596
1597	return i_ReturnValue;
1598}
1599
1600/*
1601+----------------------------------------------------------------------------+
1602| Function   Name   : int i_APCI3XXX_Reset(struct comedi_device *dev)               |                                                         +----------------------------------------------------------------------------+
1603| Task              :resets all the registers                                |
1604+----------------------------------------------------------------------------+
1605| Input Parameters  : struct comedi_device *dev                                     |
1606+----------------------------------------------------------------------------+
1607| Output Parameters : -                                                      |
1608+----------------------------------------------------------------------------+
1609| Return Value      : -                                                      |
1610+----------------------------------------------------------------------------+
1611*/
1612
1613static int i_APCI3XXX_Reset(struct comedi_device *dev)
1614{
1615	unsigned char b_Cpt = 0;
1616
1617	/*************************/
1618	/* Disable the interrupt */
1619	/*************************/
1620
1621	disable_irq(dev->irq);
1622
1623	/****************************/
1624	/* Reset the interrupt flag */
1625	/****************************/
1626
1627	devpriv->b_EocEosInterrupt = 0;
1628
1629	/***************************/
1630	/* Clear the start command */
1631	/***************************/
1632
1633	writel(0, devpriv->dw_AiBase + 8);
1634
1635	/*****************************/
1636	/* Reset the interrupt flags */
1637	/*****************************/
1638
1639	writel(readl(devpriv->dw_AiBase + 16), devpriv->dw_AiBase + 16);
1640
1641	/*****************/
1642	/* clear the EOS */
1643	/*****************/
1644
1645	readl(devpriv->dw_AiBase + 20);
1646
1647	/******************/
1648	/* Clear the FIFO */
1649	/******************/
1650
1651	for (b_Cpt = 0; b_Cpt < 16; b_Cpt++) {
1652		readl(devpriv->dw_AiBase + 28);
1653	}
1654
1655	/************************/
1656	/* Enable the interrupt */
1657	/************************/
1658
1659	enable_irq(dev->irq);
1660
1661	return 0;
1662}
1663