Parallel Ports integrated onto motherboards, upon which their configuration can be changed using BIOS.
LPT1 is normally assigned base address 378h, while LPT2 is assigned 278h. However this may not always be the case as explained later. 378h & 278h have always been commonly used for Parallel Ports. The lower case h denotes that it is in hexadecimal. These addresses may change from machine to machine.
Address |
Notes: |
3BCh - 3BFh |
Used for Parallel Ports which were incorporated on to Video Cards - Doesn't support ECP addresses |
378h - 37Fh |
Usual Address For LPT 1 |
278h - 27Fh |
Usual Address For LPT 2 |
Table Port Addresses
When the computer is first turned on, BIOS (Basic Input/Output System) will determine the number of ports you have and assign device labels LPT1, LPT2 & LPT3 to them. BIOS first looks at address 3BCh. If a Parallel Port is found here, it is assigned as LPT1, then it searches at location 378h. If a Parallel card is found there, it is assigned the next free device label. This would be LPT1 if a card wasn't found at 3BCh or LPT2 if a card was found at 3BCh. The last port of call, is 278h and follows the same procedure than the other two ports. Therefore it is possible to have a LPT2 which is at 378h and not at the expected address 278h.
What can make this even confusing, is that some manufacturers of Parallel Port Cards, have jumpers which allow you to set your Port to LPT1, LPT2, LPT3. Now what address is LPT1? - On the majority of cards LPT1 is 378h, and LPT2, 278h, but some will use 3BCh as LPT1, 378h as LPT1 and 278h as LPT2.
The assigned devices LPT1, LPT2 & LPT3 should not be a worry to people wishing to interface devices to their PC's. Most of the time the base address is used to interface the port rather than LPT1 etc. However should you want to find the address of LPT1 or any of the Line Printer Devices, you can use a lookup table provided by BIOS. When BIOS assigns addresses to your printer devices, it stores the address at specific locations in memory, so we can find them.
Start Address |
Function |
0000:0408 |
LPT1's Base Address |
0000:040A |
LPT2's Base Address |
0000:040C |
LPT3's Base Address |
0000:040E |
LPT4's Base Address (Note 1) |
Table - LPT Addresses in the BIOS Data Area;
Note 1 : Address 0000:040E in the BIOS Data Area may be used as the Extended Bios Data Area in PS/2 and newer Bioses.
The above table, table 3, shows the address at which we can find the Printer Port 's addresses in the BIOS Data Area. Each address will take up 2 bytes.
Software Registers - Standard Parallel Port (SPP)
Offset |
Name |
Read/Write |
Bit No. |
Properties |
Base + 0 |
Data Port |
Write (Note-1) |
Bit 7 |
Data 7 |
Bit 6 |
Data 6 |
|||
Bit 5 |
Data 5 |
|||
Bit 4 |
Data 4 |
|||
Bit 3 |
Data 3 |
|||
Bit 2 |
Data 2 |
|||
Bit 1 |
Data 1 |
|||
Bit 0 |
Data 0 |
Table Data Port
The base address, usually called the Data Port or Data Register is simply used for outputting data on the Parallel Port 's data lines (Pins 2-9). This register is normally a write only port. If you read from the port, you should get the last byte sent. However if your port is bi-directional, you can receive data on this address. See Bi-directional Ports for more detail.
Offset |
Name |
Read/Write |
Bit No. |
Properties |
Base + 1 |
Status Port |
Read Only |
Bit 7 |
Busy |
Bit 6 |
Ack |
|||
Bit 5 |
Paper Out |
|||
Bit 4 |
Select In |
|||
Bit 3 |
Error |
|||
Bit 2 |
IRQ (Not) |
|||
Bit 1 |
Reserved |
|||
Bit 0 |
Reserved |
Table Status Port
The Status Port (base address + 1) is a read only port. Any data written to this port will be ignored. The Status Port is made up of 5 input lines (Pins 10,11,12,13 & 15), a IRQ status register and two reserved bits. Please note that Bit 7 (Busy) is a active low input. E.g. If bit 7 happens to show a logic 0, this means that there is +5v at pin 11. Likewise with Bit 2. (nIRQ) If this bit shows a '1' then an interrupt has not occurred.
Offset |
Name |
Read/Write |
Bit No. |
Properties |
Base + 2 |
Control Port |
Read/Write |
Bit 7 |
Unused |
Bit 6 |
Unused |
|||
Bit 5 |
Enable Bi-Directional Port |
|||
Bit 4 |
Enable IRQ Via Ack Line |
|||
Bit 3 |
Select Printer |
|||
Bit 2 |
Initialize Printer (Reset) |
|||
Bit 1 |
Auto Linefeed |
|||
Bit 0 |
Strobe |
Table Control Port
The Control Port (base address + 2) was intended as a write only port. When a printer is attached to the Parallel Port , four "controls" are used. These are Strobe, Auto Linefeed, Initialize and Select Printer, all of which are inverted except Initialize.
The printer would not send a signal to initialize the computer, nor would it tell the computer to use auto linefeed. However these four outputs can also be used for inputs. If the computer has placed a pin high (e.g. +5v) and your device wanted to take it low, you would effectively short out the port, causing a conflict on that pin. Therefore these lines are "open collector" outputs (or open drain for CMOS devices). This means that it has two states. A low state (0v) and a high impedance state (open circuit).
Normally the Printer Card will have internal pull-up resistors, but as you would expect, not all will. Some may just have open collector outputs, while others may even have normal totem pole outputs. In order to make your device work correctly on as many Printer Ports as possible, you can use an external resistor as well. Should you already have an internal resistor, then it will act in Parallel with it, or if you have Totem pole outputs, the resistor will act as a load.
An external 4.7k resistor can be used to pull the pin high. I wouldn't use anything lower, just in case you do have an internal pull up resistor, as the external resistor would act in parallel giving effectively, a lower value pull up resistor. When in high impedance state the pin on the Parallel Port is high (+5v). When in this state, your external device can pull the pin low and have the control port change read a different value. This way the 4 pins of the Control Port can be used for bi-directional data transfer. However the Control Port must be set to xxxx0100 to be able to read data, that is all pins to be +5v at the port so that you can pull it down to GND (logic 0).
Bits 4 & 5 are internal controls. Bit four will enable the IRQ (See Using the Parallel Ports IRQ) and Bit 5 will enable the bi-directional port meaning that you can input 8 bits using (DATA0-7). This mode is only possible if your card supports it. Bits 6 & 7 are reserved. Any writes to these two bits will be ignored.
Bi-directional Ports
The schematic diagram below, shows a simplified view of the Parallel Port 's Data Register. The original Parallel Port card's implemented 74LS logic. These days all this is crammed into one ASIC, but the theory of operation is still the same.
The non bi-directional ports were manufactured with the 74LS374's output enable tied permanent low, thus the data port is always output only. When you read the Parallel Port 's data register, the data comes from the 74LS374 which is also connected to the data pins. Now if you can overdrive the '374 you can effectively have a Bi-directional Port. (or a input only port, once you blow up the latches output!)
What is very concerning is that people have actually done this. I've seen one circuit, a scope connected to the Parallel Port distributed on the Internet. The author uses an ADC of some type, but finds the ADC requires transistors on each data line, to make it work! No wonder why. Others have had similar trouble, the 68HC11 cannot sink enough current (30 to 40mA!)
Bi-directional ports use Control Bit 5 connected to the 374's Output Enable so that it's output drivers can be turned off. This way you can read data present on the Parallel Port 's Data Pins, without having bus conflicts and excessive current drains.
Bit 5 of the Control Port enables or disables the bi-directional function of the Parallel Port. This is only available on true bi-directional ports. When this bit is set to one, pins 2 to 9 go into high impedance state. Once in this state you can enter data on these lines and retrieve it from the Data Port (base address). Any data which is written to the data port will be stored but will not be available at the data pins. To turn off bi-directional mode, set bit 5 of the Control Port to '0'.
However not all ports behave in the same way. Other ports may require setting bit 6 of the Control Port to enable Bi-directional mode and setting of Bit 5 to disenable Bi-directional mode, Different manufacturers implement their bi-directional ports in different ways. If you wish to use your Bi-directional port to input data, test it with a logic probe or multi-meter first to make sure it is in bi-directional mode.
Using The Parallel Port to Input 8 Bits.
If your Parallel Port doesn't support bi-directional mode, don't despair. You can input a maximum of 9 bits at any one given time. To do this you can use the 5 input lines of the Status Port and the 4 inputs (open collector) lines of the Control Port.

