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