home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 8 / CDASC08.ISO / NEWS / 676 / PLAYLPT / CLKSVC2.C next >
Text File  |  1993-10-07  |  7KB  |  224 lines

  1. /* 
  2. **     This module handles the clock interupt and reprograms the 8253(4) chip.
  3. **    
  4. **    The clock interupt vector is set to an assembly routine TimerStk that
  5. **  resets to a larger private stack in the data segment.  ( Disaster 
  6. **    prevention. )  TimerStk calls "clkirq8h".
  7. **
  8. ** 
  9. \***************************************************************************/
  10. #include <stdio.h>
  11. #include <dos.h>
  12. #include <conio.h>
  13.  
  14.  
  15. /* clock and interrupt IO and interrupt definitions */
  16. #define CLKCTL_IOADDR 0x43
  17. #define CLKT0_DATA_IOADDR 0x40
  18. #define CLKT1_DATA_IOADDR 0x41
  19. #define CLKT2_DATA_IOADDR 0x42
  20. #define CLKCTL_TMD0 0x36        /* Timer 0 binary square wave */
  21. #define CLKCTL_LATCH0 0x00        /* Latch timeer 0 for reading */
  22. #define CLK_PERIOD ((unsigned) 0xffff)    /* divide by 1 */
  23.  
  24. #define IRQCTL_IOADDR 0x20
  25. #define IRQCTL_MASK 0x20
  26.  
  27. #define CLK_VECT 0x08
  28.  
  29.  
  30. /* interrupt function prototypes */
  31. void interrupt cdecl far clkirq8h();
  32. static void (interrupt far * near old_clkirq)();
  33. static void (*aux_clkfnc)();        /* pointer to irq auxillary function */
  34. static void (*aux_clkfnc_A)() = NULL; /* pointer to irq auxillary function */
  35.  
  36. /* local & countdown varaibles */
  37. static int near irq_counter;        /* timer interupt pass counter */
  38. static int near clk_factor;                /* divied clock by n */
  39. static int near re_enter_flag;    /* timer re-entry prevention flag */
  40. static int near re_enter_flag_A; /* timer re-entry prevention for fast service */
  41. unsigned long near clk_period_fast;                /* clock period */
  42. unsigned long near clk_period;                    /* clock period */
  43.  
  44. /*
  45. **        initclk_1()
  46. **
  47. **    DESCRIPTION:
  48. **        Sets the 8253 timer to be n times as fast as normal and enables 
  49. **        the clock interupt (clkirq8h) service routine.  This routine
  50. **        is used by multic.  If TimerStk is already the interupt service
  51. **        routine, then no action is taken.  Zero, One or Two functions
  52. **        that are to be executed by clkirq8h.  The first executes on every
  53. **        normal clock tick ( 55 mil sec ).  If it is NULL, then no fuction
  54. **        is executed.  The second executes on every clock tick. ( 55/n ).
  55. **        If the second function is NULL, then no function is executed.
  56. **        
  57. **
  58. **    PARAMETERS:
  59. **        Address of interupt function to be called
  60. **        Address of interupt function to be called for fast clock
  61. **        Factor of normal clock interupt - MUST be power of 2
  62. **
  63. *********/
  64. void initclk_1( void (*clock_func)(void), void (*clock_func_A)(void), int clock_factor )
  65. {
  66.     void (interrupt far * current_irq)();
  67.     int proc_status;    /* processor status word */
  68.     unsigned int clk_init;             /* clock initialization value */
  69.  
  70.     clk_factor = clock_factor;
  71.     clk_period = 0x10000;
  72.     clk_period_fast = ( 0x10000 / clk_factor );
  73.     clk_init = clk_period_fast - 1;
  74.     current_irq = _dos_getvect( CLK_VECT );
  75. /*
  76. **  if timer service was  set - change on the function vector
  77. */
  78.     if( current_irq != clkirq8h )
  79.     {
  80.         _disable();
  81.         outp( CLKCTL_IOADDR, CLKCTL_TMD0 );        /* Set the mode for T0 */
  82.         outp( CLKT0_DATA_IOADDR, (int) 0xff & ( clk_init ) ); /* Least sig byte */
  83.         outp( CLKT0_DATA_IOADDR, (int) clk_init >> 8 ); /* Most signifgant byte */
  84.         irq_counter = clk_factor;
  85.         aux_clkfnc = clock_func;        /* function to be exec for std clock */
  86.         aux_clkfnc_A = clock_func_A;    /* function to be exec for fast
  87.                                          * clock */
  88.         old_clkirq = current_irq;
  89.         _dos_setvect( CLK_VECT, clkirq8h );
  90.         re_enter_flag = 0;                /* initialize re-entry prevention flag */
  91.         re_enter_flag_A = 0;               /* initialize re-entry prevention
  92.                                          * flag for fast clock */
  93.         _enable();
  94.     }
  95.     else
  96.     {
  97.         _disable();
  98.         aux_clkfnc = clock_func;        /* function to be exec for std clock */
  99.         aux_clkfnc_A = clock_func_A;    /* function to be exec for fast */
  100.         _enable();
  101.     }
  102. }
  103. /*
  104. **        initclk()
  105. **        $paths$
  106. **
  107. **    DESCRIPTION:
  108. **        call initclk using the fast interrupt only.
  109. **        
  110. **
  111. **    PARAMETERS:
  112. **        Address of interupt function to be called for fast clock
  113. **        Factor of normal clock interupt - MUST be power of 2
  114. **
  115. *********/
  116. void initclk( void (*clock_func_A)(void), int clock_factor )
  117. {
  118.     initclk_1( NULL, clock_func_A, clock_factor );
  119. }
  120.  
  121. /*
  122. **        restclk()
  123. **
  124. **    DESCRIPTION:
  125. **        Sets the 8253 timer to be the normal DOS rate and restores the orig. 
  126. **        the clock interupt (TimerStk) service routine.  This routine
  127. **        is used by multic.  If TimerStk not the interupt service
  128. **        routine, then no action is taken.
  129. **
  130. *********/
  131. void restclk( void )
  132. {
  133.     void (interrupt far * current_irq)();
  134.     int proc_status;    /* processor status word */
  135.  
  136.     current_irq = _dos_getvect( CLK_VECT );
  137. /*
  138. **  if timer service was not set - skip to end
  139. */
  140.     if( current_irq == clkirq8h )
  141.     {
  142.         _disable();
  143.         outp( CLKCTL_IOADDR, CLKCTL_TMD0 );        /* Set the mode for T0 */
  144. /*
  145. **  set the clock back to the DOS clock rate
  146. */
  147.         outp( CLKT0_DATA_IOADDR, 0xff ); /* Least signifgant byte */
  148.         outp( CLKT0_DATA_IOADDR, 0xff ); /* Most signifgant byte */
  149.         _dos_setvect( CLK_VECT, old_clkirq );
  150.         _enable();
  151.     }
  152. }
  153. /*
  154. **        readclk()
  155. **
  156. **    DESCRIPTION:
  157. **        Reads the 8253(4) timer 0 and returns its current value
  158. **
  159. *********/
  160. int readclk( void )
  161. {
  162.     register int time = 0;
  163.     register int proc_status;
  164.  
  165.     _disable();
  166.     outp( CLKCTL_IOADDR, CLKCTL_LATCH0 );        /* Set the mode for T0 */
  167.     time = inp( CLKT0_DATA_IOADDR);                /* Least signifgant byte */
  168.     time |= inp( CLKT0_DATA_IOADDR) << 8 ;        /* Most signifgant byte */
  169.     _enable();
  170.     return( time );        /* restore interupts */
  171. }
  172. /*
  173. **        clkirq8h()
  174. **
  175. **    DESCRIPTION:
  176. **        Connects to the 8253 clock interupts.  Executes the user routine every
  177. **        clock tick.
  178. **
  179. *********/
  180. void interrupt cdecl far clkirq8h( void )
  181.     /*    $end$ synopsis */
  182. {
  183.     int slow_irq;
  184.  
  185.     slow_irq = --irq_counter;
  186.  
  187.     /* execute bios routine if required */
  188.     if( ! slow_irq )
  189.     {
  190.         ( *old_clkirq )();            /* bios clock routine */
  191.     }
  192.     else
  193.     {
  194.         outp( IRQCTL_IOADDR, IRQCTL_MASK );  /* service interupt controller */
  195.     }
  196.  
  197.     /* Check and executed fast clock function */
  198.     if( ( aux_clkfnc_A != NULL ) && ( ! re_enter_flag_A ) )
  199.     {
  200.         re_enter_flag_A = 1;        /* prevent reentery */
  201.         _enable();                      /* enable interupts */
  202.         ( *aux_clkfnc_A )();        /* execute factored tick function */
  203.         _disable();                      /* disable irq to prevent premature re-enter */
  204.         re_enter_flag_A = 0;        /* ok to execute now */
  205.     }
  206.     if( ! slow_irq )
  207.     {
  208.         irq_counter = clk_factor;    /* reset count down counter */
  209.         if( ! re_enter_flag )
  210.         {
  211.             re_enter_flag = 1;        /* prevent reentery */
  212.             _enable();                 /* interupts ok during tick */
  213.             if( ( aux_clkfnc != NULL ) )
  214.             {
  215.                 ( *aux_clkfnc )();    /* execute standard tick function */
  216.             }
  217.             re_enter_flag = 0;        /* ok to execute now */
  218.         }
  219.         _disable();                    /* turn them off again */
  220.     }
  221.     return;
  222. }
  223.  
  224.