1 /* 2 * Copyright (c) 1988 University of Utah. 3 * Copyright (c) 1992, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * the Systems Programming Group of the University of Utah Computer 8 * Science Department, Ralph Campbell, and Kazumasa Utashiro of 9 * Software Research Associates, Inc. 10 * 11 * %sccs.include.redist.c% 12 * 13 * from: Utah $Hdr: clock.c 1.18 91/01/21$ 14 * 15 * @(#)clock.c 8.1 (Berkeley) 06/11/93 16 */ 17 18 #include <machine/adrsmap.h> 19 20 #include <sys/param.h> 21 #include <sys/kernel.h> 22 23 #include <news3400/news3400/clockreg.h> 24 25 /* 26 * Machine-dependent clock routines. 27 * 28 * Startrtclock restarts the real-time clock, which provides 29 * hardclock interrupts to kern_clock.c. 30 * 31 * Inittodr initializes the time of day hardware which provides 32 * date functions. Its primary function is to use some file 33 * system information in case the hardare clock lost state. 34 * 35 * Resettodr restores the time of day hardware after a time change. 36 */ 37 38 /* 39 * We assume newhz is either stathz or profhz, and that neither will 40 * change after being set up above. Could recalculate intervals here 41 * but that would be a drag. 42 */ 43 void 44 setstatclockrate(newhz) 45 int newhz; 46 { 47 48 /* KU:XXX do something! */ 49 } 50 51 /* 52 * Set up the real-time and statistics clocks. Leave stathz 0 only if 53 * no alternative timer is available. 54 */ 55 cpu_initclocks() 56 { 57 58 /* 59 * Start the real-time clock. 60 */ 61 *(char *)ITIMER = IOCLOCK / 6144 / 100 - 1; 62 63 /* 64 * Enable the real-time clock. 65 */ 66 *(char *)INTEN0 |= (char)INTEN0_TIMINT; 67 } 68 69 /* 70 * This code is defunct after 2099. 71 * Will Unix still be here then?? 72 */ 73 static short dayyr[12] = { 74 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 75 }; 76 77 #define bcd_to_int(BCD) (i = BCD, (((i) >> 4) & 0xf) * 10 + ((i) & 0xf)) 78 #define int_to_bcd(INT) (i = INT, ((((i) / 10) % 10) << 4) + (i) % 10) 79 80 /* 81 * Initialze the time of day register, based on the time base which is, e.g. 82 * from a filesystem. Base provides the time to within six months, 83 * and the time of year clock (if any) provides the rest. 84 */ 85 inittodr(base) 86 time_t base; 87 { 88 register volatile u_char *rtc_port = (u_char *)RTC_PORT; 89 register volatile u_char *rtc_data = (u_char *)DATA_PORT; 90 register int days, yr; 91 int sec, min, hour, week, day, mon, year; 92 long deltat, badbase = 0; 93 register u_int i; 94 95 if (base < 5*SECYR) { 96 printf("WARNING: preposterous time in file system\n"); 97 /* read the system clock anyway */ 98 base = 6*SECYR + 186*SECDAY + SECDAY/2; 99 badbase = 1; 100 } 101 102 *rtc_port = READ_CLOCK; 103 sec = bcd_to_int(*rtc_data++); 104 min = bcd_to_int(*rtc_data++); 105 hour = bcd_to_int(*rtc_data++); 106 week = bcd_to_int(*rtc_data++); 107 day = bcd_to_int(*rtc_data++); 108 mon = bcd_to_int(*rtc_data++); 109 year = bcd_to_int(*rtc_data++); 110 *rtc_port = 0; 111 112 /* simple sanity checks */ 113 if (year < 70 || mon < 1 || mon > 12 || day < 1 || day > 31 || 114 hour > 23 || min > 59 || sec > 59) { 115 printf("WARNING: preposterous clock chip time\n"); 116 /* 117 * Believe the time in the file system for lack of 118 * anything better, resetting the TODR. 119 */ 120 time.tv_sec = base; 121 if (!badbase) 122 resettodr(); 123 return (0); 124 } 125 days = 0; 126 for (yr = 70; yr < year; yr++) 127 days += LEAPYEAR(yr) ? 366 : 365; 128 days += dayyr[mon - 1] + day - 1; 129 if (LEAPYEAR(yr) && mon > 2) 130 days++; 131 /* now have days since Jan 1, 1970; the rest is easy... */ 132 time.tv_sec = days * SECDAY + hour * 3600 + min * 60 + sec; 133 134 if (!badbase) { 135 /* 136 * See if we gained/lost two or more days; 137 * if so, assume something is amiss. 138 */ 139 deltat = time.tv_sec - base; 140 if (deltat < 0) 141 deltat = -deltat; 142 if (deltat < 2 * SECDAY) 143 return; 144 printf("WARNING: clock %s %d days", 145 time.tv_sec < base ? "lost" : "gained", deltat / SECDAY); 146 } 147 printf(" -- CHECK AND RESET THE DATE!\n"); 148 } 149 150 /* 151 * Reset the TODR based on the time value; used when the TODR 152 * has a preposterous value and also when the time is reset 153 * by the stime system call. Also called when the TODR goes past 154 * TODRZERO + 100*(SECYEAR+2*SECDAY) (e.g. on Jan 2 just after midnight) 155 * to wrap the TODR around. 156 */ 157 resettodr() 158 { 159 register volatile u_char *rtc_port = (u_char *)RTC_PORT; 160 register volatile u_char *rtc_data = (u_char *)DATA_PORT; 161 int sec, min, hour, week, day, mon, year; 162 register int t, t2, t3; 163 register int i; 164 165 /* compute the year */ 166 t2 = time.tv_sec / SECDAY; 167 t = 69; 168 while (t2 >= 0) { /* whittle off years */ 169 t3 = t2; 170 t++; 171 t2 -= LEAPYEAR(t) ? 366 : 365; 172 } 173 174 year = t; 175 176 /* t3 = month + day; separate */ 177 t = LEAPYEAR(t); 178 for (t2 = 1; t2 < 12; t2++) 179 if (t3 < dayyr[t2] + (t && t2 > 1)) 180 break; 181 182 /* t2 is month */ 183 mon = t2; 184 t3 = t3 - dayyr[t2 - 1] + 1; 185 if (t && t2 > 2) 186 t3--; 187 day = t3; 188 189 week = 0; 190 191 /* the rest is easy */ 192 t = time.tv_sec % SECDAY; 193 hour = t / 3600; 194 t %= 3600; 195 min = t / 60; 196 sec = t % 60; 197 198 *rtc_port = SET_CLOCK; 199 *rtc_data++ = int_to_bcd(sec); 200 *rtc_data++ = int_to_bcd(min); 201 *rtc_data++ = int_to_bcd(hour); 202 *rtc_data++ = int_to_bcd(week); 203 *rtc_data++ = int_to_bcd(day); 204 *rtc_data++ = int_to_bcd(mon); 205 *rtc_data = int_to_bcd(year); 206 *rtc_port = 0; 207 } 208