Fix routines to read/write the stupid intersil clock.
This commit is contained in:
parent
3e676d4221
commit
2905514717
@ -1,6 +1,13 @@
|
||||
/*
|
||||
* Copyright (c) 1994 Gordon W. Ross
|
||||
* Copyright (c) 1993 Adam Glass
|
||||
* All rights reserved.
|
||||
* Copyright (c) 1988 University of Utah.
|
||||
* Copyright (c) 1982, 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* the Systems Programming Group of the University of Utah Computer
|
||||
* Science Department.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -12,11 +19,13 @@
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Adam Glass.
|
||||
* 4. The name of the Author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Adam Glass ``AS IS'' AND
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
@ -28,15 +37,15 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: clock.c,v 1.17 1994/09/20 16:52:22 gwr Exp $
|
||||
* from: Utah $Hdr: clock.c 1.18 91/01/21$
|
||||
*
|
||||
* from: @(#)clock.c 8.2 (Berkeley) 1/12/94
|
||||
* $Id: clock.c,v 1.18 1994/09/26 17:25:23 gwr Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* machine-dependent clock routines; intersil7170
|
||||
* by Adam Glass
|
||||
*
|
||||
* [this code suffered terribly when we were pursuing the fast clock interrupt
|
||||
* problem. in particular, the level switching code is not legitimate]
|
||||
*
|
||||
* Machine-dependent clock routines for the Intersil 7170:
|
||||
* Original by Adam Glass; partially rewritten by Gordon Ross.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
@ -75,18 +84,6 @@ volatile char *clock_va;
|
||||
#define intersil_clear() intersil_clock->clk_intr_reg
|
||||
|
||||
|
||||
#define SECS_HOUR (60*60)
|
||||
#define SECS_DAY (SECS_HOUR*24)
|
||||
#define SECS_PER_YEAR (SECS_DAY*365)
|
||||
#define SECS_PER_LEAP (SECS_DAY*366)
|
||||
#define SECS_PER_MONTH(month, year) \
|
||||
((month == 2) && INTERSIL_LEAP_YEAR(year) \
|
||||
? 29*SECS_DAY : month_days[month-1]*SECS_DAY)
|
||||
|
||||
#define SECS_YEAR(year) \
|
||||
(INTERSIL_LEAP_YEAR(year) ? SECS_PER_LEAP : SECS_PER_YEAR)
|
||||
|
||||
|
||||
struct clock_softc {
|
||||
struct device clock_dev;
|
||||
caddr_t clock_va;
|
||||
@ -95,10 +92,6 @@ struct clock_softc {
|
||||
|
||||
struct clock_softc *intersil_softc = NULL;
|
||||
|
||||
static int month_days[12] = {
|
||||
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
||||
};
|
||||
|
||||
void clockattach __P((struct device *, struct device *, void *));
|
||||
int clockmatch __P((struct device *, struct cfdata *, void *args));
|
||||
|
||||
@ -106,6 +99,7 @@ struct cfdriver clockcd =
|
||||
{ NULL, "clock", always_match, clockattach, DV_DULL,
|
||||
sizeof(struct clock_softc), 0};
|
||||
|
||||
/* Called very earyl by internal_configure. */
|
||||
void clock_init()
|
||||
{
|
||||
clock_va = obio_find_mapping(OBIO_CLOCK, OBIO_CLOCK_SIZE);
|
||||
@ -179,12 +173,9 @@ set_clk_mode(on, off, enable)
|
||||
* to clear any pending signals there.
|
||||
*/
|
||||
*interrupt_reg &= ~(IREG_CLOCK_ENAB_7 | IREG_CLOCK_ENAB_5);
|
||||
intersil_clock->clk_cmd_reg = intersil_command(INTERSIL_CMD_RUN,
|
||||
INTERSIL_CMD_IDISABLE);
|
||||
intersil_clock->clk_cmd_reg =
|
||||
intersil_command(INTERSIL_CMD_RUN, INTERSIL_CMD_IDISABLE);
|
||||
dummy = intersil_clock->clk_intr_reg; /* clear clock */
|
||||
#ifdef lint
|
||||
dummy = dummy;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Now we set all the desired bits
|
||||
@ -193,16 +184,17 @@ set_clk_mode(on, off, enable)
|
||||
* finally we can enable all interrupts.
|
||||
*/
|
||||
*interrupt_reg |= (interreg | on); /* enable flip-flops */
|
||||
|
||||
if (enable)
|
||||
intersil_clock->clk_cmd_reg =
|
||||
intersil_command(INTERSIL_CMD_RUN,
|
||||
INTERSIL_CMD_IENABLE);
|
||||
intersil_command(INTERSIL_CMD_RUN, INTERSIL_CMD_IENABLE);
|
||||
|
||||
*interrupt_reg |= IREG_ALL_ENAB; /* enable interrupts */
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up the real-time clock. Leave stathz 0 since there is no secondary
|
||||
* clock available.
|
||||
* Set up the real-time clock. Leave stathz 0 since there is no
|
||||
* secondary clock available.
|
||||
*/
|
||||
void
|
||||
cpu_initclocks(void)
|
||||
@ -217,10 +209,10 @@ cpu_initclocks(void)
|
||||
/* make sure irq5/7 stuff is resolved :) */
|
||||
|
||||
dummy = intersil_clear();
|
||||
dummy++;
|
||||
|
||||
intersil_clock->clk_intr_reg = INTERSIL_INTER_CSECONDS;
|
||||
intersil_clock->clk_cmd_reg = intersil_command(INTERSIL_CMD_RUN,
|
||||
INTERSIL_CMD_IENABLE);
|
||||
intersil_clock->clk_cmd_reg =
|
||||
intersil_command(INTERSIL_CMD_RUN, INTERSIL_CMD_IENABLE);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -234,6 +226,10 @@ setstatclockrate(newhz)
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
/*
|
||||
* Startrtclock restarts the real-time clock, which provides
|
||||
* hardclock interrupts to kern_clock.c.
|
||||
*/
|
||||
void startrtclock()
|
||||
{
|
||||
char dummy;
|
||||
@ -242,8 +238,8 @@ void startrtclock()
|
||||
panic("clock: not initialized");
|
||||
|
||||
intersil_clock->clk_intr_reg = INTERSIL_INTER_CSECONDS;
|
||||
intersil_clock->clk_cmd_reg = intersil_command(INTERSIL_CMD_RUN,
|
||||
INTERSIL_CMD_IDISABLE);
|
||||
intersil_clock->clk_cmd_reg =
|
||||
intersil_command(INTERSIL_CMD_RUN, INTERSIL_CMD_IDISABLE);
|
||||
dummy = intersil_clear();
|
||||
}
|
||||
|
||||
@ -253,10 +249,9 @@ void enablertclock()
|
||||
/* make sure irq5/7 stuff is resolved :) */
|
||||
|
||||
dummy = intersil_clear();
|
||||
dummy++;
|
||||
intersil_clock->clk_intr_reg = INTERSIL_INTER_CSECONDS;
|
||||
intersil_clock->clk_cmd_reg = intersil_command(INTERSIL_CMD_RUN,
|
||||
INTERSIL_CMD_IENABLE);
|
||||
intersil_clock->clk_cmd_reg =
|
||||
intersil_command(INTERSIL_CMD_RUN, INTERSIL_CMD_IENABLE);
|
||||
}
|
||||
|
||||
int clock_count = 0;
|
||||
@ -266,6 +261,7 @@ void clock_intr(frame)
|
||||
{
|
||||
static unsigned char led_pattern = 0xFE;
|
||||
|
||||
/* XXX - Move this LED frobbing to the idle loop? */
|
||||
clock_count++;
|
||||
if ((clock_count & 7) == 0) {
|
||||
led_pattern = (led_pattern << 1) | 1;
|
||||
@ -278,170 +274,27 @@ void clock_intr(frame)
|
||||
|
||||
|
||||
/*
|
||||
* Machine-dependent clock routines.
|
||||
* Return the best possible estimate of the time in the timeval
|
||||
* to which tvp points. We do this by returning the current time
|
||||
* plus the amount of time since the last clock interrupt.
|
||||
*
|
||||
* Startrtclock restarts the real-time clock, which provides
|
||||
* hardclock interrupts to kern_clock.c.
|
||||
*
|
||||
* Inittodr initializes the time of day hardware which provides
|
||||
* date functions.
|
||||
*
|
||||
* Resettodr restores the time of day hardware after a time change.
|
||||
*
|
||||
* also microtime support
|
||||
* Check that this time is no less than any previously-reported time,
|
||||
* which could happen around the time of a clock adjustment. Just for
|
||||
* fun, we guarantee that the time will be greater than the value
|
||||
* obtained by a previous call.
|
||||
*/
|
||||
|
||||
|
||||
void intersil_counter_state(map)
|
||||
struct intersil_map *map;
|
||||
{
|
||||
map->csecs = intersil_clock->counters.csecs;
|
||||
map->hours = intersil_clock->counters.hours;
|
||||
map->minutes = intersil_clock->counters.minutes;
|
||||
map->seconds = intersil_clock->counters.seconds;
|
||||
map->month = intersil_clock->counters.month;
|
||||
map->date = intersil_clock->counters.date;
|
||||
map->year = intersil_clock->counters.year;
|
||||
map->day = intersil_clock->counters.day;
|
||||
}
|
||||
|
||||
|
||||
struct timeval intersil_to_timeval()
|
||||
{
|
||||
struct intersil_map now_state;
|
||||
struct timeval now;
|
||||
int i;
|
||||
|
||||
intersil_counter_state(&now_state);
|
||||
|
||||
now.tv_sec = 0;
|
||||
now.tv_usec = 0;
|
||||
|
||||
#define range_check_high(field, high) \
|
||||
now_state.field > high
|
||||
#define range_check(field, low, high) \
|
||||
now_state.field < low || now_state.field > high
|
||||
|
||||
if (range_check_high(csecs, 99) ||
|
||||
range_check_high(hours, 23) ||
|
||||
range_check_high(minutes, 59) ||
|
||||
range_check_high(seconds, 59) ||
|
||||
range_check(month, 1, 12) ||
|
||||
range_check(date, 1, 32) ||
|
||||
range_check_high(year, 99) ||
|
||||
range_check_high(day, 6)) return now;
|
||||
|
||||
if ((INTERSIL_UNIX_BASE - INTERSIL_YEAR_BASE) > now_state.year)
|
||||
return now;
|
||||
|
||||
for (i = INTERSIL_UNIX_BASE-INTERSIL_YEAR_BASE;
|
||||
i < now_state.year; i++)
|
||||
if (INTERSIL_LEAP_YEAR(INTERSIL_YEAR_BASE+now_state.year))
|
||||
now.tv_sec += SECS_PER_LEAP;
|
||||
else now.tv_sec += SECS_PER_YEAR;
|
||||
|
||||
for (i = 1; i < now_state.month; i++)
|
||||
now.tv_sec += SECS_PER_MONTH(i, INTERSIL_YEAR_BASE+now_state.year);
|
||||
now.tv_sec += SECS_DAY*(now_state.date-1);
|
||||
now.tv_sec += SECS_HOUR * now_state.hours;
|
||||
now.tv_sec += 60 * now_state.minutes;
|
||||
now.tv_sec += 60 * now_state.seconds;
|
||||
return now;
|
||||
}
|
||||
/*
|
||||
* Initialize the time of day register, based on the time base which is, e.g.
|
||||
* from a filesystem.
|
||||
*/
|
||||
void inittodr(base)
|
||||
time_t base;
|
||||
{
|
||||
struct timeval clock_time;
|
||||
long diff_time;
|
||||
void resettodr();
|
||||
|
||||
clock_time = intersil_to_timeval();
|
||||
|
||||
if (!base) goto set_time;
|
||||
if (!clock_time.tv_sec && (base <= 0)) goto set_time;
|
||||
|
||||
if (clock_time.tv_sec < base) {
|
||||
printf("WARNING: real-time clock reports a time earlier than last\n");
|
||||
printf(" write to root filesystem. Trusting filesystem...\n");
|
||||
time.tv_sec = base;
|
||||
resettodr();
|
||||
return;
|
||||
}
|
||||
diff_time = clock_time.tv_sec - base;
|
||||
if (diff_time < 0) diff_time = - diff_time;
|
||||
if (diff_time >= (SECS_DAY*2))
|
||||
printf("WARNING: clock %s %d days\n",
|
||||
(clock_time.tv_sec <base ? "lost" : "gained"),
|
||||
diff_time % SECS_DAY);
|
||||
|
||||
set_time:
|
||||
time = clock_time;
|
||||
}
|
||||
|
||||
void timeval_to_intersil(now, map)
|
||||
struct timeval now;
|
||||
struct intersil_map *map;
|
||||
{
|
||||
|
||||
for (map->year = INTERSIL_UNIX_BASE-INTERSIL_YEAR_BASE;
|
||||
now.tv_sec > SECS_YEAR(map->year);
|
||||
map->year++)
|
||||
now.tv_sec -= SECS_YEAR(map->year);
|
||||
|
||||
for (map->month = 1; now.tv_sec >=0; map->month++)
|
||||
now.tv_sec -= SECS_PER_MONTH(map->month, INTERSIL_YEAR_BASE+map->year);
|
||||
|
||||
map->month--;
|
||||
now.tv_sec -= SECS_PER_MONTH(map->month, INTERSIL_YEAR_BASE+map->year);
|
||||
|
||||
map->date = now.tv_sec % SECS_DAY ;
|
||||
now.tv_sec /= SECS_DAY;
|
||||
map->minutes = now.tv_sec %60;
|
||||
now.tv_sec /= 60;
|
||||
map->seconds = now.tv_sec %60;
|
||||
now.tv_sec /= 60;
|
||||
map->day = map->date %7;
|
||||
map->csecs = now.tv_usec / 10000;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Resettodr restores the time of day hardware after a time change.
|
||||
*/
|
||||
void resettodr()
|
||||
{
|
||||
struct intersil_map hdw_format;
|
||||
|
||||
timeval_to_intersil(time, &hdw_format);
|
||||
intersil_clock->clk_cmd_reg = intersil_command(INTERSIL_CMD_STOP,
|
||||
INTERSIL_CMD_IDISABLE);
|
||||
|
||||
intersil_clock->counters.csecs = hdw_format.csecs ;
|
||||
intersil_clock->counters.hours = hdw_format.hours ;
|
||||
intersil_clock->counters.minutes = hdw_format.minutes ;
|
||||
intersil_clock->counters.seconds = hdw_format.seconds ;
|
||||
intersil_clock->counters.month = hdw_format.month ;
|
||||
intersil_clock->counters.date = hdw_format.date ;
|
||||
intersil_clock->counters.year = hdw_format.year ;
|
||||
intersil_clock->counters.day = hdw_format.day ;
|
||||
|
||||
intersil_clock->clk_cmd_reg = intersil_command(INTERSIL_CMD_RUN,
|
||||
INTERSIL_CMD_IENABLE);
|
||||
}
|
||||
|
||||
void microtime(tvp)
|
||||
microtime(tvp)
|
||||
register struct timeval *tvp;
|
||||
{
|
||||
int s = splhigh();
|
||||
static struct timeval lasttime;
|
||||
|
||||
/* as yet...... this makes little sense*/
|
||||
|
||||
*tvp = time;
|
||||
tvp->tv_usec;
|
||||
while (tvp->tv_usec > 1000000) {
|
||||
tvp->tv_sec++;
|
||||
tvp->tv_usec -= 1000000;
|
||||
}
|
||||
if (tvp->tv_sec == lasttime.tv_sec &&
|
||||
tvp->tv_usec <= lasttime.tv_usec &&
|
||||
(tvp->tv_usec = lasttime.tv_usec + 1) > 1000000) {
|
||||
@ -451,3 +304,282 @@ void microtime(tvp)
|
||||
lasttime = *tvp;
|
||||
splx(s);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Machine-dependent clock routines.
|
||||
*
|
||||
* Inittodr initializes the time of day hardware which provides
|
||||
* date functions.
|
||||
*
|
||||
* Resettodr restores the time of day hardware after a time change.
|
||||
*/
|
||||
#define SECDAY 86400L
|
||||
#define SECYR (SECDAY * 365)
|
||||
|
||||
static long clk_get_secs(void);
|
||||
static void clk_set_secs(long);
|
||||
|
||||
/*
|
||||
* Initialize the time of day register, based on the time base
|
||||
* which is, e.g. from a filesystem.
|
||||
*/
|
||||
void inittodr(fs_time)
|
||||
time_t fs_time;
|
||||
{
|
||||
long diff, clk_time;
|
||||
long long_ago = (5 * SECYR);
|
||||
int clk_bad = 0;
|
||||
|
||||
/*
|
||||
* Sanity check time from file system.
|
||||
* If it is zero,assume filesystem time is just unknown
|
||||
* instead of preposterous. Don't bark.
|
||||
*/
|
||||
if (fs_time < long_ago) {
|
||||
/*
|
||||
* If fs_time is zero, assume filesystem time is just
|
||||
* unknown instead of preposterous. Don't bark.
|
||||
*/
|
||||
if (fs_time != 0)
|
||||
printf("WARNING: preposterous time in file system\n");
|
||||
/* 1991/07/01 12:00:00 */
|
||||
fs_time = 21*SECYR + 186*SECDAY + SECDAY/2;
|
||||
}
|
||||
|
||||
clk_time = clk_get_secs();
|
||||
|
||||
/* Sanity check time from clock. */
|
||||
if (clk_time < long_ago) {
|
||||
printf("WARNING: bad date in battery clock");
|
||||
clk_bad = 1;
|
||||
clk_time = fs_time;
|
||||
} else {
|
||||
/* Does the clock time jive with the file system? */
|
||||
diff = clk_time - fs_time;
|
||||
if (diff < 0)
|
||||
diff = -diff;
|
||||
if (diff >= (SECDAY*2)) {
|
||||
printf("WARNING: clock %s %d days",
|
||||
(clk_time < fs_time) ? "lost" : "gained",
|
||||
diff / SECDAY);
|
||||
clk_bad = 1;
|
||||
}
|
||||
}
|
||||
if (clk_bad)
|
||||
printf(" -- CHECK AND RESET THE DATE!\n");
|
||||
time.tv_sec = clk_time;
|
||||
}
|
||||
|
||||
/*
|
||||
* Resettodr restores the time of day hardware after a time change.
|
||||
*/
|
||||
void resettodr()
|
||||
{
|
||||
clk_set_secs(time.tv_sec);
|
||||
}
|
||||
|
||||
/*
|
||||
* Machine dependent base year:
|
||||
* Note: must be < 1970
|
||||
*/
|
||||
#define CLOCK_BASE_YEAR 1968
|
||||
|
||||
|
||||
/*
|
||||
* Routine to copy state into and out of the clock.
|
||||
* The clock registers have to be read or written
|
||||
* in sequential order (or so it appears). -gwr
|
||||
*/
|
||||
static void clk_get_dt(struct date_time *dt)
|
||||
{
|
||||
int s;
|
||||
register volatile char *src, *dst;
|
||||
|
||||
src = (char *) &intersil_clock->counters;
|
||||
|
||||
s = splhigh();
|
||||
intersil_clock->clk_cmd_reg =
|
||||
intersil_command(INTERSIL_CMD_STOP, INTERSIL_CMD_IENABLE);
|
||||
|
||||
dst = (char *) dt;
|
||||
dt++; /* end marker */
|
||||
do {
|
||||
*dst++ = *src++;
|
||||
} while (dst < (char*)dt);
|
||||
|
||||
intersil_clock->clk_cmd_reg =
|
||||
intersil_command(INTERSIL_CMD_RUN, INTERSIL_CMD_IENABLE);
|
||||
splx(s);
|
||||
}
|
||||
|
||||
static void clk_set_dt(struct date_time *dt)
|
||||
{
|
||||
int s;
|
||||
register volatile char *src, *dst;
|
||||
|
||||
dst = (char *) &intersil_clock->counters;
|
||||
|
||||
s = splhigh();
|
||||
intersil_clock->clk_cmd_reg =
|
||||
intersil_command(INTERSIL_CMD_STOP, INTERSIL_CMD_IENABLE);
|
||||
|
||||
src = (char *) dt;
|
||||
dt++; /* end marker */
|
||||
do {
|
||||
*dst++ = *src++;
|
||||
} while (src < (char *)dt);
|
||||
|
||||
intersil_clock->clk_cmd_reg =
|
||||
intersil_command(INTERSIL_CMD_RUN, INTERSIL_CMD_IENABLE);
|
||||
splx(s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Generic routines to convert to or from a POSIX date
|
||||
* (seconds since 1/1/1970) and yr/mo/day/hr/min/sec
|
||||
*
|
||||
* These are organized this way mostly to so the code
|
||||
* can easily be tested in an independent user program.
|
||||
* (These are derived from the hp300 code.)
|
||||
*/
|
||||
|
||||
/* Traditional UNIX base year */
|
||||
#define POSIX_BASE_YEAR 1970
|
||||
#define FEBRUARY 2
|
||||
|
||||
#define leapyear(year) ((year) % 4 == 0)
|
||||
#define days_in_year(a) (leapyear(a) ? 366 : 365)
|
||||
#define days_in_month(a) (month_days[(a) - 1])
|
||||
|
||||
static int month_days[12] = {
|
||||
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
||||
};
|
||||
|
||||
void gmt_to_dt(long *tp, struct date_time *dt)
|
||||
{
|
||||
register int i;
|
||||
register long days, secs;
|
||||
|
||||
days = *tp / SECDAY;
|
||||
secs = *tp % SECDAY;
|
||||
|
||||
/* Hours, minutes, seconds are easy */
|
||||
dt->dt_hour = secs / 3600;
|
||||
secs = secs % 3600;
|
||||
dt->dt_min = secs / 60;
|
||||
secs = secs % 60;
|
||||
dt->dt_sec = secs;
|
||||
|
||||
/* Day of week (Note: 1/1/1970 was a Thursday) */
|
||||
dt->dt_dow = (days + 4) % 7;
|
||||
|
||||
/* Number of years in days */
|
||||
i = POSIX_BASE_YEAR;
|
||||
while (days >= days_in_year(i)) {
|
||||
days -= days_in_year(i);
|
||||
i++;
|
||||
}
|
||||
dt->dt_year = i - CLOCK_BASE_YEAR;
|
||||
|
||||
/* Number of months in days left */
|
||||
if (leapyear(i))
|
||||
days_in_month(FEBRUARY) = 29;
|
||||
for (i = 1; days >= days_in_month(i); i++)
|
||||
days -= days_in_month(i);
|
||||
days_in_month(FEBRUARY) = 28;
|
||||
dt->dt_month = i;
|
||||
|
||||
/* Days are what is left over (+1) from all that. */
|
||||
dt->dt_day = days + 1;
|
||||
}
|
||||
|
||||
void dt_to_gmt(struct date_time *dt, long *tp)
|
||||
{
|
||||
register int i;
|
||||
register long tmp;
|
||||
int year;
|
||||
|
||||
/*
|
||||
* Hours are different for some reason. Makes no sense really.
|
||||
*/
|
||||
|
||||
tmp = 0;
|
||||
|
||||
if (dt->dt_hour >= 24) goto out;
|
||||
if (dt->dt_day > 31) goto out;
|
||||
if (dt->dt_month > 12) goto out;
|
||||
|
||||
year = dt->dt_year + CLOCK_BASE_YEAR;
|
||||
|
||||
/*
|
||||
* Compute days since start of time
|
||||
* First from years, then from months.
|
||||
*/
|
||||
for (i = POSIX_BASE_YEAR; i < year; i++)
|
||||
tmp += days_in_year(i);
|
||||
if (leapyear(year) && dt->dt_month > FEBRUARY)
|
||||
tmp++;
|
||||
|
||||
/* Months */
|
||||
for (i = 1; i < dt->dt_month; i++)
|
||||
tmp += days_in_month(i);
|
||||
tmp += (dt->dt_day - 1);
|
||||
|
||||
/* Now do hours */
|
||||
tmp = tmp * 24 + dt->dt_hour;
|
||||
|
||||
/* Now do minutes */
|
||||
tmp = tmp * 60 + dt->dt_min;
|
||||
|
||||
/* Now do seconds */
|
||||
tmp = tmp * 60 + dt->dt_sec;
|
||||
|
||||
out:
|
||||
*tp = tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now routines to get and set clock as POSIX time.
|
||||
*/
|
||||
|
||||
static long clk_get_secs()
|
||||
{
|
||||
struct date_time dt;
|
||||
long gmt;
|
||||
|
||||
clk_get_dt(&dt);
|
||||
dt_to_gmt(&dt, &gmt);
|
||||
return (gmt);
|
||||
}
|
||||
|
||||
static void clk_set_secs(long secs)
|
||||
{
|
||||
struct date_time dt;
|
||||
long gmt;
|
||||
|
||||
gmt = secs;
|
||||
gmt_to_dt(&gmt, &dt);
|
||||
clk_set_dt(&dt);
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
/* Call this from DDB or whatever... */
|
||||
int clkdebug()
|
||||
{
|
||||
struct date_time dt;
|
||||
long gmt;
|
||||
long *lp;
|
||||
|
||||
bzero((char*)&dt, sizeof(dt));
|
||||
clk_get_dt(&dt);
|
||||
lp = (long*)&dt;
|
||||
printf("clkdebug: dt=[%x,%x]\n", lp[0], lp[1]);
|
||||
|
||||
dt_to_gmt(&dt, &gmt);
|
||||
printf("clkdebug: gmt=%x\n", gmt);
|
||||
}
|
||||
#endif
|
||||
|
@ -28,7 +28,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: intersil7170.h,v 1.5 1994/09/20 16:52:26 gwr Exp $
|
||||
* $Id: intersil7170.h,v 1.6 1994/09/26 17:25:21 gwr Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -39,20 +39,20 @@
|
||||
* document #301680-005, Dec 85
|
||||
*/
|
||||
|
||||
struct intersil_map { /* from p. 7 of 10 */
|
||||
unsigned char csecs;
|
||||
unsigned char hours;
|
||||
unsigned char minutes;
|
||||
unsigned char seconds;
|
||||
unsigned char month;
|
||||
unsigned char date;
|
||||
unsigned char year;
|
||||
unsigned char day;
|
||||
struct date_time { /* from p. 7 of 10 */
|
||||
unsigned char dt_csec;
|
||||
unsigned char dt_hour;
|
||||
unsigned char dt_min;
|
||||
unsigned char dt_sec;
|
||||
unsigned char dt_month;
|
||||
unsigned char dt_day;
|
||||
unsigned char dt_year;
|
||||
unsigned char dt_dow;
|
||||
};
|
||||
|
||||
struct intersil7170 {
|
||||
struct intersil_map counters;
|
||||
struct intersil_map clk_ram; /* should be ok as both are word aligned */
|
||||
struct date_time counters;
|
||||
struct date_time clk_ram; /* should be ok as both are word aligned */
|
||||
unsigned char clk_intr_reg;
|
||||
unsigned char clk_cmd_reg;
|
||||
};
|
||||
@ -88,10 +88,3 @@ struct intersil7170 {
|
||||
|
||||
#define INTERSIL_INTER_BITS "\20\10PENDING\7DAYS\6HRS\5MIN\4SCDS\3DSEC\2CSEC\1ALARM"
|
||||
|
||||
/* useful info */
|
||||
|
||||
#define INTERSIL_YEAR_BASE 68
|
||||
#define INTERSIL_UNIX_BASE 70
|
||||
|
||||
#define INTERSIL_LEAP_YEAR(x) !((x) % 4)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user