home *** CD-ROM | disk | FTP | other *** search
- /* $Header: ntp_pcclock.c,v 1.5 91/06/21 15:21:40 ath Exp $ */
- /*
- * ntp_pcclock.c - routines for reading and adjusting NOS' ntp clock.
- */
-
- #include <stdio.h>
-
- #include "global.h"
- #include "sockaddr.h"
- #include "timer.h"
-
- #include "ntp_types.h"
- #include "ntp_syslog.h"
- #include "ntp_fp.h"
- #define CLOCK_ADJ 4
-
- extern int debug;
-
- /*
- * These routines (init_systime, get_systime, step_systime, adj_systime)
- * implement an interface between the (more or less) system independent
- * bits of NTP and the hacked NOS clock. NOS now keeps time in NTP format,
- * so this interface is much simpler than the Unix version.
- */
-
- /*
- * Clock variables. We limit the adjustment to (tsf_maxslew fractional sec)
- * in one four second period. As we are thus limited in the speed and
- * precision with which we can adjust the
- * clock, we compensate by keeping the known "error" in the system time
- * in sys_offset. This is added to timestamps returned by get_systime().
- */
- unsigned long tsf_maxslew; /* same as above, as long format */
- static l_fp sys_offset; /* correction for current system time */
-
- /*
- * init_systime - initialize the system clock support code, return
- * clock precision.
- *
- * used in the same manner. Tick is supposed to be the number of
- * microseconds which are added to the system clock at clock interrupt
- * time when the time isn't being slewed. Tickadj is supposed to be
- * the number of microseconds which are added or subtracted from tick when
- * the time is being slewed.
- *
- * If either of these two variables is missing, or is there but is used
- * for a purpose different than that described, you are SOL and may have
- * to do some custom kludging.
- *
- * This really shouldn't be in here.
- */
- void
- init_systime()
- {
- u_long tickadj;
- u_long tick;
- u_long hz;
-
- /*
- * Obtain the values. There are both in NTP fractional seconds.
- */
- tickadj = get_tickadj();
- tick = get_tick();
-
- /*
- * Estimate hz from tick. I'm cheating--since tick is an NTP fraction,
- * this should be 0x100000000 / tick, but we can only do 32 bit math.
- */
- hz = 0xffffffffL / tick;
-
- /*
- * Set the maximum slew based on tickadj and tick. Note
- * that maxslew is set slightly shorter than it needs to be as
- * insurance that all slews requested will complete in CLOCK_ADJ
- * seconds.
- */
- tsf_maxslew = tickadj * (hz - 1) * CLOCK_ADJ;
- #ifdef DEBUG
- if (debug)
- printf("tsf_maxslew = 0.%08lx\n", tsf_maxslew);
- #endif
-
- /*
- * Set the current offset to 0
- */
- sys_offset.l_ui = sys_offset.l_uf = 0;
- }
-
-
- /*
- * get_systime - return the system time in timestamp format
- */
- void
- get_systime(ts)
- l_fp *ts;
- {
- #ifndef SLEWALWAYS
- /*
- * Quickly get the time of day.
- */
- getntptimeofday (ts);
- #else /* SLEWALWAYS */
- /*
- * Get the time of day and add in the current time offset.
- * Then round appropriately.
- */
- getntptimeofday (ts);
- L_ADD(ts, &sys_offset);
- #endif /* SLEWALWAYS */
- }
-
-
- /*
- * step_systime - do a step adjustment in the system time (at least from
- * NTP's point of view.
- */
- void
- step_systime(ts)
- l_fp *ts;
- {
- #ifndef SLEWALWAYS
- extern char *lfptoa();
- extern void stepntptime ();
-
- /*
- * We can afford to be sloppy here since if this is called
- * the time is really screwed and everything is being reset.
- */
- L_ADD(&sys_offset, ts);
-
- /* call the hardware-specific step routine. */
- stepntptime (&sys_offset);
- #ifdef DEBUG
- if (debug > 3)
- printf("step: %s, sys_offset = %s\n",
- lfptoa(&ts, 9), lfptoa(&sys_offset, 9));
- #endif
- sys_offset.l_ui = sys_offset.l_uf = 0;
-
- #else
- /*
- * Just add adjustment into the current offset. The update
- * routine will take care of bringing the system clock into
- * line.
- */
- L_ADD(&sys_offset, ts);
- #endif /* SLEWALWAYS */
- }
-
-
- /*
- * adj_systime - called once every CLOCK_ADJ seconds to make system time
- * adjustments.
- */
- void
- adj_systime(adj)
- long adj;
- {
- register unsigned long offset_i, offset_f;
- int32 slew, leftover;
- register int isneg = 0;
- extern char *mfptoa();
- extern char *umfptoa();
-
- /*
- * Move the current offset into the registers
- */
- offset_i = sys_offset.l_ui;
- offset_f = sys_offset.l_uf;
-
- /*
- * Add the new adjustment into the system offset. Adjust the
- * system clock to minimize this.
- */
- M_ADDF(offset_i, offset_f, adj);
- if (M_ISNEG(offset_i, offset_f)) {
- isneg = 1;
- M_NEG(offset_i, offset_f);
- }
- #ifdef DEBUG
- if (debug > 4)
- printf("adj_systime(%s): offset = %s%s\n",
- mfptoa((adj<0?-1L:0L), adj, 9), isneg?"-":"",
- umfptoa(offset_i, offset_f, 9));
- #endif
-
- if (offset_i > 0 || offset_f >= tsf_maxslew) {
- /*
- * Slew is bigger than we can complete in
- * the adjustment interval. Make a maximum
- * sized slew and reduce sys_offset by this
- * much.
- */
- M_SUBUF(offset_i, offset_f, tsf_maxslew);
- if (!isneg) {
- slew = tsf_maxslew;
- } else {
- slew = -tsf_maxslew;
- M_NEG(offset_i, offset_f);
- }
-
- #ifdef DEBUG
- if (debug > 4)
- printf(
- "maximum slew: %s%s, remainder = %s\n",
- isneg?"-":"", umfptoa(0L, tsf_maxslew, 9),
- mfptoa(offset_i, offset_f, 9));
- #endif
- } else {
- /*
- * We can do this slew in the time period.
- *
- * Note that offset_i is guaranteed to be 0 here.
- */
- if (isneg) {
- slew = -offset_f;
- } else {
- slew = offset_f;
- }
- offset_i = offset_f = 0;
- #ifdef DEBUG
- if (debug > 4)
- printf("slew: %s\n", mfptoa((slew<0?-1L:0L), slew, 9));
- #endif
- }
-
- sys_offset.l_ui = offset_i;
- sys_offset.l_uf = offset_f;
-
- if (slew == 0)
- return;
- if (leftover = adjtime (slew)) {
- syslog(LOG_ERR, "Previous time adjustment didn't complete");
- #ifdef DEBUG
- if (debug > 4)
- printf(
- "Previous adjtime() incomplete, residual = %ld\n",
- leftover);
- #endif
- }
- }
-