xref: /original-bsd/sys/pmax/pmax/clock.c (revision e59fb703)
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.1 (Berkeley) 01/07/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;	/* about 64 */
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 inittodr(base)
66 	time_t base;
67 {
68 	register volatile struct chiptime *c;
69 	register int days, yr;
70 	int sec, min, hour, day, mon, year;
71 	long deltat, badbase = 0;
72 	int s;
73 
74 	if (base < 5*SECYR) {
75 		printf("WARNING: preposterous time in file system\n");
76 		/* read the system clock anyway */
77 		base = 6*SECYR + 186*SECDAY + SECDAY/2;
78 		badbase = 1;
79 	}
80 
81 	s = splclock();
82 	c = (volatile struct chiptime *)MACH_CLOCK_ADDR;
83 	/* don't read clock registers while they are being updated */
84 	while ((c->rega & REGA_UIP) == 1)
85 		;
86 	sec = c->sec;
87 	min = c->min;
88 	hour = c->hour;
89 	day = c->day;
90 	mon = c->mon;
91 	year = c->year + 19;
92 	splx(s);
93 	/* simple sanity checks */
94 	if (year < 70 || mon < 1 || mon > 12 || day < 1 || day > 31 ||
95 	    hour > 23 || min > 59 || sec > 59) {
96 		printf("WARNING: preposterous clock chip time");
97 		/*
98 		 * Believe the time in the file system for lack of
99 		 * anything better, resetting the TODR.
100 		 */
101 		time.tv_sec = base;
102 		if (!badbase)
103 			resettodr();
104 		return (0);
105 	}
106 	days = 0;
107 	for (yr = 70; yr < year; yr++)
108 		days += LEAPYEAR(yr) ? 366 : 365;
109 	days += dayyr[mon - 1] + day - 1;
110 	if (LEAPYEAR(yr) && mon > 2)
111 		days++;
112 	/* now have days since Jan 1, 1970; the rest is easy... */
113 	time.tv_sec = days * SECDAY + hour * 3600 + min * 60 + sec;
114 
115 	if (!badbase) {
116 		/*
117 		 * See if we gained/lost two or more days;
118 		 * if so, assume something is amiss.
119 		 */
120 		deltat = time.tv_sec - base;
121 		if (deltat < 0)
122 			deltat = -deltat;
123 		if (deltat < 2 * SECDAY)
124 			return;
125 		printf("WARNING: clock %s %d days",
126 		    time.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
127 	}
128 	printf(" -- CHECK AND RESET THE DATE!\n");
129 }
130 
131 /*
132  * Reset the TODR based on the time value; used when the TODR
133  * has a preposterous value and also when the time is reset
134  * by the stime system call.  Also called when the TODR goes past
135  * TODRZERO + 100*(SECYEAR+2*SECDAY) (e.g. on Jan 2 just after midnight)
136  * to wrap the TODR around.
137  */
138 resettodr()
139 {
140 	register volatile struct chiptime *c;
141 	register int t, t2, t3;
142 
143 	/* compute the year */
144 	t2 = time.tv_sec / SECDAY;
145 	t = 69;
146 	while (t2 >= 0) {	/* whittle off years */
147 		t3 = t2;
148 		t++;
149 		t2 -= LEAPYEAR(t) ? 366 : 365;
150 	}
151 	c = (volatile struct chiptime *)MACH_CLOCK_ADDR;
152 	c->regb |= REGB_SET_TIME;
153 	c->year = t - 19;
154 
155 	/* t3 = month + day; separate */
156 	t = LEAPYEAR(t);
157 	for (t2 = 1; t2 < 12; t2++)
158 		if (t3 < dayyr[t2] + (t && t2 > 1))
159 			break;
160 
161 	/* t2 is month */
162 	c->mon = t2;
163 	t3 = t3 - dayyr[t2 - 1] + 1;
164 	if (t && t2 > 2)
165 		t3--;
166 	c->day = t3;
167 
168 	/* the rest is easy */
169 	t = time.tv_sec % SECDAY;
170 	c->hour = t / 3600;
171 	t %= 3600;
172 	c->min = t / 60;
173 	c->sec = t % 60;
174 	c->regb &= ~REGB_SET_TIME;
175 }
176