I hope the following information helps those who wish to
make use of the Parallel printer port. The .INC file was
created so that the parallel port could be used for generating
and reading TTL signals to test electronic assemblies not for
driving a printer. The electronics for expanding the I/O
capabilities of the parallel port is quite simple, up to
128 inputs or outputs.
Using multi-threaded code, it is possible to use both parallel
and serial ports almost simultaneously. This is not so easy to
do under DOS. However DOS has some advantages in some applications.

NOTE. NT will object to the code in the .INC file.

The following relates to using the EPP mode paralell port,
although some is relevant to SPP mode ports.

The paralel port consists of 3 registers, Data, status and control.
EPP mode ports support 8 bit bidirectional data transfer, whilst SPP
mode ports only support 8 bit output. (Pins 2 - 9 = D0 - D7,
pins 18 - 25 = 0V).
Both types support another 4 bit output controlled via the control
register (pins 1, 14, 16,17) and a 5 bit input via the status register
(pins 10, 11, 12, 13, 15)

CONTROL REGISTER.
Bit 0 This bit (STB pin 1) directly controls the strobe signal.
It is the inverse of the /STB pin.
This signal latches data into the printer.

Bit 1 This bit (AFXT pin 14) directly controls the automatic feed
XT signal. It is the inverse of the /AFXT pin.
Setting this bit Hi causes the printer to automatically feed
after each line is printed.

Bit 2 This bit (/INIT pin 16) directly controls the initialize
signal. This bit follows the /INIT pin.
Setting this bit Lo initializes the printer.

Bit 3 This bit (/SLIN pin 17) controls the select in signal.
This bit is the inverse of the /SLIN pin.
setting this bit Hi selects the printer.

Bit 4 This bit enables the parallel port interupt. Setting
this bit Lo puts IRQ5,7 into tri-state and clears any
pending iterupts. When this bit is set Hi, the IRQ signal follows
the /ACK signal (AT comapatible mode) transitions.
In extended mode it also latches Hi on a 0 to 1 transition.

Bit 5 This bit determines the parallel port direction. This is a
write only bit. Set this bit Lo for output, Hi for input.

Bit 6 Reserved. Always 1

Bit 7 Reserved. Always 1

STATUS REGISTER.
Bit 0 Reserved. Always 1

Bit 1 Reserved. Always 1

Bit 2 In compatible mode this bit is always 1.
In extended mode this bit is the IRQ status bit. If bit 4 of
the control register is set Hi, then this bit is latched low
when the /ACK signal makes a transition from Lo to Hi.
Reading this bit set it Hi.

Bit 3 This bit repesents the current state of the printer error
signal (/ERR pin 15). The printer sets this bit Lo when
ther is a printer error. This bit follows the state of the
/ERR pin.

Bit 4 This bit respresents the current state of the printer select
signal (SLCT pin 13). This bit follows the state of the
SCLT pin.

Bit 5 This bit represents the current state of the printer paper
end signal (PE pin 12). The printer sets this bit Hi when it
detects the end of paper. This bit follows the state of the
PE pin.

Bit 6 This bit represents the current state of the printer acknowledge
signal (/ACK pin 10). The printer pulses this signal Lo after
it has received a character and is ready to receive another one.
This bit follows the state of the /ACK pin.

Bit 7 This bit represents the current state of the printer busy signal
(/BUSY pin 11). The printer sets this bit Lo when it is busy and
cannot accept another character. This bit is the inverse of of the
BUSY pin.

DATA REGISTER.
Bits D0 to D7
In the extended mode a write operation to the data register will
latch the data. If bit 5 of the control register is set Lo the
data is presented on the connector pins; if it is Hi it is only
latched.
When bit 5 of the control register is Lo a read operation to this
register allows the last data written to be read.
When bit 5 of the control register is set Lo, a read operation on
this register represents the current state of the data present on
the port (bits D0 to D7, Pins 2 to 9).

ADDRESSES
In PC's with only 1 paralell port LPT1 is usually at &H0378
although this is not always the case and yuor code needs to verify
the address's. Valid addresses are &H03BC, &H0378, &H0278.
These are the addresses of the data registers, the status registers
are the above addresses +1 and the control registers +2.


