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