home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 8 Other / 08-Other.zip / PCTJOS2.ZIP / OS2LPT.ASM < prev    next >
Assembly Source File  |  1988-09-09  |  25KB  |  811 lines

  1.     PAGE    60,132    
  2.     TITLE    Line Printer Driver
  3.     NAME    LPT
  4.     .286
  5. ;***************************************************************************
  6. ; Miscellaneous assembly parameters
  7. IOSEG    EQU    40H        ; BIOS data area segment address
  8. IOTAB    EQU    8        ; offset to printer table in BIOS area
  9. IOLPT1    EQU    3BCH        ; normal LPT1 I/O address
  10. IOLPT2    EQU    378H        ; normal LPT2 I/O address
  11. IOINT1    EQU    7        ; normal LPT1 interrupt level
  12. IOINT2    EQU    5        ; normal LPT2 interrupt level
  13. TIMEOUT    EQU    10000        ; timeout in milliseconds, -1 for no timeout
  14. ;***************************************************************************
  15. ;
  16. ; Device Helper Service information
  17. DevDone        EQU    1
  18. Block        EQU    4
  19. Run        EQU    5
  20. LockSeg        EQU    13H
  21. UnlockSeg    EQU    14H
  22. PhysToVirt    EQU    15H
  23. VirtToPhys    EQU    16H
  24. SetROMVector    EQU    1AH
  25. SetIRQ        EQU    1BH
  26. UnSetIRQ    EQU    1CH
  27. MonCreate    EQU    1FH
  28. Register    EQU    20H
  29. DeRegister    EQU    21H
  30. MonWrite    EQU    22H
  31. MonFlush    EQU    23H
  32. GetDOSVar    EQU    24H
  33. ROMCritSect    EQU    26H
  34. VerifyAccess    EQU    27H
  35. EOI        EQU    31H
  36. UnPhysToVirt    EQU    32H
  37. ;***************************************************************************
  38. ; Driver request packet data structure
  39. ;***************************************************************************
  40. DRVPKT  STRUC
  41. P_LEN   DB      ?               ; packet length
  42. P_UNIT  DB      ?               ; unit number
  43. P_CMD   DB      ?               ; command (operation) code
  44. P_STAT  DW      ?               ; status code
  45. P_SYSL  DD      ?               ; system queue linkage
  46. P_DEVL  DD      ?               ; device queue linkage
  47. DRVPKT  ENDS
  48. ;
  49. ; Flags in P_STAT
  50. PS_ERR  EQU     8000H           ; error flag
  51. PS_ERRD EQU     4000H           ; device error flag
  52. PS_BUSY EQU     0200H           ; busy flag
  53. PS_DONE EQU     0100H           ; completion flag
  54. ;
  55. ; Error codes in P_STAT
  56. ;
  57. PE_CMD    EQU    5        ; bad command code
  58. PE_OUT    EQU    9        ; out of paper
  59. PE_WRT    EQU    0AH        ; write error
  60. PE_GEN    EQU    0CH        ; general failure
  61. ;
  62. ; Request packet extension for initialize operations (code 0)
  63. ;
  64. PKTI    STRUC
  65.     DB    13 DUP(?)    ; header
  66.     DB    ?        ; reserved
  67. P_HLP0    DW    ?        ; DevHlp address, returns CS size
  68. P_HLP1    DW    ?        ; DevHlp address, returns DS size
  69. PKTI    ENDS
  70. ;
  71. ; Request packet extension for write operation (codes 08H and 09H)
  72. ;
  73. PKTW    STRUC
  74.     DB    13 DUP(?)    ; header
  75.     DB    ?        ; unused
  76. P_BADD    DD    ?        ; buffer address
  77. P_BLEN    DW    ?        ; buffer length
  78. PKTW    ENDS 
  79. ;
  80. ; Request packet extension for IOCTL operation
  81. ;
  82. PKTIOC    STRUC
  83.     DB    13 DUP(?)    ; header
  84. P_CAT    DB    ?        ; category
  85. P_FUN    DB    ?        ; function
  86. P_PARM    DD    ?        ; parameter area pointer
  87. P_DATA    DD    ?        ; data area pointer
  88. PKTIOC    ENDS
  89. ;
  90. ; Data area for IOCTL "register" function
  91. ;
  92. IOCREG    STRUC
  93. R_POS    DB    ?        ; position code
  94. R_NDX    DW    ?        ; index
  95. R_IN    DD    ?        ; input buffer address
  96. R_OUT    DW    ?        ; output buffer offset
  97. IOCREG    ENDS
  98. ;***************************************************************************
  99. ;
  100. ; Monitor chain buffer structure
  101. ;
  102. MONLEN    EQU     132        ; size of monitor buffer
  103. MONHDR    EQU    4        ; size of monitor buffer header
  104. MONPKT    STRUC
  105. M_FLAG    DW    0        ; flags
  106. M_PID    DW    0        ; user process id
  107. M_DATA    DB    MONLEN-MONHDR DUP(?)    ; data area
  108. MONPKT    ENDS
  109. ;
  110. ; Monitor flags (byte 0 of M_FLAG)
  111. ;
  112. MF_OPEN EQU    1        ; open flag
  113. MF_CLOS EQU    2        ; close flag
  114. MF_FLSH    EQU    4        ; flush flag
  115.     SUBTTL    Data Segment
  116.     PAGE
  117. ;***************************************************************************
  118. ; Define the data segment.  The name _DATA is used here for compatibility 
  119. ; with most OS/2 C compilers, but any name is acceptable. 
  120. ;***************************************************************************
  121. _DATA    SEGMENT WORD PUBLIC 'DATA'
  122. ;***************************************************************************
  123. ;
  124. ; This is the LPT1 device driver header.  No other data can precede it.
  125. ;
  126. ;***************************************************************************
  127. LPT1    DW      PRN,SEG PRN    ; linkage 
  128.         DW      88C0H           ; device type bits...
  129.                                 ;   15    => character device        
  130.                                 ;   11    => open/close support
  131.                                 ;   09-07 => driver type 1 (OS/2)
  132.                                 ;   06    => IOCTL supported
  133.         DW      S_LPT           ; offset to strategy routine
  134.         DW      -1              ; reserved
  135.         DB      'LPT1    '      ; device name
  136.         DW      4 DUP(0)        ; reserved
  137. ;***************************************************************************
  138. ; This is the PRN device driver header.  LPT1 and PRN are synonyms.
  139. ;***************************************************************************
  140. PRN     DD      -1        ; linkage (-1 indicates end of header list) 
  141.         DW      88C0H           ; device type bits...
  142.                                 ;   15    => character device        
  143.                                 ;   11    => open/close support
  144.                                 ;   09-07 => driver type 1 (OS/2)
  145.                                 ;   06    => IOCTL supported
  146.         DW      S_LPT           ; offset to strategy routine
  147.         DW      -1              ; reserved
  148.         DB      'PRN     '      ; device name
  149.         DW      4 DUP(0)        ; reserved
  150. ;***************************************************************************
  151. ; Driver command table
  152. CMDTBS  DW      S_INIT          ; 00 => Initialize
  153.         DW      CMDBAD          ; 01 => Check media
  154.         DW      CMDBAD          ; 02 => Build BPB
  155.         DW      CMDBAD          ; 03 => Reserved
  156.         DW      CMDBAD          ; 04 => Read      
  157.         DW      CMDBAD          ; 05 => Peek
  158.         DW      CMDBAD          ; 06 => Get input status
  159.         DW      CMDBAD          ; 07 => Flush input buffer
  160.         DW      S_WRT           ; 08 => Write
  161.         DW      S_WRT           ; 09 => Write and verify
  162.         DW      S_STAT          ; 0A => Get output status
  163.         DW      S_FLUSH         ; 0B => Flush output buffer
  164.         DW      CMDBAD          ; 0C => Reserved
  165.         DW      S_OPEN          ; 0D => Open
  166.         DW      S_CLOSE         ; OE => Close
  167.         DW      CMDBAD          ; 0F => Check removable media
  168.         DW      S_IOCTL         ; 10 => I/O control
  169.         DW      CMDBAD          ; 11 => Reset media
  170.         DW      CMDBAD          ; 12 => Get logical drive map
  171.         DW      CMDBAD          ; 13 => Set logical drive map
  172. CMDTBE  DW      S_RMV           ; 14 => Remove driver (de-install)
  173. CMDMAX  EQU     (CMDTBE-CMDTBS)/2        
  174. ;***************************************************************************
  175. ; Monitor buffer
  176. MON    DW    MONLEN        ; receive buffer, used by notify routine
  177. MONR    MONPKT    <>
  178. MONS    MONPKT    <>        ; send buffer, used by strategy routine
  179. ;***************************************************************************
  180. ; Driver status flags
  181. STATUS    DB    0        ; driver status flags
  182. SF_TIME    EQU    1        ; set if timer is running
  183. SF_FLSH    EQU    2        ; set if flushing
  184. SF_WAIT    EQU    4        ; set if waiting for interrupt
  185. ;***************************************************************************
  186. ; Miscellaneous data items
  187. ;
  188. DEVHLP    DD    0        ; DevHlp function address
  189. IOTADD    DW    IOTAB,IOSEG    ; points to printer table in BIOS RAM
  190. IOLPT    DW    0        ; current printer I/O address
  191. IOINT    DW    0        ; current printer interrupt level
  192. IOTIME    DD    TIMEOUT        ; timeout value for printer delay
  193. MONHAN    DW    0        ; monitor handle
  194. ;***************************************************************************
  195. ;
  196. ; End of data segment
  197. ;
  198. END_DS    EQU    $        ; used by S_INIT
  199. _DATA    ENDS
  200.     SUBTTL    Code Segment
  201.     PAGE
  202. ;***************************************************************************
  203. ;
  204. ; Define the code segment.  The name _TEXT is used for compatibility with
  205. ; most OS/2 C compilers, but any name is acceptable.  The ASSUME statement
  206. ; indicates what values the driver expects in the segment registers. 
  207. ;
  208. ;***************************************************************************
  209. _TEXT   SEGMENT WORD PUBLIC 'CODE'
  210.         ASSUME  CS:_TEXT,DS:_DATA
  211. ;***************************************************************************
  212. ;
  213. ; This is the strategy routine.  It is entered via a far call, with the
  214. ; request packet pointer in ES:BX.  The packet pointer is valid in both
  215. ; real and protected mode.  
  216. ;
  217. ;***************************************************************************
  218. S_LPT    PROC    FAR
  219.     PUSH    ES              ; save request packet pointer
  220.         PUSH    BX
  221.         MOV     BP,SP           ; set up stack frame pointer
  222.         XOR     AX,AX           ; get driver command code
  223.         MOV     AL,ES:[BX].P_CMD
  224.         CMP     AL,CMDMAX       ; check if in range
  225.         JA      CMDBAD          ; error if not
  226.         MOV     DI,AX           ; call the command routine
  227.         ADD     DI,DI
  228.         CALL    CMDTBS[DI] 
  229.         POP     BX              ; restore packet pointer
  230.         POP     ES
  231.         RETF                    ; return to caller
  232. ;***************************************************************************
  233. ; The following labels are convenient exit points for strategy routines.
  234. ; SS:SP must point to the return address, and the request packet pointer
  235. ; must be just above the return address.
  236. ;***************************************************************************
  237. ;
  238. ; Come here for bad commands
  239. ;
  240. CMDBAD:    MOV    AX,PE_CMD+PS_ERR
  241. ;
  242. ; Common exit point, with status code in AX
  243. ;
  244. DONE:    MOV    BP,SP        ; set frame pointer
  245.     LES    BX,[BP+2]    ; get packet pointer
  246.     OR    AX,PS_DONE    ; set completion flag
  247.     MOV    ES:[BX].P_STAT,AX ; store codes
  248.     RETN
  249. ;
  250. ; Come here for general errors
  251. ;
  252. ERRGEN:    MOV    AX,PE_GEN+PS_ERR
  253.     JMP    DONE
  254. ;***************************************************************************
  255. ; S_WRT -- Initiate a write operation
  256. ;
  257. S_WRT:    TEST    STATUS,SF_FLSH
  258.     JNZ    RETOK            ; ignore write request if flushing
  259.     CALL    GETPID            ; get user process id
  260.     JC    ERRGEN            ; branch if error
  261.     PUSH    AX            ; save it on stack
  262.     PUSH    0            ; clear user buffer index
  263.     PUSH    ES:[BX].P_BLEN        ; copy user buffer length/address
  264.     PUSH    WORD PTR ES:[BX].P_BADD+2
  265.     PUSH    WORD PTR ES:[BX].P_BADD
  266.     MOV    BP,SP            ; BP is now frame pointer
  267. ;
  268. ; Call MonWrite one or more times to process the user's data
  269. ;
  270. WRT1:    MOV    CX,[BP+4]        ; get residual length
  271.     CMP    CX,MONLEN-MONHDR    
  272.     JNA    WRT2            ; branch if fits in monitor buffer
  273.     MOV    CX,MONLEN-MONHDR    ; else process part of the data
  274. WRT2:    MOV    AX,[BP]            ; get user buffer address 
  275.     MOV    BX,[BP+2]
  276.     PUSH    CX            ; save current length
  277.     MOV    DX,0100H+PhysToVirt      ; convert address into ES:DI
  278.     CALL    DEVHLP
  279.     POP    CX            ; restore current length
  280.     JC    WRT4            ; branch if error
  281.     SUB    [BP+4],CX        ; reduce residual length
  282.     ADD    DI,[BP+6]        ; compute next byte address
  283.     ADD    [BP+6],CX        ; update buffer index
  284.     LEA    SI,MONS.M_DATA        ; move data to monitor send buffer
  285.     PUSH    CX
  286. WRT3:    MOV    AL,[SI]
  287.     MOV    ES:[DI],AL
  288.     INC    SI
  289.     INC    DI
  290.     LOOP    WRT3
  291.     POP    CX
  292.     ADD    CX,MONHDR        ; adjust length to include header
  293.     MOV    AX,[BP+8]        ; move process id to header
  294.     MOV    MONS.M_PID,AX
  295.     MOV    MONS.M_FLAG,0        ; reset all flags
  296.     LEA    SI,MONS            ; set pointer to data record
  297.     MOV    AX,MONHAN        ; get monitor handle
  298.     MOV    DX,MonWrite        ; DH=0 to synchronize in dispatcher
  299.     CALL    DEVHLP            ; perform monitor write
  300.     JC    WRT4            ; branch if error
  301.     CMP    WORD PTR [BP+4],0
  302.     JNE    WRT1            ; loop till residual length is zero
  303.     MOV    DL,UnPhysToVirt        ; restore prior addressing mode
  304.     CALL    DEVHLP
  305.     ADD    SP,8            ; discard local stack frame
  306. ;
  307. ; Come here when operation has completed successfully
  308. ;
  309. RETOK:    XOR    AX,AX            ; clear error code
  310.     JMP    DONE            ; return
  311. ;
  312. ; Come here for write error
  313. ;
  314. WRT4:    MOV    AX,PE_WRT+PS_ERR    ; load error code
  315.     ADD    SP,8            ; discard local stack frame
  316.     JMP    DONE            ; return
  317. ;***************************************************************************
  318. ;
  319. ; S_STAT -- Get output status
  320. ;
  321. S_STAT:    JMP    RETOK            ; return "not busy"
  322. ;***************************************************************************
  323. ;
  324. ; S_FLUSH -- Flush output queue
  325. ;
  326. S_FLUSH: OR    STATUS,SF_FLSH        ; set flush flag
  327.     MOV    AX,MONHAN        ; send flush message to monitors
  328.     MOV    DL,MonFlush
  329.     CALL    DEVHLP
  330.     JNC    RETOK            ; exit if successful
  331.     JMP    ERRGEN            ; else signal general failure
  332. ;***************************************************************************
  333. ;
  334. ; S_OPEN -- Open the printer
  335. ;
  336. S_OPEN: CMP    BYTE PTR ES:[BX].P_STAT,0
  337.     JNE    OPEN1            ; ignore if DosMonOpen
  338. ;
  339. ; Come here to handle DosOpen
  340. ;
  341.     MOV    MONS.M_FLAG,MF_OPEN    ; set open flag in header
  342.     CALL    GETPID            ; put process id into header
  343.     JC    CLS0
  344.     MOV    MONS.M_PID,AX
  345.     MOV    CX,MONHDR        ; set message length
  346.     LEA    SI,MONS            ; set pointer to message
  347.     MOV    DX,MonWrite        ; DH=0 to synchronize in dispatcher
  348.     CALL    DEVHLP            ; send the message
  349.     JC    CLS0
  350. OPEN1:    JMP    RETOK
  351. ;***************************************************************************
  352. ;
  353. ; S_CLOSE -- Close the printer
  354. ;
  355. S_CLOSE: CMP    BYTE PTR ES:[BX].P_STAT,0
  356.     JNE    CLS1            ; branch if DosMonClose
  357. ;
  358. ; Come here to handle DosClose
  359. ;
  360.     MOV    MONS.M_FLAG,MF_CLOS    ; set close flag in header
  361.     CALL    GETPID            ; put process id into header
  362.     JC    CLS0
  363.     MOV    MONS.M_PID,AX
  364.     MOV    CX,MONHDR        ; set message length
  365.     LEA    SI,MONS            ; set pointer to message
  366.     MOV    DX,MonWrite        ; DH=0 to synchronize in dispatcher
  367.     CALL    DEVHLP            ; send the message
  368.     JNC    RETOK
  369. CLS0:    JMP    ERRGEN
  370. ;
  371. ; Come here to handle DosMonClose
  372. ;
  373. CLS1:    CALL    GETPID            ; get monitor process id
  374.     JC    CLS0
  375.     MOV    BX,AX
  376.     MOV    AX,MONHAN        ; de-register this monitor
  377.     MOV    DL,DeRegister
  378.     CALL    DEVHLP
  379.     JC    CLS0            ; branch if failure
  380.     JMP    RETOK
  381. ;***************************************************************************
  382. ;
  383. ; S_IOCTL -- I/O control operation
  384. ;
  385. S_IOCTL: CMP    ES:[BX].P_CAT,5
  386.     JNE    IOC0
  387.     CMP    ES:[BX].P_FUN,65H    
  388.     JE    IOC_S            ; branch if IOCTL 5.101, STATUS
  389. IOC0:    CMP    ES:[BX].P_CAT,10
  390.     JNE    IOC1
  391.     CMP    ES:[BX].P_FUN,40H    
  392.     JE    IOC_R            ; branch if IOCTL 10.64, REGISTER
  393. IOC1:    CMP    ES:[BX].P_CAT,11
  394.     JNE    IOC2
  395.     CMP    ES:[BX].P_FUN,60H
  396.     JE    IOC_Q            ; branch if IOCTL 11.96, QUERY MON
  397. IOC2:    JMP    CMDBAD            ; else indicate invalid request                
  398. IOC3:    JMP    ERRGEN
  399. ;
  400. ; Query monitor support (Category 11, function 96)
  401. ;    
  402. IOC_Q:    JMP    RETOK            ; return OK to show monitor support
  403. ;
  404. ; Get printer status (Category 5, function 101)
  405. ;
  406. IOC_S:    LES    DI,ES:[BX].P_DATA    ; verify access to data buffer
  407.     MOV    AX,ES
  408.     MOV    CX,1
  409.     MOV    DX,0100H+VerifyAccess
  410.     CALL    DEVHLP
  411.     JC    IOC3            ; branch if access denied
  412.     XOR    BX,BX            ; lock the data buffer segment
  413.     MOV    DL,LockSeg
  414.     CALL    DEVHLP
  415.     PUSH    AX            ; save lock handle
  416.     PUSH    BX
  417.     PUSH    DS            ; convert to physical address
  418.     MOV    AX,ES
  419.     MOV    DS,AX
  420.     MOV    SI,DI
  421.     MOV    DL,VirtToPhys
  422.     CALL    DEVHLP
  423.     POP    DS
  424.     MOV    DX,0100H+PhysToVirt    ; convert to virtual address
  425.     CALL    DEVHLP
  426.     JC    IOC4            ; branch if error
  427.     CLI                ; begin critical section
  428.     MOV    DX,IOLPT        ; get device status
  429.     INC    DX
  430.     IN    AL,DX
  431.     AND    AL,0F8H            ; save only important bits
  432.     XOR    AL,48H            ; toggle "acknowledge" and "error"
  433.     MOV    AH,STATUS        ; include "timer", "flush", "wait"
  434.     AND    AH,7
  435.     OR    AL,AH
  436.     MOV    ES:[DI],AL        ; return status in user's data area
  437.     STI                ; end critical section
  438.     MOV    DL,UnPhysToVirt        ; release mapping
  439.     CALL    DEVHLP
  440.     POP    BX            ; unlock data buffer segment
  441.     POP    AX
  442.     MOV    DL,UnlockSeg
  443.     CALL    DEVHLP
  444.     JMP    RETOK
  445. IOC4:    POP    BX            ; come here on error after lock
  446.     POP    AX
  447.     MOV    DL,UnlockSeg
  448.     CALL    DEVHLP
  449. IOC5:    JMP    ERRGEN
  450. ;
  451. ;
  452. ; Register a monitor (Category 10, function 64)
  453. ;
  454. IOC_R:    CALL    GETPID            ; get monitor process id
  455.     JC    IOC3            ; branch if error
  456.     LES    SI,ES:[BX].P_DATA    ; get data area address
  457.     MOV    DH,ES:[SI].R_POS    ; get postion code
  458.     MOV    DI,ES:[SI].R_OUT    ; get output buffer offset
  459.     LES    SI,ES:[SI].R_IN        ; get input buffer pointer
  460.     MOV    AX,MONHAN        ; get monitor handle
  461.     MOV    DL,Register        ; register this monitor
  462.     CALL    DEVHLP
  463.     JC    IOC5            ; branch if error
  464.     JMP    RETOK
  465. ;***************************************************************************
  466. ;
  467. ;
  468. ; S_RMV -- Remove (de-install) the driver
  469. ;
  470. S_RMV:    MOV    AX,MONHAN        ; kill monitor chain
  471.     OR    AX,AX
  472.     JZ    RMV1
  473.     MOV    DL,MonCreate        
  474.     CALL    DEVHLP
  475. RMV1:    MOV    BX,IOINT        ; detach from interrupt
  476.     OR    BX,BX
  477.     JZ    RMV2
  478.     MOV    DL,UnSetIRQ
  479.     CALL    DEVHLP
  480. RMV2:    JMP    RETOK
  481. ;
  482. ;***************************************************************************
  483. ;
  484. ; NOTIFY routine, called by monitor dispatcher when data is available.
  485. ;
  486. NOTIFY    PROC    FAR
  487.     TEST    MONR.M_FLAG,MF_OPEN
  488.     JNZ    N_OPEN            ; branch if "open" message
  489.     TEST    MONR.M_FLAG,MF_CLOS
  490.     JNZ    N_CLOS            ; branch if "close" message
  491.     TEST    MONR.M_FLAG,MF_FLSH
  492.     JZ    N_WRT            ; branch if "write" message
  493. ;
  494. ; Process "flush" message from the monitor chain
  495. ;
  496. N_FLSH:    AND    STATUS,NOT SF_FLSH    ; reset flush flag
  497.     JMP    RETOK
  498. ;
  499. ; Process "open" message from monitor chain
  500. ;
  501. N_OPEN:    JMP    RETOK
  502. ;
  503. ; Process "close" message from the monitor chain
  504. ;
  505. N_CLOS:    JMP    RETOK
  506. ;
  507. ; Process "write" message from the monitor chain
  508. ;
  509. N_WRT:    MOV    CX,MON            ; get message length
  510.     SUB    CX,MONHDR+2        ; subtract header and length word 
  511.     JBE    N03            ; branch if no data
  512.     XOR    SI,SI            ; reset data buffer index
  513. N00:    TEST    STATUS,SF_FLSH
  514.     JNZ    N03            ; abort if flush flag is set
  515.     MOV    DX,IOLPT        ; get printer address
  516.     INC    DX            ; check status
  517.     IN    AL,DX
  518.     TEST    AL,80H
  519.     JZ    N04            ; branch if not ready
  520. N01:    MOV    AL,MONR.M_DATA[SI]    ; send next byte
  521.     DEC    DX
  522.     OUT    DX,AL
  523.     INC    DX            ; strobe it out
  524.     INC    DX
  525.     MOV    AL,0DH
  526.     OUT    DX,AL
  527.     MOV    AX,10        
  528. N02:    DEC    AX
  529.     JNZ    N02
  530.     MOV    AL,0CH
  531.     OUT    DX,AL
  532.     INC    SI            ; loop till all bytes sent
  533.     LOOP    N00
  534. N03:    RETF                ; return to monitor dispatcher
  535. ;
  536. ; Come here to wait for printer interrupt
  537. ;
  538. N04:    CLI                ; begin critical section
  539.     INC    DX            ; enable printer interrupt
  540.     MOV    AL,1CH
  541.     OUT    DX,AL
  542.     DEC    DX            ; check status
  543.     IN    AL,DX
  544.     TEST    AL,80H
  545.     JZ     N05            ; branch if still busy
  546.     MOV    AL,0CH            ; disable printer interrupt
  547.     INC    DX
  548.     OUT    DX,AL
  549.     STI                ; leave critical section
  550.     JMP    N00            ; continue data output
  551. N05:    PUSH    CX            ; save registers
  552.     PUSH    SI
  553.     OR    STATUS,SF_WAIT        ; set "wait" status
  554.     MOV    AX,WORD PTR IOTADD+2    ; use I/O table address as event id
  555.     MOV    BX,WORD PTR IOTADD        
  556.     MOV    DI,WORD PTR IOTIME+2    ; load timeout value
  557.     MOV    CX,WORD PTR IOTIME
  558.     MOV    DX,Block        ; DH=0 for interruptable sleep
  559.     CALL    DEVHLP
  560.     CLI                ; begin critical section
  561.     JC    N07            ; branch if timeout or unusual event
  562.     TEST    STATUS,SF_WAIT
  563.     JNZ    N05            ; re-block if wrong event
  564. N06:    MOV    DX,IOLPT        ; disable printer interrupt
  565.     INC    DX
  566.     INC    DX
  567.     MOV    AL,0CH
  568.     OUT    DX,AL
  569.     STI                ; end critical section
  570.     JMP    N00            ; go send more data
  571. ;
  572. ; Come here if wait times out or is aborted by unusual event
  573. ;
  574. N07:    OR    STATUS,SF_TIME        ; set timer flag
  575.     MOV    AX,WORD PTR IOTADD+2    ; use I/O table address as event id
  576.     MOV    BX,WORD PTR IOTADD
  577.     XOR    DI,DI            ; set 500 ms timeout value
  578.     MOV    CX,500
  579.     MOV    DX,Block        ; DH=0 for interruptable sleep
  580.     CALL    DEVHLP
  581.     CLI                ; begin critical section
  582.     TEST    STATUS,SF_FLSH
  583.     JNZ    N08            ; branch if flush flag is set
  584.     TEST    STATUS,SF_WAIT
  585.     JNZ    N07            ; repeat if still waiting
  586.     XOR    STATUS,SF_TIME        ; reset timer flag
  587.     JMP    N06            ; continue data output
  588. ;
  589. ; Come here if operation is being flushed
  590. ;
  591. N08:    AND    STATUS,NOT (SF_TIME OR SF_WAIT)  ; reset flags
  592.     MOV    DX,IOLPT        ; disable printer interrupt
  593.     INC    DX
  594.     INC    DX
  595.     MOV    AL,0CH
  596.     OUT     DX,AL
  597.     STI                ; end critical section
  598.     RETF
  599.     
  600. NOTIFY    ENDP
  601. ;***************************************************************************
  602. ;
  603. ; I_LPT routine, called by hardware interrupt dispatcher
  604. ;
  605. I_LPT    PROC    FAR
  606.     TEST    STATUS,SF_WAIT
  607.     JZ    INT1            ; ignore if not in "wait" mode
  608.     XOR    STATUS,SF_WAIT        ; reset "wait" status
  609.     MOV    AX,WORD PTR IOTADD+2    ; wake up the NOTIFY routine
  610.     MOV    BX,WORD PTR IOTADD
  611.     MOV    DL,Run
  612.     CALL    DEVHLP
  613. INT1:    CLI                ; begin critical section
  614.     MOV    AX,IOINT        ; signal end-of-interrupt
  615.     MOV    DL,EOI
  616.     CALL    DEVHLP
  617.     CLC                ; clear CF to claim interrupt
  618.     RETF
  619. I_LPT    ENDP    
  620. ;***************************************************************************
  621. ;
  622. ; User interrupt routine, called by DOS application via interrupt 17H.
  623. ;
  624. U_LPT    PROC    FAR
  625.     STI                ; enable interrupts
  626.     PUSH    BP            ; save all registers
  627.     PUSH    ES
  628.     PUSH    DS
  629.     PUSH    DI
  630.     PUSH    SI
  631.     PUSH    DX
  632.     PUSH    CX
  633.     PUSH    BX
  634.     PUSH    AX
  635.     MOV    BX,CS:SAVEDS        ; set up DS for the driver
  636.     MOV    DS,BX
  637.     MOV    DX,IOLPT        ; get printer address
  638.     OR    AH,AH
  639.     JZ    U_WRT            ; AH=0 to print AL
  640.     DEC    AH
  641.     JZ    U_INIT            ; AH=1 to initialize
  642.     DEC    AH
  643.     JZ    U_STAT            ; AH=2 to get status
  644. U_RET:    POP    AX            ; return from interrupt
  645.     POP    BX
  646.     POP    CX
  647.     POP    DX
  648.     POP    SI
  649.     POP    DI
  650.     POP    DS
  651.     POP    ES
  652.     POP    BP
  653.     IRET
  654. ;
  655. ; Initialization routine saves DS here
  656. ;
  657. SAVEDS    DW    0            ; DS is saved here
  658. ;
  659. ; Come here to print the character in AL
  660. ;
  661. U_WRT:    MOV    AL,1            ; begin BIOS critical section
  662.     MOV    DL,ROMCritSect
  663.     CALL    DEVHLP
  664.     MOV    CX,MONHDR+1        ; set monitor message length
  665.     MOV    MONS.M_PID,0        ; use 0 for DOS process id
  666.     MOV    MONS.M_FLAG,0        ; reset flags
  667.     POP    AX            ; put byte into buffer
  668.     PUSH    AX
  669.     MOV    MONS.M_DATA,AL
  670.     LEA    SI,MONS            ; send message to monitor chain
  671.     MOV    AX,MONHAN
  672.     MOV    DX,MonWrite
  673.     CALL    DEVHLP
  674.     XOR    AL,AL            ; end BIOS critical section
  675.     MOV    DL,ROMCritSect
  676.     CALL    DEVHLP
  677. ;    JMP    U_STAT            ; go get status
  678. ;
  679. ; Come here to initialize the printer
  680. ;
  681. U_INIT:                    ; same as status request
  682. ;
  683. ; Come here to get printer status
  684. ;
  685. U_STAT:    CLI                ; begin critical section
  686.     MOV    DX,IOLPT        ; get device status
  687.     INC    DX
  688.     IN    AL,DX
  689.     AND    AL,0F8H            ; save only important bits
  690.     XOR    AL,48H            ; toggle "acknowledge" and "error"
  691.     MOV    AH,STATUS        ; include "timer", "flush", "wait"
  692.     AND    AH,7
  693.     OR    AL,AH
  694.     STI                ; end critical section
  695.     POP    BX            ; restore AH and set up AL return
  696.     MOV    AH,BH
  697.     PUSH    AX
  698.     JMP    U_RET
  699. U_LPT    ENDP
  700. ;
  701. ;***************************************************************************
  702. ;
  703. ; GETPID function, called to obtain current process id, which is returned
  704. ; in AX.  The function returns with CF set if an error occurs.
  705. ;
  706. GETPID    PROC    NEAR
  707.     PUSH    ES            ; save regs
  708.     PUSH    BX
  709.     PUSH    DX
  710.     MOV    AL,2            ; get address of process info pointer
  711.     MOV    DL,GetDOSVar
  712.     CALL    DEVHLP
  713.     JC    PID1            ; branch if error
  714.     PUSH    AX            ; get process info pointer in ES:BX
  715.     POP    ES
  716.     LES    BX,ES:[BX]
  717.     MOV    AX,ES:[BX]        ; PID is first word 
  718.     CLC                ; reset CF to indicate success
  719. PID1:    POP    DX            ; restore regs and return
  720.     POP    BX
  721.     POP    ES
  722.     RET    
  723. GETPID    ENDP
  724. ;***************************************************************************
  725. ;
  726. ; Mark the end of the code segment.  Everything after this is discarded
  727. ; after initialization.
  728. END_CS    EQU    $
  729. ;***************************************************************************
  730. ;
  731. ; S_INIT -- Initialize
  732. ;
  733. S_INIT:    MOV    AX,ES:[BX].P_HLP0    ; save DevHlp address
  734.     MOV    WORD PTR DEVHLP,AX
  735.     MOV    AX,ES:[BX].P_HLP1
  736.     MOV    WORD PTR DEVHLP+2,AX
  737.     LEA    AX,END_CS        ; return CS size
  738.     MOV    ES:[BX].P_HLP0,AX
  739.     LEA    AX,END_DS        ; return DS size
  740.     MOV    ES:[BX].P_HLP1,AX
  741. ;
  742. ; Check for valid I/O configuration
  743.     LES    DI,DWORD PTR IOTADD    ; get printer I/O address
  744.     MOV    DX,ES:[DI]        
  745.     MOV    AL,IOINT1        ; check if first parallel device
  746.     CMP    DX,IOLPT1
  747.     JE    IN01            ; branch if yes
  748.     MOV    AL,IOINT2        ; check if second parallel device
  749.     CMP    DX,IOLPT2
  750.     JNE    INERR            ; branch if no
  751. ;
  752. ; Initialize the I/O channel and device
  753. ;
  754. IN01:    MOV    IOLPT,DX        ; save I/O address
  755.     MOV    BYTE PTR IOINT,AL    ; save interrupt level
  756.     INC    DX            ; set DX to control port
  757.     INC    DX
  758.     MOV    AL,8            ; select and initialize
  759.     OUT    DX,AL
  760.     MOV    AX,1000            ; delay at least 50 microseconds
  761. IN02:    DEC    AX
  762.     JNZ    IN02
  763.     MOV    AL,12            ; select, no initialize, no auto LF
  764.     OUT    DX,AL
  765. ;
  766. ; Create monitor chain and save its handle
  767. ;
  768.     PUSH    DS            ; make ES:SI point to monitor buffer
  769.     POP    ES
  770.     LEA    SI,MON
  771.     PUSH    DS            ; save DS
  772.     PUSH    CS            ; make DS:DI point to notify routine
  773.     POP    DS
  774.     LEA    DI,NOTIFY
  775.     XOR    AX,AX            ; set AX=0 to create monitor chain
  776.     MOV    DL,MonCreate        ; call DEVHLP using ES instead of DS
  777.     CALL    ES:DEVHLP
  778.     POP    DS            ; restore DS
  779.     JC    INERR            ; branch if error
  780.     MOV    MONHAN,AX        ; save monitor handle    
  781. ;
  782. ; Activate the hardware interrupt
  783.     LEA    AX,I_LPT        ; get interrupt routine address
  784.     MOV    BX,IOINT        ; get interrupt level number
  785.     MOV    DX,SetIRQ        ; DH=0 for non-shared interrupt
  786.     CALL    DEVHLP
  787.     JC    IN03            ; branch if error
  788. ;
  789. ; Activate user interrupt 17H for printer BIOS
  790. ;
  791.     LEA    AX,U_LPT        ; get interrupt routine address
  792.     MOV    BX,17H            ; get interrupt number
  793.     LEA    SI,SAVEDS        ; get DS save location address
  794.     MOV    DL,SetROMVector        ; set the interrupt vector
  795.     CALL    DEVHLP
  796.     JMP    RETOK
  797. ;
  798. ; Come here on initialization error
  799. IN03:    MOV    AX,MONHAN        ; kill monitor chain
  800.     MOV    DL,MonCreate
  801.     CALL    DEVHLP
  802. INERR:    JMP    ERRGEN
  803. ;
  804. S_LPT    ENDP                ; end of main proc
  805. _TEXT   ENDS                        ; end of code segment
  806.     END                ; end of module
  807.  
  808.  
  809.  
  810.  
  811.