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