|
|
researchv9-SUN3(old)
/*
* Copyright (c) 1985 by Sun Microsystems, Inc.
*/
#include "../h/param.h"
#include "../h/systm.h"
#include "../machine/clock.h"
#include "../machine/interreg.h"
/*
* Machine-dependent clock routines.
*
* Clockstart restarts the real-time clock, which provides
* hardclock interrupts to clock.c.
*
* Clkinit initializes the time of day hardware which provides
* date functions. Its primary function is to use some file
* system information in case the hardware clock lost state.
*
* Clkset restores the time of day hardware after a time change.
*/
/*
* Start the real-time clock.
*/
clkstart()
{
/*
* We will set things up to interrupt every 1/100 of a second.
* locore.s currently only calls hardclock every other clock
* interrupt, thus assuming 50 hz operation.
*/
if (hz != 50)
panic("clkstart");
CLKADDR->clk_intrreg = CLK_INT_HSEC; /* set 1/100 sec clock intr */
set_clk_mode(IR_ENA_CLK5, 0); /* turn on level 5 clock intr */
}
/*
* Set and/or clear the desired clock bits in the interrupt
* register. We have to be extremely careful that we do it
* in such a manner that we don't get ourselves lost.
*/
set_clk_mode(on, off)
u_char on, off;
{
register u_char interreg, dummy;
/*
* make sure that we are only playing w/
* clock interrupt register bits
*/
on &= (IR_ENA_CLK7 | IR_ENA_CLK5);
off &= (IR_ENA_CLK7 | IR_ENA_CLK5);
/*
* Get a copy of current interrupt register,
* turning off any undesired bits (aka `off')
*/
interreg = *INTERREG & ~(off | IR_ENA_INT);
*INTERREG &= ~IR_ENA_INT;
/*
* Next we turns off the CLK5 and CLK7 bits to clear
* the flip-flops, then we disable clock interrupts.
* Now we can read the clock's interrupt register
* to clear any pending signals there.
*/
*INTERREG &= ~(IR_ENA_CLK7 | IR_ENA_CLK5);
CLKADDR->clk_cmd = (CLK_CMD_NORMAL & ~CLK_CMD_INTRENA);
dummy = CLKADDR->clk_intrreg; /* clear clock */
#ifdef lint
dummy = dummy;
#endif
/*
* Now we set all the desired bits
* in the interrupt register, then
* we turn the clock back on and
* finally we can enable all interrupts.
*/
*INTERREG |= (interreg | on); /* enable flip-flops */
CLKADDR->clk_cmd = CLK_CMD_NORMAL; /* enable clock intr */
*INTERREG |= IR_ENA_INT; /* enable interrupts */
}
#define ABS(x) ((x) < 0? -(x) : (x))
/*
* Initialize the system time, based on the time base which is, e.g.
* from a filesystem.
*/
clkinit(base)
time_t base;
{
register unsigned todr;
register long deltat;
int ticks;
int s;
if (base < (85 - YRREF) * SECYR) { /* ~1985 */
printf("WARNING: preposterous time in file system");
goto check;
}
s = splclock();
time = todget(&ticks);
(void) splx(s);
if (time < SECYR) {
time = base;
printf("WARNING: TOD clock not initialized");
clkset();
goto check;
}
deltat = time - base;
if (deltat < 0)
deltat = -deltat;
if (deltat < 2*SECDAY)
return;
printf("WARNING: clock %s %d days",
time < base ? "lost" : "gained", deltat / SECDAY);
check:
printf(" -- CHECK AND RESET THE DATE!\n");
}
/*
* Dummy routine for version 9 compatability
*/
clkwrap()
{
return(0);
}
clktrim()
{
int ticks, sec;
int s = splclock();
/*
* Sync the software clock with the hardware clock
*/
sec = todget(&ticks);
lbolt += hz * (sec - time) + (ticks - lbolt);
(void) splx(s);
}
/*
* Reset the TODR based on the time value; used when the TODR
* has a preposterous value and also when the time is reset
* by the settimeofday system call. We call tod_set at splclock()
* to avoid synctodr() from running and getting confused.
*/
clkset()
{
int s;
s = splclock();
todset();
(void) splx(s);
}
/*
* For Sun-3, we use the Intersil ICM7170 for both the
* real time clock and the time-of-day device.
*/
static u_int monthsec[12] = {
31 * SECDAY, /* Jan */
28 * SECDAY, /* Feb */
31 * SECDAY, /* Mar */
30 * SECDAY, /* Apr */
31 * SECDAY, /* May */
30 * SECDAY, /* Jun */
31 * SECDAY, /* Jul */
31 * SECDAY, /* Aug */
30 * SECDAY, /* Sep */
31 * SECDAY, /* Oct */
30 * SECDAY, /* Nov */
31 * SECDAY /* Dec */
};
#define MONTHSEC(mon, yr) \
(((((yr) % 4) == 0) && ((mon) == 2))? 29*SECDAY : monthsec[(mon) - 1])
/*
* Set the TOD based on the argument value; used when the TOD
* has a preposterous value and also when the time is reset
* by the settimeofday system call.
*/
todset()
{
register int t = time;
u_short hsec, sec, min, hour, day, mon, weekday, year;
/*
* Figure out the (adjusted) year
*/
for (year = (YRREF - YRBASE); t > SECYEAR(year); year++)
t -= SECYEAR(year);
/*
* Figure out what month this is by subtracting off
* time per month, adjust for leap year if appropriate.
*/
for (mon = 1; t >= 0; mon++)
t -= MONTHSEC(mon, year);
t += MONTHSEC(--mon, year); /* back off one month */
sec = t % 60; /* seconds */
t /= 60;
min = t % 60; /* minutes */
t /= 60;
hour = t % 24; /* hours (24 hour format) */
day = t / 24; /* day of the month */
day++; /* adjust to start at 1 */
weekday = day % 7; /* not right, but it doesn't matter */
hsec = 0;
CLKADDR->clk_cmd = (CLK_CMD_NORMAL & ~CLK_CMD_RUN);
CLKADDR->clk_weekday = weekday;
CLKADDR->clk_year = year;
CLKADDR->clk_mon = mon;
CLKADDR->clk_day = day;
CLKADDR->clk_hour = hour;
CLKADDR->clk_min = min;
CLKADDR->clk_sec = sec;
CLKADDR->clk_hsec = hsec;
CLKADDR->clk_cmd = CLK_CMD_NORMAL;
}
/*
* Read the current time from the clock chip and convert to UNIX form.
* Assumes that the year in the counter chip is valid.
*/
todget(ticks)
int *ticks;
{
u_char now[CLK_WEEKDAY];
register int i;
register u_char *cp = (u_char *)CLKADDR;
register u_int t = 0;
u_short year;
for (i = CLK_HSEC; i < CLK_WEEKDAY; i++) /* read counters */
now[i] = *cp++;
/*
* Add the number of seconds for each year onto our time t.
* We start at YRBASE, and count up to the year value given
* by the chip. If the year is greater/equal to the difference
* between YRREF and YRBASE, then that time is added into
* the Unix time value we are calculating.
*/
for (year = 0; year < now[CLK_YEAR]; year++)
if (year >= (YRREF - YRBASE))
t += SECYEAR(year);
/*
* Now add in the seconds for each month that has gone
* by this year, adjusting for leap year if appropriate.
*/
for (i = 1; i < now[CLK_MON]; i++)
t += MONTHSEC(i, year);
t += (now[CLK_DAY] - 1) * SECDAY;
t += now[CLK_HOUR] * (60*60);
t += now[CLK_MIN] * 60;
t += now[CLK_SEC];
*ticks = now[CLK_HSEC] * hz / 100;
return (t);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.