This commit was manufactured by cvs2svn to create tag 'FreeBSD-release/1.0'.
[unix-history] / sys / i386 / isa / clock.c
CommitLineData
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
62startrtclock() {
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
87unsigned int delaycount; /* calibrated loop variable (1 millisecond) */
88
89#define FIRST_GUESS 0x2000
90findcpuspeed()
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 */
113bcd(i)
114int i;
115{
116 return ((i/16)*10 + (i%16));
117}
118
119/* convert years to seconds (from 1970) */
120unsigned long
121ytos(y)
122int 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 */
136unsigned long
137mtos(m,leap)
138int 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 */
163inittodr(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 */
206test_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 */
230resettodr()
231{
232}
233
234/*
235 * Wire clock interrupt in.
236 */
237#define V(s) __CONCAT(V, s)
238extern V(clk)();
239enablertclock() {
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 */
247void
248spinwait(millisecs)
249 int millisecs;
250{
251 DELAY(1000 * millisecs);
252}