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
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(a)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