Files
2024-02-19 00:25:23 -05:00

404 lines
16 KiB
Plaintext

PC Parallel Port Mini-FAQ
By Kris Heidenstrom (kheidens@actrix.gen.nz), revision 7, 19960430
In no event shall the author be liable for any damages whatsoever
for any loss relating to this document. Use it at your own risk!
1. INTRO
This is a six printed page mini-FAQ with basic information on the
PC parallel port. Many subjects are not covered in detail. View
on an 80-column monospaced screen with 8-column tab stops.
Comments, corrections, suggestions to kheidens@actrix.gen.nz.
A parallel port links software to the real world. To software, the
parallel port is three 8-bit registers occupying three consecutive
addresses in the I/O space. To hardware, the port is a female 25-pin
D-sub connector, carrying twelve latched outputs from the computer,
accepting five inputs into the computer, with eight ground lines.
The normal function of the port is to transfer data to a parallel
printer through the eight data pins, using the remaining signals as
flow control and miscellaneous controls and indications.
The original port was implemented with TTL/LS logic. Modern ports
are implemented in an ASIC or a combined serial/parallel port chip,
but are backward compatible. Many modern ports are bidirectional
and may have extended functionality (see section >> 5). The body
of this document applies to standard and PS/2 ports only.
2. BIOS LPT PORT TABLE
A parallel port is identifed by its I/O base address, and also by its
LPT port number. The BIOS power-on self-test checks specific I/O
addresses for the presence of a parallel port, and builds a table of
I/O addresses in the low memory BIOS data area, starting at address
0040:0008 (or 0000:0408).
This table contains up to three 16-bit words (four on some BIOSes).
Each entry gives the I/O base address of a parallel port. The first
word is the I/O base address of LPT1, the second is LPT2, etc.
If less than three ports were found, the remaining entries in the
table are zero. DOS, and the BIOS printer functions (accessed via
int 17h), use this table to translate an LPT port number to a
physical port at a certain address.
The power-on self-test checks these addresses in a specific order,
and addresses are put into the table as they are found, so the table
will never have gaps. A particular I/O address does not necessarily
always equate to the same specific LPT port number, although there
are conventions.
2.1 ADDRESSING CONVENTIONS
The video card's parallel port is normally at 3BCh. This address is
checked first by the BIOS, so if a port exists there, it will be LPT1.
The BIOS then checks at 378h, then at 278h. AFAIK there is no
standard address for a fourth port.
3. DIRECT HARDWARE ACCESS
The port consists of three 8-bit registers at adjacent addresses in
the processor's I/O space. The registers are defined relative to
the I/O base address, and are at IOBase+0, IOBase+1, and IOBase+2
(for example if IOBase is 3BCh, then the registers are at 3BCh,
3BDh, and 3BEh). Always use 8-bit I/O accesses on these registers.
3.1 DATA REGISTER
The data register is at IOBase+0. It may be read and written (using
the IN and OUT instructions, or inportb() and outportb() or inp()
and outp()). Writing a byte to this register causes the byte value
to appear on pins 2 through 9 of the D-sub connector (unless the port
is bidirectional and is set to input mode). The value will remain
latched and stable until you write another value to the data
register. Reading this register yields the state of those pins.
7 6 5 4 3 2 1 0
* . . . . . . . D7 (pin 9), 1=High, 0=Low
. * . . . . . . D6 (pin 8), 1=High, 0=Low
. . * . . . . . D5 (pin 7), 1=High, 0=Low
. . . * . . . . D4 (pin 6), 1=High, 0=Low
. . . . * . . . D3 (pin 5), 1=High, 0=Low
. . . . . * . . D2 (pin 4), 1=High, 0=Low
. . . . . . * . D1 (pin 3), 1=High, 0=Low
. . . . . . . * D0 (pin 2), 1=High, 0=Low
3.2 STATUS REGISTER
The status register is at IOBase+1. It is read-only (writes will be
ignored). Reading the port yields the state of the five status input
pins on the parallel port connector at the time of the read access:
7 6 5 4 3 2 1 0
* . . . . . . . Busy . . (pin 11), high=0, low=1 (inverted)
. * . . . . . . Ack . . (pin 10), high=1, low=0 (true)
. . * . . . . . No paper (pin 12), high=1, low=0 (true)
. . . * . . . . Selected (pin 13), high=1, low=0 (true)
. . . . * . . . Error. . (pin 15), high=1, low=0 (true)
. . . . . * * * Undefined
3.3 CONTROL REGISTER
The control register is at IOBase+2. It is read/write:
7 6 5 4 3 2 1 0
* * . . . . . . Unused (undefined on read, ignored on write)
. . * . . . . . Bidirectional enable on PS/2 ports, see below
. . . * . . . . Interrupt control, 1=enable, 0=disable
. . . . * . . . Select . . (pin 17), 1=low, 0=high (inverted)
. . . . . * . . Initialize (pin 16), 1=high, 0=low (true)
. . . . . . * . Auto Feed (pin 14), 1=low, 0=high (inverted)
. . . . . . . * Strobe . . (pin 1), 1=low, 0=high (inverted)
3.3.1 BIDIRECTIONAL CONTROL BIT (PS/2 PORTS)
See section >> 5.1 for details.
3.3.2 INTERRUPT ENABLE BIT
The parallel port interrupt was intended to be used for interrupt
driven transmission of data to a parallel printer, but is not used
by DOS and BIOS. Versions of OS/2 prior to Warp (3.0) did require
the interrupt for printing, but from Warp onwards the interrupt is
not required (though it can be used if the /IRQ switch is provided
on the line in CONFIG.SYS, i.e. BASEDEV=PRINT0x.SYS /IRQ).
For experimenters, the interrupt facility is useful as a general
purpose externally triggerable interrupt input. Beware though,
not all cards support the parallel port interrupt.
The interrupt control bit controls a tristate buffer that drives the
IRQ line. Setting the bit to '1' enables the buffer, and an IRQ will
be triggered on each falling edge (high to low transition) of the Ack
signal on pin 10 of the 25-pin connector. Disabling the interrupt
allows other devices to use the IRQ line.
The actual IRQ number is either hardwired (by convention, the port at
3BCh uses IRQ7) or jumper-selectable (IRQ5 is a common alternative).
Sound cards, in particular, tend to use IRQ7 for their own purposes.
To use the IRQ you must also enable the interrupt via the interrupt
mask register in the interrupt controller, at I/O address 21h, and
your interrupt handler must send an EOI on exit. DOS technical
programming references have notes on writing interrupt handlers.
3.3.3 PRINTER CONTROL BITS
The bottom four bits are latched and presented on the parallel port
connector, much like the data register. Three of them are inverted,
so writing a '1' will output a low voltage on the port pin for them.
These four outputs are open collector outputs with pullup resistors,
so an external device can force them low (only) without stressing the
driver in the PC, and they can even be used as inputs.
To use them as inputs, write 0100 binary to the bottom four bits of
the control register. This sets the outputs all high, so they are
pulled high by the pullup resistors (typically 4700 ohms). An
external device can then pull them low, and you can read the pin
states by reading the control register. Remember to allow for the
inversion on three of the pins.
If you are using this technique, the control register is not strictly
'read/write', because you may not read what you write (or wrote).
4 TRANSFERRING DATA VIA THE PARALLEL PORT
Many parallel ports are still the standard (send-only) type.
Data can be transferred between such ports via a PC-to-PC parallel
cable as used with INTERLNK, Laplink, and FastLynx, which links five
data outputs from one end to the five status inputs on the other and
vice versa (see section >> 4.1). Data is transferred four bits at a
time using the fifth bits for handshaking. See section >> 4.2.
Another method (which will also work with all port types) links eight
data bits across to five status inputs and three control lines, which
are used as inputs (see section >> 3.3.3). Other methods yielding a
higher data rate can be used if both ports are bidirectional. The
EPP and ECP have special hardware support for higher speeds (around
1MB/s) and the ECP (see section >> 5.3) also supports high-speed data
transfer using DMA.
4.1 FILE TRANSFER PROGRAM CABLES
The parallel-to-parallel cable is used by DOS's INTERLNK program.
Laplink and FastLynx cables are the same. The pin-to-pin connection
between two male 25-pin D-sub connectors is: 2-15, 3-13, 4-12, 5-10,
6-11, and the reverse: 15-2, 13-3, 12-4, 10-5, and 11-6, and 25-25.
This requires eleven wires. If you have spare wires, link some extra
grounds together. Pins 18 to 25 inclusive are grounds. A very long
cable may be unreliable; limit it to 5 metres, preferably less.
4.2 TRANSFERRING DATA USING STANDARD PARALLEL PORTS
These sample functions use the cable described above and work with
any parallel port. Data is sent four bits at a time, using the
fifth lines in each direction as data strobe and acknowledge
respectively. This is sometimes called 'nibble mode'.
These sample functions send and receive a byte of data. One program
must be the sender, the other must be the receiver. receive_byte()
will be used only on the receiver. transmit_byte() will be used only
on the sender, and will not return until the byte has been received
and acknowledged by the receiver. input_value() is used on both
sender and receiver. In a practical program like INTERLNK, protocols
are required to control the data direction.
--------------------------- snip snip snip ---------------------------
static unsigned int lpt_base; /* Set to base I/O address */
/* Return input value as five-bit number. If input has changed since
this function was last called, verify that the input is stable. */
unsigned int input_value(void) {
static unsigned char last_value = 0xFF;
auto unsigned char new1, new2;
new1 = inportb(lpt_base + 1) & 0xF8;
if (new1 != last_value) {
while (1) {
new2 = inportb(lpt_base + 1) & 0xF8;
if (new2 == new1) /* Wait for stable value */
break;
new1 = new2;
}
last_value = new1;
}
return (last_value ^ 0x80) >> 3;
}
/* Receive an 8-bit byte value, returns -1 if no data available yet */
signed int receive_byte(void) {
unsigned int portvalue, bytevalue;
portvalue = input_value(); /* Read input */
if ((portvalue & 0x10) == 0)
return -1; /* Await high flag */
outportb(lpt_base, 0x10); /* Assert reverse flag */
bytevalue = portvalue & 0x0F; /* Keep low nibble */
do {
portvalue = input_value();
} while ((portvalue & 0x10) != 0); /* Await low flag */
outportb(lpt_base, 0); /* Deassert reverse flag */
bytevalue |= (portvalue << 4); /* High nibble */
return bytevalue & 0xFF;
}
/* Transmit an 8-bit byte value, won't return until value is sent */
void transmit_byte(unsigned int val) {
val &= 0xFF;
outportb(lpt_base, (val & 0x0F) | 0x10); /* Set nibble flag */
while ((input_value() & 0x10) == 0)
; /* Await returned flag high */
outportb(lpt_base, val >> 4); /* Clear nibble flag */
while ((input_value() & 0x10) != 0)
; /* Await returned flag low */
return;
}
--------------------------- snip snip snip ---------------------------
5 SPECIAL PORTS
5.1 BIDIRECTIONAL PORTS (PS/2 AND COMPATIBLE)
The data register on bidirectional ports becomes an input port while
input mode is selected. In this state, the outputs of the buffer that
drives pins 2-9 of the 25-pin connector go into a high-impedance state
and these pins become inputs which may be driven by an external device
without stressing or damaging the driver. Values written to the data
register are stored, but not asserted on the connector. Reading the
data register yields the states of the pins at the time of the access.
This allows data to be received (or transferred between two ports of
this type) one byte at a time. This transfer mode is called byte mode.
Some parallel port cards may require a jumper change to allow input
mode to be selected. Machines with a parallel port integrated on
the motherboard may provide a BIOS setting to enable and disable
bidirectional capability.
Bidirectional ports (PS/2 and compatible) use control register bit
5 (see section >> 3.3) to enable input mode (input mode is enabled
while this bit is set to 1). Other ports with input mode capability
may enable input mode via a different signal, but I have no details.
5.2 SAMPLE PROGRAM - DISPLAY PORT TYPES
This program reports for LPT1, LPT2, and LPT3 whether the port exists
and whether input mode is enabled by setting the bidirectional control
bit in the control register. This only works on some bidirectional
ports, so the program will report 'non-bidirectional or in standard
mode' for ports that are bidirectional or enhanced, if input mode is
not controlled by control register bit 5.
This program was written for Borland C. Change outportb() to outp()
and inportb() to inp() for Microsoft C, I think. Save this code to
BIDIR.C and compile with:
bcc -I<include_path> -L<library_path> bidir.c
--------------------------- snip snip snip ---------------------------
#include <dos.h>
#include <process.h>
#include <stdio.h>
/* The following function returns the I/O base address of the nominated
parallel port. The input value must be 1 to 3. If the return value
is zero, the specified port does not exist. */
unsigned int get_lptport_iobase(unsigned int lptport_num) {
return *((unsigned int far *)MK_FP(0x40, 6) + lptport_num);
}
/* Checks whether the port's data register retains data, returns 1 if
so, 0 if not. The data register retains data on non-bidirectional
ports, but on bidirectional ports in high impedance (tri-state)
mode, the data register will not retain data. */
unsigned int test_retention(unsigned int iobase) {
outportb(iobase, 0x55); /* Write a new value */
(void) inportb(iobase); /* Delay */
if (inportb(iobase) != 0x55) {
return 0; /* Did not retain data */
}
outportb(iobase, 0xAA); /* Write another new value */
(void) inportb(iobase); /* Delay */
if (inportb(iobase) != 0xAA) {
return 0; /* Did not retain data */
}
return 1; /* Retained data alright */
}
void report_port_type(unsigned int portnum) {
unsigned int iobase, oldctrl, oldval;
iobase = get_lptport_iobase(portnum);
if (iobase == 0) {
printf("LPT%d does not exist\n", portnum);
return;
}
oldctrl = inportb(iobase+2);
outportb(iobase+2, oldctrl & 0xDF); /* Bidir off */
(void) inportb(iobase); /* Delay */
oldval = inportb(iobase); /* Keep old data */
if (test_retention(iobase) == 0) {
printf("LPT%d is faulty or set to input mode\n", portnum);
outportb(iobase+2, oldctrl);
outportb(iobase, oldval);
return;
}
outportb(iobase+2, oldctrl | 0x20); /* Bidir on for some ports */
if (test_retention(iobase))
printf("LPT%d is non-bidirectional or in standard mode\n", portnum);
else
printf("LPT%d is bidirectional using control port bit 5\n", portnum);
outportb(iobase+2, oldctrl); /* Put it back */
outportb(iobase, oldval); /* Restore data */
return;
}
void main(void) {
unsigned int portnum;
for (portnum = 1; portnum < 4; ++portnum)
report_port_type(portnum);
exit(0);
}
--------------------------- snip snip snip ---------------------------
5.3 ENHANCED PORTS
The major types of parallel ports are:
Name Bidir? DMA?
---- ------ ----
Standard No No
Bidirectional (PS/2) Yes No
EPP (Enhanced Parallel Port) Yes(*) No
ECP (Extended Capabilities Port) Yes(*) Yes
The PS/2 bidirectional port is a standard port with input mode
capability, enabled via bit 5 of the control register, see sections
>> 5.1 and >> 3.3.
The EPP (Enhanced Parallel Port) and ECP (Extended Capabilities Port)
are described in the IEEE 1284 standard of 1994, which gives the
physical, I/O and BIOS interfaces. Both are backward-compatible with
the original parallel port, and add special modes which include
bidirectional data transfer capability. These modes support fast
data transfer between computers and printers and between computers,
and support multiple printers or other peripherals on the same port.
In their enhanced modes, they re-define the control and status lines
of the parallel port connector, using it as a slow multiplexed
parallel bus. The ECP supports DMA (direct memory access) for
automated high-speed data transfer.
A very thorough and good reference on all port types is at:
http://www.fapo.com/1284int.htm.
End of the PC Parallel Port Mini-FAQ version 7