📄 lpt_pkg.asm
字号:
INCLUDE C:TITLE.MAC
.TITLE <LPT_PKG -- LPT1: Routines for Lattice C>
.SBTTL <History and Copyright Notice>
; lpt_pkg.asm 18 Nov 83 Craig Milo Rogers at USC/ISI
; Use int_pkg routines to set/restore interrupt vectors.
; lpt_pkg.asm 16 Nov 83 Craig Milo Rogers at USC/ISI
; Converted to PDP-11-like TITLEs.
; Converted to STRUCT for control data.
; lpt_pkg.asm 9 Nov 83 Craig Milo Rogers at USC/ISI
; Created from com_pkg.asm.
;
; These routines provide an interrupt-driven circular buffer
; interface to the LPT1: device. This version interfaces with the
; multi-model Lattice C compiler version 1.05. This package was
; adapted from the "com_pkg", which in turn was adapted from "COMM-PKG".
; See below:
;
; COM_PKG1 provides a library of serial port routines
; Adapted from code by John Romkey and Jerry Saltzer of MIT
; by Richard Gillmann (GILLMANN@ISIB), 1983
;
.SBHED Overview
; This is a module of routines for interfacing with the
; LPT1: communications interface on the IBM PC. The code has
; been carefully constructed to properly drive the printer interface
; and the 8259 Interrupt Controller. Internal circular buffers
; are used for transmit and receive.
; Only one LPT: is supported at present. A unit number is
; included in the calls to provide for multiple-printer support in
; the future.
; The LPT: interrupt source is the -ACKNOWLEGE signal from
; the printer. In the case of the Epson MX and FX printers, -ACKNOWLEGE
; goes active (low) for 5 usec when a character has been processed,
; then returns to inactive (high). Since the -ACKNOWLEGE signal is
; inverted by the printer interface card before it is presented to
; the IRQ7 line on the IBM-PC's bus, it is the high-to-low transition
; of -ACKNOWLEGE which causes the low-to-high transition of IRQ7, which
; in turn triggers the interrupt sequence in the 8259. This, in turn,
; triggers an interrupt sequence in the 8088 processor.
;
; Thus, it is the high-to-low transition of -ACKNOWLEGE which
; starts the interrupt sequence. However, since -ACKNOWLEGE is low
; for only 5 usec, it may have returned to its high state before the
; 8088 sends INTA to the 8259 to acknowlege the interrupt. This is
; a violation of the 8259 specification. The 8259 will then generate
; a "DEFAULT" interrupt request cycle, instead of a normal IR7 cycle.
; However, since the DEFAULT cycle just happens to be IR7, too, it
; all works out OK.
;
; The 8259's restriction on IRn pulse length is intended to
; catch static on the IRn lines, and/or malfunctioning devices.
; It is entirely possible that a DEFAULT IR7 may be generated for
; some reason other than the line printer. The line printer interrupt
; routine attempts to protect against this case by checking the
; BUSY bit in the interface. Everything would probably work a lot
; better if the line printer interface fed the -ACKNOWLEGE signal
; directly to IR7, instead of inverting it first.
; Entry points (Lattice C 1.05 calling conventions):
; void
; lpt_ini(unit, tbuf, tbuflen, pinit)
; /* Initializes port and interrupt vector. */
; int unit; /* 1 ==> LPT1:, 2 ==> LPT2:. */
; char *tbuf; /* Transmit buffer address. */
; int tbuflen; /* Transmit buffer length. */
; bool pinit; /* TRUE ==> force printer initialization. */
; void
; lpt_trm(unit) /* Turns off interrupts from the aux port. */
; int unit; /* 1 ==> LPT1:, 2 ==> LPT2:. */
; int /* Number of free bytes in output buffer. */
; lpt_ocnt(unit) /* Returns number of free bytes in output buffer. */
; int unit; /* 1 ==> LPT1:, 2 ==> LPT2:. */
; bool /* Returns FALSE if no more room. */
; lpt_putc(unit, ch) /* Writes a character to the output buffer. */
; int unit; /* 1 ==> LPT1:, 2 ==> LPT2:. */
; char ch; /* The character to write. */
; int /* Returns printer status bits. */
; lpt_stat(unit) /* Reads printer hardware status. */
; int unit; /* 1 ==> LPT1:, 2 ==> LPT2:. */
.SBHED Declarations
IF1
INCLUDE DOS.MAC ; C segments.
INCLUDE BMAC.MAC ; C calling conventions.
ENDIF
; int_pkg routines:
BEXTRN INT_SETU ; Setup an interrupt vector.
BEXTRN INT_REST ; Restore an interrupt vector.
; LPT: parameters:
LPT_INT EQU 7 ; Interrupt number for printer port.
PRINTER_BASE EQU 408H ; Address of BIOS table containing
; the addresses of the printers.
INT_OFF EQU 08H ; Converts 8029 interrupt numbers to
; 8088 interrupt numbers.
; Printer device registers:
DATREG EQU 0H ; Data register.
STATREG EQU 1H ; Status bits from the printer.
CMDREG EQU 2H ; Command bits to the printer.
; Printer status bits:
BUSY EQU 80H ; Printer is busy, issue no commands.
ACK EQU 40H ; Printer ready acknowlegement pulse.
PAPER EQU 20H ; Paper end -- out of paper.
SELECTD EQU 10H ; Printer is selected.
ERR EQU 08H ; Error line.
; Printer command bits:
IRQE EQU 10H ; Interrupt request enable.
SELECT EQU 08H ; Select input to printer.
INIT EQU 04H ; Initialize printer.
AUTOF EQU 02H ; Auto line feed after carriage return.
STROBE EQU 01H ; Data strobe pulse.
; 8259 interrupt controller:
IMR EQU 21H ; Interrupt mask register.
OCW2 EQU 20H ; Operational control word.
EOI EQU 60H ; Specific end of interrupt.
; Interface to C language
TRUE EQU 1 ; Truth.
FALSE EQU 0 ; Falsehood.
LPTX_CTRL STRUC ; Line printer control structure:
TBUF_SEG DW ? ; Transmit buffer segment number.
TBUF_OFF DW ? ; Transmit buffer offset.
TBUF_SIZE DW ? ; Transmit buffer size.
START_TDATA DW ? ; Index to first character in x-mit buffer.
END_TDATA DW ? ; Index to first free space in x-mit buffer.
SIZE_TDATA DW ? ; Number of characters in x-mit buffer.
LPTX_BASE DW ? ; I/O base address of printer registers.
LPTX_CTRL ENDS ; End of the LPT control structure.
.SBHED <Data Storage>
DSEG
LPT1_CTRL LPTX_CTRL <> ; Control parameters for LPT1:
ENDDS
PSEG ; All the rest is code.
.SBHED <LPT: Interrupt Handler>
;
; INT_HNDLR - Handles Interrupts Generated by LPT:
;
; WARNING!
; Note the impure use of DATASEG below. This code is not ROMmable.
;
; There is no provision for recovery in the face of printer errors.
;
DATASEG DW 0 ; Holds our data segment number.
INT_HNDLR PROC FAR ;;; Enter here on interrupt.
PUSH DS ;;; Save data segment register.
PUSH CS:DATASEG ;;; Set up new data segment.
POP DS ;;;
PUSH ES ;;; Save previous context on existing stack.
PUSH BP ;;;
PUSH SI ;;;
PUSH DI ;;;
PUSH AX ;;;
PUSH BX ;;;
PUSH CX ;;;
PUSH DX ;;;
MOV SI,OFFSET LPT1_CTRL ;;; Setup pointer to control structure.
;;; Clear the interrupt request first
;;; so new request pulses will not
;;; be ignored.
MOV DX,OCW2 ;;; Tell the 8259 that I'm done.
MOV AL,EOI ;;; Get the End-of-Interrupt code.
OR AL,LPT_INT ;;; Set to specific int. number.
OUT DX,AL ;;;
REPOLL:
MOV DX,[SI].LPTX_BASE ;;; Get LPT: base register.
ADD DX,CMDREG ;;; Point to command bits.
IN AL,DX ;;; Read the command bits.
TEST AL,IRQE ;;; Is interrupt request enable on?
JZ INT_END ;;; No, return from interrupt.
ADD DX,(STATREG-CMDREG) ;;; Point to status bits.
IN AL,DX ;;; Read the status bits.
TEST AL,BUSY ;;; Is the printer still busy?
JZ INT_END ;;; Yes, ignore this interrupt.
GOODTX: CMP [SI].SIZE_TDATA,0 ;;; See if any more data to send.
JNE HAVE_DATA ;;; If not equal then there is data to send.
;;; If no data to send then reset tx interrupt and return.
ADD DX,(CMDREG-STATREG) ;;;
MOV AL,(SELECT+INIT) ;;;
OUT DX,AL ;;;
JMP SHORT INT_END ;;;
HAVE_DATA:
MOV ES,[SI].TBUF_SEG ;;; Get transmit buffer segment number.
MOV DI,[SI].TBUF_OFF ;;; Get transmit buffer offset.
MOV BX,[SI].START_TDATA ;;; BX points to next char. to be sent.
MOV DX,[SI].LPTX_BASE ;;;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -