home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 8
/
CDASC08.ISO
/
NEWS
/
676
/
PLAYLPT
/
CLKSVC2.C
next >
Wrap
Text File
|
1993-10-07
|
7KB
|
224 lines
/*
** This module handles the clock interupt and reprograms the 8253(4) chip.
**
** The clock interupt vector is set to an assembly routine TimerStk that
** resets to a larger private stack in the data segment. ( Disaster
** prevention. ) TimerStk calls "clkirq8h".
**
**
\***************************************************************************/
#include <stdio.h>
#include <dos.h>
#include <conio.h>
/* clock and interrupt IO and interrupt definitions */
#define CLKCTL_IOADDR 0x43
#define CLKT0_DATA_IOADDR 0x40
#define CLKT1_DATA_IOADDR 0x41
#define CLKT2_DATA_IOADDR 0x42
#define CLKCTL_TMD0 0x36 /* Timer 0 binary square wave */
#define CLKCTL_LATCH0 0x00 /* Latch timeer 0 for reading */
#define CLK_PERIOD ((unsigned) 0xffff) /* divide by 1 */
#define IRQCTL_IOADDR 0x20
#define IRQCTL_MASK 0x20
#define CLK_VECT 0x08
/* interrupt function prototypes */
void interrupt cdecl far clkirq8h();
static void (interrupt far * near old_clkirq)();
static void (*aux_clkfnc)(); /* pointer to irq auxillary function */
static void (*aux_clkfnc_A)() = NULL; /* pointer to irq auxillary function */
/* local & countdown varaibles */
static int near irq_counter; /* timer interupt pass counter */
static int near clk_factor; /* divied clock by n */
static int near re_enter_flag; /* timer re-entry prevention flag */
static int near re_enter_flag_A; /* timer re-entry prevention for fast service */
unsigned long near clk_period_fast; /* clock period */
unsigned long near clk_period; /* clock period */
/*
** initclk_1()
**
** DESCRIPTION:
** Sets the 8253 timer to be n times as fast as normal and enables
** the clock interupt (clkirq8h) service routine. This routine
** is used by multic. If TimerStk is already the interupt service
** routine, then no action is taken. Zero, One or Two functions
** that are to be executed by clkirq8h. The first executes on every
** normal clock tick ( 55 mil sec ). If it is NULL, then no fuction
** is executed. The second executes on every clock tick. ( 55/n ).
** If the second function is NULL, then no function is executed.
**
**
** PARAMETERS:
** Address of interupt function to be called
** Address of interupt function to be called for fast clock
** Factor of normal clock interupt - MUST be power of 2
**
*********/
void initclk_1( void (*clock_func)(void), void (*clock_func_A)(void), int clock_factor )
{
void (interrupt far * current_irq)();
int proc_status; /* processor status word */
unsigned int clk_init; /* clock initialization value */
clk_factor = clock_factor;
clk_period = 0x10000;
clk_period_fast = ( 0x10000 / clk_factor );
clk_init = clk_period_fast - 1;
current_irq = _dos_getvect( CLK_VECT );
/*
** if timer service was set - change on the function vector
*/
if( current_irq != clkirq8h )
{
_disable();
outp( CLKCTL_IOADDR, CLKCTL_TMD0 ); /* Set the mode for T0 */
outp( CLKT0_DATA_IOADDR, (int) 0xff & ( clk_init ) ); /* Least sig byte */
outp( CLKT0_DATA_IOADDR, (int) clk_init >> 8 ); /* Most signifgant byte */
irq_counter = clk_factor;
aux_clkfnc = clock_func; /* function to be exec for std clock */
aux_clkfnc_A = clock_func_A; /* function to be exec for fast
* clock */
old_clkirq = current_irq;
_dos_setvect( CLK_VECT, clkirq8h );
re_enter_flag = 0; /* initialize re-entry prevention flag */
re_enter_flag_A = 0; /* initialize re-entry prevention
* flag for fast clock */
_enable();
}
else
{
_disable();
aux_clkfnc = clock_func; /* function to be exec for std clock */
aux_clkfnc_A = clock_func_A; /* function to be exec for fast */
_enable();
}
}
/*
** initclk()
** $paths$
**
** DESCRIPTION:
** call initclk using the fast interrupt only.
**
**
** PARAMETERS:
** Address of interupt function to be called for fast clock
** Factor of normal clock interupt - MUST be power of 2
**
*********/
void initclk( void (*clock_func_A)(void), int clock_factor )
{
initclk_1( NULL, clock_func_A, clock_factor );
}
/*
** restclk()
**
** DESCRIPTION:
** Sets the 8253 timer to be the normal DOS rate and restores the orig.
** the clock interupt (TimerStk) service routine. This routine
** is used by multic. If TimerStk not the interupt service
** routine, then no action is taken.
**
*********/
void restclk( void )
{
void (interrupt far * current_irq)();
int proc_status; /* processor status word */
current_irq = _dos_getvect( CLK_VECT );
/*
** if timer service was not set - skip to end
*/
if( current_irq == clkirq8h )
{
_disable();
outp( CLKCTL_IOADDR, CLKCTL_TMD0 ); /* Set the mode for T0 */
/*
** set the clock back to the DOS clock rate
*/
outp( CLKT0_DATA_IOADDR, 0xff ); /* Least signifgant byte */
outp( CLKT0_DATA_IOADDR, 0xff ); /* Most signifgant byte */
_dos_setvect( CLK_VECT, old_clkirq );
_enable();
}
}
/*
** readclk()
**
** DESCRIPTION:
** Reads the 8253(4) timer 0 and returns its current value
**
*********/
int readclk( void )
{
register int time = 0;
register int proc_status;
_disable();
outp( CLKCTL_IOADDR, CLKCTL_LATCH0 ); /* Set the mode for T0 */
time = inp( CLKT0_DATA_IOADDR); /* Least signifgant byte */
time |= inp( CLKT0_DATA_IOADDR) << 8 ; /* Most signifgant byte */
_enable();
return( time ); /* restore interupts */
}
/*
** clkirq8h()
**
** DESCRIPTION:
** Connects to the 8253 clock interupts. Executes the user routine every
** clock tick.
**
*********/
void interrupt cdecl far clkirq8h( void )
/* $end$ synopsis */
{
int slow_irq;
slow_irq = --irq_counter;
/* execute bios routine if required */
if( ! slow_irq )
{
( *old_clkirq )(); /* bios clock routine */
}
else
{
outp( IRQCTL_IOADDR, IRQCTL_MASK ); /* service interupt controller */
}
/* Check and executed fast clock function */
if( ( aux_clkfnc_A != NULL ) && ( ! re_enter_flag_A ) )
{
re_enter_flag_A = 1; /* prevent reentery */
_enable(); /* enable interupts */
( *aux_clkfnc_A )(); /* execute factored tick function */
_disable(); /* disable irq to prevent premature re-enter */
re_enter_flag_A = 0; /* ok to execute now */
}
if( ! slow_irq )
{
irq_counter = clk_factor; /* reset count down counter */
if( ! re_enter_flag )
{
re_enter_flag = 1; /* prevent reentery */
_enable(); /* interupts ok during tick */
if( ( aux_clkfnc != NULL ) )
{
( *aux_clkfnc )(); /* execute standard tick function */
}
re_enter_flag = 0; /* ok to execute now */
}
_disable(); /* turn them off again */
}
return;
}