www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1995/04/03/12:59:36

Date: Mon, 3 Apr 1995 10:07:13 +0500
From: hvb AT netrix DOT com
To: chan1355 AT cs DOT cuhk DOT hk, jk55 AT cornell DOT edu (Jim Karpinski)
Cc: djgpp AT sun DOT soe DOT clarkson DOT edu
Subject: Re: Code for controlling PC Timer - Complete version
References: <9503312208 DOT AA07914 AT azalea> <9504010251 DOT AA10100 AT cucs18 DOT cs DOT cuhk DOT hk>

Dear all,

Here is the code that I cut and paste from my code.  You may have to
declare the static variables here and there to get it compiled.

There are two versions of this code, one uses the TOD and one uses the
RTC.
The limitations/problems to each version are described.

Sorry for the duplication, I accidentally sent off an incomplete
version of this mail.

/*************************************************************************
        Using the TOD 8253/4 timer.  Works but had problems under
        heavy load of disk access.
*************************************************************************/

#define DOSX_GO32_RAM_OFFSET 0xe0000000

/*---------------------------------------------------------------------------
  Definitions for The PC INTERRUPT CONTROLLER
---------------------------------------------------------------------------*/
#define PC_INT_CONTROLLER  0x20        /* Interrupt controller I/O Address */

#define PC_8253_TIMER_CHANNEL  0x40    /* Timer channel (#0) of the timer chip  */
#define PC_8253_COMMAND_REG   = 0x43   /* Command register of the timer chip    */
#define PC_8253_CH_0_SEQ      = 0x36   /* 00110110 : ch 0, 2 bytes, mode 3, bin */

#define PC_8253_ONE_MSEC_COUNT = 1193   /* The PC 8253 clock input is 1.193180 MHz */
#define PC_8253_CLOCK_RATE     = 1193180
#define TO_KICK_DOS_CLOCK      = 0xffff


/*********************************************************************
*                   PM IRQ 8
* 
*  DESCRIPTION:
*    This function is called when the Time Of Day interrupt occurs
*    while the 386 CPU is in Protected mode.
*    We need to call the DOS real mode interrupt whenever the
* 
*  NOTES:
*    1.  The Rel_1ms clock is not counted every so often to take into
*        account that the real time clock is fast.
*    2.  alias_irq_regs & regs are declared sattic as the 'dpmi' code
*        assumes they belong to the 'DS' selector.
*    3.  Interrupt is explicitly disabled with an "cli" instruction
*        as when int86 is called, the processor may get another clock
*        interrupt when switched back from the real mode.
*********************************************************************/
static void
pm_irq_08 (void)
{
  asm ("cli");
  asm ("push   %eax");
  asm ("push   %ecx");
  asm ("push   %edx");
  asm ("push   %ds");
  asm ("push   $0x48");
  asm ("pop    %ds");

  if ((*One_msec_clock_remainder += *Delta_per_tick) >= PC_8253_CLOCK_RATE)
    *One_msec_clock_remainder -= PC_8253_CLOCK_RATE;
  else
    *Rel_1ms += *Msec_per_tick;

  if ((*Dos_clock_remainder += *Timer_counter) >= TO_KICK_DOS_CLOCK)
  { asm ("pusha");
    asm ("push   %gs");

    *Dos_clock_remainder -= TO_KICK_DOS_CLOCK;

/*-------------------------------------------------------------------
    This is equivalent to _go32_dpmi_simulate_fcall_iret
-------------------------------------------------------------------*/
    Alias_irq_regs.x.cs = Rm_old_irq8.rm_segment;
    Alias_irq_regs.x.ip = Rm_old_irq8.rm_offset;
    Alias_irq_regs.x.ss = 0;
    Alias_irq_regs.x.sp = 0;
    Alias_irq_regs.x.flags = 0;
    Irq_regs.x.ax = 0x302;
    Irq_regs.h.bh = 0;
    Irq_regs.x.cx = 0;
    Irq_regs.x.di = (uint32)(&Alias_irq_regs);
    int86 (0x31, &Irq_regs, &Irq_regs);

    asm ("add    $12, %esp");
    asm ("pop    %gs");
    asm ("popa");
  }
  else
  { asm ("mov    $0x20,%al");
    asm ("out    %al,$0x20");
  }

  asm ("pop    %ds");
  asm ("pop    %edx");
  asm ("pop    %ecx");
  asm ("pop    %eax");
  asm ("leave");
  asm ("iret");
}