' Declares and I/O Procedures for WIN95/98
' For PBDLL32 BY J M Hutchins 14/10/1999

'Legal Stuff.
'
'This code is supplied as is.
'The Author accepts no liability for loss, injury, damage, war, divorce or anything else.
'It is the responsibility of the user of the following code or any fragments of the
'following code, to ensure its suitability for the use to which it is put.
'-------------------------------------------------------------------------------------------------

%OutMode = 0 'use as ReturnMode flags
%InMode = 1

'------------------------------------------------------------------------------------------------
' TITLE: OutLpt1
' DESC: Outputs data (ByteValue) to parallel printer port (PortNumber) without changing the
' control register/outputs. (ReturnMode) specifies whether the data port is left in
' input or output mode on return.
' SYNTAX: OutLpt1 PortNumber,ByteValue,ReturnMode
' NOTES: This procedure is for use with EPP mode parallel ports but will also work with SPP mode.

DECLARE SUB OutLpt1(BYVAL PortNumber AS INTEGER,BYVAL ByteValue AS BYTE,BYVAL ReturnMode AS INTEGER)

SUB OutLpt1(BYVAL PortNumber AS INTEGER,BYVAL ByteValue AS BYTE,BYVAL ReturnMode AS INTEGER)

LOCAL OriControlValue AS BYTE
LOCAL ControlValue AS BYTE
LOCAL ControlMask AS BYTE
LOCAL Value AS BYTE
LOCAL PortAddress AS INTEGER
LOCAL ControlAddress AS INTEGER

SELECT CASE Portnumber

CASE 1
PortAddress = &h03bc

CASE 2
PortAddress = &h0378

CASE 3
PortAddress = &h0278

END SELECT

ControlAddress = PortAddress + 2
ControlMask = 223'31

! push dx
! mov dx, ControlAddress
! in al,dx
! mov Controlvalue, al
! pop dx
OriControlValue = ControlValue
ControlValue = ControlValue AND ControlMask

! push dx
! mov dx,ControlAddress
! mov al,ControlValue
! out dx,al
! mov dx,PortAddress
! mov al,ByteValue
! out dx,al
! pop dx

SELECT CASE ReturnMode

CASE %OutMode
ControlValue = OriControlValue AND ControlMask

! push dx
! mov dx, ControlAddress
! mov al,ControlValue
! out dx,al
! pop dx

CASE %Inmode
ControlValue = (OriControlValue AND ControlMask) + 32

! push dx
! mov dx, ControlAddress
! mov al,ControlValue
! out dx,al
! pop dx

END SELECT

END SUB

'------------------------------------------------------------------------------------------------
' TITLE: InLpt1
' DESC: Returns data present on parallel printer port (PortNumber) without changing the
' control register/outputs. (ReturnMode) specifies whether the data port is left in
' input or output mode on return.
' SYNTAX: InLpt1 PortNumber,ReturnMode TO Variable?
' NOTES: This procedure is for use with EPP mode parallel ports, it will NOT work with SPP mode.
'

DECLARE FUNCTION InLpt1(BYVAL PortNumber AS INTEGER,BYVAL ReturnMode AS INTEGER) AS BYTE

FUNCTION InLpt1(BYVAL PortNumber AS INTEGER,BYVAL ReturnMode AS INTEGER) AS BYTE

LOCAL OriControlValue AS BYTE
LOCAL ControlValue AS BYTE
LOCAL ControlMask AS BYTE
LOCAL WriteBit AS BYTE
LOCAL ByteValue AS BYTE
LOCAL PortAddress AS INTEGER
LOCAL ControlAddress AS INTEGER

SELECT CASE Portnumber

CASE 1
PortAddress = &h03bc

CASE 2
PortAddress = &h0378

CASE 3
PortAddress = &h0278

END SELECT

ControlAddress = PortAddress + 2
ControlMask = 223'31
WriteBit = 32 '32 = read 0 = write

! push dx
! mov dx, ControlAddress
! in al,dx
! mov Controlvalue, al
! pop dx

OriControlValue = ControlValue
ControlValue = ControlValue AND ControlMask
ControlValue = ControlValue + WriteBit

