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