/*********************************************************************
*                   INSTALL TOD TIMER INTERRUPT 
* 
*  DESCRIPTION:
*    This function will set up the PC time of day (tod) interrupt to
*    generate interrupt approximately every one millisecond.
*    There are the protected mode and real mode interrupts.
*    The protected mode interrupt needs to call the DOS tod interrupt
*    roughly every 18msec to keep the DOS clock happy.  A set of
*    counters are stored in the DOS low memory so the protected mode
*    and real mode code can share.
*    In real mode, we allocate a block of DOS low memory to create
*    the real mode interrupt code.  This code basically will update
*    the Rel_1ms count and call the DOS tod interrupt every 18 msec.
*
*  NOTES:
*
*********************************************************************/
static void
install_tod_timer_interrupt (void)
{
  _go32_dpmi_seginfo          rm_si;
  _go32_dpmi_seginfo          pm_si;
  uint32                      linear_addr;
  uint32                      go32_addr;
  uint16                     *p16;
  uint32                     *p32;

/*---------------------------------------------------------------------------
  This data space is the code for the real mode clock interrupt.
  The C equivalent form is:

  extern void dos_interrupt (void);
  static unsigned long Timer_counter;
  static unsigned long Dos_clock_remainder;
  static unsigned long One_msec_clock_remainder;
  static unsigned long Delta_per_tick;
  static unsigned long Rel_1ms;
  static unsigned long Msec_per_tick;
  
  #define PC_8253_CLOCK_RATE     (1193180L)
  #define TO_KICK_DOS_CLOCK      (0xffffL)
  
  extern void x (void);
  extern void outp (unsigned reg, unsigned value);
  void x (void)
  {
    if ((One_msec_clock_remainder += Delta_per_tick) >= PC_8253_CLOCK_RATE)
      One_msec_clock_remainder -= PC_8253_CLOCK_RATE;
    else
      Rel_1ms += Msec_per_tick;
  
    if ((Dos_clock_remainder += Timer_counter) >= TO_KICK_DOS_CLOCK)
    { Dos_clock_remainder -= TO_KICK_DOS_CLOCK;
      goto dos_interrupt;
    }
    else
      outp (0x20, 0x20);
  }

---------------------------------------------------------------------------*/
  static uint8 real_mode_code[] = {
                                        /* offset  opcode                          Assembly Mnemonic                                         */
    
    0x00,0x00,0x00,0x00,                /* 0000    00000000                        Timer_counter            dd 0                             */
    0x00,0x00,0x00,0x00,                /* 0004    00000000                        Dos_clock_remainder      dd 0                             */
    0x00,0x00,0x00,0x00,                /* 0008    00000000                        One_msec_clock_remainder dd 0                             */
    0x00,0x00,0x00,0x00,                /* 000C    00000000                        Delta_per_tick           dd 0                             */
    0x00,0x00,0x00,0x00,                /* 0010    00000000                        Rel_1ms                  dd 0                             */
    0x00,0x00,0x00,0x00,                /* 0014    00000000                        Msec_per_tick            dd 0                             */
                                
    0xfa,                               /* 0018    FA                              cli                                                       */
    0x50,                               /* 0019    50                              push   ax                                                 */
    0x52,                               /* 001A    52                              push   dx                                                 */
                                
    0x2e,0xa1,0x0c,0x00,                /* 001B    2E: A1 000C R                   mov    ax,WORD PTR cs:Delta_per_tick                      */
    0x2e,0x8b,0x16,0x0e,0x00,           /* 001F    2E: 8B 16 000E R                mov    dx,WORD PTR cs:Delta_per_tick+2                    */
    0x2e,0x01,0x06,0x08,0x00,           /* 0024    2E: 01 06 0008 R                add    WORD PTR cs:One_msec_clock_remainder,ax            */
    0x2e,0x11,0x16,0x0a,0x00,           /* 0029    2E: 11 16 000A R                adc    WORD PTR cs:One_msec_clock_remainder+2,dx          */
    0x2e,0x83,0x3e,0x0a,0x00,0x12,      /* 002E    2E: 83 3E 000A R 12             cmp    WORD PTR cs:One_msec_clock_remainder+2,18          */
    0x72,0x1b,                          /* 0034    72 1B                           jb     $I112                                              */
    0x77,0x09,                          /* 0036    77 09                           ja     $L20000                                            */
    0x2e,0x81,0x3e,0x08,0x00,0xdc,0x34, /* 0038    2E: 81 3E 0008 R 34DC           cmp    WORD PTR cs:One_msec_clock_remainder,13532         */
    0x72,0x10,                          /* 003F    72 10                           jb     $I112                                              */
                                        /* 0041                           $L20000:                                                           */
    0x2e,0x81,0x2e,0x08,0x00,0xdc,0x34, /* 0041    2E: 81 2E 0008 R 34DC           sub    WORD PTR cs:One_msec_clock_remainder,13532         */
    0x2e,0x83,0x1e,0x0a,0x00,0x12,      /* 0048    2E: 83 1E 000A R 12             sbb    WORD PTR cs:One_msec_clock_remainder+2,18          */
    0xeb,0x14,                          /* 004E    EB 14                           jmp    SHORT $I113                                        */
    0x90,                               /* 0050    90                              nop                                                       */
                                        /* 0051                           $I112:                                                             */
    0x2e,0xa1,0x14,0x00,                /* 0051    2E: A1 0014 R                   mov    ax,WORD PTR cs:Msec_per_tick                       */
    0x2e,0x8b,0x16,0x16,0x00,           /* 0055    2E: 8B 16 0016 R                mov    dx,WORD PTR cs:Msec_per_tick+2                     */
    0x2e,0x01,0x06,0x10,0x00,           /* 005A    2E: 01 06 0010 R                add    WORD PTR cs:Rel_1ms,ax                             */
    0x2e,0x11,0x16,0x12,0x00,           /* 005F    2E: 11 16 0012 R                adc    WORD PTR cs:Rel_1ms+2,dx                           */
                                        /* 0064                           $I113:                                                             */
    0x2e,0xa1,0x00,0x00,                /* 0064    2E: A1 0000 R                   mov    ax, WORD PTR cs:Timer_counter                      */
    0x2e,0x8b,0x16,0x02,0x00,           /* 0068    2E: 8B 16 0002 R                mov    dx, WORD PTR cs:Timer_counter+2                    */
    0x2e,0x01,0x06,0x04,0x00,           /* 006D    2E: 01 06 0004 R                add    WORD PTR cs:Dos_clock_remainder, ax                */
    0x2e,0x11,0x16,0x06,0x00,           /* 0072    2E: 11 16 0006 R                adc    WORD PTR cs:Dos_clock_remainder+2, dx              */
    0x2e,0x83,0x3e,0x06,0x00,0x00,      /* 0077    2E: 83 3E 0006 R 00             cmp    WORD PTR cs:Dos_clock_remainder+2, 0               */
    0x75,0x08,                          /* 007D    75 08                           jne    $L20002                                            */
    0x2e,0x83,0x3e,0x04,0x00,0xff,      /* 007F    2E: 83 3E 0004 R FF             cmp    WORD PTR cs:Dos_clock_remainder, TO_KICK_DOS_CLOCK */
    0x72,0x13,                          /* 0085    72 13                           jb     $I114                                              */
                                        /* 0087                           $L20002:                                                           */
    0x2e,0x83,0x2e,0x04,0x00,0xff,      /* 0087    2E: 83 2E 0004 R FF             sub    WORD PTR cs:Dos_clock_remainder, TO_KICK_DOS_CLOCK */
    0x2e,0x83,0x1e,0x06,0x00,0x00,      /* 008D    2E: 83 1E 0006 R 00             sbb    WORD PTR cs:Dos_clock_remainder+2, 0               */
    0x5a,                               /* 0093    5A                              pop    dx                                                 */
    0x58,                               /* 0094    58                              pop    ax                                                 */
    0xea,0x00,0x00,0x00,0x00,           /* 0095    EA 0000 ---- E                  jmp    <to be set at run time>                            */
                                        /* 009A                           $I114:                                                             */
    0xb0,0x20,                          /* 009A    B0 20                           mov    al,20H                                             */
    0xe6,0x20,                          /* 009C    E6 20                           out    20H,al                                             */
    0x5a,                               /* 009E    5A                              pop    dx                                                 */
    0x58,                               /* 009F    58                              pop    ax                                                 */
    0xcf                                /* 00A0    CF                              iret                                                      */
  };
  
/*---------------------------------------------------------------------------
  allocate DOS low memory to store the code above.
---------------------------------------------------------------------------*/
  Dosx_rm_clock_int_seginfo.size = (sizeof (real_mode_code) + 0x10) / 0x10;
  if (_go32_dpmi_allocate_dos_memory (&Dosx_rm_clock_int_seginfo))
    exit (1);

/*---------------------------------------------------------------------------
  make sure where we put the code is paragraph (16-byte) aligned
  fill memory with INT 3 opcode.
---------------------------------------------------------------------------*/
  linear_addr = (uint16)Dosx_rm_clock_int_seginfo.rm_segment * 0x10;
  if (linear_addr & 0x0000000f)
    linear_addr = (linear_addr + 0x10) & 0xfffffff0;
  go32_addr = linear_addr + DOSX_GO32_RAM_OFFSET;
  memset ((uint8 *)go32_addr, 0xcc, Dosx_rm_clock_int_seginfo.size * 0x10);

/*---------------------------------------------------------------------------
  set up pointers to the shared timer variables, and initialize variables
---------------------------------------------------------------------------*/
  p32 = (uint32 *)go32_addr;
  Timer_counter = p32++;
  Dos_clock_remainder = p32++;
  One_msec_clock_remainder = p32++;
  Delta_per_tick = p32++;
  Rel_1ms = p32++;
  Msec_per_tick = p32;

/*---------------------------------------------------------------------------
  write the code to the DOS low memory
---------------------------------------------------------------------------*/
  _go32_dpmi_get_real_mode_interrupt_vector(8, &Rm_old_irq8);
  memcpy ((uint8 *)go32_addr, real_mode_code, sizeof (real_mode_code));

  *Timer_counter = 1193;
  *Delta_per_tick = PC_8253_CLOCK_RATE % Timer_counter_value;
  *Msec_per_tick = 1000 / (PC_8253_CLOCK_RATE / Timer_counter_value);

  p16 = (uint16 *)(go32_addr + 0x96);
  *p16++ = Rm_old_irq8.rm_offset;
  *p16 = Rm_old_irq8.rm_segment;

/*---------------------------------------------------------------------------
  setup real and protected mode interrupt vectors
---------------------------------------------------------------------------*/
  memset (&rm_si, 0, sizeof (rm_si));
  rm_si.rm_offset = 0x18;
  rm_si.rm_segment = (uint16)(linear_addr >> 4);

  memset (&pm_si, 0, sizeof (pm_si));
  pm_si.pm_offset = (int) pm_irq_08;
  pm_si.pm_selector = _go32_my_cs();

  disable();

  _go32_dpmi_set_real_mode_interrupt_vector(8, &rm_si);
  _go32_dpmi_set_protected_mode_interrupt_vector(8, &pm_si);

  outpb (PC_8253_COMMAND_REG, PC_8253_CH_0_SEQ);
  outpb (PC_8253_TIMER_CHANNEL, Timer_counter_value & 0xff);
  outpb (PC_8253_TIMER_CHANNEL, Timer_counter_value >> 8);

  enable();
}



/*************************************************************************
        Using the RTC timer.  Worked on one PC platform but I
        found it did not work on another platform.  Still
        under investigation.
*************************************************************************/
#define DOSX_GO32_RAM_OFFSET   0xe0000000

/*---------------------------------------------------------------------------
                    MC146818A Real Time Clock (RTC)

  This RTC device can generate IRQ8 interrupt on a periodic basis to
  the PC. See:

  - Dallas Semiconductor handbook for device DS1287 (MC146818A equiv.)
  - ISA System Architecture, by Tom Shanley & Don Anderson - Mind Share Inc
    1993. (Chapter 21).

---------------------------------------------------------------------------*/

#define RTC_ADDR_PORT            0x70  /* RTC chip address port */
#define RTC_DATA_PORT           = 0x71  /* RTC chip data port */

#define RTC_STATUS_REG_A         0xa   /* RTC Status Register A RAM offset */
#define RTC_STATUS_REG_B         0xb   /* RTC Status Register B RAM offset */
#define RTC_STATUS_REG_C         0xc   /* RTC Status Register C RAM offset */

                                 /* status A register definition */
enum uint8 {
  RTC_REG_A_RATE_MASK   = 0x0f,  /* mask to the DS0-DS3 bits */
  RTC_REG_A_RATE_1K     = 0x06,  /* DS0-DS3 value for 1.024 kHz clock rate */
  RTC_REG_A_UIP_BIT     = 0x80,  /* =1 Update in Progress, Read only */
  RTC_REG_A_DV_MASK     = 0x70,  /* oscillator on and off bit */
  RTC_REG_A_DV_32K      = 0x20   /* DV bits to be set to 32.768khz timebase */
};
                                 /* status B register definition */
