home *** CD-ROM | disk | FTP | other *** search
- Terminate and Stay Resident Programs by Al Stevens
-
- /* -------- Listing 1 - tsr.h --------- */
-
- void resinit(void);
- void resident_psp(void);
- void interrupted_psp(void);
- unsigned resident(char *,void interrupt (*)());
- void terminate(void);
- void restart(void);
- void suspend(void);
- int get_char(void);
- void popup(void);
- void openfiles(void);
- void closefiles(void);
-
- /* ---------- Listing 2 - tsr.c ---------- */
-
- #include <dos.h>
- #include <stdio.h>
- #include <string.h>
- #include <dir.h>
- #include "tsr.h"
-
- static union REGS rg;
-
- /* -------- modify for the specific TSR ------------ */
- unsigned sizeprogram = 9000/16; /* TSR SIZE (PARAGRAPHS) */
- unsigned scancode = 52; /* HOT KEY SCAN CODE */
- unsigned keymask = 8; /* HOT KEY STATUS MASK */
- char signature [] = "CLOCK"; /* TSR SIGNATURE */
-
- static void interrupt ifunc();
-
- /* --------- main function for the TSR program ------- */
- main(argc, argv)
- char *argv[];
- {
- int ivec;
-
- if ((ivec = resident(signature, ifunc)) != 0) {
- /* ----- TSR is resident ------- */
- if (argc > 1) {
- /* ---- there is a command line parameter --- */
- rg.x.ax = 0;
- if (strcmp(argv[1], "quit") == 0)
- rg.x.ax = 1;
- else if (strcmp(argv[1], "restart") == 0)
- rg.x.ax = 2;
- else if (strcmp(argv[1], "wait") == 0)
- rg.x.ax = 3;
- if (rg.x.ax) {
- /* -- call the communications interrupt -- */
- int86(ivec, &rg, &rg);
- return;è }
- }
- printf("\nClock is already resident");
- }
- else {
- /* ------ initial load of TSR program ------ */
- printf("\nResident clock is loaded");
- openfiles();
- resinit();
- }
- }
-
- /* -------- TSR communications ISR ---------- */
- void interrupt ifunc(bp,di,si,ds,es,dx,cx,bx,ax)
- {
- if (ax == 1) /* "quit" */
- terminate();
- else if (ax == 2) /* "restart" */
- restart();
- else if (ax == 3) /* "wait" */
- suspend();
- }
-
- /* -------- Listing 3 - resident.c --------- */
-
- #include <dos.h>
- #include <stdio.h>
- #include "tsr.h"
-
- /* --- vectors ---- */
- #define KEYBD 9
- #define TIMER 0x1c
- #define DISK 0x13
- #define VIDEO 0x10
- #define ZERODIV 0
- #define INT28 0x28
- #define CRIT 0x24
-
- /* ------ interrupt vector chains ------ */
- static void interrupt (*oldtimer)();
- static void interrupt (*old28)();
- static void interrupt (*oldkb)();
- static void interrupt (*olddisk)();
- static void interrupt (*oldvideo)();
- static void interrupt (*oldcrit)();
- extern void interrupt (*ZeroDivVector)();
- /* ------ ISRs for the TSR ------- */
- static void interrupt newtimer();
- static void interrupt new28();
- static void interrupt newkb();
- static void interrupt newdisk();
- static void interrupt newvideo();
- static void interrupt newcrit();
- /* ------ registers for int86 & dos86 ------- */
- static union REGS rg;èstatic struct SREGS seg;
-
- static unsigned dosseg; /* DOS segment address */
- static unsigned dosbusy; /* offset to InDOS flag */
- static char far *mydta; /* TSR's DTA */
- static unsigned myss; /* TSR's stack segment */
- static unsigned stack; /* TSR's stack pointer */
- static unsigned mypsp; /* TSR's PSP address */
- static unsigned intpsp; /* Interrupted PSP address */
- static unsigned psps[2]; /* Table of DOS PSP addresses */
- static int pspctr; /* # of DOS PSP addresses */
- static int resoff; /* suspend/resume flag */
- static int running; /* TSR running indicator */
- static int popflg; /* Hot key pressed flag */
- static int diskflag; /* Disk BIOS busy flag */
- static int videoflag; /* Video BIOS busy flag */
- static int cflag; /* staging area for flags */
-
- /* ------- local prototypes -------- */
- static void resterm(void);
- static void pspaddr(void);
- static void dores(void);
-
- /* -------- establish & declare residency --------- */
- void resinit()
- {
- extern unsigned sizeprogram; /* defined in popup.c */
-
- segread(&seg);
- myss = seg.ss;
- /* ------ get address of DOS busy flag ---- */
- rg.h.ah = 0x34;
- intdos(&rg, &rg);
- dosseg = _ES;
- dosbusy = rg.x.bx;
- /* ----- get address of resident program's dta ----- */
- mydta = getdta();
- /* -------- get addresses of PID in DOS ------- */
- pspaddr();
- /* ----- get original interrupt vectors ----- */
- oldtimer = getvect(TIMER);
- old28 = getvect(INT28);
- oldkb = getvect(KEYBD);
- olddisk = getvect(DISK);
- oldvideo = getvect(VIDEO);
- /* ----- attach vectors to resident program ----- */
- setvect(TIMER, newtimer);
- setvect(KEYBD, newkb);
- setvect(INT28, new28);
- setvect(DISK, newdisk);
- setvect(VIDEO, newvideo);
- /* ------ compute stack pointer ------- */
- stack = (sizeprogram - (seg.ds - seg.cs)) * 16 - 300;
- /* ---- restore zero divide interrupt vector --- */
- setvect(ZERODIV, ZeroDivVector);è /* ----- terminate and stay resident ------- */
- keep(0, sizeprogram);
- }
-
- /* ------ BIOS disk functions ISR ------- */
- void interrupt newvideo(bp,di,si,ds,es,dx,cx,bx,ax)
- {
- videoflag++;
- (*oldvideo)();
- ax = _AX; /* for the register returns */
- bx = _BX;
- cx = _CX;
- dx = _DX;
- es = _ES;
- di = _DI;
- --videoflag;
- }
-
- /* -------- critical error ISR ---------- */
- void interrupt newcrit(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flgs)
- {
- ax = 0; /* ignore critical errors */
- cflag = flgs; /* for newdisk */
- }
-
- /* ------ BIOS disk functions ISR ------- */
- void interrupt newdisk(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flgs)
- {
- diskflag++;
- (*olddisk)();
- ax = _AX; /* for the ax return */
- newcrit(); /* to get current flags register */
- flgs = cflag; /* newdisk will return oldisk's flags */
- --diskflag;
- }
-
- /* ----- keyboard ISR ------ */
- void interrupt newkb()
- {
- extern unsigned scancode; /* defined in ... */
- extern unsigned keymask; /* ... popup.c */
- static int kbval;
-
- if (inportb(0x60) == scancode) {
- kbval = peekb(0, 0x417);
- if (!resoff && ((kbval & keymask) ^ keymask) == 0) {
- /* --- reset the keyboard ---- */
- kbval = inportb(0x61);
- outportb(0x61, kbval | 0x80);
- outportb(0x61, kbval);
- disable();
- outportb(0x20, 0x20);
- enable();
- /* ---- set hotkey indicator ---- */
- if (!running)è popflg = 1;
- return;
- }
- }
- (*oldkb)();
- }
-
- /* ----- timer ISR ------- */
- void interrupt newtimer()
- {
- (*oldtimer)();
- if (popflg && peekb(dosseg, dosbusy) == 0)
- if (diskflag == 0 && videoflag == 0) {
- outportb(0x20, 0x20);
- popflg = 0;
- dores();
- }
- }
-
- /* ----- 0x28 ISR -------- */
- void interrupt new28()
- {
- (*old28)();
- if (popflg && peekb(dosseg, dosbusy) != 0) {
- popflg = 0;
- dores();
- }
- }
-
- /* ------ switch psp context from interrupted to TSR ----- */
- void resident_psp()
- {
- int pp;
-
- /* ------ save interrupted program's psp ----- */
- intpsp = peek(dosseg, *psps);
- /* ----- set resident program's psp ----- */
- for (pp = 0; pp < pspctr; pp++)
- poke(dosseg, psps [pp], mypsp);
- }
-
- /* ---- switch psp context from TSR to interrupted ---- */
- void interrupted_psp()
- {
- int pp;
-
- /* ----- reset interrupted program's psp ----- */
- for (pp = 0; pp < pspctr; pp++)
- poke(dosseg, psps [pp], intpsp);
- }
-
- /* ------ execute the resident program ------- */
- static void dores()
- {
- static char far *intdta; /* interrupted DTA */è static unsigned intsp; /* " stack pointer */
- static unsigned intss; /* " stack segment */
- static unsigned ctrl_break; /* Ctrl-Break setting */
-
- running = 1;
- disable();
- intsp = _SP;
- intss = _SS;
- _SP = stack;
- _SS = myss;
- enable();
- oldcrit = getvect(CRIT);/* redirect critical error */
- setvect(CRIT, newcrit);
- rg.x.ax = 0x3300; /* get ctrl break setting */
- intdos(&rg, &rg);
- ctrl_break = rg.h.dl;
- rg.x.ax = 0x3301; /* turn off ctrl break logic */
- rg.h.dl = 0;
- intdos(&rg, &rg);
- intdta = getdta(); /* get interrupted dta */
- setdta(mydta); /* set resident dta */
- resident_psp(); /* swap psps */
- popup(); /* execute resident program */
- interrupted_psp(); /* reset interrupted psp */
- setdta(intdta); /* reset interrupted dta */
- setvect(CRIT, oldcrit); /* reset critical error */
- rg.x.ax = 0x3301; /* reset ctrl break */
- rg.h.dl = ctrl_break;
- intdos(&rg, &rg);
- disable(); /* reset interrupted stack */
- _SP = intsp;
- _SS = intss;
- enable();
- running = 0;
- }
-
- static int avec = 0;
-
- /* ------- test to see if the program is already resident
- if not, attach to an available interrupt ---------- */
- unsigned resident(signature, ifunc)
- char *signature;
- void interrupt (*ifunc)();
- {
- char *sg;
- unsigned df;
- int vec;
-
- segread(&seg);
- df = seg.ds-seg.cs;
- for (vec = 0x60; vec < 0x68; vec++) {
- if (getvect(vec) == NULL) {
- if (!avec)
- avec = vec;
- continue;è }
- for (sg = signature; *sg; sg++)
- if (*sg!=peekb(peek(0,2+vec*4)+df,(unsigned)sg))
- break;
- if (!*sg)
- return vec;
- }
- if (avec)
- setvect(avec, ifunc);
- return 0;
- }
-
- /* -------- find address of PID ---------- */
- static void pspaddr()
- {
- unsigned adr = 0;
- unsigned enddos; /* offset to the end of DOS */
-
- /* ------- get the current psp --------- */
- rg.h.ah = 0x51;
- intdos(&rg, &rg);
- mypsp = rg.x.bx;
- /* ----- find the end of the DOS segment ------- */
- rg.h.ah = 0x52;
- intdos(&rg, &rg);
- enddos = _ES;
- enddos = peek(enddos, rg.x.bx-2);
- /* ---- search for matches on the psp in dos ---- */
- while (pspctr < 2 &&
- (unsigned)((dosseg<<4) + adr) < (enddos<<4)) {
- if (peek(dosseg, adr) == mypsp) {
- rg.h.ah = 0x50;
- rg.x.bx = mypsp + 1;
- intdos(&rg, &rg);
- if (peek(dosseg, adr) == mypsp+1)
- psps[pspctr++] = adr;
- /* ---- reset the original psp ------ */
- rg.h.ah = 0x50;
- rg.x.bx = mypsp;
- intdos(&rg, &rg);
- }
- adr++;
- }
- }
-
- /* ------- terminate function ----------- */
- static void resterm()
- {
- static unsigned mcbseg;
-
- closefiles(); /* close TSR files */
- /* ----- restore the interrupt vectors ----- */
- setvect(TIMER, oldtimer);
- setvect(KEYBD, oldkb);
- setvect(INT28, old28);è setvect(DISK, olddisk);
- setvect(VIDEO, oldvideo);
- setvect(avec, (void interrupt (*)()) 0);
- /* ---- get the seg addr of 1st DOS MCB ---- */
- rg.h.ah = 0x52;
- intdos(&rg, &rg);
- mcbseg = _ES;
- mcbseg = peek(mcbseg, rg.x.bx-2);
- /* ---- walk thru mcb chain & release memory ----- */
- segread(&seg);
- while (peekb(mcbseg, 0) == 0x4d) {
- if (peek(mcbseg, 1) == mypsp) {
- rg.h.ah = 0x49;
- seg.es = mcbseg+1;
- intdosx(&rg, &rg, &seg);
- }
- mcbseg += peek(mcbseg, 3) + 1;
- }
- }
-
- /* --------- terminate the resident program --------- */
- void terminate()
- {
- if (getvect(VIDEO) == (void interrupt (*)()) newvideo)
- if (getvect(DISK) == (void interrupt (*)()) newdisk)
- if (getvect(KEYBD) == newkb)
- if (getvect(INT28) == new28)
- if (getvect(TIMER) == newtimer) {
- resterm();
- return;
- }
- resoff = 1; /* another TSR is above us, merely suspend */
- }
-
- /* ------------- restart the resident program --------- */
- void restart()
- {
- resoff = 0;
- }
-
- /* ------- put the program on hold -------- */
- void suspend()
- {
- resoff = 1;
- }
-
- /* ------------- get a keyboard character ---------------- */
- int get_char()
- {
- int c;
-
- while (1) {
- rg.h.ah = 1;
- int86(0x16, &rg, &rg); /* char ready? */
- if (rg.x.flags & 0x40) {è int86(0x28, &rg, &rg); /* 0x28 interrupt */
- continue;
- }
- rg.h.ah = 0;
- int86(0x16, &rg, &rg); /* read the char */
- if (rg.h.al == 0) /* function key? */
- c = rg.h.ah | 128; /* adjust scan code */
- else
- c = rg.h.al;
- break;
- }
- return c;
- }
-
- /* ---------- Listing 4 - clock.c ------------ */
-
- /*
- * A sample TSR that is connected with the TSR Library
- * functions. This program will display the current date
- * and time on the screen when the hot key is pressed.
- * The display remains and the TSR stays popped up until
- * another key is pressed.
- */
-
- #include <stdio.h>
- #include <dos.h>
- #include "tsr.h"
-
- #define VSEG 0xb800 /* change to 0xb000 for MDA */
- #define ROW 10 /* where the clock displays */
- #define COL 30
-
- void popup()
- {
- struct date dat;
- struct time tim;
- int sv[20];
- char bf[20];
- unsigned v;
- static char tmsk [] = " %2d-%02d-%02d %02d:%02d:%02d ";
-
- /* ---- get the current date and time ------ */
- gettime(&tim);
- getdate(&dat);
- /* ----- save the video memory ----- */
- for (v = 0; v < 19; v++)
- sv[v] = peek(VSEG, ((ROW*80+COL) + v) * 2);
- /* ----- build the date/time display ------- */
- sprintf(bf,tmsk,dat.da_day,dat.da_mon,dat.da_year
- % 100,tim.ti_hour, tim.ti_min, tim.ti_sec);
- /* ----- display the date and time -------- */
- for (v = 0; v < 19; v++)
- poke(VSEG, ((ROW*80+COL) + v) * 2, 0x7000 + bf[v]);
- get_char();
- /* -------- restore the video memory ---- */è for (v = 0; v < 19; v++)
- poke(VSEG, ((ROW*80+COL) + v) * 2, sv[v]);
- }
-
- /* ----- startup function, to be used in TSR application ---- */
- void openfiles()
- {
- }
-
- /* ----- shutdown function, to be used in TSR application ---- */
- void closefiles()
- {
- }
-