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