[ros-dev] Serial port type detection

Mark Junker mjscod at gmx.de
Sat Mar 19 23:07:08 CET 2005


Hi,

I found some old sources from me where I detect the IRQ and the type 
(8250, 16450, 16550, 16550A) of a COM port. I converted the type 
detection sources to C.

The detection if there is a COM port at all is made by inverting all 
bits of the LCR twice. All chips > 8250 have a scratch pad and all 
16550A+ have a usable FIFO.

I attached the diff for reactos/drivers/dd/serial/legacy.c.

BTW: I'm sorry about it but my editor always changes TABs to spaces ...

Regards,
Mark
-------------- next part --------------
Index: drivers/dd/serial/legacy.c
===================================================================
--- drivers/dd/serial/legacy.c	(revision 14202)
+++ drivers/dd/serial/legacy.c	(working copy)
@@ -1,72 +1,101 @@
 /* $Id:
  * 
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS kernel
  * FILE:            drivers/bus/serial/legacy.c
  * PURPOSE:         Legacy serial port enumeration
  * 
  * PROGRAMMERS:     Hervé Poussineau (poussine at freesurf.fr)
  */
 
 #define NDEBUG
 #include "serial.h"
 
+#define SER_TYPE_NONE   0
+#define SER_TYPE_8250   1
+#define SER_TYPE_16450  2
+#define SER_TYPE_16550  3
+#define SER_TYPE_16550A 4
+
+static BYTE
+DetectPortType(PUCHAR BaseAddress)
+{
+    BYTE Lcr, TestLcr;
+    BYTE OldScr, Scr5A, ScrA5;
+    BOOLEAN FifoEnabled;
+    BYTE NewFifoStatus;
+
+    Lcr = READ_PORT_UCHAR(SER_LCR(BaseAddress));
+    WRITE_PORT_UCHAR(BaseAddress, (BYTE) (Lcr ^ 0xFF));
+    TestLcr = (BYTE) (READ_PORT_UCHAR(SER_LCR(BaseAddress)) ^ 0xFF);
+    WRITE_PORT_UCHAR(BaseAddress, Lcr);
+
+    /* Accessing the LCR must work for a usable serial port */
+    if (TestLcr!=Lcr)
+        return SER_TYPE_NONE;
+
+    /* Ensure that all following accesses are done as required */
+    READ_PORT_UCHAR(SER_RBR(BaseAddress));
+    READ_PORT_UCHAR(SER_IER(BaseAddress));
+    READ_PORT_UCHAR(SER_IIR(BaseAddress));
+    READ_PORT_UCHAR(SER_LCR(BaseAddress));
+    READ_PORT_UCHAR(SER_MCR(BaseAddress));
+    READ_PORT_UCHAR(SER_LSR(BaseAddress));
+    READ_PORT_UCHAR(SER_MSR(BaseAddress));
+    READ_PORT_UCHAR(SER_SCR(BaseAddress));
+
+    /* Test scratch pad */
+    OldScr = READ_PORT_UCHAR(SER_SCR(BaseAddress));
+    WRITE_PORT_UCHAR(SER_SCR(BaseAddress), 0x5A);
+    Scr5A = READ_PORT_UCHAR(SER_SCR(BaseAddress));
+    WRITE_PORT_UCHAR(SER_SCR(BaseAddress), 0xA5);
+    ScrA5 = READ_PORT_UCHAR(SER_SCR(BaseAddress));
+    WRITE_PORT_UCHAR(SER_SCR(BaseAddress), OldScr);
+
+    /* When non-functional, we have a 8250 */
+    if (Scr5A!=0x5A || ScrA5!=0xA5)
+        return SER_TYPE_8250;
+
+    /* Test FIFO type */
+    FifoEnabled = (READ_PORT_UCHAR(SER_IIR(BaseAddress)) & 0x80)!=0;
+    WRITE_PORT_UCHAR(SER_FCR(BaseAddress), SR_FCR_ENABLE_FIFO);
+    NewFifoStatus = READ_PORT_UCHAR(SER_IIR(BaseAddress)) & 0xC0;
+    if (!FifoEnabled)
+        WRITE_PORT_UCHAR(SER_FCR(BaseAddress), 0);
+    switch (NewFifoStatus) {
+    case 0x00:
+        return SER_TYPE_16450;
+    case 0x80:
+        return SER_TYPE_16550;
+    }
+
+    /* FIFO is only functional for 16550A+ */
+    return SER_TYPE_16550A;
+}
+
 static BOOLEAN
 SerialDoesPortExist(PUCHAR BaseAddress)
 {
-	BOOLEAN Found;
-	BYTE Mcr;
-	BYTE Msr;
-	
-	Found = FALSE;
-	
-	/* save Modem Control Register (MCR) */
-	Mcr = READ_PORT_UCHAR(SER_MCR(BaseAddress));
-	
-	/* enable loop mode (set Bit 4 of the MCR) */
-	WRITE_PORT_UCHAR(SER_MCR(BaseAddress), 0x10);
-	
-	/* clear all modem output bits */
-	WRITE_PORT_UCHAR(SER_MCR(BaseAddress), 0x10);
-	
-	/* read the Modem Status Register */
-	Msr = READ_PORT_UCHAR(SER_MSR(BaseAddress));
-	
-	/*
-	 * the upper nibble of the MSR (modem output bits) must be
-	 * equal to the lower nibble of the MCR (modem input bits)
-	 */
-	if ((Msr & 0xf0) == 0x00)
-	{
-		/* set all modem output bits */
-		WRITE_PORT_UCHAR(SER_MCR(BaseAddress), 0x1f);
-		
-		/* read the Modem Status Register */
-		Msr = READ_PORT_UCHAR(SER_MSR(BaseAddress));
-		
-		/*
-		 * the upper nibble of the MSR (modem output bits) must be
-		 * equal to the lower nibble of the MCR (modem input bits)
-		 */
-		if ((Msr & 0xf0) == 0xf0)
-		{
-			/*
-			 * setup a resonable state for the port:
-			 * enable fifo and clear recieve/transmit buffers
-			 */
-			WRITE_PORT_UCHAR(SER_FCR(BaseAddress),
-				(SR_FCR_ENABLE_FIFO | SR_FCR_CLEAR_RCVR | SR_FCR_CLEAR_XMIT));
-			WRITE_PORT_UCHAR(SER_FCR(BaseAddress), 0);
-			READ_PORT_UCHAR(SER_RBR(BaseAddress));
-			WRITE_PORT_UCHAR(SER_IER(BaseAddress), 0);
-			Found = TRUE;
-		}
-	}
-	
-	/* restore MCR */
-	WRITE_PORT_UCHAR(SER_MCR(BaseAddress), Mcr);
-	
-	return Found;
+    BYTE Type;
+
+    Type = DetectPortType(BaseAddress);
+    if (Type==SER_TYPE_NONE)
+        return FALSE;
+
+    if (Type==SER_TYPE_16550A) {
+        /*
+         * setup a resonable state for the port:
+         * enable fifo and clear recieve/transmit buffers
+         */
+        WRITE_PORT_UCHAR(SER_FCR(BaseAddress),
+                         (SR_FCR_ENABLE_FIFO | SR_FCR_CLEAR_RCVR | SR_FCR_CLEAR_XMIT));
+        WRITE_PORT_UCHAR(SER_FCR(BaseAddress), 0);
+    }
+
+    READ_PORT_UCHAR(SER_RBR(BaseAddress));
+    WRITE_PORT_UCHAR(SER_IER(BaseAddress), 0);
+
+    return TRUE;
 }
 
 NTSTATUS


More information about the Ros-dev mailing list