page,132 ifdef NEC_98 .286p endif ; NEC_98 ;---------------------------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 ifdef NEC_98 include vint.inc endif ; NEC_98 .list ifdef NEC_98 sBegin Data ; (ins 93.03.28) InitRetry dw 0 ;LPT Retry count (ins 93.03.28) ModeFlag db 0 ; = 0 KAN-I SENTRO (ins 93.03.28) ; = 1 SENTRO (ins 93.03.28) ; CurPrinterMode db 0 ; OrgPrinterMode db 0 ; ; PC98_Mode = 00000000b ; Toki_Mode = 00000001b ; Org_Toki_ControlStatus db 0 ; Org_Toki_EX_Control db 0 ; ; Org_Toki_ControlStatus540 db 0 ; (ins 931219) Org_Toki_EX_Control540 db 0 ; (ins 931219) ; (ins 931219) Org_Toki_ControlStatusD40 db 0 ; (ins 931219) Org_Toki_EX_ControlD40 db 0 ; (ins 931219) ; (ins 931219) InitCounter db 0 ;Lpt initialize counter ; LptInit = 00000001b ; LPT Init OK ! ;RFU = 00000010b ; ;RFU = 00000100b ; ;RFU = 00001000b ; ;RFU = 00010000b ; ;RFU = 00100000b ; ;RFU = 01000000b ; ;RFU = 10000000b ; sEnd Data ; (ins 93.03.28) endif ; NEC_98 sBegin Code assumes cs,Code assumes ds,Data externFP GetSystemMsecCount externA __0040H ifdef NEC_98 ;------------------------------------------------------------------------- ; Printer Status Bit for IBM-PC ;------------------------------------------------------------------------- PS_NotBusy equ 10000000b ;Printer not busy PS_Ack equ 01000000b ;Data acknowledged PS_PaperOut equ 00100000b ;Out of paper PS_Select equ 00010000b ;Device is selected PS_IOError equ 00001000b ;IO error PS_Timeout equ 00000001b ;Timeout occured ;------------------------------------------------------------------------- ; Parameter for PC-9800 ;------------------------------------------------------------------------- PRNStrobFF_ON = 0dh ; port_C Strob F/F on PRNStrobFF_OFF = 0ch ; port_C Strob F/F off SystemPort = 37h ; port_C I/O Address PRN_Mode = 46h ; Printer Mode PRN_WSignal = 46h ; PRN_RSignal = 42h ; PRN_WRITE_DATA equ 040h ; PRN_READ_SIGNAL1 equ 042h ; PRN_WRITE_SIGNAL1 equ 046h ; PRN_PSTB_Active_X2 equ 004h ; PRN_PSTB_NonActive_X2 equ 005h ; PRN_PSTB_Active_X1 equ 00eh ; PRN_PSTB_NonActive_X1 equ 00fh ; endif ; NEC_98 ;----------------------------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 ifdef NEC_98 iodelay macro ; out 5fh, al ; endm ; endif ; NEC_98 public DoLPT DoLPT proc near ifdef NEC_98 cmp wo [si.Port], 00h ; (ins 931219) jz DoLPT98 ; jmp Toki_DoLpt ; else ; NEC_98 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 endif ; NEC_98 DoLPT endp page ifdef NEC_98 public DoLPT98 DoLPT98 proc near push di ;Need some extra space mov di,[InitRetry] ;Initialize retry count = 0 mov ah,ch ;Set function request DoLPT10: or ah,ah ;If reset jnz DoLPT50 ; skip status pre-read ;------------------------------------------------------------------------- ;output data to printer ;------------------------------------------------------------------------- xchg ax,cx ;CX = output data DoLPT20: ;------------------------------------------------------------------------- ; switch (AH) { ; 0: Output Data ; 1: Initialize Printer ; 2: Read Printer Status ; } ;------------------------------------------------------------------------- mov ah,2 ; call PrinterCall ; read status ;------------------------------------------------------------------------- ;(91.1.7) AH = (B)(A)(P)(S)|(F)(0)(0)(T) ; [IBM Printer Status] | | | | | | ; PS_NotBusy = 10000000b ------------+ | | | | | ; PS_Ack = 01000000b ---------------+ | | | | ; PS_PaperOut = 00100000b ------------------+ | | | ; PS_Select = 00010000b ---------------------+ | | ; PS_IOError = 00001000b -------------------------+ | ; PS_Timeout = 00000001b ----------------------------------+ ;------------------------------------------------------------------------- test ah,PS_PaperOut+PS_IOError ; jnz DoLPT60 ;paper empty or I/O error test ah,PS_Select jz DoLPT60 ;error if not select or ah,ah js DoLPT40 ;output data if not busy dec di jnz DoLPT20 ;until initialize retry count =0 DoLPT30: ;select & busy & retry count=0 or ComErr[si],CE_TXFULL ;Show queue full or ah, PS_Timeout ;Show timeout jmp short DoLPT60 ; goto EVENT Create DoLPT40: ; xchg ax,cx ;AX = output data DoLPT50: ;------------------------------------------------------------------------- ; switch (AH) { ; 0: Output Data ; 1: Initialize Printer ; 2: Read Printer Status ; } ;------------------------------------------------------------------------- call PrinterCall ;Let the BIOS do the work ;------------------------------------------------------------------------- ;(91.1.7) AH = (B)(A)(P)(S)|(F)(0)(0)(T) ; [IBM Printer Status] | | | | | | ; PS_NotBusy = 10000000b ------------+ | | | | | ; PS_Ack = 01000000b ---------------+ | | | | ; PS_PaperOut = 00100000b ------------------+ | | | ; PS_Select = 00010000b ---------------------+ | | ; PS_IOError = 00001000b -------------------------+ | ; PS_Timeout = 00000001b ----------------------------------+ ;------------------------------------------------------------------------- DoLPT60: and ax,(PS_PaperOut+PS_Select+PS_IOError+PS_Timeout)*256 ; 1. shr ah,1 ; 2. adc ah,al ;Get back Timeout bit 3. shr ah,1 ; 4. adc ah,al ;Get back Timeout bit 5. shl ah,1 ; 6. xor ah,HIGH CE_DNS ;Invert selected bit 7. ;------------------------------------------------------------------- ; <> ; _ ; ; BAPS|F00T ????|???? ; 1. and ax,(PS_Pa..+..)*256 ; 00PS|F00T 0000|0000 ; 2. shr ah,1 ; 000P|SF00 0000|0000 CY=(T) ; 3. adc ah,al ; 000P|SF0T 0000|0000 ; 4. shr ah,1 ; 0000|PSF0 0000|0000 CY=(T) ; 5. adc ah,al ; 0000|PSFT 0000|0000 ; 6. shl ah, 1 ; 000P|SFT0 0000|0000 ; 7. xor ah,HIGH CE_DNS ; 000P|SFT0 0000|0000 ; | ||| ; CE_OOP equ 1000h ------------------+ ||| ; CE_DNS equ 0800h --------------------+|| ; CE_IOE equ 0400h ---------------------+| ; CE_PTO equ 0200h ----------------------+ ;------------------------------------------------------------------- test ah, high(CE_TXFULL or CE_OOP or CE_DNS or CE_IOE ) jz DoLPT70 ;No error occured or by ComErr+1[si],ah ;Save comm error test by EvtMask+1[si],HIGH EV_PErr ;Printer error event request? jz DoLPT70 ; No or by EvtWord+1[si],HIGH EV_PErr ; Yes, show event occured DoLPT70: pop di ret DoLPT98 endp page ;----------------------------------------------------------------------- ; Open LPT ;----------------------------------------------------------------------- public INT_1AH_call INT_1AH_call proc near ;-(931219)----------------------------------------------------------------- ; Check H/W environment, and set correct I/O address to [si.Port]. ; ; +---------------------------------------+--------------------+ ; | | [si.Port] | ; | H/W environment |--------------------| ; | | LPT1 | LPT2 | LPT3 | ; +---------------------------------------+--------------------+ ; |1|Standard Machine | 000h | -1 | -1 | ; |2|Standard Machine+Ex board(LPT1/2) | 540h | d40h | -1 | ; |3| (LPT2/3) | 000h | 540h | d40h | ; |4|TOKI on board | 140h | -1 | -1 | ; |4|TOKI on board (LPT1 KAN-I)| 000h | -1 | -1 | ; |5|TOKI on board + Ex board | 140h | 540h | d40h | ; |5|TOKI on board + Ex board (LPT1 KAN-I)| 000h | 540h | d40h | ; +---------------------------------------+--------------------+ ; 000h -> compatible H/W, -1 -> no H/W ; ; [CurPrinterMode] ; PC98_Mode = 00000000b -> Standard Machine, no Ex board ; Toki_Mode = 00000001b -> TOKI on board ; ExToki_12 = 00000010b -> Ex LPT=LPT1/2 ; ExToki_23 = 00000100b -> Ex LPT=LPT2/3 ; ExToki_Available = (ExToki_12 or ExToki_23) ; ; ENTER: DS:SI -> ComDEB ; ; Toki_BasePort ¨ 0140h ; Base I/O Address ; Toki_DataLatch ¨ 0140h ; Data Port ; Toki_PrinterStatus ¨ 0141h ; Status Port ; Toki_PrinterControls ¨ 0142h ; Control Port ; Toki_ControlStatus ¨ 0149h ; Control Status Port ; Toki_EX_Control ¨ 014eh ; Ex Control Port ; ; BIOS Common Area [0:458h] Full SENTRO if Bit1=1 ; BIOS Common Area [0:5B3h] TOKI on board if Bit7=1 cmp by [si.DCB_Id], ID_LPT1 ; LPT1 ? (ins 931219) jne LPT2_TokiSetup ; @@N: NEXT (ins 931219) ; (ins 931219) push ds ; mov ax, 40h ; BIOS Common Area mov ds, ax ; test by ds:[1b3h], 10000000b ; TOKI if bit7=1 pop ds ; mov wo [si.Port], 140h ; (ins 931219) jz @f ; N: NEXT (ins 931219) jmp LPT1_TokiSetup ; Y: TOKI I/O (ins 931219) ; -> LPT1=TOKI on board (ins 931219) @@: ; (ins 931219) mov dx, Toki_ControlStatus+400h ; (ins 931219) in al, dx ; (ins 931219) cmp al, 0ffh ; Is there Ex board ? (ins 931219) mov wo [si.Port], 00h ; (ins 931219) jne @f ; Y: NEXT (ins 931219) jmp PrePrinterCall ; N: standard I/O (ins 931219) ; -> LPT1=KAN-I on board(ins 931219) @@: ; (ins 931219) mov dx, 54fh ; (ins 931219) in al, dx ; (ins 931219) test al, 00000100b ; Ex board = LPT1/2 ? (ins 931219) mov wo [si.Port], 00h ; (ins 931219) jz @f ; Y: Ex board I/O (ins 931219) ; -> LPT1=CH1 (ins 931219) jmp PrePrinterCall ; N: Standard I/O (ins 931219) ; -> LPT1=KAN-I on board(ins 931219) @@: ; (ins 931219) ;------------------------------------------------------------------- ; Initialize Ex 1CH(Port 054xh) ;------------------------------------------------------------------- mov wo [si.Port], 540h ; (ins 931219) Init_Port540h: ; (ins 931219) mov dx, Toki_ControlStatus+400h; (ins 931219) in al, dx ; (ins 931219) mov [Org_Toki_ControlStatus540], al; Save Control Status(ins 931219) mov dx, Toki_EX_Control+400h; (ins 931219) in al, dx ; (ins 931219) mov [Org_Toki_EX_Control540], al; Save Ex Control (ins 931219) mov dx, Toki_ControlStatus+400h ; AT Standard mode (ins 931219) mov al, 00010000b ; Normal Speed (ins 931219) out dx, al ; (ins 931219) iodelay ; (ins 931219) mov dx, Toki_EX_Control+400h ; AT Standard mode (ins 931219) mov al, 00010100b ; S/W Control (ins 931219) out dx, al ; (ins 931219) iodelay ; (ins 931219) mov dx,Toki_PrinterControls+400h; Select Printer (ins 931219) mov al, 00001100b ; nothing to initialize (ins 931219) out dx, al ; (ins 931219) ret ; (ins 931219) LPT2_TokiSetup: cmp by [si.DCB_Id], ID_LPT2 ; LPT2 ? (ins 931219) jne LPT3_TokiSetup ; N: NEXT (ins 931219) mov dx, Toki_ControlStatus+400h ; (ins 931219) in al, dx ; (ins 931219) cmp al, 0ffh ; Is there Ex board ? (ins 931219) mov wo [si.Port], -1 ; (ins 931219) jne @f ; Y: NEXT (ins 931219) ret ; N: Error (ins 931219) @@: ; (ins 931219) mov dx, 54fh ; (ins 931219) in al, dx ; (ins 931219) test al, 00000100b ; Ex board=LPT2/3 ? (ins 931219) mov wo [si.Port], 540h ; (ins 931219) jnz Init_Port540h ; Y: Init CH1 Port (ins 931219) ; -> LPT2=CH1 (ins 931219) ; N: Init CH2 Port (ins 931219) ; -> LPT2=CH2 (ins 931219) ;------------------------------------------------------------------- ; Initialize Ex 2CH(Port 0d4xh) ;------------------------------------------------------------------- mov wo [si.Port], 0d40h ; (ins 931219) Init_PortD40h: ; (ins 931219) mov dx, Toki_ControlStatus+0c00h; (ins 931219) in al, dx ; (ins 931219) mov [Org_Toki_ControlStatusD40], al; Save Control Status(ins 931219) mov dx, Toki_EX_Control+0c00h; (ins 931219) in al, dx ; (ins 931219) mov [Org_Toki_EX_ControlD40], al; Save Ex Control (ins 931219) mov dx, Toki_ControlStatus+0c00h; AT Standard mode (ins 931219) mov al, 00010000b ; Normal Speed (ins 931219) out dx, al ; (ins 931219) iodelay ; (ins 931219) mov dx, Toki_EX_Control+0c00h ; AT Standard mode (ins 931219) mov al, 00010100b ; S/W Control (ins 931219) out dx, al ; (ins 931219) iodelay ; (ins 931219) mov dx,Toki_PrinterControls+0c00h; Select Printer (ins 931219) mov al, 00001100b ; nothing to initialize (ins 931219) out dx, al ; (ins 931219) ret ; (ins 931219) LPT3_TokiSetup: mov dx, Toki_ControlStatus+0c00h; (ins 931219) in al, dx ; (ins 931219) cmp al, 0ffh ; Is there Ex board ? (ins 931219) mov wo [si.Port], -1 ; (ins 931219) jne @f ; Y: NEXT ret ; N: Error @@: ; mov dx, 54fh ; (ins 931219) in al, dx ; (ins 931219) test al, 00000100b ; Ex board=LPT2/3 ? (ins 931219) mov wo [si.Port], 0d40h ; (ins 931219) jnz Init_PortD40h ; Y: Init CH2 Port (ins 931219) ; -> LPT3=CH2 (ins 931219) mov wo [si.Port], -1 ; (ins 931219) ret ; (ins 931219) LPT1_TokiSetup: ; (ins 931219) ;---------------------------------------------------------------- ; Save Status of TOKI ;---------------------------------------------------------------- mov dx, Toki_ControlStatus ; in al, dx ; mov [Org_Toki_ControlStatus], al; Save Control Status mov dx, Toki_EX_Control ; in al, dx ; mov [Org_Toki_EX_Control], al ; Save Ex Control ;---------------------------------------------------------------- ; Set Full SENTRO for checking cable ;---------------------------------------------------------------- mov dx, Toki_ControlStatus ; AT Standard mode mov al, 00010000b ; Normal Speed out dx, al ; iodelay ; mov dx, Toki_EX_Control ; AT Standard mode mov al, 00000000b ; S/W Control out dx, al ; ;---------------------------------------------------------------- ; Check cable ;---------------------------------------------------------------- mov dx, Toki_PrinterControls ; in al, dx ; PrinterControls Read (ins 940224) and al, 11011111b ; Set DIR(=Foward) (ins 940224) out dx, al ; identification Sequence mov dx, Toki_DataLatch ; of cable mov al, 0 ; out dx, al ; mov dx, Toki_PrinterStatus ; in al, dx ; test al, 00000010b ; SENTRO cable(PowON)? jnz TokiFullInit ; Y: Init as ; Full SENTRO mov dx, Toki_DataLatch ; N: NEXT mov al, 80h ; out dx, al ; mov dx, Toki_PrinterStatus ; in al, dx ; test al, 00000010b ; SENTRO cable(PowOFF)? jz TokiFullInit ; Y: Init as ; Full SENTRO ;---------------------------------------------------------------- ; Initialize as KAN-I SENTRO ;---------------------------------------------------------------- mov wo [si.Port], 0 ; (ins 931219) mov dx, Toki_ControlStatus ; mov al, 0 ; out dx, al ; N: KAN-I jmp short PrePrinterCall ; ; ;---------------------------------------------------------------- ; Initialize as Full SENTRO ;---------------------------------------------------------------- TokiFullInit: ; or [CurPrinterMode], Toki_Mode; mov dx, Toki_ControlStatus ; AT Standard mode mov al, 00010000b ; Normal Speed out dx, al ; iodelay ; mov dx, Toki_EX_Control ; AT Standard mode mov al, 00000000b ; S/W Control out dx, al ; iodelay ; mov dx, Toki_PrinterControls; Select Printer mov al, 00001100b ; nothing to initialize out dx, al ; ret ; ; INT_1AH_call endp ;----------------------------------------------------------------------- ; Close LPT ;----------------------------------------------------------------------- public INT_1AH_Close ; INT_1AH_Close proc near ; cmp wo[si.Port], 00h ; (ins 931219) jnz @f ; ret ; @@: ; cmp wo [si.Port], 140h ; (ins 931219) jne @f ; (ins 931219) mov al,[Org_Toki_ControlStatus]; mov dx, Toki_ControlStatus ; out dx, al ; Restore Control Status mov al,[Org_Toki_EX_Control] ; mov dx, Toki_EX_Control ; out dx, al ; Restore Ex Control ret ; @@: cmp wo [si.Port], 540h ; (ins 931219) jne @f ; (ins 931219) mov al,[Org_Toki_ControlStatus540]; (ins 931219) mov dx, Toki_ControlStatus+400h; (ins 931219) out dx, al ; Restore Control Status(ins 931219) ; (ins 931219) mov al,[Org_Toki_EX_Control540]; (ins 931219) mov dx, Toki_EX_Control+400h; (ins 931219) out dx, al ; Restore Ex Control (ins 931219) ret ; (ins 931219) @@: ; (ins 931219) mov al,[Org_Toki_ControlStatusD40]; (ins 931219) mov dx, Toki_ControlStatus+0c00h; (ins 931219) out dx, al ; Restore Control Status(ins 931219) ; (ins 931219) mov al,[Org_Toki_EX_ControlD40]; (ins 931219) mov dx, Toki_EX_Control+0c00h; (ins 931219) out dx, al ; Restore Ex Control (ins 931219) ret ; (ins 931219) INT_1AH_Close endp ; public PrinterCall PrePrinterCall proc near test [InitCounter],LptInit ; LPT Init Finish ? XL jz @f ; Yes: goto Return ret ; @@: ; or [InitCounter],LptInit ; LPT Init Flag "ON" mov ah,1 ; Printer Initialize PrePrinterCall endp public PrinterCall PrinterCall proc near push bx push cx push dx or ah,ah ; switch (AH) { jnz @f ; call LPT_OutPut ; 0: Output Data jmp short End_INT1AH ; @@: dec ah ; jnz @f ; call LPT_Initialize ; 1: Initialize Printer jmp short End_INT1AH ; @@: dec ah ; jnz @f ; call LPT_GetStatus ; 2: Read Printer Status @@: End_INT1AH: pop dx pop cx pop bx ret PrinterCall endp ;--------------------------------------------------------------------------- ; Output Data to Printer ;--------------------------------------------------------------------------- public LPT_Output LPT_OutPut proc near mov dx,PRN_WRITE_DATA ;Set Printer Write Data Port out dx,al ;Data out mov dx,PRN_READ_SIGNAL1 ;Set Printer Status Port in al,dx ; Get Printer Status (ins 93.03.23) test al,(PS_NotBusy shr 5) ; if (status != Busy) (ins 93.03.23) jnz INT1AH13 ; yes : goto INT1AH13 (ins 93.03.23) INT1AH11: ; push dx ; call GetSystemMSecCount ; Get System Timer mov di, ax ; di = Tick Value pop dx ; ; INT1AH12: ; in al,dx ; Get Printer Status test al,(PS_NotBusy shr 5) ; if (status != Busy) jnz INT1AH13 ; yes : goto INT1AH13 ; push dx ; call GetSystemMSecCount ; pop dx ; sub ax, di ; cmp ax, 300 ; 1/3 sec timeout jbe INT1AH12 ; ; cmp byte ptr [ModeFlag],0 ;### (ins 93.03.31) jnz INT1AH12_1 ; or al,061h and al,065h INT1AH12_1: ; call XlatStatus ;Locate bits or ah,PS_Timeout ;Show timeout and ah,(PS_NotBusy+PS_Ack+PS_PaperOut+PS_Select+PS_IOError+PS_Timeout) ret INT1AH13: cmp byte ptr [ModeFlag],0 ;### (ins 93.03.31) jnz INT1AH13_X2 ; INT1AH13_X1: ; FCLI ; mov dx,PRN_WRITE_SIGNAL1 ;Set Printer Status Port mov al,PRN_PSTB_Active_X1 ;Strobe High out dx,al NEWIODELAY 2 ; (ins 92.11.11) mov al,PRN_PSTB_NonActive_X1 ;Strobe Low out dx,al call LPT_GetStatus ret INT1AH13_X2: ; FCLI ; mov dx,PRN_WRITE_SIGNAL1 ;Set Printer Status Port mov al,PRN_PSTB_Active_X2 ;Strobe High out dx,al NEWIODELAY 2 ; (ins 92.11.11) mov al,PRN_PSTB_NonActive_X2;Strobe Low out dx,al call LPT_GetStatus ret LPT_OutPut endp ;--------------------------------------------------------------------------- ; Read Printer Status ;--------------------------------------------------------------------------- public LPT_GetStatus LPT_GetStatus proc near FSTI mov dx,PRN_READ_SIGNAL1 ; in al,dx ; Read Status cmp byte ptr [ModeFlag],0 ;(ins 93.03.31)#### jnz INT1AH22 ; or al,061h and al,065h INT1AH22: ; jmp short XlatStatus ;(ins 93.03.31)#### LPT_GetStatus endp ;--------------------------------------------------------------------------- ; Locate Bits ; [ NES's Printer STATUS ] ; (7)(6)(5)(4)(3)(2)(1)(0) ; I I I I I I +-------------------- = 0: ACK ; I I I I I +-------------------------- = 0: BUSY ; I I I I +----------------------------- = 0: IBUSY ; I I I +-------------------------------- = 0: DC¥5V ; I I +----------------------------------- = 0: PE ; I +-------------------------------------- = 0: FAULT ; +----------------------------------------- = 0: SELECT ; ; [IBM Printer Status] ; (B)(A)(P)(S)|(F)(0)(0)(T) ; | | | | | +------------------- = 1: PS_Timeout ; | | | | +---------------------------- = 1: PS_IOError ; | | | +-------------------------------- = 1: PS_Select ; | | +----------------------------------- = 1: PS_PaperOut ; | +-------------------------------------- = 1: PS_Ack ; +----------------------------------------- = 1: PS_NotBusy ; ;--------------------------------------------------------------------------- public XlatStatus ; XlatStatus proc near ; mov ah,al ; ____ __ _ and ah,11111101b ; SFP5|IB0A ; ____ ___ inc ah ; SFP5|IBA? ; ___ ____ shr ah,1 ; 0SFP|5IBA ; _ __ ____ ror ah,1 ; A0SF|P5IB ; __ _ ____ ror ah,1 ; BA0S|FP5I and ah,(PS_NotBusy+PS_Ack+PS_Select+PS_IOError); ; __ _ _ ; BA0S|F000 _ and al,PS_PaperOut ; ____ _ 00P0|0000 or ah,al ; BAPS|F000 xor ah,(PS_Ack+PS_PaperOut+PS_Select+PS_IOError) ; _ ret ; BAPS|F000 XlatStatus endp ; ;--------------------------------------------------------------------------- ; Initialize Printer Port ;--------------------------------------------------------------------------- public LPT_Initialize LPT_Initialize proc near ; Check Printer mode ; [out] ZF =0 = KAN-I SENTRO ; ZF !=0 = Full SENTRO call mode_check jnz INT1AH42 ;(ins 92.09.25) ret ;(ins 92.09.25) INT1AH42: ;(ins 92.09.25) push ax ; [8255 mode set] push cx ; I ; I mov al,PRNStrobFF_ON ; ____ I = 0dh out SystemPort,al ; PSTB mask 'ON' NEWIODELAY 10 ; (ins 92.11.11) mov al,0a2h ; I out PRN_Mode,al ; mode set of SENTRO Interface NEWIODELAY 10 ; (ins 92.11.11) mov al,05h ; I ____ out PRN_Mode,al ; SENTRO Interface PSTB 'OFF' NEWIODELAY 10 ; (ins 92.11.11) mov al,PRNStrobFF_OFF ; ____ I out SystemPort,al ; PSTB mask 'OFF NEWIODELAY 10 ; (ins 92.11.11) xor ax,ax ; I out PRN_WSignal,al ; INPUT¥PRIME 'ON' __________ ; I I INT1AH45: ; I I mov cx,0 ; I I loop $ ; I I mov al,1 ; I I out PRN_WSignal,al ; INPUT¥PRIME 'OFF' --------- NEWIODELAY 10 ; (ins 92.11.11) mov al,0ch ; I out PRN_WSignal,al ; INTE Disable(Stop LPT Interrupt) mov cx,0 ; ____ I INT1AH47: ; BUSY Check in al,42h ; I test al,(PS_NotBusy shr 5) ; I loopz INT1AH47 ; I ;======================================================================= stc ; (ins 940115) push di ; (ins 940115) push dx ; We need to wait for (ins 940115) call GetSystemMSecCount ; reset process (ins 940115) mov di, ax ; if reset by port on (ins 940115) pop dx ; PC-PR602R. (ins 940115) @@: ; Then wait 1.5sec here. (ins 940115) push dx ; (ins 940115) call GetSystemMSecCount ; (ins 940115) pop dx ; (ins 940115) sub ax, di ; (ins 940115) cmp ax, 1500 ; (ins 940115) jbe @b ; (ins 940115) pop di ; (ins 940115) ;======================================================================= pop cx ; [ END ] pop ax INT1AH49: ret LPT_Initialize endp page endif ; NEC_98 CheckStatus proc near ifdef NEC_98 call LPT_GetStatus ;(ins 93.03.31)#### and ah, L_BITS ;; #### 93.03.30 #### mov al, ah ;; #### 92.10.11 #### else ; NEC_98 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 endif ; NEC_98 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 ifdef NEC_98 cmp wo[si.Port], 00h; (ins 931219) jz StringToLPT98 ; jmp Toki_StringToLPT ; else ; NEC_98 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 endif ; NEC_98 StringToLPT endp ifdef NEC_98 PUBLIC StringToLPT98 StringToLPT98 proc near push cx ; save count for (ins 92.09.28) push ds ; (ins 92.09.28) cld CharacterToLPT: mov dx, PRN_READ_SIGNAL1 ;Set Status Port (ins 93.03.31)#### in al, dx ;Get Status (ins 93.03.31)#### test al,(PS_NotBusy shr 5) ; if ( != Busy) (ins 93.03.31)#### jnz LPT_PrinterRdy ; yes : OUT Port (ins 93.03.31)#### push dx ; call GetSystemMSecCount ; Get System Timer mov bx, ax ; ax = Tick Value pop dx ; CharToLPT1: push bx call CheckStatus ; quick status check (ins 92.08.xx) pop bx jc PrinterError ; ## 92.10.11 ## (ins 92.08.xx) jnz LPT_PrinterRdy ; (ins 92.08.xx) CharToLPT2: push ax push dx ; call GetSystemMSecCount ; pop dx ; sub ax, bx ; cmp ax, 1000 ; ## 92.10.11 ## 1 sec timeout pop ax jbe CharToLPT1 ; jmp short PrinterBusy ; (ins 92.08.xx) LPT_PrinterRdy: mov al, es:[di] inc di push ax ; (ins 92.10.01) push di ; (ins 92.10.01) call LPT_OutPut2 ;data out (ins 92.10.01) pop di ; (ins 92.10.01) pop ax ; (ins 92.10.01) 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_Select+PS_IOError+PS_Timeout) ;(ins 93.03.30) 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 StringToLPT98 endp ;############ ins 93.03.28 ############# public LPT_OutPut2 ; (ins 93.03.30) [QN] LPT_OutPut2 proc near ; (ins 93.03.28) [QN] FCLI ; (ins 93.03.28) [QN] mov dx,PRN_WRITE_DATA ;Set Write Port (ins 93.03.28) [QN] out dx,al ;Data out (ins 93.03.28) [QN] out 5fh, al ; (ins 93.04.03) [QN] cmp byte ptr [ModeFlag],0 ; ####### (ins 93.03.31) [QN] jnz LPT_OutPut2_X2 ; (ins 93.03.28) [QN] ; (ins 93.03.28) [QN] LPT_OutPut2_X1: ; (ins 93.03.28) [QN] mov dx,PRN_WRITE_SIGNAL1 ; (ins 93.03.28) [QN] mov al,PRN_PSTB_Active_X1 ;Strobe High (ins 93.03.28) [QN] out dx,al ; (ins 93.03.28) [QN] out 5fh, al ; (ins 93.04.03) [QN] mov al,PRN_PSTB_NonActive_X1;Strobe Low (ins 93.03.28) [QN] out dx,al ; (ins 93.03.28) [QN] FSTI ; (ins 93.03.28) [QN] ret ; (ins 93.03.28) [QN] ; (ins 93.03.28) [QN] LPT_OutPut2_X2: ; (ins 93.03.28) [QN] mov dx,PRN_WRITE_SIGNAL1 ; (ins 93.03.28) [QN] mov al,PRN_PSTB_Active_X2 ;Strobe High (ins 93.03.28) [QN] out dx,al ; (ins 93.03.28) [QN] out 5fh, al ; (ins 93.04.03) [QN] mov al,PRN_PSTB_NonActive_X2;Strobe Low (ins 93.03.28) [QN] out dx,al ; (ins 93.03.28) [QN] FSTI ; (ins 93.03.28) [QN] ret ; (ins 93.03.28) [QN] LPT_OutPut2 endp ; (ins 93.03.28) [QN] ;(ins 92.08.xx) page ;------------------------------------------------------- ; Check Printer Mode ;------------------------------------------------------- ; [out] ZF == 0 = KAN-I SENTRO ; ZF != 0 = Full SENTRO ;------------------------------------------------------- _X2_mode equ 00000100b ; _NPC_check equ 10000000b ; mode_check: ; mov Byte ptr [ModeFlag],0 ;(ins 93.03.28) push ax ; push ds ; mov ax,40H ; mov ds,ax ; test by ds:[58H],_NPC_check ; pop ds ; pop ax ; jz NH_check ;Standard Machine ;------------------------------------- ; Hiper 98 ;------------------------------------- call NH_check ; jnz exit_mode_check ;Highreso for NPC ;------------------------------------ ; Hiper 98 Normal Mode ;------------------------------------ push ax ; push dx ; mov dx,448h ; ;------------------------------------------------------ ;Read data of Ex mode register from 448h ;bit0=1 : Full SENTRO, bit0=0 : KAN-I SENTRO ;------------------------------------------------------ in al,dx ; test al,1 ; pop dx ; pop ax ; jz exit_mode_check ;(ins 93.03.28) mov Byte ptr [ModeFlag],1 ;(ins 93.03.28) ;(ins 93.03.28) exit_mode_check: ret ; ;------------------------------------------------------- ; Check Machine architecture ; ; [out] ZF =0 ... Normal ; ZF !=0 ... Highreso ;------------------------------------------------------- bios_common equ 501h ; _X2_system equ 00001000b ; ; NH_check: push ax ; push ds ; ; 40H:[101H] bit3 (_X2_system) ; =0 : Normal ; =1 : Highreso mov ax,40H ; mov ds,ax ; test by ds:[101H],_X2_system ; pop ds ; pop ax ; jz @f ;(ins 93.03.28) mov Byte ptr [ModeFlag],1 ;(ins 93.03.28) @@: ;(ins 93.03.28) ret ; ; mode_check2: ;(ins 93.03.28) cmp byte ptr [ModeFlag],0 ;(ins 93.03.28) ret ;(ins 93.03.28) page ;----------------------------Private-Routine----------------------------; ; Toki_DoLPT - Do Function To LPT port ; ; 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: ;-----------------------------------------------------------------------; public Toki_DoLPT Toki_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 Toki_LPT_OutChar cmp ch, 1 jz Toki_LPT_Reset jmp Toki_LPT_GetStatus ret Toki_LPT_Reset: inc dx inc dx mov al, L_RESET iodelay out dx, al push dx cCall GetSystemMsecCount mov bx, ax Toki_LPT_ResetDelay: push bx cCall GetSystemMsecCount pop bx sub ax, bx cmp ax, 300 ; 1/3 sec as good as any jbe Toki_LPT_ResetDelay pop dx mov al, L_NORMAL iodelay iodelay out dx, al dec dx dec dx jmp short Toki_LPT_GetStatus Toki_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 Toki_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 Toki_LPT_WaitReady else dec dx endif test ah, PS_PaperOut or PS_IOError jnz Toki_LPT_PrinterNotReady test ah, PS_Select jz Toki_LPT_PrinterNotReady test ah, PS_NotBusy jnz Toki_LPT_PrinterReady push ax push dx call GetSystemMSecCount pop dx pop bx sub ax, di cmp ax, 300 ; 1/3 sec timeout jbe Toki_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 Toki_LPT_PrinterNotReady: pop di pop cx ; throw away character jmp short Toki_LPT_ReturnStatus Toki_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 Toki_LPT_Strobe: inc dx ; control port mov al, L_STROBE ; set strobe high iodelay out dx, al ; ... mov al, L_NORMAL ; out dx, al ; set strobe low sub dx, 2 ; point back to port base ; FALL THRU Toki_LPT_GetStatus: inc dx ; point to status port Toki_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 Toki_LPT_GS1 ; if they changed try again... endif Toki_LPT_ReturnStatus: assumes ds,Data and ax,( PS_Select+PS_IOError+PS_Timeout)*256 ; (ins 940125) 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 Toki_DoLPT40: assumes ds,Data or ComErr[si],CE_TXFULL ;Show queue full ret Toki_DoLPT endp page Toki_CheckStatus proc near in al, dx ; get status bits test al, PS_PaperOut ; paper empty ? (ins 94.08.09) jz @f ; N: Next (ins 94.08.09) and al, not PS_IOError ; Y: Show I/O error (ins 94.08.09) @@: ; (ins 94.08.09) 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 test al, PS_PaperOut ; paper empty ? (ins 94.08.09) jz @f ; N: Next (ins 94.08.09) and al, not PS_IOError ; Y: Show I/O error (ins 94.08.09) @@: ; (ins 94.08.09) and al, L_BITS xor al, L_BITS_INVERT cmp al, ah ; did any bits change? jnz Toki_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 Toki_CheckStatus endp ;----------------------------Public Routine-----------------------------; ; Toki_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 Toki_StringToLPT Toki_StringToLPT proc near mov dx, Port[si] ; get port address inc dx ; access status port push cx ; save count for later push ds cld call Toki_CheckStatus ; quick status check before slowness jc Toki_PrinterError jz Toki_PrinterBusy ; if printer not ready for first char ; then just return with CE_TXFULL Toki_CharacterToLPT: push dx ; call GetSystemMSecCount ; Get System Timer mov bx, ax ; ax = Tick Value pop dx ; ; Toki_CharToLPT1: ; push bx ; call Toki_CheckStatus ; quick status check pop bx ; jc Toki_PrinterError ; jnz Toki_LPT_PrinterRdy; ; Toki_CharToLPT2: ; push ax ; push dx ; call GetSystemMSecCount ; pop dx ; sub ax, bx ; cmp ax, 1000 ; 1 sec timeout pop ax ; jbe Toki_CharToLPT1 ; jmp short Toki_PrinterBusy ; ; Toki_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 ; out dx, al ; set strobe low dec dx ; point to status port for check loop Toki_CharacterToLPT pop ds jmp short Toki_LPT_Exit Toki_PrinterError: pop ds jmp short Toki_ReturnStatus Toki_PrinterBusy: pop ds or ComErr[si],CE_TXFULL ; set buffer full bit or al, L_TIMEOUT ; show timeout bit Toki_ReturnStatus: and ax,( PS_Select+PS_IOError+PS_Timeout) ; (ins 940125) 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 Toki_LPT_Exit: pop ax ; get total count sub ax, cx ; subtract remaining unsent charts ret Toki_StringToLPT endp TOMOE_PAT DB 16 DUP('PATCH !!') ;PATCH AREA (ins 92.11.11) endif ; NEC_98 IFDEF DEBUG ;Publics for debugging ifdef NEC_98 public Toki_LPT_Reset public Toki_LPT_Outchar public Toki_LPT_Strobe public Toki_LPT_GetStatus public Toki_DoLPT40 else ; NEC_98 public LPT_Reset public LPT_Outchar public LPT_Strobe public LPT_GetStatus public DoLPT40 endif ; NEC_98 ENDIF sEnd code End