delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1997/01/29/18:00:01

Message-ID: <32EFD178.316@texoma.com>
Date: Wed, 29 Jan 1997 16:40:02 -0600
From: Mark Teel <mteel AT dtechs DOT com>
MIME-Version: 1.0
To: johne AT parallax DOT co DOT uk
CC: djgpp AT delorie DOT com
Subject: Re: Hooking int 0x70 (IRQ8)

This is a multi-part message in MIME format.

--------------22C7C356429
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

John:

Attached is my timerIsr subsystem built using Watcom 10.6 (I haven't
ported it to djgpp yet).  It has a preprocessor directive for "C_386"
that if defined, is the code for a bi-modal approach to the RTC (i.e.,
real and protected mode handlers) - if not defined, it is the code for a
real-mode only treatment of the RTC.  I would think that this would be
relatively easy to port to djgpp (the bi-modal approach may not be
necessary).

Hope this helps...

Mark

--------------22C7C356429
Content-Type: text/plain; charset=us-ascii; name="Timerisr.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="Timerisr.c"

/* ---------------------------------------------------------------------------
 *
 *      FILENAME
 *      timerIsr.c
 *
 *      DESCRIPTION
 *      Provide timer ISR hook for timer subsystem.
 *
 *      MODIFICATION HISTORY
 *      DATE            ENGINEER                REVISION        COMMENTS
 *      5/25/95         M.S. Teel               0               Original
 *      1/5/96          M.S. Teel               0               Added 286/386
 *                                                              support.
 *
 *      ROUTINES INCLUDED
 *      int                     timerIsrInit (void)
 *      static void interrupt   systemRtcIsr (void)
 *      void                    timerIsrExit (void)
 *      unsigned long           getSystemTick (void)
 *
 * --------------------------------------------------------------------------
*/

/*      ... OS include files
*/
#include <stdio.h>
#include <dos.h>
#include <conio.h>
#include <i86.h>
#include <string.h>

/*      ... System include files
*/
#include <dtiDefs.h>
#include <event.h>
#include <video.h>

/*      ... Library include files
*/

/*      ... Local include files
*/


/*      ... global memory declarations
*/

/*      ... global memory referenced
*/

/*      ... static (local) memory declarations
*/
#define RTC_VECTOR              0x70
#define PERIODIC_INT_BIT        0x40
#define UPDATE_INT_BIT          0x10

#ifdef C_386

static short                    oldProtectedSegment;
static unsigned int             oldProtectedOffset;
static unsigned int             oldRealSegment;
static unsigned int             oldRealOffset;
static void interrupt           systemRtcIsr (void);
static unsigned short           lastMilliSecondTime;
static unsigned long            systemTick;
extern void __interrupt __far   realRtcIsr (void);
extern unsigned short __far     interruptCount;

extern void timerIsrExit
    (
    void
    );

#define D32RealSeg(P)           ((((DWORD) (P)) >> 4) & 0xFFFF)
#define D32RealOff(P)           (((DWORD) (P)) & 0xF)

typedef unsigned int WORD;
typedef unsigned long DWORD;


static void *realMemAlloc
    (
    DWORD       size
    )
    {
    union REGS  r;

    r.x.eax = 0x0100;              /* DPMI allocate DOS memory */
    r.x.ebx = (size + 15) >> 4;    /* Number of paragraphs requested */
    int386 (0x31, &r, &r);

    if (r.x.cflag)
        return ((DWORD) 0);        /* Failed */
    return (void *) ((r.x.eax & 0xFFFF) << 4);
    }


