home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / turbopas / tppop16.arc / TPOP.ASM < prev    next >
Assembly Source File  |  1988-10-05  |  20KB  |  518 lines

  1. TITLE   Turbo Pop Version 1.6 beta
  2. SUBTTL  Copyright (c)1988 Ross Neilson Wentworth
  3.  
  4. ; This code is Copyright (c)1988 by Ross Neilson Wentworth
  5. ; All Rights Reserved
  6. ;
  7. ; No part of this code may be reproduced, modified, sold, or used
  8. ; as an incentive to buy without the expressed written consent of
  9. ; the author.
  10.  
  11.  
  12. ; Routine Quick Reference
  13. ;
  14. ;   EnterPopUp          Saves and sets the stack then calls a high-level routine
  15. ;   InitializePopUp     Sets the low-level interrupt vectors
  16. ;   Installed           Sees if the program is already loaded
  17. ;   new05Int            Optional print-screen trap
  18. ;   new09int            Checks for our hotkey combo at each keypress
  19. ;   new10Int            Optional video BIOS trap
  20. ;   new13int            Keeps track of when the disk is busy
  21. ;   new1Cint            Called at each timer tick and checks to see if we
  22. ;                       want to pop up and whether it is safe to do so
  23. ;   new28int            Interrupt routine that is called whenever it is safe
  24. ;                       to interrupt DOS
  25. ;   new2Fint            Intercepts the Multiplex interupt
  26.  
  27. TRUE     equ    1
  28. FALSE    equ    0
  29.  
  30. TRAPINT05  EQU  FALSE    ; change to TRUE to trap print-screens
  31. TRAPINT10  EQU  FALSE    ; change to TRUE to trap video BIOS
  32.  
  33. PUBLIC InitializePopUp,Installed
  34.  
  35. CSEG  SEGMENT PARA PUBLIC 'CODE'
  36.       ASSUME  CS:CSEG
  37.  
  38. EXTRN callpopup:FAR,ReleaseProgram:FAR
  39.  
  40. ;----------------------------------------------------------------------------
  41. ; Miscellaneous data
  42. ;----------------------------------------------------------------------------
  43. hotkey  LABEL  WORD
  44. scancode       DB  0    ; scan code of our hotkey
  45. shiftstatus    DB  0    ; shift key status (alt,ctrl, etc. )
  46.  
  47. program_status DB  0    ; true if the program is active
  48. request_flag   DB  0    ; true if we want to pop-up
  49. notsafe        DB  0    ; non-zero if unsafe to pop up
  50. multiplexID    DB  0    ; unique program ID code
  51.  
  52. stack_pointer  DW  0    ; holds our program's stack pointer
  53. stack_segment  DW  0    ; holds our program's stack segment
  54. old_pointer    DW  0    ; holds the interrupted stack pointer
  55. old_stack      DW  0    ; holds the interrupted stack segment
  56.  
  57. dos_busy_flag  DD  0       ; points to DOS's busy flag
  58.  
  59. ; Follows is the interrupt service routine (ISR) installation table.
  60. ; Each interrupt will have three entries, the interrupt number, the
  61. ; original interrupt vector, and the offset of the ISR.  The entire
  62. ; table is terminated with a zero byte (this disallows the automatic
  63. ; installation of interrupt 00h).  There are two ISR's that are optional.
  64. ; One traps the print-screen interrupt (05h) and the other traps the video
  65. ; BIOS interrupt (10h).  By default, these traps are not used.  If you wish
  66. ; to include them in the interrupt trapping list you must change the EQU's
  67. ; above to TRUE.  TRAPINT05 is the EQU for trapping the print-screen
  68. ; interrupt and TRAPINT10 is the EQU for trapping the video BIOS.
  69.  
  70. ;----------------------------------------------------------------------------
  71. ; Interrupt Vector Table
  72. ;----------------------------------------------------------------------------
  73.  
  74. Vectors  LABEL   BYTE
  75.  
  76. IF TRAPINT05   ; optional interrupt trap
  77.  
  78.                DB  05h     ; print screen vector number
  79. old05int       DD  ?       ; the original print screen interrupt vector
  80.                DW  offset new05int
  81. ENDIF
  82.  
  83.                DB  09h     ; keyboard vector number
  84. old09int       DD  ?       ; the original keyboard interrupt vector
  85.                DW  offset new09int
  86.  
  87. IF TRAPINT10   ; optional interrupt trap
  88.  
  89.                DB  10h     ; video BIOS vector number
  90. old10int       DD  ?       ; the original video BIOS interrupt vector
  91.                DW  offset new10int
  92. ENDIF
  93.  
  94.                DB  13h     ; disk i/o vector number
  95. old13int       DD  ?       ; the original disk interrupt vector
  96.                DW  offset new13int
  97.  
  98.                DB  1Ch     ; timer vector number
  99. old1Cint       DD  ?       ; the original timer interrupt vector
  100.                DW  offset new1Cint
  101.  
  102.                DB  28h     ; backprocess vector number
  103. old28int       DD  ?       ; the original backprocess interrupt vector
  104.                DW  offset new28int
  105.  
  106.                DB  2Fh     ; multiplex interrupt
  107. old2Fint       DD  ?       ; the original multiplex interrupt vector
  108.                DW  offset new2Fint
  109.  
  110.                DB  0       ; end of table
  111.  
  112. ;----------------------------------------------------------------------------
  113. ; Print-Screen Interrupt Service Routine - 05h
  114. ;----------------------------------------------------------------------------
  115. ; This is an optional interrupt trap.  Change the value of TRAPINT05 to
  116. ; TRUE if you want it compiled.  This one traps the PRINT SCREEN interrupt
  117. ; and prevents popping up in the middle of a screen print.
  118.  
  119. IF  trapInt05
  120.  
  121. new05int PROC  FAR
  122.  
  123.          inc       cs:[notsafe]        ; increment status flag
  124.  
  125.          pushf
  126.          cli
  127.          call      cs:[old05int]       ; chain to original INT 05h handler
  128.  
  129.          pushf                         ; preserve flags
  130.          dec       cs:[notsafe]        ; decrement status flag
  131.          popf                          ; restore flags
  132.  
  133.          sti                           ; enable interrupts
  134.          ret       2                   ; return with flags
  135.  
  136. new05int ENDP
  137.  
  138. ENDIF
  139.  
  140. ;----------------------------------------------------------------------------
  141. ; Keyboard Interrupt Service Routine - 09h
  142. ;----------------------------------------------------------------------------
  143. ; Every keystroke is checked through here for our hot_key combination.
  144. ; If our's is pressed, a service request flag is set to TRUE.  If the
  145. ; program is already active we let the keystroke by so that conflicting
  146. ; hot-keys will work.
  147.  
  148. new09int PROC  FAR
  149.  
  150.          sti
  151.          pushf                           ; save the flags
  152.          push      ax                    ; and a register that gets used
  153.          in        al,60h                ; get the keystroke
  154.          cmp       al,cs:[scancode]      ; is it our key?
  155.          jne       @F                    ; no, so jump to original vector
  156.          mov       ah,2
  157.          int       16h                   ; get the keyboard flags
  158.          and       al,0Fh                ; mask off unused bits
  159.          cmp       al,cs:[shiftstatus]   ; does it match our mask?
  160.          jne       @F                    ; no, so jump to original vector
  161.          cmp       cs:[program_status],FALSE ; are we already active?
  162.          jne       @F                    ; yes, so chain to original vector
  163.          cmp       cs:[request_flag],FALSE   ; do we already want serveice?
  164.          je        L200                  ; yes, so chain to original vector
  165. @@:
  166.          pop       ax                    ; restore used register
  167.          popf                            ; restore flags
  168.          jmp       cs:[old09int]         ; jump to original vector
  169. L200:
  170.          mov       cs:[request_flag],TRUE ; say service is desired
  171.          cli                              ; turn off interrupts
  172.          mov       al,20h                 ; say interrupt is finished
  173.          out       20h,al
  174.          in        al,61h                 ; trash the keystroke
  175.          mov       ah,al
  176.          or        al,80h
  177.          out       61h,al
  178.          jmp       @F                     ; jump to nowhere for delay
  179. @@:
  180.          mov       al,ah
  181.          out       61h,al
  182.          pop       ax                     ; restore used register
  183.          popf                             ; restore flags
  184.          iret                             ; all done
  185.  
  186. new09int ENDP
  187.  
  188. ;----------------------------------------------------------------------------
  189. ; Video BIOS Interrupt Service Routine - 10h
  190. ;----------------------------------------------------------------------------
  191. ; This is an optional interrupt trap.  Change the value of TRAPINT10 to
  192. ; TRUE if you want it compiled.  This one traps the video BIOS interrupt
  193. ; and prevents popping up in the middle of any screen activity.
  194.  
  195. IF  trapInt10
  196.  
  197. new10int PROC  FAR
  198.  
  199.          inc       cs:[notsafe]        ; increment status flag
  200.  
  201.          pushf
  202.          cli
  203.          call      cs:[old10int]       ; chain to original INT 10h handler
  204.  
  205.          pushf                         ; preserve flags
  206.          dec       cs:[notsafe]        ; decrement status flag
  207.          popf                          ; restore flags
  208.  
  209.          sti                           ; enable interrupts
  210.          ret       2                   ; return with flags
  211.  
  212. new10int ENDP
  213.  
  214. ENDIF
  215.  
  216. ;----------------------------------------------------------------------------
  217. ; Disk I/O Interrupt Service Routine - 13h
  218. ;----------------------------------------------------------------------------
  219. ; At each disk call, increments an unsafe flag, finishes
  220. ; the disk call, then decrements the unsafe flag.  This
  221. ; prevents an unsafe "popup" during disk i/o.
  222.  
  223. new13int PROC FAR
  224.  
  225.          inc       cs:[notsafe]       ; increment status flag
  226.  
  227.          pushf                         ; chain to original INT 13h handler
  228.          cli
  229.          call      cs:[old13int]
  230.  
  231.          pushf                         ; preserve flags
  232.          dec       cs:[notsafe]        ; decrement status flag
  233.          popf                          ; restore flags
  234.  
  235.          sti                           ; enable interrupts
  236.          ret       2                   ; return with flags, this is to retain
  237.                                        ; any carry flag (error) that may
  238.                                        ; have occurred.
  239.  
  240. new13int ENDP
  241.  
  242. ;----------------------------------------------------------------------------
  243. ; Timer Tick Interrupt Service Routine - 1Ch
  244. ;----------------------------------------------------------------------------
  245. ; At each timer tick, this routine sees if our routine wants service.
  246. ; If it does, and it's safe to run, it saves junk and calls our routine.
  247.  
  248. new1Cint PROC  FAR
  249.  
  250.          pushf                               ; call original timer interrupt
  251.          cli
  252.          call      cs:[old1Cint]
  253.          cmp       cs:[request_flag],FALSE   ; request flag set?
  254.          je        L400                      ; no, then exit
  255.          push      di
  256.          push      es                        ; save es and di
  257.          les       di,cs:[dos_busy_flag]     ; address of DOS BUSY_FLAG in DI
  258.          cmp       byte ptr es:[di],FALSE    ; DOS service currently active?
  259.          pop       es
  260.          pop       di                        ; clean up the stack
  261.          jne       L400                      ; dos active, so wait
  262.          cmp       cs:[notsafe],FALSE        ; is it safe to pop-up?
  263.          je        EnterPopUp                ; yes, go for it
  264. L400:
  265.          iret                                ; busy or no request
  266.  
  267. new1Cint ENDP
  268.  
  269. ;----------------------------------------------------------------------------
  270. ; Backprocess Interrupt Service Routine - 28h
  271. ;----------------------------------------------------------------------------
  272. ; Whenever it is safe for a program to interrupt, DOS issues an
  273. ; INT 28h.  This normally occurs while sitting at the command line.
  274. ; This routine checks to see if our program wants service and pops
  275. ; it up if it does.
  276.  
  277. new28int PROC FAR
  278.  
  279.          pushf                             ; call the original interrupt routine
  280.          cli
  281.          call      cs:[old28int]
  282.  
  283.          cmp       cs:[request_flag],FALSE ; do we want to pop up?
  284.          jne       EnterPopUp              ; yes, go pop up
  285.          iret                              ; no. exit
  286.  
  287. new28int ENDP
  288.  
  289. ;----------------------------------------------------------------------------
  290. ; Multiplex Interrupt Service Routine - 2Fh
  291. ;----------------------------------------------------------------------------
  292. ; We use this ISR to check if a program is already loaded as well as to
  293. ; provide special routines needed to unload the program safely.
  294. ;
  295. ; function 0, returns 0FFh in AL to indicate the program is already loaded
  296. ; function 1, returns the vector table in DX:AX
  297. ; function 2, returns the module's code segment (CS) in AX
  298. ; function 3, releases the memory for this program
  299. ;
  300. ; Examine the UNHOOK unit to see how these are used
  301.  
  302. new2Fint PROC  FAR
  303.  
  304.          cmp       ah,cs:[MultiplexID]
  305.          je        @F
  306.          jmp       cs:[old2Fint]
  307. @@:
  308.          test      al,al          ; function 0, loaded flag
  309.          jnz       @F
  310.          mov       al,0FFh
  311.          jmp       short L300
  312. @@:
  313.          cmp       al,1           ; function 1, return vector table pointer
  314.          jne       @F
  315.          mov       dx,cs
  316.          lea       ax,cs:[vectors]
  317.          jmp       short L300
  318. @@:
  319.          cmp       al,2           ; function 2, return code segment
  320.          jne       @F
  321.          mov       ax,cs
  322.          jmp       short L300
  323. @@:
  324.          cmp       al,3           ; function 3, release program memory
  325.          jne       L300
  326.          pushf
  327.          call      ReleaseProgram
  328. L300:
  329.          iret
  330.  
  331. new2Fint ENDP
  332.  
  333. ;----------------------------------------------------------------------------
  334. ; Setup For Entering Application
  335. ;----------------------------------------------------------------------------
  336. ; Sets SS, and SP, then calls the popup program.
  337. ; After returning, it restores them.
  338.  
  339. EnterPopUp  PROC   NEAR
  340.  
  341.          mov       cs:[request_flag],FALSE  ; clear the pop up request flag
  342.          mov       cs:[program_status],TRUE ; say program is active
  343.          mov       cs:[old_stack],ss     ; save the stack segment
  344.          mov       cs:[old_pointer],sp   ; save the stack pointer
  345.          cli                             ; turn off interrupts
  346.          mov       ss,cs:[stack_segment] ; get our program's stack segment
  347.          mov       sp,cs:[stack_pointer] ; get our program's stack pointer
  348.          sti                             ; turn interrupts back on
  349.  
  350. ; call the popup procedure indirectly
  351.  
  352.          pushf                           ; simulate an interrupt
  353.          call      CallPopUp
  354.  
  355. ; restore the stack segment and pointer
  356.  
  357.          cli                            ; old cpu bug require ints be off
  358.          mov       ss,cs:[old_stack]
  359.          mov       sp,cs:[old_pointer]
  360.          sti
  361.  
  362.          mov       cs:[program_status],FALSE ; say program is not active
  363.          iret                                ; all done
  364.  
  365. EnterPopUp  ENDP
  366.  
  367. stk_str  STRUC
  368.  
  369. oldbp    DW   ?
  370. return   DW   ?
  371. keycombo DW   ?
  372. multID   DW   ?
  373.  
  374. stk_str  ENDS
  375.  
  376. ;----------------------------------------------------------------------------
  377. ; Initialize memory and the vectors
  378. ;----------------------------------------------------------------------------
  379. ; We save some interrupt vectors and flags in the code segment for
  380. ; efficiency.  We don't want to be pushing and popping all of the
  381. ; registers at every single timer tick and key press.
  382. ;
  383. ; It's too bad there isn't any way of releasing the space used by the
  384. ; initialization code.  This is the reason the most efficient resident
  385. ; programs are written in entirely assembler, complete control of segment
  386. ; ordering.
  387.  
  388. InitializePopUp PROC  NEAR
  389.  
  390. ; save the stack pointer and segment
  391.  
  392.          push      bp
  393.          mov       bp,sp
  394.  
  395. ; save our hot key combo
  396.  
  397.          mov       ax,keycombo[bp]
  398.          mov       cs:[hotkey],ax
  399.  
  400. ; save the TSR's unique ID
  401.  
  402.          mov       ax,multID[bp]
  403.          mov       cs:[multiplexID],al
  404.  
  405. ; save the stack segment and pointer
  406.  
  407.          mov       cs:[stack_segment],ss
  408.          mov       cs:[stack_pointer],sp
  409.  
  410. ; get the DOS busy flag address
  411.  
  412.          mov       ah,34h
  413.          int       21h
  414.          mov       cs:word ptr [dos_busy_flag+2],es
  415.          mov       cs:word ptr [dos_busy_flag],bx
  416.  
  417.          push      ds              ; save the data segment
  418.          push      cs
  419.          pop       ds              ; point to the code segment
  420.  
  421. ; set all of the interrupt vectors
  422.  
  423.          lea       si,vectors
  424.          cld
  425. @@:
  426.          lodsb                     ; get a vector number
  427.          or        al,al           ; are we done
  428.          jz        @F              ; yes
  429.          push      ax              ; save the interrupt number
  430.          mov       ah,35h
  431.          int       21h             ; get the old vector
  432.          mov       [si],bx         ; save the offset
  433.          mov       [si+2],es       ; save the segment
  434.          pop       ax              ; get back interrupt number
  435.          mov       ah,25h          ; set the interrupt vector
  436.          mov       dx,[si+4]       ; get the routine offset assume this code segment
  437.          int       21h
  438.          add       si,6            ; point to next item in table
  439.          jmp       short @B        ; do it again
  440. @@:
  441.          pop       ds              ; restore the data segment
  442.          pop       bp
  443.          ret       2
  444.  
  445. InitializePopUp  ENDP
  446.  
  447. ;----------------------------------------------------------------------------
  448. ; Checks for a previously installed program
  449. ;----------------------------------------------------------------------------
  450. ; Checks to see if the program is already loaded by using the Multiplex
  451. ; interrupt (2Fh).  It must do some convaluted crap to avoid problems
  452. ; under DOS 2.x.
  453.  
  454. Installed PROC  FAR
  455.  
  456.          push      bp
  457.          mov       bp,sp
  458.          mov       ah,30h
  459.          int       21h            ; get the DOS version
  460.          cmp       al,2
  461.          ja        L101           ; jump if version 3.0 or later
  462.          mov       ax,352Fh       ; get vector for 2Fh
  463.          int       21h
  464.          mov       ax,es
  465.          or        ax,bx          ; jump if current INT 2Fh vector ..
  466.          jnz       L100           ; .. is nonzero
  467.  
  468.          mov       ax,0F000h
  469.          mov       es,ax
  470.          mov       di,-1
  471.          mov       cx,-1
  472.          std
  473.          mov       al,0CFh
  474.          repne     scasb          ; find an IRET in the BIOS
  475.          inc       di
  476.  
  477.          mov       dx,di
  478.          push      ds
  479.          push      es
  480.          pop       ds
  481.          mov       ax,252Fh
  482.          int       21h            ; point 2Fh to an IRET in the BIOS
  483.          pop       ds
  484.          jmp       short L103     ; now go and install it
  485. L100:
  486.          mov       ax,0FF00h      ; look for PRINT.COM
  487.          int       2Fh            ; if resident AH = print queue length
  488.          cmp       ah,0FFh        ; otherwise AH is unchanged
  489.          je        L101           ; use multiplex interrupt
  490.          mov       al,1
  491.          jmp       short L104     ; abort if PRINT.COM already installed
  492. L101:
  493.          mov       ax,[bp+6]      ; get interrupt ID number
  494.          mov       ah,al
  495.          xor       al,al
  496.          int       2Fh            ; poll for the ID number
  497.          test      al,al          ; installed already?
  498.          jz        L103           ; jump if ok to install
  499.          cmp       al,0FFh
  500.          jne       L102           ; jump if not already installed
  501.          mov       al,2
  502.          jmp       short L104     ; error, already installed
  503. L102:
  504.          mov       al,3
  505.          jmp       short L104      ; error, can't install
  506. L103:
  507.          xor       al,al
  508. L104:
  509.          xor       ah,ah
  510.          pop       bp
  511.          ret       2
  512.  
  513. Installed ENDP
  514.  
  515. CSEG ENDS
  516.  
  517. END
  518.