Change all the file headers to LGPL
[comedilib.git] / lib / timer.c
1 /*
2     lib/timer.c
3     legacy timer crap
4
5     COMEDILIB - Linux Control and Measurement Device Interface Library
6     Copyright (C) 1997-2001 David A. Schleef <ds@schleef.org>
7
8     This library is free software; you can redistribute it and/or
9     modify it under the terms of the GNU Lesser General Public
10     License as published by the Free Software Foundation, version 2.1
11     of the License.
12
13     This library 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 GNU
16     Lesser General Public License for more details.
17
18     You should have received a copy of the GNU Lesser General Public
19     License along with this library; if not, write to the Free Software
20     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
21     USA.
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