home *** CD-ROM | disk | FTP | other *** search
- title newinit.asm
- comment |--------------------------------------------------------------
- In text modes the active page can be switched between 1-4 (80-col) or
- 1-8 (40-col) by pressing ALT and the corresponding # on the TOP ROW. This
- feature can only be used to view the other pages. Results of all CON I/O
- while paging are unpredictable and messy.
- As protection against duplicate installation, INT 15h with AX = X'FF00'
- returns AX = X'ABCD'.
- The keypad "5" key will toggle processing. While paused, a flashing,
- highlighted "P" will appear in the lower-right corner (not graphics).
- If Numlock is on, shift-"5" is required. If Alt or Ctrl are pressed, nothing
- changes. Scroll Lock, Caps Lock, and Ins are irrelevant.
- This program sets the video mode to 80 col monochrome.
- The enhanced keyboard can be toggled on/off with Alt-PrtSc, and a 1/8 sec
- 2000 Hz tone will sound when toggled on. (The PrtSc modification cannot
- be turned off.)
- NOTE: If both shift keys are depressed at installation time, the
- installation will be cancelled, with errorlevel set to X'AB'.
- ------------------------------------------------------------------------|
- bios_data segment at 0040h
- org 17h
- kb_flag db ? ; keyboard status byte
- kb_flag_1 db ?
-
- org 49h
- v_mode db ? ; BIOS video mode
- v_width db ? ; BIOS screen width
-
- org 62h
- v_page db ? ; BIOS video page
- mystery_w dw ? ; word used by pause routine
- mystery_b db ? ; byte used by pause routine
- bios_data ends
-
- cseg segment
- assume cs:cseg
- org 80h
- parm_cnt db ? ; parameter count
- parm_data db ? ; start of parameter data space
- org 100h ; .COM file
-
- begin: jmp init_vectors ; initialize and attach to DOS
-
- ; addresses of video and keyboard I/O ROM routines
- prtsc dd 0 ; INT 5
- kybd dd 0 ; INT 9
- cass dd 0 ; INT 15h
- kybd_io dd 0 ; INT 16h
-
- ; constants and segments
- bios_dat dw 40h ; bios_data segment
- mono_seg dw 0b000h ; segment of MGA
- color_seg dw 0b800h ; segment of CGA
- datatbl db 2,3,0,1,6,4,5 ; scan-code to video mode data
- indicator equ "P"+256*10001111b ; an highlighted, flashing "P"
- row equ 24 ; position of indicator for mono moniter
- col equ 79
- mono_point equ 2*((row*80)+col) ; offset in mono segment
-
- ; variable data
- vdata db 0 ; current video mode or page
- code_seg dw 0 ; CS of resident routines
- graph_bit db 0 ; flag to signal graphics mode
- toggle db 1 ; enables/disables enhanced keyboard
-
- prtsc_int: sti ; enable interrupts
- push ax ; save regs
- push dx
- mov ah,2 ; read printer status
- xor dx,dx ; zero DX - LPT1
- int 17h ; printer I/O
- xor ah,30h ; check for OFFLINE
- jnz chk_shft ; skip beep, prepare for exit
- pop dx
- no_dump: pop ax
- iret
- chk_shft: pop dx
- push ds
- mov ds,bios_dat ; set DS = X'40'
- assume ds:bios_data
- test kb_flag,00000010b ; check for LEFT shift key
- pop ds ; restore regs
- jz no_dump ; skip screen dump if no LEFT shift
- pop ax
- jmp prtsc ; print screen routine
-
- calculate: assume ds:bios_data
- xor ax,ax ; zero AX
- xor cx,cx ; likewise
- mov al,v_width ; AX = 00 width
- mov cl,v_page ; save for later multiply
- mov bx,25 ; calculate offset into page
- mul bl
- dec ax ; = (25*width)-1
- shl ax,1 ; MUL AX,2 - skip attribute bytes
- mov bx,ax ; save in BX
- mov ax,2048 ; byte length of 40 column page
- cmp v_width,40 ; check for 40 column screen
- je multiply ; if yes, leave AX alone
- shl ax,1 ; if no, change to 80 column offset
- multiply: mul cx ; multiply by page number
- add bx,ax ; sum buffer offset with page offset
- mov es,color_seg ; load ES with CGA segment
- assume es:nothing
- skip_cga: mov cx,es:[bx] ; save screen data in CX
- mov word ptr es:[bx],indicator ; store flashing "P" on screen
-
- rejoin: ; branch made if graphics mode - skip indicator
-
- mov dx,mystery_w ; load mystery word
- add dx,4 ; more mysterious code
- mov al,mystery_b ; load mystery byte
- out dx,al ; I have no clue what this does
-
- call reset
- or kb_flag_1,00001000b ; turn ctrl-num-lock on
- sti ; enable interrupts
- again: test kb_flag_1,00001000b ; check if ctrl-num-lock on
- jnz again ; if on, check again
-
- cli ; disable interrupts (play it safe)
- test graph_bit,1 ; check if graphics mode
- mov graph_bit,0 ; reset graphics flag
- jnz skip_mov ; skip restoration of screen data
- mov es:[bx],cx ; restore screen data
- skip_mov: pop es ; restore regs
- pop dx
- pop cx
- pop bx
- pop ds
- pop ax
- iret
-
- pause: assume ds:bios_data ; DS set in FIVE: routine
- push bx ; save BX (for active page)
- push cx ; save CX to use as scratch register
- push dx
- push es
- cmp v_mode,4 ; check for text mode
- jb calculate ; continue if yes
- cmp v_mode,7 ; check for monochrome buffer
- jne no_p ; skip "P" if graphics
- mov es,cs:mono_seg ; point ES to segment at 0b000h
- mov bx,mono_point ; offset into monochrome segment
- jmp short skip_cga ; skip color setup
-
- no_p: mov graph_bit,1 ; set graphics mode flag
- jmp short rejoin ; rejoin main code
-
- yes: and kb_flag_1,11110111b ; turn ctrl-num-lock off
- call reset ; reset keyboard
- pop ds
- pop ax
- iret
-
- assume ds:nothing
- five: push ds ; save data segment
- mov ds,cs:bios_dat ; point to keyboard data
- assume ds:bios_data
- test kb_flag_1,00001000b ; check if Ctrl-NumLock on
- jnz yes ; if yes, unpause
- mov al,kb_flag ; get shift key status byte
- test al,00001100b ; check for Alt or Ctrl pressed
- jnz quit ; exit if so
- and al,00100011b ; isolate NumLock and Shift bits
- jz pause ; if zero (none pressed) then go!
- cmp al,00100000b
- ja pause ; both NumLock & Shift must be pressed
- ; if not, then end
- assume ds:nothing
- quit: pop ds ; restore regs
- pop ax
- jmp kybd ; goto BIOS
-
- assume ds:nothing
- ; intercepts INT 9
- kybd_int: push ax ; save reg
- in al,60h ; get scan code
- cmp al,37h ; scan code of PrtSc key
- je tog_chk ; check for Alt pressed before toggling
- test toggle,1 ; check if enhanced keyboard enabled
- jz off ; if not, skip enhanced processing
- cmp al,4ch ; scan code of keypad "5" ?
- je five ; if yes, check further
- cmp al,46h ; check for Scroll-Lock (Break) key
- je break ; if so, look for Ctrl-Shift
- off: pop ax ; if not, restore reg and
- jmp kybd ; goto BIOS
-
- ; check for right-shift-Ctrl
- break: push ds ; save reg
- mov ds,bios_dat ; set DS to bios data segment
- assume ds:bios_data
- test kb_flag_1,00001000b ; check if ctrl-num-lock on
- jnz quit ; goto BIOS if yes
- test kb_flag,00000001b ; right shift key pressed?
- jz quit
- test kb_flag,00000100b ; check for Ctrl key pressed
- jz quit
- call reset
- mov ax,4ccah ; DOS EXIT function 4C
- ; ErrorLevel = 202
- int 21h
- pop ds ; restore regs
- pop ax
- iret ; return from key interrupt
-
- tog_chk: push ds ; save DS
- mov ds,bios_dat ; point DS to bios data segment
- assume ds:bios_data
- test kb_flag_1,00001000b ; check for Ctrl-NumLock pause on
- jnz quit ; goto BIOS if yes
- test kb_flag,00000111b ; check for Ctrl or L/R shift pressed
- jnz quit ; don't toggle if yes - send key to bios
- test kb_flag,00001000b ; check for Alt pressed
- jz quit ; don't toggle if no - send key to bios
- xor toggle,1 ; toggle
- jz skip_beep ; skip beep if toggled off
- push cx ; save count reg for delay
- ; beep
- ; Step 1 -- prepare the timer to receive its divisor
- mov al,0b6h ; timer mode register signal
- out 67,al ; output to timer control port
- ; Step 2 -- send the divisor count to the timer
- ; Divisor = (1,190,000 / desired frequency)
- mov ax,595 ; divisor for 2000 Hz
- out 66,al ; output low-order byte of divisor
- mov al,ah ; high-order byte to output reg
- out 66,al ; output high-order byte of divisor
- ; Step 3 -- turn on the two bits which activate the speaker, and the
- ; timer's control of the speaker
- in al,97 ; get current bit settings - port 97
- mov ah,al ; save port 97 to turn sound off
- or al,03 ; turn on last two bits
- out 97,al ; send back the new value
-
- mov cx,8000h ; approx 1/8 second
- delay: loop delay ; sounding tone while counting
- mov al,ah ; restore original port 97
- out 97,al ; stop tone
- pop cx ; restore count reg
-
- skip_beep: call reset ; reset kybd and interrupt controller
- pop ds ; restore regs
- assume ds:nothing
- pop ax
- iret
-
- reset proc
- in al,61h ; reset keyboard
- mov ah,al
- or al,80h
- out 61h,al
- mov al,ah
- out 61h,al
- mov al,20h ; send end-of-interrupt signal
- out 20h,al ; to interrupt controller
- ret
- reset endp
-
- assume ds:nothing
- cass_int: cmp ax,0ff00h ; duplicate installation protection
- je duped ; yes
- jmp cass ; no, goto BIOS
- duped: mov ax,0abcdh
- iret
-
- nope: jmp kybd_io ; goto BIOS
-
- assume ds:nothing
- kybd_io_int:
- test toggle,1 ; check if enhanced keyboard enabled
- jz nope ; if not, goto bios
- test ah,ah ; check for AH = 0 (read key)
- jnz nope ; if not, goto bios
- pushf ; simulate INT 16h
- call kybd_io
- test al,al ; check for zero char code
- jz extend ; continue if extended character
- iret ; return if not
-
- extend: cmp ah,53h ; skip predefined ext. functions
- ja ext ; extended function routine(s)
- back: iret ; return if predefined
-
- ; branch made if code greater than predefined (3-53h)
- ext: cmp ah,94 ; check for F21 (CTRL-F1)
- jb back ; end if below
- cmp ah,103 ; CTRL-F10 - 67h
- ja next ; goto next function
-
- push dx ; save DX
- push ax ; save scan code
-
- mov ah,2 ; read printer status
- xor dx,dx ; zero DX - LPT1
- int 17h ; printer I/O
- xor ah,30h ; check for OFFLINE
- jz offline ; skip beep, prepare for exit
-
- pop ax ; retrieve scan code
- push bx
- push cx
- sub ah,94 ; bring scan code down to 0-9
- ; mult AH by 3
- mov bl,ah ; save ah
- shl ah,1 ; mult by 2
- add bl,ah ; mult by 3
- xor bh,bh ; zero BH
- add bx,offset PRNT_BUF ; add mem loc to offset
- mov cx,3 ; 3-char printer output
- xor dx,dx ; printer zero
-
- loop1: mov al,3 ; full offset
- sub al,cl ; sub count from full offset
- xlat cs:prnt_buf ; get data in AL
- cmp al,0ffh ; check for end-of-string
- je beep ; beep if EOS
- xor ah,ah ; zero AH - print char
- int 17h ; BIOS printer I/O
- loop loop1 ; next char
-
- beep: cmp cl,3 ; check for null string
- je p_end ; skip beep if null
- mov ax,0007 ; printer output / BEL
- int 17h ; BIOS printer I/O
- mov ax,000dh ; printer output / CR
- int 17h ; BIOS printer I/O
-
- p_end: pop cx
- pop bx
- sub sp,2 ; fool next POP
- offline: pop ax
- pop dx
- xor ax,ax ; zero AX (read_char)
- back3: jmp kybd_io_int ; goto BIOS for next key
-
- next: cmp ah,113 ; code > Alt-F10 ?
- ja next1 ; yes - goto
- je cls ; if code = Alt-F10 - execute CLS
- cmp ah,110 ; Alt-F7 < code < Alt-F10 ?
- ja back3 ; null processing
-
- push bx ; save base reg for XLAT
- mov al,ah ; copy key code into AL for XLAT
- sub al,104 ; bring key-code to 0-6
- mov bx,offset datatbl ; look-up table of video modes
- xlat cs:datatbl
- xor ah,ah ; zero AH for INT 10h
- int 10h
- pop bx ; restore BX
- ; AH already zero - read_key
- jmp kybd_io_int ; goto bios
-
- cls: push bx
- push cx
- push dx
- push ds
- mov ds,bios_dat
- assume ds:bios_data
- mov bh,7 ; attribute to use on blank window
- xor cx,cx ; upper left corner = 0,0
- mov dh,24 ; bottom row to clear
- mov dl,v_width ; bios video width byte
- dec dx ; bios byte is either 40/80
- mov ax,600h ; AH=6 (scroll up) AL=0 (blank window)
- int 10h
- mov bh,v_page ; get current video page
- xor dx,dx ; upper left corner
- mov ah,2 ; position cursor
- int 10h
-
- assume ds:nothing
- pop ds ; restore regs
- pop dx
- pop cx
- pop bx
- xor ax,ax ; read_key
- jmp kybd_io_int ; get next key
-
- ; code greater than 110, ALT-F7
- next1: cmp ah,78h ; ALT-1 (top row)
- jb end_ext ; end routine
- cmp ah,127 ; check code > ALT-8
- ja end_ext
- push bx ; save regs
- push ax
- mov ah,15 ; read video state
- int 10h
- mov vdata,al ; save current mode
- cmp al,3 ; check for graphics modes
- ja back1 ; end if graphics
- pop ax ; retrieve char code
- mov al,ah ; char code into page result reg
- sub al,78h ; bring char code down to page code
- cmp al,4 ; check for valid code 80 or 40
- jb skip1 ; change if valid unconditionally
- cmp vdata,1 ; check for 40 col display
- ja back2 ; end if 80 col
- skip1: mov ah,5 ; select active display page
- int 10h
- jmp short back2 ; finished
-
- end_ext: ; if key code not defined here,
- iret ; give other routines a chance
-
- back1: add sp,2 ; skip AX on stack
- back2: pop bx ; restore BX
- xor ax,ax ; zero AH - read key
- jmp kybd_io_int ; get another char
-
- ; control codes for Gemini (Epson compatible)
- prnt_buf db 27,"V",1 ; slashed-zero F1
- db 27,"@",0ffh ; power-on reset F2
- db 27,"B",1 ; 10 cpi (80 col) F3
- db 15,0ffh,00 ; 17 cpi (132 col) F4
- db 27,"E",0ffh ; emphasized on F5
- db 27,"F",0ffh ; emphasized off F6
- db 27,"S",0 ; superscript mode F7
- db 27,"S",1 ; subscript mode F8
- db 27,"U",1 ; unidirectional F9
- db 27,"U",0 ; bidirectional F10
-
- end_of_resident:
-
- print_help:
- xor cx,cx ; upper left row/column
- mov dx,184fh ; lower right row/column
- mov bh,7 ; attribute for blank region
- mov ax,600h ; scroll up/blank entire window
- int 10h
- mov ah,15 ; get video data
- int 10h ; active page in BH
- xor dx,dx ; upper left row/column
- mov ah,2 ; set cursor position
- int 10h
- mov dx,offset help_text ; get address of help screen
- mov ah,9 ; DOS print string
- int 21h
- mov ax,0ff00h ; check (again) for duplicate installation
- int 15h
- cmp ax,0abcdh
- je skip_prnt ; if yes, skip printing install instructions
- mov dx,offset not_yet ; message - type newinit install
- mov ah,9 ; DOS print string
- int 21h
- skip_prnt: int 20h ; terminate
-
- init_vectors:
- mov ds,bios_dat
- assume ds:bios_data
- mov al,kb_flag ; get keyboard status byte
- xor al,00000011b ; check if both shift keys pressed
- jnz continue ; if not, continue with installation
- mov ax,4cabh ; DOS EXIT function, ERRORLEVEL = X'AB'
- int 21h
-
- continue: mov ax,cs ; set data segment to code segment
- mov ds,ax
- assume ds:cseg
- mov code_seg,ax ; save code segment for resident routine
- xor cx,cx ; zero CX
- mov cl,parm_cnt ; get number of parameters
- jcxz print_help ; print help screen
- mov si,offset parm_data ; start of parameter line
- cld ; clear DF to increment SI
- loop2: lods parm_data ; get byte from parm_data
- cmp al,"Z"+1 ; check if lower case
- jb lp2
- sub al,"a"-"A" ; convert to lower case
- mov [si-1],al ; put back into param line
- lp2: loop loop2 ; get next char
-
- check: mov di,offset parm_data
- mov al,"I" ; search for "I"
- mov cl,parm_cnt ; number of characters to search
- repne scasb ; scan parameter line
- jne print_help ; print help screen if not found
- mov si,1 + offset key ; "INSTALL" but past the "I"
- assume es:cseg
- repne cmps parm_data,key ; check for key in parameter line
- jne print_help ; if not found, print help screen
- mov ax,0ff00h ; if found, check for prev install
- int 15h ; cassette (snicker!) interrupt
- cmp ax,0abcdh ; duplicate installation code
- jne install ; full speed ahead
- mov dx,offset already ; error message
- mov ah,9 ; DOS print string
- int 21h
- int 20h ; bye-bye
-
- install: mov ax,2 ; AH=0 - set video mode
- ; AL=2 - 80 col mono
- int 10h
- mov ax,3505h ; get int vector for INT 5
- int 21h
- mov word ptr prtsc,bx ; save routine offset
- mov word ptr prtsc[2],es ; save routine segment
- mov dx,offset prtsc_int ; offset of new routine
- ; DS = CS above
- mov ah,25h ; set int vector for INT 5
- int 21h
-
- mov ax,3509h ; get int vector for INT 9
- int 21h
- mov word ptr kybd,bx ; save offset
- mov word ptr kybd[2],es ; save segment
- mov dx,offset kybd_int ; offset of user routine
- mov ah,25h ; set int vector
- int 21h
-
- mov ax,3515h ; get int vector for INT 15h
- int 21h
- mov word ptr cass,bx ; save offset
- mov word ptr cass[2],es ; save segment
- mov dx,offset cass_int ; offset of user routine
- mov ah,25h ; set int vector
- int 21h
-
- mov ax,3516h ; get int vector for INT 16h
- int 21h
- mov word ptr kybd_io,bx ; save offset
- mov word ptr kybd_io[2],es ; save segment
- mov dx, offset kybd_io_int ; offset of user routine
- mov ah,25h ; set int vector
- int 21h
-
- mov dx,offset installed ; completed message
- mov ah,9 ; DOS print string
- int 21h
- mov dx,offset end_of_resident
- int 27h ; terminate, remain resident
-
- key db "INSTALL" ; installation text key
-
- already db 13,10,10,9,9
- db "This utility already resident.",13,7,10,10,"$"
-
- installed db 9,9,"NEWINIT is up and running.",10,10,"$"
-
- help_text: db "This resident program modifies certain key combinations:",13,10
- db "1) PrtSc will only work if the left shift key is used.",13,10
- db "2) Ctrl-Right-Shift-Break forces a DOS function call X'4C' (EXIT) which will"
- db 13,10
- db " exit the current program. This avoids much of the need for Ctrl-Alt-Del."
- db 13,10
- db " If exit is forced in this manner, errorlevel is set to X'CA' (202).",13,10
- db "3) Alt-1 thru Alt-8 (top row) will VIEW that display page (I/O not reliable)."
- db 13,10
- db "4) Alt-F1 thru Alt-F7 change the video mode.",13,10
- db " F1 = 80 col mono (at startup) F2 = 80 col color",13,10
- db " F3 = 40 col mono F4 = 40 col color",13,10
- db " F5 = med res mono graphics F6 = medium res color graphics",13,10
- db " F7 = high res graphics F10 = clears the current display page"
- db 13,10
- db "5) Ctrl-F1 thru Ctrl-F10 send (Epson) control codes to the printer.",13,10
- db " F1 = slashed-zero F2 = power-on reset",13,10
- db " F3 = 10 cpi (80 col) F4 = 17 cpi (132 col)",13,10
- db " F5 = emphasized on F6 = emphasized off",13,10
- db " F7 = superscript mode F8 = subscript mode",13,10
- db " F9 = unidirectional F10 = bidirectional",13,10
- db "6) The keypad '5' key is a toggle pause key. While on, the letter P is"
- db 13,10
- db " displayed, flashing and highlighted, in the lower right corner.",13,10
- db "7) Alt-PrtSc will toggle the enhanced keyboard on/off. A beep signals on."
- db 13,10,10,"$"
-
- not_yet db 9,"To make NEWINIT resident, type: newinit install",13,10,10,"$"
-
- cseg ends
- end begin
-
- move alt-fn and ctrl-fn to int-9
-