xref: /original-bsd/sys/pmax/pmax/clock.c (revision 135ce860)
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 and Ralph Campbell.
9  *
10  * %sccs.include.redist.c%
11  *
12  * from: Utah $Hdr: clock.c 1.18 91/01/21$
13  *
14  *	@(#)clock.c	7.3 (Berkeley) 04/19/92
15  */
16 
17 #include "param.h"
18 #include "kernel.h"
19 
20 #include "../include/machConst.h"
21 #include "clockreg.h"
22 
23 /*
24  * Machine-dependent clock routines.
25  *
26  * Startrtclock restarts the real-time clock, which provides
27  * hardclock interrupts to kern_clock.c.
28  *
29  * Inittodr initializes the time of day hardware which provides
30  * date functions.  Its primary function is to use some file
31  * system information in case the hardare clock lost state.
32  *
33  * Resettodr restores the time of day hardware after a time change.
34  */
35 
36 /*
37  * Start the real-time clock.
38  */
39 startrtclock()
40 {
41 	register volatile struct chiptime *c;
42 	extern int tickadj;
43 
44 	tick = 15625;		/* number of micro-seconds between interrupts */
45 	hz = 1000000 / 15625;	/* 64 Hz */
46 	tickadj = 240000 / (60000000 / 15625);
47 	c = (volatile struct chiptime *)MACH_CLOCK_ADDR;
48 	c->rega = REGA_TIME_BASE | SELECTED_RATE;
49 	c->regb = REGB_PER_INT_ENA | REGB_DATA_MODE | REGB_HOURS_FORMAT;
50 }
51 
52 /*
53  * This code is defunct after 2099.
54  * Will Unix still be here then??
55  */
56 static short dayyr[12] = {
57 	0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
58 };
59 
60 /*
61  * Initialze the time of day register, based on the time base which is, e.g.
62  * from a filesystem.  Base provides the time to within six months,
63  * and the time of year clock (if any) provides the rest.
64  */
65 void
66 inittodr(base)
67 	time_t base;
68 {
69 	register volatile struct chiptime *c;
70 	register int days, yr;
71 	int sec, min, hour, day, mon, year;
72 	long deltat;
73 	int badbase, s;
74 
75 	if (base < 5*SECYR) {
76 		printf("WARNING: preposterous time in file system");
77 		/* read the system clock anyway */
78 		base = 6*SECYR + 186*SECDAY + SECDAY/2;
79 		badbase = 1;
80 	} else
81 		badbase = 0;
82 
83 	c = (volatile struct chiptime *)MACH_CLOCK_ADDR;
84 	/* don't read clock registers while they are being updated */
85 	s = splclock();
86 	while ((c->rega & REGA_UIP) == 1)
87 		;
88 	sec = c->sec;
89 	min = c->min;
90 	hour = c->hour;
91 	day = c->day;
92 	mon = c->mon;
93 	year = c->year + 20; /* must be multiple of 4 because chip knows leap */
94 	splx(s);
95 
96 	/* simple sanity checks */
97 	if (year < 70 || mon < 1 || mon > 12 || day < 1 || day > 31 ||
98 	    hour > 23 || min > 59 || sec > 59) {
99 		/*
100 		 * Believe the time in the file system for lack of
101 		 * anything better, resetting the TODR.
102 		 */
103 		time.tv_sec = base;
104 		if (!badbase) {
105 			printf("WARNING: preposterous clock chip time\n");
106 			resettodr();
107 		}
108 		goto bad;
109 	}
110 	days = 0;
111 	for (yr = 70; yr < year; yr++)
112 		days += LEAPYEAR(yr) ? 366 : 365;
113 	days += dayyr[mon - 1] + day - 1;
114 	if (LEAPYEAR(yr) && mon > 2)
115 		days++;
116 	/* now have days since Jan 1, 1970; the rest is easy... */
117 	time.tv_sec = days * SECDAY + hour * 3600 + min * 60 + sec;
118 
119 	if (!badbase) {
120 		/*
121 		 * See if we gained/lost two or more days;
122 		 * if so, assume something is amiss.
123 		 */
124 		deltat = time.tv_sec - base;
125 		if (deltat < 0)
126 			deltat = -deltat;
127 		if (deltat < 2 * SECDAY)
128 			return;
129 		printf("WARNING: clock %s %d days",
130 		    time.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
131 	}
132 bad:
133 	printf(" -- CHECK AND RESET THE DATE!\n");
134 }
135 
136 /*
137  * Reset the TODR based on the time value; used when the TODR
138  * has a preposterous value and also when the time is reset
139  * by the stime system call.  Also called when the TODR goes past
140  * TODRZERO + 100*(SECYEAR+2*SECDAY) (e.g. on Jan 2 just after midnight)
141  * to wrap the TODR around.
142  */
143 resettodr()
144 {
145 	register volatile struct chiptime *c;
146 	register int t, t2;
147 	int sec, min, hour, day, mon, year;
148 	int s;
149 
150 	/* compute the year */
151 	t2 = time.tv_sec / SECDAY;
152 	year = 69;
153 	while (t2 >= 0) {	/* whittle off years */
154 		t = t2;
155 		year++;
156 		t2 -= LEAPYEAR(year) ? 366 : 365;
157 	}
158 
159 	/* t = month + day; separate */
160 	t2 = LEAPYEAR(year);
161 	for (mon = 1; mon < 12; mon++)
162 		if (t < dayyr[mon] + (t2 && mon > 1))
163 			break;
164 
165 	day = t - dayyr[mon - 1] + 1;
166 	if (t2 && mon > 2)
167 		day--;
168 
169 	/* the rest is easy */
170 	t = time.tv_sec % SECDAY;
171 	hour = t / 3600;
172 	t %= 3600;
173 	min = t / 60;
174 	sec = t % 60;
175 
176 	c = (volatile struct chiptime *)MACH_CLOCK_ADDR;
177 	s = splclock();
178 	t = c->regb;
179 	c->regb = t | REGB_SET_TIME;
180 	MachEmptyWriteBuffer();
181 	c->sec = sec;
182 	c->min = min;
183 	c->hour = hour;
184 	c->day = day;
185 	c->mon = mon;
186 	c->year = year - 20; /* must be multiple of 4 because chip knows leap */
187 	c->regb = t;
188 	MachEmptyWriteBuffer();
189 	splx(s);
190 }
191