home *** CD-ROM | disk | FTP | other *** search
- ; EPSONSET is a memory-resident program that sends control codes to an
- ; Epson-compatible printer. After EPSONSET is installed, it may be invoked
- ; at any time by pressing the CTRL and the right-SHIFT keys simultaneuosly.
- ; This causes a window to pop up, inviting the user to press a choice
- ; of function keys to send codes to the printer. The window is deactivated
- ; when the ESC key is pressed.
-
- EPSONSET:
- JMP >L1 ; skip over the copyright message
-
- DB '(C) Copyright 1986, Ziff-Davis Publishing Company ',01A
-
-
- ; The first part of our program exists only at installation time. The buffer
- ; OLD_IMAGE is declared at location 0 in our code segment; so our PSP and
- ; all of our installation code will be destroyed the first time our window
- ; is popped up.
-
- OLD_IMAGE EQU 0
-
- W_LINES EQU 19 ; height of the pop-up window
- W_COLS EQU 28 ; width of the pop-up window
- W_SIZE EQU W_LINES * W_COLS ; number of chars in the window
- IMAGE_SIZE EQU W_SIZE * 2 ; number of bytes in a video window image
-
- W_ROW EQU 2 ; row number (0-24) of the top of the window
- W_COLUMN EQU 26 ; column number (0-79) of start of the window
- VIDEO_OFFSET EQU W_ROW*160 + W_COLUMN*2 ; offset of the pop-up window
- VIDEO_GAP EQU 160-W_COLS*2 ; gap between successive window lines
-
- L1:
- CALL MAKE_WINDOW_IMAGE ; construct the video image of our pop-up window
- CALL ADJUST_PCJR ; if we are on a PCJr then adjust the cursor
- CALL NEW_KB_VECTOR ; replace the keyboard-interrupt handler
- MOV DX,END_OF_PROGRAM ; point DX to the end of our resident section
- INT 027 ; terminate but stay resident
-
-
- ; MAKE_WINDOW_IMAGE determines the appropriate attribute bytes for our pop-up
- ; window, combines those bytes with the text from WINDOW_SOURCE, and
- ; places the conglomeration into WINDOW_IMAGE.
-
- KEYBOARD_INT DD 0:9*4
-
- MAKE_WINDOW_IMAGE:
- CLD ; string scanning is forward
- MOV AH,15 ; BIOS function number for GET_VIDEO_MODE
- INT 010 ; set AL to the video mode
- CMP AL,7 ; is it a monochrome mode?
- MOV AX,0704F ; load color attributes in case it isn't
- IF E MOV AX,0770 ; if monochrome then load the monochrome attributes
- MOV SI,WINDOW_SOURCE ; point SI to table of text
- MOV DI,WINDOW_IMAGE ; point DI to the storage area
- CALL COPY_4_LINES ; create the first four lines
- MOV BX,11 ; load the count of the second-attribute lines
- L1: ; loop here for each of the middle 11 lines of window
- MOVSB ; copy the left-border byte to the buffer
- STOSB ; output the first attribute byte, to complete the word
- MOV CX,W_COLS-2 ; load the number of bytes in the middle of the line
- XCHG AL,AH ; swap the second attribute byte into AL
- CALL COPY_ATTRIBUTE ; output the middle of the line
- XCHG AL,AH ; swap the first attribute byte back to AL
- MOVSB ; copy the right-border byte to the buffer
- STOSB ; output the first attribute byte, to complete the word
- DEC BX ; count down the middle lines
- JNZ L1 ; loop if more; else drop to make the last 4 lines
- COPY_4_LINES: ; copy 4 lines, attribute AL, to video image
- MOV CX,4 * W_COLS ; load the number of characters in 4 lines
- COPY_ATTRIBUTE: ; copy CX bytes from SI to words at DI with attr. AL
- MOVSB ; copy the text byte
- STOSB ; output the attribute byte to complete the video word
- LOOP COPY_ATTRIBUTE ; loop for the next text byte
- RET
-
-
- ; ADJUST_PCJR checks to see if we are a PCJr, and if we are, resets the
- ; cursor and corrects the CURSOR_MODE word at 0040:0060.
-
- MACHINE_ID DD 0F000:0FFFE ; pointer to ROM identification byte
- CURSOR_MODE DD 040:060 ; pointer to cursor mode word
-
- ADJUST_PCJR:
- LES DI,MACHINE_ID ; point to the identification byte for this machine
- MOV AL,0FD ; load the ID to the PCJr
- SCASB ; is this a PCJr?
- JNE RET ; no, then skip this routine
- LES DI,CURSOR_MODE ; point to the BIOS's cursor mode indicator
- MOV AX,0607 ; load our new value for the indicator
- STOSW ; store the new value in the BIOS area
- XCHG CX,AX ; swap the value into CX, for a BIOS call
- MOV AH,1 ; BIOS function number for SET_CURSOR_SIZE
- INT 010 ; set cursor to scan-lines 6 and 7 in character block
- RET
-
-
- ; NEW_KB_VECTOR saves the old keyboard interrupt vector, and replaces it with
- ; the new one.
-
- NEW_KB_VECTOR:
- LDS SI,KEYBOARD_INT ; point DS:SI to INT 9 in the vector table
- MOV DI,OFFSET OLD_KB_INT ; point ES:DI to our storage for old INT 9 vector
- MOV ES,CS
- CLI ; disable all interrupts but NMI
- MOV AX,OUR_HANDLER ; point to our new handler
- XCHG AX,[SI] ; store new handler offset and fetch the old one
- STOSW ; store the old handler offset
- MOV AX,CS ; point to this code segment
- XCHG AX,[SI+2] ; store new segment and fetch the old one
- STOSW ; store the old handler segment
- STI ; re-enable interrupts
- RET
-
-
- ; WINDOW_SOURCE contains the text to be used to construct the pop-up window.
- ; Our program will combine this text with attribute bytes, to make a video
- ; image.
-
- WINDOW_SOURCE:
- DB 201, W_COLS-2 DUP 205 ,187
- DB 186,' PRINTER SETUP MENU ',186
- DB 186,' EPSON RX/FX PRINTERS ',186
- DB 199, W_COLS-2 DUP 196 ,182
- DB 186,' F1 Compressed Mode ',186
- DB 186,' F2 Expanded Mode ',186
- DB 186,' F3 Emphasized Mode ',186
- DB 186,' F4 Double-Strike Mode ',186
- DB 186,' F5 Elite Mode ',186
- DB 186,' F6 Miniature Mode ',186
- DB 186,' F7 Skip Perforation ',186
- DB 186,' F8 Indent Left Margin ',186
- DB 186,' F9 Reset Top-of-Form ',186
- DB 186,' F10 Reset Print Modes ',186
- DB 186,' ESC Exit ',186
- DB 199, W_COLS-2 DUP 196 ,182
- DB 186,' Unshifted: Toggle ON ',186
- DB 186,' Shifted: Toggle OFF ',186
- DB 200, W_COLS-2 DUP 205 ,188
- W_SIZE EQU ($-WINDOW_SOURCE)
-
-
-
- ;-----------------------------------------------------------------------------
- ; Above this point is the part of the program that exists only when we
- ; being installed. Everything above this point is wiped out by
- ; the filling of OLD_IMAGE when our window is popped up.
-
-
-
- TRUE EQU (0 LT 1) ; define TRUE so following line is an assertion
- TRUE EQU ($ LT IMAGE_SIZE) ; insure we haven't used up too much room
- ORG IMAGE_SIZE ; now there's enough room for OLD_IMAGE
-
-
- OLD_KB_INT DD ? ; storage for old keyboard interrupt vector
- CURSOR_TYPE DW ? ; cursor scan line definition saved from user screen
- WINDOW_ACTIVE? DB 0 ; NZ if our pop-up window is already active
- ENABLE_VALUE DB ? ; video-chip programming value for the user's screen
- VIDEO_SEG DW ? ; segment address of the current memory-mapped video
-
-
- ; CODE_TABLE gives the codes to be output to the printer for each successive
- ; function key that can be pressed when the window is popped up. The
- ; 255 terminator bytes are also used to locate the code for a given key.
-
- CODE_TABLE:
- DB 15,255 ; F1: compressed mode on
- DB 27,87,1,255 ; F2: expanded mode on
- DB 27,69,255 ; F3: emphasized mode on
- DB 27,71,255 ; F4: double-strike mode on
- DB 27,77,255 ; F5: elite mode on
- DB 15,27,83,0,27,65,6,255 ; F6: miniature mode on
- DB 27,78,12,255 ; F7: perfskip on
- DB 27,108,10,255 ; F8: indent left margin
- DB 27,67,66,255 ; F9: reset top-of-form
- DB 18,27,87,0,27,70,27,72 ; F10: reset print modes
- DB 27,80,27,84,27,50,255 ; (continued)
- DB 18,255 ; Shift-F1: compress off
- DB 27,87,0,255 ; Shift-F2: expand off
- DB 27,70,255 ; Shift-F3: emphasize off
- DB 27,72,255 ; Shift-F4: double-strike off
- DB 27,80,255 ; Shift-F5: elite off
- DB 18,27,84,27,50,255 ; Shift-F6: miniature off
- DB 27,79,255 ; Shift-F7: perfskip off
- DB 27,108,0,255 ; Shift-F8: indent off
-
-
-
- ; OUR_HANDLER is our replacement for the INT 9 keyboard handler. We save
- ; registers, then call the old keyboard handler. If CTRL+RIGHT_SHIFT is
- ; pressed, we activate our code. Otherwise, we exit as if we were the
- ; old handler.
-
- OUR_HANDLER:
- STI ; enable software interrupts
- PUSH AX ; hot-key check clobbers AX only so save it
- IN AL,0A0 ; re-enable NMI on PCjr
- PUSHF ; simulate interrupt call to old keyboard routine
- CS CALL OLD_KB_INT ; call old routine
- MOV AH,2 ; BIOS function number for GET_SHIFT_STATUS
- INT 016 ; set AL to the shift-status bitmap
- AND AL,5 ; mask the map down to the CTRL and RIGHT_SHIFT keys
- CMP AL,5 ; are CTRL and RIGHT_SHIFT depressed?
- JNE AX_EXIT ; exit if they are-- we're already activated
- PUSH BX,CX,DX,SI,DI ; save the other general registers
- PUSH DS,ES ; also save segment registers
- MOV DS,ES,CS ; set ES and DS to the code segment
- TEST WINDOW_ACTIVE? ; is the window already open?
- JNZ EXIT ; if yes then ignore request
- MOV AH,15 ; BIOS function number for GET_VIDEO_STATUS
- INT 010 ; set AL = video mode, BH = video page number
- MOV AH,0 ; ENABLE_BYTE is zero for video mode 7
- MOV CX,0B000 ; VIDEO_SEG is 0B000 for video mode 7
- CMP AL,7 ; is the video mode 7 (monochrome)?
- JE >L0 ; jump if yes, that's an acceptible mode
- MOV CH,0B8 ; VIDEO_SEG is 0B800 for page 0, color modes
- ADD CH,BH ; advance VIDEO_SEG to the proper value for this page
- MOV AH,02D ; ENABLE_BYTE is 02D for video mode 2
- CMP AL,2 ; is the video mode 2?
- JE >L0 ; jump if yes, that's also an acceptible mode
- MOV AH,029 ; ENABLE_BYTE is 029 for video mode 3
- CMP AL,3 ; not 7 or 2; it had better be 3
- JNE EXIT ; error if not
- L0:
- CALL POPUP_WINDOW ; everything's OK so pop up our window
- JMP SHORT NEXT_KEY ; jump into the interactive loop
-
-
- ; ESC_SEEN is jumped to when the ESC key is pressed. The window is refilled
- ; with its original contents, the cursor is restored, and control is handed
- ; back to the application program.
-
- ESC_SEEN:
- CALL VIDEO_DISABLE ; if not then turn off the display
- MOV SI,OLD_IMAGE ; point SI to the buffer area
- CALL MEM_TO_VIDEO ; write the buffer contents to the display
- CALL VIDEO_ENABLE ; if not then turn display back on
- MOV CX,CURSOR_TYPE ; fetch the user's cursor type
- MOV AH,1 ; BIOS function number for SET_CURSOR_SIZE
- INT 010 ; restore the user's cursor
- MOV WINDOW_ACTIVE?,0 ; the window is no longer active
- EXIT: ; common exit point
- POP ES,DS ; restore interrupted segment registers
- POP DI,SI,DX,CX,BX ; restore interrupted general registers
- AX_EXIT: ; exit here if we saved AX only
- POP AX ; restore interrupted AX
- IRET ; return from interrupt
-
-
- ; NEXT_KEY is the main loop for the interactive portion of our handler. We
- ; intercept all keystrokes while our window is open, and act on them.
- ; This interactive mode is terminated when the ESC key is seen.
-
- FUNC EQU 58 ; defining code for non-shifted function keys
- SHIFT_F EQU 83 ; defining code for shifted function keys
-
- BEEP_KEY: ; jump here if an illegal key is seen
- CALL BEEP ; beep and wait for another keypress
- NEXT_KEY:
- MOV AH,0 ; BIOS function code for GET_KEY
- INT 016 ; fetch a keystroke from the BIOS
- CMP AL,27 ; is it the ESC key?
- JE ESC_SEEN ; jump if it is, to exit our interactive mode
- CMP AL,0 ; is it an extended code?
- JNE BEEP_KEY ; error if not
- MOV AL,AH ; move the extended code into AL, for examination
- CMP AL,FUNC 1 ; less than F1?
- JB BEEP_KEY ; yes, then don't accept it
- CMP AL,SHIFT_F 8 ; greater than Shift-F8?
- JA BEEP_KEY ; yes, then don't accept it
- CMP AL,FUNC 10 ; between F1 and F10?
- JBE >L1 ; jump if yes -- unshifted function key
- CMP AL,SHIFT_F 1 ; between Shift-F1 and Shift-F9?
- JB BEEP_KEY ; error if not
- SUB AL,15 ; adjust so Shift-F1 has an index of 10
- L1:
- SUB AL,FUNC 1 ; adjust so F1 has an index of 0
- CBW ; extend the index AL to AX
- XCHG CX,AX ; swap the index into CX
- MOV SI,CODE_TABLE ; point to the first of our code sequences
- JCXZ >L3 ; skip if our index is zero
- L2: ; loop here for each code byte to be skipped
- LODSB ; fetch a code byte
- CMP AL,255 ; is it a terminator?
- JNE L2 ; if yes then loop without counting down the index
- LOOP L2 ; terminator: count down index and loop for next line
- L3:
- CALL LPT1_ERROR? ; check for printer ready
- JNZ BEEP_KEY ; beep if printer not ready
- MOV BL,255 ; specify delimiter for call to LPRINTZ
- CALL LPRINTZ ; send control code string to printer
- JMP NEXT_KEY ; return for another keypress
-
-
- ; POPUP_WINDOW saves the current video state, then overlays our window
- ; on the screen.
-
- POPUP_WINDOW:
- MOV VIDEO_SEG,CX ; store our video segment
- MOV ENABLE_VALUE,AH ; store hardware value for re-enabling the screen
- CLD ; all string scanning is forward
- INC WINDOW_ACTIVE? ; store the fact that the window is now active
- MOV AH,3 ; BIOS function number for READ_CURSOR
- INT 010 ; set CX to the cursor type (scan-line boundaries)
- MOV CURSOR_TYPE,CX ; save the cursor type
- MOV CH,32 ; load impossible scan-line number
- MOV AH,1 ; BIOS function number for SET_CURSOR_SIZE
- INT 010 ; the cursor is now invisible
- CALL VIDEO_DISABLE ; turn display off for snow-free writing
- MOV DS,VIDEO_SEG ; fetch the video segment in effect
- MOV DI,OLD_IMAGE ; set DI to buffer area to save screen contents
- CALL VIDEO_TO_MEM ; then transfer screen contents to buffer
- MOV ES,DS ; set ES to video memory
- MOV DS,CS ; reset DS to code segment
- LEA SI,WINDOW_IMAGE ; point SI to window image
- CALL MEM_TO_VIDEO ; and write the window to the display
- VIDEO_ENABLE:
- MOV AL,ENABLE_VALUE ; fetch the re-enable hardware value
- TEST AL ; are we in monochrome mode?
- JZ RET ; return if yes, we never disabled the screen
- MOV DX,03D8 ; address the CGA Mode Control Register
- OUT DX,AL ; output the ENABLE_VALUE to the control register
- RET
-
-
-
- ; VIDEO_ENABLE and VIDEO_DISABLE manipulate bit 3 of port 3D8H, the CGA Mode
- ; Control Register, to temporarily turn the display on or off. Since these
- ; routines write directly to hardware, they have no effect on other video
- ; adapters.
-
- VIDEO_DISABLE:
- TEST ENABLE_VALUE ; are we in monochrome mode?
- JZ RET ; return if yes-- snow is not a problem
- MOV DX,03DA ; address CGA status port
- L1: ; loop here until we see vertical retrace
- IN AL,DX ; fetch the status directly from hardware
- TEST AL,8 ; mask the vertical-retrace bit
- JE L1 ; loop if we do not yet see vertical retrace
- MOV DL,0D8 ; retrace is seen: address the Control Register
- MOV AL,025 ; this value will disable the display
- OUT DX,AL ; the display is disabled
- RET
-
-
-
- ; VIDEO_TO_MEM copies a window from the video segment DS, to a memory buffer at
- ; ES:DI.
-
- VIDEO_TO_MEM:
- MOV BL,W_LINES ; load the number of lines in a window
- MOV SI,VIDEO_OFFSET ; point to our window within the video segment
- L1: ; loop here to copy each line
- MOV CX,W_COLS ; load the number of columns in the line
- REP MOVSW ; transfer one line
- ADD SI,VIDEO_GAP ; advance SI to next line address
- DEC BL ; count down lines
- JNZ L1 ; loop until all lines are done
- RET
-
-
-
- ; MEM_TO_VIDEO writes a window from memory at DS:SI to the video segment ES.
-
- MEM_TO_VIDEO:
- MOV BL,W_LINES ; load the number of lines in a window
- MOV DI,VIDEO_OFFSET ; point to our window within the video segment
- L1: ; loop here to copy each line
- MOV CX,W_COLS ; load the number of columns in the line
- REP MOVSW ; transfer one line
- ADD DI,VIDEO_GAP ; advance DI to next line address
- DEC BL ; count down lines
- JNZ L1 ; loop until all lines are done
- RET
-
-
-
- ; LPRINTZ routine sends a string of bytes, delimited by BL, from DS:SI to
- ; LPT1: thru INT 17h.
-
- L1: ; loop here to send AL to the printer
- MOV DX,0 ; printer no. 0 (LPT1:)
- MOV AH,0 ; BIOS function number for SEND_BYTE_TO_PRINTER
- INT 017 ; send the byte
- LPRINTZ:
- LODSB ; get one byte
- CMP AL,BL ; is it the delimiter?
- JNE L1 ; loop if not, to output the byte
- RET
-
-
- ; LPT1_ERROR? checks the current status of printer LPT1:. If it's either
- ; powered off or off-line, then we return NZ to signal an error condition.
- ; If LPT1 is ready, we return Z.
-
- LPT1_ERROR?:
- SUB DX,DX ; printer number 0
- MOV AH,2 ; use ROM BIOS 'get status' function
- INT 017 ; status is returned in AH
- TEST AH,8 ; test bit 3, I/O error indicator
- RET ; Z means ready, NZ means error
-
-
- ; BEEP uses the 8253 timer chip to emit a short beep thru the PC's speaker.
-
- BEEP:
- MOV AL,182 ; notify 8253 that frequency data is coming
- OUT 67,AL ; 8253 now programmed to take a frequency
- MOV AL,0 ; load the low byte of the frequency (776.8 Hz)
- OUT 66,AL ; output the low byte
- MOV AL,6 ; load the high byte of the frequency
- OUT 66,AL ; output the high byte
- IN AL,97 ; fetch program value from hardware
- OR AL,3 ; turn on the bottom two bits, to activate the speaker
- OUT 97,AL ; speaker is activated
- MOV CX,06000 ; time delay for sound duration
- L1: ; loop here while speaker sounds
- LOOP L1
- IN AL,97 ; fetch program value from hardware
- AND AL,NOT 3 ; turn off the bottom two bits, to deactivate the speaker
- OUT 97,AL ; speaker is shut off
- RET
-
-
- ; WINDOW_IMAGE is the place where the video image of our pop-up window is
- ; constructed when we install ourselves.
-
- WINDOW_IMAGE:
-
- END_OF_PROGRAM EQU $ + IMAGE_SIZE
-
-