xref: /original-bsd/sys/luna68k/luna68k/clock.c (revision 29d8ef23)
1 /*
2  * Copyright (c) 1988 University of Utah.
3  * Copyright (c) 1992 OMRON Corporation.
4  * Copyright (c) 1982, 1990, 1992 The Regents of the University of California.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * the Systems Programming Group of the University of Utah Computer
9  * Science Department.
10  *
11  * %sccs.include.redist.c%
12  *
13  * from: Utah $Hdr: clock.c 1.18 91/01/21$
14  * OMRON: $Id: clock.c,v 1.1 92/05/27 14:24:06 moti Exp $
15  *
16  * from: hp300/hp300/clock.c    7.14 (Berkeley) 7/8/92
17  *
18  *	@(#)clock.c	7.3 (Berkeley) 09/01/92
19  */
20 
21 #include "param.h"
22 #include "kernel.h"
23 #include "clockreg.h"
24 
25 extern int clock_on;
26 
27 static int month_days[12] = {
28     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
29 };
30 struct bbc_tm *gmt_to_bbc();
31 
32 volatile struct bbc *bbc = (struct bbc *)BBC_ADDR;
33 
34 int battery_clock;
35 int battery_chkfg;
36 
37 /*
38  * Machine-dependent clock routines.
39  *
40  * Startrtclock just checks battry backuped clock
41  * (when it does not work, starts it).
42  *
43  * Enablertclock sets flag for clock interrupt.
44  *
45  * Inittodr initializes the time of day hardware which provides
46  * date functions.
47  *
48  * Resettodr restores the time of day hardware after a time change.
49  *
50  */
51 
52 /*
53  * Start the real-time clock.
54  */
55 cpu_initclocks()
56 {
57 	static char *rtcstrings = "RTC";     /* For compat */
58 
59 	/* set flag for clockintr. */
60 	clock_on = 1;
61 
62 	batterychk();
63 	if (!battery_clock)
64 	  return;
65 
66 	if (!strncmp(bbc->nvram.nv_calclock, rtcstrings, sizeof(rtcstrings))) /* Okey */
67 	  return;
68 
69 	printf("Initialize Battery Backup Clock.\n");
70 	bbc->cal_ctl |= BBC_WRT;
71 	bbc->cal_sec &= ~BBC_STOP;
72 	bbc->cal_hour |= BBC_KICK;
73 	bbc->cal_dow &= ~BBC_FRQ;
74 	bbc->cal_ctl &= ~BBC_WRT;
75 	DELAY(BBC_DELAY);
76 	bbc->cal_ctl |= BBC_WRT;
77 	bbc->cal_hour &= ~BBC_KICK;
78 	bbc->cal_ctl &= ~BBC_WRT;
79 	strcpy(bbc->nvram,rtcstrings);
80 }
81 
82 void
83 setstatclockrate(newhz)
84         int newhz;
85 {
86 }
87 
88 microtime(tvp)
89         register struct timeval *tvp;
90 {
91         int s = splhigh();
92 
93         *tvp = time;
94         tvp->tv_usec += tick;
95         while (tvp->tv_usec > 1000000) {
96                 tvp->tv_sec++;
97                 tvp->tv_usec -= 1000000;
98         }
99         splx(s);
100 }
101 
102 /*
103  * Initialize the time of day register, based on the time base which is, e.g.
104  * from a filesystem.
105  */
106 inittodr(base)
107 	time_t base;
108 {
109 	u_long timbuf = base;	/* assume no battery clock exists */
110 
111 	/*
112 	 * bbc_to_gmt converts and stores the gmt in timbuf.
113 	 * If an error is detected in bbc_to_gmt, or if the filesystem
114 	 * time is more recent than the gmt time in the clock,
115 	 * then use the filesystem time and warn the user.
116  	 */
117 	if (!bbc_to_gmt(&timbuf) || timbuf < base) {
118 		printf("WARNING: bad date in battery clock\n");
119 		timbuf = base;
120 	}
121 	if (base < 5*SECYR) {
122 		printf("WARNING: preposterous time in file system");
123 		timbuf = 6*SECYR + 186*SECDAY + SECDAY/2;
124 		printf(" -- CHECK AND RESET THE DATE!\n");
125 	}
126 
127 	/* Battery clock does not store usec's, so forget about it. */
128 	time.tv_sec = timbuf;
129 }
130 
131 resettodr()
132 {
133 	register int i,s;
134 	register struct bbc_tm *tmptr;
135 
136 	tmptr = gmt_to_bbc(time.tv_sec);
137 
138 	s = splimp();
139 
140 	/* set bb-clock */
141 	bbc->cal_ctl |= BBC_WRT;
142 	bbc->cal_sec = binary_to_bcd(tmptr->tm_sec);
143 	bbc->cal_min = binary_to_bcd(tmptr->tm_min);
144 	bbc->cal_hour = binary_to_bcd(tmptr->tm_hour);
145 	bbc->cal_day = binary_to_bcd(tmptr->tm_mday);
146 	bbc->cal_mon = binary_to_bcd(tmptr->tm_mon);
147 	bbc->cal_year = binary_to_bcd(tmptr->tm_year);
148 	bbc->cal_ctl &= ~BBC_WRT;
149 
150 	splx(s);
151 }
152 
153 struct bbc_tm *
154 gmt_to_bbc(tim)
155 	long tim;
156 {
157 	register int i;
158 	register long hms, day;
159 	static struct bbc_tm rt;
160 
161 	day = tim / SECDAY;
162 	hms = tim % SECDAY;
163 
164 	/* Hours, minutes, seconds are easy */
165 	rt.tm_hour = hms / 3600;
166 	rt.tm_min  = (hms % 3600) / 60;
167 	rt.tm_sec  = (hms % 3600) % 60;
168 
169 	/* Number of years in days */
170 	for (i = STARTOFTIME - 1900; day >= days_in_year(i); i++)
171 	  	day -= days_in_year(i);
172 	rt.tm_year = i;
173 
174 	/* Number of months in days left */
175 	if (leapyear(rt.tm_year))
176 		days_in_month(FEBRUARY) = 29;
177 	for (i = 1; day >= days_in_month(i); i++)
178 		day -= days_in_month(i);
179 	days_in_month(FEBRUARY) = 28;
180 	rt.tm_mon = i;
181 
182 	/* Days are what is left over (+1) from all that. */
183 	rt.tm_mday = day + 1;
184 
185 	return(&rt);
186 }
187 
188 bbc_to_gmt(timbuf)
189 	u_long *timbuf;
190 {
191 	register int i,s;
192 	register u_long tmp;
193 	int year, month, day, hour, min, sec;
194 
195         if (!battery_clock)
196 	   return(0);
197 
198 	s = splimp();
199 
200 	/* read bb-clock */
201 	bbc->cal_ctl |= BBC_RD;
202 	sec = bcd_to_binary(bbc->cal_sec);
203 	min = bcd_to_binary(bbc->cal_min);
204 	hour = bcd_to_binary(bbc->cal_hour);
205 	day = bcd_to_binary(bbc->cal_day);
206 	month = bcd_to_binary(bbc->cal_mon);
207 	year = bcd_to_binary(bbc->cal_year) + 1900;
208 	bbc->cal_ctl &= ~BBC_RD;
209 
210 	splx(s);
211 
212 	range_test(hour, 0, 23);
213 	range_test(day, 1, 31);
214 	range_test(month, 1, 12);
215 	range_test(year, STARTOFTIME, 2000);
216 
217 	tmp = 0;
218 
219 	for (i = STARTOFTIME; i < year; i++)
220 	    tmp += days_in_year(i);
221 	if (leapyear(year) && month > FEBRUARY)
222 	    tmp++;
223 
224 	for (i = 1; i < month; i++)
225 	    tmp += days_in_month(i);
226 
227 	tmp += (day - 1);
228 	tmp = ((tmp * 24 + hour) * 60 + min) * 60 + sec;
229 
230 	*timbuf = tmp;
231 	return(1);
232 }
233 
234 batterychk()
235 {
236 	static char btchkdata[] = "chk";
237 
238 	/* if already checked, return */
239 	if (battery_chkfg)
240 		return;
241 
242 	battery_chkfg = 1;
243 	if (badaddr((caddr_t)bbc, 2))
244 		return;
245 
246 	strcpy(bbc->nvram.nv_testwrite, btchkdata);
247 	if (strncmp(bbc->nvram.nv_testwrite, btchkdata, sizeof(btchkdata))) {
248 		printf("WARNING: calendar clock battery down\n");
249 		return;
250 	}
251 	battery_clock = 1;
252 	return;
253 }
254