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