_STRUCTURED PROGRAMMING COLUMN_ by Jeff Duntemann [LISTING ONE] PROGRAM LoopTest; { From "Structured Programming" DDJ 7/91 } CONST UART : ARRAY[0..4] OF STRING = (' faulty','n 8250',' 16450',' 16550',' 16550A'); VAR PortNum : Byte; {-----------------------------------------------------------------} { FUNCTION DetectComPort by Jeff Duntemann } { This function returns a Boolean value indicating whether or not } { a National Semiconductor UART (one of 8250B, 16450, 16550, or } { 16550A) is present at the COM port passed in the PortNumber } { parameter. Don't run this function on serial ports that may be } { operating in some sort of background mode; it will probably } { disrupt any communication stream currently in progress. } {-----------------------------------------------------------------} FUNCTION DetectComPort(PortNumber : Integer) : Boolean; CONST LOOPBIT = $10; PortBases : ARRAY[1..4] OF Integer = ($03F8,$02F8,$03E8,$02E8); { COM1 COM2 COM3 COM4 } VAR Holder,HoldMCR,HoldMSR : Byte; MCRPort,MSRPort,THRPort,RBRPort : Integer; BEGIN { Calculate port numbers for the port being looked for: } RBRPort := PortBases[PortNumber]; { RBR is at the base address } THRPort := RBRPort; { RBR and THR have same I/O address } MCRPort := RBRPort + 4; { MCR is at offset 4 } MSRPort := RBRPort + 6; { MSR is at offset 6 } { Put the UART into loopback test mode: } HoldMCR := Port[MCRPort]; { Save existing value of MCR } Port[MCRPort] := HoldMCR OR LOOPBIT; { Turn on loopback test mode } HoldMSR := Port[MSRPort]; Port[MCRPort] := $0A OR LOOPBIT; { Put pattern to low 4 bits of MCR } { without disabling loopback mode } Holder := Port[MSRPort] AND $F0; { Read pattern from hi 4 bits of MSR } IF Holder = $90 THEN { The $A pattern is changed to $9 inside UART } DetectComPort := True ELSE DetectComPort := False; { Restore previous contents of MSR: } Port[MSRPort] := HoldMSR; { Take the UART out of loopback mode & restore old state of MCR: } Port[MCRPort] := HoldMCR AND (NOT LOOPBIT); END; {-----------------------------------------------------------------} { FUNCTION DetectUARTType by Jeff Duntemann } { This function returns a numeric code indicating which UART chip } { is present at the selected PortNumber (1-4.) The UART codes } { returned are as follows: } { 0 : Error; bad UART or no UART at COMn, where n=PortNumber } { 1 : 8250; generally (but not always!) present in PC or XT } { 2 : 16450; generally present in AT-class machines } { 3 : 16550; in PS/2 mod 50/60/early 80. FIFOs don't work! } { 4 : 16550A; in later PS/2's. FIFOs fully operative. } { NOTE: This routine assumes a UART is "out there" at the port # } { specified. Run DetectComPort first to make sure port is there! } {-----------------------------------------------------------------} FUNCTION DetectUARTType(PortNumber : Integer) : Integer; CONST PortBases : ARRAY[1..4] OF Integer = ($03F8,$02F8,$03E8,$02E8); { COM1 COM2 COM3 COM4 } VAR ScratchPort,IIRPort,FCRPort : Integer; Holder : Byte; BEGIN { The scratch register is at offset 7 from the comm port base: } ScratchPort := PortBases[PortNumber] + 7; FCRPort := PortBases[PortNumber] + 2; IIRPort := FCRPort; { IIR and FCR are at same offset } Port[ScratchPort] := $AA; { Write pattern to the scratch register } IF Port[ScratchPort] <> $AA THEN { Attempt to read it back... } DetectUARTType := 1 { A UART without a scratch register is an 8250 } ELSE BEGIN { Now we have to test among the 16450, 16550, and 16550A } Port[FCRPort] := $01; { Setting FCR bit 0 on 16550 enables FIFOs } Holder := Port[IIRPort] AND $C0; { Read back to FIFO status bits } CASE Holder OF $C0 : DetectUARTType := 4; { Bits 6 & 7 both set = 16550A } $80 : DetectUARTType := 3; { Bit 7 set & bit 6 cleared = 16550 } $00 : DetectUARTType := 2; { Neither bit set = 16450 } ELSE DetectUARTType := 0; { Error condition } END; {CASE} Port[FCRPort] := $00; { Don't leave the FIFOs enabled! } END; END; BEGIN FOR PortNum := 1 TO 4 DO BEGIN IF DetectComPort(PortNum) THEN BEGIN Write ('Port COM',PortNum,' is present,'); Writeln(' using a',UART[DetectUARTType(PortNum)],' UART.'); END ELSE Writeln('Port COM',Portnum,' is not present.'); END; END.