[Back to COMM SWAG index]  [Back to Main SWAG index]  [Original]

{-------------------------------------------------------------------------
 !                                                                       !
 !  UARD.PAS   : Uart Detection Program        Ver 1.0                   !
 !                                                                       !
 !  Created    : 09-23-93        Changed: 09-23-93                       !
 !                                                                       !
 !  Converted To Turbo Pascal 6.0 By: David D. Cruger                    !
 !                                                                       !
 !  Original Program By:      National Semiconductor Corporation         !
 !  NS1655.ZIP                Microcomputer Systems Division             !
 !                            Microcontroller Applications Group         !
 !                            Written By: Louis Shay / 01/11/89          !
 !                            Originaly Written in some form of 'C'.     !
 !                            This program only does the 'detection'.    !
 !                            The original program ran some tests on     !
 !                            the Uarts.                                 !
 !                                                                       !
 !  SAVE/RESTORE Uart Registers Routines from Form Message #195739       !
 !  by Michael Day (TeamB)                                               !
 !                                                                       !
 !  *NOTE*  This program is just an example of how to detect Uarts and   !
 !          is not intended to be a stand alone program.  I here by      !
 !          release this program to the public domain.  Use at your own  !
 !          risk.                                                        !
 !                                                                       !
 !   0: No Uart at Port Address                                          !
 !   1: INS8250, INS8250-B                                               !
 !   2: INS8250A, INS82C50A, NS16450, NS16C450                           !
 !   3: NS16550A                                                         !
 !   4: NS16C552                                                         !
 !                                                                       !
 !------------------------------------------------------------------------}

Program UartD;

  {
     A =  Align Data
     B =  Boolean Short
     D =  Debug On
     E =  Emulate 80287
     F =  Far Calls
     G =  Generate 286 Code
     L =  Local Symbol Information
     N =  Numeric Processing Switch
     O =  Overlay
     R =  Range Checking On
     S =  Stack-Overflow
     V =  Var-String Checking
  }

{$a+,b-,d-,e-,f-,g-,l-,n-,o-,r-,s-,v-}                                 {}
{$M 2500,0,0}

Uses Dos;

Type Uart_Registers=Array[0..9] OF Byte;  { Uart Registers              }

Var  URegs: Uart_Registers;      { Uart Register Array                  }
     PA   : Word;                { Port Address Com1=$3F8  Com2=$2F8..  }

     RBR,THR,IER,IIR,FCR,LCR,MCR,LSR,MSR,SCR,DLL,DLM,AFR: Word;

{-------- Save Uart Registers --------}
Procedure Save_Uart_Registers(BaseAdd: Word; Var URegs: Uart_Registers);
Var I: Byte;
Begin
  ASM CLI; END;
  For I:=1 to 6 Do URegs[I]:=Port[BaseAdd+I];
  Port[BaseAdd+3]:=Port[BaseAdd+3] or $80;
  URegs[7]:=Port[BaseAdd+0];
  URegs[8]:=Port[BaseAdd+1];
  Port[BaseAdd+3]:=Port[BaseAdd+3] and $7F;
  ASM STI; END;
End; { End Procedure }

{------ Restore Uart Registers --------}
Procedure Restore_Uart_Registers(BaseAdd: Word; URegs: Uart_Registers);
Var I: Byte;
Begin
  ASM CLI; END;
  Port[BaseAdd+3]:=Port[BaseAdd+3] or $80;
  Port[BaseAdd+0]:=URegs[7];
  Port[BaseAdd+1]:=URegs[8];
  Port[BaseAdd+3]:=Port[BaseAdd+3] and $7F;
  For I:=1 to 6 Do Port[BaseAdd+I]:=URegs[I];
  ASM STI; END;
End; { End Procedure }

Procedure Return_Code(C: Byte);
Begin

  Case C of
   0:Writeln('No Uart at Port Address');
   1:Writeln('INS8250, INS8250-B');
   2:Writeln('INS8250A, INS82C50A, NS16450, NS16C450');
   3:Writeln('NS16550A');
   4:Writeln('NS16C552');
   End;

   Restore_Uart_Registers(PA,URegs);

   Halt(C);  { Halt with Errorlevel of Uart }

