Message-ID: <32EFD178.316@texoma.com> Date: Wed, 29 Jan 1997 16:40:02 -0600 From: Mark Teel MIME-Version: 1.0 To: johne AT parallax DOT co DOT uk CC: djgpp AT delorie DOT com Subject: Re: Hooking int 0x70 (IRQ8) Content-Type: multipart/mixed; boundary="------------22C7C356429" 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 #include #include #include #include /* ... System include files */ #include #include #include /* ... 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,®s,®s,&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,®s,®s,&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--