#define RTC_REG_B_PIE_BIT        0x40  /* 1=> Periodic Interrupt enable */
#define RTC_REG_B_AIE_BIT        0x20  /* 1=> Alarm Interrupt enable */
#define RTC_REG_B_UEIE_BIT       0x10  /* 1=> Update-Ended Interrupt Enable */

#define RTC_INT_TYPE             0x70  /* RTC interrupt type */

#define RTC_REMAINDER_PER_TICK   24    /* count remainder per tick */

/*********************************************************************
*                   PM RTC IRQ
* 
*  DESCRIPTION:
*    This function is called when the RTC interrupt occurs
*    while the 386 CPU is in Protected mode.
* 
*  NOTES:
*    1.  The Rel_1ms clock is not counted every so often to take into
*        account that the real time clock is fast.
*    2.  There is a bug in the gcc compiler used that prohibits the use
*        of "out %al,immed8".  This instruction always generates
*        "out %ax,immed16".  Therefore we have to use the
*        "out %al,%dx" format.
*
*********************************************************************/
static void
pm_rtc_irq (void)
{
  asm ("cli               \n"
       "push   %eax       \n"
       "push   %edx       \n"
       "push   %ds        \n"
       "push   $0x48      \n"
       "pop    %ds        \n"
      );

  if ((*One_msec_clock_remainder += RTC_REMAINDER_PER_TICK) >= 1000)
    *One_msec_clock_remainder -= 1000;
  else
    ++(*Rel_1ms);

/*--------------------------------------------------------------------
  reset the RTC IRQ pin, and the interrupt controller
--------------------------------------------------------------------*/
  asm ("mov    $0x0c,%al   \n"
       "outb   %al,$0x70   \n"
       "in     $0x71,%al   \n"

       "mov    $0x20,%al   \n"
       "outb   %al,$0xa0   \n"
       "outb   %al,$0x20   \n"

       "pop    %ds         \n"
       "pop    %edx        \n"
       "pop    %eax        \n"
       "leave              \n"
       "iret               \n"
      );
}

