; LPTMONT.ASM by Jim Webster ; aka ; LPTMON.ASM by Celso Minnitti, Jr ; Date: 01-16-1994 ; Compile: TASM /m2 LPTMON ; TLINK /t LPTMON ; or ; MASM LPTMON; ; LINK LPTMON; ; < LINK : warning L4021: no stack segment > ; EXE2BIN LPTMON ; REN LPTMON.BIN LPTMON.COM ; ; Please note that the file LPTMONT.ZIP contains LPTMON.* and LPTMONT.* ; The LPTMON.* files are Celso Minnittis' and the LPTMONT.* files are mine. ; These files are identical. Except that I took Celso's .ASM file, which ; was not commented very well, and extensively commented it. ; The file LPTMON.DOC is Celsos' document file. Is also at end of this file. ; ; James Webster EMail: jwebste3@bellsouth.net ATTR equ 70h ;Character attribute. REFRESH equ 9 ;55ms*9 = 0.495 seconds pushr macro a,b,c,d,e,f,g,h,i,j,k irp xx, ifnb push xx else exitm endif endm endm popr macro a,b,c,d,e,f,g,h,i,j,k irp xx, ifnb pop xx else exitm endif endm endm _TEXT segment byte public 'CODE' assume cs:_TEXT, ds:_TEXT org 100h start: jmp install ;Go to beginning of code. pause db 0 ;0 = display, 1 = display disabled. old08 dd 0 ;Old INT 08h. ; (IRQ 0) System Timer Interrupt. old0f dd 0 ;Old INT 0Fh. ; (IRQ 7) LPT1 Interrupt. old2f dd 0 ;Old INT 2Fh. ; DOS Multiplexer Interrupt. column dw 70 * 2 ;Start at Row 0, Column 70. lptIO dw 378h ;Base port address of LPT1. vidseg dw 0b800h ;B000h = monochrome. count_08 db 0 ;Set to 9. Allows for RAM refresh. count_0f db 0 ;Counter of INT 0Fh (IRQ 7). ;------------------------------------------------------------------------------ int_08: pushf ;Simulate an INT. call cs:old08 ;First service old INT 08h. pushf ;Simulate an INT. cmp byte ptr cs:[pause],1 ;Is the display turned off ? je int08_ret ;If so [ZR], exit. Else: inc byte ptr cs:[count_08] ;Inc RAM refresh counter. cmp byte ptr cs:[count_08],REFRESH ;Check. jb int08_ret ;If less than REFRESH [09h], exit. pushr ;Else, continue. pop ds ;DS = CS. mov count_08,0 ;Reset RAM refresh count to 0. call write_lptmon ;Display values. popr int08_ret: popf ;Pop flags. iret ;And exit INT. ;------------------------------------------------------------------------------ int_0f: inc byte ptr cs:[count_0f] ;Inc counter of calls. jmp cs:old0f ;And FAR JUMP to old INT 0Fh. ;------------------------------------------------------------------------------ int_2f: cmp ah,90h ;Is this our Major Function number? ; [Major Functions 80h thru FFh] ; [are program definable. ] je int2f_00 ;If so, process the Minor Function. jmp cs:old2f ;Else, FAR JUMP to old INT 2Fh. ;*** Minor Function 00h = show if LPTMON is resident. ***** int2f_00: cmp al,0 ;Minor Function 00h ? jne int2f_01 ;If not, try another. mov ax,0ffffh ;Else, return 0FFFFh to show that iret ; LPTMON is resident. ;*** Minor Function 02h = turn on/off LPTMON display. ***** int2f_01: cmp al,1 ;Minor Function 01h ? jne int2f_02 ;If not, assume 02h. xor byte ptr cs:[pause],1 ;Else, turn on/off LPTMON display. iret ;And exit INT. ;*** Minor Function 02h = uninstall LPTMON. ***** int2f_02: push ds ;Save the DATA segment. mov ax,2508h ;AH = Set Interrupt Vector. ;AL = the Interrupt Vector Number. lds dx,cs:[old08] ;DS:DX = old INT 08h. int 21h ;Call DOS. ;----------------------------- mov al,0fh ;AH = Set Interrupt Vector. ;AL = the Interrupt Vector Number. lds dx,cs:[old0f] ;DS:DX = old INT 0Fh. int 21h ;Call DOS. ;----------------------------- mov al,2fh ;AH = Set Interrupt Vector. ;AL = the Interrupt Vector Number. lds dx,cs:[old2f] ;DS:DX = old INT 2Fh. int 21h ;Call DOS. ;----------------------------- mov es,word ptr cs:[2ch] ;ES = segment of this programs ; Enviroment. mov ah,49h ;AH = Release Memory Block. int 21h ;Call DOS. ;----------------------------- push cs pop es ;ES = segment of this programs ; Program Segment Prefix. mov ah,49h ;AH = Release Memory Block. int 21h ;Call DOS. pop ds ;Restore the DATA segment. iret ;And exit INT for last time. ;------------------------------------------------------------------------------ write_lptmon: cld ;Set direction for increment. push cs pop es ;ES = CS. call read_port ;Read our port addresses. ;----------------------------- mov es,[vidseg] ;ES = Video Segment address. mov di,column ;DI = offset in Video Segment. mov ax,6 ;AX = write 6 lines (row count). mov si,offset LPTMON ;DS:SI = source address. ;----------------------------- write_lptmon1: mov cx,10 ;CX = each line has 10 characters. rep movsw ;Move CX words from DS:SI to ES:DI. add di,140 ;Advance to next line (160 - 20). dec ax ;Decrement row counter. jnz write_lptmon1 ;If AX <> 0, write next line. ret ;Else, AX = 0, exit. ;-------------------------------------------------------------------------- read_port: mov dx,[lptIO] ;DX = Base port address of LPT1. xor si,si ;SI = 0. mov cx,3 ;CX = loop count. ;----------------------------- read_port1: in al,dx ;AL = byte from DX port. mov di,word ptr [si+XY] ;ES:DI = destination. call write_8h ;Convert to keyboard hex and store. inc si ;Advance SI to next line of the inc si ; stored display. inc dx ;DX = current port address + 1. loop read_port1 ;Loop til CX = 0. ;----------------------------- mov al,count_0f ;AL = count of INT 0Fh calls. mov di,word ptr [si+XY] ;ES:DI = destination. call write_8h ;Convert to keyboard hex and store. ret ;And exit. ;************************************************************************** ; WRITE_8H ; ; On entry: AL = # to write in hexadecimal at ES:DI. ;************************************************************************** write_8h proc near ;Declare as NEAR procedure. pushr ;Save registers used. wri81: mov cx,2 ;CX = loop count (i.e. FF). mov dl,al ;DL = AL. mov ah,ATTR ;AH = character attribute. wri82: push cx ;Save overall loop count. mov cl,4 ;CL = bit rotation count. rol dl,cl ;Swap high and low nibbles. ; Example: 1Fh becomes F1h. mov al,dl ;AL = DL. and al,0fh ;Make high bit a 0. daa ;Convert to BCD. add al,0f0h ;Prepare for ASCII conversion. adc al,40h ;Convert to ASCII. stosw ;Store AX in ES:DI. pop cx ;Restore overall loop count. loop wri82 ;Loop until CX = 0. popr ;Restore registers. ret ;And exit. write_8h endp ; Offsets into LPTMON LABEL BYTE XY dw offset LPTMON+1*20+6*2 ;Offset 32d. dw offset LPTMON+2*20+6*2 ;Offset 52d. dw offset LPTMON+3*20+6*2 ;Offset 72d. dw offset LPTMON+4*20+6*2 ;Offset 92d. ; This data was created using Thedraw ; Character attributes: DEC HEX Background Foreground ; --- --- ---------- ----------- ; 122 7A White Light Green ; 123 7B White Light Cyan ; 126 7E White Yellow LPTMON LABEL BYTE DB 'Ú',122,'Ä',122,'L',126,'P',126,'T',126,'M',126,'O',126 DB 'N',126,'Ä',122,'¿',122,'³',122,'3',123,'7',123,'8',123 DB '=',123,' ',123,' ',122,' ',122,' ',122,'³',122,'³',122 DB '3',123,'7',123,'9',123,'=',123,' ',123,' ',122,' ',122 DB ' ',122,'³',122,'³',122,'3',123,'7',123,'A',123,'=',123 DB ' ',123,' ',122,' ',122,' ',122,'³',122,'³',122,'I',123 DB 'R',123,'Q',123,'7',123,'=',123,' ',123,' ',122,' ',122 DB '³',122,'À',122,'Ä',122,'Ä',122,'Ä',122,'Ä',122,'Ä',122 DB 'Ä',122,'Ä',122,'Ä',122,'Ù',122 ;------------------------------------------------------------------------------ install: mov al,byte ptr ds:[80h] ;AL = # characters in the command ; line (from the PSP). cmp al,2 ;Space + 1st argument (U or -) ? jne install0 ;If <> 2, jump. Assume install. ;----------------------------- mov al,byte ptr ds:[82h] ;AL = 1st argument. cmp al,'u' ;Uninstall ? je uninstall ;If so, uninstall LPTMON. cmp al,'U' ;Uninstall ? je uninstall ;If so, uninstall LPTMON. cmp al,'-' ;Turn display on/off ? jne install0 ;If not, see if already installed. mov ax,9001h ;If so, invoke call to INT2F_01. ; AH = INT #, AL = Sub-function. int 2fh ;Call DOS Multiplexer Service. jmp exit ;And exit. ;----------------------------- install0: mov ax,9000h ;Is lptmon already installed ? int 2fh ;Call DOS Multiplexer Service. cmp ax,0ffffh ;AX = FFFF ? jne install1 ;If <> FFFF, install LPTMON. lea dx,msg00 ;If = FFFF, is already installed. jmp dos_write_string ;Display message. ;----------------------------- install1: mov ah,9 ;OK to install. lea dx,copyright ;DS:DX = address of string. int 21h ;Call DOS. call init_video ;Initial VIDSEG variable. ;----------------------------- mov ax,3508h ;AH = Get Interrupt Vector. ;AL = the Interrupt Vector Number. int 21h ;Call DOS. Returns ES:BX pointer. mov word ptr [old08],bx ;Store old INT 08h for future use. mov word ptr [old08+2],es lea dx,int_08 ;DS:DX = address of new routine. mov ah,25h ;AH = Set Interrupt Vector. ;AL = the Interrupt Vector Number. int 21h ;Call DOS. ;----------------------------- mov ax,350fh ;AH = Get Interrupt Vector. ;AL = the Interrupt Vector Number. int 21h ;Call DOS. Returns ES:BX pointer. mov word ptr [old0f],bx ;Store old INT 0Fh for future use. mov word ptr [old0f+2],es lea dx,int_0f ;DS:DX = address of new routine. mov ah,25h ;AH = Set Interrupt Vector. ;AL = the Interrupt Vector Number. int 21h ;Call DOS. ;----------------------------- mov ax,352fh ;AH = Get Interrupt Vector. ;AL = the Interrupt Vector Number. int 21h ;Call DOS. Returns ES:BX pointer. mov word ptr [old2f],bx ;Store old INT 2Fh for future use. mov word ptr [old2f+2],es lea dx,int_2f ;DS:DX = address of new routine. mov ah,25h ;AH = Set Interrupt Vector. ;AL = the Interrupt Vector Number. int 21h ;Call DOS. ;----------------------------- lea dx,install ;DS:DX = offset of end of program ; to remain memory resident. ;CS = segment of PSP (automatic). int 27h ;Terminate and Stay Resident. ;----------------------------- dos_write_string: mov ah,9 ;AH = Display String. int 21h ;Call DOS. exit: int 20h ;Exit program to DOS. uninstall: mov ax,9002h ;Invoke call to INT2F_02. int 2fh ;Call DOS Multiplexer Service. lea dx,msg01 ;DS:DX = address of string. jmp dos_write_string ;Display message. ;************************************************************************** ; INIT_VIDEO ; Writes: VIDSEG = B800 (color) or B000 (mono) ;************************************************************************** init_video proc near push ds ;Save our DATA segment. xor ax,ax ;AX = 0. mov ds,ax ;DS = 0. mov al,byte ptr ds:[410h] ;AL = Installed Hardwr 1 from BIOS. pop ds ;Restore our DATA segment. ;----------------------------- and al,30h ;Mask out all but bits 4 and 5. cmp al,30h ;Monochrome ? mov ax,0B800h ;Assume Color. jnz init1 ;If <> 30h, its Color. mov ax,0B000h ;Else, its Monochrome. init1: mov vidseg,ax ;Store the Video Segment address. ret ;And exit. init_video endp copyright db 'LPTMON 1.0 Public Domain by Celso Minnitti Jr ' db '01-16-94',0dh,0ah,24h msg00 db 'Usage: LPTMON [option]',0dh,0ah db ' U Uninstall LPTMON',0dh,0ah db ' - Turn on/off the display of LPTMON' db 0dh,0ah,24h msg01 db 'LPTMON successfully uninstalled',0dh,0ah,24h _TEXT ends end start comment \ LPTMON version 1.0 By Celso Minnitti Jr. Public domain software. Copy freely. LPTMON10.ZIP has these files: ÉÍÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÍ» ³ LPTMON.ASM 8086 Assembly language source code ³ ³ LPTMON.COM Executable program ³ ³ LPTMON.DOC This document ³ ³ L.BAT Batch to compile and link LPTMON.ASM ³ ÈÍÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄͼ Introduction ÄÄÄÄÄÄÄÄÄÄÄÄ LPTMON is a Terminate and Stay Resident (TSR) program that will display the values of the ports 378h (data port), 379h (status port), 3FAh (control port), and how many times an IRQ7 has been occured so the user can monitor a printer at LPT1. I am including the full source code of LPTMON so you can change it as you like. Port 378h printer data output ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ³7³6³5³4³3³2³1³0³ ³ ³ ³ ³ ³ ³ ³ ÀÄÄÄÄ data bit 0, hardware pin 2 ³ ³ ³ ³ ³ ³ ÀÄÄÄÄÄ data bit 1, hardware pin 3 ³ ³ ³ ³ ³ ÀÄÄÄÄÄÄ data bit 2, hardware pin 4 ³ ³ ³ ³ ÀÄÄÄÄÄÄÄ data bit 3, hardware pin 5 ³ ³ ³ ÀÄÄÄÄÄÄÄÄ data bit 4, hardware pin 6 ³ ³ ÀÄÄÄÄÄÄÄÄÄ data bit 5, hardware pin 7 ³ ÀÄÄÄÄÄÄÄÄÄÄ data bit 6, hardware pin 8 ÀÄÄÄÄÄÄÄÄÄÄÄ data bit 7, hardware pin 9 Port 379h printer status register ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ³7³6³5³4³3³2³1³0³ ³ ³ ³ ³ ³ ³ ³ ÀÄÄÄÄ 1 = time-out ³ ³ ³ ³ ³ ÀÄÁÄÄÄÄÄ unused ³ ³ ³ ³ ÀÄÄÄÄÄÄÄÄ 1 = fault, pin 15 ³ ³ ³ ÀÄÄÄÄÄÄÄÄÄ 1 = on-line, pin 13 ³ ³ ÀÄÄÄÄÄÄÄÄÄÄ 1 = paper end (out of paper), pin 12 ³ ÀÄÄÄÄÄÄÄÄÄÄÄ 0 = Acknowledge, pin 10 ÀÄÄÄÄÄÄÄÄÄÄÄÄ 0 = busy, pin 11 Port 37Ah printer control register ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ³7³6³5³4³3³2³1³0³ ³ ³ ³ ³ ³ ³ ³ ÀÄÄÄÄ 1 = output data to printer, pin 1 ³ ³ ³ ³ ³ ³ ÀÄÄÄÄÄ 1 = auto line feed, pin 14 ³ ³ ³ ³ ³ ÀÄÄÄÄÄÄ 0 = initialize printer, pin 16 ³ ³ ³ ³ ÀÄÄÄÄÄÄÄ 1 = select input, pin 17 ³ ³ ³ ÀÄÄÄÄÄÄÄÄ 0 = IRQ disable,1=IRQ enable for ACK ÀÄÁÄÁÄÄÄÄÄÄÄÄÄ unused Signal Name 25-Pin Connector Description ÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Strobe 1 Output signal indicating the eight data lines can be read Data bit 0-7 2-9 Five volts = logical one Zero volts = logical zero Acknowledge 10 Input signal indicating data received Busy 11 Input signal indicating do NOT transmit Paper end 12 Input signal indicating printer is out of paper On-line 13 Input signal indicating printer is on-line, ready to receive Auto line feed 14 Output signal selecting the line-feed option. If the signal is low, the printer is commanded to automatically feed one line when it detects a carriage return; If the signal is high, an explicit line-feed character is required Fault 15 Input Status indicating an error Initialize printer 16 Output signal resetting the printer to its default operating parameters Select input 17 Output signal to switch the printer on and off line Ground 18-25 Ground How to contact the Author ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ If you have any comments or suggestions about LPTMON you can reach me at 617-235-4018 or write to: Celso Minnitti Jr 139 Linden St Wellesley, MA 02181 \