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