
;       Piano...
  
code    segment
 assume  cs:code

 org     100h

break   equ     6ch             ; break-code last pressed key
env     equ     2ch             ; address of environment
int_9   equ     24h             ; address of int 9 vector
keyb    equ     60h             ; port of keyboard
mode    equ     43h             ; port of 8255 mode register

new_9   equ     72h             ; address of new int 9 routine
old_9   equ     6eh             ; address of old int 9 vector
spkr    equ     61h             ; port of speaker
timer   equ     42h             ; port of timer 2 (speaker freq.)
  
piano   proc
  
  xor   ax,ax                   ; Get int 9 vector
  push  ds
  mov   ds,ax
  lds   bx,ds:int_9
  cmp   bx,new_9                ; Already installed?
  je    remove                  ; Yes? -> remove piano
  mov   di,old_9                ; Build tsr
  mov   ax,bx                   ; Save old int 9 vector
  stosw
  mov   ax,ds
  stosw
  mov   cx,offset mes1 - tsr    ; Place new int 9 routine
  mov   dx,di
  mov   si,offset tsr
  pop   ds
  rep   movsb
  mov   ax,2509h                ; Set new int 9 vector
  int   21h
  mov   ah,9                    ; Write message 'installed'
  mov   dx,si
  int   21h
  mov   dx,di                   ; Terminate and stay resident
  int   27h
remove:
  push  ds                      ; Restore old int 9 vector
  mov   ax,2509h
  lds   dx,ds:old_9
  int   21h
  mov   ah,49h                  ; Free memory tsr used
  pop   es
  int   21h
  mov   ah,49h                  ; Free memory environment of tsr used
  mov   es,es:env
  int   21h
  in    al,spkr                 ; Turn speaker off (just in case)
  and   al,-3
  out   spkr,al
  mov   ah,9                    ; Write message 'removed'
  mov   dx,offset mes2
  pop   ds
  int   21h
  ret                           ; just terminate

piano   endp

tsr     proc

  push  ax                      ; Save ALL registers used
  in    al,keyb                 ; Get key code
  test  al,80h                  ; Is it a break code?
  jz    tsr0                    ; No? -> plink
  cmp   cs:break,al             ; Is it the expected break code?
  jne   tsr1                    ; No? -> exit
  in    al,spkr                 ; Turn speaker off
  and   al,-3
  out   spkr,al
  jmp   short tsr1              ; -> exit
tsr0:
  mov   ah,al                   ; Transform make code into break code
  or    al,80h
  mov   cs:break,al             ; Save it
  mov   al,10110110b            ; Timer 2, LSB/MSB, square wave, binary count
  out   mode,al
  shr   ax,1                    ; Transform key code into frequenty
  out   timer,al
  mov   al,ah
  out   timer,al
  in    al,spkr                 ; Turn speaker on
  or    al,3
  out   spkr,al
tsr1:
  pop   ax                      ; Restore ALL registers used & exit
  jmp   dword ptr cs:old_9
tsr     endp

mes1    db 'Piano installed', 10, '$'
mes2    db 'Piano removed', 10, '$'

code    ends
 end     piano
