home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / c / tsrc.arc / TSR2.LTG next >
Text File  |  1988-02-26  |  19KB  |  556 lines

  1. /* -------- Listing 1 - tsr.h --------- */
  2. void resinit(void);
  3. void resident_psp(void);
  4. void interrupted_psp(void);
  5. int resident(char *);
  6. void terminate(void);
  7. void restart(void);
  8. void suspend(void);
  9. int get_char(void);
  10. void popup(void);
  11. void openfiles(void);
  12. void closefiles(void);
  13. void vpoke(unsigned, unsigned, unsigned);
  14. unsigned vpeek(unsigned, unsigned);
  15. int keyrdy(void);
  16. unsigned getsp(void);
  17. unsigned peek(unsigned, unsigned);
  18. char peekb(unsigned, unsigned);
  19. void poke(unsigned, unsigned, unsigned);
  20. int keyhit(void);
  21.  
  22.  
  23.  
  24. /* ---------- Listing 2 - tsr.c ---------- */
  25. #include <dos.h>
  26. #include <stdio.h>
  27. #include <string.h>
  28. #include <bios.h>
  29. #include "tsr.h"
  30. static union REGS rg;
  31. static struct SREGS sg;
  32. /* -------- modify this for each TSR ------------ */
  33. unsigned heaplen = 128;      /* heap length                  */
  34. unsigned scancode = 52;      /* (Period) HOT KEY SCAN CODE   */
  35. unsigned keymask = 8;        /* (Alt)    HOT KEY STATUS MASK */
  36. char signature [] = "CLOCK"; /* TSR SIGNATURE                */
  37. void main(void);
  38. /* --------- main function for the TSR program ------- */
  39. void main()
  40. {
  41.     int r;
  42.     if ((r = resident(signature)) == 0)    {
  43.         printf("\nResident clock is loaded");
  44.         openfiles();
  45.         resinit();
  46.     }
  47.     printf("\nClock is %s", (r == 1 ? "already resident" : "restarted"));
  48. }
  49. /* ------------- get a keyboard character ---------------- */
  50. int get_char()
  51. {
  52.     int c;
  53.     while (keyhit() == 0)
  54.         ;
  55.     c = _bios_keybrd(_KEYBRD_READ);è    return ((c&0xff)==0) ? (((c>>8)&0xff)|128) : (c&0xff);
  56. }
  57. /* ------- set the Disk Transfer Address ---------- */
  58. void setdta(char far *dta)
  59. {
  60.     rg.h.ah = 0x1a;
  61.     rg.x.dx = FP_OFF(dta);
  62.     sg.ds = FP_SEG(dta);
  63.     int86x(0x21, &rg, &rg, &sg);
  64. }
  65. /* ------- get the Disk Transfer Address ---------- */
  66. char far *getdta(void)
  67. {
  68.     static char far *dta;
  69.     rg.h.ah = 0x2f;
  70.     int86x(0x21, &rg, &rg, &sg);
  71.     FP_SEG(dta) = sg.es;
  72.     FP_OFF(dta) = rg.x.bx;
  73.     return dta;
  74. }
  75. /* ----- peek, peekb, poke --------- */
  76. unsigned peek(unsigned s, unsigned o)
  77. {
  78.     static unsigned far *ip;
  79.     FP_SEG(ip) = s;
  80.     FP_OFF(ip) = o;
  81.     return *ip;
  82. }
  83. char peekb(unsigned s, unsigned o)
  84. {
  85.     static char far *ip;
  86.     FP_SEG(ip) = s;
  87.     FP_OFF(ip) = o;
  88.     return *ip;
  89. }
  90. void poke(unsigned s, unsigned o, unsigned c)
  91. {
  92.     static unsigned far *ip;
  93.     FP_SEG(ip) = s;
  94.     FP_OFF(ip) = o;
  95.     *ip = c;
  96. }
  97.  
  98. /* -------- Listing 3 - resident.c --------- */
  99. #include <dos.h>
  100. #include <conio.h>
  101. #include <stdio.h>
  102. #include <stdlib.h>
  103. #include <malloc.h>
  104. #include "tsr.h"
  105. #pragma intrinsic (inp, outp)
  106. char far *getdta(void);
  107. void setdta(char far *);
  108. static union REGS rg;
  109. static struct SREGS seg;è/* --- vectors ---- */
  110. #define KEYBD   9
  111. #define VIDEO   0x10
  112. #define TIMER   0x1c
  113. #define DISK    0x13
  114. #define ZERODIV 0
  115. #define INT28   0x28
  116. #define CRIT    0x24
  117. #define CTRLC    0x23
  118. #define CTRLBRK    0x1b
  119. /* ------ interrupt vector chains ------ */
  120. static void (interrupt far *oldbreak)(void);
  121. static void (interrupt far *oldctrlc)(void);
  122. static void (interrupt far *oldtimer)(void);
  123. static void (interrupt far *old28)(void);
  124. static void (interrupt far *oldkb)(void);
  125. static void (interrupt far *oldcrit)(void);
  126. void (interrupt far *olddisk)(void);
  127. void (interrupt far *oldvideo)(void);
  128. /* ------ ISRs for the TSR ------- */
  129. static void interrupt far newtimer(void);
  130. static void interrupt far new28(void);
  131. static void interrupt far newkb(void);
  132. static void interrupt far newcrit(int,int,int,int,int,int,int,int,int,int);
  133. static void interrupt far newbreak(void);
  134. extern void interrupt far newdisk(void);
  135. extern void interrupt far newvideo(void);
  136.  
  137. extern unsigned heaplen;      /* TSR's heap size            */
  138. static unsigned sizeprogram;  /* TSR's program size         */
  139. static unsigned dosseg;       /* DOS segment address        */
  140. static char far *dosbusy;     /* points to InDOS flag       */
  141. static char far *mydta;       /* TSR's DTA                  */
  142. static unsigned intpsp;       /* Interrupted PSP address    */
  143. static unsigned far *psps[2]; /* Table of DOS PSP addresses */
  144. static int pspctr;            /* # of DOS PSP addresses     */
  145. static int popflg;            /* Hot key pressed flag       */
  146. unsigned myss;                /* TSR's stack segment        */
  147. unsigned stack;               /* TSR's stack pointer        */
  148. int suspending;               /* suspend/resume flag        */
  149. int terminating;              /* terminate flag             */
  150. int diskflag;                 /* Disk BIOS busy flag        */
  151. int videoflag;                /* Video BIOS busy flag       */
  152. /* ------- local prototypes -------- */
  153. static void resterm(void);
  154. static void pspaddr(void);
  155. void dores(void);
  156. void _ctermsub(void);
  157. void popup_tsr(void);
  158. /* -------- establish & declare residency --------- */
  159. void resinit()
  160. {
  161.     /* ------ save TSR stack pointer ------- */
  162.     stack = getsp();
  163.     segread(&seg);è    myss = seg.ss;
  164.     /* ------ get address of DOS busy flag ---- */
  165.     rg.h.ah = 0x34;
  166.     int86x(0x21, &rg, &rg, &seg);
  167.     dosseg = seg.es;
  168.     FP_SEG(dosbusy) = seg.es;
  169.     FP_OFF(dosbusy) = rg.x.bx;
  170.     /* ----- get address of resident program's dta ----- */
  171.     mydta = getdta();
  172.     /* -------- get addresses of PSP in DOS ------- */
  173.     pspaddr();
  174.     /* ----- get original interrupt vectors ----- */
  175.     oldtimer = _dos_getvect(TIMER);
  176.     old28 = _dos_getvect(INT28);
  177.     oldkb = _dos_getvect(KEYBD);
  178.     olddisk = _dos_getvect(DISK);
  179.     oldvideo = _dos_getvect(VIDEO);
  180.     /* ----- attach vectors to resident program ----- */
  181.     _dos_setvect(TIMER, newtimer);
  182.     _dos_setvect(INT28, new28);
  183.     _dos_setvect(KEYBD, newkb);
  184.     _dos_setvect(DISK, newdisk);
  185.     _dos_setvect(VIDEO, newvideo);
  186.     /* ------ compute program size ------- */
  187.     sizeprogram = heaplen/16 + ((myss + (stack+50) / 16) - _psp);
  188.     /* ---- restore zero divide interrupt vector --- */
  189.     _ctermsub();
  190.     /* ----- terminate and stay resident ------- */
  191.     _dos_keep(0, sizeprogram);
  192. }
  193. /* ---------- break handler ------------ */
  194. static void interrupt far newbreak()
  195. {    return;   }
  196. /* -------- critical error ISR ---------- */
  197. static void interrupt far newcrit(es,ds,di,si,bp,sp,bx,dx,cx,ax)
  198. {    ax = 0;   }
  199. static int kbval;
  200. static char far *kmask = (char far *) 0x417;
  201. /* ----- keyboard ISR ------ */
  202. static void interrupt far newkb()
  203. {
  204.     extern unsigned scancode, keymask, running;
  205.     if (scancode && inp(0x60) == scancode)    {
  206.         kbval = *kmask & keymask;
  207.         if (!suspending && kbval == keymask) {
  208.             /* --- reset the keyboard ---- */
  209.             kbval = inp(0x61);
  210.             outp(0x61, kbval | 0x80);
  211.             outp(0x61, kbval);
  212.             outp(0x20, 0x20);
  213.             /* ---- set hotkey indicator ---- */
  214.             if (!running)
  215.                 popflg = 1;
  216.             return;
  217.         }è    }
  218.     (*oldkb)();
  219. }
  220. /* ----- timer ISR ------- */
  221. static void interrupt far newtimer()
  222. {
  223.     extern unsigned scancode, keymask, running;
  224.     (*oldtimer)();
  225.     if (!scancode)    {
  226.         kbval = *kmask & keymask;
  227.         if (!suspending && kbval == keymask)
  228.             if (!running)
  229.                 popflg = 1;
  230.     }
  231.     if (popflg && *dosbusy == 0)
  232.         if (diskflag == 0 && videoflag == 0)    {
  233.             outp(0x20, 0x20);
  234.             popflg = 0;
  235.             dores();
  236.         }
  237. }
  238. /* ----- INT28 ISR -------- */
  239. static void interrupt far new28()
  240. {
  241.     (*old28)();
  242.     if (popflg && *dosbusy != 0)    {
  243.         popflg = 0;
  244.         dores();
  245.     }
  246. }
  247. /* ------ switch psp context from interrupted to TSR ----- */
  248. void resident_psp()
  249. {
  250.     int pp;
  251.     intpsp = *psps[0];              /* save interrupted program's psp */
  252.     for (pp = 0; pp < pspctr; pp++) /* set resident program's psp */
  253.         *psps [pp] = _psp;
  254. }
  255. /* ---- switch psp context from TSR to interrupted ---- */
  256. void interrupted_psp()
  257. {
  258.     int pp;
  259.     for (pp = 0; pp < pspctr; pp++)  /* reset interrupted program's psp */
  260.         *psps [pp] = intpsp;
  261. }
  262. void popup_tsr()
  263. {
  264.     static char far *intdta;         /* interrupted DTA     */
  265.     static unsigned intsp, intss;    /*     "       stack   */
  266.     static unsigned char ctrl_break; /* Ctrl-Break setting  */
  267.     oldcrit = _dos_getvect(CRIT);/* redirect critical error */
  268.     oldbreak = _dos_getvect(CTRLBRK);
  269.     oldctrlc = _dos_getvect(CTRLC);
  270.     _dos_setvect(CRIT, newcrit);
  271.     _dos_setvect(CTRLBRK, newbreak);è    _dos_setvect(CTRLC, newbreak);
  272.     rg.x.ax = 0x3300;            /* get ctrl break setting      */
  273.     int86(0x21, &rg, &rg);
  274.     ctrl_break = rg.h.dl;
  275.     rg.x.ax = 0x3301;            /* turn off ctrl break logic   */
  276.     rg.h.dl = 0;
  277.     int86(0x21, &rg, &rg);
  278.     intdta = getdta();           /* get interrupted dta         */
  279.     setdta(mydta);               /* set resident dta            */
  280.     resident_psp();              /* swap psps                   */
  281.     popup();                     /* execute resident program    */
  282.     interrupted_psp();           /* reset interrupted psp       */
  283.     setdta(intdta);              /* reset interrupted dta       */
  284.     _dos_setvect(CRIT, oldcrit); /* reset critical error*/
  285.     _dos_setvect(CTRLBRK, oldbreak);
  286.     _dos_setvect(CTRLC, oldctrlc);
  287.     rg.x.ax = 0x3301;            /* reset ctrl break            */
  288.     rg.h.dl = ctrl_break;
  289.     int86(0x21, &rg, &rg);
  290.     if (terminating)
  291.         terminate();
  292. }
  293. /* ------- test to see if the TSR is already resident ------- */
  294. int resident(signature)
  295. char *signature;
  296. {
  297.     char *sg;
  298.     unsigned df, mcbseg, blkseg;
  299.     segread(&seg);
  300.     df = seg.ds - _psp;
  301.     rg.h.ah = 0x52;    /*  get the seg addr of 1st DOS MCB */
  302.     intdosx(&rg, &rg, &seg);
  303.     mcbseg = peek(seg.es, rg.x.bx-2);
  304.     while (peekb(mcbseg, 0) == 0x4d)  {  /* walk thru chain, srch for TSR */
  305.         blkseg = peek(mcbseg, 1);
  306.         if (peek(blkseg, 0) == 0x20cd)    {
  307.             if (blkseg == _psp)   /* this is a psp */
  308.                 break;            /* if the transient copy */
  309.             for (sg = signature; *sg; sg++)
  310.                 if (*sg!=peekb(blkseg+df,(unsigned)sg))
  311.                     break;
  312.             if (!*sg)    {    /* if TSR is already resident */
  313.                 if (peek(blkseg+df, (unsigned) &suspending))    {
  314.                     poke(blkseg+df, (unsigned) &suspending, 0);
  315.                     return 2;  /* unsuspend a suspended TSR */
  316.                 }
  317.                 return 1;
  318.             }
  319.         }
  320.         mcbseg += peek(mcbseg, 3) + 1;
  321.     }
  322.     return 0;
  323. }
  324. /* -------- find address of PSP ---------- */
  325. static void pspaddr()è{
  326.     unsigned adr = 0;
  327.     unsigned enddos;    /* offset to the end of DOS */
  328.     static unsigned far *ed, far *ps;
  329.     rg.h.ah = 0x52;     /* find the end of the DOS segment */
  330.     int86x(0x21, &rg, &rg, &seg);
  331.     FP_SEG(ed) = seg.es;
  332.     FP_OFF(ed) = rg.x.bx-2;
  333.     enddos = *ed;
  334.     while (pspctr < 2 &&    /* search for matches on the psp in dos */
  335.             (unsigned)((dosseg<<4) + adr) < (enddos<<4))    {
  336.         FP_SEG(ps) = dosseg;
  337.         FP_OFF(ps) = adr;
  338.         if (*ps == _psp)    {
  339.             rg.h.ah = 0x50;
  340.             rg.x.bx = _psp + 1;
  341.             int86(0x21, &rg, &rg);
  342.             if (*ps == _psp+1)
  343.                 psps[pspctr++] = ps;
  344.             rg.h.ah = 0x50;    /* reset the original psp */
  345.             rg.x.bx = _psp;
  346.             int86(0x21, &rg, &rg);
  347.         }
  348.         adr++;
  349.     }
  350. }
  351. /* ------- terminate function ----------- */
  352. static void resterm()
  353. {
  354.     static unsigned far *env;
  355.     closefiles();    /*  close TSR files */
  356.     _dos_setvect(TIMER, oldtimer);    /*  restore the interrupt vectors */
  357.     _dos_setvect(INT28, old28);
  358.     _dos_setvect(KEYBD, oldkb);
  359.     _dos_setvect(DISK, olddisk);
  360.     _dos_setvect(VIDEO, oldvideo);
  361.     FP_SEG(env) = _psp;    /* release memory owned by the TSR */
  362.     FP_OFF(env) = 0x2c;
  363.     _dos_freemem(*env);
  364.     _dos_freemem(_psp);
  365. }
  366. /* --------- terminate the resident program --------- */
  367. void terminate()
  368. {
  369.     if (_dos_getvect(VIDEO) == (void (interrupt far *)()) newvideo)
  370.         if (_dos_getvect(DISK) == (void (interrupt far *)()) newdisk)
  371.             if (_dos_getvect(KEYBD) == newkb)
  372.                 if (_dos_getvect(INT28) == new28)
  373.                     if (_dos_getvect(TIMER) == newtimer)    {
  374.                         resterm();
  375.                         return;
  376.                     }
  377.     terminating = 0;    /* another TSR is above, suspend */
  378.     suspending = 1;
  379. ;------------------- Listing 4 - tsrasm.asm ------------------------
  380.         dosseg
  381.         .model small
  382.         .data
  383.         public  _running
  384.         extrn   _myss       : word
  385.         extrn   _stack      : word
  386.         extrn   _suspending : word
  387.         extrn   _olddisk    : dword
  388.         extrn   _oldvideo   : dword
  389.         extrn   _diskflag   : word
  390.         extrn   _videoflag  : word
  391. intss   dw      ?
  392. intsp   dw      ?
  393. _running db     0
  394.         .code
  395. extrn   _popup_tsr : near
  396. public  _getsp
  397. ; -------- return the stack pointer
  398. ;       stackpointer = getsp()
  399. ; ------------------------------------------
  400. _getsp  proc    near
  401.         mov     ax,sp
  402.         ret
  403. _getsp  endp
  404. public  _keyhit
  405. ; ------- test for a keystroke, return 1 if key ready, 0 if not
  406. ;         k = keyhit();
  407. ;--------------------------------------
  408. _keyhit proc    near
  409.         mov     ah,1      ; BIOS read key status
  410.         int     16h
  411.         mov     ah,1      ; in case of ctrl-break
  412.         jnz     keyret    ; if a key is ready
  413.         int     28h       ; else, call int 28 to allow other TSRs in
  414.         mov     ax,0      ; and return false
  415. keyret: ret
  416. _keyhit endp
  417. public  _dores
  418. ; -------- swap the stack and call the popup function
  419. _dores  proc    near
  420.         cmp     _suspending,0
  421.         jne     resret      ; don't pop up if the TSR is suspended
  422.         mov     _running,1  ; prevent reentrant TSRs
  423.         cli
  424.         mov     intss,ss    ; save the interrupted stack
  425.         mov     intsp,sp
  426.         mov     ss,_myss    ; set the TSR's stack
  427.         mov     sp,_stack
  428.         sti
  429.         call    _popup_tsr  ; pop up the TSR utility
  430.         cli
  431.         mov     ss,intss    ; restore the interrupted stack
  432.         mov     sp,intspè        sti        
  433.         mov     _running,0
  434. resret: ret
  435. _dores  endp
  436. public  _newdisk
  437. ;--------- 0x13 (disk) BIOS Interrupt Service Routine
  438. _newdisk proc   far
  439.         push    ds
  440.         push    bp
  441.         mov     bp,dgroup   ; set ds to TSR's data segment
  442.         mov     ds,bp
  443.         inc     _diskflag   ; set disk in process flag
  444.         pushf
  445.         call    _olddisk    ; chain to old disk interrupt
  446.         dec     _diskflag   ; reset disk in process flag
  447.         pop     bp
  448.         pop     ds
  449.         ret     2           ; ret 2 passes on the flags
  450. _newdisk endp
  451. public  _newvideo
  452. ;--------- 0x10 (video) BIOS Interrupt Service Routine
  453. _newvideo proc  far
  454.         push    ds
  455.         push    bp
  456.         mov     bp,dgroup   ; set ds to TSR's data segment
  457.         mov     ds,bp
  458.         inc     _videoflag  ; set video in process flag
  459.         pop     bp          ; some EGA functions use bp in
  460.         pushf
  461.         call    _oldvideo   ; chain to old video interrupt
  462.         dec     _videoflag  ; reset video in process flag
  463.         pop     ds
  464.         iret
  465. _newvideo endp
  466. public  _vpoke
  467. ; -------- insert a word into video memory
  468. ;       vpoke(unsigned vseg, unsigned adr, unsigned ch);
  469. ; ------------------------------------------
  470. _vpoke  proc    near
  471.         push    bp
  472.         mov     bp,sp
  473.         push    di
  474.         push    es
  475.         mov     cx,4[bp]  ; video board base address
  476.         mov     es,cx
  477.         mov     di,6[bp]  ; offset address from caller
  478.         cmp     cx,45056  ;mono?
  479.         jz      mono1
  480.         mov     dx,986    ; video status port address
  481. loop1:  in      al,dx     ; wait for retrace to quit
  482.         test    al,1
  483.         jnz     loop1
  484. loop2:  in      al,dx     ; wait for retrace to start
  485.         test    al,1
  486.         jz      loop2èmono1:  mov     ax,8[bp]  ; word to insert
  487.         stosw             ; insert it
  488.         pop     es
  489.         pop     di
  490.         pop     bp
  491.         ret
  492. _vpoke  endp
  493. public _vpeek
  494. ; -------- retrieve a word from video memory
  495. ;       unsigned vpeek(unsigned vseg, unsigned adr);
  496. ; ------------------------------------------
  497. _vpeek  proc    near
  498.         push    bp
  499.         mov     bp,sp
  500.         push    si
  501.         push    ds
  502.         mov     si,6[bp]  ; offset address
  503.         mov     cx,4[bp]  ; video board base address
  504.         mov     ds,cx                
  505.         cmp     cx,45056  ;mono?
  506.         jz      mono2
  507.         mov     dx,986    ; video status port address
  508. loop3:  in      al,dx     ; wait for retrace to stop
  509.         test    al,1
  510.         jnz     loop3
  511. loop4:  in      al,dx     ; wait for retrace to start
  512.         test    al,1
  513.         jz      loop4
  514. mono2:  lodsw             ; get the word
  515.         pop     ds
  516.         pop     si
  517.         pop     bp
  518.         ret
  519. _vpeek  endp
  520. end
  521.  
  522. /* ---------- Listing 5 - clock.c ------------ */
  523. #include <dos.h>
  524. #include <time.h>
  525. #include "tsr.h"
  526. #define VSG 0xb800    /* video memory segment (MDA=0xb000) */
  527. #define ROW 10        /* where the clock displays */
  528. #define COL 30
  529. #define vad(x,y) ((y)*160+(x)*2)
  530. extern int terminating, suspending;
  531. /* --- function called when TSR is popped up ----- */
  532. void popup()
  533. {
  534.     int c, v;
  535.     unsigned sv[24];
  536.     char *tm;
  537.     long tim;
  538.     for (v = 0; v < 24; v++)    /* save the video memory */
  539.         sv[v] = vpeek(VSG, vad(COL+v, ROW));
  540.     while (!keyhit())    { /* run until a key is pressed    */è        time(&tim);        /* get the current date and time */
  541.         tm = ctime(&tim);  /* display the date and time     */
  542.         for (v = 0; v < 24; v++)
  543.             vpoke(VSG, vad(COL+v, ROW), *(tm + v) | 0x7000);
  544.     }
  545.     terminating = ((c = get_char()) == 'u');
  546.     suspending = (c == 's');
  547.     /* -------- restore the video memory ---- */
  548.     for (v = 0; v < 24; v++)
  549.         vpoke(VSG, vad(COL+v, ROW), sv[v]);
  550. }
  551. /* --- null startup & shutdown functions --- */
  552. void openfiles() {}
  553. void closefiles() {}
  554.  
  555.