_C PROGRAMMING COLUMN_ by Al Stevens [LISTING ONE] /* --------- tsr.c --------- */ /* * A Terminate and Stay Resident (TSR) engine */ #include #include #include #include "mouse.h" #include "keys.h" void tsr_program(void); #define KEYMASK 8 #define SCANCODE 52 extern unsigned _stklen = 1024; extern unsigned _heaplen = 8192; /* ------- the interrupt function registers -------- */ typedef struct { int bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,fl; } IREGS; /* --- vectors ---- */ #define DISK 0x13 #define CTRLBRK 0x1b #define INT28 0x28 #define CRIT 0x24 #define CTRLC 0x23 #define TIMER 8 #define KYBRD 9 #define DOS 0x21 unsigned highmemory; /* ------ interrupt vector chains ------ */ static void (interrupt *oldtimer)(void); static void (interrupt *old28)(void); static void (interrupt *oldkb)(void); static void (interrupt *olddisk)(void); /* ------ ISRs for the TSR ------- */ static void interrupt newtimer(void); static void interrupt new28(void); static void interrupt newdisk(IREGS); static void interrupt newkb(void); static void interrupt newcrit(IREGS); static void interrupt newbreak(void); static unsigned sizeprogram; /* TSR's program size */ unsigned dossegmnt; /* DOS segment address */ unsigned dosbusy; /* offset to InDOS flag */ static int diskflag; /* Disk BIOS busy flag */ unsigned mcbseg; /* address of 1st DOS mcb */ static char far *mydta; /* TSR's DTA */ int hotkeyhit = FALSE; int tsrss; /* TSR's stack segment */ int tsrsp; /* TSR's stack pointer */ /* -------------- context for the popup ---------------- */ unsigned intpsp; /* Interrupted PSP address */ int running; /* TSR running indicator */ char far *intdta; /* interrupted DTA */ unsigned intsp; /* " stack pointer */ unsigned intss; /* " stack segment */ unsigned ctrl_break; /* Ctrl-Break setting */ void (interrupt *oldcrit)(void); void (interrupt *oldbreak)(void); void (interrupt *oldctrlc)(void); /* ------- local prototypes -------- */ static void resident_psp(void); static void interrupted_psp(void); static void popup(void); void main(void) { unsigned es, bx; /* ---------- compute memory parameters ------------ */ highmemory = _SS + ((_SP + 256) / 16); /* ------ get address of DOS busy flag ---- */ _AH = 0x34; geninterrupt(DOS); dossegmnt = _ES; dosbusy = _BX; /* ---- get the seg addr of 1st DOS MCB ---- */ _AH = 0x52; geninterrupt(DOS); es = _ES; bx = _BX; mcbseg = peek(es, bx-2); /* ----- get address of resident program's dta ----- */ mydta = getdta(); /* ------------ prepare for residence ------------ */ tsrss = _SS; tsrsp = _SP; oldtimer = getvect(TIMER); old28 = getvect(INT28); oldkb = getvect(KYBRD); olddisk = getvect(DISK); /* ----- attach vectors to resident program ----- */ setvect(KYBRD, newkb); setvect(INT28, new28); setvect(DISK, newdisk); setvect(TIMER, newtimer); /* ------ compute program size ------- */ sizeprogram = highmemory - _psp + 1; /* ----- terminate and stay resident ------- */ _DX = sizeprogram; _AX = 0x3100; geninterrupt(DOS); } /* ---------- break handler ------------ */ static void interrupt newbreak(void) { return; } /* -------- critical error ISR ---------- */ static void interrupt newcrit(IREGS ir) { ir.ax = 0; /* ignore critical errors */ } /* ------ BIOS disk functions ISR ------- */ static void interrupt newdisk(IREGS ir) { diskflag++; (*olddisk)(); ir.ax = _AX; /* for the register returns */ ir.cx = _CX; ir.dx = _DX; ir.es = _ES; ir.di = _DI; ir.fl = _FLAGS; --diskflag; } /* ----- keyboard ISR ------ */ static void interrupt newkb(void) { static unsigned char kbval; kbval = inportb(0x60); if (!hotkeyhit && !running) if ((peekb(0, 0x417) & 0xf) == KEYMASK) if (SCANCODE == kbval) { hotkeyhit = TRUE; /* --- reset the keyboard ---- */ kbval = inportb(0x61); outportb(0x61, kbval | 0x80); outportb(0x61, kbval); outportb(0x20, 0x20); return; } (*oldkb)(); } /* ----- timer ISR ------- */ static void interrupt newtimer(void) { (*oldtimer)(); if (hotkeyhit && (peekb(dossegmnt, dosbusy) == 0) && !diskflag) popup(); } /* ----- 0x28 ISR -------- */ static void interrupt new28(void) { (*old28)(); if (hotkeyhit) popup(); } /* ------ switch psp context from interrupted to TSR ----- */ static void resident_psp(void) { intpsp = getpsp(); _AH = 0x50; _BX = _psp; geninterrupt(DOS); } /* ---- switch psp context from TSR to interrupted ---- */ static void interrupted_psp(void) { _BX = intpsp; _AH = 0x50; geninterrupt(DOS); } /* ------ execute the resident program ------- */ static void popup(void) { running = TRUE; hotkeyhit = FALSE; intsp = _SP; intss = _SS; _SP = tsrsp; _SS = tsrss; oldcrit = getvect(CRIT); /* redirect critical err */ oldbreak = getvect(CTRLBRK); oldctrlc = getvect(CTRLC); setvect(CRIT, newcrit); setvect(CTRLBRK, newbreak); setvect(CTRLC, newbreak); ctrl_break = getcbrk(); /* get ctrl break setting */ setcbrk(0); /* turn off ctrl break */ intdta = getdta(); /* get interrupted dta */ setdta(mydta); /* set resident dta */ resident_psp(); /* swap psps */ intercept_mouse(); /* intercept the mouse */ /* ------ save the video cursor configuration ------- */ savecursor(); normalcursor(); unhidecursor(); enable(); tsr_program(); /* call the TSR C program */ disable(); /* ----- restore the video cursor configuration ----- */ restorecursor(); restore_mouse(); /* restore the mouse */ interrupted_psp(); /* reset interrupted psp */ setdta(intdta); /* reset interrupted dta */ setvect(CRIT, oldcrit); /* reset critical error */ setvect(CTRLBRK, oldbreak); setvect(CTRLC, oldctrlc); setcbrk(ctrl_break); /* reset ctrl break */ disable(); _SP = intsp; /* reset interrupted stack*/ _SS = intss; running = FALSE; /* reset semaphore */ }