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