; ; telebell.asm: Change the teletype bell (Int10/AX=0E07). ; ; Jason Hood, 7 September, 1999. ; Public Domain. ; ; 14 & 15 October, 2003, v1.00: ; configurable frequency and duration; ; unloadable. ; .model tiny .code org 100h telebell: jmp install db 8, 8, 8 helpmsg db "Telebell by Jason Hood .", 13, 10 db "Version 1.00 (15 October, 2003). Public Domain.", 13, 10 db "http://misc.adoxa.cjb.net/", 13, 10 db 13, 10 db "Change the frequency and duration of the teletype bell.",13,10 db 13, 10 db "telebell [frequency] [=duration] [c|u]", 13, 10 db 13, 10 db " frequency bell tone (default is 440)", 13, 10 db " duration bell length in milliseconds (default is 50)",13,10 db " c load in conventional memory", 13, 10 db " u unload (if possible)", 13, 10 db 26, 8, " $" NOWARN ALN align 16 ; Below needs to be paragraph-aligned resident_begin label byte new_int_10 proc far cmp ax,0e07h ; Output bell using teletype je is_bell exit: db 0eah ; jmp far old_10 dw ?, ? is_bell: push ax push cx push dx mov ax, 8600h + 10110110b ; BIOS Wait, select 8253 out 43h, al ; Control port address mov al, 0 div_lo equ byte ptr $-1 out 42h, al ; Timer 2 address mov al, 0 div_hi equ byte ptr $-1 out 42h, al in al, 61h ; Get current value of control bits push ax or al, 3 out 61h, al ; Turn speaker on mov cx, 0 ; CX:DX delay in microseconds dur_hi equ word ptr $-2 mov dx, 0 dur_lo equ word ptr $-2 int 15h pop ax ; and al, not 3 ; Turn speaker off (assume off before) out 61h, al pop dx pop cx pop ax iret new_int_10 endp resident_end label byte resident_len = resident_end - resident_begin intdos MACRO function, service IFB mov ah, function ELSE mov ax, (function shl 8) + service ENDIF int 21h ENDM MCBName label byte no_msg db "Telebell cannot be uninstalled at this time.", 13, 10, '$' beep_div dw 440 beep_dur dw 50 umb dw 1 ; Link in UMB strat dw 81h ; Try high memory then low, best fit uninst: intdos 35h, 10h ; Get current Int10 mov di, bx mov si, offset new_int_10 mov cx, 6 ; Test if first six bytes match repe cmpsb mov dx, offset no_msg jne msg_out mov dx, es:old_10 ; Read original Int10 mov ds, es:old_10+2 intdos 25h, 10h ; Restore it mov ax, es ; Readjust the segment mov bx, offset resident_begin shr bx, 4 add ax, bx mov es, ax ; Free the memory intdos 49h intdos 4ch, 0 ; Exit install: cld mov si, 81h targ: lodsb cmp al, 13 je arg_done cmp al, ' ' je targ cmp al, '/' je targ cmp al, '-' je targ cmp al, 'u' je uninst cmp al, 'c' jne narg mov umb, 0 ; Don't link in UMB mov strat, 1 ; Low memory, best fit jmp targ narg: mov bx, offset beep_div cmp al, '=' jne num lodsb mov bx, offset beep_dur num: call getnum jnc targ mov dx, offset helpmsg ; Invalid option msg_out: ; or can't be uninstalled mov ah, 9 int 21h intdos 4ch, 0 ; Exit arg_done: mov dx, 12h ; 1 193 180 mov ax, 34dch ; --------- = divisor div beep_div ; frequency mov div_lo, al mov div_hi, ah mov ax, beep_dur ; Milliseconds mov cx, 1000 ; to microseconds mul cx mov dur_lo, ax mov dur_hi, dx sub ax, ax ; Get and zero the environment pointer xchg ax, ds:[2ch] mov es, ax ; Free its memory intdos 49h intdos 58h, 2 ; Get current UMB state push ax ; and save it intdos 58h, 0 ; Get current allocation strategy push ax ; and save it mov bx, umb ; Set UMB state intdos 58h, 3 mov bx, strat ; Set allocation strategy intdos 58h, 1 mov bx, (resident_len + 15) shr 4 intdos 48h ; Allocate the memory dec ax mov es, ax ; The MCB of the newly allocated memory inc ax mov word ptr es:[1], ax ; Make the memory block own itself pop bx ; Restore allocation strategy intdos 58h, 1 pop bx ; Restore UMB state intdos 58h, 3 mov si,offset MCBName ; Change the MCB name mov di,8 movsw movsw movsw movsw mov ax, es ; Adjust the segment for our offset mov bx, offset resident_begin shr bx, 4 ; xxxx:0000 = xxxx-12:0120 dec bx sub ax, bx push ax ; Remember resident segment intdos 35h, 10h ; Remember the old interrupt 10 mov old_10, bx mov old_10+2, es pop es ; Retrieve resident segment for reloc push es ; Remember it again for int10 mov si, offset resident_begin ; Relocate mov di, si mov cx, resident_len rep movsb mov dx, offset new_int_10 ; Point to the new interrupt 10 pop ds ; in the resident segment intdos 25h, 10h intdos 4ch, 0 ; Read a decimal word at [SI] into [BX]; AL should already contain the first ; digit. SI is updated to the end of the number. ; Returns CY if the number is zero. getnum proc near mov dl, al ; Get first digit mov dh, 0 sub ax, ax ; Store number into AX mov cx, 10 ; Base 10 gn: sub dl, '0' jb num_done cmp dl, 9 ja num_done push dx mul cx pop dx add ax, dx mov dl, [si] inc si jmp gn num_done: dec si mov [bx], ax cmp ax, 1 ret getnum endp end telebell