! push dx
! mov dx,ControlAddress
! mov al,ControlValue
! out dx,al
! mov dx,PortAddress
! in al,dx
! mov ByteValue ,al
! pop dx

SELECT CASE ReturnMode

CASE %OutMode
ControlValue = OriControlValue AND ControlMask

! push dx
! mov dx, ControlAddress
! mov al,ControlValue
! out dx,al
! pop dx

CASE %Inmode
ControlValue = (OriControlValue AND ControlMask) + 32

! push dx
! mov dx, ControlAddress
! mov al,ControlValue
! out dx,al
! pop dx
END SELECT

FUNCTION = ByteValue
END FUNCTION

'------------------------------------------------------------------------------------------------
' TITLE: InLpt2
' DESC: Returns data present on parallel printer port (PortNumber) after changing the
' control register/outputs. (ReturnMode) specifies whether the data port is left in
' input or output mode on return.
' SYNTAX: InLpt2 PortNumber,ControlByte,ReturnMode TO Variable?
' NOTES: This procedure is for use with EPP mode parallel ports, it will NOT work with SPP mode.
' Bits 0 - 3 of ControlByte are passed as you want the output pin states. ie. ignor inversions.

DECLARE FUNCTION InLpt2(BYVAL PortNumber AS INTEGER,BYVAL ControlByte AS BYTE, BYVAL ReturnMode AS INTEGER) AS BYTE

FUNCTION InLpt2(BYVAL PortNumber AS INTEGER,BYVAL ControlByte AS BYTE, BYVAL ReturnMode AS INTEGER) AS BYTE

LOCAL OriControlValue AS BYTE
LOCAL ControlValue AS BYTE
LOCAL ControlMask AS BYTE
LOCAL ByteValue AS BYTE
LOCAL PortAddress AS INTEGER
LOCAL ControlAddress AS INTEGER

SELECT CASE Portnumber

CASE 1
PortAddress = &h03bc

CASE 2
PortAddress = &h0378

CASE 3
PortAddress = &h0278

END SELECT

ControlAddress = PortAddress + 2
ControlMask = 11
ControlValue = (ControlByte XOR ControlMask) + 192

! push dx
! mov dx,ControlAddress
! mov al,ControlValue
! out dx,al
! mov dx,PortAddress
! in al,dx
! mov ByteValue,al
! pop dx

SELECT CASE ReturnMode

CASE %OutMode
ControlValue = ControlValue AND 223

! push dx
! mov dx, ControlAddress
! mov al,ControlValue
! out dx,al
! pop dx

CASE %Inmode
ControlValue = (ControlValue AND 223) + 32

! push dx
! mov dx, ControlAddress
! mov al,ControlValue
! out dx,al
! pop dx

END SELECT

FUNCTION = ByteValue
END FUNCTION

'------------------------------------------------------------------------------------------------
' TITLE: OutLpt2
' DESC: Outputs data (ByteValue) to parallel printer port (PortNumber) after changing the
' control register/outputs to (ControlByte). (ReturnMode) specifies whether the data
' port is left in input or output mode on return.
' SYNTAX: OutLpt PortNumber,ByteValue,ContrlByte,ReturnMode
' NOTES: This procedure is for use with EPP mode parallel ports but will also work with SPP mode.
' Bits 0 - 3 of ControlByte are passed as you want the output pin states. ie. ignor inversions.

DECLARE SUB OutLpt2(BYVAL PortNumber AS INTEGER,BYVAL ByteValue AS BYTE,BYVAL ControlByte AS BYTE, BYVAL ReturnMode AS INTEGER)

SUB OutLpt2(BYVAL PortNumber AS INTEGER,BYVAL ByteValue AS BYTE,BYVAL ControlByte AS BYTE, BYVAL ReturnMode AS INTEGER)

LOCAL OriControlValue AS BYTE
LOCAL ControlValue AS BYTE
LOCAL ControlMask AS BYTE
LOCAL PortAddress AS INTEGER
LOCAL ControlAddress AS INTEGER

SELECT CASE Portnumber

CASE 1
PortAddress = &h03bc

CASE 2
PortAddress = &h0378