/*********************************************************************
*                   INSTALL RTC INTERRUPT 
* 
*  DESCRIPTION:
*    This function will set up the PC time of day (tod) interrupt to
*    generate interrupt approximately every one millisecond.
*    There are the protected mode and real mode interrupts.
*    The protected mode interrupt needs to call the DOS tod interrupt
*    roughly every 18msec to keep the DOS clock happy.  A set of
*    counters are stored in the DOS low memory so the protected mode
*    and real mode code can share.
*    In real mode, we allocate a block of DOS low memory to create
*    the real mode interrupt code.  This code basically will update
*    the Rel_1ms count and call the DOS tod interrupt every 18 msec.
*
*  NOTES:
*
*********************************************************************/
static void
install_rtc_interrupt (void)
{
  _go32_dpmi_seginfo          rm_si;
  _go32_dpmi_seginfo          pm_si;
  uint32                      linear_addr;
  uint32                      go32_addr;
  uint8                       temp8;

/*---------------------------------------------------------------------------
  This data space is the code for the real mode clock interrupt.
  The C equivalent form is:

  static unsigned long Rel_1ms;
  static unsigned      One_msec_clock_remainder;
  
  #define RTC_REMAINDER_PER_TICK  (24)
  #define RTC_ADDR_PORT           (0x70) 
  #define RTC_DATA_PORT           (0x71)
  #define RTC_STATUS_REG_C        (0xc) 
  
  extern void x (void);
  extern void outp (unsigned reg, unsigned value);
  extern void inp  (unsigned reg);
  void x (void)
  { 
    if ((*One_msec_clock_remainder += RTC_REMAINDER_PER_TICK) >= 1000)
      *One_msec_clock_remainder -= 1000;
    else
      ++(*Rel_1ms);
  
    outp (0x70, 0x0c);
    inp  (0x71);

    outp (0xa0, 0x20);
    outp (0x20, 0x20);
  }

---------------------------------------------------------------------------*/
  static uint8 real_mode_code[] = {
                                        /* offset  opcode                          Assembly Mnemonic                                                       */
    
    0x00,0x00,0x00,0x00,                /* 0000    00000000                        Rel_1ms                  dd 0                                           */
    0x00,0x00,                          /* 0004    0000                            One_msec_clock_remainder dw 0                                           */
                                
    0xfa,                               /* 0006    FA	                           cli                                                                     */
    0x50,                               /* 0007    50                              push       ax                                                           */
				
    0x2e,0x83,0x06,0x04,0x00,0x18,      /* 0008  2E: 83 06 0004 R 18               add        WORD PTR cs:One_msec_clock_remainder,RTC_REMAINDER_PER_TICK  */
    0x2e,0x81,0x3e,0x04,0x00,0xe8,0x03, /* 000E  2E: 81 3E 0004 R 03E8	           cmp        WORD PTR cs:One_msec_clock_remainder,1000                    */
    0x72,0x09,                          /* 0015  72 09                             jb         $I110                                                        */
    0x2e,0x81,0x2e,0x04,0x00,0xe8,0x03, /* 0017  2E: 81 2E 0004 R 03E8             sub        WORD PTR cs:One_msec_clock_remainder,1000                    */
    0xeb,0x0c,                          /* 001E  EB 0C                             jmp        SHORT $I111                                                  */
				
                                        /* 0020                         $I110:                                                                             */
    0x2e,0x83,0x06,0x00,0x00,0x01,      /* 0020  2E: 83 06 0000 R 01               add        WORD PTR cs:Rel_1ms,1                                        */
    0x2e,0x83,0x16,0x02,0x00,0x00,      /* 0026  2E: 83 16 0002 R 00               adc        WORD PTR cs:Rel_1ms+2,0                                      */
				
                                        /* 002C                         $I111:                                                                             */
    0xb0,0x0c,                          /* 002C  B0 0C                             mov        al,RTC_STATUS_REG_C                                          */
    0xe6,0x70,                          /* 002E  E6 70                             out        RTC_ADDR_PORT,al                                             */
    0xe4,0x71,                          /* 0030  E4 71                             in         al,RTC_DATA_PORT                                             */
				
    0xb0,0x20,                          /* 0032  B0 20	                           mov        al,20H                                                       */
    0xe6,0xa0,                          /* 0034  E6 A0                             out        0a0H,al                                                      */
    0xe6,0x20,                          /* 0036  E6 20                             out        020H,al                                                      */
				
    0x58,                               /* 0038  58                                pop        ax                                                           */
    0xcf                                /* 0039  CF                                iret                                                                    */
  };
  
/*---------------------------------------------------------------------------
  allocate DOS low memory to store the code above.
---------------------------------------------------------------------------*/
  Dosx_rm_clock_int_seginfo.size = (sizeof (real_mode_code) + 0x10) / 0x10;
  if (_go32_dpmi_allocate_dos_memory (&Dosx_rm_clock_int_seginfo))
    n_sys_error (Dosx_out_of_dos_memory);

/*---------------------------------------------------------------------------
  make sure where we put the code is paragraph (16-byte) aligned
  fill memory with INT 3 opcode.
---------------------------------------------------------------------------*/
  linear_addr = (uint16)Dosx_rm_clock_int_seginfo.rm_segment * 0x10;
  go32_addr = linear_addr + DOSX_GO32_RAM_OFFSET;
  memset ((uint8 *)go32_addr, 0xcc, Dosx_rm_clock_int_seginfo.size * 0x10);

/*---------------------------------------------------------------------------
  set up pointers to the shared timer variables, and initialize variables
---------------------------------------------------------------------------*/
  Rel_1ms = (uint32 *)go32_addr;
  One_msec_clock_remainder = (uint16 *)(go32_addr + 4);

  memcpy ((uint8 *)go32_addr, real_mode_code, sizeof (real_mode_code));

  memset (&rm_si, 0, sizeof (rm_si));
  rm_si.rm_offset = 0x06;
  rm_si.rm_segment = (uint16)(linear_addr >> 4);

  memset (&pm_si, 0, sizeof (pm_si));
  pm_si.pm_offset = (int) pm_rtc_irq;
  pm_si.pm_selector = _go32_my_cs();

/*---------------------------------------------------------------------------
  set up the RTC registers for Periodic Interrupt @ 1.024khz
---------------------------------------------------------------------------*/
  disable ();

  outpb (RTC_ADDR_PORT, RTC_STATUS_REG_A);
  temp8 = inpb (RTC_DATA_PORT);
  if ((temp8 & RTC_REG_A_DV_MASK) != RTC_REG_A_DV_32K)
    n_sys_error (Dosx_krnl_rtc_conflict);
  temp8 &= ~RTC_REG_A_RATE_MASK;
  temp8 |= RTC_REG_A_RATE_1K;
  outpb (RTC_ADDR_PORT, RTC_STATUS_REG_A);
  outpb (RTC_DATA_PORT, temp8);

  outpb (RTC_ADDR_PORT, RTC_STATUS_REG_C);
  inpb (RTC_DATA_PORT);
  outpb (RTC_ADDR_PORT, RTC_STATUS_REG_B);
  temp8 = inpb (RTC_DATA_PORT);

  if (temp8 & (RTC_REG_B_PIE_BIT | RTC_REG_B_AIE_BIT | RTC_REG_B_UEIE_BIT))
    n_sys_error (Dosx_krnl_rtc_conflict);

/*---------------------------------------------------------------------------
  setup real and protected mode interrupt vectors
---------------------------------------------------------------------------*/
  _go32_dpmi_set_real_mode_interrupt_vector (RTC_INT_TYPE, &rm_si);
  _go32_dpmi_set_protected_mode_interrupt_vector (RTC_INT_TYPE, &pm_si);

  outpb (RTC_ADDR_PORT, RTC_STATUS_REG_B);
  outpb (RTC_DATA_PORT, temp8 | RTC_REG_B_PIE_BIT);
  outpb (0xa1, (inpb (0xa1) & 0xfe));

  enable();
}

==============================================================
Hung Bui                            Internet: h DOT bui AT ieee DOT org
Netrix Corporation                    Phone: +1 703 793 1016
13595 Dulles Technology Drive           Fax: +1 703 713 3805
Herndon Va 22071
==============================================================

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019