/* ---------------------------------------------------------------------------------
 *
 *
    FUNCTION: int timerIsrInit (void)
 *
 *  DESCRIPTION: Save old handler and install ours.
 *
 *  ASSUMPTIONS
 *  None.
 * ---------------------------------------------------------------------------------
*/
static void startTimerIsr
    (
    EVENT_ID            eventToFree
    )
    {
    union REGS          r;
    unsigned char       x;
    void                *lowp;


    eventDelete (eventToFree);


/*  ... Save the starting real-mode and protected-mode handler addresses
*/
    r.x.eax = 0x0204;            /* DPMI get protected mode vector */
    r.h.bl = RTC_VECTOR;
    int386 (0x31, &r, &r);
    oldProtectedSegment = (WORD) r.x.ecx;
    oldProtectedOffset = r.x.edx;

    r.x.eax = 0x0200;            /* DPMI get real mode vector */
    r.h.bl = RTC_VECTOR;
    int386 (0x31, &r, &r);
    oldRealSegment = (WORD) r.x.ecx;
    oldRealOffset = (WORD) r.x.edx;


/*  ... Allocate 128 bytes of DOS memory for the real-mode handler,
    ... which must of course be less than 128 bytes long.  Then copy
    ... the real-mode handler into that segment.
*/
    if (!(lowp = realMemAlloc (128)))
        {
        generateMessage ("Couldn't get low memory!", TRUE, TRUE);
        return;
        }

    _fmemcpy ((void __far *) lowp, (void __far *) realRtcIsr, 128);


/*  ... Install the new handlers.  The memory touched by the protected mode
    ... handler needs to be locked, in case we are running under VMM
    ... or an external DPMI host.
*/
    r.x.eax = 0x0205;             /* DPMI set protected mode vector */
    r.x.ebx = (DWORD) RTC_VECTOR;
    r.x.ecx = (DWORD) FP_SEG(systemRtcIsr);
    r.x.edx = FP_OFF(systemRtcIsr);
    int386 (0x31, &r, &r);

    r.x.eax = 0x0600;             /* DPMI lock linear region */
    r.x.ebx = ((DWORD) systemRtcIsr) >> 16;
    r.x.ecx = ((DWORD) systemRtcIsr) & 0xFFFF;
    r.x.esi = 0;
    r.x.edi = 256;                /* lock 256 bytes */
    int386 (0x31, &r, &r);

    r.x.eax = 0x0201;             /* DPMI set real mode vector */
    r.x.ebx = (DWORD) RTC_VECTOR;
    r.x.ecx = D32RealSeg(lowp);   /* CX:DX == real mode &handler */
    r.x.edx = D32RealOff(lowp);
    int386 (0x31, &r, &r);


/*  ... now let's enable IRQ 8 (RTC)
*/
    interruptDisable ();

    outp (0x70,0x0C);               /* access Register C */
    inp (0x71);                     /* read Register C */

    outp (0xA0,0x60);

    x = inp (0xA1);                 /* read IMR */
    x &= 0xFE;                      /* clear enable IRQ0 */
    outp (0xA1,x);

    outp (0xA0,0x60);

    outp (0x70,0x0a);               /* access register C */

    if (!(inp (0x71) & 0x80))       /* is IRQ Flag set ? */
        {
        outp (0x70,0x0C);           /* access Register C */
        inp (0x71);                 /* read/clear IRQ Flag */
        outp (0x70,0x0b);           /* access Register B */
        x = inp (0x71);             /* clear interrupt */
        x |= PERIODIC_INT_BIT;      /* turn on the PIE bit */
        x &= ~UPDATE_INT_BIT;       /* turn off update interrupt */
        outp (0x70,0x0b);           /* access register B */
        outp (0x71,x);              /* set the PIE bit */
        }

    interruptEnable();

    return;
    }

/* -----------------------------------------------------------------------------
 *
 *
 *  FUNCTION: static void interrupt systemRtcIsr (void)
 *
 *  DESCRIPTION: Our RTC ISR.
 *
 *  ASSUMPTIONS
 *  None.
 * ------------------------------------------------------------------------------
*/
static void interrupt systemRtcIsr
    (
    void
    )
    {
    unsigned short      milliSeconds;


/*  ... normalize 976 us to 1 ms
*/
    milliSeconds = (++interruptCount * 125) >> 7;


/*  ... update it
*/
    if (milliSeconds != lastMilliSecondTime)
        {
        systemTick ++;
        lastMilliSecondTime = milliSeconds;
        }


/*  ... reset the interrupt for the next time
*/
    outp (0x70,0x0C);       /* access Register C */
    inp (0x71);             /* clear interrupt */
    outp (0xA0,0x20);       /* send end-of-INT signal to slave 8259 */
    outp (0x20,0x20);       /* send end-of-INT signal to master 8259 */

    return;
    }


