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