CASE 3
PortAddress = &h0278

END SELECT

ControlAddress = PortAddress + 2
ControlMask = 11
ControlValue = (ControlByte XOR ControlMask) + 192

! push dx
! mov dx,ControlAddress
! mov al,ControlValue
! out dx,al
! mov dx,PortAddress
! mov al,ByteValue
! out dx,al
! pop dx

SELECT CASE ReturnMode

CASE %OutMode
ControlValue = ControlValue AND 223

! push dx
! mov dx, ControlAddress
! mov al,ControlValue
! out dx,al
! pop dx

CASE %Inmode
ControlValue = (ControlValue AND 223) + 32

! push dx
! mov dx, ControlAddress
! mov al,ControlValue
! out dx,al
! pop dx

END SELECT

END SUB

'------------------------------------------------------------------------------------------------
' TITLE: LptReadStat
' DESC: Returns data present on parallel printer port (PortNumber) status pins/status register.
' SYNTAX: LptReadStat PortNumber TO Variable?
' NOTES: This procedure is for use with EPP mode parallel ports but will also work with SPP mode.
' Bit 0 & 1 reserved
' Bit 2 = IRQ Status bit. Reading this bit sets it to a hi.( best ignored.)
' Bit 3 = ERR This bit follows the state of the ERR pin on the signal on the LPT connector.
' Bit 4 = SLCT This bit follows the state of the SLCT pin on the signal on the LPT connector.
' Bit 5 = PE This bit follows the state of the PE pin on the signal on the LPT connector.
' Bit 6 = ACK This bit follows the state of the ACK pin on the signal on the LPT connector.
' Bit 7 = BUSY This bit is the inverse of the state of the BUSY pin on the signal on the LPT connector.
' Bit 7 of return value is state of input pin (busy). ie. ignor inversion

DECLARE FUNCTION LptReadStat(BYVAL PortNumber AS INTEGER) AS BYTE

FUNCTION LptReadStat(BYVAL PortNumber AS INTEGER) AS BYTE

LOCAL StatAddress AS INTEGER
LOCAL PortAddress AS INTEGER
LOCAL Value AS BYTE

SELECT CASE Portnumber

CASE 1
PortAddress = &h03bc

CASE 2
PortAddress = &h0378

CASE 3
PortAddress = &h0278

END SELECT

StatAddress = PortAddress + 1

! push dx
! mov dx, StatAddress
! in al,dx
! mov Value,al
! pop dx

FUNCTION = Value XOR 128
END FUNCTION

'------------------------------------------------------------------------------------------------
' TITLE: LptReadControlReg
' DESC: Returns data from the parallel printer port control register.
' SYNTAX: LptReadControlReg PortNumber TO Variable?
' NOTES: This procedure is for use with EPP mode parallel ports.
' Bit 0 = STB The signal on the LPT connector is the inverse of the register setting.
' Bit 1 = AFD The signal on the LPT connector is the inverse of the register setting.
' Bit 2 = INIT The signal on the LPT connector is the same as that of the register
' setting.
' Bit 3 = SLIN The signal on the LPT connector is the inverse of the register setting.
' Bit 4 = IntEN This bit enables the parallel port interupt. Setting this bit lo puts
' IRQ5,7 in tristate and clears any pending interupts.
'
' Bit 5 = PPD This bit is write only see SUB LptWriteControlReg.
' Bits 6 & 7 reserved always hi.
' The result is returned as: bits 0 to 3 - state of output pins
' bits 4 to 7 - as register contents.

DECLARE FUNCTION LptReadControlReg(BYVAL PortNumber AS INTEGER) AS BYTE

FUNCTION LptReadControlReg(BYVAL PortNumber AS INTEGER) AS BYTE

LOCAL ControlValue AS BYTE
LOCAL ControlMask AS BYTE
LOCAL PortAddress AS INTEGER
LOCAL ControlAddress AS INTEGER

SELECT CASE Portnumber

CASE 1
PortAddress = &h03bc

CASE 2
PortAddress = &h0378

CASE 3
PortAddress = &h0278

END SELECT

ControlAddress = PortAddress + 2
ControlMask = 11

