413 lines
8.3 KiB
NASM
413 lines
8.3 KiB
NASM
|
page,132
|
||
|
;---------------------------Module-Header-------------------------------;
|
||
|
; Module Name: IBMLPT.ASM
|
||
|
;
|
||
|
; Copyright (c) Microsoft Corporation 1985-1990. All Rights Reserved.
|
||
|
;
|
||
|
; General Description:
|
||
|
;
|
||
|
; History:
|
||
|
;
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
title IBMLpt - IBM PC, PC-XT, PC-AT, PS/2 Parallel Communications Interface
|
||
|
|
||
|
.xlist
|
||
|
include cmacros.inc
|
||
|
include comdev.inc
|
||
|
include ins8250.inc
|
||
|
include ibmcom.inc
|
||
|
.list
|
||
|
|
||
|
sBegin Code
|
||
|
assumes cs,Code
|
||
|
assumes ds,Data
|
||
|
|
||
|
externFP GetSystemMsecCount
|
||
|
|
||
|
externA __0040H
|
||
|
|
||
|
;----------------------------Private-Routine----------------------------;
|
||
|
;
|
||
|
; DoLPT - Do Function To LPT port
|
||
|
;
|
||
|
; The given function (output or reset) is performed to the
|
||
|
; passed LPT port.
|
||
|
;
|
||
|
; Before a character is sent, a check is made to see if the device
|
||
|
; will be able to accept the character. If it can, then the character
|
||
|
; will be sent. If not, then an error will be returned. If the
|
||
|
; printer is selected and busy and no error, then the code returned
|
||
|
; will be CE_TXFULL and the handshake bits will be set in HSFlag
|
||
|
; to simulate that a handshake was received.
|
||
|
;
|
||
|
; If the BIOS ROM code is examined, you will note that they wait for
|
||
|
; the busy character from the last charcater to be cleared before
|
||
|
; they strobe in the current character. This can take a long time
|
||
|
; on the standard EPSON class printer (1 mSec to greater than
|
||
|
; 300 mSec if the last character actually caused printing).
|
||
|
;
|
||
|
; Because of this, several status read retrys will be made before
|
||
|
; declaring that the device is actually busy. If only one status
|
||
|
; read is performed, the spooler will yeild, take a while to get
|
||
|
; back here, and things will be really slow. What difference does
|
||
|
; it really make if we or the BIOS does the delay, at least we can
|
||
|
; break out of it at some point when it seems hopeless.
|
||
|
;
|
||
|
; The OKIHACK: Okidata reports a 50 ns. 2.2 volt pulse on the paper
|
||
|
; out signal on the trailing edge of the Busy signal. If we see this
|
||
|
; glitch then we report paper out. So we try to get the status twice...
|
||
|
; if it changes between the two tries we keep getting the status.
|
||
|
;
|
||
|
;
|
||
|
; Entry:
|
||
|
; AH = cid
|
||
|
; AL = character to output
|
||
|
; CH = Function request. 0 = Output, 1 = Initialize, 2 = Status
|
||
|
; DS:SI -> DEB for the port
|
||
|
; Returns:
|
||
|
; AX = 0 if no errors occured
|
||
|
; Error Returns:
|
||
|
; AX = error code
|
||
|
; Registers Preserved:
|
||
|
; SI,DI
|
||
|
; Registers Destroyed:
|
||
|
; AX,BX,CX,DX,ES,FLAGS
|
||
|
; History:
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
assumes ds,Data
|
||
|
assumes es,nothing
|
||
|
|
||
|
public DoLPT
|
||
|
DoLPT proc near
|
||
|
|
||
|
mov dx,Port[si] ;Get port address
|
||
|
|
||
|
; DX = port address
|
||
|
; CH = operation: 0 = write, 1 = init, 2 = status
|
||
|
; AL = character
|
||
|
|
||
|
or ch, ch
|
||
|
jz LPT_OutChar
|
||
|
cmp ch, 1
|
||
|
jz LPT_Reset
|
||
|
jmp LPT_GetStatus
|
||
|
ret
|
||
|
|
||
|
LPT_Reset:
|
||
|
|
||
|
inc dx
|
||
|
inc dx
|
||
|
mov al, L_RESET
|
||
|
iodelay
|
||
|
out dx, al
|
||
|
|
||
|
push dx
|
||
|
|
||
|
cCall GetSystemMsecCount
|
||
|
mov bx, ax
|
||
|
|
||
|
LPT_ResetDelay:
|
||
|
push bx
|
||
|
cCall GetSystemMsecCount
|
||
|
pop bx
|
||
|
sub ax, bx
|
||
|
cmp ax, 300 ; 1/3 sec as good as any
|
||
|
jbe LPT_ResetDelay
|
||
|
|
||
|
pop dx
|
||
|
|
||
|
mov al, L_NORMAL
|
||
|
iodelay
|
||
|
iodelay
|
||
|
out dx, al
|
||
|
dec dx
|
||
|
dec dx
|
||
|
jmp LPT_GetStatus
|
||
|
|
||
|
LPT_OutChar:
|
||
|
push ax ; save character to be written
|
||
|
|
||
|
; first check to see if printer is ready for us
|
||
|
push di
|
||
|
|
||
|
push dx
|
||
|
call GetSystemMSecCount
|
||
|
mov di, ax
|
||
|
pop dx
|
||
|
|
||
|
LPT_WaitReady:
|
||
|
|
||
|
inc dx ; point to status port
|
||
|
iodelay
|
||
|
in al, dx ; get status bits
|
||
|
and al, L_BITS ; mask unused ones
|
||
|
xor al, L_BITS_INVERT ; flip a couple
|
||
|
xchg al, ah
|
||
|
|
||
|
ifndef NOOKIHACK
|
||
|
iodelay
|
||
|
in al, dx
|
||
|
|
||
|
dec dx
|
||
|
|
||
|
and al, L_BITS
|
||
|
xor al, L_BITS_INVERT
|
||
|
cmp al, ah ; did any bits change?
|
||
|
jnz LPT_WaitReady
|
||
|
else
|
||
|
dec dx
|
||
|
endif
|
||
|
|
||
|
|
||
|
test ah, PS_PaperOut or PS_IOError
|
||
|
jnz LPT_PrinterNotReady
|
||
|
test ah, PS_Select
|
||
|
jz LPT_PrinterNotReady
|
||
|
test ah, PS_NotBusy
|
||
|
jnz LPT_PrinterReady
|
||
|
|
||
|
push ax
|
||
|
push dx
|
||
|
call GetSystemMSecCount
|
||
|
pop dx
|
||
|
pop bx
|
||
|
sub ax, di
|
||
|
cmp ax, 300 ; 1/3 sec timeout
|
||
|
|
||
|
jbe LPT_WaitReady
|
||
|
|
||
|
; The device seems to be selected and powered up, but is just
|
||
|
; busy (some printers seem to show selected but busy when they
|
||
|
; are taken offline). Show that the transmit queue is full and
|
||
|
; that the hold handshakes are set. This is so the windows
|
||
|
; spooler will retry (and do yields so that other apps may run).
|
||
|
|
||
|
|
||
|
or ComErr[si],CE_TXFULL ;Show queue full
|
||
|
mov ah,bh
|
||
|
or ah, L_TIMEOUT
|
||
|
|
||
|
LPT_PrinterNotReady:
|
||
|
|
||
|
pop di
|
||
|
pop cx ; throw away character
|
||
|
jmp short LPT_ReturnStatus
|
||
|
|
||
|
LPT_PrinterReady:
|
||
|
pop di ; get di back
|
||
|
pop ax ; get character back
|
||
|
|
||
|
iodelay
|
||
|
out dx, al ; write character to port
|
||
|
|
||
|
inc dx ; access status port
|
||
|
|
||
|
LPT_Strobe:
|
||
|
inc dx ; control port
|
||
|
mov al, L_STROBE ; set strobe high
|
||
|
iodelay
|
||
|
iodelay
|
||
|
iodelay
|
||
|
iodelay
|
||
|
out dx, al ; ...
|
||
|
|
||
|
mov al, L_NORMAL ;
|
||
|
iodelay
|
||
|
iodelay
|
||
|
iodelay
|
||
|
iodelay
|
||
|
out dx, al ; set strobe low
|
||
|
|
||
|
sub dx, 2 ; point back to port base
|
||
|
|
||
|
; FALL THRU
|
||
|
|
||
|
LPT_GetStatus:
|
||
|
inc dx ; point to status port
|
||
|
LPT_GS1:
|
||
|
iodelay
|
||
|
iodelay
|
||
|
in al, dx ; get status bits
|
||
|
and al, L_BITS ; mask unused ones
|
||
|
xor al, L_BITS_INVERT ; flip a couple
|
||
|
mov ah, al
|
||
|
|
||
|
ifndef NOOKIHACK
|
||
|
in al, dx
|
||
|
and al, L_BITS
|
||
|
xor al, L_BITS_INVERT
|
||
|
cmp al, ah
|
||
|
jnz LPT_GS1 ; if they changed try again...
|
||
|
endif
|
||
|
|
||
|
LPT_ReturnStatus:
|
||
|
|
||
|
assumes ds,Data
|
||
|
and ax,(PS_PaperOut+PS_Select+PS_IOError+PS_Timeout)*256
|
||
|
shr ah,1
|
||
|
adc ah,al ;Get back Timeout bit
|
||
|
xor ah,HIGH CE_DNS ;Invert selected bit
|
||
|
.errnz LOW CE_DNS
|
||
|
or by ComErr+1[si],ah ;Save comm error
|
||
|
ret
|
||
|
|
||
|
.errnz CE_PTO-0200h
|
||
|
.errnz CE_IOE-0400h
|
||
|
.errnz CE_DNS-0800h
|
||
|
.errnz CE_OOP-1000h
|
||
|
|
||
|
DoLPT40:
|
||
|
assumes ds,Data
|
||
|
or ComErr[si],CE_TXFULL ;Show queue full
|
||
|
ret
|
||
|
|
||
|
DoLPT endp
|
||
|
page
|
||
|
|
||
|
|
||
|
CheckStatus proc near
|
||
|
in al, dx ; get status bits
|
||
|
mov ah, al
|
||
|
and al, L_BITS ; mask unused ones
|
||
|
xor al, L_BITS_INVERT ; flip a couple
|
||
|
xchg al, ah
|
||
|
|
||
|
ifndef NOOKIHACK
|
||
|
iodelay
|
||
|
in al, dx
|
||
|
|
||
|
and al, L_BITS
|
||
|
xor al, L_BITS_INVERT
|
||
|
cmp al, ah ; did any bits change?
|
||
|
jnz CheckStatus
|
||
|
endif
|
||
|
test ah, PS_PaperOut or PS_IOError
|
||
|
jz @F
|
||
|
stc
|
||
|
ret
|
||
|
@@:
|
||
|
test ah, PS_Select
|
||
|
jnz @F
|
||
|
stc
|
||
|
ret
|
||
|
@@:
|
||
|
and ah, PS_NotBusy
|
||
|
clc
|
||
|
ret
|
||
|
|
||
|
CheckStatus endp
|
||
|
|
||
|
|
||
|
;----------------------------Public Routine-----------------------------;
|
||
|
;
|
||
|
; StringToLPT - Send string To LPT Port
|
||
|
;
|
||
|
; Entry:
|
||
|
; DS:SI -> DEB
|
||
|
; ES:DI -> string to send
|
||
|
; CX = # of bytes to send
|
||
|
; Returns:
|
||
|
; AX = # of bytes actually sent
|
||
|
; Registers Destroyed:
|
||
|
; AX,BX,CX,DX,ES,FLAGS
|
||
|
; History:
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
PUBLIC StringToLPT
|
||
|
StringToLPT proc near
|
||
|
|
||
|
mov dx, Port[si] ; get port address
|
||
|
inc dx ; access status port
|
||
|
|
||
|
push cx ; save count for later
|
||
|
push ds
|
||
|
mov bx, __0040H
|
||
|
mov ds, bx
|
||
|
|
||
|
cld
|
||
|
|
||
|
call CheckStatus ; quick status check before slowness
|
||
|
jc PrinterError
|
||
|
jz PrinterBusy ; if printer not ready for first char
|
||
|
; then just return with CE_TXFULL
|
||
|
|
||
|
CharacterToLPT:
|
||
|
;; mov bh, 10 ; will wait 10 clock tics (~ 1/2 sec)
|
||
|
mov bh, 3 ; will wait 3 clock tics (~ 1/6 sec)
|
||
|
l1:
|
||
|
mov bl, ds:[006Ch] ; low byte of tic counter
|
||
|
l2:
|
||
|
call CheckStatus ; quick status check before slowness
|
||
|
jc PrinterError
|
||
|
jnz LPT_PrinterRdy
|
||
|
|
||
|
cmp bl, ds:[006Ch]
|
||
|
jz l2 ; tic count hasn't changed
|
||
|
|
||
|
dec bh
|
||
|
jz PrinterBusy ; out of tics, timeout
|
||
|
jmp short l1
|
||
|
|
||
|
LPT_PrinterRdy:
|
||
|
mov al, es:[di]
|
||
|
inc di
|
||
|
|
||
|
dec dx ; point to data port
|
||
|
|
||
|
out dx, al ; write character to port
|
||
|
|
||
|
add dx, 2 ; access control port
|
||
|
mov al, L_STROBE ; set strobe high
|
||
|
out dx, al ; ...
|
||
|
|
||
|
mov al, L_NORMAL ;
|
||
|
iodelay
|
||
|
iodelay
|
||
|
out dx, al ; set strobe low
|
||
|
|
||
|
dec dx ; point to status port for check
|
||
|
|
||
|
loop CharacterToLPT
|
||
|
pop ds
|
||
|
jmp short LPT_Exit
|
||
|
|
||
|
PrinterError:
|
||
|
pop ds
|
||
|
jmp short ReturnStatus
|
||
|
|
||
|
PrinterBusy:
|
||
|
pop ds
|
||
|
or ComErr[si],CE_TXFULL ; set buffer full bit
|
||
|
or al, L_TIMEOUT ; show timeout bit
|
||
|
|
||
|
ReturnStatus:
|
||
|
and ax,(PS_PaperOut+PS_Select+PS_IOError+PS_Timeout)
|
||
|
xchg al, ah
|
||
|
shr ah,1
|
||
|
adc ah,al ;Get back Timeout bit
|
||
|
xor ah,HIGH CE_DNS ;Invert selected bit
|
||
|
.errnz LOW CE_DNS
|
||
|
or by ComErr+1[si],ah ;Save comm error
|
||
|
|
||
|
LPT_Exit:
|
||
|
pop ax ; get total count
|
||
|
sub ax, cx ; subtract remaining unsent charts
|
||
|
|
||
|
ret
|
||
|
|
||
|
StringToLPT endp
|
||
|
|
||
|
|
||
|
IFDEF DEBUG ;Publics for debugging
|
||
|
public LPT_Reset
|
||
|
public LPT_Outchar
|
||
|
public LPT_Strobe
|
||
|
public LPT_GetStatus
|
||
|
public DoLPT40
|
||
|
ENDIF
|
||
|
|
||
|
sEnd code
|
||
|
End
|