Reading CP Codes from LPT-port

Introduction

PS/2 machines send the CP codes during POST to the onboard LPT-port. With some hardware you should be able to track them easily and -probably- find out where your PS/2 hangs after Power on.

The requirements are rather low - and you should be able to handle a solder iron.

Method 1: Simple LED Decoder

This little piece of hardware helps, it is easy to create but a bit cryptic to read.

        D7   ....   D0      
         o 9   -  2 o       
         |   .....  |       
         |          |       
        +++        +++      
        | | 330R   | |      
        | |        | |      
        +++        +++      
         |          |       
         |          |       
       \-+-/      \-+-/     
        \|/ LED    \|/ LED  
       ----- 8    ----- 1   
         |          |       
         |          |       
   25 o--+-- ...  --+       


It is of some importance, that you arrange the LEDs D7 (data bit 7) to D0 (data bit 0) from left to right: the bit patterns then are in correct order and re-calculating them down to the CP-code isn't that hard to do.

If the bit pattern is for example:
8   4   2   1   |   8   4   2   1
----------------+----------------
#   o   o   #   |   o   #   o   #
----------------+----------------
D7  D6  D5  D4     D3  D2  D1  D0

You simply add the "bit values" for the first four bits (D7 - D4) and get "6" (4 + 2) and for the second four bits (D3 - D0) and get "A" (8 + 2 = 10 = hex A). So your CP code is "6A" - which were "Initialize Printer Parameter" in Stage-2 POST.

Method 2: "Hex-to-7-segment" decoder

The CP codes consist out of 2 x 4 bits, which range from "0" to "F" only. This is pretty simple to adapt - if you manage to get an appropriate decoder chip.
The very common TTL chip 74LS47 cannot be used for our purpose: it only decodes the numbers "0" - "9" properly and the hexadecimals "A" - "F" are invalid combinations and look crappy.
If you are lucky you get two of the old Motorola MC14495 hexadecimal to 7-segment decoder chips - but they are no longer manufactured by Motorola and no longer available.

A way out of this misery is using two specially programmed EPROM (one for each 4-bit code half) - like a 2716 2K x 8 bit EPROM - for that purpose. If you feed the 4-bit hex-code to the adresslines A0 - A3 with all other unsused adresslines tied to GND the datalines D0 - D6 can be used as 7-segment driver outputs. D7 is not used.

A detailed schematic diagram in PDF can be downloaded from here.

Method 3: "PC-to-PC connection"

Well - why bother with building some proprietary hardware... why not using a PC to read the CP codes?

Well - why not ? You only need a sort of adapter plug that allows to feed the 8 data lines from one PC to another - and a small software to read the data from the parallel port. Luckily all MCA PS/2 have a bi-directional printerport, tha allowes to send data as well as receiving data.

First the hardware part. I used a small 25-pin Sub-D "m/m gender changer" and modified the wiring inside. Then I plugged it at the end of a 3-meters 25-pin extension cable (f/m) to have 25-pin male plugs at each end.
The wiring of the adapter plug looks like that:

            +-----+                
 2 o--------+ 2K2 +--------o 2   D0
            +-----+                
                                   
               ...                 
                                   
            +-----+                
 9 o--------+ 2K2 +--------o 9   D7
            +-----+                
                                   
                                   
25 o-----------------------o 25 GND

The 2K2 resistors have been included to avoid damage on the printer interfaces for the case that both machines try to send signals ... this would otherwise damage the planar parallel port driver chips.

And then you need a piece of software to be able to read the incoming codes from the printer port. A simple example in BASIC is this below:

(everything after the ' is a comment)

10 CLS                                ' clears screen
20 DEF SEG=0                          ' sets the segment address
30 LPTD=PEEK(&H408)+256*PEEK(&H409)   ' determines address of LPT1
40 LPTC=LPTD+2                        ' and its control-register
50 OUT LPTC,(PEEK(LPTC) OR 32)        ' bit 5 set to 1 all other bits maintained
60 B=0                                ' set a dummy variable
70 A=INP(LPTD)                        ' read from LPT1 dataregister
75 IF INKEY$=CHR$(27) THEN END        ' press ESC to stop program
80 CP$=HEX$(A)                        ' convert value to hex
90 IF LEN(CP$)<>2 THEN CP$=STRING$(2-LEN(CP$),"0")+CP$ ' adjust length
100 IF A=B GOTO 70                    ' stored data hasn't changed
110 PRINT CP$;" : ";                  ' print value
120 B=A                               ' save value for comparison
130 GOTO 70                           ' next read
140 END                               ' end program

As said: this is just an example in BASIC - if you can do better in C++ or Pascal or Assembler ... give it a try. The important point is the correct order of the LPT-port addresses. You could of cause use another LPT-port too - if there is one and if it is bi-directional.

Good luck and success!

Content created and/or collected by:
Louis Ohland, Peter Wendt, William Walsh, Kevin Bowling, Jim Shorney, Tim Clarke, David Beem, Tatsuo Sunagawa, Tomáš Slavotínek, and many others.

Ardent Tool of Capitalism - MAD Edition! is maintained by Tomáš Slavotínek.
Last update: 03 Mar 2021 - Changes & Credits | Legal Info & Contact