;-----------------------
; Here is some sample code extracted from an on-screen clock program I
; wrote.  Feel free to plagiarize it.  Timer int 08 is used to update the
; screen clock, keyboard int 09 is used to toggle the display.
;                          Mitch Ames


.radix  16
org     0100

start:  jmp     instal

;---------------------------------------------------------------------
; RESIDENT CODE

; System clock handler

int_08: pushf                           ;INT_08's IRET will pop flags
        call    dword ptr cs:org_08     ;call original vector first
        ; now do your stuff here, preserving all registers
        ; this code is called 18.2 times per second
        iret                            ;then quit

org_08  dd      ?                       ;original timer vector

; Keyboard interrupt, used to enable/disable clock
; Checks for hot-key control-alt-C

int_09: push    ax
        in      al,60                   ;read scan code
        cmp     al,2E                   ;check for hot key ("C")
        jne     end_09                  ;if not, pass control to BIOS
        push    ds
        mov     ax,40                   ;DS points to BIOS
        mov     ds,ax
        mov     al,ds:[17]              ;get shift flags
        pop     ds
        and     al,00001100b            ;keep only Ctrl and Alt
        cmp     al,00001100b            ;check for both pressed
        jne     end_09                  ;if not, pass control to BIOS
        mov     al,20                   ;signal end of interrupt
        out     20,al                   ;to controller
        sti                             ;allow other interrupts
        ; put your code here, preserving all registers
        ; it will run every time you press control-alt-C
finish: pop     ax
        iret                            ;finished

; come here if not your key
end_09: pop     ax
        jmp     far cs:[org_09]         ;jump to original handler

org_09  dd      ?                       ;original Int 09 code

;---------------------------------------------------------------------
; NON-RESIDENT CODE

instal: ; preprocessing goes here, including check for unload switch

        mov     ax,3508                 ;get current timer interrupt
        int     21
        mov     word ptr org_08,bx      ;save it
        mov     word ptr org_08+2,es
        mov     dx,offset int_08        ;point to new routine
        mov     ax,2508                 ;set interrupt
        int     21
        mov     ax,3509                 ;repeat for keyboard interrupt
        int     21
        mov     word ptr org_09,bx
        mov     word ptr org_09+2,es
        mov     dx,offset int_09
        mov     ax,2509
        int     21
        mov     dx,offset loaded        ;display message
        mov     ah,9
        int     21
        mov     ax,3100                 ;terminate and stay resident
        mov     dx,(instal-start+10F)/10;number of paragraphs to reserve
        int     21

; Unload TSR

unload:
        push    ds                      ;save program DS
        lds     dx,es:org_08            ;get original timer interrupt
        mov     ax,2508                 ;restore it
        int     21
        pop     ds                      ;restore program DS

        push    ds                      ;save program DS
        lds     dx,es:org_09            ;get keyboard interrupt
        mov     ax,2509                 ;restore it
        int     21
        pop     ds                      ;restore program DS
        push    es                      ;save TSR program segment
        mov     bx,es                   ;and copy to BX
        mov     ax,es:2C                ;get TSR's environment segment to AX
        push    ax                      ;save it
        dec     ax                      ;get memory control block's segment
        mov     es,ax                   ;to ES
        cmp     bx,es:[1]               ;check that environment block is still
                                        ;owned by TSR program block
        jne     fail                    ;quit if not
        pop     es                      ;restore TSR's environment segment
        mov     ah,49                   ;release memory
        int     21
        jc      fail
        pop     es                      ;restore TSR program segment
        mov     ah,49                   ;release memory
        int     21
        jc      fail
        mov     dx,offset removed       ;message if successful
        mov     al,0                    ;exit code = 0
        jnc     quit                    ;quit if succeeded
fail:   mov     dx,offset not_rem       ;message if failed
fail1:  mov     al,1                    ;exit code = 1
quit:   push    ax                      ;save exit code
        mov     ah,9                    ;write message in DS:DX
        int     21
        pop     ax                      ;restore exit code
        mov     ah,4C                   ;and quit
        int     21

loaded  db      "Clock loaded.",cr,lf,"$"
removed db      "Clock unloaded.",cr,lf,"$"
not_rem db      "Can't unload clock.",bell,cr,lf,"$"
