mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
828 lines
19 KiB
828 lines
19 KiB
#include "windows.h" /* included for Sleep() */
|
|
|
|
|
|
|
|
#include "insignia.h"
|
|
#include "host_def.h"
|
|
/*
|
|
* SoftPC Revision 2.0
|
|
*
|
|
* File : time_day.c
|
|
*
|
|
* Title : Time of day
|
|
*
|
|
* Sccs ID : @(#)time_day.c 1.27 4/20/94
|
|
*
|
|
* Description : Get/Set time of day
|
|
*
|
|
* Author : Henry Nash
|
|
*
|
|
* Notes : The PC-XT version has an interrupt 18.203 times a second
|
|
* to keep the counter up to date. We interrupt at a similar
|
|
* rate, but because of occasional heavy graphics or disk
|
|
* operations we lose ticks. In an attempt to still keep
|
|
* good time, we correct the stored time whenever the host
|
|
* detects a timer event, using the host time facilities.
|
|
*
|
|
* Upon reset time_of_day_init() grabs the host system time &
|
|
* puts it into the BIOS data area variables. Subsequent
|
|
* time of day accesses are maintained using the host system
|
|
* time. This enables well behaved programs to keep good time
|
|
* even if ticks are missed.
|
|
*
|
|
* Mods: (r3.4) : Make use of the host time structures host_timeval,
|
|
* host_timezone, and host_tm, which are equivalent
|
|
* to the Unix BSD4.2 structures.
|
|
*
|
|
* Removed calls to cpu_sw_interrupt and replaced with
|
|
* host_simulate
|
|
*/
|
|
|
|
#ifdef SCCSID
|
|
static char SccsID[]="@(#)time_day.c 1.27 4/20/94 Copyright Insignia Solutions Ltd.";
|
|
#endif
|
|
|
|
#ifdef SEGMENTATION
|
|
/*
|
|
* The following #include specifies the code segment into which this
|
|
* module will by placed by the MPW C compiler on the Mac II running
|
|
* MultiFinder.
|
|
*/
|
|
#include "SOFTPC_BIOS.seg"
|
|
#endif
|
|
|
|
|
|
/*
|
|
* O/S include files.
|
|
*/
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include TimeH
|
|
#include TypesH
|
|
|
|
/*
|
|
* SoftPC include files
|
|
*/
|
|
#include "xt.h"
|
|
#include "sas.h"
|
|
#include "ios.h"
|
|
#include CpuH
|
|
#include "bios.h"
|
|
#include "fla.h"
|
|
#include "host.h"
|
|
#include "timeval.h"
|
|
#include "timer.h"
|
|
#include "error.h"
|
|
|
|
#include "cmos.h"
|
|
#include "cmosbios.h"
|
|
#include "ica.h"
|
|
|
|
|
|
/*
|
|
* ===========================================================================
|
|
* Local static data and defines
|
|
* ===========================================================================
|
|
*/
|
|
|
|
|
|
#ifdef XTSFD
|
|
# define DAY_COUNT BIOS_VAR_START + 0xCE
|
|
#endif
|
|
|
|
|
|
#ifdef NTVDM
|
|
|
|
BOOL UpDateInProgress(void);
|
|
#define UPDATE_IN_PROGRESS UpDateInProgress()
|
|
IMPORT VOID host_init_bda_timer(void);
|
|
|
|
#else
|
|
|
|
#define UPDATE_IN_PROGRESS ( cmos_read(CMOS_REG_A ) & 0x80 )
|
|
static sys_addr user_timer_int_vector;
|
|
static IVT_ENTRY standard_user_timer_int_vector;
|
|
static IVT_ENTRY compatibility_user_timer_int_vector;
|
|
#endif
|
|
|
|
#ifdef ANSI
|
|
LOCAL void get_host_timestamp(word *, word *, half_word *);
|
|
LOCAL void write_host_timestamp(int, int);
|
|
LOCAL void TimeToTicks(int, int, int, word *, word *);
|
|
LOCAL void get_host_time(int *, int *, int *);
|
|
#else
|
|
LOCAL void get_host_timestamp();
|
|
LOCAL void write_host_timestamp();
|
|
LOCAL void TimeToTicks();
|
|
LOCAL void get_host_time();
|
|
#endif /* ANSI */
|
|
|
|
#define TICKS_PER_HOUR 65543L
|
|
#define TICKS_PER_MIN 1092L
|
|
#define TICKS_PER_SEC 18L
|
|
|
|
/*
|
|
* ============================================================================
|
|
* External functions
|
|
* ============================================================================
|
|
*/
|
|
|
|
void time_of_day()
|
|
{
|
|
/*
|
|
* BIOS function to return the number of PC interrupts since boot.
|
|
*/
|
|
|
|
half_word mask;
|
|
word low, high;
|
|
half_word overflow, alarm;
|
|
|
|
|
|
/*
|
|
* Block the Alarm signal whilst we are looking at the clock timer
|
|
*/
|
|
|
|
#ifdef BSD4_2
|
|
host_block_timer();
|
|
#endif
|
|
|
|
switch (getAH()) {
|
|
case 0x00: /* Get time */
|
|
|
|
#ifdef NTVDM
|
|
sas_loadw(TIMER_LOW, &low);
|
|
setDX(low);
|
|
|
|
sas_loadw(TIMER_HIGH, &high);
|
|
setCX(high);
|
|
|
|
sas_load(TIMER_OVFL, &overflow);
|
|
setAL(overflow);
|
|
sas_store(TIMER_OVFL, 0); /* Always write zero after read */
|
|
|
|
#else /* ! NTVDM */
|
|
#ifndef PROD
|
|
if (host_getenv("TIME_OF_DAY_FRIG") == NULL){
|
|
#endif
|
|
/*
|
|
* First get the time from the host
|
|
*/
|
|
|
|
get_host_timestamp(&low, &high, &overflow);
|
|
|
|
/*
|
|
* Use it to return the time AND overwrite the BIOS data
|
|
*/
|
|
|
|
setDX(low);
|
|
sas_storew(TIMER_LOW, low);
|
|
|
|
setCX(high);
|
|
sas_storew(TIMER_HIGH, high);
|
|
|
|
setAL(overflow);
|
|
sas_store(TIMER_OVFL, 0); /* Always write zero after read */
|
|
|
|
#ifndef PROD
|
|
}else{
|
|
SAVED int first=1;
|
|
|
|
if (first){
|
|
first = 0;
|
|
printf ("FRIG ALERT!!!! - time of day frozen!\n");
|
|
}
|
|
|
|
setDX(1);
|
|
sas_storew(TIMER_LOW, 1);
|
|
|
|
setCX(1);
|
|
sas_storew(TIMER_HIGH, 1);
|
|
|
|
setAL(0);
|
|
sas_store(TIMER_OVFL, 0); /* Always write zero after read */
|
|
}
|
|
#endif
|
|
#endif /* NTVDM */
|
|
|
|
break;
|
|
|
|
case 0x01: /* Set time */
|
|
/*
|
|
* Load the BIOS variables
|
|
*/
|
|
|
|
sas_storew(TIMER_LOW, getDX());
|
|
sas_storew(TIMER_HIGH, getCX());
|
|
sas_store(TIMER_OVFL, 0);
|
|
|
|
#ifndef NTVDM
|
|
/*
|
|
* Also the host timestamp
|
|
*/
|
|
|
|
write_host_timestamp(getDX(), getCX());
|
|
#endif
|
|
break;
|
|
case 2: /* read the real time clock */
|
|
|
|
#ifndef NTVDM
|
|
#ifndef PROD
|
|
if (host_getenv("TIME_OF_DAY_FRIG") == NULL){
|
|
#endif
|
|
#endif
|
|
if( UPDATE_IN_PROGRESS )
|
|
setCF(1);
|
|
else
|
|
{
|
|
setDH( cmos_read( CMOS_SECONDS ) );
|
|
setDL( cmos_read( CMOS_REG_B ) & 1 ); /* DSE bit */
|
|
setCL( cmos_read( CMOS_MINUTES ) );
|
|
setCH( cmos_read( CMOS_HOURS ) );
|
|
setCF(0);
|
|
}
|
|
#ifndef NTVDM
|
|
#ifndef PROD
|
|
}else{
|
|
SAVED int first=1;
|
|
|
|
if (first){
|
|
first = 0;
|
|
printf ("FRIG ALERT!!!! - real time clock frozen!\n");
|
|
}
|
|
|
|
setDH( 1 );
|
|
setDL( 0 ); /* DSE bit */
|
|
setCL( 1 );
|
|
setCH( 1 );
|
|
setCF(0);
|
|
}
|
|
#endif
|
|
#endif
|
|
break;
|
|
|
|
case 3: /* Set the real time clock */
|
|
|
|
if( UPDATE_IN_PROGRESS )
|
|
{
|
|
/* initialise real time clock */
|
|
cmos_write( CMOS_REG_A, 0x26 );
|
|
cmos_write( CMOS_REG_B, 0x82 );
|
|
cmos_read( CMOS_REG_C );
|
|
cmos_read( CMOS_REG_D );
|
|
}
|
|
cmos_write( CMOS_SECONDS, getDH() );
|
|
cmos_write( CMOS_MINUTES, getCL() );
|
|
cmos_write( CMOS_HOURS, getCH() );
|
|
alarm = ( cmos_read( CMOS_REG_B ) & 0x62 ) | 2;
|
|
alarm |= (getDL() & 1); /* only use the DSE bit */
|
|
cmos_write( CMOS_REG_B, alarm );
|
|
setCF(0);
|
|
break;
|
|
|
|
|
|
case 4: /* read the date from the real time clock */
|
|
|
|
#ifndef NTVDM
|
|
#ifndef PROD
|
|
if (host_getenv("TIME_OF_DAY_FRIG") == NULL){
|
|
#endif
|
|
#endif
|
|
if( UPDATE_IN_PROGRESS )
|
|
setCF(1);
|
|
else
|
|
{
|
|
setDL( cmos_read( CMOS_DAY_MONTH ) );
|
|
setDH( cmos_read( CMOS_MONTH ) );
|
|
setCL( cmos_read( CMOS_YEAR ) );
|
|
setCH( cmos_read( CMOS_CENTURY ) );
|
|
setCF(0);
|
|
}
|
|
#ifndef NTVDM
|
|
#ifndef PROD
|
|
}else{
|
|
SAVED int first=1;
|
|
|
|
if (first){
|
|
first = 0;
|
|
printf ("FRIG ALERT!!!! - date frozen!\n");
|
|
}
|
|
|
|
setDL( 1 );
|
|
setDH( 4 );
|
|
setCL( 91 );
|
|
setCH( 19 );
|
|
setCF(0);
|
|
}
|
|
#endif
|
|
#endif
|
|
break;
|
|
|
|
case 5: /* Set the date into the real time clock */
|
|
|
|
if( UPDATE_IN_PROGRESS )
|
|
{
|
|
/* initialise real time clock */
|
|
cmos_write( CMOS_REG_A, 0x26 );
|
|
cmos_write( CMOS_REG_B, 0x82 );
|
|
cmos_read( CMOS_REG_C );
|
|
cmos_read( CMOS_REG_D );
|
|
}
|
|
cmos_write( CMOS_DAY_WEEK, 0 );
|
|
cmos_write( CMOS_DAY_MONTH, getDL() );
|
|
cmos_write( CMOS_MONTH, getDH() );
|
|
cmos_write( CMOS_YEAR, getCL() );
|
|
cmos_write( CMOS_CENTURY, getCH() );
|
|
alarm = cmos_read( CMOS_REG_B ) & 0x7f; /* clear 'set bit' */
|
|
cmos_write( CMOS_REG_B, alarm);
|
|
setCF(0);
|
|
break;
|
|
|
|
case 6: /* set the alarm */
|
|
|
|
if( cmos_read(CMOS_REG_B) & 0x20 ) /* alarm already enabled? */
|
|
{
|
|
setCF(1);
|
|
#ifdef BSD4_2
|
|
host_release_timer();
|
|
#endif
|
|
return;
|
|
}
|
|
if( UPDATE_IN_PROGRESS )
|
|
{
|
|
/* initialise real time clock */
|
|
cmos_write( CMOS_REG_A, 0x26 );
|
|
cmos_write( CMOS_REG_B, 0x82 );
|
|
cmos_read( CMOS_REG_C );
|
|
cmos_read( CMOS_REG_D );
|
|
}
|
|
cmos_write( CMOS_SEC_ALARM, getDH() );
|
|
cmos_write( CMOS_MIN_ALARM, getCL() );
|
|
cmos_write( CMOS_HR_ALARM, getCH() );
|
|
inb( ICA1_PORT_1, &mask );
|
|
mask &= 0xfe; /* enable alarm timer int. */
|
|
outb( ICA1_PORT_1, mask );
|
|
alarm = cmos_read( CMOS_REG_B ) & 0x7f; /* ensure set bit turned off */
|
|
alarm |= 0x20; /* turn on alarm enable */
|
|
cmos_write( CMOS_REG_B, alarm );
|
|
break;
|
|
|
|
case 7:
|
|
|
|
alarm = cmos_read( CMOS_REG_B );
|
|
alarm &= 0x57; /* turn off alarm enable */
|
|
cmos_write( CMOS_REG_B, alarm );
|
|
break;
|
|
|
|
|
|
#ifdef XTSFD
|
|
case 0x0A:
|
|
{
|
|
word count;
|
|
|
|
sas_loadw(DAY_COUNT, &count);
|
|
setCX( count );
|
|
break;
|
|
}
|
|
case 0x0B:
|
|
sas_storew(DAY_COUNT, getCX() );
|
|
break;
|
|
default:
|
|
setCF( 1 );
|
|
#else
|
|
default:
|
|
; /* Do nothing */
|
|
#endif
|
|
}
|
|
setAH( 0 );
|
|
|
|
#ifdef BSD4_2
|
|
host_release_timer();
|
|
#endif
|
|
}
|
|
|
|
|
|
void time_int()
|
|
{
|
|
/*
|
|
* NT port does everything in 16 bit int08 handler
|
|
*/
|
|
#ifndef NTVDM
|
|
|
|
/*
|
|
* The BIOS timer interrupt routine.
|
|
*/
|
|
word low, high;
|
|
half_word motor_count, motor_flags;
|
|
|
|
/*
|
|
* Increment the low portion
|
|
*/
|
|
|
|
sas_loadw(TIMER_LOW, &low);
|
|
sas_storew(TIMER_LOW, ++low);
|
|
|
|
/*
|
|
1.9.92 MG
|
|
We need to actually load the timer high value before doing the 24 hour
|
|
test below here.
|
|
*/
|
|
|
|
sas_loadw(TIMER_HIGH, &high);
|
|
|
|
if (low == 0)
|
|
{
|
|
/*
|
|
* Timer has wrapped so update the high count
|
|
*/
|
|
|
|
sas_storew(TIMER_HIGH, ++high);
|
|
}
|
|
|
|
/*
|
|
* Wrap at 24 hrs
|
|
*/
|
|
|
|
if (high == 0x0018 && low == 0x00b0)
|
|
{
|
|
sas_storew(TIMER_LOW, 0x0000);
|
|
sas_storew(TIMER_HIGH, 0x0000);
|
|
sas_store(TIMER_OVFL, 0x01);
|
|
}
|
|
|
|
/*
|
|
* Decrement motor count
|
|
*/
|
|
|
|
sas_load(MOTOR_COUNT, &motor_count);
|
|
if(motor_count < 4)
|
|
motor_count = 0;
|
|
else
|
|
motor_count -= 4;
|
|
sas_store(MOTOR_COUNT, motor_count);
|
|
|
|
if (motor_count == 0)
|
|
{
|
|
/*
|
|
* Turn off motor running bits
|
|
*/
|
|
|
|
sas_load(MOTOR_STATUS,&motor_flags);
|
|
motor_flags &= 0xF0;
|
|
sas_store(MOTOR_STATUS,motor_flags);
|
|
|
|
|
|
/*
|
|
* Provided FLA is not busy, then actually turn the motor off.
|
|
*/
|
|
|
|
if (!fla_busy)
|
|
outb(DISKETTE_DOR_REG, 0x0C);
|
|
}
|
|
|
|
if ( getVM() ||
|
|
((standard_user_timer_int_vector.all != sas_dw_at(user_timer_int_vector)) &&
|
|
(compatibility_user_timer_int_vector.all != sas_dw_at(user_timer_int_vector))) )
|
|
/*
|
|
* There is a user time routine defined - so lets call it
|
|
*/
|
|
{
|
|
exec_sw_interrupt(USER_TIMER_INT_SEGMENT,
|
|
USER_TIMER_INT_OFFSET);
|
|
}
|
|
#endif /* NTVDM */
|
|
}
|
|
|
|
/*
|
|
* ============================================================================
|
|
* Internal Functions
|
|
* ============================================================================
|
|
*/
|
|
|
|
/*
|
|
* NT's sense of time in the bios data area is always
|
|
* kept in sync with the real systems tic count
|
|
* Most of the compensation to readjust tics according
|
|
* to the time of day stuff is not needed
|
|
*/
|
|
#ifndef NTVDM
|
|
/*
|
|
* The routines get_host_timestamp() and write_host_timestamp() are used to
|
|
* override the BIOS record of time, since timer events are known to be lost.
|
|
* Internally the routines work in seconds and microseconds, using the "timeval"
|
|
* struct provided by 4.2BSD. Since System V does not provide this, we supply a
|
|
* version of the 4.2BSD gettimeofday() function locally, making use of the
|
|
* System V function ticks().
|
|
*/
|
|
|
|
/*
|
|
* Our own timestamp for calculating PC time
|
|
*/
|
|
|
|
static struct host_timeval time_stamp;
|
|
|
|
LOCAL void get_host_timestamp(low, high, overflow)
|
|
word *low, *high;
|
|
half_word *overflow;
|
|
{
|
|
/*
|
|
* Provide the time in PC interrupts since startup, in the
|
|
* 32-bit value high:low. The parameter overflow is set to 1
|
|
* if a 24-hour boundary has been passed since the last call.
|
|
*/
|
|
|
|
struct host_timeval now, interval;
|
|
struct host_timezone junk; /* Not used */
|
|
unsigned long ticks; /* Total ticks elapsed */
|
|
long days;
|
|
SAVED long last_time = 0;
|
|
long hours, mins, secs;
|
|
|
|
/*
|
|
* Obtain the current time (since host boot-up)
|
|
*/
|
|
|
|
host_gettimeofday(&now, &junk);
|
|
|
|
/*
|
|
* Calculate how long has passed since the time stamp
|
|
*/
|
|
|
|
interval.tv_sec = now.tv_sec - time_stamp.tv_sec;
|
|
interval.tv_usec = now.tv_usec - time_stamp.tv_usec;
|
|
|
|
/*
|
|
* Handle the "borrow" correction
|
|
*/
|
|
|
|
if (interval.tv_sec > 0 && interval.tv_usec < 0)
|
|
{
|
|
interval.tv_usec += 1000000L;
|
|
interval.tv_sec -= 1;
|
|
};
|
|
|
|
/*
|
|
* TMM 8/1/92:
|
|
* -----------
|
|
*
|
|
* If someone changes the date forwards by >= 24 hours then we should set
|
|
* the overflow flag and ensure that we don't return an interval greater
|
|
* than 24 hours. If the date has changed by >= 48 hours then we will have
|
|
* lost a day. So we put up a panel to tell the user.
|
|
*
|
|
* If some one has set the date backwards and the interval has gone
|
|
* negative then all we can do is put up an error panel informing
|
|
* the user and ensure that we don't set the interval to a negative
|
|
* value.
|
|
*
|
|
* Notes:
|
|
*
|
|
* 1. Setting the overflow flag causes DOS to add a day onto the current
|
|
* date.
|
|
*
|
|
* 2. Setting the interval to a value greater than 24 hours causes DOS
|
|
* to print a "Divide Overflow" error.
|
|
*
|
|
* 3. Setting the interval to a -ve value causes DOS to go into an
|
|
* infinite loop printing "Divide Overflow".
|
|
*/
|
|
|
|
days = interval.tv_sec / (24 * 60 * 60);
|
|
|
|
if (days >= 1)
|
|
{
|
|
/*
|
|
* Someone has set the clock forwards, or we have been frozen for a
|
|
* couple of days. Ensure that the interval is not more than 24 hours,
|
|
* adjust the time_stamp to take care of the lost days.
|
|
*/
|
|
|
|
interval.tv_sec %= 24 * 60 * 60;
|
|
time_stamp.tv_sec += days * (24 * 60 * 60);
|
|
|
|
if (days > 1)
|
|
{
|
|
host_error (EG_DATE_FWD, ERR_CONT | ERR_RESET, "");
|
|
}
|
|
|
|
*overflow = 1;
|
|
}
|
|
else if (interval.tv_sec < 0)
|
|
{
|
|
/*
|
|
* Somebody has set the clock backwards, all we can do is maintain
|
|
* the same time that we had before the clock went back.
|
|
*/
|
|
|
|
time_stamp.tv_sec -= (last_time - now.tv_sec );
|
|
interval.tv_sec = now.tv_sec - time_stamp.tv_sec;
|
|
|
|
*overflow = 0;
|
|
|
|
host_error (EG_DATE_BACK, ERR_CONT | ERR_RESET, "");
|
|
}
|
|
else
|
|
*overflow = 0;
|
|
|
|
/*
|
|
* Convert seconds to hours/minutes/seconds
|
|
*/
|
|
|
|
hours = interval.tv_sec / (60L*60L); /* Hours */
|
|
interval.tv_sec %= (60L*60L);
|
|
|
|
mins = interval.tv_sec / 60L; /* Minutes */
|
|
secs = interval.tv_sec % 60L; /* Seconds */
|
|
|
|
/*
|
|
* Now convert the interval into PC ticks
|
|
* One tick lasts 54925 microseconds.
|
|
*/
|
|
|
|
|
|
ticks = hours * TICKS_PER_HOUR + mins * TICKS_PER_MIN +
|
|
secs * TICKS_PER_SEC + interval.tv_usec/54925 ;
|
|
|
|
/*
|
|
* Split the value into two 16-bit quantities and return
|
|
*/
|
|
|
|
*low = ticks & 0xffff;
|
|
*high = ticks >> 16;
|
|
}
|
|
|
|
|
|
LOCAL void write_host_timestamp(low, high)
|
|
int low, high;
|
|
{
|
|
/*
|
|
* Update our timestamp so that subsequent calls of get_host_timestamp
|
|
* return the correct value. A call of get_host_timestamp() made immediately
|
|
* after this call must return the values set here, so set the timestamp
|
|
* to be the current time less the value set here.
|
|
*/
|
|
|
|
struct host_timeval now, interval;
|
|
struct host_timezone junk; /* Not used */
|
|
long lowms;
|
|
|
|
/*
|
|
* Get the current time.
|
|
*/
|
|
|
|
host_gettimeofday(&now, &junk);
|
|
|
|
|
|
interval.tv_sec = high * 3599 + high/2; /* high ticks to seconds */
|
|
|
|
/*
|
|
* The multiply below can overflow, which has the interesting effect
|
|
* of making Softpc 1 hr 12 mins 40 secs (4300 secs, or 2^32 us) slow
|
|
* if booted in the last third of every hour. So compensate by
|
|
* letting the overflow occur and correcting interval by 4300 secs.
|
|
*/
|
|
|
|
lowms = (IS32) (low & 0xffff) * 54925 + (low & 0xffff)/2;
|
|
if (low > 39098)
|
|
interval.tv_sec += 4300;
|
|
|
|
interval.tv_sec += lowms / 1000000;
|
|
interval.tv_usec = lowms % 1000000;
|
|
|
|
/*
|
|
* The timestamp is the current time less this interval
|
|
*/
|
|
|
|
time_stamp.tv_sec = now.tv_sec - interval.tv_sec;
|
|
time_stamp.tv_usec = now.tv_usec - interval.tv_usec;
|
|
|
|
/*
|
|
* Handle the "borrow" correction, including negative timestamps
|
|
*/
|
|
|
|
if (time_stamp.tv_sec > 0 && time_stamp.tv_usec < 0)
|
|
{
|
|
time_stamp.tv_usec += 1000000L;
|
|
time_stamp.tv_sec -= 1;
|
|
}
|
|
else
|
|
if (time_stamp.tv_sec < 0 && time_stamp.tv_usec > 0)
|
|
{
|
|
time_stamp.tv_usec -= 1000000L;
|
|
time_stamp.tv_sec += 1;
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef SEGMENTATION
|
|
/*
|
|
* The following #include specifies the code segment into which this
|
|
* module will by placed by the MPW C compiler on the Mac II running
|
|
* MultiFinder.
|
|
*/
|
|
#include "SOFTPC_INIT.seg"
|
|
#endif
|
|
|
|
|
|
LOCAL void get_host_time( h, m, s )
|
|
int *h, *m, *s; /* hours, minutes and secs */
|
|
{
|
|
struct host_tm *tp;
|
|
time_t SecsSince1970;
|
|
|
|
SecsSince1970 = host_time(NULL);
|
|
tp = host_localtime(&SecsSince1970);
|
|
*h = tp->tm_hour;
|
|
*m = tp->tm_min;
|
|
*s = tp->tm_sec;
|
|
}
|
|
|
|
/*
|
|
** Take a normal time in hours, minutes and seconds then
|
|
** transmutate it into PC ticks since the beginning of the day.
|
|
*/
|
|
LOCAL void TimeToTicks( hour, minutes, sec, low, hi )
|
|
int hour, minutes, sec; /* inputs */
|
|
word *low, *hi; /* outputs */
|
|
{
|
|
unsigned long ticks; /* Total ticks elapsed */
|
|
|
|
/*
|
|
* Calculate ticks to date
|
|
*/
|
|
|
|
|
|
ticks = hour * TICKS_PER_HOUR + minutes * TICKS_PER_MIN +
|
|
sec * TICKS_PER_SEC;
|
|
|
|
/*
|
|
* Split the value into two 16-bit quantities and return
|
|
*/
|
|
|
|
*low = ticks & 0xffff;
|
|
*hi = ticks >> 16;
|
|
}
|
|
|
|
#endif /* ifndef NTVDM */
|
|
|
|
|
|
void time_of_day_init()
|
|
{
|
|
#ifndef NTVDM
|
|
int hour, minutes, sec; /* Current host time */
|
|
word low, hi; /* Host time in PC ticks */
|
|
|
|
/*
|
|
* Initialise the clock timer.
|
|
*/
|
|
|
|
get_host_time( &hour, &minutes, &sec ); /* get the time from the host */
|
|
|
|
TimeToTicks( hour, minutes, sec, &low, &hi ); /* convert to PC time */
|
|
|
|
sas_storew(TIMER_LOW, low );
|
|
sas_storew(TIMER_HIGH, hi );
|
|
sas_store(TIMER_OVFL,0x01);
|
|
|
|
/*
|
|
* Initialise the host time stamp
|
|
*/
|
|
|
|
write_host_timestamp( low, hi );
|
|
|
|
/*
|
|
* Build the standard IVT entry for the user timer interrupt(s)
|
|
*/
|
|
|
|
compatibility_user_timer_int_vector.all = ((double_word)ADDR_COMPATIBILITY_SEGMENT << 16) + ADDR_COMPATIBILITY_OFFSET;
|
|
standard_user_timer_int_vector.all = ((double_word)DUMMY_INT_SEGMENT << 16) + DUMMY_INT_OFFSET;
|
|
|
|
user_timer_int_vector = BIOS_USER_TIMER_INT * 4;
|
|
|
|
#endif /* NTVDM */
|
|
}
|
|
|
|
|
|
|
|
#ifdef NTVDM
|
|
|
|
/*
|
|
* NTVDM: the rtc is setup so that the UIP bit is set on a cmos
|
|
* port read if the cmos ports haven't been touched for at least
|
|
* 1 second. The IBM pc bios routine for accessing the clock
|
|
* polls RegA for UIP bit in a tight loop 600h times before
|
|
* failing the call. This means that MOST of the time the int1ah
|
|
* rtc fns almost never fail! To mimic this behaviour we poll
|
|
* the port until success, since we know that our rtc will clear
|
|
* UIP bit very quickly.
|
|
*/
|
|
BOOL UpDateInProgress(void)
|
|
{
|
|
|
|
while (cmos_read(CMOS_REG_A) & 0x80) {
|
|
Sleep(0); // give other threads a chance to work
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
#endif
|