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@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