Commit | Line | Data |
---|---|---|
af5295ff KM |
1 | /* |
2 | * Copyright (c) 1988 University of Utah. | |
3 | * Copyright (c) 1992 The Regents of the University of California. | |
4 | * All rights reserved. | |
5 | * | |
6 | * This code is derived from software contributed to Berkeley by | |
7 | * the Systems Programming Group of the University of Utah Computer | |
8 | * Science Department, Ralph Campbell, and Kazumasa Utashiro of | |
9 | * Software Research Associates, Inc. | |
10 | * | |
11 | * %sccs.include.redist.c% | |
12 | * | |
13 | * from: Utah $Hdr: clock.c 1.18 91/01/21$ | |
14 | * | |
679d1338 | 15 | * @(#)clock.c 7.4 (Berkeley) %G% |
af5295ff KM |
16 | */ |
17 | ||
18 | #include "../include/fix_machine_type.h" | |
19 | #include "../include/adrsmap.h" | |
20 | ||
21 | #include "param.h" | |
22 | #include "kernel.h" | |
23 | ||
24 | #include "clockreg.h" | |
25 | ||
26 | /* | |
27 | * Machine-dependent clock routines. | |
28 | * | |
29 | * Startrtclock restarts the real-time clock, which provides | |
30 | * hardclock interrupts to kern_clock.c. | |
31 | * | |
32 | * Inittodr initializes the time of day hardware which provides | |
33 | * date functions. Its primary function is to use some file | |
34 | * system information in case the hardare clock lost state. | |
35 | * | |
36 | * Resettodr restores the time of day hardware after a time change. | |
37 | */ | |
38 | ||
6d429c8e KB |
39 | /* |
40 | * We assume newhz is either stathz or profhz, and that neither will | |
41 | * change after being set up above. Could recalculate intervals here | |
42 | * but that would be a drag. | |
43 | */ | |
44 | void | |
45 | setstatclockrate(newhz) | |
46 | int newhz; | |
47 | { | |
48 | ||
49 | /* KU:XXX do something! */ | |
50 | } | |
51 | ||
af5295ff KM |
52 | /* |
53 | * Start the real-time clock. | |
54 | */ | |
6d429c8e | 55 | static void |
af5295ff KM |
56 | startrtclock() |
57 | { | |
58 | ||
59 | *(char *)ITIMER = IOCLOCK / 6144 / 100 - 1; | |
60 | } | |
61 | ||
62 | /* | |
63 | * Enable the real-time clock. | |
64 | */ | |
6d429c8e | 65 | static void |
af5295ff KM |
66 | enablertclock() |
67 | { | |
68 | ||
69 | *(char *)INTEN0 |= (char)INTEN0_TIMINT; | |
70 | } | |
71 | ||
679d1338 KU |
72 | /* |
73 | * Set up the real-time and statistics clocks. Leave stathz 0 only if | |
74 | * no alternative timer is available. | |
75 | * | |
76 | */ | |
77 | cpu_initclocks() | |
78 | { | |
79 | ||
80 | startrtclock(); | |
81 | enablertclock(); | |
82 | } | |
83 | ||
af5295ff KM |
84 | /* |
85 | * This code is defunct after 2099. | |
86 | * Will Unix still be here then?? | |
87 | */ | |
88 | static short dayyr[12] = { | |
89 | 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 | |
90 | }; | |
91 | ||
f8bea1d3 | 92 | #define bcd_to_int(BCD) (i = BCD, (((i) >> 4) & 0xf) * 10 + ((i) & 0xf)) |
af5295ff KM |
93 | #define int_to_bcd(INT) (i = INT, ((((i) / 10) % 10) << 4) + (i) % 10) |
94 | ||
95 | /* | |
96 | * Initialze the time of day register, based on the time base which is, e.g. | |
97 | * from a filesystem. Base provides the time to within six months, | |
98 | * and the time of year clock (if any) provides the rest. | |
99 | */ | |
100 | inittodr(base) | |
101 | time_t base; | |
102 | { | |
103 | register volatile u_char *rtc_port = (u_char *)RTC_PORT; | |
104 | register volatile u_char *rtc_data = (u_char *)DATA_PORT; | |
105 | register int days, yr; | |
106 | int sec, min, hour, week, day, mon, year; | |
107 | long deltat, badbase = 0; | |
f8bea1d3 | 108 | register u_int i; |
af5295ff KM |
109 | |
110 | if (base < 5*SECYR) { | |
111 | printf("WARNING: preposterous time in file system\n"); | |
112 | /* read the system clock anyway */ | |
113 | base = 6*SECYR + 186*SECDAY + SECDAY/2; | |
114 | badbase = 1; | |
115 | } | |
116 | ||
117 | *rtc_port = READ_CLOCK; | |
118 | sec = bcd_to_int(*rtc_data++); | |
119 | min = bcd_to_int(*rtc_data++); | |
120 | hour = bcd_to_int(*rtc_data++); | |
121 | week = bcd_to_int(*rtc_data++); | |
122 | day = bcd_to_int(*rtc_data++); | |
123 | mon = bcd_to_int(*rtc_data++); | |
124 | year = bcd_to_int(*rtc_data++); | |
125 | *rtc_port = 0; | |
126 | ||
127 | /* simple sanity checks */ | |
128 | if (year < 70 || mon < 1 || mon > 12 || day < 1 || day > 31 || | |
129 | hour > 23 || min > 59 || sec > 59) { | |
f8bea1d3 | 130 | printf("WARNING: preposterous clock chip time\n"); |
af5295ff KM |
131 | /* |
132 | * Believe the time in the file system for lack of | |
133 | * anything better, resetting the TODR. | |
134 | */ | |
135 | time.tv_sec = base; | |
136 | if (!badbase) | |
137 | resettodr(); | |
138 | return (0); | |
139 | } | |
140 | days = 0; | |
141 | for (yr = 70; yr < year; yr++) | |
142 | days += LEAPYEAR(yr) ? 366 : 365; | |
143 | days += dayyr[mon - 1] + day - 1; | |
144 | if (LEAPYEAR(yr) && mon > 2) | |
145 | days++; | |
146 | /* now have days since Jan 1, 1970; the rest is easy... */ | |
147 | time.tv_sec = days * SECDAY + hour * 3600 + min * 60 + sec; | |
148 | ||
149 | if (!badbase) { | |
150 | /* | |
151 | * See if we gained/lost two or more days; | |
152 | * if so, assume something is amiss. | |
153 | */ | |
154 | deltat = time.tv_sec - base; | |
155 | if (deltat < 0) | |
156 | deltat = -deltat; | |
157 | if (deltat < 2 * SECDAY) | |
158 | return; | |
159 | printf("WARNING: clock %s %d days", | |
160 | time.tv_sec < base ? "lost" : "gained", deltat / SECDAY); | |
161 | } | |
162 | printf(" -- CHECK AND RESET THE DATE!\n"); | |
163 | } | |
164 | ||
165 | /* | |
166 | * Reset the TODR based on the time value; used when the TODR | |
167 | * has a preposterous value and also when the time is reset | |
168 | * by the stime system call. Also called when the TODR goes past | |
169 | * TODRZERO + 100*(SECYEAR+2*SECDAY) (e.g. on Jan 2 just after midnight) | |
170 | * to wrap the TODR around. | |
171 | */ | |
172 | resettodr() | |
173 | { | |
174 | register volatile u_char *rtc_port = (u_char *)RTC_PORT; | |
175 | register volatile u_char *rtc_data = (u_char *)DATA_PORT; | |
176 | int sec, min, hour, week, day, mon, year; | |
177 | register int t, t2, t3; | |
178 | register int i; | |
179 | ||
180 | /* compute the year */ | |
181 | t2 = time.tv_sec / SECDAY; | |
182 | t = 69; | |
183 | while (t2 >= 0) { /* whittle off years */ | |
184 | t3 = t2; | |
185 | t++; | |
186 | t2 -= LEAPYEAR(t) ? 366 : 365; | |
187 | } | |
188 | ||
189 | year = t; | |
190 | ||
191 | /* t3 = month + day; separate */ | |
192 | t = LEAPYEAR(t); | |
193 | for (t2 = 1; t2 < 12; t2++) | |
194 | if (t3 < dayyr[t2] + (t && t2 > 1)) | |
195 | break; | |
196 | ||
197 | /* t2 is month */ | |
198 | mon = t2; | |
199 | t3 = t3 - dayyr[t2 - 1] + 1; | |
200 | if (t && t2 > 2) | |
201 | t3--; | |
202 | day = t3; | |
203 | ||
204 | week = 0; | |
205 | ||
206 | /* the rest is easy */ | |
207 | t = time.tv_sec % SECDAY; | |
208 | hour = t / 3600; | |
209 | t %= 3600; | |
210 | min = t / 60; | |
211 | sec = t % 60; | |
212 | ||
213 | *rtc_port = SET_CLOCK; | |
214 | *rtc_data++ = int_to_bcd(sec); | |
215 | *rtc_data++ = int_to_bcd(min); | |
216 | *rtc_data++ = int_to_bcd(hour); | |
217 | *rtc_data++ = int_to_bcd(week); | |
218 | *rtc_data++ = int_to_bcd(day); | |
219 | *rtc_data++ = int_to_bcd(mon); | |
220 | *rtc_data = int_to_bcd(year); | |
221 | *rtc_port = 0; | |
222 | } |