326 lines
7.0 KiB
C
326 lines
7.0 KiB
C
|
/*
|
||
|
Copyright (C) 1994-1995 Apogee Software, Ltd.
|
||
|
|
||
|
This program is free software; you can redistribute it and/or
|
||
|
modify it under the terms of the GNU General Public License
|
||
|
as published by the Free Software Foundation; either version 2
|
||
|
of the License, or (at your option) any later version.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||
|
|
||
|
See the GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with this program; if not, write to the Free Software
|
||
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||
|
|
||
|
*/
|
||
|
/**********************************************************************
|
||
|
module: IRQ.C
|
||
|
|
||
|
author: James R. Dose
|
||
|
date: August 26, 1994
|
||
|
|
||
|
Low level routines to set and restore IRQ's through DPMI.
|
||
|
|
||
|
(c) Copyright 1994 James R. Dose. All Rights Reserved.
|
||
|
**********************************************************************/
|
||
|
|
||
|
#include <dos.h>
|
||
|
#include <stdlib.h>
|
||
|
#include "irq.h"
|
||
|
|
||
|
#define D32RealSeg(P) ( ( ( ( unsigned long )( P ) ) >> 4 ) & 0xFFFF )
|
||
|
#define D32RealOff(P) ( ( ( unsigned long )( P ) ) & 0xF )
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
unsigned long drdi;
|
||
|
unsigned long drsi;
|
||
|
unsigned long drbp;
|
||
|
unsigned long drxx;
|
||
|
unsigned long drbx;
|
||
|
unsigned long drdx;
|
||
|
unsigned long drcx;
|
||
|
unsigned long drax;
|
||
|
|
||
|
unsigned short drflags;
|
||
|
unsigned short dres;
|
||
|
unsigned short drds;
|
||
|
unsigned short drfs;
|
||
|
unsigned short drgs;
|
||
|
unsigned short drip;
|
||
|
unsigned short drcs;
|
||
|
unsigned short drsp;
|
||
|
unsigned short drss;
|
||
|
} DPMI_REGS;
|
||
|
|
||
|
static DPMI_REGS rmregs = { 0 };
|
||
|
static void ( __interrupt __far *IRQ_Callback )( void ) = NULL;
|
||
|
|
||
|
static char *IRQ_RealModeCode = NULL;
|
||
|
|
||
|
static unsigned short IRQ_CallBackSegment;
|
||
|
static unsigned short IRQ_CallBackOffset;
|
||
|
static unsigned short IRQ_RealModeSegment;
|
||
|
static unsigned short IRQ_RealModeOffset;
|
||
|
static unsigned long IRQ_ProtectedModeOffset;
|
||
|
static unsigned short IRQ_ProtectedModeSelector;
|
||
|
|
||
|
static union REGS Regs;
|
||
|
static struct SREGS SegRegs;
|
||
|
|
||
|
static void *D32DosMemAlloc
|
||
|
(
|
||
|
unsigned long size
|
||
|
)
|
||
|
|
||
|
{
|
||
|
// DPMI allocate DOS memory
|
||
|
Regs.x.eax = 0x0100;
|
||
|
|
||
|
// Number of paragraphs requested
|
||
|
Regs.x.ebx = ( size + 15 ) >> 4;
|
||
|
|
||
|
int386( 0x31, &Regs, &Regs );
|
||
|
|
||
|
if ( Regs.x.cflag != 0 )
|
||
|
{
|
||
|
// Failed
|
||
|
return ( ( unsigned long )0 );
|
||
|
}
|
||
|
|
||
|
return( ( void * )( ( Regs.x.eax & 0xFFFF ) << 4 ) );
|
||
|
}
|
||
|
|
||
|
// Intermediary function: DPMI calls this, making it
|
||
|
// easier to write in C
|
||
|
// handle 16-bit incoming stack
|
||
|
|
||
|
void fixebp
|
||
|
(
|
||
|
void
|
||
|
);
|
||
|
|
||
|
#pragma aux fixebp = \
|
||
|
"mov bx, ss" \
|
||
|
"lar ebx, ebx" \
|
||
|
"bt ebx, 22" \
|
||
|
"jc bigstk" \
|
||
|
"movzx esp, sp" \
|
||
|
"mov ebp, esp" \
|
||
|
"bigstk:" \
|
||
|
modify exact [ ebx ];
|
||
|
|
||
|
#pragma aux rmcallback parm [];
|
||
|
|
||
|
void rmcallback
|
||
|
(
|
||
|
unsigned short _far *stkp
|
||
|
)
|
||
|
|
||
|
{
|
||
|
// "Pop" the real mode return frame so we
|
||
|
// can resume where we left off
|
||
|
rmregs.drip = *stkp++;
|
||
|
rmregs.drcs = *stkp++;
|
||
|
|
||
|
rmregs.drsp = FP_OFF(stkp);
|
||
|
|
||
|
// Call protected-mode handler
|
||
|
IRQ_Callback();
|
||
|
}
|
||
|
|
||
|
static void _interrupt _cdecl callback_x
|
||
|
(
|
||
|
// regs pushed in this order by prologue
|
||
|
|
||
|
int rgs,
|
||
|
int rfs,
|
||
|
int res,
|
||
|
int rds,
|
||
|
int rdi,
|
||
|
int rsi,
|
||
|
int rbp,
|
||
|
int rsp,
|
||
|
int rbx,
|
||
|
int rdx,
|
||
|
int rcx,
|
||
|
int rax
|
||
|
)
|
||
|
|
||
|
{
|
||
|
// unsigned short _far *stkp;
|
||
|
// return;
|
||
|
|
||
|
fixebp();
|
||
|
rmcallback (MK_FP(rds, rsi));
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
static void _interrupt _cdecl callback_x
|
||
|
(
|
||
|
// regs pushed in this order by prologue
|
||
|
|
||
|
int rgs,
|
||
|
int rfs,
|
||
|
int res,
|
||
|
int rds,
|
||
|
int rdi,
|
||
|
int rsi,
|
||
|
int rbp,
|
||
|
int rsp,
|
||
|
int rbx,
|
||
|
int rdx,
|
||
|
int rcx,
|
||
|
int rax
|
||
|
)
|
||
|
|
||
|
{
|
||
|
unsigned short _far *stkp;
|
||
|
|
||
|
fixebp();
|
||
|
stkp = MK_FP(rds, rsi);
|
||
|
|
||
|
// "Pop" the real mode return frame so we
|
||
|
// can resume where we left off
|
||
|
rmregs.drip = *stkp++;
|
||
|
rmregs.drcs = *stkp++;
|
||
|
|
||
|
rmregs.drsp = FP_OFF(stkp);
|
||
|
|
||
|
// Call protected-mode handler
|
||
|
IRQ_Callback();
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
|
||
|
int IRQ_SetVector
|
||
|
(
|
||
|
int vector,
|
||
|
void ( __interrupt __far *function )( void )
|
||
|
)
|
||
|
|
||
|
{
|
||
|
void far *fp;
|
||
|
|
||
|
IRQ_Callback = function;
|
||
|
|
||
|
// Save the starting real-mode and protected-mode handler addresses
|
||
|
|
||
|
// DPMI get protected mode vector */
|
||
|
Regs.w.ax = 0x0204;
|
||
|
Regs.w.bx = vector;
|
||
|
int386( 0x31, &Regs, &Regs );
|
||
|
IRQ_ProtectedModeSelector = Regs.w.cx;
|
||
|
IRQ_ProtectedModeOffset = Regs.x.edx;
|
||
|
|
||
|
// DPMI get real mode vector
|
||
|
Regs.w.ax = 0x0200;
|
||
|
Regs.w.bx = vector;
|
||
|
int386( 0x31, &Regs, &Regs );
|
||
|
IRQ_RealModeSegment = Regs.w.cx;
|
||
|
IRQ_RealModeOffset = Regs.w.dx;
|
||
|
|
||
|
// Set up callback
|
||
|
// DPMI allocate real mode callback
|
||
|
Regs.w.ax = 0x0303;
|
||
|
fp = ( void far * )callback_x;
|
||
|
SegRegs.ds = FP_SEG( fp );
|
||
|
Regs.x.esi = FP_OFF( fp );
|
||
|
fp = ( void _far * )&rmregs;
|
||
|
SegRegs.es = FP_SEG( fp );
|
||
|
Regs.x.edi = FP_OFF( fp );
|
||
|
int386x( 0x31, &Regs, &Regs, &SegRegs );
|
||
|
|
||
|
IRQ_CallBackSegment = Regs.w.cx;
|
||
|
IRQ_CallBackOffset = Regs.w.dx;
|
||
|
|
||
|
if ( Regs.x.cflag != 0 )
|
||
|
{
|
||
|
return( IRQ_Error );
|
||
|
}
|
||
|
|
||
|
if ( IRQ_RealModeCode == NULL )
|
||
|
{
|
||
|
// Allocate 6 bytes of low memory for real mode interrupt handler
|
||
|
IRQ_RealModeCode = D32DosMemAlloc( 6 );
|
||
|
if ( IRQ_RealModeCode == NULL )
|
||
|
{
|
||
|
// Free callback
|
||
|
Regs.w.ax = 0x304;
|
||
|
Regs.w.cx = IRQ_CallBackSegment;
|
||
|
Regs.w.dx = IRQ_CallBackOffset;
|
||
|
int386x( 0x31, &Regs, &Regs, &SegRegs );
|
||
|
|
||
|
return( IRQ_Error );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Poke code (to call callback) into real mode handler
|
||
|
|
||
|
// CALL FAR PTR (callback)
|
||
|
IRQ_RealModeCode[ 0 ] = '\x9A';
|
||
|
*( ( unsigned short * )&IRQ_RealModeCode[ 1 ] ) = IRQ_CallBackOffset;
|
||
|
*( ( unsigned short * )&IRQ_RealModeCode[ 3 ] ) = IRQ_CallBackSegment;
|
||
|
|
||
|
// IRET
|
||
|
IRQ_RealModeCode[ 5 ] = '\xCF';
|
||
|
|
||
|
// Install protected mode handler
|
||
|
// DPMI set protected mode vector
|
||
|
Regs.w.ax = 0x0205;
|
||
|
Regs.w.bx = vector;
|
||
|
fp = function;
|
||
|
|
||
|
Regs.w.cx = FP_SEG( fp );
|
||
|
Regs.x.edx = FP_OFF( fp );
|
||
|
int386( 0x31, &Regs, &Regs );
|
||
|
|
||
|
// Install callback address as real mode handler
|
||
|
// DPMI set real mode vector
|
||
|
Regs.w.ax = 0x0201;
|
||
|
Regs.w.bx = vector;
|
||
|
Regs.w.cx = D32RealSeg( IRQ_RealModeCode );
|
||
|
Regs.w.dx = D32RealOff( IRQ_RealModeCode );
|
||
|
int386( 0x31, &Regs, &Regs );
|
||
|
|
||
|
return( IRQ_Ok );
|
||
|
}
|
||
|
|
||
|
int IRQ_RestoreVector
|
||
|
(
|
||
|
int vector
|
||
|
)
|
||
|
|
||
|
{
|
||
|
// Restore original interrupt handlers
|
||
|
// DPMI set real mode vector
|
||
|
Regs.w.ax = 0x0201;
|
||
|
Regs.w.bx = vector;
|
||
|
Regs.w.cx = IRQ_RealModeSegment;
|
||
|
Regs.w.dx = IRQ_RealModeOffset;
|
||
|
int386( 0x31, &Regs, &Regs );
|
||
|
|
||
|
Regs.w.ax = 0x0205;
|
||
|
Regs.w.bx = vector;
|
||
|
Regs.w.cx = IRQ_ProtectedModeSelector;
|
||
|
Regs.x.edx = IRQ_ProtectedModeOffset;
|
||
|
int386( 0x31, &Regs, &Regs );
|
||
|
|
||
|
// Free callback
|
||
|
Regs.w.ax = 0x304;
|
||
|
Regs.w.cx = IRQ_CallBackSegment;
|
||
|
Regs.w.dx = IRQ_CallBackOffset;
|
||
|
int386x( 0x31, &Regs, &Regs, &SegRegs );
|
||
|
|
||
|
if ( Regs.x.cflag )
|
||
|
{
|
||
|
return( IRQ_Error );
|
||
|
}
|
||
|
|
||
|
return( IRQ_Ok );
|
||
|
}
|