dio fixes
[comedilib.git] / lib / timer.c
1 /*
2     lib/comedi.c
3     comedi library routines
4
5     COMEDI - Linux Control and Measurement Device Interface
6     Copyright (C) 1997-8 David A. Schleef <ds@stm.lbl.gov>
7
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17
18     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 */
23
24 #include <stdio.h>
25 #include <math.h>
26 #include <stdlib.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <sys/ioctl.h>
32 #include <errno.h>
33 #include <comedi.h>
34 #include <string.h>
35
36 #include <libinternal.h>
37
38
39
40 /* dt282x timer */
41
42 static int dt282x_timer(double freq,unsigned int *trigvar,double *actual_freq)
43 {
44         int divider,prescaler;
45         double basefreq=4e6;
46         
47         divider=floor(4e6/(freq));
48         prescaler=0;
49         while(divider>255){
50                 prescaler++;
51                 divider>>=1;
52                 basefreq/=2;
53         }
54         if(prescaler==1){
55                 prescaler++;
56                 divider>>=1;
57                 basefreq/=2;
58         }
59         if(prescaler>=16)return -1;
60         *trigvar=(prescaler<<8)|(255-divider);
61         *actual_freq=basefreq/divider;
62         
63         return 0;
64 }
65
66
67 /* dt2814 timer */
68 static int dt2814_timer(double freq,unsigned int *trigvar,double *actual_freq)
69 {
70         double f;
71         int  i;
72         
73         f=1e5;
74         for(i=0;i<8;i++){
75                 if(f-freq<freq-f/10){
76                         *trigvar=i;
77                         *actual_freq=f;
78                         return 0;
79                 }
80                 f/=10;
81         }
82         *trigvar=i;
83         *actual_freq=f;
84         
85         return 0;
86 }
87
88 /* atmio/pcimio timer */
89 static int atmio_timer(double freq,unsigned int *trigvar,double *actual_freq)
90 {
91         unsigned int divider;
92         
93         divider=floor(20e6/(freq));
94         *actual_freq=20e6/divider;
95         *trigvar=divider-1;
96         
97         return 0;
98 }
99
100 /* acl8112 timer */
101 static int acl8112_timer(double freq,unsigned int *trigvar,double *actual_freq)
102 {
103         int divider,prescaler;
104         double basefreq=2e6;
105
106         /* XXX my notes say that the prescaler and divider cannot
107            be 1.  This needs to be checked.  --ds */
108         
109         /* Force at least one division to get something in CTR2. */
110         prescaler=1;
111         divider = basefreq/(freq);
112
113         while(divider>32767){
114                 prescaler*=2;
115                 divider>>=1;
116         }
117
118         *trigvar = (prescaler<<16) | divider;
119         *actual_freq=basefreq/(divider*prescaler);
120         
121         return 0;
122 }
123
124 /* nanosec timer */
125 static int nanosec_timer(double freq,unsigned int *trigvar,double *actual_freq)
126 {
127         *trigvar=(1e9/freq);
128         *actual_freq=1e9/(*trigvar);
129
130         return 0;
131 }
132
133 typedef int (*timerfunc)(double freq,unsigned int *trigvar,double *actual_freq);
134
135 static timerfunc timer_functions[]={
136         NULL,
137         dt282x_timer,
138         dt2814_timer,
139         atmio_timer,
140         acl8112_timer,
141         nanosec_timer,
142 };
143 #define N_TIMERTYPES 6
144
145 int comedi_get_timer(comedi_t *it,unsigned int subdev,double freq,
146         unsigned int *trigvar,double *actual_freq)
147 {
148         int timer_type;
149         
150         if(!it || !trigvar || !actual_freq)
151                 return -1;
152
153         timer_type=it->subdevices[subdev].timer_type;
154         
155         if(timer_type==0 || timer_type>=N_TIMERTYPES)
156                 return -1;
157         
158         return (timer_functions[timer_type])(freq,trigvar,actual_freq);
159 }
160