home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 December
/
simtel1292_SIMTEL_1292_Walnut_Creek.iso
/
msdos
/
c
/
tsrc.arc
/
TSR2.LTG
next >
Wrap
Text File
|
1988-02-26
|
19KB
|
556 lines
/* -------- Listing 1 - tsr.h --------- */
void resinit(void);
void resident_psp(void);
void interrupted_psp(void);
int resident(char *);
void terminate(void);
void restart(void);
void suspend(void);
int get_char(void);
void popup(void);
void openfiles(void);
void closefiles(void);
void vpoke(unsigned, unsigned, unsigned);
unsigned vpeek(unsigned, unsigned);
int keyrdy(void);
unsigned getsp(void);
unsigned peek(unsigned, unsigned);
char peekb(unsigned, unsigned);
void poke(unsigned, unsigned, unsigned);
int keyhit(void);
/* ---------- Listing 2 - tsr.c ---------- */
#include <dos.h>
#include <stdio.h>
#include <string.h>
#include <bios.h>
#include "tsr.h"
static union REGS rg;
static struct SREGS sg;
/* -------- modify this for each TSR ------------ */
unsigned heaplen = 128; /* heap length */
unsigned scancode = 52; /* (Period) HOT KEY SCAN CODE */
unsigned keymask = 8; /* (Alt) HOT KEY STATUS MASK */
char signature [] = "CLOCK"; /* TSR SIGNATURE */
void main(void);
/* --------- main function for the TSR program ------- */
void main()
{
int r;
if ((r = resident(signature)) == 0) {
printf("\nResident clock is loaded");
openfiles();
resinit();
}
printf("\nClock is %s", (r == 1 ? "already resident" : "restarted"));
}
/* ------------- get a keyboard character ---------------- */
int get_char()
{
int c;
while (keyhit() == 0)
;
c = _bios_keybrd(_KEYBRD_READ);è return ((c&0xff)==0) ? (((c>>8)&0xff)|128) : (c&0xff);
}
/* ------- set the Disk Transfer Address ---------- */
void setdta(char far *dta)
{
rg.h.ah = 0x1a;
rg.x.dx = FP_OFF(dta);
sg.ds = FP_SEG(dta);
int86x(0x21, &rg, &rg, &sg);
}
/* ------- get the Disk Transfer Address ---------- */
char far *getdta(void)
{
static char far *dta;
rg.h.ah = 0x2f;
int86x(0x21, &rg, &rg, &sg);
FP_SEG(dta) = sg.es;
FP_OFF(dta) = rg.x.bx;
return dta;
}
/* ----- peek, peekb, poke --------- */
unsigned peek(unsigned s, unsigned o)
{
static unsigned far *ip;
FP_SEG(ip) = s;
FP_OFF(ip) = o;
return *ip;
}
char peekb(unsigned s, unsigned o)
{
static char far *ip;
FP_SEG(ip) = s;
FP_OFF(ip) = o;
return *ip;
}
void poke(unsigned s, unsigned o, unsigned c)
{
static unsigned far *ip;
FP_SEG(ip) = s;
FP_OFF(ip) = o;
*ip = c;
}
/* -------- Listing 3 - resident.c --------- */
#include <dos.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include "tsr.h"
#pragma intrinsic (inp, outp)
char far *getdta(void);
void setdta(char far *);
static union REGS rg;
static struct SREGS seg;è/* --- vectors ---- */
#define KEYBD 9
#define VIDEO 0x10
#define TIMER 0x1c
#define DISK 0x13
#define ZERODIV 0
#define INT28 0x28
#define CRIT 0x24
#define CTRLC 0x23
#define CTRLBRK 0x1b
/* ------ interrupt vector chains ------ */
static void (interrupt far *oldbreak)(void);
static void (interrupt far *oldctrlc)(void);
static void (interrupt far *oldtimer)(void);
static void (interrupt far *old28)(void);
static void (interrupt far *oldkb)(void);
static void (interrupt far *oldcrit)(void);
void (interrupt far *olddisk)(void);
void (interrupt far *oldvideo)(void);
/* ------ ISRs for the TSR ------- */
static void interrupt far newtimer(void);
static void interrupt far new28(void);
static void interrupt far newkb(void);
static void interrupt far newcrit(int,int,int,int,int,int,int,int,int,int);
static void interrupt far newbreak(void);
extern void interrupt far newdisk(void);
extern void interrupt far newvideo(void);
extern unsigned heaplen; /* TSR's heap size */
static unsigned sizeprogram; /* TSR's program size */
static unsigned dosseg; /* DOS segment address */
static char far *dosbusy; /* points to InDOS flag */
static char far *mydta; /* TSR's DTA */
static unsigned intpsp; /* Interrupted PSP address */
static unsigned far *psps[2]; /* Table of DOS PSP addresses */
static int pspctr; /* # of DOS PSP addresses */
static int popflg; /* Hot key pressed flag */
unsigned myss; /* TSR's stack segment */
unsigned stack; /* TSR's stack pointer */
int suspending; /* suspend/resume flag */
int terminating; /* terminate flag */
int diskflag; /* Disk BIOS busy flag */
int videoflag; /* Video BIOS busy flag */
/* ------- local prototypes -------- */
static void resterm(void);
static void pspaddr(void);
void dores(void);
void _ctermsub(void);
void popup_tsr(void);
/* -------- establish & declare residency --------- */
void resinit()
{
/* ------ save TSR stack pointer ------- */
stack = getsp();
segread(&seg);è myss = seg.ss;
/* ------ get address of DOS busy flag ---- */
rg.h.ah = 0x34;
int86x(0x21, &rg, &rg, &seg);
dosseg = seg.es;
FP_SEG(dosbusy) = seg.es;
FP_OFF(dosbusy) = rg.x.bx;
/* ----- get address of resident program's dta ----- */
mydta = getdta();
/* -------- get addresses of PSP in DOS ------- */
pspaddr();
/* ----- get original interrupt vectors ----- */
oldtimer = _dos_getvect(TIMER);
old28 = _dos_getvect(INT28);
oldkb = _dos_getvect(KEYBD);
olddisk = _dos_getvect(DISK);
oldvideo = _dos_getvect(VIDEO);
/* ----- attach vectors to resident program ----- */
_dos_setvect(TIMER, newtimer);
_dos_setvect(INT28, new28);
_dos_setvect(KEYBD, newkb);
_dos_setvect(DISK, newdisk);
_dos_setvect(VIDEO, newvideo);
/* ------ compute program size ------- */
sizeprogram = heaplen/16 + ((myss + (stack+50) / 16) - _psp);
/* ---- restore zero divide interrupt vector --- */
_ctermsub();
/* ----- terminate and stay resident ------- */
_dos_keep(0, sizeprogram);
}
/* ---------- break handler ------------ */
static void interrupt far newbreak()
{ return; }
/* -------- critical error ISR ---------- */
static void interrupt far newcrit(es,ds,di,si,bp,sp,bx,dx,cx,ax)
{ ax = 0; }
static int kbval;
static char far *kmask = (char far *) 0x417;
/* ----- keyboard ISR ------ */
static void interrupt far newkb()
{
extern unsigned scancode, keymask, running;
if (scancode && inp(0x60) == scancode) {
kbval = *kmask & keymask;
if (!suspending && kbval == keymask) {
/* --- reset the keyboard ---- */
kbval = inp(0x61);
outp(0x61, kbval | 0x80);
outp(0x61, kbval);
outp(0x20, 0x20);
/* ---- set hotkey indicator ---- */
if (!running)
popflg = 1;
return;
}è }
(*oldkb)();
}
/* ----- timer ISR ------- */
static void interrupt far newtimer()
{
extern unsigned scancode, keymask, running;
(*oldtimer)();
if (!scancode) {
kbval = *kmask & keymask;
if (!suspending && kbval == keymask)
if (!running)
popflg = 1;
}
if (popflg && *dosbusy == 0)
if (diskflag == 0 && videoflag == 0) {
outp(0x20, 0x20);
popflg = 0;
dores();
}
}
/* ----- INT28 ISR -------- */
static void interrupt far new28()
{
(*old28)();
if (popflg && *dosbusy != 0) {
popflg = 0;
dores();
}
}
/* ------ switch psp context from interrupted to TSR ----- */
void resident_psp()
{
int pp;
intpsp = *psps[0]; /* save interrupted program's psp */
for (pp = 0; pp < pspctr; pp++) /* set resident program's psp */
*psps [pp] = _psp;
}
/* ---- switch psp context from TSR to interrupted ---- */
void interrupted_psp()
{
int pp;
for (pp = 0; pp < pspctr; pp++) /* reset interrupted program's psp */
*psps [pp] = intpsp;
}
void popup_tsr()
{
static char far *intdta; /* interrupted DTA */
static unsigned intsp, intss; /* " stack */
static unsigned char ctrl_break; /* Ctrl-Break setting */
oldcrit = _dos_getvect(CRIT);/* redirect critical error */
oldbreak = _dos_getvect(CTRLBRK);
oldctrlc = _dos_getvect(CTRLC);
_dos_setvect(CRIT, newcrit);
_dos_setvect(CTRLBRK, newbreak);è _dos_setvect(CTRLC, newbreak);
rg.x.ax = 0x3300; /* get ctrl break setting */
int86(0x21, &rg, &rg);
ctrl_break = rg.h.dl;
rg.x.ax = 0x3301; /* turn off ctrl break logic */
rg.h.dl = 0;
int86(0x21, &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 */
_dos_setvect(CRIT, oldcrit); /* reset critical error*/
_dos_setvect(CTRLBRK, oldbreak);
_dos_setvect(CTRLC, oldctrlc);
rg.x.ax = 0x3301; /* reset ctrl break */
rg.h.dl = ctrl_break;
int86(0x21, &rg, &rg);
if (terminating)
terminate();
}
/* ------- test to see if the TSR is already resident ------- */
int resident(signature)
char *signature;
{
char *sg;
unsigned df, mcbseg, blkseg;
segread(&seg);
df = seg.ds - _psp;
rg.h.ah = 0x52; /* get the seg addr of 1st DOS MCB */
intdosx(&rg, &rg, &seg);
mcbseg = peek(seg.es, rg.x.bx-2);
while (peekb(mcbseg, 0) == 0x4d) { /* walk thru chain, srch for TSR */
blkseg = peek(mcbseg, 1);
if (peek(blkseg, 0) == 0x20cd) {
if (blkseg == _psp) /* this is a psp */
break; /* if the transient copy */
for (sg = signature; *sg; sg++)
if (*sg!=peekb(blkseg+df,(unsigned)sg))
break;
if (!*sg) { /* if TSR is already resident */
if (peek(blkseg+df, (unsigned) &suspending)) {
poke(blkseg+df, (unsigned) &suspending, 0);
return 2; /* unsuspend a suspended TSR */
}
return 1;
}
}
mcbseg += peek(mcbseg, 3) + 1;
}
return 0;
}
/* -------- find address of PSP ---------- */
static void pspaddr()è{
unsigned adr = 0;
unsigned enddos; /* offset to the end of DOS */
static unsigned far *ed, far *ps;
rg.h.ah = 0x52; /* find the end of the DOS segment */
int86x(0x21, &rg, &rg, &seg);
FP_SEG(ed) = seg.es;
FP_OFF(ed) = rg.x.bx-2;
enddos = *ed;
while (pspctr < 2 && /* search for matches on the psp in dos */
(unsigned)((dosseg<<4) + adr) < (enddos<<4)) {
FP_SEG(ps) = dosseg;
FP_OFF(ps) = adr;
if (*ps == _psp) {
rg.h.ah = 0x50;
rg.x.bx = _psp + 1;
int86(0x21, &rg, &rg);
if (*ps == _psp+1)
psps[pspctr++] = ps;
rg.h.ah = 0x50; /* reset the original psp */
rg.x.bx = _psp;
int86(0x21, &rg, &rg);
}
adr++;
}
}
/* ------- terminate function ----------- */
static void resterm()
{
static unsigned far *env;
closefiles(); /* close TSR files */
_dos_setvect(TIMER, oldtimer); /* restore the interrupt vectors */
_dos_setvect(INT28, old28);
_dos_setvect(KEYBD, oldkb);
_dos_setvect(DISK, olddisk);
_dos_setvect(VIDEO, oldvideo);
FP_SEG(env) = _psp; /* release memory owned by the TSR */
FP_OFF(env) = 0x2c;
_dos_freemem(*env);
_dos_freemem(_psp);
}
/* --------- terminate the resident program --------- */
void terminate()
{
if (_dos_getvect(VIDEO) == (void (interrupt far *)()) newvideo)
if (_dos_getvect(DISK) == (void (interrupt far *)()) newdisk)
if (_dos_getvect(KEYBD) == newkb)
if (_dos_getvect(INT28) == new28)
if (_dos_getvect(TIMER) == newtimer) {
resterm();
return;
}
terminating = 0; /* another TSR is above, suspend */
suspending = 1;
}è
;------------------- Listing 4 - tsrasm.asm ------------------------
dosseg
.model small
.data
public _running
extrn _myss : word
extrn _stack : word
extrn _suspending : word
extrn _olddisk : dword
extrn _oldvideo : dword
extrn _diskflag : word
extrn _videoflag : word
intss dw ?
intsp dw ?
_running db 0
.code
extrn _popup_tsr : near
public _getsp
; -------- return the stack pointer
; stackpointer = getsp()
; ------------------------------------------
_getsp proc near
mov ax,sp
ret
_getsp endp
public _keyhit
; ------- test for a keystroke, return 1 if key ready, 0 if not
; k = keyhit();
;--------------------------------------
_keyhit proc near
mov ah,1 ; BIOS read key status
int 16h
mov ah,1 ; in case of ctrl-break
jnz keyret ; if a key is ready
int 28h ; else, call int 28 to allow other TSRs in
mov ax,0 ; and return false
keyret: ret
_keyhit endp
public _dores
; -------- swap the stack and call the popup function
_dores proc near
cmp _suspending,0
jne resret ; don't pop up if the TSR is suspended
mov _running,1 ; prevent reentrant TSRs
cli
mov intss,ss ; save the interrupted stack
mov intsp,sp
mov ss,_myss ; set the TSR's stack
mov sp,_stack
sti
call _popup_tsr ; pop up the TSR utility
cli
mov ss,intss ; restore the interrupted stack
mov sp,intspè sti
mov _running,0
resret: ret
_dores endp
public _newdisk
;--------- 0x13 (disk) BIOS Interrupt Service Routine
_newdisk proc far
push ds
push bp
mov bp,dgroup ; set ds to TSR's data segment
mov ds,bp
inc _diskflag ; set disk in process flag
pushf
call _olddisk ; chain to old disk interrupt
dec _diskflag ; reset disk in process flag
pop bp
pop ds
ret 2 ; ret 2 passes on the flags
_newdisk endp
public _newvideo
;--------- 0x10 (video) BIOS Interrupt Service Routine
_newvideo proc far
push ds
push bp
mov bp,dgroup ; set ds to TSR's data segment
mov ds,bp
inc _videoflag ; set video in process flag
pop bp ; some EGA functions use bp in
pushf
call _oldvideo ; chain to old video interrupt
dec _videoflag ; reset video in process flag
pop ds
iret
_newvideo endp
public _vpoke
; -------- insert a word into video memory
; vpoke(unsigned vseg, unsigned adr, unsigned ch);
; ------------------------------------------
_vpoke proc near
push bp
mov bp,sp
push di
push es
mov cx,4[bp] ; video board base address
mov es,cx
mov di,6[bp] ; offset address from caller
cmp cx,45056 ;mono?
jz mono1
mov dx,986 ; video status port address
loop1: in al,dx ; wait for retrace to quit
test al,1
jnz loop1
loop2: in al,dx ; wait for retrace to start
test al,1
jz loop2èmono1: mov ax,8[bp] ; word to insert
stosw ; insert it
pop es
pop di
pop bp
ret
_vpoke endp
public _vpeek
; -------- retrieve a word from video memory
; unsigned vpeek(unsigned vseg, unsigned adr);
; ------------------------------------------
_vpeek proc near
push bp
mov bp,sp
push si
push ds
mov si,6[bp] ; offset address
mov cx,4[bp] ; video board base address
mov ds,cx
cmp cx,45056 ;mono?
jz mono2
mov dx,986 ; video status port address
loop3: in al,dx ; wait for retrace to stop
test al,1
jnz loop3
loop4: in al,dx ; wait for retrace to start
test al,1
jz loop4
mono2: lodsw ; get the word
pop ds
pop si
pop bp
ret
_vpeek endp
end
/* ---------- Listing 5 - clock.c ------------ */
#include <dos.h>
#include <time.h>
#include "tsr.h"
#define VSG 0xb800 /* video memory segment (MDA=0xb000) */
#define ROW 10 /* where the clock displays */
#define COL 30
#define vad(x,y) ((y)*160+(x)*2)
extern int terminating, suspending;
/* --- function called when TSR is popped up ----- */
void popup()
{
int c, v;
unsigned sv[24];
char *tm;
long tim;
for (v = 0; v < 24; v++) /* save the video memory */
sv[v] = vpeek(VSG, vad(COL+v, ROW));
while (!keyhit()) { /* run until a key is pressed */è time(&tim); /* get the current date and time */
tm = ctime(&tim); /* display the date and time */
for (v = 0; v < 24; v++)
vpoke(VSG, vad(COL+v, ROW), *(tm + v) | 0x7000);
}
terminating = ((c = get_char()) == 'u');
suspending = (c == 's');
/* -------- restore the video memory ---- */
for (v = 0; v < 24; v++)
vpoke(VSG, vad(COL+v, ROW), sv[v]);
}
/* --- null startup & shutdown functions --- */
void openfiles() {}
void closefiles() {}