/* ---------------------------------------------------------------------------------
 *
 *
    FUNCTION: void timerIsrExit (void)
 *
 *  DESCRIPTION: Reset RTC ISR to old vector contents.
 *
 *  ASSUMPTIONS
 *  None.
 * ---------------------------------------------------------------------------------
*/
void timerIsrExit
    (
    void
    )
    {
    union REGS      regs;
    struct SREGS    srii;


    segread (&srii);


/*  ...set the real mode RTC interrupt
*/
    regs.w.ax = 0x0201;
    regs.h.bl = RTC_VECTOR;
    regs.w.cx = oldRealSegment;
    regs.w.dx = oldRealOffset;
    int386x(0x31,&regs,&regs,&srii);


/*  ...Restore the protected mode ISR
*/
    regs.w.ax   = 0x0205;
    regs.h.bl   = RTC_VECTOR;
    regs.w.cx = oldProtectedSegment;
    regs.x.edx = oldProtectedOffset;
    int386x(0x31,&regs,&regs,&srii);

    return;
    }

#else       /* ifdef C_386 */


typedef void interrupt far      (*INTRPTR)(void);
static void interrupt far       (*originalIsr)(void);
static unsigned short           interruptCount;
static unsigned short           lastMilliSecondTime;
static unsigned long            systemTick;

extern void timerIsrExit
    (
    void
    );


static void far *getvect
    (
    unsigned char       intNo
    )
    {
    union REGS          r;
    struct SREGS        s;
    void far            *retPtr;

    segread (&s);
    r.h.ah = 0x35;
    r.h.al = intNo;

    int86x (0x21, &r, &r, &s);

    retPtr = (void far *)MK_FP(s.es,r.w.bx);

    return retPtr;
    }

static void setvect
    (
    unsigned char       intNo,
    void far            *handler
    )
    {
    union REGS          r;
    struct SREGS        s;


    memset (&s, 0, sizeof (struct SREGS));
    r.h.ah = 0x25;
    r.h.al = intNo;
    s.ds = FP_SEG((INTRPTR)(handler));
    r.w.dx = FP_OFF((INTRPTR)(handler));

    int86x (0x21, &r, &r, &s);
    return;
    }


/* ---------------------------------------------------------------------------------
 *
 *
    FUNCTION: static void interrupt systemRtcIsr (void)
 *
 *  DESCRIPTION: Our RTC ISR.
 *
 *  ASSUMPTIONS
 *  None.
 * ---------------------------------------------------------------------------------
*/

void interrupt far systemRtcIsr
    (
    void
    )
    {
    unsigned short      milliSecondTime;


/*  ... normalize 976 us to 1 ms
*/
    milliSecondTime = (++interruptCount * 125) >> 7;


/*  ... If a millisecond has changed update it
*/
    if (milliSecondTime != lastMilliSecondTime)
        {
        systemTick += 1;
        lastMilliSecondTime = milliSecondTime;
        }


/*  ... reset the interrupt for the next time
*/
    outp (0x70,0x0C);               /* access Register C */
    inp (0x71);                     /* clear interrupt */
    outp (0xA0,0x20);               /* send end-of-INT signal to slave 8259 */
    outp (0x20,0x20);               /* send end-of-INT signal to master 8259 */


/*  ... call the "real" handler

    (*originalIsr) ();
*/

    return;
    }


