APCI1710_Ssi.c revision 7aead6d77a8f4c3d05cce54fc2ab5babf2b8753f
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  +-----------------------------------------------------------------------+
27  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
28  +-----------------------------------------------------------------------+
29  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
30  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
31  +-----------------------------------------------------------------------+
32  | Project     : API APCI1710    | Compiler : gcc                        |
33  | Module name : SSI.C           | Version  : 2.96                       |
34  +-------------------------------+---------------------------------------+
35  | Project manager: Eric Stolz   | Date     :  02/12/2002                |
36  +-----------------------------------------------------------------------+
37  | Description :   APCI-1710 SSI counter module                          |
38  +-----------------------------------------------------------------------+
39  | several changes done by S. Weber in 1998 and C. Guinot in 2000        |
40  +-----------------------------------------------------------------------+
41*/
42
43/*
44+----------------------------------------------------------------------------+
45|                               Included files                               |
46+----------------------------------------------------------------------------+
47*/
48
49#include "APCI1710_Ssi.h"
50
51/*
52+----------------------------------------------------------------------------+
53| Function Name     : _INT_ i_APCI1710_InitSSI                               |
54|                               (unsigned char_    b_BoardHandle,                     |
55|                                unsigned char_    b_ModulNbr,                        |
56|                                unsigned char_    b_SSIProfile,                      |
57|                                unsigned char_    b_PositionTurnLength,              |
58|                                unsigned char_    b_TurnCptLength,                   |
59|                                unsigned char_    b_PCIInputClock,                   |
60|                                ULONG_  ul_SSIOutputClock,                  |
61|                                unsigned char_    b_SSICountingMode)                 |
62+----------------------------------------------------------------------------+
63| Task              : Configure the SSI operating mode from selected module  |
64|                     (b_ModulNbr). You must calling this function be for you|
65|                     call any other function witch access of SSI.           |
66+----------------------------------------------------------------------------+
67| Input Parameters  : unsigned char_ b_BoardHandle         : Handle of board APCI-1710|
68|                     unsigned char_ b_ModulNbr            : Module number to         |
69|                                                   configure (0 to 3)       |
70|                     unsigned char_  b_SSIProfile         : Selection from SSI       |
71|                                                   profile length (2 to 32).|
72|                     unsigned char_  b_PositionTurnLength : Selection from SSI       |
73|                                                   position data length     |
74|                                                   (1 to 31).               |
75|                     unsigned char_  b_TurnCptLength      : Selection from SSI turn  |
76|                                                   counter data length      |
77|                                                   (1 to 31).               |
78|                     unsigned char   b_PCIInputClock      : Selection from PCI bus   |
79|                                                   clock                    |
80|                                                 - APCI1710_30MHZ :         |
81|                                                   The PC have a PCI bus    |
82|                                                   clock from 30 MHz        |
83|                                                 - APCI1710_33MHZ :         |
84|                                                   The PC have a PCI bus    |
85|                                                   clock from 33 MHz        |
86|                     ULONG_ ul_SSIOutputClock    : Selection from SSI output|
87|                                                   clock.                   |
88|                                                   From  229 to 5 000 000 Hz|
89|                                                   for 30 MHz selection.    |
90|                                                   From  252 to 5 000 000 Hz|
91|                                                   for 33 MHz selection.    |
92|                     unsigned char   b_SSICountingMode    : SSI counting mode        |
93|                                                   selection                |
94|                                                 - APCI1710_BINARY_MODE :   |
95|                                                    Binary counting mode.   |
96|                                                 - APCI1710_GRAY_MODE :     |
97|                                                    Gray counting mode.
98
99	b_ModulNbr			= CR_AREF(insn->chanspec);
100	b_SSIProfile		= (unsigned char) data[0];
101	b_PositionTurnLength= (unsigned char) data[1];
102	b_TurnCptLength		= (unsigned char) data[2];
103	b_PCIInputClock		= (unsigned char) data[3];
104	ul_SSIOutputClock	= (unsigned int) data[4];
105	b_SSICountingMode	= (unsigned char)  data[5];     |
106+----------------------------------------------------------------------------+
107| Output Parameters : -                                                      |
108+----------------------------------------------------------------------------+
109| Return Value      : 0: No error                                            |
110|                    -1: The handle parameter of the board is wrong          |
111|                    -2: The module parameter is wrong                       |
112|                    -3: The module is not a SSI module                      |
113|                    -4: The selected SSI profile length is wrong            |
114|                    -5: The selected SSI position data length is wrong      |
115|                    -6: The selected SSI turn counter data length is wrong  |
116|                    -7: The selected PCI input clock is wrong               |
117|                    -8: The selected SSI output clock is wrong              |
118|                    -9: The selected SSI counting mode parameter is wrong   |
119+----------------------------------------------------------------------------+
120*/
121
122int i_APCI1710_InsnConfigInitSSI(struct comedi_device *dev, struct comedi_subdevice *s,
123	struct comedi_insn *insn, unsigned int *data)
124{
125	int i_ReturnValue = 0;
126	unsigned int ui_TimerValue;
127	unsigned char b_ModulNbr, b_SSIProfile, b_PositionTurnLength, b_TurnCptLength,
128		b_PCIInputClock, b_SSICountingMode;
129	unsigned int ul_SSIOutputClock;
130
131	b_ModulNbr = CR_AREF(insn->chanspec);
132	b_SSIProfile = (unsigned char) data[0];
133	b_PositionTurnLength = (unsigned char) data[1];
134	b_TurnCptLength = (unsigned char) data[2];
135	b_PCIInputClock = (unsigned char) data[3];
136	ul_SSIOutputClock = (unsigned int) data[4];
137	b_SSICountingMode = (unsigned char) data[5];
138
139	i_ReturnValue = insn->n;
140	/**************************/
141	/* Test the module number */
142	/**************************/
143
144	if (b_ModulNbr < 4) {
145	   /***********************/
146		/* Test if SSI counter */
147	   /***********************/
148
149		if ((devpriv->s_BoardInfos.
150				dw_MolduleConfiguration[b_ModulNbr] &
151				0xFFFF0000UL) == APCI1710_SSI_COUNTER) {
152	      /*******************************/
153			/* Test the SSI profile length */
154	      /*******************************/
155
156			/*  CG 22/03/00 b_SSIProfile >= 2 anstatt b_SSIProfile > 2 */
157			if (b_SSIProfile >= 2 && b_SSIProfile < 33) {
158		 /*************************************/
159				/* Test the SSI position data length */
160		 /*************************************/
161
162				if (b_PositionTurnLength > 0
163					&& b_PositionTurnLength < 32) {
164		    /*****************************************/
165					/* Test the SSI turn counter data length */
166		    /*****************************************/
167
168					if (b_TurnCptLength > 0
169						&& b_TurnCptLength < 32) {
170		       /***************************/
171						/* Test the profile length */
172		       /***************************/
173
174						if ((b_TurnCptLength +
175								b_PositionTurnLength)
176							<= b_SSIProfile) {
177			  /****************************/
178							/* Test the PCI input clock */
179			  /****************************/
180
181							if (b_PCIInputClock ==
182								APCI1710_30MHZ
183								||
184								b_PCIInputClock
185								==
186								APCI1710_33MHZ)
187							{
188			     /*************************/
189								/* Test the output clock */
190			     /*************************/
191
192								if ((b_PCIInputClock == APCI1710_30MHZ && (ul_SSIOutputClock > 228 && ul_SSIOutputClock <= 5000000UL)) || (b_PCIInputClock == APCI1710_33MHZ && (ul_SSIOutputClock > 251 && ul_SSIOutputClock <= 5000000UL))) {
193									if (b_SSICountingMode == APCI1710_BINARY_MODE || b_SSICountingMode == APCI1710_GRAY_MODE) {
194				   /**********************/
195										/* Save configuration */
196				   /**********************/
197										devpriv->
198											s_ModuleInfo
199											[b_ModulNbr].
200											s_SSICounterInfo.
201											b_SSIProfile
202											=
203											b_SSIProfile;
204
205										devpriv->
206											s_ModuleInfo
207											[b_ModulNbr].
208											s_SSICounterInfo.
209											b_PositionTurnLength
210											=
211											b_PositionTurnLength;
212
213										devpriv->
214											s_ModuleInfo
215											[b_ModulNbr].
216											s_SSICounterInfo.
217											b_TurnCptLength
218											=
219											b_TurnCptLength;
220
221				   /*********************************/
222										/* Initialise the profile length */
223				   /*********************************/
224
225										if (b_SSICountingMode == APCI1710_BINARY_MODE) {
226
227											outl(b_SSIProfile + 1, devpriv->s_BoardInfos.ui_Address + 4 + (64 * b_ModulNbr));
228										} else {
229
230											outl(b_SSIProfile, devpriv->s_BoardInfos.ui_Address + 4 + (64 * b_ModulNbr));
231										}
232
233				   /******************************/
234										/* Calculate the output clock */
235				   /******************************/
236
237										ui_TimerValue
238											=
239											(unsigned int)
240											(
241											((unsigned int) (b_PCIInputClock) * 500000UL) / ul_SSIOutputClock);
242
243				   /************************/
244										/* Initialise the timer */
245				   /************************/
246
247										outl(ui_TimerValue, devpriv->s_BoardInfos.ui_Address + (64 * b_ModulNbr));
248
249				   /********************************/
250										/* Initialise the counting mode */
251				   /********************************/
252
253										outl(7 * b_SSICountingMode, devpriv->s_BoardInfos.ui_Address + 12 + (64 * b_ModulNbr));
254
255										devpriv->
256											s_ModuleInfo
257											[b_ModulNbr].
258											s_SSICounterInfo.
259											b_SSIInit
260											=
261											1;
262									} else {
263				   /*****************************************************/
264										/* The selected SSI counting mode parameter is wrong */
265				   /*****************************************************/
266
267										DPRINTK("The selected SSI counting mode parameter is wrong\n");
268										i_ReturnValue
269											=
270											-9;
271									}
272								} else {
273				/******************************************/
274									/* The selected SSI output clock is wrong */
275				/******************************************/
276
277									DPRINTK("The selected SSI output clock is wrong\n");
278									i_ReturnValue
279										=
280										-8;
281								}
282							} else {
283			     /*****************************************/
284								/* The selected PCI input clock is wrong */
285			     /*****************************************/
286
287								DPRINTK("The selected PCI input clock is wrong\n");
288								i_ReturnValue =
289									-7;
290							}
291						} else {
292			  /********************************************/
293							/* The selected SSI profile length is wrong */
294			  /********************************************/
295
296							DPRINTK("The selected SSI profile length is wrong\n");
297							i_ReturnValue = -4;
298						}
299					} else {
300		       /******************************************************/
301						/* The selected SSI turn counter data length is wrong */
302		       /******************************************************/
303
304						DPRINTK("The selected SSI turn counter data length is wrong\n");
305						i_ReturnValue = -6;
306					}
307				} else {
308		    /**************************************************/
309					/* The selected SSI position data length is wrong */
310		    /**************************************************/
311
312					DPRINTK("The selected SSI position data length is wrong\n");
313					i_ReturnValue = -5;
314				}
315			} else {
316		 /********************************************/
317				/* The selected SSI profile length is wrong */
318		 /********************************************/
319
320				DPRINTK("The selected SSI profile length is wrong\n");
321				i_ReturnValue = -4;
322			}
323		} else {
324	      /**********************************/
325			/* The module is not a SSI module */
326	      /**********************************/
327
328			DPRINTK("The module is not a SSI module\n");
329			i_ReturnValue = -3;
330		}
331	} else {
332	   /***********************/
333		/* Module number error */
334	   /***********************/
335
336		DPRINTK("Module number error\n");
337		i_ReturnValue = -2;
338	}
339
340	return i_ReturnValue;
341}
342
343/*
344+----------------------------------------------------------------------------+
345| Function Name     : _INT_  i_APCI1710_Read1SSIValue                        |
346|                               (unsigned char_     b_BoardHandle,                    |
347|                                unsigned char_     b_ModulNbr,                       |
348|                                unsigned char_     b_SelectedSSI,                    |
349|                                PULONG_ pul_Position,                       |
350|                                PULONG_ pul_TurnCpt)
351 int i_APCI1710_ReadSSIValue(struct comedi_device *dev,struct comedi_subdevice *s,
352	struct comedi_insn *insn,unsigned int *data)                       |
353+----------------------------------------------------------------------------+
354| Task              :
355
356
357						Read the selected SSI counter (b_SelectedSSI) from     |
358|                     selected module (b_ModulNbr).
359						or Read all SSI counter (b_SelectedSSI) from              |
360|                     selected module (b_ModulNbr).                            |
361+----------------------------------------------------------------------------+
362| Input Parameters  : unsigned char_ b_BoardHandle         : Handle of board APCI-1710|
363|                     unsigned char_ b_ModulNbr            : Module number to         |
364|                                                   configure (0 to 3)       |
365|                     unsigned char_ b_SelectedSSI         : Selection from SSI       |
366|                                                   counter (0 to 2)
367
368    b_ModulNbr		=   (unsigned char) CR_AREF(insn->chanspec);
369	b_SelectedSSI	=	(unsigned char) CR_CHAN(insn->chanspec); (in case of single ssi)
370	b_ReadType		=	(unsigned char) CR_RANGE(insn->chanspec);
371|
372+----------------------------------------------------------------------------+
373| Output Parameters : PULONG_  pul_Position       : SSI position in the turn |
374|                     PULONG_  pul_TurnCpt        : Number of turns
375
376pul_Position	=	(unsigned int *) &data[0];
377	pul_TurnCpt		=	(unsigned int *) &data[1];         |
378+----------------------------------------------------------------------------+
379| Return Value      : 0: No error                                            |
380|                    -1: The handle parameter of the board is wrong          |
381|                    -2: The module parameter is wrong                       |
382|                    -3: The module is not a SSI module                      |
383|                    -4: SSI not initialised see function                    |
384|                        "i_APCI1710_InitSSI"                                |
385|                    -5: The selected SSI is wrong                           |
386+----------------------------------------------------------------------------+
387*/
388
389int i_APCI1710_InsnReadSSIValue(struct comedi_device *dev, struct comedi_subdevice *s,
390	struct comedi_insn *insn, unsigned int *data)
391{
392	int i_ReturnValue = 0;
393	unsigned char b_Cpt;
394	unsigned char b_Length;
395	unsigned char b_Schift;
396	unsigned char b_SSICpt;
397	unsigned int dw_And;
398	unsigned int dw_And1;
399	unsigned int dw_And2;
400	unsigned int dw_StatusReg;
401	unsigned int dw_CounterValue;
402	unsigned char b_ModulNbr;
403	unsigned char b_SelectedSSI;
404	unsigned char b_ReadType;
405	unsigned int *pul_Position;
406	unsigned int *pul_TurnCpt;
407	unsigned int *pul_Position1;
408	unsigned int *pul_TurnCpt1;
409
410	i_ReturnValue = insn->n;
411	pul_Position1 = (unsigned int *) &data[0];
412/* For Read1 */
413	pul_TurnCpt1 = (unsigned int *) &data[1];
414/* For Read all */
415	pul_Position = (unsigned int *) &data[0];	/* 0-2 */
416	pul_TurnCpt = (unsigned int *) &data[3];	/* 3-5 */
417	b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
418	b_SelectedSSI = (unsigned char) CR_CHAN(insn->chanspec);
419	b_ReadType = (unsigned char) CR_RANGE(insn->chanspec);
420
421	/**************************/
422	/* Test the module number */
423	/**************************/
424
425	if (b_ModulNbr < 4) {
426	   /***********************/
427		/* Test if SSI counter */
428	   /***********************/
429
430		if ((devpriv->s_BoardInfos.
431				dw_MolduleConfiguration[b_ModulNbr] &
432				0xFFFF0000UL) == APCI1710_SSI_COUNTER) {
433	      /***************************/
434			/* Test if SSI initialised */
435	      /***************************/
436
437			if (devpriv->s_ModuleInfo[b_ModulNbr].
438				s_SSICounterInfo.b_SSIInit == 1) {
439
440				switch (b_ReadType) {
441
442				case APCI1710_SSI_READ1VALUE:
443		 /****************************************/
444					/* Test the selected SSI counter number */
445		 /****************************************/
446
447					if (b_SelectedSSI < 3) {
448		    /************************/
449						/* Start the conversion */
450		    /************************/
451
452						outl(0, devpriv->s_BoardInfos.
453							ui_Address + 8 +
454							(64 * b_ModulNbr));
455
456						do {
457		       /*******************/
458							/* Read the status */
459		       /*******************/
460
461							dw_StatusReg =
462								inl(devpriv->
463								s_BoardInfos.
464								ui_Address +
465								(64 * b_ModulNbr));
466						} while ((dw_StatusReg & 0x1)
467							 != 0);
468
469		    /******************************/
470						/* Read the SSI counter value */
471		    /******************************/
472
473						dw_CounterValue =
474							inl(devpriv->
475							s_BoardInfos.
476							ui_Address + 4 +
477							(b_SelectedSSI * 4) +
478							(64 * b_ModulNbr));
479
480						b_Length =
481							devpriv->
482							s_ModuleInfo
483							[b_ModulNbr].
484							s_SSICounterInfo.
485							b_SSIProfile / 2;
486
487						if ((b_Length * 2) !=
488							devpriv->
489							s_ModuleInfo
490							[b_ModulNbr].
491							s_SSICounterInfo.
492							b_SSIProfile) {
493							b_Length++;
494						}
495
496						b_Schift =
497							b_Length -
498							devpriv->
499							s_ModuleInfo
500							[b_ModulNbr].
501							s_SSICounterInfo.
502							b_PositionTurnLength;
503
504						*pul_Position1 =
505							dw_CounterValue >>
506							b_Schift;
507
508						dw_And = 1;
509
510						for (b_Cpt = 0;
511							b_Cpt <
512							devpriv->
513							s_ModuleInfo
514							[b_ModulNbr].
515							s_SSICounterInfo.
516							b_PositionTurnLength;
517							b_Cpt++) {
518							dw_And = dw_And * 2;
519						}
520
521						*pul_Position1 =
522							*pul_Position1 &
523							((dw_And) - 1);
524
525						*pul_TurnCpt1 =
526							dw_CounterValue >>
527							b_Length;
528
529						dw_And = 1;
530
531						for (b_Cpt = 0;
532							b_Cpt <
533							devpriv->
534							s_ModuleInfo
535							[b_ModulNbr].
536							s_SSICounterInfo.
537							b_TurnCptLength;
538							b_Cpt++) {
539							dw_And = dw_And * 2;
540						}
541
542						*pul_TurnCpt1 =
543							*pul_TurnCpt1 &
544							((dw_And) - 1);
545					} else {
546		    /*****************************/
547						/* The selected SSI is wrong */
548		    /*****************************/
549
550						DPRINTK("The selected SSI is wrong\n");
551						i_ReturnValue = -5;
552					}
553					break;
554
555				case APCI1710_SSI_READALLVALUE:
556					dw_And1 = 1;
557
558					for (b_Cpt = 0;
559						b_Cpt <
560						devpriv->
561						s_ModuleInfo[b_ModulNbr].
562						s_SSICounterInfo.
563						b_PositionTurnLength; b_Cpt++) {
564						dw_And1 = dw_And1 * 2;
565					}
566
567					dw_And2 = 1;
568
569					for (b_Cpt = 0;
570						b_Cpt <
571						devpriv->
572						s_ModuleInfo[b_ModulNbr].
573						s_SSICounterInfo.
574						b_TurnCptLength; b_Cpt++) {
575						dw_And2 = dw_And2 * 2;
576					}
577
578		 /************************/
579					/* Start the conversion */
580		 /************************/
581
582					outl(0, devpriv->s_BoardInfos.
583						ui_Address + 8 +
584						(64 * b_ModulNbr));
585
586					do {
587		    /*******************/
588						/* Read the status */
589		    /*******************/
590
591						dw_StatusReg =
592							inl(devpriv->
593							s_BoardInfos.
594							ui_Address +
595							(64 * b_ModulNbr));
596					} while ((dw_StatusReg & 0x1) != 0);
597
598					for (b_SSICpt = 0; b_SSICpt < 3;
599						b_SSICpt++) {
600		    /******************************/
601						/* Read the SSI counter value */
602		    /******************************/
603
604						dw_CounterValue =
605							inl(devpriv->
606							s_BoardInfos.
607							ui_Address + 4 +
608							(b_SSICpt * 4) +
609							(64 * b_ModulNbr));
610
611						b_Length =
612							devpriv->
613							s_ModuleInfo
614							[b_ModulNbr].
615							s_SSICounterInfo.
616							b_SSIProfile / 2;
617
618						if ((b_Length * 2) !=
619							devpriv->
620							s_ModuleInfo
621							[b_ModulNbr].
622							s_SSICounterInfo.
623							b_SSIProfile) {
624							b_Length++;
625						}
626
627						b_Schift =
628							b_Length -
629							devpriv->
630							s_ModuleInfo
631							[b_ModulNbr].
632							s_SSICounterInfo.
633							b_PositionTurnLength;
634
635						pul_Position[b_SSICpt] =
636							dw_CounterValue >>
637							b_Schift;
638						pul_Position[b_SSICpt] =
639							pul_Position[b_SSICpt] &
640							((dw_And1) - 1);
641
642						pul_TurnCpt[b_SSICpt] =
643							dw_CounterValue >>
644							b_Length;
645						pul_TurnCpt[b_SSICpt] =
646							pul_TurnCpt[b_SSICpt] &
647							((dw_And2) - 1);
648					}
649					break;
650
651				default:
652					printk("Read Type Inputs Wrong\n");
653
654				}	/*  switch  ending */
655
656			} else {
657		 /***********************/
658				/* SSI not initialised */
659		 /***********************/
660
661				DPRINTK("SSI not initialised\n");
662				i_ReturnValue = -4;
663			}
664		} else {
665	      /**********************************/
666			/* The module is not a SSI module */
667	      /**********************************/
668
669			DPRINTK("The module is not a SSI module\n");
670			i_ReturnValue = -3;
671
672		}
673	} else {
674	   /***********************/
675		/* Module number error */
676	   /***********************/
677
678		DPRINTK("Module number error\n");
679		i_ReturnValue = -2;
680	}
681
682	return i_ReturnValue;
683}
684
685/*
686+----------------------------------------------------------------------------+
687| Function Name     : _INT_   i_APCI1710_ReadSSI1DigitalInput                |
688|                                       (unsigned char_     b_BoardHandle,            |
689|                                        unsigned char_     b_ModulNbr,               |
690|                                        unsigned char_     b_InputChannel,           |
691|                                        unsigned char *_   pb_ChannelStatus)          |
692+----------------------------------------------------------------------------+
693| Task              :
694					(0) Set the digital output from selected SSI moule         |
695|                     (b_ModuleNbr) ON
696                    (1) Set the digital output from selected SSI moule         |
697|                     (b_ModuleNbr) OFF
698					(2)Read the status from selected SSI digital input        |
699|                     (b_InputChannel)
700                    (3)Read the status from all SSI digital inputs from       |
701|                     selected SSI module (b_ModulNbr)                   |
702+----------------------------------------------------------------------------+
703| Input Parameters  : unsigned char_ b_BoardHandle         : Handle of board APCI-1710|
704|                     unsigned char_ b_ModulNbr    CR_AREF        : Module number to         |
705|                                                   configure (0 to 3)       |
706|                     unsigned char_ b_InputChannel CR_CHAN       : Selection from digital   |
707|                        data[0] which IOTYPE                           input ( 0 to 2)          |
708+----------------------------------------------------------------------------+
709| Output Parameters : unsigned char *_  pb_ChannelStatus    : Digital input channel    |
710|                                 data[0]                  status                   |
711|                                                   0 : Channle is not active|
712|                                                   1 : Channle is active    |
713+----------------------------------------------------------------------------+
714| Return Value      : 0: No error                                            |
715|                    -1: The handle parameter of the board is wrong          |
716|                    -2: The module parameter is wrong                       |
717|                    -3: The module is not a SSI module                      |
718|                    -4: The selected SSI digital input is wrong             |
719+----------------------------------------------------------------------------+
720*/
721
722int i_APCI1710_InsnBitsSSIDigitalIO(struct comedi_device *dev, struct comedi_subdevice *s,
723	struct comedi_insn *insn, unsigned int *data)
724{
725	int i_ReturnValue = 0;
726	unsigned int dw_StatusReg;
727	unsigned char b_ModulNbr;
728	unsigned char b_InputChannel;
729	unsigned char *pb_ChannelStatus;
730	unsigned char *pb_InputStatus;
731	unsigned char b_IOType;
732	i_ReturnValue = insn->n;
733	b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
734	b_IOType = (unsigned char) data[0];
735
736	/**************************/
737	/* Test the module number */
738	/**************************/
739
740	if (b_ModulNbr < 4) {
741	   /***********************/
742		/* Test if SSI counter */
743	   /***********************/
744
745		if ((devpriv->s_BoardInfos.
746				dw_MolduleConfiguration[b_ModulNbr] &
747				0xFFFF0000UL) == APCI1710_SSI_COUNTER) {
748			switch (b_IOType) {
749			case APCI1710_SSI_SET_CHANNELON:
750					/*****************************/
751				/* Set the digital output ON */
752					/*****************************/
753
754				outl(1, devpriv->s_BoardInfos.ui_Address + 16 +
755					(64 * b_ModulNbr));
756				break;
757
758			case APCI1710_SSI_SET_CHANNELOFF:
759					/******************************/
760				/* Set the digital output OFF */
761					/******************************/
762
763				outl(0, devpriv->s_BoardInfos.ui_Address + 16 +
764					(64 * b_ModulNbr));
765				break;
766
767			case APCI1710_SSI_READ_1CHANNEL:
768				   /******************************************/
769				/* Test the digital imnput channel number */
770				   /******************************************/
771
772				b_InputChannel = (unsigned char) CR_CHAN(insn->chanspec);
773				pb_ChannelStatus = (unsigned char *) &data[0];
774
775				if (b_InputChannel <= 2) {
776					/**************************/
777					/* Read all digital input */
778					/**************************/
779
780					dw_StatusReg =
781						inl(devpriv->s_BoardInfos.
782						ui_Address + (64 * b_ModulNbr));
783					*pb_ChannelStatus =
784						(unsigned char) (((~dw_StatusReg) >> (4 +
785								b_InputChannel))
786						& 1);
787				} else {
788					/********************************/
789					/* Selected digital input error */
790					/********************************/
791
792					DPRINTK("Selected digital input error\n");
793					i_ReturnValue = -4;
794				}
795				break;
796
797			case APCI1710_SSI_READ_ALLCHANNEL:
798					/**************************/
799				/* Read all digital input */
800					/**************************/
801				pb_InputStatus = (unsigned char *) &data[0];
802
803				dw_StatusReg =
804					inl(devpriv->s_BoardInfos.ui_Address +
805					(64 * b_ModulNbr));
806				*pb_InputStatus =
807					(unsigned char) (((~dw_StatusReg) >> 4) & 7);
808				break;
809
810			default:
811				printk("IO type wrong\n");
812
813			}	/* switch end */
814		} else {
815	      /**********************************/
816			/* The module is not a SSI module */
817	      /**********************************/
818
819			DPRINTK("The module is not a SSI module\n");
820			i_ReturnValue = -3;
821		}
822	} else {
823	   /***********************/
824		/* Module number error */
825	   /***********************/
826
827		DPRINTK("Module number error\n");
828		i_ReturnValue = -2;
829	}
830
831	return i_ReturnValue;
832}
833