! push dx
! mov dx, ControlAddress
! in al,dx
! mov Controlvalue, al
! pop dx

FUNCTION = ControlValue XOR ControlMask
END FUNCTION

'------------------------------------------------------------------------------------------------
' TITLE: LptWriteControlReg
' DESC: Writes data (ControlByte)to parallel printer port (PortNumber) control pins/control register.
' SYNTAX: LptWriteControlReg PortNumber, ControlByte
' NOTES: This procedure is for use with EPP mode parallel ports,it NOT work with SPP mode.
' Bit 0 = STB The signal on the LPT connector is the inverse of the register setting.
' Bit 1 = AFD The signal on the LPT connector is the inverse of the register setting.
' Bit 2 = INIT The signal on the LPT connector is the same as that of the register
' setting.
' Bit 3 = SLIN The signal on the LPT connector is the inverse of the register setting.
' Bit 4 = IntEN This bit enables the parallel port interupt. Setting this bit lo puts
' IRQ5,7 in tristate and clears any pending interupts.
'
' Bit 5 = PPD Sets data port direction. lo = output, hi = input.
' Bits 6 & 7 reserved always hi.
' Bits 0 - 3 of ControlByte are passed as you want the output pin states. ie. ignor inversions.


DECLARE SUB LptWriteControlReg(BYVAL PortNumber AS INTEGER, BYVAL ControlByte AS BYTE,BYVAL ReturnMode AS INTEGER)

SUB LptWriteControlReg(BYVAL PortNumber AS INTEGER, BYVAL ControlByte AS BYTE,BYVAL ReturnMode AS INTEGER)

LOCAL ControlMask AS BYTE
LOCAL PortAddress AS INTEGER
LOCAL ControlAddress AS INTEGER
LOCAL ControlValue AS BYTE
LOCAL OriControlMask AS BYTE

OriControlMask = 192
ControlMask = 11

SELECT CASE Portnumber

CASE 1
PortAddress = &h03bc

CASE 2
PortAddress = &h0378

CASE 3
PortAddress = &h0278

END SELECT

ControlAddress = PortAddress + 2
! push dx
! mov dx, ControlAddress
! in al,dx
! mov Controlvalue, al
! pop dx

ControlValue = ControlValue AND OriControlMask
ControlByte = (ControlByte XOR ControlMask)+(ControlValue AND OriControlMask)

SELECT CASE ReturnMode

CASE %OutMode
ControlByte = ControlByte AND 223

CASE %Inmode
ControlByte = ControlByte + 32

END SELECT

! push dx
! mov dx,ControlAddress
! mov al,ControlByte
! out dx,al
! pop dx

END SUB

'------------------------------------------------------------------------------------------------
' TITLE: Out32
' DESC: Writes data (ByteValue)to I/O port (PortAddress).
' SYNTAX: Out32 PortAddress, ByteValue
' NOTES: This procedure is for use with I/O ports using 8 bit data ie. ISA expansion cards.
' This procedure may also be used to write data to SPP mode parallel ports

DECLARE SUB Out32(BYVAL PortAddress AS INTEGER,BYVAL ByteValue AS BYTE)

SUB Out32(BYVAL PortAddress AS INTEGER,BYVAL ByteValue AS BYTE)

! push dx
! mov dx,PortAddress
! mov al,ByteValue
! out dx,al
! pop dx

END SUB


'------------------------------------------------------------------------------------------------
' TITLE: In32
' DESC: Returns data from I/O port (PortAddress).
' SYNTAX: In32 PortAddress TO Variable?
' NOTES: This procedure is for use with I/O ports using 8 bit data ie. ISA expansion cards.
' This procedure may also be used to return the last data written to a SPP mode parallel
' port. It will NOT work with EPP mode parallel ports.


DECLARE FUNCTION In32(BYVAL PortAddress AS INTEGER) AS BYTE

FUNCTION In32(BYVAL PortAddress AS INTEGER) AS BYTE
LOCAL ByteValue AS BYTE

! push dx
! mov dx,PortAddress
! in al,dx
! mov ByteValue,al
! pop dx

FUNCTION = ByteValue
END FUNCTION





------------------