End; { End Procedure }

Procedure Set_Uart_Register_Values(PA: Word);
Begin

RBR:=PA+0;         { Receive Buffer Registers          (R  ) (DLAB=0)     }
THR:=PA+0;         { Transmitter Holding Register      (  W) (DLAB=0)     }
IER:=PA+1;         { Interrupt Enable Register         (R/W) (DLAB=0)     }
IIR:=PA+2;         { Interrupt Ident. Register         (R  )              }
FCR:=PA+2;         { FIFO Control Register             (  W)              }
LCR:=PA+3;         { Line Control Register             (R/W)              }
MCR:=PA+4;         { MODEM Control Register            (R/W)              }
LSR:=PA+5;         { Line Status Register              (R  )              }
MSR:=PA+6;         { MODEM Status Register             (R/W)              }
SCR:=PA+7;         { Scratch Register                  (R/W)              }
DLL:=PA+0;         { Divisor Latch (LSB)               (R/W) (DLAB=1)     }
DLM:=PA+1;         { Divisor Latch (MSB)               (R/W) (DLAB=1)     }
AFR:=PA+2;         { Alternate Function Register       (R/W)              }

End; { End Procedure }

Begin  { Main Section of Program }

PA:=$3F8; { Com1/ This can be changed to any port address you want }
Write('Com1: $3F8 : Uart:=');

Save_Uart_Registers(PA,URegs);  { Saves State of Current Uart Registers    }
Set_Uart_Register_Values(PA);   { Return_Code() Restores Uart Registers    }

Port[LCR]:=$AA;                         { Test LCR Registers               }
If $AA<>Port[LCR] Then Return_Code(0);

Port[DLM]:=$55;                         { Test DLM Present 8-bits          }
If $55<>Port[DLM] Then Return_Code(0);

Port[LCR]:=$55;                         { LCR/ DLAB=0                      }
If $55<>Port[LCR] Then Return_Code(0);

Port[IER]:=$55;                         { Test IER Present 4-bits          }
If $05<>Port[IER] Then Return_Code(0);

Port[FCR]:=$0;                          { FIFO's Off, If Present           }
Port[IER]:=$0;                          { Interrupts Off, IIR Should be 01 }
If $1<>Port[IIR] Then Return_Code(0);

{----- Test Modem Control Register Address. Should be 5-bits Wide -----}
Port[MCR]:=$F5;                         { 8-bit Write                      }
If $15<>Port[MCR] Then Return_Code(0);

{------ Test MCR/MSR Loopback Functions ------}

Port[MCR]:=$10;                         { Set Loop Mode                    }
Port[MSR]:=$0;                          { Clear out Delta Bits             }
If ($F0 and Port[MSR])<>0 Then Return_Code(0); { Check State Bits          }

Port[MCR]:=$1F;                         { Toggle Modem Control Lines       }
If ($F0 and Port[MSR])<>$F0 Then Return_Code(0); { Check State Bits        }

Port[MCR]:=$03;                         { Exit Loop Mode, DTR, RTS Active  }

{---- Port Id Successful at this point. determine port type ----}

Port[SCR]:=$55;                         { Is There a Scratch Register?    }
If $55<>Port[SCR] Then Return_Code(1);  { No SCR, Type = INS8250          }

Port[FCR]:=$CF;                         { Enable FIFO's, If Present       }
If ($C0 and Port[IIR])<>$C0 Then Return_Code(2); { Check FIFO ID bits     }
Port[FCR]:=$0;                          { Turn Off FIFO's                 }

Port[LCR]:=$80;                         { Set DLAB                        }
Port[AFR]:=$07;                         { Write to AFR                    }
If $07<>Port[AFR] Then                  { Read AFR                        }
  Begin
    Port[LCR]:=$0;                      { Reset DLAB                      }
    Return_Code(3);                     { If Not Type=NS16550A            }
  End;

Port[AFR]:=$0;                          { Clear AFR                       }
Port[LCR]:=$0;                          { Reset DLAB                      }
Return_Code(4);

End.

[Back to COMM SWAG index]  [Back to Main SWAG index]  [Original]