APCI1710_82x54.c revision 34c43922e62708d45e9660eee4b4f1fb7b4bf2c7
1/*
2 *  Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
3 *
4 *	ADDI-DATA GmbH
5 *	Dieselstrasse 3
6 *	D-77833 Ottersweier
7 *	Tel: +19(0)7223/9493-0
8 *	Fax: +49(0)7223/9493-92
9 *	http://www.addi-data-com
10 *	info@addi-data.com
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the Free
14 * Software Foundation; either version 2 of the License, or (at your option)
15 * any later version.
16 */
17/*
18  | Description :   APCI-1710 82X54 timer module                          |
19*/
20
21#include "APCI1710_82x54.h"
22
23/*
24+----------------------------------------------------------------------------+
25| Function Name     : _INT_     i_APCI1710_InitTimer                         |
26|                               (BYTE_   b_BoardHandle,                      |
27|                                BYTE_   b_ModulNbr,                         |
28|                                BYTE_   b_TimerNbr,                         |
29|                                BYTE_   b_TimerMode,                        |
30|                                ULONG_ ul_ReloadValue,                      |
31|                                BYTE_   b_InputClockSelection,              |
32|                                BYTE_   b_InputClockLevel,                  |
33|                                BYTE_   b_OutputLevel,                      |
34|                                BYTE_   b_HardwareGateLevel)
35INT i_InsnConfig_InitTimer(struct comedi_device *dev,struct comedi_subdevice *s,
36	comedi_insn *insn,unsigned int *data)
37|
38+----------------------------------------------------------------------------+
39| Task              : Configure the Timer (b_TimerNbr) operating mode        |
40|                     (b_TimerMode) from selected module (b_ModulNbr).       |
41|                     You must calling this function be for you call any     |
42|                     other function witch access of the timer.              |
43|                                                                            |
44|                                                                            |
45|                       Timer mode description table                         |
46|                                                                            |
47|+--------+-----------------------------+--------------+--------------------+|
48||Selected+      Mode description       +u_ReloadValue | Hardware gate input||
49||  mode  |                             |  description |      action        ||
50|+--------+-----------------------------+--------------+--------------------+|
51||        |Mode 0 is typically used     |              |                    ||
52||        |for event counting. After    |              |                    ||
53||        |the initialisation, OUT      |              |                    ||
54||        |is initially low, and        |              |                    ||
55||   0    |will remain low until the    |Start counting|   Hardware gate    ||
56||        |counter reaches zero.        |   value      |                    ||
57||        |OUT then goes high and       |              |                    ||
58||        |remains high until a new     |              |                    ||
59||        |count is written. See        |              |                    ||
60||        |"i_APCI1710_WriteTimerValue" |              |                    ||
61||        |function.                    |              |                    ||
62|+--------+-----------------------------+--------------+--------------------+|
63||        |Mode 1 is similar to mode 0  |              |                    ||
64||        |except for the gate input    |              |                    ||
65||   1    |action. The gate input is not|Start counting|  Hardware trigger  ||
66||        |used for enabled or disabled |   value      |                    ||
67||        |the timer.                   |              |                    ||
68||        |The gate input is used for   |              |                    ||
69||        |triggered the timer.         |              |                    ||
70|+--------+-----------------------------+--------------+--------------------+|
71||        |This mode functions like a   |              |                    ||
72||        |divide-by-ul_ReloadValue     |              |                    ||
73||        |counter. It is typically used|              |                    ||
74||        |to generate a real time clock|              |                    ||
75||        |interrupt. OUT will initially|              |                    ||
76||   2    |be high after the            |   Division   |  Hardware gate     ||
77||        |initialisation. When the     |    factor    |                    ||
78||        |initial count has decremented|              |                    ||
79||        |to 1, OUT goes low for one   |              |                    ||
80||        |CLK pule. OUT then goes high |              |                    ||
81||        |again, the counter reloads   |              |                    ||
82||        |the initial count            |              |                    ||
83||        |(ul_ReloadValue) and the     |              |                    ||
84||        |process is repeated.         |              |                    ||
85||        |This action can generated a  |              |                    ||
86||        |interrupt. See function      |              |                    ||
87||        |"i_APCI1710_SetBoardInt-     |              |                    ||
88||        |RoutineX"                    |              |                    ||
89||        |and "i_APCI1710_EnableTimer" |              |                    ||
90|+--------+-----------------------------+--------------+--------------------+|
91||        |Mode 3 is typically used for |              |                    ||
92||        |baud rate generation. This   |              |                    ||
93||        |mode is similar to mode 2    |              |                    ||
94||        |except for the duty cycle of |              |                    ||
95||   3    |OUT. OUT will initially be   |  Division    |   Hardware gate    ||
96||        |high after the initialisation|   factor     |                    ||
97||        |When half the initial count  |              |                    ||
98||        |(ul_ReloadValue) has expired,|              |                    ||
99||        |OUT goes low for the         |              |                    ||
100||        |remainder of the count. The  |              |                    ||
101||        |mode is periodic; the        |              |                    ||
102||        |sequence above is repeated   |              |                    ||
103||        |indefinitely.                |              |                    ||
104|+--------+-----------------------------+--------------+--------------------+|
105||        |OUT will be initially high   |              |                    ||
106||        |after the initialisation.    |              |                    ||
107||        |When the initial count       |              |                    ||
108||   4    |expires OUT will go low for  |Start counting|  Hardware gate     ||
109||        |one CLK pulse and then go    |    value     |                    ||
110||        |high again.                  |              |                    ||
111||        |The counting sequences is    |              |                    ||
112||        |triggered by writing a new   |              |                    ||
113||        |value. See                   |              |                    ||
114||        |"i_APCI1710_WriteTimerValue" |              |                    ||
115||        |function. If a new count is  |              |                    ||
116||        |written during counting,     |              |                    ||
117||        |it will be loaded on the     |              |                    ||
118||        |next CLK pulse               |              |                    ||
119|+--------+-----------------------------+--------------+--------------------+|
120||        |Mode 5 is similar to mode 4  |              |                    ||
121||        |except for the gate input    |              |                    ||
122||        |action. The gate input is not|              |                    ||
123||   5    |used for enabled or disabled |Start counting|  Hardware trigger  ||
124||        |the timer. The gate input is |    value     |                    ||
125||        |used for triggered the timer.|              |                    ||
126|+--------+-----------------------------+--------------+--------------------+|
127|                                                                            |
128|                                                                            |
129|                                                                            |
130|                      Input clock selection table                           |
131|                                                                            |
132|  +--------------------------------+------------------------------------+   |
133|  |       b_InputClockSelection    |           Description              |   |
134|  |           parameter            |                                    |   |
135|  +--------------------------------+------------------------------------+   |
136|  |    APCI1710_PCI_BUS_CLOCK      | For the timer input clock, the PCI |   |
137|  |                                | bus clock / 4 is used. This PCI bus|   |
138|  |                                | clock can be 30MHz or 33MHz. For   |   |
139|  |                                | Timer 0 only this selection are    |   |
140|  |                                | available.                         |   |
141|  +--------------------------------+------------------------------------+   |
142|  | APCI1710_ FRONT_CONNECTOR_INPUT| Of the front connector you have the|   |
143|  |                                | possibility to inject a input clock|   |
144|  |                                | for Timer 1 or Timer 2. The source |   |
145|  |                                | from this clock can eat the output |   |
146|  |                                | clock from Timer 0 or any other    |   |
147|  |                                | clock source.                      |   |
148|  +--------------------------------+------------------------------------+   |
149|                                                                            |
150+----------------------------------------------------------------------------+
151| Input Parameters  : BYTE_   b_BoardHandle        : Handle of board         |
152|                                                    APCI-1710               |
153|                     BYTE_   b_ModulNbr           : Module number to        |
154|                                                    configure (0 to 3)      |
155|                     BYTE_   b_TimerNbr           : Timer number to         |
156|                                                    configure (0 to 2)      |
157|                     BYTE_   b_TimerMode          : Timer mode selection    |
158|                                                    (0 to 5)                |
159|                                                    0: Interrupt on terminal|
160|                                                       count                |
161|                                                    1: Hardware             |
162|                                                       retriggerable one-   |
163|                                                       shot                 |
164|                                                    2: Rate generator       |
165|                                                    3: Square wave mode     |
166|                                                    4: Software triggered   |
167|                                                       strobe               |
168|                                                    5: Hardware triggered   |
169|                                                       strobe               |
170|                                                       See timer mode       |
171|                                                       description table.   |
172|                     ULONG_ ul_ReloadValue         : Start counting value   |
173|                                                     or division factor     |
174|                                                     See timer mode         |
175|                                                     description table.     |
176|                     BYTE_   b_InputClockSelection : Selection from input   |
177|                                                     timer clock.           |
178|                                                     See input clock        |
179|                                                     selection table.       |
180|                     BYTE_   b_InputClockLevel     : Selection from input   |
181|                                                     clock level.           |
182|                                                     0 : Low active         |
183|                                                         (Input inverted)   |
184|                                                     1 : High active        |
185|                     BYTE_   b_OutputLevel,        : Selection from output  |
186|                                                     clock level.           |
187|                                                     0 : Low active         |
188|                                                     1 : High active        |
189|                                                         (Output inverted)  |
190|                     BYTE_   b_HardwareGateLevel   : Selection from         |
191|                                                     hardware gate level.   |
192|                                                     0 : Low active         |
193|                                                         (Input inverted)   |
194|                                                     1 : High active        |
195|                                                     If you will not used   |
196|                                                     the hardware gate set  |
197|                                                     this value to 0.
198|b_ModulNbr        = (BYTE) CR_AREF(insn->chanspec);
199	b_TimerNbr		  = (BYTE) CR_CHAN(insn->chanspec);
200	b_TimerMode		  = (BYTE) data[0];
201	ul_ReloadValue	  = (ULONG) data[1];
202	b_InputClockSelection	=(BYTE) data[2];
203	b_InputClockLevel		=(BYTE) data[3];
204	b_OutputLevel			=(BYTE) data[4];
205	b_HardwareGateLevel		=(BYTE) data[5];
206+----------------------------------------------------------------------------+
207| Output Parameters : -                                                      |
208+----------------------------------------------------------------------------+
209| Return Value      : 0: No error                                            |
210|                    -1: The handle parameter of the board is wrong          |
211|                    -2: Module selection wrong                              |
212|                    -3: Timer selection wrong                               |
213|                    -4: The module is not a TIMER module                    |
214|                    -5: Timer mode selection is wrong                       |
215|                    -6: Input timer clock selection is wrong                |
216|                    -7: Selection from input clock level is wrong           |
217|                    -8: Selection from output clock level is wrong          |
218|                    -9: Selection from hardware gate level is wrong         |
219+----------------------------------------------------------------------------+
220*/
221
222INT i_APCI1710_InsnConfigInitTimer(struct comedi_device * dev, struct comedi_subdevice * s,
223				   comedi_insn * insn, unsigned int * data)
224{
225
226	INT i_ReturnValue = 0;
227	BYTE b_ModulNbr;
228	BYTE b_TimerNbr;
229	BYTE b_TimerMode;
230	ULONG ul_ReloadValue;
231	BYTE b_InputClockSelection;
232	BYTE b_InputClockLevel;
233	BYTE b_OutputLevel;
234	BYTE b_HardwareGateLevel;
235
236	//BEGIN JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz
237	DWORD dw_Test = 0;
238	//END JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz
239
240	i_ReturnValue = insn->n;
241	b_ModulNbr = (BYTE) CR_AREF(insn->chanspec);
242	b_TimerNbr = (BYTE) CR_CHAN(insn->chanspec);
243	b_TimerMode = (BYTE) data[0];
244	ul_ReloadValue = (ULONG) data[1];
245	b_InputClockSelection = (BYTE) data[2];
246	b_InputClockLevel = (BYTE) data[3];
247	b_OutputLevel = (BYTE) data[4];
248	b_HardwareGateLevel = (BYTE) data[5];
249
250	/* Test the module number */
251	if (b_ModulNbr < 4) {
252		/* Test if 82X54 timer */
253		if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) {
254			/* Test the timer number */
255
256			if (b_TimerNbr <= 2) {
257				/* Test the timer mode */
258				if (b_TimerMode <= 5) {
259					//BEGIN JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz
260					/* Test te imput clock selection */
261					/*
262					   if (((b_TimerNbr == 0) && (b_InputClockSelection == 0)) ||
263					   ((b_TimerNbr != 0) && ((b_InputClockSelection == 0) || (b_InputClockSelection == 1))))
264					 */
265
266					if (((b_TimerNbr == 0) &&
267					     (b_InputClockSelection == APCI1710_PCI_BUS_CLOCK)) ||
268					    ((b_TimerNbr == 0) &&
269					     (b_InputClockSelection == APCI1710_10MHZ)) ||
270					    ((b_TimerNbr != 0) &&
271					     ((b_InputClockSelection == APCI1710_PCI_BUS_CLOCK) ||
272					      (b_InputClockSelection == APCI1710_FRONT_CONNECTOR_INPUT) ||
273					      (b_InputClockSelection == APCI1710_10MHZ)))) {
274						//BEGIN JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz
275						if (((b_InputClockSelection == APCI1710_10MHZ) &&
276						     ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0x0000FFFFUL) >= 0x3131)) ||
277						     (b_InputClockSelection != APCI1710_10MHZ)) {
278							//END JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz
279							/* Test the input clock level selection */
280
281							if ((b_InputClockLevel == 0) ||
282							    (b_InputClockLevel == 1)) {
283								/* Test the output clock level selection */
284								if ((b_OutputLevel == 0) || (b_OutputLevel == 1)) {
285									/* Test the hardware gate level selection */
286									if ((b_HardwareGateLevel == 0) || (b_HardwareGateLevel == 1)) {
287										//BEGIN JK 27.10.03 : Add the possibility to use a 40 Mhz quartz
288										/* Test if version > 1.1 and clock selection = 10MHz */
289										if ((b_InputClockSelection == APCI1710_10MHZ) && ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0x0000FFFFUL) > 0x3131)) {
290											/* Test if 40MHz quartz on board */
291											dw_Test = inl(devpriv->s_BoardInfos.ui_Address + (16 + (b_TimerNbr * 4) + (64 * b_ModulNbr)));
292
293											dw_Test = (dw_Test >> 16) & 1;
294										} else {
295											dw_Test = 1;
296										}
297
298										/* Test if detection OK */
299										if (dw_Test == 1) {
300											//END JK 27.10.03 : Add the possibility to use a 40 Mhz quartz
301											/* Initialisation OK */
302											devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init = 1;
303
304											/* Save the input clock selection */
305											devpriv-> s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_InputClockSelection = b_InputClockSelection;
306
307											/* Save the input clock level */
308											devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_InputClockLevel = ~b_InputClockLevel & 1;
309
310											/* Save the output level */
311											devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_OutputLevel = ~b_OutputLevel & 1;
312
313											/* Save the gate level */
314											devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_HardwareGateLevel = b_HardwareGateLevel;
315
316											/* Set the configuration word and disable the timer */
317											//BEGIN JK 27.10.03 : Add the possibility to use a 40 Mhz quartz
318											/*
319											   devpriv->s_ModuleInfo [b_ModulNbr].
320											   s_82X54ModuleInfo.
321											   s_82X54TimerInfo  [b_TimerNbr].
322											   dw_ConfigurationWord = (DWORD) (((b_HardwareGateLevel         << 0) & 0x1) |
323											   ((b_InputClockLevel           << 1) & 0x2) |
324											   (((~b_OutputLevel       & 1)  << 2) & 0x4) |
325											   ((b_InputClockSelection       << 4) & 0x10));
326											 */
327											/* Test if 10MHz selected */
328											if (b_InputClockSelection == APCI1710_10MHZ) {
329												b_InputClockSelection = 2;
330											}
331
332											devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord = (DWORD)(((b_HardwareGateLevel << 0) & 0x1) | ((b_InputClockLevel << 1) & 0x2) | (((~b_OutputLevel & 1) << 2) & 0x4) | ((b_InputClockSelection << 4) & 0x30));
333											//END JK 27.10.03 : Add the possibility to use a 40 Mhz quartz
334											outl(devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord, devpriv->s_BoardInfos.ui_Address + 32 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
335
336											/* Initialise the 82X54 Timer */
337											outl((DWORD) b_TimerMode, devpriv->s_BoardInfos.ui_Address + 16 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
338
339											/* Write the reload value */
340											outl(ul_ReloadValue, devpriv->s_BoardInfos.ui_Address + 0 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
341											//BEGIN JK 27.10.03 : Add the possibility to use a 40 Mhz quartz
342										}	// if (dw_Test == 1)
343										else {
344											/* Input timer clock selection is wrong */
345											i_ReturnValue = -6;
346										}	// if (dw_Test == 1)
347										//END JK 27.10.03 : Add the possibility to use a 40 Mhz quartz
348									}	// if ((b_HardwareGateLevel == 0) || (b_HardwareGateLevel == 1))
349									else {
350										/* Selection from hardware gate level is wrong */
351										DPRINTK("Selection from hardware gate level is wrong\n");
352										i_ReturnValue = -9;
353									}	// if ((b_HardwareGateLevel == 0) || (b_HardwareGateLevel == 1))
354								}	// if ((b_OutputLevel == 0) || (b_OutputLevel == 1))
355								else {
356									/* Selection from output clock level is wrong */
357									DPRINTK("Selection from output clock level is wrong\n");
358									i_ReturnValue = -8;
359								}	// if ((b_OutputLevel == 0) || (b_OutputLevel == 1))
360							}	// if ((b_InputClockLevel == 0) || (b_InputClockLevel == 1))
361							else {
362								/* Selection from input clock level is wrong */
363								DPRINTK("Selection from input clock level is wrong\n");
364								i_ReturnValue = -7;
365							}	// if ((b_InputClockLevel == 0) || (b_InputClockLevel == 1))
366						} else {
367							/* Input timer clock selection is wrong */
368							DPRINTK("Input timer clock selection is wrong\n");
369							i_ReturnValue = -6;
370						}
371					} else {
372						/* Input timer clock selection is wrong */
373						DPRINTK("Input timer clock selection is wrong\n");
374						i_ReturnValue = -6;
375					}
376				}	// if ((b_TimerMode >= 0) && (b_TimerMode <= 5))
377				else {
378					/* Timer mode selection is wrong */
379					DPRINTK("Timer mode selection is wrong\n");
380					i_ReturnValue = -5;
381				}	// if ((b_TimerMode >= 0) && (b_TimerMode <= 5))
382			}	// if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2))
383			else {
384				/* Timer selection wrong */
385				DPRINTK("Timer selection wrong\n");
386				i_ReturnValue = -3;
387			}	// if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2))
388		} else {
389			/* The module is not a TIMER module */
390			DPRINTK("The module is not a TIMER module\n");
391			i_ReturnValue = -4;
392		}
393	} else {
394		/* Module number error */
395		DPRINTK("Module number error\n");
396		i_ReturnValue = -2;
397	}
398
399	return (i_ReturnValue);
400}
401
402/*
403+----------------------------------------------------------------------------+
404| Function Name     : _INT_     i_APCI1710_EnableTimer                       |
405|                               (BYTE_ b_BoardHandle,                        |
406|                                BYTE_ b_ModulNbr,                           |
407|                                BYTE_ b_TimerNbr,                           |
408|                                BYTE_ b_InterruptEnable)
409INT i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device *dev,struct comedi_subdevice *s,
410	comedi_insn *insn,unsigned int *data)                |
411+----------------------------------------------------------------------------+
412| Task              : Enable OR Disable the Timer (b_TimerNbr) from selected module     |
413|                     (b_ModulNbr). You must calling the                     |
414|                     "i_APCI1710_InitTimer" function be for you call this   |
415|                     function. If you enable the timer interrupt, the timer |
416|                     generate a interrupt after the timer value reach       |
417|                     the zero. See function "i_APCI1710_SetBoardIntRoutineX"|
418+----------------------------------------------------------------------------+
419| Input Parameters  : BYTE_   b_BoardHandle     : Handle of board            |
420|                                                 APCI-1710                  |
421|                     BYTE_   b_ModulNbr        : Selected module number     |
422|                                                 (0 to 3)                   |
423|                     BYTE_   b_TimerNbr        : Timer number to enable     |
424|                                                 (0 to 2)                   |
425|                     BYTE_   b_InterruptEnable : Enable or disable the      |
426|                                                 timer interrupt.           |
427|                                                 APCI1710_ENABLE :          |
428|                                                 Enable the timer interrupt |
429|                                                 APCI1710_DISABLE :         |
430|                                                 Disable the timer interrupt|
431i_ReturnValue=insn->n;
432	b_ModulNbr        = (BYTE) CR_AREF(insn->chanspec);
433	b_TimerNbr		  = (BYTE) CR_CHAN(insn->chanspec);
434	b_ActionType      = (BYTE) data[0]; // enable disable
435+----------------------------------------------------------------------------+
436| Output Parameters : -                                                      |
437+----------------------------------------------------------------------------+
438| Return Value      : 0: No error                                            |
439|                    -1: The handle parameter of the board is wrong          |
440|                    -2: Module selection wrong                              |
441|                    -3: Timer selection wrong                               |
442|                    -4: The module is not a TIMER module                    |
443|                    -5: Timer not initialised see function                  |
444|                        "i_APCI1710_InitTimer"                              |
445|                    -6: Interrupt parameter is wrong                        |
446|                    -7: Interrupt function not initialised.                 |
447|                        See function "i_APCI1710_SetBoardIntRoutineX"       |
448+----------------------------------------------------------------------------+
449*/
450
451INT i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device * dev,
452					   struct comedi_subdevice * s,
453					   comedi_insn * insn, unsigned int * data)
454{
455	INT i_ReturnValue = 0;
456	DWORD dw_DummyRead;
457	BYTE b_ModulNbr;
458	BYTE b_TimerNbr;
459	BYTE b_ActionType;
460	BYTE b_InterruptEnable;
461
462	i_ReturnValue = insn->n;
463	b_ModulNbr = (BYTE) CR_AREF(insn->chanspec);
464	b_TimerNbr = (BYTE) CR_CHAN(insn->chanspec);
465	b_ActionType = (BYTE) data[0];	// enable disable
466
467	/* Test the module number */
468	if (b_ModulNbr < 4) {
469		/* Test if 82X54 timer */
470		if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) {
471			/* Test the timer number */
472			if (b_TimerNbr <= 2) {
473				/* Test if timer initialised */
474				if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init == 1) {
475
476					switch (b_ActionType) {
477					case APCI1710_ENABLE:
478						b_InterruptEnable = (BYTE) data[1];
479						/* Test the interrupt selection */
480						if ((b_InterruptEnable == APCI1710_ENABLE) ||
481						    (b_InterruptEnable == APCI1710_DISABLE)) {
482							if (b_InterruptEnable == APCI1710_ENABLE) {
483
484								dw_DummyRead = inl(devpriv->s_BoardInfos.ui_Address + 12 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
485
486								/* Enable the interrupt */
487								devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord | 0x8;
488
489								outl(devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord, devpriv->s_BoardInfos.ui_Address + 32 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
490								devpriv->tsk_Current = current;	// Save the current process task structure
491
492							}	// if (b_InterruptEnable == APCI1710_ENABLE)
493							else {
494								/* Disable the interrupt */
495								devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord & 0xF7;
496
497								outl(devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord, devpriv->s_BoardInfos.ui_Address + 32 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
498
499								/* Save the interrupt flag */
500								devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask & (0xFF - (1 << b_TimerNbr));
501							}	// if (b_InterruptEnable == APCI1710_ENABLE)
502
503							/* Test if error occur */
504							if (i_ReturnValue >= 0) {
505								/* Save the interrupt flag */
506								devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask | ((1 & b_InterruptEnable) << b_TimerNbr);
507
508								/* Enable the timer */
509								outl(1, devpriv->s_BoardInfos.ui_Address + 44 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
510							}
511						} else {
512							/* Interrupt parameter is wrong */
513							DPRINTK("\n");
514							i_ReturnValue = -6;
515						}
516						break;
517					case APCI1710_DISABLE:
518						/* Test the interrupt flag */
519						if (((devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask >> b_TimerNbr) & 1) == 1) {
520							/* Disable the interrupt */
521
522							devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr]. dw_ConfigurationWord = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord & 0xF7;
523
524							outl(devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord, devpriv->s_BoardInfos.ui_Address + 32 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
525
526							/* Save the interrupt flag */
527							devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask & (0xFF - (1 << b_TimerNbr));
528						}
529
530						/* Disable the timer */
531						outl(0, devpriv->s_BoardInfos.ui_Address + 44 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
532						break;
533					}	// Switch end
534				} else {
535					/* Timer not initialised see function */
536					DPRINTK ("Timer not initialised see function\n");
537					i_ReturnValue = -5;
538				}
539			} else {
540				/* Timer selection wrong */
541				DPRINTK("Timer selection wrong\n");
542				i_ReturnValue = -3;
543			}	// if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2))
544		} else {
545			/* The module is not a TIMER module */
546			DPRINTK("The module is not a TIMER module\n");
547			i_ReturnValue = -4;
548		}
549	} else {
550		/* Module number error */
551		DPRINTK("Module number error\n");
552		i_ReturnValue = -2;
553	}
554
555	return (i_ReturnValue);
556}
557
558/*
559+----------------------------------------------------------------------------+
560| Function Name     : _INT_     i_APCI1710_ReadAllTimerValue                 |
561|                                       (BYTE_     b_BoardHandle,            |
562|                                        BYTE_     b_ModulNbr,               |
563|                                        PULONG_ pul_TimerValueArray)
564INT i_APCI1710_InsnReadAllTimerValue(struct comedi_device *dev,struct comedi_subdevice *s,
565	comedi_insn *insn,unsigned int *data)        |
566+----------------------------------------------------------------------------+
567| Task              : Return the all timer values from selected timer        |
568|                     module (b_ModulNbr).                                   |
569+----------------------------------------------------------------------------+
570| Input Parameters  : BYTE_   b_BoardHandle     : Handle of board            |
571|                                                 APCI-1710                  |
572|                     BYTE_   b_ModulNbr        : Selected module number     |
573|                                                 (0 to 3)                   |
574+----------------------------------------------------------------------------+
575| Output Parameters : PULONG_ pul_TimerValueArray : Timer value array.       |
576|                           Element 0 contain the timer 0 value.             |
577|                           Element 1 contain the timer 1 value.             |
578|                           Element 2 contain the timer 2 value.             |
579+----------------------------------------------------------------------------+
580| Return Value      : 0: No error                                            |
581|                    -1: The handle parameter of the board is wrong          |
582|                    -2: Module selection wrong                              |
583|                    -3: The module is not a TIMER module                    |
584|                    -4: Timer 0 not initialised see function                |
585|                        "i_APCI1710_InitTimer"                              |
586|                    -5: Timer 1 not initialised see function                |
587|                        "i_APCI1710_InitTimer"                              |
588|                    -6: Timer 2 not initialised see function                |
589|                        "i_APCI1710_InitTimer"                              |
590+----------------------------------------------------------------------------+
591*/
592
593INT i_APCI1710_InsnReadAllTimerValue(struct comedi_device *dev, struct comedi_subdevice *s,
594				     comedi_insn *insn, unsigned int *data)
595{
596	INT i_ReturnValue = 0;
597	BYTE b_ModulNbr, b_ReadType;
598	PULONG pul_TimerValueArray;
599
600	b_ModulNbr = CR_AREF(insn->chanspec);
601	b_ReadType = CR_CHAN(insn->chanspec);
602	pul_TimerValueArray = (PULONG) data;
603	i_ReturnValue = insn->n;
604
605	switch (b_ReadType) {
606	case APCI1710_TIMER_READINTERRUPT:
607
608		data[0] = devpriv->s_InterruptParameters.s_FIFOInterruptParameters[devpriv->s_InterruptParameters.ui_Read].b_OldModuleMask;
609		data[1] = devpriv->s_InterruptParameters.s_FIFOInterruptParameters[devpriv->s_InterruptParameters.ui_Read].ul_OldInterruptMask;
610		data[2] = devpriv->s_InterruptParameters.s_FIFOInterruptParameters[devpriv->s_InterruptParameters.ui_Read].ul_OldCounterLatchValue;
611
612		/* Increment the read FIFO */
613		devpriv->s_InterruptParameters.ui_Read = (devpriv->s_InterruptParameters.ui_Read + 1) % APCI1710_SAVE_INTERRUPT;
614
615		break;
616
617	case APCI1710_TIMER_READALLTIMER:
618		/* Test the module number */
619		if (b_ModulNbr < 4) {
620			/* Test if 82X54 timer */
621			if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) {
622				/* Test if timer 0 iniutialised */
623				if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[0].b_82X54Init == 1) {
624					/* Test if timer 1 iniutialised */
625					if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[1].b_82X54Init == 1) {
626						/* Test if timer 2 iniutialised */
627						if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[2].b_82X54Init == 1) {
628							/* Latch all counter */
629							outl(0x17, devpriv->s_BoardInfos.ui_Address + 12 + (64 * b_ModulNbr));
630
631							/* Read the timer 0 value */
632							pul_TimerValueArray[0] = inl(devpriv->s_BoardInfos.ui_Address + 0 + (64 * b_ModulNbr));
633
634							/* Read the timer 1 value */
635							pul_TimerValueArray[1] = inl(devpriv->s_BoardInfos.ui_Address + 4 + (64 * b_ModulNbr));
636
637							/* Read the timer 2 value */
638							pul_TimerValueArray[2] = inl(devpriv->s_BoardInfos.ui_Address + 8 + (64 * b_ModulNbr));
639						} else {
640							/* Timer 2 not initialised see function */
641							DPRINTK("Timer 2 not initialised see function\n");
642							i_ReturnValue = -6;
643						}
644					} else {
645						/* Timer 1 not initialised see function */
646						DPRINTK("Timer 1 not initialised see function\n");
647						i_ReturnValue = -5;
648					}
649				} else {
650					/* Timer 0 not initialised see function */
651					DPRINTK("Timer 0 not initialised see function\n");
652					i_ReturnValue = -4;
653				}
654			} else {
655				/* The module is not a TIMER module */
656				DPRINTK("The module is not a TIMER module\n");
657				i_ReturnValue = -3;
658			}
659		} else {
660			/* Module number error */
661			DPRINTK("Module number error\n");
662			i_ReturnValue = -2;
663		}
664
665	}			// End of Switch
666	return (i_ReturnValue);
667}
668
669/*
670+----------------------------------------------------------------------------+
671| Function Name     :INT i_APCI1710_InsnBitsTimer(struct comedi_device *dev,
672struct comedi_subdevice *s,comedi_insn *insn,unsigned int *data)                   |
673+----------------------------------------------------------------------------+
674| Task              : Read write functions for Timer                                          |
675+----------------------------------------------------------------------------+
676| Input Parameters  :
677+----------------------------------------------------------------------------+
678| Output Parameters : -                                                      |
679+----------------------------------------------------------------------------+
680| Return Value      :
681+----------------------------------------------------------------------------+
682*/
683
684INT i_APCI1710_InsnBitsTimer(struct comedi_device * dev, struct comedi_subdevice * s,
685			     comedi_insn * insn, unsigned int * data)
686{
687	BYTE b_BitsType;
688	INT i_ReturnValue = 0;
689	b_BitsType = data[0];
690
691	printk("\n82X54");
692
693	switch (b_BitsType) {
694	case APCI1710_TIMER_READVALUE:
695		i_ReturnValue = i_APCI1710_ReadTimerValue(dev,
696							  (BYTE)CR_AREF(insn->chanspec),
697							  (BYTE)CR_CHAN(insn->chanspec),
698							  (PULONG) & data[0]);
699		break;
700
701	case APCI1710_TIMER_GETOUTPUTLEVEL:
702		i_ReturnValue = i_APCI1710_GetTimerOutputLevel(dev,
703							       (BYTE)CR_AREF(insn->chanspec),
704							       (BYTE)CR_CHAN(insn->chanspec),
705							       (PBYTE) &data[0]);
706		break;
707
708	case APCI1710_TIMER_GETPROGRESSSTATUS:
709		i_ReturnValue = i_APCI1710_GetTimerProgressStatus(dev,
710								  (BYTE)CR_AREF(insn->chanspec),
711								  (BYTE)CR_CHAN(insn->chanspec),
712								  (PBYTE)&data[0]);
713		break;
714
715	case APCI1710_TIMER_WRITEVALUE:
716		i_ReturnValue = i_APCI1710_WriteTimerValue(dev,
717							   (BYTE)CR_AREF(insn->chanspec),
718							   (BYTE)CR_CHAN(insn->chanspec),
719							   (ULONG)data[1]);
720
721		break;
722
723	default:
724		printk("Bits Config Parameter Wrong\n");
725		i_ReturnValue = -1;
726	}
727
728	if (i_ReturnValue >= 0)
729		i_ReturnValue = insn->n;
730	return (i_ReturnValue);
731}
732
733/*
734+----------------------------------------------------------------------------+
735| Function Name     : _INT_     i_APCI1710_ReadTimerValue                    |
736|                                       (BYTE_     b_BoardHandle,            |
737|                                        BYTE_     b_ModulNbr,               |
738|                                        BYTE_     b_TimerNbr,               |
739|                                        PULONG_ pul_TimerValue)             |
740+----------------------------------------------------------------------------+
741| Task              : Return the timer value from selected digital timer     |
742|                     (b_TimerNbr) from selected timer  module (b_ModulNbr). |
743+----------------------------------------------------------------------------+
744| Input Parameters  : BYTE_   b_BoardHandle     : Handle of board            |
745|                                                 APCI-1710                  |
746|                     BYTE_   b_ModulNbr        : Selected module number     |
747|                                                 (0 to 3)                   |
748|                     BYTE_   b_TimerNbr        : Timer number to read       |
749|                                                 (0 to 2)                   |
750+----------------------------------------------------------------------------+
751| Output Parameters : PULONG_ pul_TimerValue    : Timer value                |
752+----------------------------------------------------------------------------+
753| Return Value      : 0: No error                                            |
754|                    -1: The handle parameter of the board is wrong          |
755|                    -2: Module selection wrong                              |
756|                    -3: Timer selection wrong                               |
757|                    -4: The module is not a TIMER module                    |
758|                    -5: Timer not initialised see function                  |
759|                        "i_APCI1710_InitTimer"                              |
760+----------------------------------------------------------------------------+
761*/
762
763INT i_APCI1710_ReadTimerValue(struct comedi_device * dev,
764			      BYTE b_ModulNbr, BYTE b_TimerNbr,
765			      PULONG pul_TimerValue)
766{
767	INT i_ReturnValue = 0;
768
769	/* Test the module number */
770	if (b_ModulNbr < 4) {
771		/* Test if 82X54 timer */
772		if ((devpriv->s_BoardInfos.
773		     dw_MolduleConfiguration[b_ModulNbr] &
774		     0xFFFF0000UL) == APCI1710_82X54_TIMER) {
775			/* Test the timer number */
776			if (b_TimerNbr <= 2) {
777				/* Test if timer initialised */
778				if (devpriv->
779				    s_ModuleInfo[b_ModulNbr].
780				    s_82X54ModuleInfo.
781				    s_82X54TimerInfo[b_TimerNbr].
782				    b_82X54Init == 1) {
783					/* Latch the timer value */
784					outl((2 << b_TimerNbr) | 0xD0,
785					     devpriv->s_BoardInfos.
786					     ui_Address + 12 +
787					     (64 * b_ModulNbr));
788
789					/* Read the counter value */
790					*pul_TimerValue =
791					    inl(devpriv->s_BoardInfos.
792						ui_Address + (b_TimerNbr * 4) +
793						(64 * b_ModulNbr));
794				} else {
795					/* Timer not initialised see function */
796					DPRINTK("Timer not initialised see function\n");
797					i_ReturnValue = -5;
798				}
799			} else {
800				/* Timer selection wrong */
801				DPRINTK("Timer selection wrong\n");
802				i_ReturnValue = -3;
803			}	// if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2))
804		} else {
805			/* The module is not a TIMER module */
806			DPRINTK("The module is not a TIMER module\n");
807			i_ReturnValue = -4;
808		}
809	} else {
810		/* Module number error */
811		DPRINTK("Module number error\n");
812		i_ReturnValue = -2;
813	}
814
815	return (i_ReturnValue);
816}
817
818	/*
819	   +----------------------------------------------------------------------------+
820	   | Function Name     : _INT_     i_APCI1710_GetTimerOutputLevel               |
821	   |                                       (BYTE_     b_BoardHandle,            |
822	   |                                        BYTE_     b_ModulNbr,               |
823	   |                                        BYTE_     b_TimerNbr,               |
824	   |                                        PBYTE_   pb_OutputLevel)            |
825	   +----------------------------------------------------------------------------+
826	   | Task              : Return the output signal level (pb_OutputLevel) from   |
827	   |                     selected digital timer (b_TimerNbr) from selected timer|
828	   |                     module (b_ModulNbr).                                   |
829	   +----------------------------------------------------------------------------+
830	   | Input Parameters  : BYTE_   b_BoardHandle     : Handle of board            |
831	   |                                                 APCI-1710                  |
832	   |                     BYTE_   b_ModulNbr        : Selected module number     |
833	   |                                                 (0 to 3)                   |
834	   |                     BYTE_   b_TimerNbr        : Timer number to test       |
835	   |                                                 (0 to 2)                   |
836	   +----------------------------------------------------------------------------+
837	   | Output Parameters : PBYTE_ pb_OutputLevel     : Output signal level        |
838	   |                                                 0 : The output is low      |
839	   |                                                 1 : The output is high     |
840	   +----------------------------------------------------------------------------+
841	   | Return Value      : 0: No error                                            |
842	   |                    -1: The handle parameter of the board is wrong          |
843	   |                    -2: Module selection wrong                              |
844	   |                    -3: Timer selection wrong                               |
845	   |                    -4: The module is not a TIMER module                    |
846	   |                    -5: Timer not initialised see function                  |
847	   |                        "i_APCI1710_InitTimer"                              |
848	   +----------------------------------------------------------------------------+
849	 */
850
851INT i_APCI1710_GetTimerOutputLevel(struct comedi_device * dev,
852				   BYTE b_ModulNbr, BYTE b_TimerNbr,
853				   PBYTE pb_OutputLevel)
854{
855	INT i_ReturnValue = 0;
856	DWORD dw_TimerStatus;
857
858	/* Test the module number */
859	if (b_ModulNbr < 4) {
860		/* Test if 82X54 timer */
861		if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) {
862			/* Test the timer number */
863			if (b_TimerNbr <= 2) {
864				/* Test if timer initialised */
865				if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init == 1) {
866					/* Latch the timer value */
867					outl((2 << b_TimerNbr) | 0xE0, devpriv->s_BoardInfos.ui_Address + 12 + (64 * b_ModulNbr));
868
869					/* Read the timer status */
870					dw_TimerStatus = inl(devpriv->s_BoardInfos.ui_Address + 16 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
871
872					*pb_OutputLevel = (BYTE) (((dw_TimerStatus >> 7) & 1) ^ devpriv-> s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_OutputLevel);
873				} else {
874					/* Timer not initialised see function */
875					DPRINTK("Timer not initialised see function\n");
876					i_ReturnValue = -5;
877				}
878			} else {
879				/* Timer selection wrong */
880				DPRINTK("Timer selection wrong\n");
881				i_ReturnValue = -3;
882			}	// if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2))
883		} else {
884			/* The module is not a TIMER module */
885			DPRINTK("The module is not a TIMER module\n");
886			i_ReturnValue = -4;
887		}
888	} else {
889		/* Module number error */
890		DPRINTK("Module number error\n");
891		i_ReturnValue = -2;
892	}
893
894	return (i_ReturnValue);
895}
896
897/*
898+----------------------------------------------------------------------------+
899| Function Name     : _INT_     i_APCI1710_GetTimerProgressStatus            |
900|                                       (BYTE_     b_BoardHandle,            |
901|                                        BYTE_     b_ModulNbr,               |
902|                                        BYTE_     b_TimerNbr,               |
903|                                        PBYTE_   pb_TimerStatus)            |
904+----------------------------------------------------------------------------+
905| Task              : Return the progress status (pb_TimerStatus) from       |
906|                     selected digital timer (b_TimerNbr) from selected timer|
907|                     module (b_ModulNbr).                                   |
908+----------------------------------------------------------------------------+
909| Input Parameters  : BYTE_   b_BoardHandle     : Handle of board            |
910|                                                 APCI-1710                  |
911|                     BYTE_   b_ModulNbr        : Selected module number     |
912|                                                 (0 to 3)                   |
913|                     BYTE_   b_TimerNbr        : Timer number to test       |
914|                                                 (0 to 2)                   |
915+----------------------------------------------------------------------------+
916| Output Parameters : PBYTE_ pb_TimerStatus     : Output signal level        |
917|                                                 0 : Timer not in progress  |
918|                                                 1 : Timer in progress      |
919+----------------------------------------------------------------------------+
920| Return Value      : 0: No error                                            |
921|                    -1: The handle parameter of the board is wrong          |
922|                    -2: Module selection wrong                              |
923|                    -3: Timer selection wrong                               |
924|                    -4: The module is not a TIMER module                    |
925|                    -5: Timer not initialised see function                  |
926|                        "i_APCI1710_InitTimer"                              |
927+----------------------------------------------------------------------------+
928*/
929
930INT i_APCI1710_GetTimerProgressStatus(struct comedi_device *dev,
931				      BYTE b_ModulNbr, BYTE b_TimerNbr,
932				      PBYTE pb_TimerStatus)
933{
934	INT i_ReturnValue = 0;
935	DWORD dw_TimerStatus;
936
937	/* Test the module number */
938	if (b_ModulNbr < 4) {
939		/* Test if 82X54 timer */
940
941		if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) {
942			/* Test the timer number */
943			if (b_TimerNbr <= 2) {
944				/* Test if timer initialised */
945				if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init == 1) {
946					/* Latch the timer value */
947					outl((2 << b_TimerNbr) | 0xE0, devpriv->s_BoardInfos.ui_Address + 12 + (64 * b_ModulNbr));
948
949					/* Read the timer status */
950					dw_TimerStatus = inl(devpriv->s_BoardInfos.ui_Address + 16 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
951
952					*pb_TimerStatus = (BYTE) ((dw_TimerStatus) >> 8) & 1;
953					printk("ProgressStatus : %d", *pb_TimerStatus);
954				} else {
955					/* Timer not initialised see function */
956					i_ReturnValue = -5;
957				}
958			} else {
959				/* Timer selection wrong */
960				i_ReturnValue = -3;
961			}	// if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2))
962		} else {
963			/* The module is not a TIMER module */
964
965			i_ReturnValue = -4;
966		}
967	} else {
968		/* Module number error */
969
970		i_ReturnValue = -2;
971	}
972
973	return i_ReturnValue;
974}
975
976/*
977+----------------------------------------------------------------------------+
978| Function Name     : _INT_     i_APCI1710_WriteTimerValue                   |
979|                                       (BYTE_   b_BoardHandle,              |
980|                                        BYTE_   b_ModulNbr,                 |
981|                                        BYTE_   b_TimerNbr,                 |
982|                                        ULONG_ ul_WriteValue)               |
983+----------------------------------------------------------------------------+
984| Task              : Write the value (ul_WriteValue) into the selected timer|
985|                     (b_TimerNbr) from selected timer module (b_ModulNbr).  |
986|                     The action in depend of the time mode selection.       |
987|                     See timer mode description table.                      |
988+----------------------------------------------------------------------------+
989| Input Parameters  : BYTE_   b_BoardHandle     : Handle of board            |
990|                                                 APCI-1710                  |
991|                     BYTE_   b_ModulNbr        : Selected module number     |
992|                                                 (0 to 3)                   |
993|                     BYTE_   b_TimerNbr        : Timer number to write      |
994|                                                 (0 to 2)                   |
995|                     ULONG_ ul_WriteValue      : Value to write             |
996+----------------------------------------------------------------------------+
997| Output Parameters : -                                                      |
998+----------------------------------------------------------------------------+
999| Return Value      : 0: No error                                            |
1000|                    -1: The handle parameter of the board is wrong          |
1001|                    -2: Module selection wrong                              |
1002|                    -3: Timer selection wrong                               |
1003|                    -4: The module is not a TIMER module                    |
1004|                    -5: Timer not initialised see function                  |
1005|                        "i_APCI1710_InitTimer"                              |
1006+----------------------------------------------------------------------------+
1007*/
1008
1009INT i_APCI1710_WriteTimerValue(struct comedi_device * dev,
1010			       BYTE b_ModulNbr, BYTE b_TimerNbr,
1011			       ULONG ul_WriteValue)
1012{
1013	INT i_ReturnValue = 0;
1014
1015	/* Test the module number */
1016	if (b_ModulNbr < 4) {
1017		/* Test if 82X54 timer */
1018		if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) {
1019			/* Test the timer number */
1020			if (b_TimerNbr <= 2) {
1021				/* Test if timer initialised */
1022				if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init == 1) {
1023					/* Write the value */
1024					outl(ul_WriteValue, devpriv->s_BoardInfos.ui_Address + (b_TimerNbr * 4) + (64 * b_ModulNbr));
1025				} else {
1026					/* Timer not initialised see function */
1027					DPRINTK("Timer not initialised see function\n");
1028					i_ReturnValue = -5;
1029				}
1030			} else {
1031				/* Timer selection wrong */
1032				DPRINTK("Timer selection wrong\n");
1033				i_ReturnValue = -3;
1034			}	// if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2))
1035		} else {
1036			/* The module is not a TIMER module */
1037			DPRINTK("The module is not a TIMER module\n");
1038			i_ReturnValue = -4;
1039		}
1040	} else {
1041		/* Module number error */
1042		DPRINTK("Module number error\n");
1043		i_ReturnValue = -2;
1044	}
1045
1046	return i_ReturnValue;
1047}
1048