home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 December
/
simtel1292_SIMTEL_1292_Walnut_Creek.iso
/
msdos
/
pctech
/
feb88.arc
/
OS2LPT.ASM
< prev
next >
Wrap
Assembly Source File
|
1987-12-16
|
25KB
|
811 lines
PAGE 60,132
TITLE Line Printer Driver
NAME LPT
.286
;***************************************************************************
; Miscellaneous assembly parameters
IOSEG EQU 40H ; BIOS data area segment address
IOTAB EQU 8 ; offset to printer table in BIOS area
IOLPT1 EQU 3BCH ; normal LPT1 I/O address
IOLPT2 EQU 378H ; normal LPT2 I/O address
IOINT1 EQU 7 ; normal LPT1 interrupt level
IOINT2 EQU 5 ; normal LPT2 interrupt level
TIMEOUT EQU 10000 ; timeout in milliseconds, -1 for no timeout
;***************************************************************************
;
; Device Helper Service information
DevDone EQU 1
Block EQU 4
Run EQU 5
LockSeg EQU 13H
UnlockSeg EQU 14H
PhysToVirt EQU 15H
VirtToPhys EQU 16H
SetROMVector EQU 1AH
SetIRQ EQU 1BH
UnSetIRQ EQU 1CH
MonCreate EQU 1FH
Register EQU 20H
DeRegister EQU 21H
MonWrite EQU 22H
MonFlush EQU 23H
GetDOSVar EQU 24H
ROMCritSect EQU 26H
VerifyAccess EQU 27H
EOI EQU 31H
UnPhysToVirt EQU 32H
;***************************************************************************
; Driver request packet data structure
;***************************************************************************
DRVPKT STRUC
P_LEN DB ? ; packet length
P_UNIT DB ? ; unit number
P_CMD DB ? ; command (operation) code
P_STAT DW ? ; status code
P_SYSL DD ? ; system queue linkage
P_DEVL DD ? ; device queue linkage
DRVPKT ENDS
;
; Flags in P_STAT
PS_ERR EQU 8000H ; error flag
PS_ERRD EQU 4000H ; device error flag
PS_BUSY EQU 0200H ; busy flag
PS_DONE EQU 0100H ; completion flag
;
; Error codes in P_STAT
;
PE_CMD EQU 5 ; bad command code
PE_OUT EQU 9 ; out of paper
PE_WRT EQU 0AH ; write error
PE_GEN EQU 0CH ; general failure
;
; Request packet extension for initialize operations (code 0)
;
PKTI STRUC
DB 13 DUP(?) ; header
DB ? ; reserved
P_HLP0 DW ? ; DevHlp address, returns CS size
P_HLP1 DW ? ; DevHlp address, returns DS size
PKTI ENDS
;
; Request packet extension for write operation (codes 08H and 09H)
;
PKTW STRUC
DB 13 DUP(?) ; header
DB ? ; unused
P_BADD DD ? ; buffer address
P_BLEN DW ? ; buffer length
PKTW ENDS
;
; Request packet extension for IOCTL operation
;
PKTIOC STRUC
DB 13 DUP(?) ; header
P_CAT DB ? ; category
P_FUN DB ? ; function
P_PARM DD ? ; parameter area pointer
P_DATA DD ? ; data area pointer
PKTIOC ENDS
;
; Data area for IOCTL "register" function
;
IOCREG STRUC
R_POS DB ? ; position code
R_NDX DW ? ; index
R_IN DD ? ; input buffer address
R_OUT DW ? ; output buffer offset
IOCREG ENDS
;***************************************************************************
;
; Monitor chain buffer structure
;
MONLEN EQU 132 ; size of monitor buffer
MONHDR EQU 4 ; size of monitor buffer header
MONPKT STRUC
M_FLAG DW 0 ; flags
M_PID DW 0 ; user process id
M_DATA DB MONLEN-MONHDR DUP(?) ; data area
MONPKT ENDS
;
; Monitor flags (byte 0 of M_FLAG)
;
MF_OPEN EQU 1 ; open flag
MF_CLOS EQU 2 ; close flag
MF_FLSH EQU 4 ; flush flag
SUBTTL Data Segment
PAGE
;***************************************************************************
; Define the data segment. The name _DATA is used here for compatibility
; with most OS/2 C compilers, but any name is acceptable.
;***************************************************************************
_DATA SEGMENT WORD PUBLIC 'DATA'
;***************************************************************************
;
; This is the LPT1 device driver header. No other data can precede it.
;
;***************************************************************************
LPT1 DW PRN,SEG PRN ; linkage
DW 88C0H ; device type bits...
; 15 => character device
; 11 => open/close support
; 09-07 => driver type 1 (OS/2)
; 06 => IOCTL supported
DW S_LPT ; offset to strategy routine
DW -1 ; reserved
DB 'LPT1 ' ; device name
DW 4 DUP(0) ; reserved
;***************************************************************************
; This is the PRN device driver header. LPT1 and PRN are synonyms.
;***************************************************************************
PRN DD -1 ; linkage (-1 indicates end of header list)
DW 88C0H ; device type bits...
; 15 => character device
; 11 => open/close support
; 09-07 => driver type 1 (OS/2)
; 06 => IOCTL supported
DW S_LPT ; offset to strategy routine
DW -1 ; reserved
DB 'PRN ' ; device name
DW 4 DUP(0) ; reserved
;***************************************************************************
; Driver command table
CMDTBS DW S_INIT ; 00 => Initialize
DW CMDBAD ; 01 => Check media
DW CMDBAD ; 02 => Build BPB
DW CMDBAD ; 03 => Reserved
DW CMDBAD ; 04 => Read
DW CMDBAD ; 05 => Peek
DW CMDBAD ; 06 => Get input status
DW CMDBAD ; 07 => Flush input buffer
DW S_WRT ; 08 => Write
DW S_WRT ; 09 => Write and verify
DW S_STAT ; 0A => Get output status
DW S_FLUSH ; 0B => Flush output buffer
DW CMDBAD ; 0C => Reserved
DW S_OPEN ; 0D => Open
DW S_CLOSE ; OE => Close
DW CMDBAD ; 0F => Check removable media
DW S_IOCTL ; 10 => I/O control
DW CMDBAD ; 11 => Reset media
DW CMDBAD ; 12 => Get logical drive map
DW CMDBAD ; 13 => Set logical drive map
CMDTBE DW S_RMV ; 14 => Remove driver (de-install)
CMDMAX EQU (CMDTBE-CMDTBS)/2
;***************************************************************************
; Monitor buffer
MON DW MONLEN ; receive buffer, used by notify routine
MONR MONPKT <>
MONS MONPKT <> ; send buffer, used by strategy routine
;***************************************************************************
; Driver status flags
STATUS DB 0 ; driver status flags
SF_TIME EQU 1 ; set if timer is running
SF_FLSH EQU 2 ; set if flushing
SF_WAIT EQU 4 ; set if waiting for interrupt
;***************************************************************************
; Miscellaneous data items
;
DEVHLP DD 0 ; DevHlp function address
IOTADD DW IOTAB,IOSEG ; points to printer table in BIOS RAM
IOLPT DW 0 ; current printer I/O address
IOINT DW 0 ; current printer interrupt level
IOTIME DD TIMEOUT ; timeout value for printer delay
MONHAN DW 0 ; monitor handle
;***************************************************************************
;
; End of data segment
;
END_DS EQU $ ; used by S_INIT
_DATA ENDS
SUBTTL Code Segment
PAGE
;***************************************************************************
;
; Define the code segment. The name _TEXT is used for compatibility with
; most OS/2 C compilers, but any name is acceptable. The ASSUME statement
; indicates what values the driver expects in the segment registers.
;
;***************************************************************************
_TEXT SEGMENT WORD PUBLIC 'CODE'
ASSUME CS:_TEXT,DS:_DATA
;***************************************************************************
;
; This is the strategy routine. It is entered via a far call, with the
; request packet pointer in ES:BX. The packet pointer is valid in both
; real and protected mode.
;
;***************************************************************************
S_LPT PROC FAR
PUSH ES ; save request packet pointer
PUSH BX
MOV BP,SP ; set up stack frame pointer
XOR AX,AX ; get driver command code
MOV AL,ES:[BX].P_CMD
CMP AL,CMDMAX ; check if in range
JA CMDBAD ; error if not
MOV DI,AX ; call the command routine
ADD DI,DI
CALL CMDTBS[DI]
POP BX ; restore packet pointer
POP ES
RETF ; return to caller
;***************************************************************************
; The following labels are convenient exit points for strategy routines.
; SS:SP must point to the return address, and the request packet pointer
; must be just above the return address.
;***************************************************************************
;
; Come here for bad commands
;
CMDBAD: MOV AX,PE_CMD+PS_ERR
;
; Common exit point, with status code in AX
;
DONE: MOV BP,SP ; set frame pointer
LES BX,[BP+2] ; get packet pointer
OR AX,PS_DONE ; set completion flag
MOV ES:[BX].P_STAT,AX ; store codes
RETN
;
; Come here for general errors
;
ERRGEN: MOV AX,PE_GEN+PS_ERR
JMP DONE
;***************************************************************************
; S_WRT -- Initiate a write operation
;
S_WRT: TEST STATUS,SF_FLSH
JNZ RETOK ; ignore write request if flushing
CALL GETPID ; get user process id
JC ERRGEN ; branch if error
PUSH AX ; save it on stack
PUSH 0 ; clear user buffer index
PUSH ES:[BX].P_BLEN ; copy user buffer length/address
PUSH WORD PTR ES:[BX].P_BADD+2
PUSH WORD PTR ES:[BX].P_BADD
MOV BP,SP ; BP is now frame pointer
;
; Call MonWrite one or more times to process the user's data
;
WRT1: MOV CX,[BP+4] ; get residual length
CMP CX,MONLEN-MONHDR
JNA WRT2 ; branch if fits in monitor buffer
MOV CX,MONLEN-MONHDR ; else process part of the data
WRT2: MOV AX,[BP] ; get user buffer address
MOV BX,[BP+2]
PUSH CX ; save current length
MOV DX,0100H+PhysToVirt ; convert address into ES:DI
CALL DEVHLP
POP CX ; restore current length
JC WRT4 ; branch if error
SUB [BP+4],CX ; reduce residual length
ADD DI,[BP+6] ; compute next byte address
ADD [BP+6],CX ; update buffer index
LEA SI,MONS.M_DATA ; move data to monitor send buffer
PUSH CX
WRT3: MOV AL,[SI]
MOV ES:[DI],AL
INC SI
INC DI
LOOP WRT3
POP CX
ADD CX,MONHDR ; adjust length to include header
MOV AX,[BP+8] ; move process id to header
MOV MONS.M_PID,AX
MOV MONS.M_FLAG,0 ; reset all flags
LEA SI,MONS ; set pointer to data record
MOV AX,MONHAN ; get monitor handle
MOV DX,MonWrite ; DH=0 to synchronize in dispatcher
CALL DEVHLP ; perform monitor write
JC WRT4 ; branch if error
CMP WORD PTR [BP+4],0
JNE WRT1 ; loop till residual length is zero
MOV DL,UnPhysToVirt ; restore prior addressing mode
CALL DEVHLP
ADD SP,8 ; discard local stack frame
;
; Come here when operation has completed successfully
;
RETOK: XOR AX,AX ; clear error code
JMP DONE ; return
;
; Come here for write error
;
WRT4: MOV AX,PE_WRT+PS_ERR ; load error code
ADD SP,8 ; discard local stack frame
JMP DONE ; return
;***************************************************************************
;
; S_STAT -- Get output status
;
S_STAT: JMP RETOK ; return "not busy"
;***************************************************************************
;
; S_FLUSH -- Flush output queue
;
S_FLUSH: OR STATUS,SF_FLSH ; set flush flag
MOV AX,MONHAN ; send flush message to monitors
MOV DL,MonFlush
CALL DEVHLP
JNC RETOK ; exit if successful
JMP ERRGEN ; else signal general failure
;***************************************************************************
;
; S_OPEN -- Open the printer
;
S_OPEN: CMP BYTE PTR ES:[BX].P_STAT,0
JNE OPEN1 ; ignore if DosMonOpen
;
; Come here to handle DosOpen
;
MOV MONS.M_FLAG,MF_OPEN ; set open flag in header
CALL GETPID ; put process id into header
JC CLS0
MOV MONS.M_PID,AX
MOV CX,MONHDR ; set message length
LEA SI,MONS ; set pointer to message
MOV DX,MonWrite ; DH=0 to synchronize in dispatcher
CALL DEVHLP ; send the message
JC CLS0
OPEN1: JMP RETOK
;***************************************************************************
;
; S_CLOSE -- Close the printer
;
S_CLOSE: CMP BYTE PTR ES:[BX].P_STAT,0
JNE CLS1 ; branch if DosMonClose
;
; Come here to handle DosClose
;
MOV MONS.M_FLAG,MF_CLOS ; set close flag in header
CALL GETPID ; put process id into header
JC CLS0
MOV MONS.M_PID,AX
MOV CX,MONHDR ; set message length
LEA SI,MONS ; set pointer to message
MOV DX,MonWrite ; DH=0 to synchronize in dispatcher
CALL DEVHLP ; send the message
JNC RETOK
CLS0: JMP ERRGEN
;
; Come here to handle DosMonClose
;
CLS1: CALL GETPID ; get monitor process id
JC CLS0
MOV BX,AX
MOV AX,MONHAN ; de-register this monitor
MOV DL,DeRegister
CALL DEVHLP
JC CLS0 ; branch if failure
JMP RETOK
;***************************************************************************
;
; S_IOCTL -- I/O control operation
;
S_IOCTL: CMP ES:[BX].P_CAT,5
JNE IOC0
CMP ES:[BX].P_FUN,65H
JE IOC_S ; branch if IOCTL 5.101, STATUS
IOC0: CMP ES:[BX].P_CAT,10
JNE IOC1
CMP ES:[BX].P_FUN,40H
JE IOC_R ; branch if IOCTL 10.64, REGISTER
IOC1: CMP ES:[BX].P_CAT,11
JNE IOC2
CMP ES:[BX].P_FUN,60H
JE IOC_Q ; branch if IOCTL 11.96, QUERY MON
IOC2: JMP CMDBAD ; else indicate invalid request
IOC3: JMP ERRGEN
;
; Query monitor support (Category 11, function 96)
;
IOC_Q: JMP RETOK ; return OK to show monitor support
;
; Get printer status (Category 5, function 101)
;
IOC_S: LES DI,ES:[BX].P_DATA ; verify access to data buffer
MOV AX,ES
MOV CX,1
MOV DX,0100H+VerifyAccess
CALL DEVHLP
JC IOC3 ; branch if access denied
XOR BX,BX ; lock the data buffer segment
MOV DL,LockSeg
CALL DEVHLP
PUSH AX ; save lock handle
PUSH BX
PUSH DS ; convert to physical address
MOV AX,ES
MOV DS,AX
MOV SI,DI
MOV DL,VirtToPhys
CALL DEVHLP
POP DS
MOV DX,0100H+PhysToVirt ; convert to virtual address
CALL DEVHLP
JC IOC4 ; branch if error
CLI ; begin critical section
MOV DX,IOLPT ; get device status
INC DX
IN AL,DX
AND AL,0F8H ; save only important bits
XOR AL,48H ; toggle "acknowledge" and "error"
MOV AH,STATUS ; include "timer", "flush", "wait"
AND AH,7
OR AL,AH
MOV ES:[DI],AL ; return status in user's data area
STI ; end critical section
MOV DL,UnPhysToVirt ; release mapping
CALL DEVHLP
POP BX ; unlock data buffer segment
POP AX
MOV DL,UnlockSeg
CALL DEVHLP
JMP RETOK
IOC4: POP BX ; come here on error after lock
POP AX
MOV DL,UnlockSeg
CALL DEVHLP
IOC5: JMP ERRGEN
;
;
; Register a monitor (Category 10, function 64)
;
IOC_R: CALL GETPID ; get monitor process id
JC IOC3 ; branch if error
LES SI,ES:[BX].P_DATA ; get data area address
MOV DH,ES:[SI].R_POS ; get postion code
MOV DI,ES:[SI].R_OUT ; get output buffer offset
LES SI,ES:[SI].R_IN ; get input buffer pointer
MOV AX,MONHAN ; get monitor handle
MOV DL,Register ; register this monitor
CALL DEVHLP
JC IOC5 ; branch if error
JMP RETOK
;***************************************************************************
;
;
; S_RMV -- Remove (de-install) the driver
;
S_RMV: MOV AX,MONHAN ; kill monitor chain
OR AX,AX
JZ RMV1
MOV DL,MonCreate
CALL DEVHLP
RMV1: MOV BX,IOINT ; detach from interrupt
OR BX,BX
JZ RMV2
MOV DL,UnSetIRQ
CALL DEVHLP
RMV2: JMP RETOK
;
;***************************************************************************
;
; NOTIFY routine, called by monitor dispatcher when data is available.
;
NOTIFY PROC FAR
TEST MONR.M_FLAG,MF_OPEN
JNZ N_OPEN ; branch if "open" message
TEST MONR.M_FLAG,MF_CLOS
JNZ N_CLOS ; branch if "close" message
TEST MONR.M_FLAG,MF_FLSH
JZ N_WRT ; branch if "write" message
;
; Process "flush" message from the monitor chain
;
N_FLSH: AND STATUS,NOT SF_FLSH ; reset flush flag
JMP RETOK
;
; Process "open" message from monitor chain
;
N_OPEN: JMP RETOK
;
; Process "close" message from the monitor chain
;
N_CLOS: JMP RETOK
;
; Process "write" message from the monitor chain
;
N_WRT: MOV CX,MON ; get message length
SUB CX,MONHDR+2 ; subtract header and length word
JBE N03 ; branch if no data
XOR SI,SI ; reset data buffer index
N00: TEST STATUS,SF_FLSH
JNZ N03 ; abort if flush flag is set
MOV DX,IOLPT ; get printer address
INC DX ; check status
IN AL,DX
TEST AL,80H
JZ N04 ; branch if not ready
N01: MOV AL,MONR.M_DATA[SI] ; send next byte
DEC DX
OUT DX,AL
INC DX ; strobe it out
INC DX
MOV AL,0DH
OUT DX,AL
MOV AX,10
N02: DEC AX
JNZ N02
MOV AL,0CH
OUT DX,AL
INC SI ; loop till all bytes sent
LOOP N00
N03: RETF ; return to monitor dispatcher
;
; Come here to wait for printer interrupt
;
N04: CLI ; begin critical section
INC DX ; enable printer interrupt
MOV AL,1CH
OUT DX,AL
DEC DX ; check status
IN AL,DX
TEST AL,80H
JZ N05 ; branch if still busy
MOV AL,0CH ; disable printer interrupt
INC DX
OUT DX,AL
STI ; leave critical section
JMP N00 ; continue data output
N05: PUSH CX ; save registers
PUSH SI
OR STATUS,SF_WAIT ; set "wait" status
MOV AX,WORD PTR IOTADD+2 ; use I/O table address as event id
MOV BX,WORD PTR IOTADD
MOV DI,WORD PTR IOTIME+2 ; load timeout value
MOV CX,WORD PTR IOTIME
MOV DX,Block ; DH=0 for interruptable sleep
CALL DEVHLP
CLI ; begin critical section
JC N07 ; branch if timeout or unusual event
TEST STATUS,SF_WAIT
JNZ N05 ; re-block if wrong event
N06: MOV DX,IOLPT ; disable printer interrupt
INC DX
INC DX
MOV AL,0CH
OUT DX,AL
STI ; end critical section
JMP N00 ; go send more data
;
; Come here if wait times out or is aborted by unusual event
;
N07: OR STATUS,SF_TIME ; set timer flag
MOV AX,WORD PTR IOTADD+2 ; use I/O table address as event id
MOV BX,WORD PTR IOTADD
XOR DI,DI ; set 500 ms timeout value
MOV CX,500
MOV DX,Block ; DH=0 for interruptable sleep
CALL DEVHLP
CLI ; begin critical section
TEST STATUS,SF_FLSH
JNZ N08 ; branch if flush flag is set
TEST STATUS,SF_WAIT
JNZ N07 ; repeat if still waiting
XOR STATUS,SF_TIME ; reset timer flag
JMP N06 ; continue data output
;
; Come here if operation is being flushed
;
N08: AND STATUS,NOT (SF_TIME OR SF_WAIT) ; reset flags
MOV DX,IOLPT ; disable printer interrupt
INC DX
INC DX
MOV AL,0CH
OUT DX,AL
STI ; end critical section
RETF
NOTIFY ENDP
;***************************************************************************
;
; I_LPT routine, called by hardware interrupt dispatcher
;
I_LPT PROC FAR
TEST STATUS,SF_WAIT
JZ INT1 ; ignore if not in "wait" mode
XOR STATUS,SF_WAIT ; reset "wait" status
MOV AX,WORD PTR IOTADD+2 ; wake up the NOTIFY routine
MOV BX,WORD PTR IOTADD
MOV DL,Run
CALL DEVHLP
INT1: CLI ; begin critical section
MOV AX,IOINT ; signal end-of-interrupt
MOV DL,EOI
CALL DEVHLP
CLC ; clear CF to claim interrupt
RETF
I_LPT ENDP
;***************************************************************************
;
; User interrupt routine, called by DOS application via interrupt 17H.
;
U_LPT PROC FAR
STI ; enable interrupts
PUSH BP ; save all registers
PUSH ES
PUSH DS
PUSH DI
PUSH SI
PUSH DX
PUSH CX
PUSH BX
PUSH AX
MOV BX,CS:SAVEDS ; set up DS for the driver
MOV DS,BX
MOV DX,IOLPT ; get printer address
OR AH,AH
JZ U_WRT ; AH=0 to print AL
DEC AH
JZ U_INIT ; AH=1 to initialize
DEC AH
JZ U_STAT ; AH=2 to get status
U_RET: POP AX ; return from interrupt
POP BX
POP CX
POP DX
POP SI
POP DI
POP DS
POP ES
POP BP
IRET
;
; Initialization routine saves DS here
;
SAVEDS DW 0 ; DS is saved here
;
; Come here to print the character in AL
;
U_WRT: MOV AL,1 ; begin BIOS critical section
MOV DL,ROMCritSect
CALL DEVHLP
MOV CX,MONHDR+1 ; set monitor message length
MOV MONS.M_PID,0 ; use 0 for DOS process id
MOV MONS.M_FLAG,0 ; reset flags
POP AX ; put byte into buffer
PUSH AX
MOV MONS.M_DATA,AL
LEA SI,MONS ; send message to monitor chain
MOV AX,MONHAN
MOV DX,MonWrite
CALL DEVHLP
XOR AL,AL ; end BIOS critical section
MOV DL,ROMCritSect
CALL DEVHLP
; JMP U_STAT ; go get status
;
; Come here to initialize the printer
;
U_INIT: ; same as status request
;
; Come here to get printer status
;
U_STAT: CLI ; begin critical section
MOV DX,IOLPT ; get device status
INC DX
IN AL,DX
AND AL,0F8H ; save only important bits
XOR AL,48H ; toggle "acknowledge" and "error"
MOV AH,STATUS ; include "timer", "flush", "wait"
AND AH,7
OR AL,AH
STI ; end critical section
POP BX ; restore AH and set up AL return
MOV AH,BH
PUSH AX
JMP U_RET
U_LPT ENDP
;
;***************************************************************************
;
; GETPID function, called to obtain current process id, which is returned
; in AX. The function returns with CF set if an error occurs.
;
GETPID PROC NEAR
PUSH ES ; save regs
PUSH BX
PUSH DX
MOV AL,2 ; get address of process info pointer
MOV DL,GetDOSVar
CALL DEVHLP
JC PID1 ; branch if error
PUSH AX ; get process info pointer in ES:BX
POP ES
LES BX,ES:[BX]
MOV AX,ES:[BX] ; PID is first word
CLC ; reset CF to indicate success
PID1: POP DX ; restore regs and return
POP BX
POP ES
RET
GETPID ENDP
;***************************************************************************
;
; Mark the end of the code segment. Everything after this is discarded
; after initialization.
END_CS EQU $
;***************************************************************************
;
; S_INIT -- Initialize
;
S_INIT: MOV AX,ES:[BX].P_HLP0 ; save DevHlp address
MOV WORD PTR DEVHLP,AX
MOV AX,ES:[BX].P_HLP1
MOV WORD PTR DEVHLP+2,AX
LEA AX,END_CS ; return CS size
MOV ES:[BX].P_HLP0,AX
LEA AX,END_DS ; return DS size
MOV ES:[BX].P_HLP1,AX
;
; Check for valid I/O configuration
LES DI,DWORD PTR IOTADD ; get printer I/O address
MOV DX,ES:[DI]
MOV AL,IOINT1 ; check if first parallel device
CMP DX,IOLPT1
JE IN01 ; branch if yes
MOV AL,IOINT2 ; check if second parallel device
CMP DX,IOLPT2
JNE INERR ; branch if no
;
; Initialize the I/O channel and device
;
IN01: MOV IOLPT,DX ; save I/O address
MOV BYTE PTR IOINT,AL ; save interrupt level
INC DX ; set DX to control port
INC DX
MOV AL,8 ; select and initialize
OUT DX,AL
MOV AX,1000 ; delay at least 50 microseconds
IN02: DEC AX
JNZ IN02
MOV AL,12 ; select, no initialize, no auto LF
OUT DX,AL
;
; Create monitor chain and save its handle
;
PUSH DS ; make ES:SI point to monitor buffer
POP ES
LEA SI,MON
PUSH DS ; save DS
PUSH CS ; make DS:DI point to notify routine
POP DS
LEA DI,NOTIFY
XOR AX,AX ; set AX=0 to create monitor chain
MOV DL,MonCreate ; call DEVHLP using ES instead of DS
CALL ES:DEVHLP
POP DS ; restore DS
JC INERR ; branch if error
MOV MONHAN,AX ; save monitor handle
;
; Activate the hardware interrupt
LEA AX,I_LPT ; get interrupt routine address
MOV BX,IOINT ; get interrupt level number
MOV DX,SetIRQ ; DH=0 for non-shared interrupt
CALL DEVHLP
JC IN03 ; branch if error
;
; Activate user interrupt 17H for printer BIOS
;
LEA AX,U_LPT ; get interrupt routine address
MOV BX,17H ; get interrupt number
LEA SI,SAVEDS ; get DS save location address
MOV DL,SetROMVector ; set the interrupt vector
CALL DEVHLP
JMP RETOK
;
; Come here on initialization error
IN03: MOV AX,MONHAN ; kill monitor chain
MOV DL,MonCreate
CALL DEVHLP
INERR: JMP ERRGEN
;
S_LPT ENDP ; end of main proc
_TEXT ENDS ; end of code segment
END ; end of module