|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1985 by Sun Microsystems, Inc. ! 3: */ ! 4: ! 5: #include "../h/param.h" ! 6: #include "../h/systm.h" ! 7: #include "../machine/clock.h" ! 8: #include "../machine/interreg.h" ! 9: ! 10: /* ! 11: * Machine-dependent clock routines. ! 12: * ! 13: * Clockstart restarts the real-time clock, which provides ! 14: * hardclock interrupts to clock.c. ! 15: * ! 16: * Clkinit initializes the time of day hardware which provides ! 17: * date functions. Its primary function is to use some file ! 18: * system information in case the hardware clock lost state. ! 19: * ! 20: * Clkset restores the time of day hardware after a time change. ! 21: */ ! 22: ! 23: /* ! 24: * Start the real-time clock. ! 25: */ ! 26: clkstart() ! 27: { ! 28: ! 29: /* ! 30: * We will set things up to interrupt every 1/100 of a second. ! 31: * locore.s currently only calls hardclock every other clock ! 32: * interrupt, thus assuming 50 hz operation. ! 33: */ ! 34: if (hz != 50) ! 35: panic("clkstart"); ! 36: ! 37: CLKADDR->clk_intrreg = CLK_INT_HSEC; /* set 1/100 sec clock intr */ ! 38: set_clk_mode(IR_ENA_CLK5, 0); /* turn on level 5 clock intr */ ! 39: } ! 40: ! 41: /* ! 42: * Set and/or clear the desired clock bits in the interrupt ! 43: * register. We have to be extremely careful that we do it ! 44: * in such a manner that we don't get ourselves lost. ! 45: */ ! 46: set_clk_mode(on, off) ! 47: u_char on, off; ! 48: { ! 49: register u_char interreg, dummy; ! 50: ! 51: /* ! 52: * make sure that we are only playing w/ ! 53: * clock interrupt register bits ! 54: */ ! 55: on &= (IR_ENA_CLK7 | IR_ENA_CLK5); ! 56: off &= (IR_ENA_CLK7 | IR_ENA_CLK5); ! 57: ! 58: /* ! 59: * Get a copy of current interrupt register, ! 60: * turning off any undesired bits (aka `off') ! 61: */ ! 62: interreg = *INTERREG & ~(off | IR_ENA_INT); ! 63: *INTERREG &= ~IR_ENA_INT; ! 64: ! 65: /* ! 66: * Next we turns off the CLK5 and CLK7 bits to clear ! 67: * the flip-flops, then we disable clock interrupts. ! 68: * Now we can read the clock's interrupt register ! 69: * to clear any pending signals there. ! 70: */ ! 71: *INTERREG &= ~(IR_ENA_CLK7 | IR_ENA_CLK5); ! 72: CLKADDR->clk_cmd = (CLK_CMD_NORMAL & ~CLK_CMD_INTRENA); ! 73: dummy = CLKADDR->clk_intrreg; /* clear clock */ ! 74: #ifdef lint ! 75: dummy = dummy; ! 76: #endif ! 77: ! 78: /* ! 79: * Now we set all the desired bits ! 80: * in the interrupt register, then ! 81: * we turn the clock back on and ! 82: * finally we can enable all interrupts. ! 83: */ ! 84: *INTERREG |= (interreg | on); /* enable flip-flops */ ! 85: CLKADDR->clk_cmd = CLK_CMD_NORMAL; /* enable clock intr */ ! 86: *INTERREG |= IR_ENA_INT; /* enable interrupts */ ! 87: } ! 88: ! 89: #define ABS(x) ((x) < 0? -(x) : (x)) ! 90: ! 91: /* ! 92: * Initialize the system time, based on the time base which is, e.g. ! 93: * from a filesystem. ! 94: */ ! 95: clkinit(base) ! 96: time_t base; ! 97: { ! 98: register unsigned todr; ! 99: register long deltat; ! 100: int ticks; ! 101: int s; ! 102: ! 103: if (base < (85 - YRREF) * SECYR) { /* ~1985 */ ! 104: printf("WARNING: preposterous time in file system"); ! 105: goto check; ! 106: } ! 107: s = splclock(); ! 108: time = todget(&ticks); ! 109: (void) splx(s); ! 110: if (time < SECYR) { ! 111: time = base; ! 112: printf("WARNING: TOD clock not initialized"); ! 113: clkset(); ! 114: goto check; ! 115: } ! 116: deltat = time - base; ! 117: if (deltat < 0) ! 118: deltat = -deltat; ! 119: if (deltat < 2*SECDAY) ! 120: return; ! 121: printf("WARNING: clock %s %d days", ! 122: time < base ? "lost" : "gained", deltat / SECDAY); ! 123: check: ! 124: printf(" -- CHECK AND RESET THE DATE!\n"); ! 125: } ! 126: ! 127: /* ! 128: * Dummy routine for version 9 compatability ! 129: */ ! 130: clkwrap() ! 131: { ! 132: return(0); ! 133: } ! 134: ! 135: clktrim() ! 136: { ! 137: int ticks, sec; ! 138: int s = splclock(); ! 139: ! 140: /* ! 141: * Sync the software clock with the hardware clock ! 142: */ ! 143: sec = todget(&ticks); ! 144: lbolt += hz * (sec - time) + (ticks - lbolt); ! 145: (void) splx(s); ! 146: } ! 147: ! 148: /* ! 149: * Reset the TODR based on the time value; used when the TODR ! 150: * has a preposterous value and also when the time is reset ! 151: * by the settimeofday system call. We call tod_set at splclock() ! 152: * to avoid synctodr() from running and getting confused. ! 153: */ ! 154: clkset() ! 155: { ! 156: int s; ! 157: ! 158: s = splclock(); ! 159: todset(); ! 160: (void) splx(s); ! 161: } ! 162: ! 163: /* ! 164: * For Sun-3, we use the Intersil ICM7170 for both the ! 165: * real time clock and the time-of-day device. ! 166: */ ! 167: ! 168: static u_int monthsec[12] = { ! 169: 31 * SECDAY, /* Jan */ ! 170: 28 * SECDAY, /* Feb */ ! 171: 31 * SECDAY, /* Mar */ ! 172: 30 * SECDAY, /* Apr */ ! 173: 31 * SECDAY, /* May */ ! 174: 30 * SECDAY, /* Jun */ ! 175: 31 * SECDAY, /* Jul */ ! 176: 31 * SECDAY, /* Aug */ ! 177: 30 * SECDAY, /* Sep */ ! 178: 31 * SECDAY, /* Oct */ ! 179: 30 * SECDAY, /* Nov */ ! 180: 31 * SECDAY /* Dec */ ! 181: }; ! 182: ! 183: #define MONTHSEC(mon, yr) \ ! 184: (((((yr) % 4) == 0) && ((mon) == 2))? 29*SECDAY : monthsec[(mon) - 1]) ! 185: ! 186: /* ! 187: * Set the TOD based on the argument value; used when the TOD ! 188: * has a preposterous value and also when the time is reset ! 189: * by the settimeofday system call. ! 190: */ ! 191: todset() ! 192: { ! 193: register int t = time; ! 194: u_short hsec, sec, min, hour, day, mon, weekday, year; ! 195: ! 196: /* ! 197: * Figure out the (adjusted) year ! 198: */ ! 199: for (year = (YRREF - YRBASE); t > SECYEAR(year); year++) ! 200: t -= SECYEAR(year); ! 201: ! 202: /* ! 203: * Figure out what month this is by subtracting off ! 204: * time per month, adjust for leap year if appropriate. ! 205: */ ! 206: for (mon = 1; t >= 0; mon++) ! 207: t -= MONTHSEC(mon, year); ! 208: ! 209: t += MONTHSEC(--mon, year); /* back off one month */ ! 210: ! 211: sec = t % 60; /* seconds */ ! 212: t /= 60; ! 213: min = t % 60; /* minutes */ ! 214: t /= 60; ! 215: hour = t % 24; /* hours (24 hour format) */ ! 216: day = t / 24; /* day of the month */ ! 217: day++; /* adjust to start at 1 */ ! 218: weekday = day % 7; /* not right, but it doesn't matter */ ! 219: ! 220: hsec = 0; ! 221: ! 222: CLKADDR->clk_cmd = (CLK_CMD_NORMAL & ~CLK_CMD_RUN); ! 223: CLKADDR->clk_weekday = weekday; ! 224: CLKADDR->clk_year = year; ! 225: CLKADDR->clk_mon = mon; ! 226: CLKADDR->clk_day = day; ! 227: CLKADDR->clk_hour = hour; ! 228: CLKADDR->clk_min = min; ! 229: CLKADDR->clk_sec = sec; ! 230: CLKADDR->clk_hsec = hsec; ! 231: CLKADDR->clk_cmd = CLK_CMD_NORMAL; ! 232: } ! 233: ! 234: /* ! 235: * Read the current time from the clock chip and convert to UNIX form. ! 236: * Assumes that the year in the counter chip is valid. ! 237: */ ! 238: todget(ticks) ! 239: int *ticks; ! 240: { ! 241: u_char now[CLK_WEEKDAY]; ! 242: register int i; ! 243: register u_char *cp = (u_char *)CLKADDR; ! 244: register u_int t = 0; ! 245: u_short year; ! 246: ! 247: for (i = CLK_HSEC; i < CLK_WEEKDAY; i++) /* read counters */ ! 248: now[i] = *cp++; ! 249: ! 250: /* ! 251: * Add the number of seconds for each year onto our time t. ! 252: * We start at YRBASE, and count up to the year value given ! 253: * by the chip. If the year is greater/equal to the difference ! 254: * between YRREF and YRBASE, then that time is added into ! 255: * the Unix time value we are calculating. ! 256: */ ! 257: for (year = 0; year < now[CLK_YEAR]; year++) ! 258: if (year >= (YRREF - YRBASE)) ! 259: t += SECYEAR(year); ! 260: ! 261: /* ! 262: * Now add in the seconds for each month that has gone ! 263: * by this year, adjusting for leap year if appropriate. ! 264: */ ! 265: for (i = 1; i < now[CLK_MON]; i++) ! 266: t += MONTHSEC(i, year); ! 267: ! 268: t += (now[CLK_DAY] - 1) * SECDAY; ! 269: t += now[CLK_HOUR] * (60*60); ! 270: t += now[CLK_MIN] * 60; ! 271: t += now[CLK_SEC]; ! 272: ! 273: *ticks = now[CLK_HSEC] * hz / 100; ! 274: return (t); ! 275: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.