The inputs to the Parallel Port have been chosen as such, to make life easier for us. Busy just happens to be the MSB (Bit 7) of the Status Port , then in ascending order comes Ack, Paper Out and Select, making up the most significant nibble of the Control Port. The Bars are used to represent which inputs are Hardware inverted, i.e. +5v will read 0 from the register, while GND will read 1. The Status Port only has one inverted input.
The Control port is used to read the least significant nibble. As described before, the control port has open collector outputs, i.e. two possible states, high impedance and GND. If we connect our inputs directly to the port (For example an ADC0804 with totem pole outputs), a conflict will result if the input is high and the port is trying to pull it down. Therefore we use open collector inverters.
However this is not always entirely necessary. If we were connecting single pole switches to the port with a pull up resistor, then there is no need to bother with this protection. Also if your software initializes the control port with xxxx0100 so that all the pins on the control port are high, then it may be unnecessary. If however you don't bother and your device is connected to the Parallel Port before your software has a chance to initialize then you may encounter problems.
Another problem to be aware of is the pull up resistors on the control port. The average pull-up resistor is 4.7k. In order to pull the line low, your device will need to sink 1mA, which some low powered devices may struggle to do. Now what happens if I suggest that some ports have 1K pull up resistors? Yes, there are such cards. Your device now has to sink 5mA. More reason to use the open collector inverters.
Open collector inverters were chosen over open collector buffers as they are more popular, and thus easier to obtain. There is no reason, however why you can't use them. Another possibility is to use transistors.
The input, D3 is connected via the inverter to Select Printer. Select Printer just happens to be bit 3 of the control port. D2, D1 & D0 are connected to Init, Auto linefeed and strobe, respectively to make up the lower nibble. Now this is done, all we have to do is assemble the byte using software. The first thing we must do is to write xxxx0100 to the Control Port. This places all the control port lines high, so they can be pulled down to input data.
outportb(CONTROL, inportb(CONTROL) & 0xF0 | 0x04);
Now that this is done, we can read the most significant nibble. This just happens to be the most significant nibble of the status port. As we are only interested in the MSnibble we will AND the results with 0xF0, so that the LSnibble is clear. Busy is hardware inverted, but we won't worry about it now. Once the two bytes are constructed, we can kill two birds with one stone by toggling Busy and Init at the same time.
a = (inportb(STATUS) & 0xF0); /* Read MSnibble */
We can now read the LSnibble. This just happens to be LSnibble of the control port - How convenient! This time we are not interested with the MSnibble of the port, thus we AND the result with 0x0F to clear the MSnibble. Once this is done, it is time to combine the two bytes together. This is done by OR'ing the two bytes. This now leaves us with one byte, however we are not finished yet. Bits 2 and 7 are inverted. This is overcome by XOR'ing the byte with 0x84, which toggles the two bits.
a = a |(inportb(CONTROL) & 0x0F); /* Read LSnibble */
a = a ^ 0x84; /* Toggle Bit 2 & 7 */
Nibble Mode
Nibble mode is the preferred way of reading 8 bits of data without placing the port in reverse mode and using the data lines. Nibble mode uses a Quad 2 line to 1 line multiplexer to read a nibble of data at a time. Then it "switches" to the other nibble and reads its. Software can then be used to construct the two nibbles into a byte. The only disadvantage of this technique is that it is slower. It now requires a few I/O instructions to read the one byte, and it requires the use of an external IC.
The operation of the 74LS157, Quad 2 line to 1 line multiplexer is quite simple. It simply acts as four switches. When the A/B input is low, the A inputs are selected. E.g. 1A passes through to 1Y, 2A passes through to 2Y etc. When the A/B is high, the B inputs are selected. The Y outputs are connected up to the Parallel Port 's status port, in such a manner that it represents the MSnibble of the status register. While this is not necessary, it makes the software easier.
To use this circuit, first we must initialize the multiplexer to switch either inputs A or B. We will read the LSnibble first, thus we must place A/B low. The strobe is hardware inverted, thus we must set Bit 0 of the control port to get a low on Pin 1.
outportb(CONTROL, inportb(CONTROL) | 0x01); /* Select Low Nibble (A)*/
Once the low nibble is selected, we can read the LSnibble from the Status Port. Take note that the Busy Line is inverted, however we won't tackle it just yet. We are only interested in the MSnibble of the result, thus we AND the result with 0xF0, to clear the LSnibble.
a = (inportb(STATUS) & 0xF0); /* Read Low Nibble */
Now it's time to shift the nibble we have just read to the LSnibble of variable a,
a = a >> 4; /* Shift Right 4 Bits */
We are now half way there. It's time to get the MSnibble, thus we must switch the multiplexer to select inputs B. Then we can read the MSnibble and put the two nibbles together to make a byte,
outportb(CONTROL, inportb(CONTROL) & 0xFE); /* Select High Nibble (B)*/
a = a |(inportb(STATUS) & 0xF0); /* Read High Nibble */
byte = byte ^ 0x88;
The last line toggles two inverted bits which were read in on the Busy line. It may be necessary to add delays in the process, if the incorrect results are being returned.
Using the Parallel Port 's IRQ
The Parallel Port 's interrupt request is not used for printing under DOS or Windows. Early versions of OS-2 used them, but don't anymore. Interrupts are good when interfacing monitoring devices such as high temp alarms etc, where you don't know when it is going to be activated. It's more efficient to have an interrupt request rather than have the software poll the ports regularly to see if something has changed. This is even more noticeable if you are using your computer for other tasks, such as with a multitasking operating system.
The Parallel Port 's interrupt request is normally IRQ5 or IRQ7 but may be something else if these are in use. It may also be possible that the interrupts are totally disabled on the card, if the card was only used for printing. The Parallel Port interrupt can be disabled and enabled using bit 4 of the control register, Enable IRQ Via Ack Line. Once enabled, an interrupt will occur upon a low to high transition (rising edge) of the nACK. However like always, some cards may trigger the interrupt on the high to low transition.
The following code is an Interrupt Polarity Tester, which serves as two things. It will determine which polarity your Parallel Port interrupt is, while also giving you an example for how to use the Parallel Port 's Interrupt. It checks if your interrupt is generated on the rising or falling edge of the nACK line. To use the program simply wire one of the Data lines (Pins 2 to 9) to the Ack Pin (Pin 10). The easiest way to do this is to bridge some solder from DATA7 (Pin 9) to ACK (Pin 10) on a male DB25 connector.
Parallel Port Modes in BIOS
Today, most Parallel Ports are multimode ports. They are normally software configurable to one of many modes from BIOS. The typical modes are,
Printer Mode (Sometimes called Default or Normal Modes)
Standard & Bi-directional (SPP) Mode
- EPP1.7 and SPP Mode
- EPP1.9 and SPP Mode
- ECP Mode
- ECP and EPP1.7 Mode
- ECP and EPP1.9 Mode
Printer Mode is the most basic mode. It is a Standard Parallel Port in forward mode only. It has no bi-directional feature, thus Bit 5 of the Control Port will not respond. Standard & Bi-directional (SPP) Mode is the bi-directional mode. Using this mode, bit 5 of the Control Port will reverse the direction of the port, so you can read back a value on the data lines.
EPP1.7 and SPP Mode is a combination of EPP 1.7 ( Enhanced Parallel Port ) and SPP Modes. In this mode of operation you will have access to the SPP registers (Data, Status and Control) and access to the EPP Registers. In this mode you should be able to reverse the direction of the port using bit 5 of the control register. EPP 1.7 is the earlier version of EPP. This version, version 1.7, may not have the time-out bit.
EPP1.9 and SPP Mode is just like the previous mode, only it uses EPP Version 1.9 this time. As in the other mode, you will have access to the SPP registers, including Bit 5 of the control port. However this differs from EPP1.7 and SPP Mode as you should have access to the EPP Timeout bit.
ECP Mode will give you an Extended Capabilities Port. The mode of this port can then be set using the ECP's Extended Control Register (ECR). However in this mode from BIOS the EPP Mode (100) will not be available.
ECP and EPP1.7 Mode and ECP and EPP1.9 Mode will give you an Extended Capabilities Port , just like the previous mode. However the EPP Mode in the ECP's ECR will now be available. Should you be in ECP and EPP1.7 Mode you will get an EPP1.7 Port, or if you are in ECP and EPP1.9 Mode, an EPP1.9 Port will be at your disposal.
The above modes are configurable via BIOS. You can reconfigure them by using your own software, but this is not recommended. These software registers, typically found at 0x2FA, 0x3F0, 0x3F1 etc are only intended to be accessed by BIOS. There is no set standard for these configuration registers, thus if you were to use these registers, your software would not be very portable. With today's multitasking operating systems, its also not a good idea to change them when it suits you.
A better option is to select ECP and EPP1.7 Mode or ECP and EPP1.9 Mode from BIOS and then use the ECP's Extended Control Register to select your Parallel Port 's Mode. The EPP1.7 mode had a few problems in regards to the Data and Address Strobes being asserted to start a cycle regardless of the wait state, thus this mode if not typically used now. Best set your Parallel Port to ECP and EPP1.9 Mode.
Parallel Port Modes and the ECP's Extended Control Register
As we have just discussed, it is better to set the Parallel Port to ECP and EPP1.9 Mode and use the ECP's Extended Control Register to select different modes of operation. The ECP Registers are standardized under Microsoft's Extended Capabilities Port Protocol and ISA Interface Standard, thus we don't have that problem of every vendor having their own register set.
When set to ECP Mode, a new set of registers become available at Base + 0x400h. A discussion of these registers are available in Interfacing the Extended Capabilities Port . Here we are only interested in the Extended Control Register (ECR) which is mapped at Base + 0x402h. It should be stated that the ECP's registers are not available for port's with a base address of 0x3BCh.
Bit |
Function |
|
7:5 |
Selects Current Mode of Operation |
|
000 |
Standard Mode |
|
001 |
Byte Mode |
|
010 |
Parallel Port FIFO Mode |
|
011 |
ECP FIFO Mode |
|
100 |
EPP Mode |
|
101 |
Reserved |
|
110 |
FIFO Test Mode |
|
111 |
Configuration Mode |
|
4 |
ECP Interrupt Bit |
|
3 |
DMA Enable Bit |
|
2 |
ECP Service Bit |
|
1 |
FIFO Full |
|
0 |
FIFO Empty |
|
Table - Extended Control Register (ECR)
The table above is of the Extended Control Register. We are only interested in the three MSB of the Extended Control Register which selects the mode of operation. There are 7 possible modes of operation, but not all ports will support all modes. The EPP mode is one such example, not being available on some ports.
Modes of Operation |
|
Standard Mode |
Selecting this mode will cause the ECP port to behave as a Standard Parallel Port , without bi-directional functionality. |
Byte Mode / PS/2 Mode |
Behaves as a SPP in bi-directional mode. Bit 5 will place the port in reverse mode. |
Parallel Port FIFO Mode |
In this mode, any data written to the Data FIFO will be sent to the peripheral using the SPP Handshake. The hardware will generate the handshaking required. Useful with non-ECP devices such as Printers. You can have some of the features of ECP like FIFO buffers and hardware generation of handshaking but with the existing SPP handshake instead of the ECP Handshake. |
ECP FIFO Mode |
Standard mode for ECP use. This mode uses the ECP Handshake described in Interfacing the Extended Capabilities Port. - When in ECP Mode though BIOS, and the ECR register is set to ECP FIFO Mode (011), the SPP registers may disappear. |
EPP Mode/Reserved |
This will enable EPP Mode, if available. Under BIOS, if ECP mode is set then it's more than likely, this mode is not an option. However if BIOS is set to ECP and EPP1.x Mode, then EPP 1.x will be enabled. - Under Microsoft's Extended Capabilities Port Protocol and ISA Interface Standard this mode is Vendor Specified. |
Reserved |
Currently Reserved. - Under Microsoft's Extended Capabilities Port Protocol and ISA Interface Standard this mode is Vendor Specified. |
FIFO Test Mode |
While in this mode, any data written to the Test FIFO Register will be placed into the FIFO and any data read from the Test FIFO register will be read from the FIFO buffer. The FIFO Full/Empty Status Bits will reflect their true value, thus FIFO depth, among other things can be determined in this mode. |
Configuration Mode |
In this mode, the two configuration registers, cnfgA & cnfgB become available at their designated register addresses. |
If you are in ECP Mode under BIOS, or if your card is jumpered to use ECP then it is a good idea to initialize the mode of your ECP port to a pre-defined state before use. If you are using SPP, then set the port to Standard Mode as the first thing you do. Don't assume that the port will already be in Standard (SPP) mode.
Under some of the modes, the SPP registers may disappear or not work correctly. If you are using SPP, then set the ECR to Standard Mode. This is one of the most common mistakes that people make.