; SCCSID = @(#)prthwint.asm     6.33 92/03/24
;/**********************************************************************
;/*                                                                    *
;/*                       IBM/Microsoft Confidential                   *
;/*                                                                    *
;/*                 Copyright (c) IBM Corporation  1987, 1990          *
;/*                 Copyright (c) Microsoft Corp.  1987, 1990          *
;/*                           All Rights Reserved                      *
;/*                                                                    *
;/**********************************************************************
 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
;       STARTPRT
;       PRTINT07
;       PRTPROCABIOSRC
;       PRT_TIMEOUT_1
;       PRT_TIMEOUT_2
;       PRT_TIMEOUT_3
;       PRT_TIMEOUT
;       STARTKSTIMER
;       STOPKSTIMER
;       KSTIMERMGR
;       PRT_KICKSTART
;       PRT_KICKABIOS
;       CLEANUP
;       PRTERP
;       GETSTATUS,HYBRID
;       CLEARARB,HYBRID
;       PRTINIT
;       prtdeterminehardware
;       RM_PRT_RegisterResources
;       GETABIOSPARMS
;       GETDEVPARMS
;       PARSECMDLINE
;***********************************************************************

        .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 abios.inc               ; ABIOS 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 prtdd2.inc              ; PRINTER DEVICE DRIVER INCLUDE FILE
        INCLUDE prtinit.inc             ; PRINTER DEVICE DRIVER INCLUDE FILE

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  flags2
        PUBLIC  deinstallflg
        PUBLIC  doserrors
        PUBLIC  reqblks
        PUBLIC  reqblks1                                                        ;@IBM J-PTR #JS02886(A)
        PUBLIC  timeoutval

                EVEN
prevact         dw      OFFSET perprtarea ; OFFSET INTO PPDA OF PREVIOUS IRQ7
prevks          dw      OFFSET perprtarea ; OFF INTO PPDA OF PRE LOST IRQ7 TIMER
timeoutval      dw      ?               ; TIME OUT FOR 1 SECOND (TICKS)
flags2          dw      0               ; BIT 0 - IRQ7 ABIOS PS/2 FIX
                                        ; 0 = ABIOS SUPPORTS THE IRQ7 FIX
                                        ; 1 = ABIOS DOESN'T SUPPORT IRQ7 FIX
                                        ; BIT 1 - FIRST TIME SETTING IRQ
                                        ; 0 = FIRST TIME SETTING IRQ - NOT SET
                                        ; 1 = FIRST TIME SETTING IRQ - SET

kstimerneeded   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
default         db      0               ; CALL DEFAULT INT HANDLER FLAG
                                        ; 001 - LPT1 HAS NO ACTIVE ABIOS RB'S
                                        ; 010 - LPT2 HAS NO ACTIVE ABIOS RB'S
                                        ; 100 - LPT3 HAS NO ACTIVE ABIOS RB'S
bustype         dw      0               ; BUS TYPE
                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

; Storage for ABIOS request blocks

MAXREQBLKS      EQU     3               ; one for each printer (LID)
reqblks         db      MAXREQBLKS * (SIZE requestblk) DUP (00H)
reqblks1        db      MAXREQBLKS * (SIZE requestblk) DUP (00H)                ;@IBM J-PTR #JS02886(A)

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      'print02.sys',0

DSEG    ENDS

SWAPSEG SEGMENT PUBLIC  'code'
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING

        EXTRN   PLPTCMD_Entry:FAR

;BUGBUG Make sure that interrupts are not disabled across a page boundary.
;BUGBUG Page manager cannot load next page, print request appears hung.

BREAK <INITAILIZE PRINTER>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  INITIALPRT                                       */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  Routine to initialize printer device.           */
;/*                                                                    */
;/* FUNCTION:   This routine will set up the ABIOS request block and   */
;/*             call the start entry point.  The status returned will  */
;/*             be moved into AH and returned to the caller.           */
;/*                                                                    */
;/* NOTES:                                                             */
;/*                                                                    */
;/* ENTRY POINT:                                                       */
;/*         LINKAGE:    EXTRN initialprt:NEAR OR FAR                   */
;/*                     call initialprt                                */
;/*                                                                    */
;/* INPUT:   DS:[DI] = perprtdata area                                 */
;/*          ES:[BX] = kernel request packet                           */
;/*                                                                    */
;/* EXIT-NORMAL:  DS:[SI] = offset of ABIOS request block              */
;/*               DS:[DI] = perprtdata area                            */
;/*               ES:[BX] = kernel request packet                      */
;/*                                                                    */
;/* EXIT-ERROR:   See EXIT-NORMAL above.                               */
;/*                                                                    */
;/* INTERNAL REFERENCES:  cleararb                                     */
;/*    ROUTINES:          getstatus                                    */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  ABIOSCall                       */
;/*    ROUTINES:                       ProcBlock                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure initialprt,HYBRID
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING

        mov     si,[di].abiosrb_off                     ; SI -> ADDR ABIOS RB
        CALLFAR cleararb                                ; CLEAR ABIOS RB
        mov     [si].function,RESETINIT                 ; RESET/INITIALIZE PRT

        mov     cx,BUSYRETRY                            ; RETRY COUNT
initialprt0:
        mov     [si].retcode,0FFFFH                     ; RETURN CODE - PENDING

        mov     ax,[si].logicalid                       ; GET LID
        mov     dh,START_EPT                            ; START ENTRY POINT
        mov     dl,DevHlp_ABIOSCall                     ; CALL ABIOS
        call    DWORD PTR [device_help]

        cmp     [si].retcode,STAGEONTIME                ; IF RETCODE = SOT
        je      initialprt1                             ; THEN CONTINUE
        loop    initialprt0                             ; ELSE RETCODE = DIU
        jmp     initialprt5                             ; EXIT

initialprt1:
        test    [di].commonflags1,BOOTINIT              ; IS THIS BOOT TIME?
        jz      initialprt3                             ; JUMP IF NOT
        mov     ax,INITLOOPCNT                          ; ELSE MUST SPIN

initialprt2:
        dec     ax
        jnz     initialprt2                             ; SPIN LOOP
        jmp     SHORT initialprt4

initialprt3:
        cli                                             ; DISABLE INTERRUPTS
        SaveReg <bx,di>                                 ; SAVE REGISTERS
        mov     ax,ds                                   ; SEG. OF ABIOS REQ BLK
        mov     bx,si                                   ; OFF. OF ABIOS REQ BLK
        mov     cx,[di].inittime_lo                     ; TIME LIMIT LOW VALUE
        mov     di,[di].inittime_hi                     ; 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
        sti
        jnc     initialprt3                             ; JMP IF UNUSUAL WAKEUP
        jnz     initialprt3                             ; JMP IF SLEEP INT

initialprt4:
        mov     ax,[si].logicalid                       ; GET LID
        mov     dh,INTERRUPT_EPT                        ; INTERRUPT ENTRY POINT
        mov     dl,DevHlp_ABIOSCall                     ; CALL ABIOS
        call    DWORD PTR [device_help]

        test    [di].commonflags1,BOOTINIT              ; IS THIS BOOT TIME?
        jnz     initialprt5                             ; JUMP IF IT IS TO EXIT

        ; ABIOS RETURNS TO US BEFORE BEING DONE WITH INITIALIZE REQUEST.
        ; MUST WAIT TIL NOT BUSY BEFORE RETURNING TO USER OR USER'S NEXT
        ; REQUEST WILL FAIL.

initialprt41:
        mov     cx,BUSYRETRY                            ; LOOP CONTROL VARIABLE
        mov     ah,[si].initstatus                      ; ABIOS STATUS
initialprt42:
        test    ah,NOTBUSY                              ; IF DEVICE NOT BUSY
        jnz     initialprt5                             ; THEN RETURN
        cli                                             ; DISABLE INTERRUPTS
        SaveReg <bx,cx,di>                              ; SAVE REGISTERS
        mov     ax,ds                                   ; SEG. OF ABIOS REQ BLK
        mov     bx,si                                   ; OFF. OF ABIOS REQ BLK
        mov     cx,[di].inittime_lo                     ; TIME LIMIT LOW VALUE
        mov     di,[di].inittime_hi                     ; 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,cx,bx>                           ; RESTORE REGISTERS
        sti
        push    si                                      ; SAVE SI REGISTER      ;@IBM J-PTR #JS02886(A)
        CALLFAR getstatus                               ; GET DEVICE STATUS
        pop     si                                      ; RESTORE SI REGISTER   ;@IBM J-PTR #JS02886(A)
        loop    initialprt42                            ; SEE IF NOT BUSY

initialprt5:
        ret
EndProc initialprt

BREAK <PRINT DEVICE DRIVER DEINSTALL ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTDEINSTALL                                     */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  Deinstall the printer device driver.            */
;/*                                                                    */
;/* FUNCTION:   This routine unhooks hardware interrupt 7, frees the   */
;/*             ABIOS LIDs and unhooks software interrupt 17H.         */
;/*                                                                    */
;/* 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:                                                       */
;/*         LINKAGE:  prtdeinstall:near                                */
;/*                   call prtdeinstall                                */
;/*                                                                    */
;/* 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.  */
;/*                                                                    */
;/* EXIT-ERROR:  see EXIT-NORMAL above.                                */
;/*                                                                    */
;/* EFFECTS:                                                           */
;/*                                                                    */
;/* INTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  RegisterPDD                     */
;/*    ROUTINES:                       UnSetIRQ                        */
;/*                                    FreeLIDEntry                    */
;/*                                    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
        test    deinstallflg,al                         ; IF PRN DEINSTALLED
        jnz     prtdein21                               ; DONT DO LPT1, SAME LID
        or      deinstallflg,al                         ; DEVICE IS DEINSTALLED
        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

        ; RESET HARDWARE INTERRUPT 7 HANDLER

        xor     bh,bh
        mov     bl,[di].intlevel                        ; IRQ INT NUMBER
        mov     dl,DevHlp_UnSetIRQ                      ; UNSET IRQ
        call    DWORD PTR [device_help]                 ; CALL DEVHLP

prtdein2:
        ; FREE LID ENTRY

        mov     si,[di].abiosrb_off                     ; SI -> ABIOS REQ BLK
        mov     ax,[si].logicalid                       ; GET LID
        mov     dl,DevHlp_FreeLIDEntry                  ; FREE LID ENTRY
        call    DWORD PTR [device_help]                 ; CALL DEVHLP
        mov     [si].logicalid,0                        ; CLEAR LID

        ; 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
prtdein21:
        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   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

        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

        test    [di].commonflags1,DMAAVAIL              ; DMA AVAIL FOR DEVICE
        jz      prtblk1                                 ; NO, DO PIO
        test    flags2,PDDABIOSPS2FIX                   ; UPDATED ABIOS AVAIL?
        jz      prtblk1                                 ; NO, DO PIO
        call    prt_transmit                            ; TRANSMIT BYTES
        jmp     SHORT prtblk6                           ; DMA ENTIRE BUFFER

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
        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:  Start ABIOS with a print block request.         */
;/*                                                                    */
;/* FUNCTION:   This routine fills in an ABIOS request block and calls */
;/*             startprt which will call ABIOS at its start entry      */
;/*             point. If no errors, this call returns to the file     */
;/*             system, otherwise it updates the Kernel request block. */
;/*                                                                    */
;/* 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                            */
;/*               DS:[SI] = ABIOS Request Block                        */
;/*               ES:[BX].Pktstatus = filled in.                       */
;/*               ES:[BX].IOCount = filled in.                         */
;/*               IOACTIVE FLAG SET TO OFF                             */
;/*                                                                    */
;/* EXIT-ERROR:   See exit normal above.                               */
;/*                                                                    */
;/* EFFECTS:                                                           */
;/*                                                                    */
;/* INTERNAL REFERENCES:  cleararb                                     */
;/*    ROUTINES:          startprt                                     */
;/*                       stopkstimer                                  */
;/*                       cleanup                                      */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  ProcBlock                       */
;/*    ROUTINES:                       TickCount                       */
;/*                                    ABIOSCall                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prt_transmit near
        ASSUME  CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        pvtimer 1                                       ; SUB FROM PFVW TIMER

        mov     si,[di].abiosrb_off                     ; DS:SI -> ADDR ABIOS RB
        call    cleararb                                ; CLEAR ABIOS RB
        mov     [si].function,PRTBLK                    ; PRINT A CHARACTER
        mov     cx,es:[bx].IOcount                      ; GET REQUESTED BUF SIZE
        mov     [di].initialcount,cx                    ; SAVE INITIAL SIZE
        mov     [di].printedcnt,0                       ; CLEAR COUNTER
        mov     [si].count,cx                           ; SET PRT REQ SIZE

        push    bx                                      ; SAVE REGISTER
        test    [di].commonflags1,DMAAVAIL              ; DMA AVAIL FOR DEVICE
        jz      prtxmit2                                ; NO, SKIP VIRTTOPHYS
        test    flags2,PDDABIOSPS2FIX                   ; UPDATED ABIOS AVAIL?
        jz      prtxmit2                                ; NO, TRY PIO MODE ONLY
        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].dataseg1,ax                        ; SAVE PHYS ADDR - HIGH
        mov     [si].dataoff1,bx                        ; SAVE PHYS ADDR - LOW
        or      [si].reqflags,ARBDEALLOC                ; DEALLOC ARB LEVEL
prtxmit2:
        mov     ax,[di].gdtprintbuf                     ; GET VIRT ADDR - SEL
        mov     [si].dataseg,ax                         ; SAVE VIRT ADDR - SEL
        mov     ax,_Printed                             ; GET VIRT ADDR - OFF
        mov     [si].dataoff,ax                         ; SAVE VIRT ADDR - OFF

        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]
        pop     bx

        call    startprt                                ; START THE ABIOS PRNT
        jnc     prtxmit3                                ; IF !ERROR, BLOCK

        test    [di].commonflags,PRTRESTART             ; RESTARTABLE ERROR
        jnz     prtxmit3                                ; YES
        jmp     SHORT prtxmit5                          ; NO, CANCEL REQUEST
prtxmit3:
        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      prtxmit4                                ; UNUSUAL WAKEUP
        jmp     prtxmit3                                ; RETEST DONE
prtxmit4:
        mov     [si].function,CANPRTBLK                 ; CANCEL PRINT REQ
        or      [si].reqflags,ARBDEALLOC                ; DEALLOC DMA ARB LEVEL
        mov     ax,[si].logicalid                       ; LOGICAL ID
        mov     dh,START_EPT                            ; START ENTRY POINT
        mov     dl,DevHlp_ABIOSCAll                     ; CALL ABIOS
        call    DWORD PTR [device_help]

        mov     ax,[si].countsent                       ; GET AMOUNT PRINTED
        add     [di].printedcnt,ax                      ; UPDATE TOTAL PRINTED

        call    stopkstimer                             ; STOP KICKSTART TIMER
        mov     es:[bx].PktStatus,CHARIOINT             ; RETURN STATUS
        call    cleanup                                 ; TERMINATE PRT REQUEST
prtxmit5:
        sti                                             ; ENABLE INTERRUPTS
        pvtimer                                         ; ADD TO PFVW TIMER/CTRS
        ret
EndProc prt_transmit

BREAK <COPY DATA FROM USER'S BUFFER INTO PERPRTDATA AREA>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  STARTPRT                                         */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  Start the ABIOS print request.                  */
;/*                                                                    */
;/* FUNCTION:   This routine calls ABIOS at its start entry point.  If */
;/*             ABIOS returns with staged on interrupt or complete,    */
;/*             this routine will return with NC.  If ABIOS returns    */
;/*             with an error, this routine will return with CY.       */
;/*             However, if the error is restartable, the PRTRESTART   */
;/*             flag will be on.                                       */
;/*                                                                    */
;/* NOTES:                                                             */
;/*       A race condition exists where an interrupt may come in before*/
;/*       we return from ABIOS and have an opportunity to block.  It   */
;/*       has been corrected by disabling interrupts.                  */
;/*                                                                    */
;/*       A lost interrupt problem exists on PS/2 hardware.  Startprt  */
;/*       attempts to start a timer to detect this problem when it     */
;/*       receives staged on interrupt from ABIOS.                     */
;/*                                                                    */
;/*       Caller is responsible for re-enabling interrupts.            */
;/*                                                                    */
;/* ENTRY POINT:                                                       */
;/*         LINKAGE:  startprt:near                                    */
;/*                   call startprt                                    */
;/*                                                                    */
;/* INPUT:  DS:[DI]   = perprtdata area                                */
;/*         DS:[SI]   = ABIOS request block                            */
;/*                                                                    */
;/* EXIT-NORMAL:  NC  = started ok                                     */
;/*                                                                    */
;/* EXIT-ERROR:   CY  = could not start request                        */
;/*               [di].commonflags = PRTRESTART if retryable error     */
;/*                                                                    */
;/* EFFECTS:                                                           */
;/*                                                                    */
;/* INTERNAL REFERENCES:  prtprocabiosrc                               */
;/*    ROUTINES:          startkstimer                                 */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  ABIOSCall                       */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure startprt near
        ASSUME  CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        mov     [si].retcode,0FFFFH                     ; RETURN CODE - PENDING
        mov     ax,[si].logicalid                       ; GET LID
        mov     dh,START_EPT                            ; START ENTRY POINT
        mov     dl,DevHlp_ABIOSCAll                     ; CALL ABIOS
        cli                                             ; DISABLE INTERRUPTS
        call    DWORD PTR [device_help]

        cmp     [si].retcode,STAGEONINT                 ; IF RETCODE != SOI
        jne     startprt1                               ; THEN SEE IF ERROR
        call    startkstimer                            ; START KICKSTART TIMER
startprt1:

        ; STARTPRT CANNOT RETURN COMPLETEDOK AS LONG AS INTERRUPTS ARE
        ; DISABLED

        call    prtprocabiosrc                          ; PROCESS ABIOS RET CODE
        ret
EndProc startprt

BREAK <IRQ7 INTERRUPT HANDLER>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTINT07                                         */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  Hardware Interrupt entry point.                 */
;/*                                                                    */
;/* FUNCTION:   This routine determines if the printer device driver   */
;/*             has any outstanding print requests, and if so calls    */
;/*             ABIOS to see if the request caused the interrupt.  If  */
;/*             it did not, the loop continues until all outstanding   */
;/*             print requests are tested.  If no outstanding requests */
;/*             caused the interrupt,this routine will call the default*/
;/*             interrupt handler for the devices which did not have   */
;/*             outstanding requests in order to reset any spurious    */
;/*             interrupting conditions.  If an outstanding request    */
;/*             caused the interrupt, this routine will process the    */
;/*             interrupt and return to the hardware interrupt manager.*/
;/*             If an error is returned while trying to print the next */
;/*             character, the print request will be cancelled.  If    */
;/*             infinite retry is on, the timeout timer will be reset  */
;/*             to interrupt every tick and try to restart the request.*/
;/*                                                                    */
;/* NOTES:                                                             */
;/*                                                                    */
;/* ENTRY POINT:                                                       */
;/*         LINKAGE:  prtint07:far                                     */
;/*                   call prtint07                                    */
;/*                                                                    */
;/* INPUT: DS = OUR DATA SEGMENT                                       */
;/*                                                                    */
;/* EXIT-NORMAL:  Clear CY flag if it is my interrupt.                 */
;/*               Set CY if not my interrupt.                          */
;/*                                                                    */
;/* EXIT-ERROR:  [di].commonflags = PRTRESTART                         */
;/*                                                                    */
;/* INTERNAL REFERENCES:  prtprocabiosrc                               */
;/*    ROUTINES:          startprt                                     */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  ABIOSCall                       */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtint07 far
        ASSUME  CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        mov     default,0                               ; CLEAR INT HANDLER FLAG
        mov     cx,MAXPRINTERS                          ; LOOP CONTROL CTR
        mov     di,prevact                              ; PREV ACTIVE DEVICE
        mov     ax,[di].nextppda                        ; GET NEXT DEVICE
        mov     prevact,ax                              ; SAVE FOR NEXT IRQ7

        ; 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.

ifdef SMP
        jmp prtint01            ; skip this for now, after the april beta
                                ; we will check _PSDInfo flags for adv
                                ; int mode bit
endif

        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      prtint01                                ; JMP IF NO PENDING IRQS
        inc     pendirq                                 ; ELSE INC PENDING IRQ
prtint01:
        sti                                             ; ENABLE INTERRUPTS

        ; DETERMINE IF ANY ACTIVE REQ BLKS PER PRT CAUSED HARDWARE INTERRUPT.
        ; CALL ABIOS WITH ALL RB's = SOI ELSE SAVE PRT# IN DEFAULT FLAG.
prtint1:
        mov     si,[di].abiosrb_off
        cmp     [si].retcode,STAGEONINT                 ; IF RB = WAITING ON INT
        je      prtint12                                ; THEN CALL ABIOS - INT

        ; DS:SI.retcode != SOI. SAVE PRT# FOR DEFAULT INT HANDLER.

        mov     dl,[di].deviceflag                      ; GET DEVICE FLAG
        or      default,dl                              ; SET MUST CALL FLAG ON
        jmp     SHORT prtint13

        ; DS:SI.retcode = SOI. CALL ABIOS TO SEE IF MY INT.
prtint12:
        mov     ax,[si].logicalid                       ; ELSE GET LOGICAL ID
        mov     dh,INTERRUPT_EPT                        ; INTERRUPT ENTRY POINT
        mov     dl,DevHlp_ABIOSCAll                     ; CALL ABIOS
        call    DWORD PTR [device_help]

        cmp     [si].retcode,NOTMYINT                   ; IF RB != NOTMYINT
        jne     prtint3                                 ; THEN PROCESS IT
        mov     [si].retcode,STAGEONINT                 ; RESET TO SOI

        ; RB DID NOT CAUSE HARDWARE INTERRUPT.  TRY NEXT RB PER PRT.
prtint13:
        mov     di,[di].nextppda                        ; GET ADDR NEXT DEV AREA
        loop    prtint1                                 ; DEC CX, LOOP TO TOP

        ; NO RB's CAUSED INT.  CALL DEFAULT INT HANDLER IN CASE OF SPURIOUS.
        mov     dl,1                                    ; START INDEX - LPT1
        mov     di,OFFSET perprtarea                    ; START OF PERPRTDATA
prtint2:
        test    default,dl                              ; INACTIVE RB?
        jz      prtint21                                ; NO
        test    deinstallflg,dl                         ; DEINSTALLED DEVICE?
        jnz     prtint21                                ; YES
        test    [di].commonflags1,PDDDIRACCESS          ; PDD HAS PORT ACCESS?
        jz      prtint21                                ; NO, IGNORE PORT

        mov     si,[di].abiosrb_off                     ; GET ABIOS REQUEST BLK
        mov     [si].function,DEFAULTINT                ; CALL DEFAULT INT HDLR
        mov     ax,[si].logicalid                       ; GET LOGICAL ID
        or      ax,ax                                   ; PHYS PORT INSTALLED
        jz      prtint21                                ; NO
        push    dx                                      ; YES - SAVE DX
        mov     dh,INTERRUPT_EPT                        ; INTERRUPT ENTRY POINT
        mov     dl,DevHlp_ABIOSCAll                     ; CALL ABIOS
        call    DWORD PTR [device_help]                 ; DEVICE HELP
        pop     dx                                      ; RESTORE DX
        mov     [si].function,PRTBLK                    ; RESET FUNCTION CODE

        ; SPURIOUS INTERRUPT FOUND.  ISSUE EOI AND RETURN AS OWNING INT.
        cmp     [si].retcode,COMPLETEDOK                ; SPURIOUS INT?
        jne     prtint21                                ; NO, TRY NEXT RB
        jmp     prtint8                                 ; YES, EOI / EXIT

        ; SPURIOUS INTERRUPT NOT FOUND.  TRY NEXT RB PER PRINTER.
prtint21:
        add     di,SIZE printer_database                ; NEXT DATABASE ENTRY
        sal     dl,1                                    ; TRY NEXT REQUEST BLK
        cmp     dl,04h                                  ; END OF RB's ?
        jbe     prtint2                                 ; NO

        ; NO PRINTERS HAD SPURIOUS INTERRUPT.  TELL INT MANAGER NOT MY INT.
        stc
        jmp     prtint9                                 ; ELSE RETURN NOT MY INT

        ; FOUND RB WHICH CAUSED HARDWARE INT.  TEST RETURN CODE FROM ABIOS.
prtint3:
        and     [di].commonflags,NOT MONERRPKTSENT      ; CLEAR PKT SENT FLAG
        cli                                             ; DISABLE INTERRUPTS
        mov     [di].kstimercnt,0                       ; RESET KS TIMER COUNT
        call    prtprocabiosrc                          ; PROCESS ABIOS RET CODE
        jnc     prtint8                                 ; IF !ERROR, EOI, EXIT

        test    [di].commonflags,PRTRESTART             ; ERROR, NEED TO START
        jz      prtint8                                 ; NO, EOI AND EXIT
        call    startprt                                ; START THE ABIOS PRINT
prtint8:
        cli                                             ; !NESTED INTS
        mov     [di].timeoutctr,0                       ; RESET TIMEOUT COUNTER
prtint85:

ifndef SMP                                              ; #81531 start
        mov     al,20h                                  ; NON SPECIFIC EOI
        out     20h,al                                  ; ISSUE EOI TO 8259
else
        mov     al,[di].intlevel                        ; IRQ
        mov     dl,DevHlp_EOI                           ; END OF INTERRUPT
        call    DWORD PTR [device_help]                 ; CALL DEVHLP TO BLOCK
endif                                                   ; #81531 end

        clc                                             ; TELL KERNEL MY INT
prtint9:
        ret
EndProc prtint07

BREAK <PRINTER DEVICE DRIVER PROCESS ABIOS RETURN CODE ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTPROCABIOSRC                                   */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  Printer device driver process ABIOS             */
;/*                    return code routine.                            */
;/*                                                                    */
;/* FUNCTION:   This routine processes an ABIOS request block.  This   */
;/*             routine will return NC if no error or CY if an error   */
;/*             occured.  If a restartable error occured the prtrestart*/
;/*             flag will be turned on.                                */
;/*                                                                    */
;/* NOTES:  This chart summarizes the ABIOS return codes and the       */
;/*         printer device drivers' action.                            */
;/*                                                                    */
;/*         RETURN         INFINITE                     RESTART        */
;/*         CODE           RETRY     ACTION         CY  FLAG           */
;/*         -----------    --------  ------         --  -------        */
;/*     (1) COMPLETE       OFF       EXIT           NC  NO             */
;/*         (no more data) ON        EXIT           NC  NO             */
;/*     (2) COMPLETE       OFF       RETRY TIL T.O. CY  YES            */
;/*         (more data)    ON        RETRY FOREVER  CY  YES            */
;/*     (3) STAGE ON INT   N/A       EXIT           NC  NO             */
;/*                                                                    */
;/*     (4) DEVICE IN USE  OFF       CANCEL         CY  NO             */
;/*                        ON        CANCEL         CY  NO             */
;/*     (5) PRT DEV BUSY   OFF       SMALL RETRY    CY  YES/NO         */
;/*                        ON        RETRY FOREVER  CY  YES/NO         */
;/*     (6) DEVICE ERROR   OFF       CANCEL         CY  NO             */
;/*                        ON        RETRY FOREVER  CY  YES            */
;/*                                                                    */
;/* (2) IRQ7 can occur and cancel DMA PRTBLK requests if the device    */
;/*     asserts a status line.  If glitch is short enough, it may      */
;/*     latch into the device status register but not the interface    */
;/*     status register.  ABIOS returns complete but count does not    */
;/*     equal countsent.                                               */
;/*                                                                    */
;/*         Prtprocabiosrc can be called after calling the start,      */
;/*         interrupt, or timeout ABIOS entry point.                   */
;/*                                                                    */
;/*         Generally, this routine will be called with interrupts     */
;/*         disabled to protect it from the printer timers.            */
;/*                                                                    */
;/* ENTRY POINT:                                                       */
;/*         LINKAGE:  prtprocabiosrc near                              */
;/*                   call prtprocabiosrc                              */
;/*                                                                    */
;/* INPUT:  DS = our data segment                                      */
;/*         DS:[DI] = perprtdata area                                  */
;/*         DS:[SI] = abios request block                              */
;/*                                                                    */
;/* EXIT-NORMAL: NC = CARRY FLAG NOT SET                               */
;/*              [di].printedcnt = updated                             */
;/*              [di].commonflags1 = NOT RETRYIFBUSY                   */
;/*              [di].retryctr = undefined                             */
;/*              [di].commonflags = NOT PRTRESTART                     */
;/*                                                                    */
;/* EXIT-ERROR:  CY = CARRY FLAG SET                                   */
;/*              [di].printedcnt = updated                             */
;/*              [di].commonflags1 = RETRYIFBUSY if PRTDEVBUSY         */
;/*              [di].retryctr = BUSYRETRYRU if PRTDEVBUSY             */
;/*              [di].commonflags = PRTRESTART if restartable error    */
;/*                            ABIOS RB also updated/ready to restart  */
;/*                                                                    */
;/* INTERNAL REFERENCES:  cleanup                                      */
;/*    ROUTINES:          stopkstimer                                  */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtprocabiosrc near
        ASSUME  CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING

        ; PROCESS ABIOS GOOD RETURN CODES

        cmp     [si].retcode,STAGEONINT                 ; IF RB != STAGE ON INT
        jne     prtparc2                                ; THEN CHECK OTHER RCS
        jmp     prtparc8                                ; ELSE EXIT, NO ERROR
prtparc2:

        call    stopkstimer                             ; STOP KICKSTART TIMER

        mov     ax,[si].countsent                       ; GET PRINTED COUNT
        add     [di].printedcnt,ax                      ; UPDATE TOTAL PRINTED

        cmp     [si].retcode,COMPLETEDOK                ; IF RB != COMPLETED OK
        jne     prtparc3                                ; THEN CONTINUE CHECKING

        test    [di].commonflags1,CANMONPKT             ; CANCEL THIS REQUEST?
        jnz     prtparc6                                ; YES

        cmp     [si].count,ax                           ; IF COUNT != COUNTSENT
        jne     prtparc5                                ; THEN ERROR, RESTART

        call    cleanup                                 ; YES, CLEANUP
        jmp     SHORT prtparc8                          ; EXIT, NO ERROR

        ; PROCESS ABIOS ERROR RETURN CODES

prtparc3:
        cmp     [si].retcode,DEVICEINUSE                ; IF RETCODE = DEVINUSE
        je      prtparc6                                ; THEN UPDATE, CANCEL

        test    [di].commonflags,INFINRETRY             ; IF INF RETRY&DE OR PDB
        jnz     prtparc5                                ; THEN UPDATE, RESTART

        cmp     [si].retcode,PRTDEVBUSY                 ; IF DEVICE BUSY
        je      prtparc4                                ; THEN UPDATE, RESTART

        ; SOME DEVICES WILL ASSERT ACK (DMA) TO GENERATE AN INTERRUPT AND STOP
        ; THE TRANSMISSION (DMA) INSTEAD OF JUST ASSERTING BUSY (PIO).
        ; ABIOS WILL RETURN DEVICE ERROR, IF COUNT DOES NOT EQUAL COUNT SENT.

        cmp     [si].retcode,DEVICEERROR                ; IF NOT DEVICE ERROR
        jne     prtparc31                               ; THEN MUST BE NEW RC

        cmp     [si].count,ax                           ; IF COUNT != COUNTSENT
        jne     prtparc5                                ; THEN ERROR, RESTART

        ; (NEW) ABIOS RETURN CODES

prtparc31:
        jmp     SHORT prtparc6                          ; ELSE UPDATE, CANCEL

        ; PRINTER DEVICE BUSY, SETUP FOR SMALL RETRY

prtparc4:
        test    [di].commonflags1,RETRYIFBUSY           ; IF BUSY RETRY CNT SET
        jnz     prtparc41                               ; THEN DON'T RESET
        or      [di].commonflags1,RETRYIFBUSY           ; SET RETRY FLAG
        push    [di].timeoutmax                         ; GET TIMEOUT MAX
        pop     [di].retryctr                           ; SET RETRY COUNTER
        jmp     SHORT prtparc5

prtparc41:
        dec     [di].retryctr                           ; DECREMENT UNTIL ZERO
        jz      prtparc6                                ; IF ZERO, CANCEL

        ; UPDATE BUFFER POINTER(S) AND COUNT(S) IN ABIOS RB, AND TURN ON
        ; RESTART FLAG

prtparc5:
        add     [si].dataoff,ax                         ; UPDATE OFFSET IN BUF
        test    [di].commonflags1,DMAAVAIL              ; DMA AVAIL FOR DEV?
        jz      prtparc51                               ; NO
        test    flags2,PDDABIOSPS2FIX                   ; UPDATED ABIOS AVAIL?
        jz      prtparc51                               ; NO, DO PIO MODE ONLY
        add     [si].dataoff1,ax                        ; UPDATE DMA BUF OFF
        adc     [si].dataseg1,0                         ; HANDLE OVERFLOW
prtparc51:
        sub     [si].count,ax                           ; NEW COUNT TO PRINT
        mov     [si].countsent,0                        ; CLEAR COUNTSENT
        or      [di].commonflags,PRTRESTART             ; SET RESTART FLAG
        jmp     SHORT prtparc7                          ; EXIT

        ; TURN OFF RESTART AND RETRY IF BUSY FLAG, CLEANUP AND RETURN

prtparc6:
        call    cleanup                                 ; CLEANUP
prtparc7:
        stc                                             ; ERROR
        jmp     SHORT prtparc9
prtparc8:
        and     [di].commonflags,NOT PRTRESTART         ; RESET RESTART FLAG
        and     [di].commonflags1,NOT RETRYIFBUSY       ; TURN OFF RETRY FLAG
        clc                                             ; NO ERROR
prtparc9:
        ret
EndProc prtprocabiosrc

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:  Call ABIOS at the timeout entry point to cancel */
;/*                    the 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.  If infinite retry is  */
;/*            on and a timeout occured, the printer device driver will*/
;/*            continue to wait for the hardware interrupt.  If        */
;/*            infinite retry is off and a timeout occured, the ABIOS  */
;/*            request will be canceled and the cleanup routine will be*/
;/*            called to cancel the kernel write request.              */
;/*                                                                    */
;/* NOTES:  If a monitor is registered, an error packet will be sent   */
;/*         one time to allow the monitor to inform the user of the    */
;/*         error.                                                     */
;/*                                                                    */
;/* ENTRY POINT:  prt_timeout                                          */
;/*    LINKAGE:  CALL NEAR                                             */
;/*                   call prt_timeout                                 */
;/*                                                                    */
;/* INPUT:  DI = offset of device into perprtarea.                     */
;/*         [DI].commonflags = [NOT] PRTRESTART                        */
;/*         [DI].commonflags = [NOT] INFINRETRY                        */
;/*         [DI].timeoutmax = maximum wait time in seconds before      */
;/*                           canceling the print request.             */
;/*         [DI].timeoutctr = counter maintained to reach timeoutmax   */
;/*                                                                    */
;/* EXIT-NORMAL:  timeoutctr = incremented by 1, If = MAX, reset to 0  */
;/*         SI = Offset to appropriate ABIOS PRINTBLOCK request block  */
;/*                                                                    */
;/* EXIT-ERROR:  See EXIT-NORMAL above.                                */
;/*                                                                    */
;/* INTERNAL REFERENCES:  cleanup                                      */
;/*    ROUTINES:          prterp                                       */
;/*                       sendmonerpkt                                 */
;/*                       startprt                                     */
;/*                       stopkstimer                                  */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP - ABIOSCall                      */
;/*    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_timeout8                            ; AND EXIT

prt_timeout_interrupts:
        mov     si,[di].abiosrb_off                     ; ACTIVE ABIOS REQ BLOCK

        test    [di].commonflags1,CANMONPKT             ; CANCEL MON PRT REQ?
        jnz     prt_timeout5                            ; YES

        inc     [di].timeoutctr                         ; INC TIMEOUT COUNTER
        mov     ax,[di].timeoutmax                      ; GET TIMEOUT LIMIT
        cmp     [di].timeoutctr,ax                      ; IF CTR >= LIMIT
        jae     prt_timeout1                            ; THEN PERFORM TIMEOUT
        jmp     prt_timeout7                            ; ELSE EXIT

prt_timeout1:

        ; TIMEOUT OCCURED

        test    [di].commonflags,MONPRINTING            ; ERROR ON MON REQ?
        jz      prt_timeout2                            ; NO
        test    [di].commonflags,MONERRPKTSENT          ; ERR PKT ALREADY SENT
        jnz     prt_timeout2                            ; YES
        SaveReg <ax,si>                                 ; SAVE REGISTERS
        call    prterp                                  ; GET ERROR CODE
        call    sendmonerpkt                            ; SEND MON ERROR PKT
        RestoreReg <si,ax>                              ; RESTORE REGISTERS

prt_timeout2:
        mov     [di].timeoutctr,0                       ; RESET TIMEOUT CTR

        ; IF RESTART FLAG ON, ERROR RETURNED FROM ABIOS, REQUEST BLOCK
        ; CANCELLED, MUST CALL ABIOS AT START ENTRY POINT

        cli
        test    [di].commonflags,PRTRESTART             ; ABIOS REQ CANCELED?
        jnz     prt_timeout3                            ; YES, RESTART IT NOW

        ; ABIOS REQUEST BLOCK RETURNED STAGE ON INTERRUPT, PDD WAITING FOR INT.
        ; HARDWARE INTERRUPT HAS NOT HAPPENED, COULD BE LONG BUSY FROM
        ; LASER OR POSTSCRIPT PRINTERS, OR OUT OF PAPER FROM DOT MATRIX

        test    [di].commonflags,INFINRETRY             ; IF INFINITE RETRY
        jnz     prt_timeout8                            ; THEN WAIT LONGER
        jmp     SHORT prt_timeout5                      ; ELSE CANCEL REQUEST

        ; RESTART THE ABIOS PRINT REQUEST

prt_timeout3:
        call    startprt                                ; START THE ABIOS PRINT
        jmp     SHORT prt_timeout8                      ; EXIT

        ; CANCEL ACTIVE ABIOS PRINT REQUEST

prt_timeout5:
        or      [si].reqflags,ARBDEALLOC                ; DEALLOC ARB LEVEL
        mov     ax,[si].logicalid                       ; LOGICAL ID
        mov     dh,TIMEOUT_EPT                          ; TIMEOUT ENTRY POINT
        mov     dl,DevHlp_ABIOSCAll                     ; CALL ABIOS
        call    DWORD PTR [device_help]

; THE DEVICE DID NOT INTERRUPT WITHIN THE TIMEOUT PERIOD.  THE DEVICE MAY
; OR MAY NOT HAVE RECEIVED THE LAST CHARACTER SENT.  THE PDD WILL ASSUME THE
; BYTE WAS RECEIVED.  SOME PRINTERS WILL NOT PRINT THE CHARACTER.  IF THE
; INC INSTRUCTION IS REMOVED, SOME PRINTERS WILL PRINT THE CHARACTER TWICE.

;       inc     [di].printedcnt                         ; ASSUME CHAR RECEIVED
        mov     ax,[si].countsent                       ; GET PRINTED COUNT
        add     [di].printedcnt,ax                      ; UPDATE TOTAL PRINTED

        call    stopkstimer                             ; STOP KICKSTART TIMER

        ; CANCEL THE KERNEL PRINT REQUEST

        sti                                             ; ENABLE INTERRUPTS
        call    cleanup                                 ; CLEANUP
        jmp     SHORT prt_timeout8                      ; EXIT

        ; NO TIMEOUT, MAYBE NEEDS RESTART FROM HARDWARE INTERRUPT HANDLER

prt_timeout7:
        cli                                             ; DISABLE INTERRUPTS
        test    [di].commonflags,PRTRESTART             ; FAIL TO START AT INT?
        jnz     prt_timeout3                            ; YES, RESTART NOW
prt_timeout8:
        sti                                             ; ENABLE INTERRUPTS
        ret
EndProc prt_timeout

BREAK <START THE KICKSTART TIMER>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  STARTKSTIMER                                     */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  Printer Device Driver Start KickStart Timer     */
;/*                    Routine.                                        */
;/*                                                                    */
;/* FUNCTION:  The function of this subroutine is to start a timer     */
;/*            manager to get invoked after a timer tick.  If the      */
;/*            timer manager is already started, this routine will     */
;/*            not attempt to start it again.                          */
;/*                                                                    */
;/* NOTE: The kickstart timer is being used to detect a hardware       */
;/*       problem on PS/2 parallel ports.  If two parallel ports are   */
;/*       transmitting simultaneously, there is a window where a       */
;/*       hardware interrupt can be lost.  If the device status        */
;/*       register is not in error and the device is not busy, the     */
;/*       printer device driver will call ABIOS to transmit the next   */
;/*       character.                                                   */
;/*                                                                    */
;/*       Startkstimer should execute with interrupts disabled.        */
;/*                                                                    */
;/* ENTRY POINT:  startkstimer:near                                    */
;/*    LINKAGE :  call startkstimer                                    */
;/*                                                                    */
;/* INPUT:  ES = Virtual segment of kernel request block               */
;/*         BX = Virtual offset of kernel request block                */
;/*         DI = offset to appropriate perprtdata area                 */
;/*         SI = offset to PRTBLK ABIOS request block                  */
;/*         [DI].deviceflag = 001, 010, or 100 for LPT1, LPT2 or LPT3  */
;/*                                                                    */
;/* EXIT-NORMAL: kstimerneeded=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].kstimercnt = 0                                   */
;/*                                                                    */
;/* EXIT-ERROR :  See EXIT-NORMAL above.                               */
;/*                                                                    */
;/* INTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  SetTimer                        */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure startkstimer near
        ASSUME  CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        test    [si].blkstatus,DMAREQ                   ; IF DMA REQUEST
        jnz     startkstimer2                           ; DON'T START KICKSTART
        test    kstimerneeded,TIMERMASK                 ; IF TIMERMGR PREV REG
        jnz     startkstimer1                           ; THEN DON'T REREGISTER

        mov     ax,OFFSET kstimermgr                    ; OFFSET PRT TIMER MGR
        mov     dl,DevHlp_SetTimer                      ; SET TIMER FUNCTION
        call    DWORD PTR [device_help]                 ; CALL DEVHLP
startkstimer1:
        mov     [di].kstimercnt,0                       ; ZERO TIMER COUNTER
        mov     al,[di].deviceflag                      ; GET DEVICE FLAG
        or      kstimerneeded,al                        ; DEVICE RUNS BY TIMER
startkstimer2:
        ret
EndProc startkstimer

BREAK <STOP THE KICKSTART TIMER>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  STOPKSTIMER                                      */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  Printer Device Driver Stop KickStart Timer      */
;/*                    Routine.                                        */
;/*                                                                    */
;/* FUNCTION:  The function of this subroutine is to stop the kick-    */
;/*            start timer manager.  If the timer manager is needed    */
;/*            by another device this will turn off only the requesting*/
;/*            device and not reset the timer manager.                 */
;/*                                                                    */
;/* NOTE: Startkstimer should execute with interrupts disabled.        */
;/*                                                                    */
;/* ENTRY POINT:  stopkstimer:near                                     */
;/*    LINKAGE :  call stopkstimer                                     */
;/*                                                                    */
;/* INPUT:  ES = Virtual segment of kernel request block               */
;/*         BX = Virtual offset of kernel request block                */
;/*         DI = offset to appropriate perprtdata area                 */
;/*         SI = offset to PRTBLK ABIOS request block                  */
;/*         [DI].deviceflag = 001, 010, or 100 for LPT1, LPT2 or LPT3  */
;/*                                                                    */
;/* EXIT-NORMAL: kstimerneeded=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 stopkstimer,HYBRID
        ASSUME  CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        test    [si].blkstatus,DMAREQ                   ; IF DMA REQUEST
        jnz     stopkstimer1                            ; KICKSTART NOT STARTED
        mov     al,[di].deviceflag                      ; GET DEVICE FLAG
        xor     al,0ffh                                 ; GET REVERSE BITMASK
        and     kstimerneeded,al                        ; SET FLAG OFF

        test    kstimerneeded,TIMERMASK                 ; IF KSTIMERMGR NEEDED
        jnz     stopkstimer1                            ; THEN DON'T DEREGISTER

        mov     ax,OFFSET kstimermgr                    ; ELSE DEREGISTER TIMER
        mov     dl,DevHlp_ResetTimer                    ; TURN OFF TIMER
        call    DWORD PTR [device_help]                 ; CALL TIMER SERVICES

stopkstimer1:
        ret
EndProc stopkstimer

BREAK <PRINTER DEVICE DRIVER KICKSTART TIMER MANAGER>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* MODULE NAME:  KSTIMERMGR                                           */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  Printer device driver kick start timer manager. */
;/*                                                                    */
;/* FUNCTION:  The function of this module is to call prt_kickstart    */
;/*            when a 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: KSTIMERMGR                                            */
;/*    LINKAGE : CALL FAR                                              */
;/*                                                                    */
;/* INPUT:  DS = our data segment                                      */
;/*         numofprts   = number of parallel ports installed.          */
;/*         kstimerneeded=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].kstimercnt = number of timer interrupts waiting       */
;/*                                                                    */
;/* EXIT-NORMAL:  All registers are restored.                          */
;/*               [di].kstimercnt = 0                                  */
;/*                                                                    */
;/* EXIT-ERROR:  See EXIT-NORMAL above.                                */
;/*                                                                    */
;/* INTERNAL REFERENCES:  prt_kickstart                                */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure kstimermgr far
        ASSUME  CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        pusha                                           ; SAVE REGESTERS
        push    es                                      ; SAVE EXTRA SEGMENT
        test    kstimerneeded,TIMERMASK                 ; IF TIMER NOT REQUESTED
        jz      kstimermgr3                             ; EXIT

        xor     ch,ch                                   ; MAKE CH 0
        mov     cl,numofprts                            ; # OF PARALLEL PORTS
        mov     di,prevks                               ; PREV KICKSTART DEV
        mov     dx,[di].nextppda                        ; GET NEXT DEVICE
        mov     prevks,dx                               ; SAVE FOR NEXT TICK
kstimermgr1:
        cli                                             ; DISABLE INTERRUPTS
        mov     al,[di].deviceflag                      ; GET DEVICE FLAG
        test    kstimerneeded,al                        ; IF DEV !NEEDS T. TICKS
        jz      kstimermgr2                             ; THEN TRY NEXT DEVICE

        inc     [di].kstimercnt                         ; DX = TIMER COUNT
        mov     dx,[di].kstimercnt                      ; INC CTR FOR LOST IRQ7
        cmp     dx,2                                    ; IF TIMER IS < WAITTIME
        jb      kstimermgr2                             ; THEN GET NEXT REQUEST

        push    cx                                      ; SAVE LOOP CONTROL
        test    flags2,PDDABIOSPS2FIX                   ; UPDATED ABIOS AVAIL?
        jz      kstimermgr11                            ; NO, NO NEW INTERFACE

        call    prt_kickabios                           ; YES, USE NEW INTERFACE
        jmp     SHORT kstimermgr12
kstimermgr11:
        call    prt_kickstart                           ; GO DIRECT TO HARDWARE

kstimermgr12:
        pop     cx                                      ; RESTORE LOOP CONTROL
        mov     [di].kstimercnt,0                       ; RESET RUNNING COUNT

kstimermgr2:
        sti                                             ; ENABLE INTERRUPTS
        mov     di,[di].nextppda                        ; DI -> NEXT DEVICE
        loop    kstimermgr1                             ; TRY NEXT DEVICE
kstimermgr3:
        pop     es                                      ; RESTORE EXTRA SEGMENT
        popa                                            ; RESTORE REGESTERS
        ret
EndProc kstimermgr

BREAK <PRINTER DEVICE DRIVER KICKSTART ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* MODULE NAME:  PRT_KICKSTART                                        */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  Printer device driver kick start routine.       */
;/*                                                                    */
;/* FUNCTION:  The function of this module is check the status of the  */
;/*            device status register.  If the status is in error then */
;/*            allow the normal timeout to occur.  If the status is NOT*/
;/*            in error and the device is NOT busy, then the hardware  */
;/*            interrupt was lost and we need to force send the next   */
;/*            character even though a hardware interrupt did not      */
;/*            occur.                                                  */
;/*                                                                    */
;/*            All PS/2 hardware to date (including model 90 and 95)   */
;/*            contain the hardware bug.  There is a window where a    */
;/*            hardware interrupt (IRQ7) can be lost even though the   */
;/*            parallel attached device issued the interrupt via the   */
;/*            acknowledgement signal.  This routine is designed to    */
;/*            detect and correct the lost interrupt.                  */
;/*                                                                    */
;/* NOTES:  The timer will only expire and this routine will only be   */
;/*         called if IRQ7 does not occur.  DOS and this fix rely on   */
;/*         the BUSY signal to indicate whether the device can accept  */
;/*         another character.                                         */
;/*                                                                    */
;/* ENTRY POINT: PRT_KICKSTART                                         */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:  DS = our data segment                                      */
;/*         DI = perprtdata area                                       */
;/*                                                                    */
;/* EXIT-NORMAL:  DS:[SI] = ABIOS request block                        */
;/*                                                                    */
;/* EXIT-ERROR:  See EXIT-NORMAL above.                                */
;/*                                                                    */
;/* INTERNAL REFERENCES:  prtprocabiosrc                               */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP - ABIOSCall                      */
;/*    ROUTINES:                      - EOI                            */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prt_kickstart near
        ASSUME  CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        mov     si,[di].abiosrb_off                     ; GET ABIOS RB

        test    [di].commonflags,PRTRESTART             ; REQ IN ERROR?
        jz      prt_ks1                                 ; NO
        jmp     prt_ks2                                 ; YES, LET TIMEOUT START

        ; ABIOS NOW ALLOWS DYNAMIC STATUS RETURN AND WILL NOT RETURN
        ; DEVICE IN USE.

prt_ks1:
        mov     dx,[di].deviceaddr                      ; GET DEVICE ADDRESS
        inc     dx                                      ; POINT TO STATUS PORT
        mov     cx,0ah                                  ; LOOP CONTROL

        ; MODEL 80 - 20 MHZ PROBLEM, INT DOESN'T CLEAR, MUST REREAD STATUS
prt_ks11:
        in      al,dx                                   ; GET STATUS BYTE
        mov     ah,al                                   ; MOV STATUS INTO AH
        and     ah,0FCh                                 ; TURN OFF UNUSED BITS
        xor     ah,REVERSEBITS                          ; FLIP A COUPLE OF BITS
        cmp     ah,NORMALSTAT OR NOTINTPENDING          ; IF NORMAL STATUS
        je      prt_ks13                                ; THEN FORCE CHAR
        cmp     ah,NORMALSTAT                           ; IF !NORM W/INT PENDING
        jne     prt_ks2                                 ; THEN CONTINUE CHECKING
prt_ks111:
        in      al,dx                                   ; GET STATUS BYTE
        mov     ah,al                                   ; MOV STATUS INTO AH
        and     ah,0FCh                                 ; TURN OFF UNUSED BITS
        xor     ah,REVERSEBITS                          ; FLIP A COUPLE OF BITS
        test    ah,NOTINTPENDING                        ; IF !INT PENDING
        jnz     prt_ks12                                ; THEN FORCE CHAR
        loop    prt_ks111                               ; MAKE SURE INT CLEARS
prt_ks12:
        mov     al,[di].intlevel                        ; INTERRUPT NUMBER
        mov     dl,DevHlp_EOI                           ; RESET INT AT 8259
        call    DWORD PTR [device_help]                 ; CALL INT SERVICES
prt_ks13:
        inc     [si].countsent                          ; ASSUME IRQ OCCURED
        mov     ax,[si].countsent                       ; GET PRINTED COUNT
        cmp     ax,[si].count                           ; IF COUNTSENT < COUNT
        jb      forceitout                              ; THEN FORCE CHAR

        ; THE LAST CHARACTER IN BUFFER CAUSED LOST INTERRUPT, JUST READ STATUS
        ; WHICH CLEARED INTERRUPT AT PORT, INCREMENTED COUNT TO EQUAL TOTAL
        ; OF THIS REQUEST, MUST NOW CANCEL ABIOS PRINT REQUEST TO GET ABIOS
        ; IN SYNC AND READY TO START NEXT BUFFER.

        mov     [si].function,CANPRTBLK                 ; END OF BUF, CANCEL REQ
        mov     ax,[si].logicalid                       ; GET LOGICAL ID
        mov     dh,START_EPT                            ; START ENTRY POINT
        mov     dl,DevHlp_ABIOSCAll                     ; CALL ABIOS
        call    DWORD PTR [device_help]
        mov     [si].function,PRTBLK                    ; SET BACK TO PRT BLOCK

        ; CANCEL PRINT BLOCK CAN ONLY RETURN A GOOD RETURN CODE.  THE PRINT
        ; BLOCK REQUEST IS DONE, THE DEVICE DRIVER NEEDS TO BE CLEANED UP AND
        ; THE REQUEST RETURNED TO THE APPLICATION.

        call    prtprocabiosrc
        jmp     prt_ks2

forceitout:
        mov     bx,[si].dataoff                         ; GET OFFSET OF BUFFER
        add     bx,[si].countsent                       ; ADD INDEX
        push    ds                                      ; SAVE DATA SEGMENT
        mov     ds,[di].gdtprintbuf                     ; GET GDT TO USER BUF
        mov     al,BYTE PTR [bx]                        ; GET NEXT BYTE FROM BUF
        pop     ds                                      ; RESTORE DATA SEGMENT
        dec     dx                                      ; POINT TO DATA PORT
        out     dx,al                                   ; SEND CHAR TO DATA PORT
        DevIODelay <ax>                                 ; I/O DELAY - IO SETTLE
        DevIODelay <ax>                                 ; I/O DELAY - IO SETTLE
        add     dx,2                                    ; POINT TO CONTROL PORT
        mov     al,STROBELOW                            ; SET THE STROBE LOW
        out     dx,al                                   ; SEND NEW CONTROL BYTE
        DevIODelay <ax>                                 ; I/O DELAY - STR WIDTH
        DevIODelay <ax>                                 ; I/O DELAY - STR WIDTH
        mov     al,STROBEHIGH                           ; SET THE STROBE HIGH
        out     dx,al                                   ; SEND NEW CONTROL BYTE
prt_ks2:
        ret
EndProc prt_kickstart

BREAK <PRINTER DEVICE DRIVER KICKABIOS ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* MODULE NAME:  PRT_KICKABIOS                                        */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  Printer device driver kick ABIOS routine.       */
;/*                                                                    */
;/* FUNCTION:  The function of this module is check the status of the  */
;/*            device status register.  If the status is in error then */
;/*            allow the normal timeout to occur.  If the status is NOT*/
;/*            in error and the device is NOT busy, then the hardware  */
;/*            interrupt was lost and we need to call ABIOS to send    */
;/*            the next character even though a hardware interrupt did */
;/*            not occur.                                              */
;/*                                                                    */
;/*            All PS/2 hardware to date (including model 90 and 95)   */
;/*            contain the hardware bug.  There is a window where a    */
;/*            hardware interrupt (IRQ7) can be lost even though the   */
;/*            parallel attached device issued the interrupt via the   */
;/*            acknowledgement signal.  This routine is designed to    */
;/*            detect and correct the lost interrupt.                  */
;/*                                                                    */
;/* NOTES:  The timer will only expire and this routine will only be   */
;/*         called if IRQ7 does not occur.  The ABIOS return status    */
;/*         function will now work while other requests are in         */
;/*         progress (*NEW*).  DOS and this fix rely on the BUSY signal*/
;/*         to indicate whether the device can accept another character*/
;/*                                                                    */
;/* ENTRY POINT: PRT_KICKSTART                                         */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:  DS = our data segment                                      */
;/*         DI = perprtdata area                                       */
;/*                                                                    */
;/* EXIT-NORMAL:  DS:[SI] = ABIOS request block                        */
;/*                                                                    */
;/* EXIT-ERROR:  See EXIT-NORMAL above.                                */
;/*                                                                    */
;/* INTERNAL REFERENCES:  prtprocabiosrc                               */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP - ABIOSCall                      */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prt_kickabios near
        ASSUME  CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        mov     si,[di].abiosrb_off                     ; GET ABIOS RB

        test    [di].commonflags,PRTRESTART             ; REQ IN ERROR?
        jnz     prt_ksab2                               ; YES, LET TIMEOUT START

        ; ABIOS NOW ALLOWS DYNAMIC STATUS RETURN AND WILL NOT RETURN
        ; DEVICE IN USE.

prt_ksab0:
        mov     [si].function,RETDYNSTAT                ; RETURN PRINTER STATUS
        mov     ax,[si].logicalid                       ; ELSE GET LOGICAL ID
        mov     dh,START_EPT                            ; START ENTRY POINT
        mov     dl,DevHlp_ABIOSCAll                     ; CALL ABIOS
        call    DWORD PTR [device_help]

        mov     [si].function,PRTBLK                    ; SET BACK TO PRT BLOCK
        mov     [si].retcode,STAGEONINT                 ; SET BACK TO SOI

        mov     ah,[si].blkstatus
        cmp     ah,NORMALSTAT OR NOTINTPENDING          ; IF NOT NORMAL STATUS
        jne     prt_ksab2                               ; THEN EXIT

prt_ksab1:
        mov     [si].function,RESUMEPRTBLK              ; SET TO RESUME PRT BLK
        mov     ax,[si].logicalid                       ; GET LOGICAL ID
        mov     dh,START_EPT                            ; INTERRUPT ENTRY POINT
        mov     dl,DevHlp_ABIOSCAll                     ; CALL ABIOS
        call    DWORD PTR [device_help]

        mov     [si].function,PRTBLK                    ; SET BACK TO PRT BLOCK
        call    prtprocabiosrc                          ; PROCESS ABIOS RET CODE
prt_ksab2:
        ret
EndProc prt_kickabios

BREAK <CLEANUP ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  CLEANUP ROUTINE                                  */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  Fill in the Kernel Request block and PROCRUN    */
;/*                    the blocked strategy request.                   */
;/*                                                                    */
;/* FUNCTION:   This routine fills in an Output Kernel Request Block   */
;/*             with the printed count and the return status and       */
;/*             runs the the previously blocked strategy thread.       */
;/*                                                                    */
;/* ENTRY POINT:                                                       */
;/*         LINKAGE:  cleanup:near                                     */
;/*                   call cleanup                                     */
;/*                                                                    */
;/* INPUT:  DI = Offset to appropriate PERPRTDATA area                 */
;/*         SI = Offset to appropriate ABIOS PRINTBLOCK request block  */
;/*                                                                    */
;/* EXIT-NORMAL:  ES:[BX].PktStatus = updated                          */
;/*               ES:[BX].IOCount   = updated                          */
;/*               [di].commonflags1 = NOT RETRYIFBUSY                  */
;/*               [di].commonflags  = NOT PRTRESTART                   */
;/*                                                                    */
;/* EXIT-ERROR:  see EXIT-NORMAL above.                                */
;/*                                                                    */
;/* INTERNAL REFERENCES:  prterp                                       */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  ProcRun                         */
;/*    ROUTINES:                       ResetTimer                      */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure cleanup near
        ASSUME  CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        and     [di].commonflags1,NOT RETRYIFBUSY       ; TURN OFF RETRY FLAG
        and     [di].commonflags,NOT PRTRESTART         ; RESET RESTART FLAG

        mov     ax,[di].timeout_off                     ; TIMEOUT ENTRY POINT
        mov     dl,DevHlp_ResetTimer                    ; TURN TIMER OFF
        call    DWORD PTR [device_help]                 ; CALL TIMER SERVICES

        sti                                             ; ENABLE INTERRUPTS
        mov     es,[di].dosrqseg                        ; ASSUME DOS REQUEST BLK
        mov     bx,[di].dosoffset                       ; ASSUME DOS REQUEST BLK
        test    [di].commonflags,MONPRINTING            ; IF !MONITOR REQUEST
        jz      cleanup1                                ; THEN ASSUMED CORRECTLY
        mov     es,[di].monseg                          ; MON REQUEST BLOCK
        mov     bx,[di].monoffset                       ; MON REQUEST BLOCK
cleanup1:
        cmp     es:[bx].PktCmd,CMDOUTPUT                ; IF COMMAND = WRITE
        je      cleanup11                               ; THEN RETURN PRT COUNT
        cmp     es:[bx].PktCmd,CMDOUTPUTV               ; IF COMMAND = WRITE/V
        jne     cleanup12                               ; THEN RETURN PRT COUNT

        ; UPDATE IOCOUNT IN OUTPUT KERNEL REQUEST PACKET

cleanup11:
        mov     ax,[di].printedcnt                      ; CHARACTERS PRINTED
        mov     es:[bx].IOcount,ax                      ; PUT COUNT IN REQ BLK
        cmp     es:[bx].PktStatus,CHARIOINT             ; CTRL C PRESSED BY USER
        je      cleanup22                               ; YES EXIT

        ; UPDATE PKTSTATUS IN OUTPUT KERNEL REQUEST PACKET

        cmp     [di].initialcount,ax                    ; COMPARE COUNTS
        jne     cleanup12                               ; JUMP IF NOT DONE
        mov     ax,CANNOERROR                           ; SET NO ERROR
        jmp     SHORT cleanup13                         ; GET PKTSTATUS

cleanup12:
        call    prterp                                  ; DETERMINE ERROR
        xor     ah,ah                                   ; ZERO OUT AH
        mov     al,[di].cancelflags                     ; GET ERROR INDEX
        mov     [di].cancelflags,0                      ; ZERO OUT CANCEL FLAGS
cleanup13:
        push    si                                      ; SAVE ABIOS RB
        mov     si,ax                                   ; GET ERROR CODE
        sal     si,1                                    ; GET WORD INDEX
        mov     ax,doserrors[si]                        ; GET RETURN STATUS
        pop     si                                      ; RESTORE ABIOS RB
        mov     es:[bx].PktStatus,ax                    ; PUT STATUS IN REQ BLK

        ; RUN THREAD BLOCKED WAITING ON TRANSMISSION COMPLETE

        mov     ax,es                                   ; BLOCK ID
        inc     bx                                      ; UNIQUE BLOCK ID
        mov     dl,DevHlp_ProcRun                       ; RUN FUNCTION
        call    DWORD PTR [device_help]                 ; START MONNOTIFY THREAD
        dec     bx                                      ; ADDRESS REQ BLOCK

cleanup22:
        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 SAVED IN THE CANCELSTATUS BYTE.              */
;/*                                                                    */
;/* ENTRY POINT: PRTERP                                                */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT: DI = Offset tp appropriate PERPRTDATA area                  */
;/*        SI = Offset to appropriate ABIOS PRINTBLOCK request block   */
;/*                                                                    */
;/* 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
        push    ax

        mov     [di].cancelflags,CANNOERROR             ; CLEAR CANCEL FLAGS
        call    getstatus                               ; CALL GET STATUS

;*******************************************************************************
;* 4C = BUSY & ACKNOWLEDGE & I/O ERROR = POWERED OFF                       #20 *
;*******************************************************************************
        .IF <BIT ah Z NOTBUSY> AND                      ; IF BUSY AND
        .IF <BIT ah NZ ACKNOWLEDGE> AND                 ; IF ACK ON AND
        .IF <BIT ah Z PAPEROUT> AND                     ; IF PAPEROUT OFF AND
        .IF <BIT ah Z NOTSELECTED> AND                  ; IF SELECTED OFF AND
        .IF <BIT ah NZ IOERROR>                         ; IF I/O ERROR ON
          mov     [di].cancelflags,CANNOTSELECT         ; SET SELECT ERROR
;*******************************************************************************
;* 34/24 = BUSY & !ACKNOWLEDGE & PAPER OUT & I/O ERROR = !CABLED           #20 *
;*******************************************************************************
        .ELSEIF <BIT ah Z NOTBUSY> AND                  ; IF BUSY AND
        .IF <BIT ah Z ACKNOWLEDGE> AND                  ; IF ACK OFF AND
        .IF <BIT ah NZ PAPEROUT> AND                    ; IF PAPEROUT ON AND
        .IF <BIT ah Z IOERROR>                          ; IF I/O ERROR ON
          mov     [di].cancelflags,CANNOTSELECT         ; SET SELECT ERROR
;*******************************************************************************
;* 2C = BUSY & NO ACKNOWLEDGE & PAPER OUT & I/O ERROR = PAPER OUT          #28 *
;*******************************************************************************
        .ELSEIF <BIT ah Z NOTBUSY> AND                  ; IF BUSY AND
        .IF <BIT ah Z ACKNOWLEDGE> AND                  ; IF ACK OFF AND
        .IF <BIT ah NZ PAPEROUT> AND                    ; IF PAPEROUT ON AND
        .IF <BIT ah Z NOTSELECTED> AND                  ; IF SELECTED OFF AND
        .IF <BIT ah NZ IOERROR>                         ; IF I/O ERROR ON
          mov     [di].cancelflags,CANPAPEROUT          ; SET PAPER ERROR
;*******************************************************************************
;* 0C = BUSY & NO ACKNOWLEDGE & I/O ERROR = OFFLINE                        #29 *
;*******************************************************************************
        .ELSEIF <BIT ah Z NOTBUSY> AND                  ; IF BUSY AND
        .IF <BIT ah Z ACKNOWLEDGE> AND                  ; IF ACK OFF AND
        .IF <BIT ah Z PAPEROUT> AND                     ; IF PAPEROUT OFF AND
        .IF <BIT ah Z NOTSELECTED> AND                  ; IF SELECTED OFF AND
        .IF <BIT ah NZ IOERROR>                         ; IF I/O ERROR ON
          mov     [di].cancelflags,CANIOERROR           ; SET I/O ERROR
        .ELSE                                           ; USE DEFAULT
          mov     [di].cancelflags,CANIOERROR           ; SET I/O ERROR
        .ENDIF
        pop     ax
        ret
EndProc prterp

BREAK <GET STATUS OF SPECIFIED DEVICE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  GETSTATUS                                        */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  Routine to get device status.                   */
;/*                                                                    */
;/* FUNCTION:   This routine will set up the ABIOS request block and   */
;/*             call the start entry point.  The status returned will  */
;/*             be moved into AH for return to the caller.             */
;/*                                                                    */
;/* NOTES:  The parms are identical to Compatibility BIOS int 17H.     */
;/*                                                                    */
;/* ENTRY POINT:                                                       */
;/*         LINKAGE:  EXTRN getstatus:NEAR OR FAR                      */
;/*                   call getstatus                                   */
;/*                                                                    */
;/* INPUT:  DS:[DI] = perprtdata area                                  */
;/*         ES:[BX] = kernel request packet                            */
;/*                                                                    */
;/* EXIT-NORMAL:  AH = port status register                            */
;/*                                                                    */
;/* EXIT-ERROR:   See EXIT-NORMAL above.                               */
;/*                                                                    */
;/* INTERNAL REFERENCES:  cleararb                                     */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  ABIOSCall                       */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure getstatus,HYBRID
        ASSUME  CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING

; @IBM  mov     si,[di].abiosrb_off                     ; SI -> ADDR ABIOS RB   ;@IBM J-PTR #JS02886(C)
        mov     si,[di].abiosrb1_off                    ; SI -> ADDR ABIOS RB #1;@IBM J-PTR #JS02886(C)
        call    cleararb                                ; CLEAR ABIOS RB
        mov     [si].function,RETPRTSTAT                ; RETURN PRINTER STATUS
        mov     [si].retcode,0FFFFH                     ; RETURN CODE - PENDING

        mov     ax,[si].logicalid                       ; GET LID
        mov     dh,START_EPT                            ; START ENTRY POINT
        mov     dl,DevHlp_ABIOSCAll                     ; CALL ABIOS
        call    DWORD PTR [device_help]
;*===========================================================================*  ;@IBM J-PTR #JS03277(A)
;|  If ABIOS returns DEVICE_IN_USE as its return code, it means that another    ;@IBM J-PTR #JS03277(A)
;|  thread has already issued Discrete Multi-Staged request of ABIOS like       ;@IBM J-PTR #JS03277(A)
;|  Print Block.  Then, the getstatus function always returns the constant      ;@IBM J-PTR #JS03277(A)
;|  value (NORMALSTAT & ~NOTBUSY).  It cause the restriction that the caller    ;@IBM J-PTR #JS03277(A)
;|  cannot detect SELECT/DESELECT, PE, etc. in such situation.                  ;@IBM J-PTR #JS03277(A)
;*===========================================================================*  ;@IBM J-PTR #JS03277(A)
        cmp     [si].retcode,COMPLETEDOK                ; IF NO ERROR           ;@IBM J-PTR #JS03277(A)
        je      getstatus_00                            ; THEN GET ABIOS STATUS ;@IBM J-PTR #JS03277(A)
        mov     [si].returnstatus,NORMALSTAT            ; ELSE GENERATE         ;@IBM J-PTR #JS03277(A)
        and     [si].returnstatus,NOT NOTBUSY           ; BUSY STATUS           ;@IBM J-PTR #JS03277(A)
getstatus_00:                                                                   ;@IBM J-PTR #JS03277(A)

        mov     ah,[si].returnstatus                    ; ABIOS STATUS
        and     ah,NOT NOTINTPENDING                    ; TURN INT PENDING OFF
        ret
EndProc getstatus

BREAK <CLEAR ABIOS REQUEST BLOCK>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  CLEARARB                                         */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  Clear the ABIOS request block.                  */
;/*                                                                    */
;/* FUNCTION:  This routine zeros out the ABIOS request block.         */
;/*                                                                    */
;/* NOTES:  First word of ABIOS RB contains request block length and   */
;/*         the second word contains the logical id.                   */
;/*                                                                    */
;/* ENTRY POINT:                                                       */
;/*         LINKAGE:  cleararb:near or far                             */
;/*                   call cleararb                                    */
;/*                                                                    */
;/* INPUT:  DS:[DI]   = perprtdata area                                */
;/*         DS:[SI]   = ABIOS request block                            */
;/*         DS:[SI].length  = ABIOS rb length (first word)             */
;/*         DS:[SI].logicalid = ABIOS rb logical id (second word)      */
;/*                                                                    */
;/* EXIT-NORMAL:  ABIOS RB is zero                                     */
;/*                                                                    */
;/* EXIT-ERROR:  See Exit-Normal above.                                */
;/*                                                                    */
;/* EFFECTS:                                                           */
;/*                                                                    */
;/* INTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure cleararb,HYBRID
        ASSUME  CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        SaveReg <ax,cx,di,es>                           ; SAVE REGISTERS
        xor     ax,ax                                   ; CLEAR AX
        mov     cx,SIZE requestblk                      ; GET LENGTH
        sub     cx,4                                    ; SUBTRACT LENGTH & LID
        shr     cx,1                                    ; CONVERT BYTES TO WORDS
        mov     di,si                                   ; DS:DI -> ABIOS RB
        add     di,4                                    ; GET PASSED LENGTH/LID
        push    ds
        pop     es                                      ; ES:DI -> ABIOS RB
   rep  stosw                                           ; ZERO ABIOS RB
        RestoreReg <es,di,cx,ax>                        ; RESTORE REGISTERS
        ret
EndProc cleararb

;  *** END OF RESIDENT CODE ***
;  ALL CODE AFTER THIS POINT IS RELEASED AFTER INITIALIZATION
CODEEND EQU     $ - 1                                   ; USE LIMIT OF SEGMENT

BREAK <INITIALIZATION ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTINIT                                          */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  Initialize the printer device driver            */
;/*                                                                    */
;/* FUNCTION:   This routine will SETIRQ 7, get the LID's for LPT1,    */
;/*             LPT2, and LPT3, and set the end of the code and data   */
;/*             segments.                                              */
;/* 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.  */
;/*               initialtime = # of milliseconds to block at prt init.*/
;/*               timeoutval = # of ticks to wait for timeout          */
;/*                                                                    */
;/* EXIT-ERROR:  see EXIT-NORMAL above.                                */
;/*                                                                    */
;/* EFFECTS:                                                           */
;/*                                                                    */
;/* INTERNAL REFERENCES:  _RM_PRT_CreateDriver                         */
;/*    ROUTINES:          parsecmdline                                 */
;/*                       initialprt                                   */
;/*                       RM_PRT_RegisterResources                     */
;/*                                                                    */
;/* 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

        ; SET THE PARALLEL PORTS TO BIDIRECTIONAL MODE FOR VLPT (DMF)

        SaveReg <ax,dx>                                 ; SAVE REGISTERS
        mov     al,07Fh                                 ; ALLOW MANIPULATION
        out     94h,al                                  ; OF PLANAR PORT 102H

        mov     dx,102h                                 ; PLANAR PORT 102
        in      al,dx                                   ; READ IN STATE
        DevIODelay <bx>                                 ; I/O DELAY
        and     al,07Fh                                 ; ENABLE BI-DIRECTION
        or      al,01h                                  ; SET PLANAR ENABLE
        out     dx,al                                   ; PARALLEL PORT READY
                                                        ; TO RECEIVE

        mov     al,0FFh                                 ; DISALLOW MANIPULATION
        out     94h,al                                  ; OF PLANAR PORT 102H
        RestoreReg <dx,ax>                              ; RESTORE REGISTERS

        ; 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,MCBUS                           ; MC BUS SYSTEM

        ; 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].nextppda,di                        ; SET PTR TO THIS PPDA
        mov     [di].deviceindex,LPT1_INDEX             ; INDEX FOR LPT1
        mov     [di].deviceflag,LPT1_FLAG               ; FLAG FOR LPT1
        mov     [di].hdroff,(1 * SIZE SysDev3)          ; DEVICE HEADER OFFSET
        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].nextppda,di                        ; SET PTR TO THIS PPDA
        mov     [di].deviceindex,LPT2_INDEX             ; INDEX FOR LPT2
        mov     [di].deviceflag,LPT2_FLAG               ; FLAG FOR LPT2
        mov     [di].hdroff,(2 * SIZE SysDev3)          ; DEVICE HEADER OFFSET
        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].nextppda,di                        ; SET PTR TO THIS PPDA
        mov     [di].deviceindex,LPT3_INDEX             ; INDEX FOR LPT3
        mov     [di].deviceflag,LPT3_FLAG               ; FLAG FOR LPT3
        mov     [di].hdroff,(3 * SIZE SysDev3)          ; DEVICE HEADER OFFSET
        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].nextppda = next perprtarea                       */
;/*              [di].abiosrb_off = offset of ABIOS request block      */
;/*              flags2 |= PDDABIOSPS2FIX                              */
;/*              flags2 |= FIRSTSETIRQ                                 */
;/*                                                                    */
;/* EXIT-ERROR:  CY                                                    */
;/*                                                                    */
;/* EFFECTS:                                                           */
;/*                                                                    */
;/* INTERNAL REFERENCES:  getabiosparms                                */
;/*    ROUTINES:          getdevparms                                  */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  SetIRQ                          */
;/*    ROUTINES:                       GetLIDEntry                     */
;/*                                    ABIOSCall                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtdeterminehardware near
        ASSUME  CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING

        add     [di].nextppda,SIZE printer_database     ; CALC OFFSET TO NEXT
        cmp     [di].deviceindex,LPT3_INDEX             ; IF NOT LAST ENTRY
        jne     prtdethard1                             ; CONTINUE
        mov     [di].nextppda,OFFSET perprtarea         ; ELSE POINT TO FIRST
prtdethard1:

        ; GET ADDRESSIBILITY TO BIOS ROM DATA AREA

        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     bx,BIOSDATA.printer_adapt[si]           ; GET PORT ADDRESS
        mov     [di].deviceaddr,bx                      ; SAVE PORT ADDRESS

        ; SETUP POINTER TO ABIOS REQUEST BLOCK FOR THIS DEVICE

        imul    si,ax,SIZE requestblk                   ; CALC OFFSET TO REQ BLK
        add     si,OFFSET reqblks                       ; SI -> ABIOS REQ BLOCK
        mov     [di].abiosrb_off,si                     ; SAVE ABIOS RB OFFSET
                                                                                ;@IBM J-PTR #JS02886(A)
        ; SETUP POINTER TO ABIOS REQUEST BLOCK #1 FOR THIS DEVICE               ;@IBM J-PTR #JS02886(A)
                                                                                ;@IBM J-PTR #JS02886(A)
        push    si                                      ; SAVE SI REGISTER      ;@IBM J-PTR #JS02886(A)
        imul    si,ax,SIZE requestblk                   ; CALC OFFSET TO REQ BLK;@IBM J-PTR #JS02886(A)
        add     si,OFFSET reqblks1                      ; SI -> ABIOS REQ BLK #1;@IBM J-PTR #JS02886(A)
        mov     [di].abiosrb1_off,si                    ; SAVE ABIOS RB OFFSET  ;@IBM J-PTR #JS02886(A)
        pop     si                                      ; RESTORE SI REGISTER   ;@IBM J-PTR #JS02886(A)

        ; GET THE LOGICAL ID AND SAVE IT IN THE ABIOS REQUEST BLOCK

        cmp     [di].deviceaddr,0                                               ;@IBM J-FUNC(A)
        jnz     skip01                                  ; IF DEVICEADDR IS ZERO ;@IBM J-FUNC(A)
        jmp     prtdethard2                             ; THEN EXIT             ;@IBM J-FUNC(A)
skip01:                                                                         ;@IBM J-FUNC(A)
        mov     ax,Printer                              ; PRT ABIOS DEVICE ID
        mov     bl,0                                    ; FIRST UNCLAIMED LID
        mov     dh,DEVICESTATE                          ; RESERVED
        mov     dl,DevHlp_GetLIDEntry                   ; GET LID ENTRY FUNC
        call    DWORD PTR [device_help]                 ; CALL DEVHLP
        jc      prtdethard2                             ; IF ERROR, EXIT

        mov     [si].logicalid,ax                       ; SAVE LID
        mov     [si].rblength,SIZE requestblk           ; SAVE ABIOS RB LENGTH

        inc     numofprts                               ; # OF PRTS INSTALLED
        or      [di].commonflags1,PORTEXISTS            ; SAVE PORT INSTALLED

        call    getabiosparms                           ; GET LID PARAMETERS

        ; PARALLEL PORT DD IS STATICALLY ALLOCATING ABIOS REQUEST BLOCKS BUT
        ; SHOULD BE DYNAMICALLY ALLOCATING THEM IN CASE FUTURE REQUIREMENTS
        ; CAUSE THEM TO GROW.  IF THEY GROW, PP DD WILL FAIL TO INITIALIZE.

        cmp     [si].rblen,SIZE requestblk              ; RB BIG ENOUGH FOR LID?
        ja      prtdethard4                             ; NO, ERROR, EXIT

        call    getdevparms                             ; GET DEVICE PARMS
                                                                                ;@IBM J-PTR #JS02886(A)
        ; MAKE A COPY OF REQUEST BLOCK                                          ;@IBM J-PTR #JS02886(A)
                                                                                ;@IBM J-PTR #JS02886(A)
        SaveReg <si,es,di,cx>                                                   ;@IBM J-PTR #JS02886(A)
        cld                                                                     ;@IBM J-PTR #JS02886(A)
        push    ds                                      ; ES:DI -> REQBLK1      ;@IBM J-PTR #JS02886(A)
        pop     es                                                              ;@IBM J-PTR #JS02886(A)
        mov     di,si                                                           ;@IBM J-PTR #JS02886(A)
        add     di,MAXREQBLKS * (SIZE requestblk)                               ;@IBM J-PTR #JS02886(A)
        mov     cx,SIZE requestblk                      ; SET LENGTH OF REQBLK  ;@IBM J-PTR #JS02886(A)
        rep     movsb                                                           ;@IBM J-PTR #JS02886(A)
        RestoreReg <cx,di,es,si>                                                ;@IBM J-PTR #JS02886(A)

        ; SEE IF ABIOS FIX AVAILABLE FOR IRQ7 PROBLEM

        call    cleararb                                ; CLEAR ABIOS RB
        mov     [si].function,RETDYNSTAT                ; RETURN PRINTER STATUS
        mov     [si].retcode,0FFFFH                     ; RETURN CODE

        mov     ax,[si].logicalid                       ; ELSE GET LOGICAL ID
        mov     dh,START_EPT                            ; START ENTRY POINT
        mov     dl,DevHlp_ABIOSCAll                     ; CALL ABIOS
        call    DWORD PTR [device_help]
        cmp     [si].retcode,COMPLETEDOK                ; IF !COMPLETED OK
        jne     prtdethard2                             ; THEN UNSUPPORTED CALL
        or      flags2,PDDABIOSPS2FIX                   ; ELSE ABIOS HAS FIX

        ; IF POLLING FLAG IS OFF, THEN SET THE NEEDIRQ FLAG ON

prtdethard2:
        test    [di].commonflags,USEPOLLING             ; IF POLLING PROTOCOL
        jnz     prtdethard3                             ; THEN CONTINUE
        or      flags2,NEEDIRQ                          ; ELSE SET NEEDIRQ FLAG

prtdethard3:
        ; SET HARDWARE INTERRUPT HANDLER ENTRY POINT ONCE.
        ; DON'T ENABLE IRQ UNTIL MOST VARIABLES ARE INITIALIZED, IF IRQ PENDING,
        ; IRQ HANDLER CANNOT HANDLE HARDWARE INTERRUPT PROPERLY AND WILL TRAP D.

        cmp     [di].deviceindex,LPT3_INDEX             ; IF DEVICE != LPT3
        jne     prtdethard5                             ; THEN CONTINUE
        test    flags2,NEEDIRQ                          ; NEED IRQ?
        jz      prtdethard5                             ; NO

        mov     ax,OFFSET prtint07                      ; OFF HARD INT HANDLER
        xor     bh,bh
        mov     bl,LEVEL7                               ; INTERRUPT NUMBER
        mov     dh,1                                    ; LEVEL SHARED
        mov     dl,DevHlp_SetIRQ                        ; SET IRQ FUNC
        call    DWORD PTR [device_help]                 ; CALL DEVHLP
        jnc     prtdethard6                             ; IRQ7 AVAILABLE

        ; 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:
        test    [di].commonflags,USEPOLLING             ; IF USE POLLING
        jnz     RM_PRT_Reg2                             ; DON'T DEALLOC IRQ
        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 <GET ABIOS PARMS ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  GET ABIOS PARMS ROUTINE                          */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  Call abios and return the parallel port parms.  */
;/*                                                                    */
;/* FUNCTION:   This routine will call ABIOS and return the parallel   */
;/*             port parameters to be used by the other ABIOS routines.*/
;/*                                                                    */
;/* NOTES:  ABIOS request block length must be at least 32 bytes.      */
;/*                                                                    */
;/*         The PRT default is for the file system to lock application */
;/*         buffers below 16 MB to accomodate 24 bit DMA since PRT DMA */
;/*         is done directly from the application buffer.  If the port */
;/*         supports 32 bit DMA, this routine will set the supports    */
;/*         >16MB bit in the device driver header so file system will  */
;/*         not have to ask memory management to move the buffer low.  */
;/*                                                                    */
;/* ENTRY POINT:                                                       */
;/*         LINKAGE:  getabiosparms:NEAR                               */
;/*                   call getabiosparms                               */
;/*                                                                    */
;/* INPUT:  DS = Data segment                                          */
;/*         SI = Offset to appropriate ABIOS request block             */
;/*         DI = Offset to appropriate perprtdata area                 */
;/*                                                                    */
;/* EXIT-NORMAL:  [di].intlevel = hardware interrupt level for LID     */
;/*               [si].rblen = abios request block length for LID      */
;/*               >16MB bit set in capabilities flag of dd header      */
;/*                                                                    */
;/* EXIT-ERROR:  see EXIT-NORMAL above.                                */
;/*                                                                    */
;/* EFFECTS:                                                           */
;/*                                                                    */
;/* INTERNAL REFERENCES:  cleararb                                     */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  ABIOSCall                       */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure getabiosparms near
        ASSUME  CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING

        call    cleararb                                ; CLEAR ABIOS RB
        mov     [si].function,RETLIDPARMS               ; RETURN LID PARAMETERS
        mov     [si].retcode,0FFFFH                     ; RETURN CODE

        mov     ax,[si].logicalid                       ; GET LID
        mov     dh,START_EPT                            ; START ENTRY POINT
        mov     dl,DevHlp_ABIOSCall                     ; CALL ABIOS
        call    DWORD PTR [device_help]

        mov     al,[si].intlvl                          ; HARDWARE INT LEVEL
        mov     [di].intlevel,al

        test    [si].lidflags,DMA32BIT                  ; 32 BIT DMA AVAILABLE?
        jz      getabiosp2                              ; NOT THIS PORT
        cmp     [di].deviceindex,LPT1_INDEX             ; IS THIS LPT1 PORT?
        jne     getabiosp1                              ; NOPE
        push    di                                      ; SAVE REGISTER
        xor     di,di                                   ; OFFSET TO FIRST HDR
        or      WORD PTR [di].SDevCaps,DEV_16MB         ; SET PRN >16MB SUPPORT
        pop     di                                      ; RESTORE REGISTER
getabiosp1:
        push    di                                      ; SAVE REGISTER
        mov     di,[di].hdroff                          ; PTR TO LPTx HEADER
        or      WORD PTR [di].SDevCaps,DEV_16MB         ; SET LPTx >16MB SUPPORT
        pop     di                                      ; RESTORE REGISTER
getabiosp2:
        ret
EndProc getabiosparms

BREAK <GET DEVICE PARMS ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  GET DEVICE PARMS ROUTINE                         */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  Call abios and return the parallel port parms.  */
;/*                                                                    */
;/* FUNCTION:   This routine will call ABIOS and return the parallel   */
;/*             port parameters to be used by the other ABIOS routines.*/
;/* NOTES:                                                             */
;/*                                                                    */
;/* ENTRY POINT:                                                       */
;/*         LINKAGE:  getdevparms:NEAR                                 */
;/*                   call getdevparms                                 */
;/*                                                                    */
;/* INPUT:  DS = Data segment                                          */
;/*         SI = Offset to appropriate ABIOS request block             */
;/*         DI = Offset to appropriate perprtdata area                 */
;/*                                                                    */
;/* EXIT-NORMAL: [di].commonflags1 = DMAAVAIL if port supports DMA     */
;/*              [di].commonflags = NOT USEPOLLING if DMAAVAIL         */
;/*              [di].inittime_lo = device initialization time         */
;/*              [di].inittime_hi = device initialization time         */
;/*                                                                    */
;/* EXIT-ERROR:  see EXIT-NORMAL above.                                */
;/*                                                                    */
;/* EFFECTS:                                                           */
;/*                                                                    */
;/* INTERNAL REFERENCES:  cleararb                                     */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  ABIOSCall                       */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure getdevparms near
        ASSUME  CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING

        call    cleararb                                ; CLEAR ABIOS RB
        mov     [si].function,READDEVPARMS              ; READ DEV PARAMETERS
        mov     [si].retcode,0FFFFH                     ; RETURN CODE

        mov     ax,[si].logicalid                       ; GET LID
        mov     dh,START_EPT                            ; START ENTRY POINT
        mov     dl,DevHlp_ABIOSCall                     ; CALL ABIOS
        call    DWORD PTR [device_help]

        test    [si].suppflags,DMAPRESENT               ; DMA PRESENT FOR DEV?
        jz      getdevparms1                            ; NO
        or      [di].commonflags1,DMAAVAIL              ; YES, SAVE INFO
        and     [di].commonflags,NOT USEPOLLING         ; USE DMA, SET POLL OFF
getdevparms1:
        mov     ax,WORD PTR [si].inittime               ; RESET/INIT WAIT TIME
        mov     dx,WORD PTR [si].inittime + 2           ; RESET/INIT WAIT TIME
        mov     cx,1000
        div     cx                                      ; .000001 to .001 SECS
        mov     [di].inittime_lo,ax                     ; SAVE INITIALTIME IN
        mov     [di].inittime_hi,0                      ; .001 (MILLI)SECS
        ret
EndProc getdevparms

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
