Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /*- |
2 | * Copyright (c) 1990 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * This code is derived from software contributed to Berkeley by | |
6 | * William Jolitz and Don Ahn. | |
7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | |
11 | * 1. Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | |
13 | * 2. Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in the | |
15 | * documentation and/or other materials provided with the distribution. | |
16 | * 3. All advertising materials mentioning features or use of this software | |
17 | * must display the following acknowledgement: | |
18 | * This product includes software developed by the University of | |
19 | * California, Berkeley and its contributors. | |
20 | * 4. Neither the name of the University nor the names of its contributors | |
21 | * may be used to endorse or promote products derived from this software | |
22 | * without specific prior written permission. | |
23 | * | |
24 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
34 | * SUCH DAMAGE. | |
35 | * | |
78ed81a3 | 36 | * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 |
37 | * $Id$ | |
15637ed4 RG |
38 | */ |
39 | ||
40 | /* | |
41 | * Primitive clock interrupt routines. | |
42 | */ | |
43 | #include "param.h" | |
44 | #include "systm.h" | |
45 | #include "time.h" | |
46 | #include "kernel.h" | |
47 | #include "machine/segments.h" | |
48 | #include "i386/isa/icu.h" | |
49 | #include "i386/isa/isa.h" | |
50 | #include "i386/isa/rtc.h" | |
51 | #include "i386/isa/timerreg.h" | |
52 | ||
53 | #define DAYST 119 | |
54 | #define DAYEN 303 | |
55 | ||
56 | /* X-tals being what they are, it's nice to be able to fudge this one... */ | |
57 | /* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */ | |
58 | #ifndef TIMER_FREQ | |
59 | #define TIMER_FREQ 1193182 /* XXX - should be in isa.h */ | |
60 | #endif | |
61 | ||
62 | startrtclock() { | |
63 | int s; | |
64 | ||
65 | findcpuspeed(); /* use the clock (while it's free) | |
66 | to find the cpu speed */ | |
67 | /* initialize 8253 clock */ | |
68 | outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); | |
69 | ||
70 | /* Correct rounding will buy us a better precision in timekeeping */ | |
71 | outb (IO_TIMER1, (TIMER_FREQ+hz/2)/hz); | |
72 | outb (IO_TIMER1, ((TIMER_FREQ+hz/2)/hz)/256); | |
73 | ||
74 | /* initialize brain-dead battery powered clock */ | |
75 | outb (IO_RTC, RTC_STATUSA); | |
76 | outb (IO_RTC+1, 0x26); | |
77 | outb (IO_RTC, RTC_STATUSB); | |
78 | outb (IO_RTC+1, 2); | |
79 | ||
80 | outb (IO_RTC, RTC_DIAG); | |
81 | if (s = inb (IO_RTC+1)) | |
82 | printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS); | |
83 | outb (IO_RTC, RTC_DIAG); | |
84 | outb (IO_RTC+1, 0); | |
85 | } | |
86 | ||
87 | unsigned int delaycount; /* calibrated loop variable (1 millisecond) */ | |
88 | ||
89 | #define FIRST_GUESS 0x2000 | |
90 | findcpuspeed() | |
91 | { | |
92 | unsigned char low; | |
93 | unsigned int remainder; | |
94 | ||
95 | /* Put counter in count down mode */ | |
96 | outb(IO_TIMER1+3, 0x34); | |
97 | outb(IO_TIMER1, 0xff); | |
98 | outb(IO_TIMER1, 0xff); | |
99 | delaycount = FIRST_GUESS; | |
100 | spinwait(1); | |
101 | /* Read the value left in the counter */ | |
102 | low = inb(IO_TIMER1); /* least siginifcant */ | |
103 | remainder = inb(IO_TIMER1); /* most significant */ | |
104 | remainder = (remainder<<8) + low ; | |
105 | /* Formula for delaycount is : | |
106 | * (loopcount * timer clock speed)/ (counter ticks * 1000) | |
107 | */ | |
108 | delaycount = (FIRST_GUESS * (TIMER_FREQ/1000)) / (0xffff-remainder); | |
109 | } | |
110 | ||
111 | ||
112 | /* convert 2 digit BCD number */ | |
113 | bcd(i) | |
114 | int i; | |
115 | { | |
116 | return ((i/16)*10 + (i%16)); | |
117 | } | |
118 | ||
119 | /* convert years to seconds (from 1970) */ | |
120 | unsigned long | |
121 | ytos(y) | |
122 | int y; | |
123 | { | |
124 | int i; | |
125 | unsigned long ret; | |
126 | ||
127 | ret = 0; | |
128 | for(i = 1970; i < y; i++) { | |
129 | if (i % 4) ret += 365*24*60*60; | |
130 | else ret += 366*24*60*60; | |
131 | } | |
132 | return ret; | |
133 | } | |
134 | ||
135 | /* convert months to seconds */ | |
136 | unsigned long | |
137 | mtos(m,leap) | |
138 | int m,leap; | |
139 | { | |
140 | int i; | |
141 | unsigned long ret; | |
142 | ||
143 | ret = 0; | |
144 | for(i=1;i<m;i++) { | |
145 | switch(i){ | |
146 | case 1: case 3: case 5: case 7: case 8: case 10: case 12: | |
147 | ret += 31*24*60*60; break; | |
148 | case 4: case 6: case 9: case 11: | |
149 | ret += 30*24*60*60; break; | |
150 | case 2: | |
151 | if (leap) ret += 29*24*60*60; | |
152 | else ret += 28*24*60*60; | |
153 | } | |
154 | } | |
155 | return ret; | |
156 | } | |
157 | ||
158 | ||
159 | /* | |
160 | * Initialize the time of day register, based on the time base which is, e.g. | |
161 | * from a filesystem. | |
162 | */ | |
163 | inittodr(base) | |
164 | time_t base; | |
165 | { | |
166 | unsigned long sec; | |
167 | int leap,day_week,t,yd; | |
168 | int sa,s; | |
169 | ||
170 | /* do we have a realtime clock present? (otherwise we loop below) */ | |
171 | sa = rtcin(RTC_STATUSA); | |
172 | if (sa == 0xff || sa == 0) return; | |
173 | ||
174 | /* ready for a read? */ | |
175 | while ((sa&RTCSA_TUP) == RTCSA_TUP) | |
176 | sa = rtcin(RTC_STATUSA); | |
177 | ||
178 | sec = bcd(rtcin(RTC_YEAR)) + 1900; | |
179 | if (sec < 1970) | |
180 | sec += 100; | |
181 | leap = !(sec % 4); sec = ytos(sec); /* year */ | |
182 | yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec += yd; /* month */ | |
183 | t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec += t; yd += t; /* date */ | |
184 | day_week = rtcin(RTC_WDAY); /* day */ | |
185 | sec += bcd(rtcin(RTC_HRS)) * 60*60; /* hour */ | |
186 | sec += bcd(rtcin(RTC_MIN)) * 60; /* minutes */ | |
187 | sec += bcd(rtcin(RTC_SEC)); /* seconds */ | |
188 | ||
189 | /* XXX off by one? Need to calculate DST on SUNDAY */ | |
190 | /* Perhaps we should have the RTC hold GMT time to save */ | |
191 | /* us the bother of converting. */ | |
192 | yd = yd / (24*60*60); | |
193 | if ((yd >= DAYST) && ( yd <= DAYEN)) { | |
194 | sec -= 60*60; | |
195 | } | |
196 | sec += tz.tz_minuteswest * 60; | |
197 | ||
198 | time.tv_sec = sec; | |
199 | } | |
200 | ||
201 | #ifdef garbage | |
202 | /* | |
203 | * Initialze the time of day register, based on the time base which is, e.g. | |
204 | * from a filesystem. | |
205 | */ | |
206 | test_inittodr(base) | |
207 | time_t base; | |
208 | { | |
209 | ||
210 | outb(IO_RTC,9); /* year */ | |
211 | printf("%d ",bcd(inb(IO_RTC+1))); | |
212 | outb(IO_RTC,8); /* month */ | |
213 | printf("%d ",bcd(inb(IO_RTC+1))); | |
214 | outb(IO_RTC,7); /* day */ | |
215 | printf("%d ",bcd(inb(IO_RTC+1))); | |
216 | outb(IO_RTC,4); /* hour */ | |
217 | printf("%d ",bcd(inb(IO_RTC+1))); | |
218 | outb(IO_RTC,2); /* minutes */ | |
219 | printf("%d ",bcd(inb(IO_RTC+1))); | |
220 | outb(IO_RTC,0); /* seconds */ | |
221 | printf("%d\n",bcd(inb(IO_RTC+1))); | |
222 | ||
223 | time.tv_sec = base; | |
224 | } | |
225 | #endif | |
226 | ||
227 | /* | |
228 | * Restart the clock. | |
229 | */ | |
230 | resettodr() | |
231 | { | |
232 | } | |
233 | ||
234 | /* | |
235 | * Wire clock interrupt in. | |
236 | */ | |
237 | #define V(s) __CONCAT(V, s) | |
238 | extern V(clk)(); | |
239 | enablertclock() { | |
240 | setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL); | |
241 | INTREN(IRQ0); | |
242 | } | |
243 | ||
244 | /* | |
245 | * Delay for some number of milliseconds. | |
246 | */ | |
247 | void | |
248 | spinwait(millisecs) | |
249 | int millisecs; | |
250 | { | |
251 | DELAY(1000 * millisecs); | |
252 | } |