home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
ddkx86v5.zip
/
DDKX86
/
SRC
/
DEV
/
PRINTER
/
PRTHWIAT.ASM
< prev
next >
Wrap
Assembly Source File
|
1995-04-14
|
169KB
|
2,839 lines
;*DDK*************************************************************************/
;
; COPYRIGHT (C) Microsoft Corporation, 1989
; COPYRIGHT Copyright (C) 1995 IBM Corporation
;
; The following IBM OS/2 WARP source code is provided to you solely for
; the purpose of assisting you in your development of OS/2 WARP device
; drivers. You may use this code in accordance with the IBM License
; Agreement provided in the IBM Device Driver Source Kit for OS/2. This
; Copyright statement may not be removed.;
;*****************************************************************************/
; SCCSID = @(#)prthwiat.asm 6.21 92/03/24
;/**********************************************************************
;/* *
;/* *
;/* *
;/**********************************************************************
TITLE PRINTDD - PRINTER DEVICE DRIVER HARDWARE ROUTINES
NAME PRINTDD
PAGE ,132
.286C
;***********************************************************************
; CODING CONVENTIONS
; all psuedo-ops, equates, documentation, publics, and externs are in uppercase.
; all code and data names are in lowercase.
;
; ROUTINES IN THIS MODULE:
; INITIALPRT,HYBRID
; PRTDEINSTALL
; PRINTBLOCK
; PRT_TRANSMIT
; SEARCHANDSTEAL
; eInt_1
; eInt_2
; eInt_3
; PRTINT05
; PRTINT07
; STARTTIMER
; STOPTIMER
; PRTTIMGR
; TIMERINTERRUPT
; CHANGEIRQTOST
; CHECKSTATUS
; INTERRUPT
; SENDCHAR
; SENDTODEV
; PRT_TIMEOUT_1
; PRT_TIMEOUT_2
; PRT_TIMEOUT_3
; PRT_TIMEOUT
; CLEANUP
; PRTERP
; GETSTATUS,HYBRID
; PRTINIT
; prtdeterminehardware
; RM_PRT_RegisterResources
; PARSECMDLINE
;
; MODIFICATION HISTORY
;
; 87416 07/11/94 SLC (ChgTeam) Added one line to proc interrupt
; to disable interrupts in
; interrupt01 before returning to
; interrupt manager.
;
;***********************************************************************
.XCREF
.XLIST
INCLUDE basemaca.inc ; VARIOUS MACRO'S (BREAK, LJC, ETC.)
INCLUDE osmaca.inc
INCLUDE devsym.inc
INCLUDE devhlp.inc ; DEFINITION OF DEVICE HELP CALLS.
INCLUDE struc.inc ; STRUCTURED MACRO SUPPORT
INCLUDE infoseg.inc ; STRUCTURES DEFINING THE INFOSEG
INCLUDE pvwxport.inc ; PERFVIEW STRUCS AND EQUATES.
INCLUDE iniequ.inc ; CONFIG.SYS DEFAULT EQUATES
INCLUDE iodelay.inc ; IODELAY MACROS
.LIST
.CREF
INCLUDE prtdd.inc ; PRINTER DEVICE DRIVER INCLUDE FILE
INCLUDE prtdd1.inc ; PRINTER DEVICE DRIVER INCLUDE FILE
INCLUDE prtinit.inc ; PRINTER DEVICE DRIVER INCLUDE FILE
INCLUDE prteisa.inc ; EISA SUPPORT EQUATES
BREAK <DATA FOR THE PRINTER DEVICE DRIVER>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SUBROUTINE NAME: PRTDATA */
;/* */
;/* DESCRIPTIVE NAME: PRINTER DEVICE DRIVER DATA DECLARATIONS */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
DSEG SEGMENT public 'data'
EXTRN glinfoseg:DWORD
EXTRN dosvar:DWORD
EXTRN device_help:DWORD
EXTRN _Device_Help:DWORD
EXTRN numofprts:BYTE
EXTRN flags:BYTE
EXTRN perprtarea:BYTE
EXTRN moncache:BYTE
EXTRN plptname:BYTE
PUBLIC irq5index
PUBLIC irq7owner
PUBLIC timeoutval
PUBLIC deinstallflg
PUBLIC doserrors
PUBLIC fIRQStolen
EVEN
irq5index dw ? ; INDEX INTO PERPRTDATA AREA
irq7owner dw ? ; INDEX INTO PERPRTDATA AREA
timeoutval dw ? ; TIME OUT FOR 1 SECOND (TICKS)
timercount db 0 ; NUMBER OF TIMER TICKS SINCE IRQ
fIRQStolen db 0 ; FLAG SET TO 1 IF IRQ WAS STOLEN
timerneeded db 0 ; BIT 0 = 0 - TIMER NOT NEEDED FOR LPT1
; BIT 0 = 1 - TIMER NEEDED FOR LPT1
; BIT 1 = 0 - TIMER NOT NEEDED FOR LPT2
; BIT 1 = 1 - TIMER NEEDED FOR LPT2
; BIT 2 = 0 - TIMER NOT NEEDED FOR LPT3
; BIT 2 = 1 - TIMER NEEDED FOR LPT3
deinstallflg db 0 ; DEVICES PDD NO LONGER SUPPORTS
; 0 = LPT1, 1 = LPT2, 2 = LPT3
bustype dw 0 ; BUS TYPE 1=ISA, 2=EISA, and 4=MC
EVEN
; index 0 2 4 6 8 10
blksiz dw 8, 32, 128, 256, 512, 1024 ; BURST RATE IN BYTES
allowedpending dw 1, 6, 32, 60, 118, 230 ; MAX OTHER IRQS PENDING
nextindx dw 0, 0, 2, 4, 0, 0 ; NEXT LOWER BURST RATE
MAXBLKINDX EQU (allowedpending-blksiz-2) ; MAX BURST RATE
blkindx dw MAXBLKINDX ; BURST RATE INDEX
pendirq dw 0 ; PENDING IRQ COUNTER
doserrors dw REQDONE,NOACCESS,PAPEROUTERR,WRITEFAULT
PUBLIC data_block ; PERFVIEW DATA STRUCTURES
data_block LABEL BYTE
db_length dw DATA_BLOCK_LEN ; DATA BLOCK TOTAL LENGTH IN BYTES
dw 0 ; IDENTIFIER (ORDINAL)
dd 0 ; INSTANCE ID/ GROUP ID
dd RPC_FL_16BIT ; FLAGS
dd 0 ; SEMAPHORE OR SEMAPHORE HANDLE
dd 0 ; POINTER TO TIMER ADD FUNCTION
dd 0 ; POINTER TO TIMER SUB FUNCTION
DATA_BLOCK_LEN EQU $ - data_block ; LENGTH OF DATA_BLOCK
prfvw_ctrs dd 12 dup (0) ; PERFVIEW PER DEVICE COUNTER AREA
PUBLIC text_block
text_block LABEL BYTE
dd TBH_VER_2_0_0_0 ; VERSION NUMBER
; TEXT BLOCK IDENTIFIER
dw 0 ; BLOCK INSTANCE ID
dw 0 ; BLOCK GROUP ID
; TEXT BLOCK GROUP NAME
dd 0 ; FLAGS
dw 0 ; SIZE
dw 0 ; MESSAGE ID
dw OFFSET driver_name ; OFFSET OF DEVICE DRIVER NAME
dw SEG driver_name ; SEGMENT OF DEVICE DRIVER NAME
; TEXT BLOCK INSTANCE NAME
dd 0 ; FLAGS
dw 0 ; SIZE
dw 0 ; MESSAGE ID
dd 0 ; DEFAULT MESSAGE
dd 0 ; MESSAGE FILE NAME
dd 0 ; HELP FILE NAME
tb_totalctrs dd 0 ; NUMBER OF TIMERS AND COUNTERS
dw OFFSET name_block ; OFFSET OF NAME BLOCK
dw SEG name_block ; SEGMENT OF NAME BLOCK
dataend dw OFFSET monbuffers ; PTR TO END OF RESIDENT DATA SEGMENT
; ALL DATA AFTER THIS POINT IS
; RELEASED AFTER INITIALIZATION
monbuffers db (MAXPRINTERS * 2) * MaxPBUFCount DUP (00H)
; ALL DATA AFTER THIS POINT IS RELEASED AFTER INITIALIZATION
NUMBER_TMRS_CTRS EQU 3 ; NUMBER OF TIMERS AND COUNTERS
str1 db 'LPT1 Write Requests',0
str2 db 'LPT1 Write Time',0
str3 db 'LPT1 Write Bytes',0
str4 db 'LPT2 Write Requests',0
str5 db 'LPT2 Write Time',0
str6 db 'LPT2 Write Bytes',0
str7 db 'LPT3 Write Requests',0
str8 db 'LPT3 Write Time',0
str9 db 'LPT3 Write Bytes',0
PUBLIC name_block
name_block LABEL BYTE
dd PVW_CT_CNT ; NUMBER OF WRITES COUNTER
dw SIZE num_writes ; SIZE OF COUNTER
dw 0
dw OFFSET str1 ; OFFSET OF COUNTER NAME
dw SEG str1 ; SEGMENT OF COUNTER NAME
dd PVW_CT_TIMR ; WRITE TIME COUNTER
dw SIZE TIMR ; SIZE OF COUNTER
dw 0
dw OFFSET str2 ; OFFSET OF COUNTER NAME
dw SEG str2 ; SEGMENT OF COUNTER NAME
dd PVW_CT_CNT ; NUMBER OF BYTES WRITTEN COUNTER
dw SIZE write_bytes ; SIZE OF COUNTER
dw 0
dw OFFSET str3 ; OFFSET OF COUNTER NAME
dw SEG str3 ; SEGMENT OF COUNTER NAME
dd PVW_CT_CNT ; NUMBER OF WRITES COUNTER
dw SIZE num_writes ; SIZE OF COUNTER
dw 0
dw OFFSET str4 ; OFFSET OF COUNTER NAME
dw SEG str4 ; SEGMENT OF COUNTER NAME
dd PVW_CT_TIMR ; WRITE TIME COUNTER
dw SIZE TIMR ; SIZE OF COUNTER
dw 0
dw OFFSET str5 ; OFFSET OF COUNTER NAME
dw SEG str5 ; SEGMENT OF COUNTER NAME
dd PVW_CT_CNT ; NUMBER OF BYTES WRITTEN COUNTER
dw SIZE write_bytes ; SIZE OF COUNTER
dw 0
dw OFFSET str6 ; OFFSET OF COUNTER NAME
dw SEG str6 ; SEGMENT OF COUNTER NAME
dd PVW_CT_CNT ; NUMBER OF WRITES COUNTER
dw SIZE num_writes ; SIZE OF COUNTER
dw 0
dw OFFSET str7 ; OFFSET OF COUNTER NAME
dw SEG str7 ; SEGMENT OF COUNTER NAME
dd PVW_CT_TIMR ; WRITE TIME COUNTER
dw SIZE TIMR ; SIZE OF COUNTER
dw 0
dw OFFSET str8 ; OFFSET OF COUNTER NAME
dw SEG str8 ; SEGMENT OF COUNTER NAME
dd PVW_CT_CNT ; NUMBER OF BYTES WRITTEN COUNTER
dw SIZE write_bytes ; SIZE OF COUNTER
dw 0
dw OFFSET str9 ; OFFSET OF COUNTER NAME
dw SEG str9 ; SEGMENT OF COUNTER NAME
PUBLIC driver_name
driver_name db 'Parallel Port Device Driver',0
ddname db 'print01.sys',0
DSEG ENDS
SWAPSEG SEGMENT PUBLIC 'code'
ASSUME CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
EXTRN PLPTCMD_Entry:FAR
BREAK <INITAILIZE PRINTER>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SUBROUTINE NAME: INITIALPRT */
;/* */
;/* DESCRIPTIVE NAME: INITIALIZE PRINTERS */
;/* */
;/* FUNCTION: THE FUNCTION OF THIS ROUTINE IS TO INITIALIZE THE */
;/* PRINTER WHOSE DEVICE ADDRESS IS IN AX. */
;/* */
;/* NOTES: */
;/* */
;/* ENTRY POINT: INITIALPRT */
;/* LINKAGE : CALL NEAR OR FAR */
;/* */
;/* INPUT: DX = 0FFH IF CALLED FROM PRTDD INITIALIZE ROUTINE. */
;/* */
;/* EXIT-NORMAL: N/A */
;/* */
;/* EXIT-ERROR: N/A */
;/* */
;/* INTERNAL REFERENCES: getstatus */
;/* ROUTINES: */
;/* */
;/* EXTERNAL REFERENCES: DEVICE_HELP ProcBlock */
;/* ROUTINES: */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure initialprt,HYBRID
ASSUME CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
SaveReg <cx,dx> ; SAVE REGISTERS
mov dx,[di].deviceaddr ; GET DEVICE ADDRESS
inc dx
inc dx ; POINT TO CONTROL PORT
mov al,INITLINELOW ; SET INIT LINE LOW
out dx,al ; SEND NEW CONTROL VALUE
mov ax,INITLOOPCNT ; LOOP COUNT
initprt:
dec ax
jnz initprt ; LOOP UNTIL RESET DONE
mov al,INITLINEHIGH ; SET INIT LINE HIGH
out dx,al ; SEND NEW CONTROL VALUE
; MUST WAIT UNTIL NOT BUSY BEFORE RETURNING TO USER OR USER'S NEXT
; REQUEST WILL FAIL.
pop dx ; GET DD INIT FLAG
push dx
test [di].commonflags1,BOOTINIT ; IS THIS BOOT TIME?
jnz initprt2 ; JUMP IF IT IS
; PROPRINTER RETURNS WITH NORMAL STATUS BUT NEXT PRINT REQUEST WILL FAIL
; UNLESS THIS THREAD IS BLOCKED.
mov cx,BUSYRETRY ; LOOP CONTROL VARIABLE
initprt1:
SaveReg <ax,bx,cx,dx,di> ; SAVE REGISTERS
mov bx,[di].dosoffset ; OFF. OF THIS REQ BLK
inc bx ; MAKE BLOCK ID UNIQUE
mov ax,[di].dosrqseg ; SEG. OF THIS REQ BLK
mov cx,0FFH ; TIME LIMIT LOW VALUE
mov di,0 ; TIME LIMIT HIGH VALUE
mov dh,BLOCKSLEEPNOTINT ; SLEEP NOTINTERRUPTIBLE
mov dl,DevHlp_ProcBlock ; BLOCK FUNCTION
call DWORD PTR [device_help] ; CALL DEVHLP TO BLOCK
RestoreReg <di,dx,cx,bx,ax> ; RESTORE REGISTERS
CALLFAR getstatus ; GET THE PORT STATUS
test ah,NOTBUSY ; IF DEVICE NOT BUSY
jnz initprt2 ; THEN RETURN
loop initprt1 ; SEE IF NOT BUSY
initprt2:
RestoreReg <dx,cx> ; RESTORE REGISTERS
ret
EndProc initialprt
BREAK <PRINT DEVICE DRIVER DEINSTALL ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SUBROUTINE NAME: PRTDEINSTALL */
;/* */
;/* DESCRIPTIVE NAME: PRINT DEVICE DRIVER DEINSTALL ROUTINE. */
;/* */
;/* FUNCTION: THE FUNCTION OF THIS SUBROUTINE IS TO DEINSTALL THE */
;/* THE PRINTER DEVICE DRIVER ONE DEVICE AT A TIME. */
;/* */
;/* NOTES: DEINSTALL COMES IN ONLY AT INIT TIME */
;/* DEINSTALL OCCURS ON A DEVICE BASIS */
;/* KERNEL INSURES NO MORE REQUESTS AFTER DEINSTALL */
;/* SPOOLER CANNOT BE ACTIVE YET */
;/* */
;/* ENTRY POINT: PRTDEINSTALL */
;/* LINKAGE : CALL NEAR */
;/* */
;/* INPUT: ES = VIRTUAL SEGMENT OF REQUEST BLOCK */
;/* BX = VIRTUAL OFFSET OF REQUEST BLOCK */
;/* DI = OFFSET TO APPROPRIATE PERPRTDATA AREA */
;/* */
;/* REGISTERS USED: ALL REGISTERS SAVED BY THE KERNEL */
;/* */
;/* EXIT-NORMAL: ES:[BX].PktStatus = REQDONE */
;/* */
;/* EXIT-ERROR: N/A */
;/* */
;/* INTERNAL REFERENCES: NONE */
;/* ROUTINES: */
;/* */
;/* EXTERNAL REFERENCES: DEVICE_HELP RegisterPDD */
;/* ROUTINES: FreeGDTSelector */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtdeinstall near
ASSUME CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
cmp [di].accessctr,0 ; NO ONE ACCESSING PDD
je prtdein1 ; TRY TO DEINSTALL
mov es:[bx].PktStatus,UNKNOWNCMD ; ELSE REFUSE TO DEIN
jmp SHORT prtdein3 ; EXIT
prtdein1:
SaveReg <bx,es> ; SAVE REGISTERS
mov al,[di].deviceflag ; GET DEVICE FLAG
or deinstallflg,al ; SET DEINSTALL FLAG
cmp deinstallflg,DEINSTALLMSK ; IF ALL DEV != DEINSTAL
jne prtdein2 ; THEN RETURN
; DEREGISTER THE PLPT'S VDD SERVICES ENTRY POINT WITH VLPT.
push di ; SAVE PER PRT AREA
lea si,plptname ; LOAD PLPT NAME
push 0
pop es ; MAKE NULL PTR
.386
xor edi,edi ; MAKE NULL PTR
.286
mov dl,DevHlp_RegisterPDD ; REGISTERPDD FUNC
call DWORD PTR [device_help] ; CALL DEVICE HELP
pop di
prtdein2:
; FREE GDT SELECTOR ALLOCATED AT DEVICE DRIVER INITIALIZATION TIME
mov ax,[di].gdtuserbuf ; GET GDT SELECTOR
mov dl,DevHlp_FreeGDTSelector ; FREE GDT SEL FUNC
call DWORD PTR [device_help] ; CALL DEVICE HELP
mov [di].gdtuserbuf,0 ; CLEAR GDT SELECTOR
; FREE PRINTBUF GDT SELECTOR ALLOCATED AT DEVICE DRIVER INIT TIME
mov ax,[di].gdtprintbuf ; GET GDT SELECTOR
mov dl,DevHlp_FreeGDTSelector ; FREE GDT SEL FUNC
call DWORD PTR [device_help] ; CALL DEVICE HELP
mov [di].gdtprintbuf,0 ; CLEAR GDT SELECTOR
RestoreReg <es,bx> ; RESTORE REGISTERS
mov es:[bx].PktStatus,REQDONE ; SET THE DONE BIT
prtdein3:
ret
EndProc prtdeinstall
SWAPSEG ENDS
CSEG SEGMENT public 'code'
ASSUME CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
EXTRN sendmonerpkt:NEAR
EXTRN eisainit:NEAR
EXTRN prt_polling:NEAR
EXTRN prt_timeout_polling:NEAR
EXTRN _RM_PRT_CreateDriver:NEAR
EXTRN _RM_PRT_DestroyDriver:NEAR
EXTRN _RM_PRT_AllocPorts:NEAR
EXTRN _RM_PRT_DeallocPorts:NEAR
EXTRN _RM_PRT_AllocIRQ:NEAR
EXTRN _RM_PRT_DeallocIRQ:NEAR
EXTRN _RM_PRT_CreateAdapter:NEAR
EXTRN _RM_PRT_DestroyAdapter:NEAR
BREAK <PRINT A BLOCK OF CHARACTERS>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SUBROUTINE NAME: PRINTBLOCK */
;/* */
;/* DESCRIPTIVE NAME: Schedule a print block request. */
;/* */
;/* FUNCTION: This routine will throttle back PIO print requests */
;/* in order to improve mouse and keyboard usability when */
;/* printing is generating many interrupts. Due to the */
;/* rotation of the 8259 programable interrupt controller, */
;/* mouse and keyboard hardware interrupts have a lower */
;/* priority than the printer. */
;/* */
;/* NOTES: */
;/* */
;/* ENTRY POINT: */
;/* LINKAGE: printblock:near */
;/* call printblock */
;/* */
;/* INPUT: ES = Virtual segment of Kernel request block */
;/* BX = Virtual offset of Kernel request block */
;/* DS:DI = Offset to appropriate perprtdata area */
;/* IOACTIVE FLAG OR MONPRINTING FLAG SET TO ON */
;/* */
;/* EXIT-NORMAL: ES:[BX] = Kernel Request Block */
;/* DS:[DI] = Perprtdata area */
;/* DS:[SI] = ABIOS Request Block */
;/* ES:[BX].Pktstatus = filled in. */
;/* ES:[BX].IOCount = filled in. */
;/* IOACTIVE FLAG SET TO OFF */
;/* CANMONPKT FLAG SET TO OFF */
;/* */
;/* EXIT-ERROR: See exit normal above. */
;/* */
;/* EFFECTS: */
;/* */
;/* INTERNAL REFERENCES: prt_transmit */
;/* ROUTINES: prt_polling */
;/* */
;/* EXTERNAL REFERENCES: DEVICE_HELP PhysToGDTSelector */
;/* ROUTINES: ProcBlock */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure printblock far
ASSUME CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
LocalVar _IOCount,WORD ; COUNT TO TRANSMIT
LocalVar _Printed,WORD ; COUNT PRINTED
EnterProc
test [di].commonflags, USEPOLLING ; USE POLLING?
jz prtblk0 ; NO, USE INTS
call prt_polling ; CALL POLL ROUTINE
jmp prtblk6 ; AND RETURN
prtblk0:
mov cx,es:[bx].IOCount
mov _IOCount,cx ; SAVE COUNT TO TRANSMIT
mov _Printed,0 ; INITIALIZE PRT COUNT
mov [di].printbufoff,0 ; SET OFFSET TO ZERO
push bx ; SAVE REGISTER
mov ax,WORD PTR es:[bx].IOpData + 2 ; GET PHYS ADDR - HIGH
mov bx,WORD PTR es:[bx].IOpData ; GET PHYS ADDR - LOW
mov si,[di].gdtprintbuf ; GET GDT SELECTOR
mov dl,DevHlp_PhysToGDTSelector ; CONVERT PHYS TO GDT
call DWORD PTR [device_help] ; DO ADDRESS CONVERSION
pop bx ; RESTORE REGISTER
prtblk1:
mov pendirq,0 ; CLEAR PENDING IRQ CNT
mov si,blkindx ; GET BURST RATE INDEX
mov ax,blksiz[si] ; GET BURST RATE
cmp es:[bx].IOCount,ax ; IF LENGTH <= BLKSIZ
jbe prtblk2 ; NO LOW IRQ PREEMPTING
mov es:[bx].IOCount,ax ; SET PREEMPT INTERVAL
prtblk2:
call prt_transmit ; TRANSMIT BYTES
mov ax,pendirq ; GET PENDING IRQ COUNT
mov si,blkindx ; GET BURST RATE INDEX
cmp allowedpending[si],ax ; IF ALLOWED >= PENDING
jae prtblk3 ; THEN INC BURST RATE
mov si,nextindx[si] ; ELSE DEC BURST RATE
jmp SHORT prtblk31
prtblk3:
cmp si,MAXBLKINDX ; IF MAX BURST RATE
je prtblk32 ; THEN DON'T INCREMENT
add si,2 ; ELSE INC BURST RATE
prtblk31:
mov blkindx,si ; SAVE NEXT RATE INDEX
prtblk32:
mov ax,es:[bx].IOCount ; GET PRINTED COUNT
add _Printed,ax ; ADD PRINTED TO TOTAL
add [di].printbufoff,ax ; ADD PRINTED TO OFFSET
mov ax,_IOCount ; GET INITIAL COUNT
sub ax,_Printed ; CALC REMAINING
jz prtblk5 ; IF ZERO, EXIT
cmp es:[bx].PktStatus,REQDONE ; ERROR?
jne prtblk5 ; YES, EXIT
mov es:[bx].IOCount,ax ; MOVE REMAIN TO REQ PKT
mov es:[bx].PktStatus,0 ; RESET RETURN CODE
; COMPENSATE FOR HIGH HARDWARE INTERRUPT PRIORITY BY PREEMPTING
; TIME SLICE AND ALLOWING MOUSE AND KEYBOARD TIME TO SERVICE.
SaveReg <bx,di> ; SAVE REGISTERS
mov ax,es ; REQ BLK SEG ADDRESS
inc bx ; UNIQUE BLOCK ID
mov cx,1 ; TIME LIMIT LOW VALUE
mov di,0 ; TIME LIMIT HIGH VALUE
mov dh,BLOCKSLEEPNOTINT ; SLEEP NOTINTERRUPTIBLE
mov dl,DevHlp_ProcBlock ; BLOCK FUNCTION
call DWORD PTR [device_help] ; CALL DEVHLP TO BLOCK
RestoreReg <di,bx> ; RESTORE REGISTERS
jmp SHORT prtblk1 ; DO MORE PRINTING
prtblk5:
mov ax,_Printed ; GET PRINTED COUNT
mov es:[bx].IOCount,ax ; RETURN PRINTED COUNT
prtblk6:
and [di].commonflags1,NOT CANMONPKT ; TURN OFF CANCEL FLAG
LeaveProc
ret
EndProc printblock
BREAK <TRANSMIT A BLOCK OF CHARACTERS>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SUBROUTINE NAME: PRT_TRANSMIT */
;/* */
;/* DESCRIPTIVE NAME: TRANSMIT A BLOCK OF DATA ROUTINE */
;/* */
;/* FUNCTION: THE FUNCTION OF THIS SUBROUTINE IS TO PRINT A BLOCK */
;/* OF CHARACTERS. IT WILL ENABLE OR DISABLE THE INTERRUPT */
;/* AT THE PORT OF THE SPECIFIED DEVICE, SETUP THE WAITTIME */
;/* AND RESUME POINTERS IN THE PRINT REQUEST BLOCK AND CALL */
;/* SENDCHAR TO SEND THE FIRST CHARACTER. */
;/* */
;/* */
;/* NOTES: */
;/* */
;/* ENTRY POINT: */
;/* LINKAGE: prt_transmit:near */
;/* call prt_transmit */
;/* */
;/* INPUT: ES = Virtual segment of Kernel request block */
;/* BX = Virtual offset of Kernel request block */
;/* DS:DI = Offset to appropriate perprtdata area */
;/* IOACTIVE FLAG OR MONPRINTING FLAG SET TO ON */
;/* */
;/* EXIT-NORMAL: ES:[BX] = Kernel Request Block */
;/* DS:[DI] = Perprtdata area */
;/* ES:[BX].Pktstatus = filled in. */
;/* ES:[BX].IOCount = filled in. */
;/* IOACTIVE FLAG SET TO OFF */
;/* */
;/* EXIT-ERROR: See exit normal above. */
;/* */
;/* EFFECTS: */
;/* */
;/* INTERNAL REFERENCES: sendchar */
;/* ROUTINES: starttimer */
;/* cleanup */
;/* searchandsteal */
;/* */
;/* EXTERNAL REFERENCES: DEVICE_HELP SetIRQ */
;/* ROUTINES: TickCount */
;/* ProcBlock */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prt_transmit near
ASSUME CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
pvtimer 1 ; SUB FROM PFVW TIMER
mov ax,es:[bx].IOcount ; INITIAL COUNT
mov [di].initialcount,ax ; SAVE INITIALCOUNT
mov [di].prtcount, 0 ; CLEAR PRINTED COUNT
; TRY TO SET THE APPROPRIATE IRQ LEVEL. IF IT FAILS, WE KNOW IT'S IN
; USE AND WILL HAVE TO DRIVE THE DEVICE BY TIMER INTERRUPTS.
test [di].share_interrupt, INT_SHARING ; INT SHARING SUPPORT?
jz prtxmit2 ; NO
xor ch,ch ; CLEAR HIGH BYTE
mov cl,[di].intlevel ; SPECIFY INT LEVEL
jmp short prtxmit3 ; ALREADY HAVE THE IRQ
prtxmit2:
push bx
mov ax,[di].introutine ; OFF HARD INT HANDLER
xor bh,bh ; ZERO OUT BH
mov bl,[di].intlevel ; HARD INT LEVEL NUMBER
mov dh,0 ; LEVEL NOT SHARED
cli ; DISABLE INTERRUPTS
mov dl,DevHlp_SetIRQ ; ASSIGN HARDWARE INT
call DWORD PTR [device_help] ; CALL DEVHLP
mov [di].curintlevel,0 ; ASSUME RUN OFF TIMER
mov cx,bx
pop bx
jc prtxmit4 ; IF IN-USE RUN ON TIMER
prtxmit3:
mov [di].curintlevel,cl ; SAVE HARD INT LEVEL
cmp cl,IRQ7INTNUM ; IF IRQ NOT IRQ 7
jne prtxmit4 ; THEN JUMP
mov al,[di].deviceindex ; GET DEVICE INDEX
xor ah,ah ; ZERO OUT AH
mov irq7owner,ax ; SET OWNER OF IRQ7
prtxmit4:
sti ; ENABLE INTERRUPTS
push bx
mov [di].timeoutctr,0 ; CLEAR TIMEOUT CTR
mov ax,[di].timeout_off ; TIMEOUT ENTRY POINT
mov bx,timeoutval ; TIMEOUT IN TICKCOUNTS
mov dl,DevHlp_TickCount ; CALL TIMER SERVICES
call DWORD PTR [device_help]
call sendchar ; CHECK STATUS PORT AND
pop bx ; PRINT FIRST CHARACTER
cmp [di].curintlevel,0 ; IF !RUNNING ON TIMER
jne prtxmit41 ; THEN WAIT FOR HARD INT
call starttimer ; START THE TIMER
prtxmit41:
cli ; DISABLE INTERRUPTS
test es:[bx].PktStatus,REQDONE ; IF REQUEST IS DONE
jnz prtxmit5 ; THEN EXIT
push di ; SAVE DI
mov ax,es ; REQ BLK SEG ADDRESS
inc bx ; UNIQUE BLOCK ID
mov cx,BLOCKLOWVALUE ; -1 NEVER TIMEOUT
mov di,BLOCKLOWVALUE ; -1 NEVER TIMEOUT
mov dh,BLOCKSLEEPINT ; SLEEP INTERRUPTIBLE
mov dl,DevHlp_ProcBlock ; PROCBLOCK FUNCTION
call DWORD PTR [device_help] ; CALL DEVHLP
dec bx ; ADDRESS REQ BLOCK
pop di ; RESTORE DI
jc prtxmit45 ; UNUSUAL WAKEUP
jmp prtxmit41 ; RETEST DONE
prtxmit45:
mov es:[bx].PktStatus,CHARIOINT ; RETURN STATUS
call cleanup ; TERMINATE PRT REQ
prtxmit5:
cmp [di].curintlevel,IRQ7INTNUM ; DID IRQ7 FINISH?
jne prtxmit6 ; YES, GIVE TO TIMER DEV
call searchandsteal ; GIVE IRQ7 TO SYS TIMER
prtxmit6:
sti ; ENABLE INTERRUPTS
pvtimer ; ADD TO PFVW TIMER/CTRS
ret
EndProc prt_transmit
BREAK <SEARCH FOR TIMER AND GIVE IT THE IRQ>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SUBROUTINE NAME: SEARCHANDSTEAL */
;/* */
;/* DESCRIPTIVE NAME: SEARCH FOR DEVICE ON TIMER, REPLACE WITH IRQ7. */
;/* */
;/* FUNCTION: THE FUNCTION OF THIS SUBROUTINE IS TO SEARCH FOR A */
;/* REQUEST RUNNING ON A DEVICE USING THE SYSTEM TIMER AND */
;/* TRANSFER IT TO RUN OFF OF IRQ7. */
;/* */
;/* ENTRY POINT: SEARCHANDSTEAL */
;/* LINKAGE : CALL NEAR */
;/* */
;/* INPUT: NONE */
;/* */
;/* EXIT-NORMAL: REQ on system timer transfered to IRQ7 */
;/* */
;/* EXIT-ERROR : See EXIT-NORMAL above. */
;/* */
;/* INTERNAL REFERENCES: stoptimer */
;/* ROUTINES: sendchar */
;/* */
;/* EXTERNAL REFERENCES: DEVICE_HELP SetIRQ */
;/* ROUTINES: */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure searchandsteal near
ASSUME CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
pusha ; SAVE REGESTERS
push es ; SAVE EXTRA SEGMENT
test timerneeded,TIMERMASK ; IF TIMER RUNNING
jnz srchandstl0 ; CONTINUE
jmp srchandstl5 ; EXIT
; FIND DEVICE RUNNING OFF OF THE SYSTEM TIMER
srchandstl0:
mov ax,1 ; SET AX = 1
xor ch,ch ; MAKE CH 0
mov cl,numofprts ; # OF PARALLEL PORTS
mov di,OFFSET perprtarea ; DI = START OF DATABASE
srchandstl1:
test timerneeded,al ; IF DEVICE USING TIMER
jnz srchandstl3 ; THEN FOUND DEVICE
srchandstl2:
add di,SIZE printer_database ; DX = SIZE OF ONE ENTRY
sal al,1 ; CHECK NEXT DEVICE
loop srchandstl1 ; TRY NEXT DEVICE
jcxz srchandstl5 ; IF CX=0, !FOUND, EXIT
srchandstl3:
mov ax,[di].initialcount ; GET INITIAL COUNT
cmp ax,[di].prtcount ; IF NO BYTES REMAINING
je srchandstl2 ; THEN TRY NEXT DEVICE
; SETUP SYSTEM TIMER JOB TO RUN ON IRQ7
cmp [di].share_interrupt,INT_SHARING ; IF INT SHARING
je srchandstl4 ; THEN DON'T SET AGAIN
mov ax,[di].introutine ; OFF HARD INT HANDLER
xor bh,bh ; ZERO OUT BH
mov bl,[di].intlevel ; HARD INT LEVEL NUMBER
mov dh,0 ; LEVEL NOT SHARED
mov dl,DevHlp_SetIRQ ; ASSIGN HARDWARE INT
call DWORD PTR [device_help] ; CALL DEVHLP
jc srchandstl5 ; IF ERROR, CAN'T SWITCH
srchandstl4:
mov [di].curintlevel,IRQ7INTNUM ; SET LEVEL TO IRQ7
mov al,[di].deviceindex ; GET DEVICE INDEX
xor ah,ah ; ZERO OUT AH
mov irq7owner,ax ; SET OWNER OF IRQ7
; SHUT DOWN DEVICE ON SYSTEM TIMER AND RESTART IT ON HARDWARE
; INTERRUPT LEVEL 7 (IRQ7)
call stoptimer ; STOP DEVICE ON TIMER
call sendchar ; PRINT NEXT CHAR W IRQ7
srchandstl5:
pop es ; RESTORE EXTRA SEGMENT
popa ; RESTORE REGESTERS
ret
EndProc searchandsteal
BREAK <SHARED INTERRUPT HANDLERS>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SOURCE FILE NAME: eInt_1 */
;/* eInt_2 */
;/* eInt_3 */
;/* */
;/* DESCRIPTIVE NAME: Printer Hardware Interrupt Handlers for shared */
;/* interrupts on an EISA system. */
;/* */
;/* FUNCTION: These routines are used as entry points to the */
;/* interrupt service routine when OS/2 is run on an EISA */
;/* system that is sharing the printer's interrupt line. */
;/* This "interrupt sharing" is TRUE hardware interrupt */
;/* sharing, by use of level triggered interrupt lines. */
;/* This allows the interrupt line to be shared between the */
;/* printer and other non-printer devices that are */
;/* configured for the same interrupt line. These entry */
;/* points will ONLY be used when the EISA configuration */
;/* information indicates that the printer's interrupt line */
;/* is being shared. Otherwise, the ISA compatible entry */
;/* points, PRTINT05 and PRTINT07 will be used. */
;/* */
;/* NOTE: The Hardware Interrupt Manager saves all registers and */
;/* calls with interrupts enabled. On exit, interrupts are */
;/* disabled to prevent nested interrupts after EOI. */
;/* */
;/* INPUT: DS = setup to our data segment. */
;/* */
;/* ENTRY POINT: eInt_1, eInt_2, eInt_3 */
;/* LINKAGE : CALL FAR */
;/* */
;/* EXIT-NORMAL: Return to the hardware interrupt manager. */
;/* */
;/* EXIT-ERROR: N/A */
;/* */
;/* INTERNAL REFERENCES: interrupt */
;/* ROUTINES: */
;/* */
;/* EXTERNAL REFERENCES: NONE */
;/* ROUTINES: */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure eInt_1 far
mov di,OFFSET perprtarea ; FIRST PERPRTDATA AREA
mov si, LPT1_INDEX ; SET-UP FOR INTERRUPT
test [di].share_interrupt, INT_SHARING ; SUPPORTS INT SHARING?
jz eInt11 ; NO: GO PROCESS INT.
test [di].commonflags,CHARACTER_OUT ; HAS A CHAR BEEN SENT?
jz eInt10 ; JUMP IF NO.
test [di].commonflags1,PDDDIRACCESS ; PDD HAS PORT ACCESS?
jz eInt10 ; NO, IGNORE PORT
mov dx, [di].deviceaddr ; DATA PORT
inc dx ; STATUS PORT
cli ; INTS BACK OFF
in al, dx ; GET CURRENT STATUS
test al, INT_PENDING ; OUR INTERRUPT?
jz eInt11 ; Y: PROCESS IT
eInt10: ;
stc ; N: SIGNAL KERNEL
ret ; AND RETURN
eInt11:
call interrupt ; PROCESS INTERRUPT
ret
EndProc eInt_1
Procedure eInt_2 far
mov di,OFFSET perprtarea ; FIRST PERPRTDATA AREA
add di, (SIZE printer_database * LPT2_INDEX); 2ND PERPRTDATA AREA
mov si, LPT2_INDEX ; SET-UP FOR INTERRUPT
test [di].share_interrupt, INT_SHARING ; SUPPORTS INT SHARING?
jz eInt21 ; NO: GO PROCESS INT.
test [di].commonflags,CHARACTER_OUT ; HAS A CHAR BEEN SENT?
jz eInt20 ; JUMP IF NO.
test [di].commonflags1,PDDDIRACCESS ; PDD HAS PORT ACCESS?
jz eInt20 ; NO, IGNORE PORT
mov dx, [di].deviceaddr ; DATA PORT
inc dx ; STATUS PORT
cli ; INTS BACK OFF
in al, dx ; GET CURRENT STATUS
test al, INT_PENDING ; OUR INTERRUPT?
jz eInt21 ; Y: PROCESS IT
eInt20: ;
stc ; N: SIGNAL KERNEL
ret ; AND RETURN
eInt21:
call interrupt ; PROCESS INTERRUPT
ret
EndProc eInt_2
Procedure eInt_3 far
mov di,OFFSET perprtarea ; FIRST PERPRTDATA AREA
add di, (SIZE printer_database * LPT3_INDEX); 3RD PERPRTDATA AREA
mov si, LPT3_INDEX ; SET-UP FOR INTERRUPT
test [di].share_interrupt, INT_SHARING ; SUPPORTS INT SHARING?
jz eInt31 ; NO: GO PROCESS INT.
test [di].commonflags,CHARACTER_OUT ; HAS A CHAR BEEN SENT?
jz eInt30 ; JUMP IF NO.
test [di].commonflags1,PDDDIRACCESS ; PDD HAS PORT ACCESS?
jz eInt30 ; NO, IGNORE PORT
mov dx, [di].deviceaddr ; DATA PORT
inc dx ; STATUS PORT
cli ; INTS BACK OFF
in al, dx ; GET CURRENT STATUS
test al, INT_PENDING ; INT PENDING?
jz eInt31 ; Y: PROCESS IT
eInt30: ;
stc ; N: SIGNAL KERNEL
ret ; AND RETURN
eInt31:
call interrupt ; PROCESS INTERRUPT
ret
EndProc eInt_3
BREAK <IRQ5 INTERRUPT HANDLER>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SOURCE FILE NAME: PRTINT05 */
;/* */
;/* DESCRIPTIVE NAME: Printer Hardware Interrupt Handler for IRQ5. */
;/* */
;/* FUNCTION: The function of PRTINT05 is to set si to the device */
;/* index which caused the hardware interrupt on level 5. */
;/* */
;/* NOTE: The Hardware Interrupt Manager saves all registers and */
;/* calls with interrupt disabled. On exit, interrupts are */
;/* disabled to prevent nested interrupts after EOI. */
;/* */
;/* INPUT: DS = setup to our data segment. */
;/* */
;/* ENTRY POINT: PRTINT05 */
;/* LINKAGE : CALL FAR */
;/* */
;/* EXIT-NORMAL: Return to the hardware interrupt manager. */
;/* */
;/* EXIT-ERROR: N/A */
;/* */
;/* INTERNAL REFERENCES: interrupt */
;/* ROUTINES: */
;/* */
;/* EXTERNAL REFERENCES: NONE */
;/* ROUTINES: */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtint05 far
ASSUME CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
mov si,irq5index ; IND TO CURR OWNER IRQ5
call interrupt ; CALL COMMON ROUTINE
ret
EndProc prtint05
BREAK <IRQ7 INTERRUPT HANDLER>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SOURCE FILE NAME: PRTINT07 */
;/* */
;/* DESCRIPTIVE NAME: PRINTER HARDWARE INTERRUPT HANDLER FOR IRQ7. */
;/* */
;/* FUNCTION: THE FUNCTION OF PRTINT07 IS TO SET SI TO THE DEVICE */
;/* INDEX WHICH CAUSED THE HARDWARE INTERRUPT ON LEVEL 7. */
;/* */
;/* NOTE: The Hardware Interrupt Manager saves all registers and */
;/* calls with interrupt disabled. On exit, interrupts are */
;/* disabled to prevent nested interrupts after EOI. */
;/* */
;/* INPUT: DS = setup to our data segment. */
;/* */
;/* ENTRY POINT: PRTINT07 */
;/* LINKAGE : CALL FAR */
;/* */
;/* EXIT-NORMAL: Return to the hardware interrupt manager. */
;/* */
;/* EXIT-ERROR: N/A */
;/* */
;/* INTERNAL REFERENCES: interrupt */
;/* ROUTINES: */
;/* */
;/* EXTERNAL REFERENCES: NONE */
;/* ROUTINES: */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtint07 far
ASSUME CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
mov si,irq7owner ; IND TO CURR OWNER IRQ7
mov timercount,0 ; CLEAR TIMER COUNTER
call interrupt ; CALL COMMON ROUTINE
ret
EndProc prtint07
BREAK <START A TIMER>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SUBROUTINE NAME: STARTTIMER */
;/* */
;/* DESCRIPTIVE NAME: Printer Device Driver Start Timer Routine */
;/* */
;/* FUNCTION: The function of this subroutine is to start a timer */
;/* manager to get invoked on each timer tick. If the */
;/* timer manager is already started, this routine will not */
;/* attempt to start it again. */
;/* */
;/* NOTE: */
;/* This routine is only called if the SetIRQ function call */
;/* fails in the printblock routine or if no hardware interrupt */
;/* is assigned to this device. */
;/* */
;/* ENTRY POINT: STARTTIMER */
;/* LINKAGE : CALL NEAR */
;/* */
;/* INPUT: di = offset to appropriate perprtdata area */
;/* */
;/* EXIT-NORMAL: timerneeded = 001B LPT1 is running off of the timer. */
;/* 010B LPT2 is running off of the timer. */
;/* 100B LPT3 is running off of the timer. */
;/* [di].prttime = reset running count of ticks */
;/* [di].waittime = set maximum count of ticks to wait */
;/* */
;/* EXIT-ERROR : See EXIT-NORMAL above. */
;/* */
;/* INTERNAL REFERENCES: NONE */
;/* ROUTINES: */
;/* */
;/* EXTERNAL REFERENCES: DEVICE_HELP SetTimer */
;/* ROUTINES: */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure starttimer near
ASSUME CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
mov [di].prttime,0 ; RESET RUNNING COUNT
mov [di].waittime,MINWAITTIME ; # OF TICKS TO WAIT
test timerneeded,TIMERMASK ; IF TIMERMGR PREV REG
jnz starttimer1 ; THEN DON'T REREGISTER
mov ax,OFFSET prttimgr ; OFFSET PRT TIMER MGR
mov dl,DevHlp_SetTimer ; SET TIMER FUNCTION
call DWORD PTR [device_help] ; CALL DEVHLP
starttimer1:
mov al,[di].deviceflag ; GET DEVICE FLAG
or timerneeded,al ; DEVICE RUNS BY TIMER
ret
EndProc starttimer
BREAK <STOP A TIMER>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SUBROUTINE NAME: STOPTIMER */
;/* */
;/* DESCRIPTIVE NAME: Printer Device Driver Stop Timer Routine */
;/* */
;/* FUNCTION: The function of this subroutine is to stop a timer */
;/* manager. If the timer manager is needed by another */
;/* device, it will only deregister this request from */
;/* running on the timer. */
;/* */
;/* NOTE: */
;/* */
;/* ENTRY POINT: STOPTIMER */
;/* LINKAGE : CALL NEAR */
;/* */
;/* INPUT: di = offset to appropriate perprtdata area */
;/* */
;/* EXIT-NORMAL: timerneeded = 001B LPT1 is running off of the timer. */
;/* 010B LPT2 is running off of the timer. */
;/* 100B LPT3 is running off of the timer. */
;/* */
;/* EXIT-ERROR : See EXIT-NORMAL above. */
;/* */
;/* INTERNAL REFERENCES: NONE */
;/* ROUTINES: */
;/* */
;/* EXTERNAL REFERENCES: DEVICE_HELP ResetTimer */
;/* ROUTINES: */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure stoptimer near
ASSUME CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
mov al,[di].deviceflag ; GET DEVICE FLAG
xor al,0ffh ; GET REVERSE BITMASK
and timerneeded,al ; SET FLAG OFF
test timerneeded,TIMERMASK ; IF PRT TIMERMGR NEEDED
jnz stoptimer1 ; THEN DON'T DEREGISTER
mov ax,OFFSET prttimgr ; ELSE DEREGISTER TIMER
mov dl,DevHlp_ResetTimer ; TURN OFF TIMER
call DWORD PTR [device_help] ; CALL TIMER SERVICES
stoptimer1:
ret
EndProc stoptimer
BREAK <PRINTER DEVICE DRIVER TIMER MANAGER>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* MODULE NAME: PRTTIMGR */
;/* */
;/* DESCRIPTIVE NAME: Print timer manager */
;/* */
;/* FUNCTION: The function of this module is to call interrupt when */
;/* the certain time interval has elasped. */
;/* */
;/* NOTES: */
;/* It is the timer routine's responsibility to save and */
;/* restore all registers used in the printer timer handler. */
;/* */
;/* ENTRY POINT: PRTTIMGR */
;/* LINKAGE : CALL FAR */
;/* */
;/* INPUT: DS = our data segment */
;/* numofprts = number of parallel ports installed. */
;/* timerneeded = 001B LPT1 is running off of the timer. */
;/* 010B LPT2 is running off of the timer. */
;/* 100B LPT3 is running off of the timer. */
;/* [DI].prttime = running count of ticks */
;/* [DI].waittime = # of ticks to wait */
;/* */
;/* EXIT-NORMAL: All registers are restored. */
;/* [DI].prttime = [di].prttime + 1 or */
;/* [di].prttime = 0 if prttime = waittime. */
;/* */
;/* EXIT-ERROR: See EXIT-NORMAL above. */
;/* */
;/* INTERNAL REFERENCES: timerinterrupt */
;/* ROUTINES: */
;/* */
;/* EXTERNAL REFERENCES: NONE */
;/* ROUTINES: */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prttimgr far
ASSUME CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
pusha ; SAVE REGESTERS
push es ; SAVE EXTRA SEGMENT
test timerneeded,TIMERMASK ; IF TIMER NOT REQUESTED
jz prttimgr3 ; THEN EXIT
mov ax,1 ; SET AX = 1
xor ch,ch ; MAKE CH 0
mov cl,numofprts ; # OF PARALLEL PORTS
mov di,OFFSET perprtarea ; DI = START OF DATABASE
prttimgr1:
test timerneeded,al ; IF DEV !NEEDS T. TICKS
jz prttimgr2 ; THEN TRY NEXT DEVICE
inc [di].prttime ; ADD 1 TO TIMER COUNT
mov dx,[di].prttime ; DX = TIMER COUNT
cmp dx,[di].waittime ; IF TIMER IS < WAITTIME
jb prttimgr2 ; THEN GET NEXT REQUEST
SaveReg <ax,cx> ; SAVE REGISTERS
call timerinterrupt ; HANDLE REQUEST
mov [di].prttime,0 ; RESET RUNNING COUNT
RestoreReg <cx,ax> ; RESTORE REGISTERS
prttimgr2:
sal al,1 ; CHECK NEXT DEVICE
add di,SIZE printer_database ; DI -> NEXT DEVICE
loop prttimgr1 ; TRY NEXT DEVICE
prttimgr3:
pop es ; RESTORE EXTRA SEGMENT
popa ; RESTORE REGESTERS
ret
EndProc prttimgr
BREAK <TIMER INTERRUPT HANDLER>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SUBROUTINE NAME: TIMERINTERRUPT */
;/* */
;/* DESCRIPTIVE NAME: Timer Interrupt Handler */
;/* */
;/* FUNCTION: The function of interrupt will be to perform the timer */
;/* interrupt handler functions. */
;/* */
;/* NOTE: The Hardware Interrupt Manager saves all registers and */
;/* calls with interrupts disabled. */
;/* */
;/* ENTRY POINT: TIMEINTERRUPT */
;/* LINKAGE : CALL NEAR */
;/* */
;/* INPUT: DI = INDEX TO APPROPRIATE PERPRTDATA AREA */
;/* */
;/* EXIT-NORMAL: */
;/* */
;/* EXIT-ERROR : See EXIT-NORMAL above. */
;/* */
;/* INTERNAL REFERENCES: */
;/* ROUTINES: sendchar */
;/* cleanup */
;/* checkstatus */
;/* changeirqtost */
;/* */
;/* EXTERNAL REFERENCES: */
;/* ROUTINES: */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure timerinterrupt near
ASSUME CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
test [di].commonflags,MONPRINTING ; IF MON PRINTING
jnz tinterrupt0 ; CONTINUE
test [di].commonflags,IOACTIVE ; IF I/O !ACTIVE
jz tinterrupt3 ; THEN JUST RETURN
tinterrupt0:
and [di].commonflags,NOT CHARACTER_OUT ; RESET CHAR SENT FLAG.
mov fIRQStolen,0 ; CLEAR IRQ STOLEN FLAG
; I/O IS ACTIVE ON THIS DEVICE
mov ax,[di].initialcount ; GET INITIAL COUNT
cmp ax,[di].prtcount ; IF BYTES REMAINING
jne tinterrupt1 ; THEN CONTINUE PRINTING
; COMPLETELY FINISHED PRINTING
call cleanup ; CALL CLEANUP
jmp SHORT tinterrupt3 ; RET TO HARD INT MGR
; NOT FINISHED PRINTING
tinterrupt1:
inc timercount ; INCREMENT TIMER COUNT
cmp timercount,TICKSTOWAIT ; CHECK IRQ STATUS?
jbe tinterrupt05 ; IF NOT CONTINUE PRT.
mov timercount,0 ; ZERO TIMER COUNT
cli ; DISABLE INTERRUPTS
mov al,IRQ7INTNUM
call checkstatus ; CHECK IRQ7 PORT STATUS
cmp al,0 ; IF AL = 0
je tinterrupt05 ; THEN CONTINUE ON TIMER
mov fIRQStolen,1 ; SET IRQ STOLEN FLAG
call changeirqtost ; ELSE GRAB IRQ
tinterrupt05:
sti ; ENABLE INTERRUPTS
tinterrupt2:
call sendchar ; PRINT NEXT CHAR
tinterrupt3:
ret
EndProc timerinterrupt
BREAK <GRAB IRQ WHEN PRINTER NOT USED>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SUBROUTINE NAME: CHANGEIRQTOST */
;/* */
;/* DESCRIPTIVE NAME: Change IRQ job to ST and ST job to IRQ */
;/* */
;/* FUNCTION: The function of this routine is to change the internal */
;/* data structures of the print jobs to represent the */
;/* change from IRQ to ST. */
;/* */
;/* ENTRY POINT: CHANGEIRQTOST */
;/* LINKAGE : CALL NEAR */
;/* */
;/* INPUT: DI = POINTER TO ST PERPRTDATA DATA */
;/* */
;/* EXIT-NORMAL: none */
;/* */
;/* EXIT-ERROR : See EXIT-NORMAL above. */
;/* */
;/* INTERNAL REFERENCES: starttimer */
;/* ROUTINES: stoptimer */
;/* */
;/* EXTERNAL REFERENCES: NONE */
;/* ROUTINES: */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure changeirqtost near
ASSUME CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
push bx ; SAVE BX
push di ; SAVE DI FOR ST JOB
; DI MUST BE INDEXED TO IRQ JOB AT THIS POINT!!!!!
; THEREFORE, THE FOLLOWING LOOP WILL SEARCH FOR THE
; IRQ JOB AND SET DI APPROPRIATELY
xor ch,ch ; MAKE CH 0
mov cl,numofprts ; # OF PARALLEL PORTS
mov di,OFFSET perprtarea ; DI = START OF DATABASE
change0:
cmp [di].curintlevel,IRQ7INTNUM ; IF DEV USING IRQ7
je change1 ; THEN HAVE DEVICE
add di,SIZE printer_database ; DX = SIZE OF ONE ENTRY
loop change0 ; TRY NEXT DEVICE
pop di
jmp SHORT changeEND
change1:
mov [di].curintlevel,0 ; CHANGE IRQ TO TIMER
call starttimer ; START THE TIMER
; DISABLE INTS AT OLD IRQ PORT
mov dx,[di].deviceaddr ; GET PORT ADDRESS
inc dx ; POINT TO CONTROL PORT
inc dx ; POINT TO CONTROL PORT
mov al,DISABLEINT ; DISABLE INT AT PORT
out dx,al ; NEW CTRL VALUE
; If the interrupt line that was just disabled was level triggered (EISA
; systems have this option), then we need to clear any pending interrupt
; that occurred since the CLI at the top of this routine. This can be
; done by reading the printer status port. Doing this will cause the
; PIC to report a spurious interrupt to the CPU, but OS/2's kernel will
; handle this, and our interrupt service routine will not be called.
mov dx,[di].deviceaddr ; GET PORT ADDRESS
inc dx ; POINT TO STATUS PORT
in al,dx ; READ THE STATUS PORT
;******************************************************************************
;* NOW WE PROCESS THE ST JOB TO CONVERT IT TO THE IRQ *
;******************************************************************************
; DI MUST BE INDEXED TO ST JOB AT THIS POINT!!!!!
pop di ; RESTORE DI FOR ST JOB
mov [di].curintlevel,IRQ7INTNUM ; CHANGE TIMER TO IRQ
xor ah,ah ; ZERO AH
mov al,[di].deviceindex ; GET DEVICE INDEX
mov irq7owner,ax ; SET IRQ7 OWNER
call stoptimer ; STOP TIMER ON ST JOB
changeEND:
pop bx ; RESTORE BX
ret
EndProc changeirqtost
BREAK <PRINTER ERROR STATUS PROCESSING>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SUBROUTINE NAME: CHECKSTATUS */
;/* */
;/* DESCRIPTIVE NAME: ANALYZE STATUS FLAGS */
;/* */
;/* FUNCTION: THE FUNCTION OF THIS SUBROUTINE IS TO ANALYZE THE STATUS */
;/* INFORMATION RETURNED FROM "GETSTATUS". */
;/* */
;/* ENTRY POINT: CHECKSTATUS */
;/* LINKAGE : CALL NEAR */
;/* */
;/* INPUT: al = interrupt level to check status on */
;/* */
;/* EXIT-NORMAL: al = 1 if ok to steal IRQ, 0 otherwise */
;/* */
;/* EXIT-ERROR : See EXIT-NORMAL above. */
;/* */
;/* INTERNAL REFERENCES: getstatus */
;/* ROUTINES: */
;/* */
;/* EXTERNAL REFERENCES: NONE */
;/* ROUTINES: */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure checkstatus near
ASSUME CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
push di ; SAVE ST INDEX
; SEARCH FOR IRQ JOB
xor ch,ch ; MAKE CH 0
mov cl,numofprts ; # OF PARALLEL PORTS
mov di,OFFSET perprtarea ; DI = START OF DATABASE
checkstatus0:
cmp [di].curintlevel,al ; IF DEV USING IRQ7
je checkstatus1 ; THEN FOUND IT!
add di,SIZE printer_database ; DX = SIZE OF ONE ENTRY
loop checkstatus0 ; TRY NEXT DEVICE
jcxz checkstatus2 ; NOT OK, EXIT
checkstatus1:
mov ax,[di].initialcount ; GET INITIAL COUNT
cmp [di].prtcount,ax ; IF NONE REMAIN
je checkstatus2 ; EXIT
call getstatus ; GET PORT STATUS (AH)
xor al,al ; NO ERROR
;*******************************************************************************
;* B0 = NOT BUSY & PAPER OUT & SELECTED = !CABLED ON MONO / SERIAL ADAPTER #20 *
;*******************************************************************************
cmp ah,0b0h
jnz cs1
mov al,1 ; SET SELECT ERROR
jmp SHORT checkstatus3
;*******************************************************************************
;* 38 = BUSY & PAPER OUT & SELECTED & I/O ERROR = OUT OF PAPER #28 *
;*******************************************************************************
cs1:
cmp ah,38h
jnz cs2
mov al,1 ; SET PAPER OUT ERROR
jmp SHORT checkstatus3
;*******************************************************************************
;* 30 = BUSY & PAPER OUT & SELECTED & NOT I/O ERROR = OUT OF PAPER #28 *
;*******************************************************************************
cs2:
cmp ah,30h
jnz cs3
mov al,1 ; SET PAPER OUT ERROR
jmp SHORT checkstatus3
;*******************************************************************************
;* 28 = BUSY & PAPER OUT & NOT SELECTED & I/O ERROR = OUT OF PAPER #28 *
;*******************************************************************************
cs3:
cmp ah,28h
jnz cs4
mov al,1 ; SET PAPER OUT ERROR
jmp SHORT checkstatus3
;*******************************************************************************
;* 18 = BUSY & I/O ERROR & SELECTED = OFF LINE #29 *
;*******************************************************************************
cs4:
cmp ah,18h
jnz cs5
mov al,1 ; SET I/O ERROR
jmp SHORT checkstatus3
;*******************************************************************************
;* 10 = BUSY & SELECTED = NOT READY #29 *
;*******************************************************************************
cs5:
cmp ah,10h
jnz cs6
mov al,1 ; SET I/O ERROR
jmp SHORT checkstatus3
;*******************************************************************************
;* 08 = BUSY & I/O ERROR = OFF LINE #29 *
;*******************************************************************************
cs6:
cmp ah,08h
jnz cs7
mov al,1 ; SET I/O ERROR
jmp SHORT checkstatus3
;*******************************************************************************
;* 00 = BUSY & NOTHING ELSE = NOT READY #29 *
;*******************************************************************************
cs7:
cmp ah,00h
jnz cs8
mov al,1 ; SET I/O ERROR
jmp SHORT checkstatus3
;*******************************************************************************
;* 88 = NOT BUSY & I/O ERROR = POWERED OFF #20 *
;*******************************************************************************
cs8:
cmp ah,88h
jnz checkstatus2
mov al,1 ; SET SELECT ERROR
jmp SHORT checkstatus3
checkstatus2:
mov al,0
checkstatus3:
pop di ; RESTORE ST INDEX
ret
EndProc checkstatus
BREAK <HARDWARE INTERRUPT HANDLER>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SUBROUTINE NAME: INTERRUPT */
;/* */
;/* DESCRIPTIVE NAME: Hardware Interrupt Handler */
;/* */
;/* FUNCTION: The function of interrupt will be to perform the */
;/* hardware interrupt handler functions. */
;/* */
;/* NOTE: The Hardware Interrupt Manager saves all registers and */
;/* calls with interrupts enabled. On exit, interrupts are */
;/* disabled to prevent nested interrupts after EOI. */
;/* */
;/* ENTRY POINT: INTERRUPT */
;/* LINKAGE : CALL NEAR */
;/* */
;/* INPUT: SI = INDEX TO APPROPRIATE PERPRTDATA AREA */
;/* */
;/* EXIT-NORMAL: NC = TELL INT MGR, MY INT (HARDWARE INTS ONLY) */
;/* */
;/* EXIT-ERROR : See EXIT-NORMAL above. */
;/* */
;/* INTERNAL REFERENCES: copynext */
;/* ROUTINES: sendchar */
;/* cleanup */
;/* */
;/* EXTERNAL REFERENCES: DEVICE_HELP EOI */
;/* ROUTINES: */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure interrupt near
ASSUME CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
mov di,OFFSET perprtarea ; FIRST PERPRTDATA AREA
mov ax,SIZE printer_database ; SIZE OF PRT DATABASE
mul si ; MULT BY DEVICE INDEX
add di,ax ; INDEX INTO DEV AREA
; IF OTHER HARDWARE INTERRUPT PENDING IN THE SYSTEM, COUNT THESE TO
; DETERMINE WHEN TO STOP PRINTING AND ALLOW THESE LOWER PRIORITY
; INTERRUPTS TIME TO SERVICE.
cli ; DISABLE INTERRUPTS
in al,21h ; GET 8259 MASTER IMR
or al,0E0h ; MASK OFF IRQ7
mov ah,al ; AH=MASTER IMR
in al,0a1h ; GET 8259 SLAVE IMR
not ax ; INVERT FOR ACTIVE IRQS
mov si,ax ; SAVE ACTIVE IRQS
mov ax,0a0ah ; READ IRR CMD
out 20h,al ; TO 8259 MASTER
DevIODelay <bx> ; IO DELAY
in al,20h ; GET 8259 MASTER IRR
xchg ah,al ; SAVE MASTER IRR
out 0a0h,al ; READ IRR CMD TO SLAVE
DevIODelay <bx> ; IO DELAY
in al,0a0h ; GET 8259 SLAVE IRR
and ax,si ; ENABLED IRQS-REQS PEND
jz interrupt01 ; JMP IF NO PENDING IRQS
inc pendirq ; ELSE INC PENDING IRQ
interrupt01:
sti ; ENDABLE INTERRUPTS
;/** START SPURIOUS TEST ***********************************************/
;/* */
;/* THE FOLLOWING CODE WAS ADDED IN ORDER TO PROCESS SPURIOUS */
;/* INTERRUPTS. WE ARE CURRENTLY GETTING SPURIOUS INTERRUPTS FROM THE */
;/* NEW 3 MEG CARDS WITH SERIAL/PARALLEL PORTS AND FROM THE "FIRST */
;/* ISSUE" SERIAL/PARALLEL CARDS. FUTURE ENHANCEMENTS TO THIS CODE */
;/* WOULD BE TO COUNT THE NUMBER OF SPURIOUS INTERRUPTS IN A GIVEN */
;/* AMOUNT OF TIME AND TO ALERT THE INTERRUPT MANAGER TO DISABLE THIS */
;/* LEVEL ALTOGETHER. THIS WOULD ALLOW THE PRINTER DEVICE DRIVER TO */
;/* RUN FROM VIA THE TIMER OPERATION. THE CODE NOW REQUIRES THAT IN */
;/* ORDER FOR US TO RECOGNIZE THE INTERRUPT AS OURS, WE MUST HAVE SENT */
;/* A CHARACTER OUT TO THE PRINTER. */
;/* */
;/**********************************************************************/
test [di].commonflags,CHARACTER_OUT ; HAS A CHAR BEEN SENT?
jnz interrupt05 ; JUMP IF YES.
cmp fIRQStolen,1 ; IS THIS AN "OLD" INT
je interrupt3 ; YES, EOI
; PRINT REQUEST, HAVE SETIRQ, PRINTER OFF, PRTRESTART SET, PRINTER ON
; MAY NOT HAVE SENT CHAR BUT LASER PRINTERS GENERATE IRQ WHEN TURNED ON
test [di].commonflags,PRTRESTART ; REQUEST IN PROGRESS?
jnz interrupt05 ; JUMP IF YES.
stc ; OTHERWISE, SET CARRY
cli ; DISABLE INTS 87416
jmp SHORT interrupt4 ; AND RETURN.
interrupt05:
and [di].commonflags,NOT CHARACTER_OUT ; RESET CHAR SENT FLAG.
;/** END SPURIOUS TEST *************************************************/
;/* */
;/**********************************************************************/
test [di].commonflags,MONPRINTING ; IF !MON PRINTING
jnz interrupt0 ; CONTINUE
test [di].commonflags,IOACTIVE ; IF I/O !ACTIVE
jz interrupt3 ; THEN JUST RETURN
interrupt0:
; I/O IS ACTIVE ON THIS DEVICE
mov ax,[di].initialcount ; GET INITIAL COUNT
cmp ax,[di].prtcount ; IF BYTES REMAIN
jne interrupt1 ; THEN CONTINUE PRINTING
; COMPLETELY FINISHED PRINTING
call cleanup ; CALL CLEANUP
jmp SHORT interrupt3 ; RET TO HARD INT MGR
interrupt1:
;NOT FINISISHED PRINTING
;/**********************************************************************/
;/* INTERRUPTS WILL BE ENABLED BY SENDCHAR ROUTINE */
;/**********************************************************************/
call sendchar ; PRINT NEXT CHAR
interrupt3:
cli ; DONT ALLOW NESTED INTS
mov al,20h ; NON SPECIFIC EOI
out 20h,al ; ISSUE EOI TO 8259
clc ; TELL INT MGR, MY INT
interrupt4:
ret
EndProc interrupt
BREAK <PREPARE TO SEND A CHAR. TO A DEVICE>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SUBROUTINE NAME: SENDCHAR */
;/* */
;/* DESCRIPTIVE NAME: SEND CHARACTER ROUTINE */
;/* */
;/* FUNCTION: THE FUNCTION OF THIS SUBROUTINE IS TO SEND A CHARACTER */
;/* TO A DEVICE IF THAT DEVICE IS NOT IN ERROR. */
;/* */
;/* ENTRY POINT: SENDCHAR */
;/* LINKAGE : CALL NEAR */
;/* */
;/* INPUT: DI = OFFSET TO APPROPRIATE PERPRTDATA AREA */
;/* */
;/* EXIT-NORMAL: [DI].cancelflags = filled in. */
;/* Interrupts are enabled. */
;/* */
;/* EXIT-ERROR : See EXIT-NORMAL above. */
;/* */
;/* INTERNAL REFERENCES: getstatus */
;/* ROUTINES: sendtodev */
;/* */
;/* EXTERNAL REFERENCES: NONE */
;/* ROUTINES: */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure sendchar near
ASSUME CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
mov cx,BUSYRETRY ; SET RETRY CNT
.REPEAT
call getstatus ; GET DEVICE STATUS
dec cx ; DECREMENT COUNT LOOP
.UNTIL <BIT ah NZ NOTBUSY> OR ; UNTIL NOT BUSY OR
.UNTIL CXZ ; COUNT REACHES "0"
SaveReg <es,bx> ; SAVE REGISTERS
mov es,[di].gdtprintbuf ; GET USER BUF GDT SEL
mov bx,[di].printbufoff ; GET USER BUF OFFSET
add bx,[di].prtcount ; ADD PRINTED COUNT
cmp ah,NORMALSTAT ; IF NORMAL PORT STATUS
je sendchar1 ; THEN SEND CHAR TO DEV
cmp ah,NOTBUSY ; IF ! DESELECTED
jne sendchar0 ; THEN TRY TO RESTART
cmp BYTE PTR es:[bx],SELECT ; ELSEIF BYTE 1 = SELECT
je sendchar1 ; THEN SEND CHAR TO DEV
sendchar0:
or [di].commonflags,PRTRESTART ; ELSE SET RESTART FLAG
mov [di].cancelstatus,ah ; SAVE STATUS FLAGS
jmp SHORT sendchar2 ; EXIT
sendchar1:
and [di].commonflags,NOT MONERRPKTSENT ; CLEAR PKT SENT FLAG
and [di].commonflags,NOT PRTRESTART ; CLEAR RESTART FLAG
mov [di].cancelstatus,CANNOERROR ; CLEAR CANCEL STATUS
mov [di].cancelflags,CANNOERROR ; SET NO ERROR
mov [di].timeoutctr,0 ; RESET TIMEOUT COUNTER
call sendtodev ; SEND CHAR TO DEVICE
sendchar2:
RestoreReg <bx,es> ; RESTORE REGISTERS
sti ; ENABLE INTERRUPTS
ret
EndProc sendchar
BREAK <SEND A CHARACTER TO A DEVICE>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SUBROUTINE NAME: SENDTODEV */
;/* */
;/* DESCRIPTIVE NAME: SEND CHARACTER ROUTINE */
;/* */
;/* FUNCTION: THE FUNCTION OF THIS SUBROUTINE IS TO SEND A CHARACTER */
;/* TO A DEVICE. */
;/* */
;/* ENTRY POINT: SENDTODEV */
;/* LINKAGE : CALL NEAR */
;/* */
;/* INPUT: DI = OFFSET TO APPROPRIATE PERPRTDATA AREA */
;/* DX = DATA PORT ADDRESS */
;/* ES:BX = PTR TO APPROPRIATE DATA BUFFER */
;/* */
;/* EXIT-NORMAL: [di].prtcount = incremented by 1. */
;/* set CHARACTER_OUT in commonflags */
;/* */
;/* EXIT-ERROR : N/A */
;/* */
;/* INTERNAL REFERENCES: NONE */
;/* ROUTINES: */
;/* */
;/* EXTERNAL REFERENCES: NONE */
;/* ROUTINES: */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure sendtodev near
ASSUME CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
mov al,BYTE PTR es:[bx] ; GET NEXT CHAR TO PRINT
inc [di].prtcount ; INC PRINTED COUNT
cli ; DISABLE INTERRUPTS
or [di].commonflags,CHARACTER_OUT ; SET CHAR OUT FLAG
out dx,al ; SEND DATA TO DATA PORT
inc dx ; POINT TO CONTROL PORT
inc dx ; POINT TO CONTROL PORT
mov al,STROBELOW ; SET STROBE LOW BIT
cmp [di].curintlevel,0 ; IF !RUNNING ON TIMER
jne sendtodev1 ; THEN IRQ ENABLE SET
and al,NOT IRQENABLEBIT ; ELSE NO IRQ ENABLE
sendtodev1:
out dx,al ; STROBE >1us AND <5us
DevIODelay <bx> ; I/O DELAY - STR WIDTH
DevIODelay <bx> ; I/O DELAY - STR WIDTH
mov al,STROBEHIGH ; SET THE STROBE HIGH
cmp [di].curintlevel,0 ; IF !RUNNING ON TIMER
jne sendtodev2 ; THEN IRQ ENABLE SET
and al,NOT IRQENABLEBIT ; ELSE NO IRQ ENABLE
sendtodev2:
out dx,al ; NEW CTRL VALUE TO PORT
sti ; ELSE ENABLE INTERRUPTS
ret
EndProc sendtodev
BREAK <TIMEOUT ROUTINE FOR DEVICE LPT1>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SUBROUTINE NAME: PRT_TIMEOUT_1 */
;/* */
;/* DESCRIPTIVE NAME: Timeout routine for LPT1 */
;/* */
;/* FUNCTION: This routine calculates the index into the device data */
;/* area and calls the general timeout routine. This */
;/* routine is called by timer services once every second. */
;/* */
;/* NOTES: It is the timeout routine's responsibility to save and */
;/* restore all registers used in the printer timeout handler. */
;/* */
;/* ENTRY POINT: */
;/* LINKAGE: prt_timeout_1:far */
;/* call prt_timeout_1 */
;/* */
;/* INPUT: DS = our data segment */
;/* */
;/* EXIT-NORMAL: All registers are restored. */
;/* */
;/* EXIT-ERROR: See EXIT-NORMAL above. */
;/* */
;/* INTERNAL REFERENCES: prt_timeout */
;/* ROUTINES: */
;/* */
;/* EXTERNAL REFERENCES: NONE */
;/* ROUTINES: */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prt_timeout_1 far
ASSUME CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
pusha ; SAVE ALL REGISTERS
push es ; SAVE EXTRA SEGMENT
mov di,(LPT1_INDEX * SIZE printer_database) ; TIMEOUT DEVICE = LPT1
call prt_timeout ; GEN TIMEOUT ROUTINE
pop es ; RESTORE EXTRA SEGMENT
popa ; RESTORE ALL REGISTERS
ret ; RET TO TIMER MANAGER
EndProc prt_timeout_1
BREAK <TIMEOUT ROUTINE FOR DEVICE LPT2>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SUBROUTINE NAME: PRT_TIMEOUT_2 */
;/* */
;/* DESCRIPTIVE NAME: Timeout routine for LPT2 */
;/* */
;/* FUNCTION: This routine calculates the index into the device data */
;/* area and calls the general timeout routine. This */
;/* routine is called by timer services once every second. */
;/* */
;/* NOTES: It is the timeout routine's responsibility to save and */
;/* restore all registers used in the printer timeout handler. */
;/* */
;/* ENTRY POINT: */
;/* LINKAGE: prt_timeout_2:far */
;/* call prt_timeout_2 */
;/* */
;/* INPUT: DS = our data segment */
;/* */
;/* EXIT-NORMAL: All registers are restored. */
;/* */
;/* EXIT-ERROR: See EXIT-NORMAL above. */
;/* */
;/* INTERNAL REFERENCES: prt_timeout */
;/* ROUTINES: */
;/* */
;/* EXTERNAL REFERENCES: NONE */
;/* ROUTINES: */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prt_timeout_2 far
ASSUME CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
pusha ; SAVE ALL REGISTERS
push es ; SAVE EXTRA SEGMENT
mov di,(LPT2_INDEX * SIZE printer_database) ; TIMEOUT DEVICE = LPT2
call prt_timeout ; GEN TIMEOUT ROUTINE
pop es ; RESTORE EXTRA SEGMENT
popa ; RESTORE ALL REGISTERS
ret ; RET TO TIMER MANAGER
EndProc prt_timeout_2
BREAK <TIMEOUT ROUTINE FOR DEVICE LPT3>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SUBROUTINE NAME: PRT_TIMEOUT_3 */
;/* */
;/* DESCRIPTIVE NAME: Timeout routine for LPT3 */
;/* */
;/* FUNCTION: This routine calculates the index into the device data */
;/* area and calls the general timeout routine. This */
;/* routine is called by timer services once every second. */
;/* */
;/* NOTES: It is the timeout routine's responsibility to save and */
;/* restore all registers used in the printer timeout handler. */
;/* */
;/* ENTRY POINT: */
;/* LINKAGE: prt_timeout_3:far */
;/* call prt_timeout_3 */
;/* */
;/* INPUT: DS = our data segment */
;/* */
;/* EXIT-NORMAL: All registers are restored. */
;/* */
;/* EXIT-ERROR: See EXIT-NORMAL above. */
;/* */
;/* INTERNAL REFERENCES: prt_timeout */
;/* ROUTINES: */
;/* */
;/* EXTERNAL REFERENCES: NONE */
;/* ROUTINES: */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prt_timeout_3 far
ASSUME CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
pusha ; SAVE ALL REGISTERS
push es ; SAVE EXTRA SEGMENT
mov di,(LPT3_INDEX * SIZE printer_database) ; TIMEOUT DEVICE = LPT3
call prt_timeout ; GEN TIMEOUT ROUTINE
pop es ; RESTORE EXTRA SEGMENT
popa ; RESTORE ALL REGISTERS
ret ; RET TO TIMER MANAGER
EndProc prt_timeout_3
BREAK <GENERAL TIMEOUT ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SUBROUTINE NAME: PRT_TIMEOUT */
;/* */
;/* DESCRIPTIVE NAME: The timeout entry point is used to cancel the */
;/* timed out print block request. */
;/* */
;/* FUNCTION: This routine is called 1 time a second. It will count */
;/* timeoutmax times to see if a timeout has occurred. */
;/* If the restart flag is on, this routine will try to */
;/* immediately restart the request otherwise if timeout */
;/* equals timeoutmax, it will deregister the timeout */
;/* handler from the Timer Manager, and will call the */
;/* cleanup routine to cancel the request. If infinite */
;/* retry is set, this routine will try to restart the */
;/* print request. */
;/* */
;/* NOTES: */
;/* */
;/* ENTRY POINT: PRT_TIMEOUT:NEAR */
;/* LINKAGE: CALL PRT_TIMEOUT */
;/* */
;/* INPUT: DI = offset of device into perprtarea. */
;/* [DI].timeoutmax = maximum wait time in seconds before */
;/* canceling the print request. */
;/* [DI].timeoutctr = counter maintained to reach timeoutmax */
;/* */
;/* EXIT-NORMAL: [DI].cancelflags = CANIOERROR */
;/* */
;/* EXIT-ERROR: See EXIT-NORMAL above. */
;/* */
;/* INTERNAL REFERENCES: cleanup */
;/* ROUTINES: prterp */
;/* sendmonerpkt */
;/* sendchar */
;/* */
;/* EXTERNAL REFERENCES: NONE */
;/* ROUTINES: */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prt_timeout near
ASSUME CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
add di,OFFSET perprtarea ; START OF PERPRTDATA
test [di].commonflags, USEPOLLING ; USING POLLING?
jz prt_timeout_interrupts ; NO, USING INTERUPTS
call prt_timeout_polling ; YES, CALL POLLING FUNC
jmp prt_time_2 ; AND EXIT
prt_timeout_interrupts:
test [di].commonflags1,CANMONPKT ; CANCEL MON PRT REQ?
jnz prt_time_05 ; YES
inc [di].timeoutctr ; INC CTR TO 20 SECONDS
mov ax,[di].timeoutmax ; GET TIMEOUT LIMIT
cmp [di].timeoutctr,ax ; IF !20 SECOND TIMEOUT
jb prt_time_1 ; THEN TRY TO RESEND
mov [di].timeoutctr,0 ; ELSE CLEAR THE COUNTER
test [di].commonflags,MONPRINTING ; ERROR ON MON REQ?
jz prt_time_0 ; NO
test [di].commonflags,MONERRPKTSENT ; ERR PKT ALREADY SENT
jnz prt_time_0 ; YES
call prterp ; GET ERROR CODE
call sendmonerpkt ; SEND MON ERROR PKT
prt_time_0:
or [di].commonflags,PRTRESTART ; ASSUME INF RETRY
test [di].commonflags,INFINRETRY ; IF INF RETRY
jnz prt_time_1 ; THEN PROC INF RETRY
and [di].commonflags,NOT PRTRESTART ; ASSUMED WRONG, RESET
prt_time_05:
call prterp ; GET CANCEL FLAGS
call cleanup ; CLEANUP
jmp prt_time_2 ; EXIT
prt_time_1: ; THEN INFINITE RETRY
cmp [di].curintlevel,0 ; IF !USING INTERRUPTS
je prt_time_2 ; THEN USING TIMER, NOP
test [di].commonflags,PRTRESTART ; ELSEIF RESTART IS OFF
jz prt_time_2 ; THEN NO ERRORS, NOP
call sendchar ; ELSE INTS/ERRS RESTART
prt_time_2:
ret
EndProc prt_timeout
BREAK <CLEANUP ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SUBROUTINE NAME: CLEANUP ROUTINE */
;/* */
;/* DESCRIPTIVE NAME: Print cleanup routine. */
;/* */
;/* FUNCTION: THE FUNCTION OF THIS SUBROUTINE IS TO PERFORM THE */
;/* CLEANUP WORK WHEN A REQUEST IS COMPLETED. THIS ROUTINE */
;/* RETURN INFORMATION IN THE REQUEST BLOCK AND ISSUES A */
;/* DEVICE DONE ON THE REQUEST BLOCK. */
;/* */
;/* NOTE: SetIRQ done on printblock call and UnSetIRQ done on */
;/* cleanup calls. This allows sharing of IRQ5 and 7 on AT. */
;/* */
;/* ENTRY POINT: CLEANUP */
;/* LINKAGE : CALL NEAR */
;/* */
;/* INPUT: DI = offset to appropriate perprtdata area */
;/* [DI].cancelflags = filled in. */
;/* */
;/* EXIT-NORMAL: */
;/* */
;/* EXIT-ERROR : */
;/* */
;/* INTERNAL REFERENCES: stoptimer */
;/* ROUTINES: */
;/* */
;/* EXTERNAL REFERENCES: DEVICE_HELP ResetTimer */
;/* ROUTINES: UnSetIRQ */
;/* ProcRun */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure cleanup near
ASSUME CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
mov ax,[di].timeout_off ; TIMEOUT ENTRY POINT
mov dl,DevHlp_ResetTimer ; RESET TIMEOUT TIMER
call DWORD PTR [device_help] ; CALL TIMER SERVICES
cmp [di].curintlevel,0 ; IF !RUNNING ON TIMER
jne cleanup1 ; THEN RUNNING ON INTS
call stoptimer ; RESET DEVICE ON TIMER
jmp SHORT cleanup2
cleanup1:
xor bh,bh ; MAKE BH ZERO
mov bl,[di].intlevel ; IRQ NUMBER 0-F
mov dl,DevHlp_UnSetIRQ ; UNSET IRQ AT 8259
call DWORD PTR [device_help] ; CALL HARD INT MGR
mov dx,[di].deviceaddr ; GET DEVICE ADDRESS
inc dx
inc dx ; POINT TO CONTROL PORT
mov al,DISABLEINT ; DISABLE INT AT PORT
out dx,al ; SEND NEW CTRL VALUE
cleanup2:
mov es,[di].dosrqseg ; ASSUME DOS REQUEST BLK
mov bx,[di].dosoffset ; ASSUME DOS REQUEST BLK
test [di].commonflags,MONPRINTING ; IF !MONITOR REQUEST
jz cleanup3 ; THEN ASSUMED CORRECTLY
mov es,[di].monseg ; MON REQUEST BLOCK
mov bx,[di].monoffset ; MON REQUEST BLOCK
cleanup3:
cmp es:[bx].PktCmd,CMDOUTPUT ; IF COMMAND = WRITE
je cleanup4 ; THEN RETURN PRT COUNT
cmp es:[bx].PktCmd,CMDOUTPUTV ; IF COMMAND = WRITE/V
jne cleanup5 ; THEN RETURN PRT COUNT
cleanup4:
mov dx,[di].prtcount ; GET COUNT PRINTED
;/**********************************************************************/
;/* */
;/* ANOTHER 3X BOX KLUGE - PTM 7095 */
;/* */
;/**********************************************************************/
;/* */
;/* THE FOLLOWING CODE IS REQUIRED TO FIX A SITUATION IN THE REAL MODE */
;/* BOX CAUSED BY THE "COPY" AND "TYPE" COMMANDS WHICH ARE DIRECTED TO */
;/* THE PRINTER. THESE COMMANDS ISSUE CHARACTER REQUESTS ONE */
;/* CHARACTER AT A TIME. IF THE PRINTER IS A BUFFERED DEVICE AND IT */
;/* IS TURNED OFF LINE, IT IS QUITE POSSIBLE THAT THE CHARACTER HAS */
;/* BEEN SENT TO THE PRINTER BUFFER BUT THE INTERRUPT WON'T BE */
;/* RECEIVED AND WE WILL TIME OUT. THIS RESULTS IN AN ERROR BEING */
;/* RETURNED IN THE REQUEST PACKET BUT THE BYTE COUNT PRINTED IS THE */
;/* TOTAL BYTE COUNT REQUESTED. THE HARD ERROR HANDLER GETS THE ERROR */
;/* AND ALLOWS THE USER TO SELECT THE RETRY FUNCTION. THIS CAUSES THE */
;/* SAME CHARACTER TO BE SENT TO THE PRINTER WHEN IT IS PUT BACK ON */
;/* LINE AGAIN. */
;/* */
;/* THE FOLLOWING CODE WILL CLEAR ANY ERROR STATUS SET BY OTHER PARTS */
;/* OF THE DEVICE DRIVER ONLY IF THE TOTAL NUMBER OF CHARS REQUESTED */
;/* HAVE BEEN SENT TO THE DEVICE. THIS MEANS THAT THE REQUEST IS */
;/* COMPLETE. THIS WAY, THE HARD ERROR HANDLER WON'T RE-ISSUE THE */
;/* REQUEST FOR THE SAME CHARACTER IF RETRY IS SELECTED. THE HARD */
;/* ERROR HANDLER WON'T SEE THE ERROR FOR THIS CHARACTER. */
;/* */
;/**********************************************************************/
cmp [di].initialcount,dx ; IF BYTES REMAINING
jne cleanup45 ; THEN MUST SET ERROR
mov [di].cancelflags,CANNOERROR ; SET NO ERROR
cleanup45:
;/**********************************************************************/
;/* */
;/* END OF KLUGE. */
;/* */
;/**********************************************************************/
mov es:[bx].IOcount,dx ; PUT COUNT IN REQ PKT
cleanup5:
cmp es:[bx].PktStatus,CHARIOINT ; CTRL C PRESSED BY USER
je cleanup6 ; YES, EXIT
xor ah,ah ; ZERO OUT AH
mov al,[di].cancelflags ; GET CANCEL FLAGS
mov [di].cancelflags,0 ; ZERO OUT CANCEL FLAGS
mov si,ax ; GET ERROR CODE
sal si,1 ; GET WORD INDEX
mov ax,doserrors[si] ; GET ERROR CODE
mov es:[bx].PktStatus,ax ; PUT ERR. IN REQ.BLK
mov ax,es ; BLOCK ID
inc bx ; UNIQUE BLOCK ID
mov dl,DevHlp_ProcRun ; RUN PRINTBLOCK THREAD
call DWORD PTR [device_help] ; DEVICE HELP
dec bx ; ADDRESS REQUEST BLOCK
cleanup6:
ret
EndProc cleanup
BREAK <PRINTER ERROR STATUS PROCESSING>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SUBROUTINE NAME: PRTERP */
;/* */
;/* DESCRIPTIVE NAME: ANALYZE STATUS FLAGS */
;/* */
;/* FUNCTION: THE FUNCTION OF THIS SUBROUTINE IS TO ANALYZE THE STATUS */
;/* INFORMATION RETURNED FROM "GETSTATUS" AND SAVED IN THE */
;/* CANCELSTATUS BYTE. */
;/* */
;/* ENTRY POINT: PRTERP */
;/* LINKAGE : CALL NEAR */
;/* */
;/* INPUT: DI = OFFSET TO APPROPRIATE PERPRTDATA AREA */
;/* AH = PRINTER STATUS */
;/* */
;/* EXIT-NORMAL: [DI].cancelflags = filled in. */
;/* */
;/* EXIT-ERROR : See EXIT-NORMAL above. */
;/* */
;/* INTERNAL REFERENCES: getstatus */
;/* ROUTINES: */
;/* */
;/* EXTERNAL REFERENCES: NONE */
;/* ROUTINES: */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
;***********************************************************************
;* *
;* CHECK STATUS BITS AND TAKE APPROPRIATE ACTION. *
;* MESSAGES CURRENTLY ISSUED FOR ERROR CONDITIONS: *
;* *
;* #20 = THE SYSTEM CANNOT FIND THE DEVICE SPECIFIED. *
;* *
;* #28 = THE PRINTER IS OUT OF PAPER. *
;* *
;* #29 = THE SYSTEM CANNOT WRITE TO THE SPECIFIED DEVICE. *
;* *
;***********************************************************************
Procedure prterp near
ASSUME CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
mov [di].cancelflags,CANNOERROR ; CLEAR CANCEL FLAGS
mov ah,[di].cancelstatus ; GET STATUS FLAGS
and ah,ah ; CHECK IF ZERO
.IF Z
call getstatus
mov [di].cancelstatus,ah ; SAVE CANCEL STATUS
.ENDIF
;*******************************************************************************
;* B0 = NOT BUSY & PAPER OUT & SELECTED = !CABLED ON MONO / SERIAL ADAPTER #20 *
;*******************************************************************************
.IF <BIT ah NZ NOTBUSY> AND ; IF NOT BUSY AND
.IF <BIT ah NZ PAPEROUT> AND ; IF PAPER OUT AND
.IF <BIT ah NZ NOTSELECTED> ; IF SELECTED
mov [di].cancelflags,CANNOTSELECT ; SET SELECT ERROR
;*******************************************************************************
;* 30 = BUSY & PAPER OUT & SELECTED & NOT I/O ERROR = OUT OF PAPER #28 *
;*******************************************************************************
.ELSEIF <BIT ah Z NOTBUSY> AND ; IF BUSY AND
.IF <BIT ah NZ PAPEROUT> AND ; IF PAPER OUT AND
.IF <BIT ah NZ NOTSELECTED> AND ; IF SELECTED AND
.IF <BIT ah Z IOERROR> ; IF NOT I/O ERROR
mov [di].cancelflags,CANPAPEROUT ; SET PAPER OUT ERROR
;*******************************************************************************
;* 28 = BUSY & PAPER OUT & NOT SELECTED & I/O ERROR = OUT OF PAPER #28 *
;*******************************************************************************
.ELSEIF <BIT ah Z NOTBUSY> AND ; IF BUSY AND
.IF <BIT ah NZ PAPEROUT> AND ; IF PAPER OUT AND
.IF <BIT ah Z NOTSELECTED> AND ; IF NOT SELECTED AND
.IF <BIT ah NZ IOERROR> ; IF I/O ERROR
mov [di].cancelflags,CANPAPEROUT ; SET PAPER OUT ERROR
;*******************************************************************************
;* 10 = BUSY & SELECTED = NOT READY #29 *
;*******************************************************************************
.ELSEIF <BIT ah Z NOTBUSY> AND ; IF BUSY AND
.IF <BIT ah NZ NOTSELECTED> ; IF SELECTED
mov [di].cancelflags,CANIOERROR ; SET I/O ERROR
;*******************************************************************************
;* 08 = BUSY & I/O ERROR = OFF LINE #29 *
;*******************************************************************************
.ELSEIF <BIT ah Z NOTBUSY> AND ; IF BUSY AND
.IF <BIT ah NZ IOERROR> ; IF I/O ERROR
mov [di].cancelflags,CANIOERROR ; SET I/O ERROR
;*******************************************************************************
;* 00 = BUSY & NOTHING ELSE = NOT READY #29 *
;*******************************************************************************
.ELSEIF <ah EQ 0> ; IF ONLY BUSY
mov [di].cancelflags,CANIOERROR ; SET I/O ERROR
;*******************************************************************************
;* 88 = NOT BUSY & I/O ERROR = POWERED OFF #20 *
;*******************************************************************************
.ELSEIF <BIT ah NZ NOTBUSY> AND ; IF NOT BUSY AND
.IF <BIT ah NZ IOERROR> ; IF I/O ERROR
mov [di].cancelflags,CANNOTSELECT ; SET SELECT ERROR
.ELSE ; NOT A "SELECT" CHAR
mov [di].cancelflags,CANNOTSELECT ; SET SELECT ERROR
.ENDIF
xor ah,ah ; ZERO OUT AH
mov [di].cancelstatus,ah ; SET STATUS FLAGS = 0
RET
EndProc prterp
BREAK <GET STATUS OF SPECIFIED DEVICE>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SUBROUTINE NAME: GETSTATUS */
;/* */
;/* DESCRIPTIVE NAME: GET STATUS ROUTINE */
;/* */
;/* FUNCTION: THE FUNCTION OF THIS SUBROUTINE IS TO RETURN THE STATUS */
;/* OF THE REQUESTED DEVICE IN REGISTER AH. */
;/* */
;/* NOTES: DATA, STATUS, THEN CONTROL PORT. */
;/* */
;/* ENTRY POINT: GETSTATUS */
;/* LINKAGE : CALL NEAR OR FAR */
;/* */
;/* INPUT: DI = OFFSET TO APPROPRIATE PERPRTDATA AREA */
;/* */
;/* EXIT-NORMAL: AH = DEVICE STATUS, DX = DATA PORT ADDRESS */
;/* */
;/* EXIT-ERROR : AH = DEVICE STATUS, DX = DATA PORT ADDRESS */
;/* */
;/* INTERNAL REFERENCES: NONE */
;/* ROUTINES: */
;/* */
;/* EXTERNAL REFERENCES: NONE */
;/* ROUTINES: */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure getstatus,HYBRID
ASSUME CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
mov dx,[di].deviceaddr ; GET DEVICE ADDRESS
inc dx ; POINT TO STATUS PORT
in al,dx ; GET STATUS BYTE
mov ah,al ; MOV STATUS INTO AH
and ah,UNUSEDBITS ; TURN OFF UNUSED BITS
xor ah,REVERSEBITS ; FLIP A COUPLE OF BITS
dec dx ; RESET DX TO DATA ADDR
ret
EndProc getstatus
; *** END OF RESIDENT CODE ***
; ALL CODE AFTER THIS POINT IS RELEASED AFTER INITIALIZATION
CODEEND EQU $ - 1 ; USE LIMIT OF SEGMENT
BREAK <INITIALIZATION ROUTINE>
;/*********************** END OF SPECIFICATIONS ************************/
;/* */
;/* SUBROUTINE NAME: PRTINIT */
;/* */
;/* DESCRIPTIVE NAME: Initialize the printer device driver */
;/* */
;/* FUNCTION: This routine is called to perform any parallel port */
;/* device driver initialization. This routine will be */
;/* called once for each device header defined in the data */
;/* segment. All initialization is performed on the first */
;/* call. */
;/* */
;/* NOTES: */
;/* */
;/* ENTRY POINT: */
;/* LINKAGE: prtinit:NEAR */
;/* call prtinit */
;/* */
;/* INPUT: ES = Virtual segment of kernel request block */
;/* BX = Virtual offset of kernel request block */
;/* DI = Offset to appropriate perprtdata area */
;/* */
;/* EXIT-NORMAL: Status field of Kernel Request Block is filled in. */
;/* See the specific request in the CP/DOS OS and Util. */
;/* Functional Specification for other return values. */
;/* timeoutval = # of ticks to wait for timeout */
;/* */
;/* EXIT-ERROR: see EXIT-NORMAL above. */
;/* */
;/* EFFECTS: */
;/* */
;/* INTERNAL REFERENCES: eisainit */
;/* ROUTINES: _RM_PRT_CreateDriver */
;/* parsecmdline */
;/* RM_PRT_RegisterResources */
;/* initialprt */
;/* */
;/* EXTERNAL REFERENCES: DEVICE_HELP GetDOSVar */
;/* ROUTINES: RegisterPDD */
;/* AllocGDTSelector */
;/* VirtToPhys */
;/* RegisterPerfCtrs */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtinit far
ASSUME CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
SaveReg <es,bx> ; SAVE REGISTERS
test flags,FIRSTINIT ; IF 1ST TIME THEN
jz prtinit0 ; DO ONCE ONLY CODE
jmp prtinit1 ; SKIP ONCE ONLY CODE
; INITIALIZATION CODE DONE ONCE ONLY (DONE DURING PRN INIT CALL)
; (FROM HERE TO PRTINIT1)
prtinit0:
or flags,FIRSTINIT ; SET FIRST INIT ON
; SAVE ADDRESS OF DEVHLP ROUTINE
mov ax,WORD PTR es:[bx].InitpEnd ; OFFSET OF DEVHLP
mov WORD PTR device_help,ax ; OFFSET OF DEVHLP
mov WORD PTR _Device_Help,ax ; OFFSET OF DEVHLP
mov ax,WORD PTR es:[bx].InitpEnd + 2 ; SEG OF DEVHLP
mov WORD PTR device_help + 2,ax ; SEG OF DEVHLP
mov WORD PTR _Device_Help + 2,ax ; SEG OF DEVHLP
; GET POINTER TO GLOBAL INFO SEG
mov al,GLOBINFOSEG ; GET VAR GLOBALINFOSEG
mov dl,DevHlp_GetDOSVar ; GET DOS VAR FUNCTION
call DWORD PTR [device_help] ; CALL DEVHLP
mov es,ax ; AX:BX -> GLOBALINFOSEG
mov es,WORD PTR es:[bx] ; ES:BX -> ADDR/GLOBINFO
xor bx,bx
mov WORD PTR glinfoseg,bx ; GLOBAL INFOSEG OFF
mov WORD PTR glinfoseg + 2,es ; GLOBAL INFOSEG SEG
mov bx,es:[bx].SIS_ClkIntrvl ; GET TIMER INTERVAL
xor dx,dx
mov ax,10000 ; MICROSEC TO SEC RULE
div bx ; TICKS / MICROSEC
mov timeoutval,ax ; SAVE TICKS / SEC
; GET POINTER TO LOCAL INFO SEG
mov al,LOCINFOSEG ; GET VAR LOCAL INFOSEG
mov dl,DevHlp_GetDOSVar ; GET DOS VAR FUNCTION
call DWORD PTR [device_help] ; CALL DEVHLP
mov WORD PTR dosvar,bx ; OFF LOCAL INFOSEG
mov WORD PTR dosvar + 2,ax ; SEG LOCAL INFOSEG
; REGISTER THE PLPT'S VDD SERVICES ENTRY POINT WITH VLPT.
; THIS ENTRY POINT IS THE ROUTER FOR ALL THE IDC COMMUNICATIONS.
push di ; SAVE PER PRT AREA
lea si,plptname ; LOAD PLPT NAME
push SWAPSEG ; SETUP ES
pop es ;
lea di,PLPTCMD_Entry ; ES:DI -> PLPT ROUTER
mov dl,DevHlp_RegisterPDD ; REGISTERPDD FUNC
call DWORD PTR [device_help] ; CALL DEVICE HELP
pop di
; REGISTER DRIVER WITH RESOURCE MANAGER
push di ; SAVE PERPRTDATA AREA
push ds ; DRIVER NAME SEG
lea ax,ddname ; GET DRIVER NAME OFF
push ax ; DRIVER NAME OFF
call _RM_PRT_CreateDriver ; REGISTER DRIVER
add sp,4 ; CLEAN UP STACK
pop di ; RESTORE PERPRTDATA
; DETERMINE BUS TYPE
mov bustype,ISABUS ; ASSUME ISA BUS SYSTEM
call eisainit ; CHECK FOR EISA SYSTEM
jc prtinit0a ; ASSUMED CORRECT - ISA
mov bustype,EISABUS ; EISA BUS SYSTEM
prtinit0a:
; SET TIMEOUT ENTRY POINTS AND DEVICE INDICES
RestoreReg <bx,es> ; RESTORE REGISTERS
SaveReg <es,bx> ; SAVE REGISTERS
push di ; SAVE PERPRTAREA PTR
les bx,es:[bx].InitParms ; GET CONFIG.SYS PARMS
mov di,OFFSET perprtarea ; STARTING POINT
mov [di].deviceindex,LPT1_INDEX ; INDEX FOR LPT1
mov [di].deviceflag,LPT1_FLAG ; FLAG FOR LPT1
mov ax,es:[bx].LPT1BufSize ; GET LPT1 BUFFER SIZE
mov [di].configbufsize,ax ; SAVE LPT1 BUFFER SIZE
mov [di].prfvw_off,OFFSET prfvw_ctrs ; START OF DEVICE CTRS
mov [di].timeout_off,OFFSET prt_timeout_1 ; LPT1 EPT
add di,SIZE printer_database
mov [di].deviceindex,LPT2_INDEX ; INDEX FOR LPT2
mov [di].deviceflag,LPT2_FLAG ; FLAG FOR LPT2
mov ax,es:[bx].LPT2BufSize ; GET LPT2 BUFFER SIZE
mov [di].configbufsize,ax ; SAVE LPT2 BUFFER SIZE
mov [di].prfvw_off,OFFSET prfvw_ctrs ; START OF PERFVIEW CTRS
add [di].prfvw_off,SIZE prfvw_devarea ; START OF DEVICE CTRS
mov [di].timeout_off,OFFSET prt_timeout_2 ; LPT2 EPT
add di,SIZE printer_database
mov [di].deviceindex,LPT3_INDEX ; INDEX FOR LPT3
mov [di].deviceflag,LPT3_FLAG ; FLAG FOR LPT3
mov ax,es:[bx].LPT3BufSize ; GET LPT3 BUFFER SIZE
mov [di].configbufsize,ax ; SAVE LPT3 BUFFER SIZE
mov [di].prfvw_off,OFFSET prfvw_ctrs ; START OF PERFVIEW CTRS
add [di].prfvw_off,(2 * (SIZE prfvw_devarea)) ; START OF DEVICE CTRS
mov [di].timeout_off,OFFSET prt_timeout_3 ; LPT3 EPT
pop di ; RESTORE PERPRTAREA PTR
jmp prtinit3 ; EXIT
; PDD INITIALIZATION CODE FOR EACH PHYSICAL DEVICE (LPT1, LPT2, LPT3)
prtinit1:
xor ah,ah ; CLEAR AH
mov al,[di].deviceindex ; GET ZERO BASED INDEX
add [di].signature+3,al ; PPDA SIGNATURE
; ALLOCATE GDT SELECTOR FOR SENDING DATA TO MONITORS
SaveReg <ax,di> ; SAVE REGISTERS
push ds
pop es
lea di,[di].gdtuserbuf ; ES:DI -> GDT
mov cx,1 ; ALLOCATE 1 SELECTOR
mov dl,DevHlp_AllocGDTSelector ; ALLOC GDT SEL FUNC
call DWORD PTR [device_help] ; CALL DEVHLP
RestoreReg <di,ax> ; RESTORE REGISTERS
jnc prtinit11 ; IF NO ERROR, CONTINUE
jmp prtinit4 ; IF ERROR, EXIT
prtinit11:
; ALLOCATE GDT SELECTOR FOR PRINTING
SaveReg <ax,di> ; SAVE REGISTERS
lea di,[di].gdtprintbuf ; ES:DI -> GDT
mov cx,1 ; ALLOCATE 1 SELECTOR
mov dl,DevHlp_AllocGDTSelector ; ALLOC GDT SEL FUNC
call DWORD PTR [device_help] ; CALL DEVHLP
RestoreReg <di,ax> ; RESTORE REGISTERS
jnc prtinit12 ; IF NO ERROR, CONTINUE
jmp prtinit4 ; IF ERROR, EXIT
prtinit12:
; SETUP POINTER TO CACHE TO BUFFER SMALL WRITE REQUESTS WITH THE
; SAME SFN. AT APPROPRIATE TIME, SEND PACKET TO MONITOR.
imul si,ax,SIZE mcache ; CALC OFF IN MON CACHE
add si,OFFSET moncache ; SI -> DEVICE MON CACHE
mov [di].cache_off,si ; SAVE MON CACHE OFFSET
; SETUP POINTER TO BUFFER TO CONTAIN MONITOR PACKET TO BE SENT
; TO MONITORS FOR THIS DEVICE.
mov cx,dataend ; GET CURRENT MBUF START
mov [di].tomonbuf_off,cx ; SAVE TO MON BUF OFFSET
add cx,[di].configbufsize ; CALC NEW MON BUF START
; SETUP POINTER TO BUFFER TO CONTAIN MONITOR PACKET TO BE RECEIVED
; FROM MONITORS FOR THIS DEVICE (MONITOR FINAL BUFFER).
mov [di].frommonbuf_off,cx ; SAVE FROM MON BUF OFF
add cx,[di].configbufsize ; CALC NEW MON BUF START
mov dataend,cx ; SET NEW DATA SEG END
; CONVERT VIRTUAL MONITOR FINAL BUFFER ADDRESS TO PHYSICAL ADDRESS
; AND SAVE IT FOR FUTURE MONITOR REQUESTS.
mov si,[di].frommonbuf_off ; DS:SI -> VIRT MON PKT
lea si,[si].frommonbuf ; DS:SI -> VIRT ADDR BUF
mov dl,DevHlp_VirtToPhys ; VIRTTOPHYS FUNCTION
call DWORD PTR [device_help] ; CALL DEVICE HELP
jc prtinit4 ; IF ERROR, EXIT
mov [di].physbufoff,bx ; SAVE PHYS BUF OFF
mov [di].physbufseg,ax ; SAVE PHYS BUF SEG
; PARSE FOR COMMAND LINE PARAMETERS
RestoreReg <bx,es> ; RESTORE REGISTERS
SaveReg <es,bx> ; SAVE REGISTERS
call ParseCmdLine ; PARSE CMD LINE PARMS
; DETERMINE HARDWARE CAPABILITIES
call prtdeterminehardware ; CHECK FOR HARDWARE
jc prtinit4 ; IF ERROR, EXIT
test [di].commonflags1,PORTEXISTS ; IF PORT DOESN'T EXIST
jz prtinit2 ; THEN DON'T REGISTER
; REGISTER WITH RESOURCE MANAGER
call RM_PRT_RegisterResources ; OBTAIN RESOURCES
jc prtinit4 ; IF ERROR, EXIT
; INITIALIZE DEVICE
or [di].commonflags1,BOOTINIT ; SET BOOTINIT FLAG
CALLFAR initialprt ; INITIALIZE DEVICE
and [di].commonflags1,NOT BOOTINIT ; RESET BOOTINIT FLAG
; ADD PER-DEVICE PERFVIEW COUNTERS
add db_length,SIZE prfvw_devarea ; ADD DEV TO DATABLOCK
add WORD PTR tb_totalctrs,NUMBER_TMRS_CTRS ; ADD DEV CTRS TO TOTAL
prtinit2:
cmp [di].deviceindex,LPT3_INDEX ; IF DEVICE != LPT3
jne prtinit3 ; THEN CONTINUE
; SET PERFVIEW TO POINT TO DATA STRUCTURES
mov si,SEG data_block ; SEGMENT OF DATA_BLOCK
mov ax,OFFSET data_block ; OFFSET OF DATA_BLOCK
mov di,SEG text_block ; SEGMENT OF TEXT_BLOCK
mov bx,OFFSET text_block ; OFFSET OF TEXT_BLOCK
mov cx,WORD PTR data_block.dbh_flFlags ; GET FLAGS
mov dl,DevHlp_RegisterPerfCtrs ; REGISTER PERFVIEW FUNC
call DWORD PTR [device_help] ; CALL DEVICE HELP
; CY = ERROR, AX = CODE
prtinit3:
RestoreReg <bx,es> ; RESTORE REGISTERS
; SET ENDING ADDRESS OF CODE AND DATA SEGMENT IN DOS REQUEST BLOCK
mov ax,dataend ; END OF DATA SEGMENT
dec ax ; CONVERT TO LIMIT
mov WORD PTR es:[bx].InitpEnd+2,ax ; END OF DATA SEGMENT
mov WORD PTR es:[bx].InitpEnd,OFFSET CODEEND ; END OF CODE SEGMENT
mov es:[bx].PktStatus,REQDONE ; SET THE DONE BIT
jmp SHORT prtinit5 ; EXIT
prtinit4:
pop bx
pop es
mov WORD PTR es:[bx].InitpEnd+2,0 ; END OF DATA SEGMENT
mov WORD PTR es:[bx].InitpEnd,0 ; END OF CODE SEGMENT
mov es:[bx].PktStatus,GENFAILURE ; SET THE ERROR CODE
prtinit5:
ret
EndProc prtinit
BREAK <DETERMINE HARDWARE ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SUBROUTINE NAME: DETERMINE HARDWARE ROUTINE */
;/* */
;/* DESCRIPTIVE NAME: Determine parallel port hardware. */
;/* */
;/* FUNCTION: This routine determines the parallel port hardware */
;/* for ISA-bus systems and updates the perprtdata area */
;/* accordingly. */
;/* */
;/* NOTES: This routine is called for each device initialized. */
;/* */
;/* ENTRY POINT: */
;/* LINKAGE: prtdeterminehardware:NEAR */
;/* call prtdeterminehardware */
;/* */
;/* INPUT: DS = Data segment */
;/* DI = Offset to appropriate perprtdata area */
;/* */
;/* EXIT-NORMAL: NC */
;/* [di].deviceaddr = base port address */
;/* numofprts incremented */
;/* [di].commonflags1 |= PORTEXISTS */
;/* [di].introutine = hardware interrupt routine offset */
;/* [di].intlevel = hardware interrupt level */
;/* */
;/* EXIT-ERROR: CY */
;/* */
;/* EFFECTS: irq5index */
;/* */
;/* INTERNAL REFERENCES: NONE */
;/* ROUTINES: */
;/* */
;/* EXTERNAL REFERENCES: NONE */
;/* ROUTINES: */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtdeterminehardware near
ASSUME CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
test bustype,EISABUS ; IF !EISA MACHINE
jz prtdethard1 ; THEN CONTINUE SETUP
cmp [di].deviceaddr,0 ; PORT EXIST?
je prtdethard5 ; NO, EXIT
or [di].commonflags1,PORTEXISTS ; SAVE PORT INSTALLED
jmp SHORT prtdethard5 ; PREV SETUP, EISAINIT
; GET ADDRESSIBILITY TO BIOS ROM DATA AREA
prtdethard1:
push BIOSROMDATA ; SEG OF BIOS AREA
pop es ; SEG OF BIOS AREA
xor bx,bx ; OFF OF BIOS AREA
sub ah,ah ; CLEAR AH
mov al,[di].deviceindex ; GET ZERO BASED INDEX
mov si,ax ; PORT ADDRESS OFFSET
sal si,1 ; WORD ALIGN
mov ax,BIOSDATA.printer_adapt[si] ; GET PORT ADDRESS
mov [di].deviceaddr,ax ; SAVE PORT ADDRESS
or ax,ax ; IS PORT AVAILABLE?
jz prtdethard5 ; NO, EXIT
inc numofprts ; # OF PRTS INSTALLED
or [di].commonflags1,PORTEXISTS ; SAVE PORT INSTALLED
cmp ax,PORT278H ; IF DEV ADDR != 278H
jne prtdethard2 ; THEN PROCEED
; SET UP DEVICE INFO FOR IRQ 5 (INT 0DH) PROCESSING
mov [di].introutine,OFFSET prtint05 ; OFFSET INT HANDLER
mov [di].intlevel,LEVEL5 ; INTERRUPT LEVEL = 5
xor ah,ah ; CLEAR AH
mov al,[di].deviceindex ; GET DEVICE INDEX
mov irq5index,ax ; INDEX OF IRQ5 DEV
jmp SHORT prtdethard5 ; EXIT
; SET UP DEVICE INFO FOR IRQ 7 (INT 0FH) PROCESSING
prtdethard2:
mov [di].introutine,OFFSET prtint07 ; OFFSET INT HANDLER
mov [di].intlevel,LEVEL7 ; INTERRUPT LEVEL = 7
jmp SHORT prtdethard5 ; EXIT
; SET ERROR INDICATION
prtdethard4:
stc ; SET ERROR INDICATION
jmp SHORT prtdethard6 ; EXIT
; SET SUCCESS INDICATION
prtdethard5:
clc ; SET SUCCESS INDICATION
; EXIT
prtdethard6:
ret
EndProc prtdeterminehardware
BREAK <REGISTER RESOURCES ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SUBROUTINE NAME: REGISTER RESOURCES WITH RESOURCE MANAGER ROUTINE */
;/* */
;/* DESCRIPTIVE NAME: Call resource manager with resources needed. */
;/* */
;/* FUNCTION: This routine calls the resource manager with the */
;/* resources required by the parallel port device driver. */
;/* */
;/* NOTES: We currently cannot determine the DMA channel from ABIOS */
;/* so we do not report it. We must allocate the resources */
;/* before we register the adapter. */
;/* */
;/* ENTRY POINT: */
;/* LINKAGE: RM_PRT_RegisterResources:NEAR */
;/* call RM_PRT_RegisterResources */
;/* */
;/* INPUT: DS = Data segment */
;/* DI = Offset to appropriate perprtdata area */
;/* [di].deviceaddr = base port address */
;/* [di].intlevel = hardware interrupt level */
;/* [di].deviceindex = adapter number (zero based) */
;/* bustype = bus architecture (ISA, EISA, MC) */
;/* */
;/* EXIT-NORMAL: NC */
;/* */
;/* EXIT-ERROR: CY */
;/* */
;/* EFFECTS: */
;/* */
;/* INTERNAL REFERENCES: _RM_PRT_AllocPorts */
;/* ROUTINES: _RM_PRT_AllocIRQ */
;/* _RM_PRT_CreateAdapter */
;/* _RM_PRT_DeallocPorts */
;/* _RM_PRT_DeallocIRQ */
;/* */
;/* EXTERNAL REFERENCES: NONE */
;/* ROUTINES: */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure RM_PRT_RegisterResources near
ASSUME CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
pusha
push es
; OBTAIN CONFLICT-FREE PORT RESOURCES FROM RESOURCE MANAGER
push di ; SAVE PERPRTDATA AREA
push [di].deviceaddr ; BASE PORT
call _RM_PRT_AllocPorts ; CLAIM PORTS
add sp,2 ; CLEAN UP STACK
pop di ; RESTORE PERPRTDATA
or ax,ax ; IF ERROR
jnz RM_PRT_Reg3 ; EXIT
; OBTAIN CONFLICT-FREE IRQ RESOURCES FROM RESOURCE MANAGER
test [di].commonflags,USEPOLLING ; IF USE POLLING
jnz RM_PRT_Reg0 ; DON'T ALLOC IRQ
push di ; SAVE PERPRTDATA AREA
sub ah,ah ; CLEAR AH
mov al,[di].intlevel ; GET INTERRUPT LEVEL
push ax ; INTERRUPT LEVEL
push bustype ; BUS TYPE
call _RM_PRT_AllocIRQ ; CLAIM IRQ
add sp,4 ; CLEAN UP STACK
pop di ; RESTORE PERPRTDATA
or ax,ax ; IF ERROR
jnz RM_PRT_Reg2 ; EXIT
; REGISTER ADAPTER AND RESOURCES WITH RESOURCE MANAGER
RM_PRT_Reg0:
push di ; SAVE PERPRTDATA AREA
sub ah,ah ; CLEAR AH
mov al,[di].deviceindex ; GET ADAPTER NUMBER
push ax ; ADAPTER NUMBER
push bustype ; BUS TYPE
call _RM_PRT_CreateAdapter ; REGISTER ADAPTER
add sp,4 ; CLEAN UP STACK
pop di ; RESTORE PERPRTDATA
or ax,ax ; IF NO ERROR
jz RM_PRT_Reg4 ; EXIT
; IRQ ALLOCATED, DEALLOCATE IRQ
RM_PRT_Reg1:
call _RM_PRT_DeallocIRQ ; DEALLOC IRQ RESOURCE
; PORTS ALLOCATED, DEALLOCATE PORTS
RM_PRT_Reg2:
call _RM_PRT_DeallocPorts ; DEALLOC PORT RESOURCE
; SET ERROR INDICATION
RM_PRT_Reg3:
stc ; SET ERROR INDICATION
jmp SHORT RM_PRT_Reg5 ; EXIT
; SET SUCCESS INDICATION
RM_PRT_Reg4:
clc ; SET SUCCESS INDICATION
; EXIT
RM_PRT_Reg5:
pop es
popa ; RESTORE REGISTERS
ret
EndProc RM_PRT_RegisterResources
BREAK <PARSE COMMAND LINE ARGS>
;/********************** START OF SPECIFICATIONS ***********************/
;/* */
;/* SUBROUTINE NAME: ParseCmdLine */
;/* */
;/* DESCRIPTIVE NAME: PARSE COMMAND LINE ARGS */
;/* */
;/* FUNCTION: THE PURPOSE OF THIS SUBROUTINE IS TO EXAMINE COMMAND */
;/* LINE ARGS AND PERFORM APPROPRIATE ACTIONS. */
;/* */
;/* NOTES: FOR COMPATIBILITY WITH PREVIOUS VERSIONS OF PRINT0?.SYS */
;/* THE COMMAND LINE ARGS BEGIN IN THE ReqPacket:InitParms */
;/* BUFFER OFFSET BY THE 3 WORDS THAT CONTAIN THE BUFSIZE */
;/* VALUES (See prtinit.asm & prtinit.inc) */
;/* */
;/* CURRENTLY, THE CHECK FOR '/IRQ' IS VERY HARD CODED IN */
;/* THIS ROUTINE SINCE WITH THE ONE ARG WE DONT WANT TO */
;/* BLOAT PRINT0?.SYS WITH SOPHISTICATED PARSING CODE. */
;/* */
;/* COMMAND LINE ARGS SUPPORTED: */
;/* */
;/* None - directs the driver to use POLLING for printing rather than */
;/* IRQs. */
;/* */
;/* /IRQ - (Case insensitive) directs the driver to use IRQs for */
;/* printing rather than polling. */
;/* */
;/* ENTRY POINT: PARSECMDLINE */
;/* LINKAGE : CALL NEAR */
;/* */
;/* INPUT: DI = OFFSET TO APPROPRIATE PERPRTDATA AREA */
;/* ES:BX = PTR TO KERNEL REQUEST PACKET */
;/* */
;/* REGSITERS USED: All registers preserved */
;/* */
;/* EXIT-NORMAL: [di].commonflags USEPOLLING BIT SET APPROPRIATELY */
;/* */
;/* EXIT-ERROR : NO ERROR STATUS RETURNED */
;/* */
;/* INTERNAL REFERENCES: NONE */
;/* ROUTINES: */
;/* */
;/* EXTERNAL REFERENCES: NONE */
;/* ROUTINES: */
;/* */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure ParseCmdLine near
ASSUME CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
pusha ; SAVE REGISTERS
push es ; SAVE ES
or [di].commonflags, USEPOLLING ; ASSUME POLLING
mov si, di ; SAVE DI in SI
cld ; CLEAR DIRECTION FLAG
les bx, es:[bx].InitParms ; GET CONFIG.SYS PARMS
lea di, es:[bx].CmdLineParms ; OFFSET PAST BUF SIZES
; (SEE PRT_Parm_List
; STRUC IN PRTINIT.INC)
;/***********************************************/
;/* */
;/* ES:DI NOW POINTING AT COMMAND LINE ARGS, */
;/* */
;/* DO A VERY BRUTE FORCE SEARCH FOR "/IRQ" */
;/* (CASE INSENSITIVE). FIRST, FIND THE "/". */
;/* */
;/***********************************************/
mov al, '/' ; FIND FORWARD SLASH
mov cx, CMDLINE_ARGSIZE ; PRTINIT.INC EQU
repne scasb ; LOOK FOR IT
jnz ParseCmdLine_Exit ; JUMP IF DIDNT FIND
;/***********************************************/
;/* FOUND THE '/', NOW ES:DI IS POINTING AT */
;/* FIRST CHAR PAST THE '/'. LETS CHECK IF THE */
;/* NEXT 3 CHARS ARE "IRQ" (CASE-INSENSITIVE) */
;/***********************************************/
; CHECK FOR I or i
cmp byte ptr es:[di], 'I' ; IS IT 'I'?
je ParseCmdLine_CheckFor_R ; YES, CHECK NEXT CHAR
cmp byte ptr es:[di], 'i' ; IS IT 'i'?
je ParseCmdLine_CheckFor_R ; YES, CHECK NEXT CHAR
jmp short ParseCmdLine_Exit ; NO MATCH
ParseCmdLine_CheckFor_R:
; CHECK FOR R or r
inc di ; POINT TO NEXT CHAR
cmp byte ptr es:[di], 'R' ; IS IT 'R'?
je ParseCmdLine_CheckFor_Q ; YES, CHECK NEXT CHAR
cmp byte ptr es:[di], 'r' ; IS IT 'r'?
je ParseCmdLine_CheckFor_Q ; YES, CHECK NEXT CHAR
jmp short ParseCmdLine_Exit ; NO MATCH
ParseCmdLine_CheckFor_Q:
; CHECK FOR Q or q
inc di ; POINT TO NEXT CHAR
cmp byte ptr es:[di], 'Q' ; IS IT 'Q'?
je ParseCmdLine_Match ; YES, MATCH
cmp byte ptr es:[di], 'q' ; IS IT 'q'?
je ParseCmdLine_Match ; YES, MATCH
jmp short ParseCmdLine_Exit ; NO MATCH
ParseCmdLine_Match:
; FOUND "/IRQ" ON COMMAND LINE, DONT USE POLLING
mov di, si ; RESTORE DI
and [di].commonflags, NOT USEPOLLING ; RESET POLLING FLAG
ParseCmdLine_Exit:
pop es ; RESTORE ES
popa ; RESTORE REGISTERS
ret
EndProc ParseCmdLine
CSEG ENDS
END