void systemRtcIsrTemp
    (
    void
    )
    {
    unsigned char       x;


    interruptDisable ();

    outp (0x70,0x0C);               /* access Register C */
    inp (0x71);                     /* read Register C */

    outp (0xA0,0x60);

    x = inp (0xA1);                 /* read IMR */
    x &= 0xFE;                      /* clear enable IRQ0 */
    outp (0xA1,x);

    outp (0xA0,0x60);

    outp (0x70,0x0a);               /* access register A */

    if (!(inp (0x71) & 0x80))       /* is IRQ Flag set ? */
        {
        outp (0x70,0x0C);           /* access Register C */
        inp (0x71);                 /* read/clear IRQ Flag */
        outp (0x70,0x0b);           /* access Register B */
        x = inp (0x71);             /* clear interrupt */
        x |= PERIODIC_INT_BIT;      /* turn on the PIE bit */
        x &= ~UPDATE_INT_BIT;       /* turn off update interrupt */
        outp (0x70,0x0b);           /* access register B */
        outp (0x71,x);              /* set the PIE bit */
        }

    interruptEnable ();
    return;
    }


/* ---------------------------------------------------------------------------------
 *
 *
    FUNCTION: void startTimerIsr (void)
 *
 *  DESCRIPTION: Save old handler and install ours.
 *
 *  ASSUMPTIONS
 *  None.
 * ---------------------------------------------------------------------------------
*/
static void startTimerIsr
    (
    EVENT_ID            eventToFree
    )
    {
    unsigned char       x;
    void far            *tempIsr;


    eventDelete (generalEventList, eventToFree);

    tempIsr = getvect (RTC_VECTOR);

    if (tempIsr == systemRtcIsr)
        {
/*      ... we have already installed it!
*/
        return;
        }
    else
        originalIsr = tempIsr;

    systemTick = 0L;
    interruptCount = 0;

    setvect (RTC_VECTOR, systemRtcIsr);

/*  ... now let's enable IRQ 8 (RTC)
*/
    interruptDisable ();

    outp (0x70,0x0C);               /* access Register C */
    inp (0x71);                     /* read Register C */

    outp (0xA0,0x60);

    x = inp (0xA1);                 /* read IMR */
    x &= 0xFE;                      /* clear enable IRQ0 */
    outp (0xA1,x);

    outp (0xA0,0x60);

    outp (0x70,0x0a);               /* access register A */

    if (!(inp (0x71) & 0x80))       /* is IRQ Flag set ? */
        {
        outp (0x70,0x0C);           /* access Register C */
        inp (0x71);                 /* read/clear IRQ Flag */
        outp (0x70,0x0b);           /* access Register B */
        x = inp (0x71);             /* clear interrupt */
        x |= PERIODIC_INT_BIT;      /* turn on the PIE bit */
        x &= ~UPDATE_INT_BIT;       /* turn off update interrupt */
        outp (0x70,0x0b);           /* access register B */
        outp (0x71,x);              /* set the PIE bit */
        }

    interruptEnable ();
    return;
    }


/* ---------------------------------------------------------------------------------
 *
 *
    FUNCTION: void timerIsrExit (void)
 *
 *  DESCRIPTION: Reset RTC ISR to old vector contents.
 *
 *  ASSUMPTIONS
 *  None.
 * ---------------------------------------------------------------------------------
*/
void timerIsrExit
    (
    void
    )
    {
    setvect (RTC_VECTOR, originalIsr);

    return;
    }

#endif          /* ifdef C_386 */



/*  ...Now do the timer interrupt initialization
*/
int timerIsrInit()
    {
    EVENT_ID    eventId;


/*  ... Now initialize the system tick and interruptCount
*/
    systemTick = 0;
    interruptCount = 0;

    if ((eventId =
            eventCreate (generalEventList, NULL, startTimerIsr, 0)) == NULL)
        return ERROR;

/*  ... give him the eventId as his parameter
*/
    eventCreate (generalEventList, eventId, startTimerIsr, eventId);
    eventRaise (generalEventList, eventId);
    return OK;
    }


/* ---------------------------------------------------------------------------------
 *
 *
    FUNCTION: unsigned long getSystemTick (void)
 *
 *  DESCRIPTION: Return current value of system tick counter.
 *
 *  ASSUMPTIONS
 *  None.
 * ---------------------------------------------------------------------------------
*/
unsigned long getSystemTick
    (
    void
    )
    {
    return systemTick;
    }
--------------22C7C356429--

- Raw text -


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