|
|
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.