Author: hbelusca
Date: Wed Nov 28 22:12:29 2012
New Revision: 57776
URL: http://svn.reactos.org/svn/reactos?rev=57776&view=rev
Log:
[CPORTLIB]
- Do a synthesis of all the code I've found concerning initializing COM ports (in kdcom / kddll / kdbg in the kernel and in freeldr). The "// Windows" comments concern the original code for testing the existence of COM ports, inside cportlib, whereas "// ReactOS" comments concern the equivalent existing in our kdcom/kddll/kdbg etc...
- CORRECT THE VIRTUAL PC COM PORT INITIALIZATION !! The problem was, that the current COM port existence test fails on VPC whereas it works well in all other virtual machines. Therefore :
* I keep the existing testing code in a function called ComPortTest1, this works everywhere but on VPC ;
* I add a very basic COM port existence test function called ComPortTest2, which basically looks for the scratch register, this works everywhere including on VPC.
* The COM port existence test consists in the two tests above.
Modified:
trunk/reactos/include/reactos/libs/cportlib/cportlib.h
trunk/reactos/lib/cportlib/cport.c
Modified: trunk/reactos/include/reactos/libs/cportlib/cportlib.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/include/reactos/libs/cport…
==============================================================================
--- trunk/reactos/include/reactos/libs/cportlib/cportlib.h [iso-8859-1] (original)
+++ trunk/reactos/include/reactos/libs/cportlib/cportlib.h [iso-8859-1] Wed Nov 28 22:12:29 2012
@@ -10,31 +10,45 @@
#include <ntdef.h>
+//
+// Return error codes.
+//
#define CP_GET_SUCCESS 0
#define CP_GET_NODATA 1
#define CP_GET_ERROR 2
+//
+// COM port flags.
+//
#define CPPORT_FLAG_MODEM_CONTROL 0x02
+
typedef struct _CPPORT
{
PUCHAR Address;
- ULONG Baud;
+ ULONG BaudRate;
USHORT Flags;
} CPPORT, *PCPPORT;
-
-VOID
-NTAPI
-CpInitialize(
- IN PCPPORT Port,
- IN PUCHAR Address,
- IN ULONG Rate
-);
VOID
NTAPI
CpEnableFifo(
IN PUCHAR Address,
IN BOOLEAN Enable
+);
+
+VOID
+NTAPI
+CpSetBaud(
+ IN PCPPORT Port,
+ IN ULONG BaudRate
+);
+
+NTSTATUS
+NTAPI
+CpInitialize(
+ IN PCPPORT Port,
+ IN PUCHAR Address,
+ IN ULONG BaudRate
);
BOOLEAN
@@ -50,20 +64,13 @@
IN UCHAR ExpectedValue
);
-VOID
-NTAPI
-CpSetBaud(
- IN PCPPORT Port,
- IN ULONG Rate
-);
-
USHORT
NTAPI
CpGetByte(
- IN PCPPORT Port,
- IN PUCHAR Byte,
- IN BOOLEAN Wait,
- IN BOOLEAN Poll
+ IN PCPPORT Port,
+ OUT PUCHAR Byte,
+ IN BOOLEAN Wait,
+ IN BOOLEAN Poll
);
VOID
Modified: trunk/reactos/lib/cportlib/cport.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/cportlib/cport.c?rev=5…
==============================================================================
--- trunk/reactos/lib/cportlib/cport.c [iso-8859-1] (original)
+++ trunk/reactos/lib/cportlib/cport.c [iso-8859-1] Wed Nov 28 22:12:29 2012
@@ -11,6 +11,10 @@
* documented their serial algorithms, we use the same ones to stay "compliant".
* Do not change this code to "improve" it. It's done this way on purpose, at least on x86.
* -- sir_richard
+ *
+ * REPLY: I reworked the COM-port testing code because the original one
+ * (i.e. the Microsoft's documented one) doesn't work on Virtual PC 2007.
+ * -- hbelusca
*/
/* NOTE: This code is used by Headless Support (Ntoskrnl.exe and Osloader.exe) and
@@ -30,47 +34,100 @@
#include <drivers/serial/ns16550.h>
#include <intrin.h>
#include <ioaccess.h>
+#include <ntstatus.h>
+
+#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
+// Wait timeout value
+#define TIMEOUT_COUNT 1024 * 200
+
UCHAR RingIndicator;
+
/* FUNCTIONS ******************************************************************/
VOID
+NTAPI
+CpEnableFifo(IN PUCHAR Address,
+ IN BOOLEAN Enable)
+{
+ /* Set FIFO and clear the receive/transmit buffers */
+ WRITE_PORT_UCHAR(Address + FIFO_CONTROL_REGISTER,
+ Enable ? SERIAL_FCR_ENABLE | SERIAL_FCR_RCVR_RESET | SERIAL_FCR_TXMT_RESET
+ : SERIAL_FCR_DISABLE);
+}
+
+VOID
+NTAPI
+CpSetBaud(IN PCPPORT Port,
+ IN ULONG BaudRate)
+{
+ UCHAR Lcr;
+ ULONG Mode = CLOCK_RATE / BaudRate;
+
+ /* Set the DLAB on */
+ Lcr = READ_PORT_UCHAR(Port->Address + LINE_CONTROL_REGISTER);
+ WRITE_PORT_UCHAR(Port->Address + LINE_CONTROL_REGISTER, Lcr | SERIAL_LCR_DLAB);
+
+ /* Set the baud rate */
+ WRITE_PORT_UCHAR(Port->Address + DIVISOR_LATCH_LSB, (UCHAR)(Mode & 0xFF));
+ WRITE_PORT_UCHAR(Port->Address + DIVISOR_LATCH_MSB, (UCHAR)((Mode >> 8) & 0xFF));
+
+ /* Reset DLAB */
+ WRITE_PORT_UCHAR(Port->Address + LINE_CONTROL_REGISTER, Lcr);
+
+ /* Save baud rate in port */
+ Port->BaudRate = BaudRate;
+}
+
+NTSTATUS
NTAPI
CpInitialize(IN PCPPORT Port,
IN PUCHAR Address,
- IN ULONG Rate)
-{
- /* Reset port data */
- Port->Address = Address;
- Port->Baud = 0;
+ IN ULONG BaudRate)
+{
+ /* Validity checks */
+ if (Port == NULL || Address == NULL || BaudRate == 0)
+ return STATUS_INVALID_PARAMETER;
+
+ if (!CpDoesPortExist(Address))
+ return STATUS_NOT_FOUND;
+
+ /* Initialize port data */
+ Port->Address = Address;
+ Port->BaudRate = 0;
+ Port->Flags = 0;
+
+ /* Disable the interrupts */
+ WRITE_PORT_UCHAR(Address + LINE_CONTROL_REGISTER, 0);
+ WRITE_PORT_UCHAR(Address + INTERRUPT_ENABLE_REGISTER, 0);
+
+ /* Turn on DTR, RTS and OUT2 */
+ WRITE_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER,
+ SERIAL_MCR_DTR | SERIAL_MCR_RTS | SERIAL_MCR_OUT2);
/* Set the baud rate */
- CpSetBaud(Port, Rate);
-
- /* Enable on DTR and RTS */
- WRITE_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER,
- SERIAL_MCR_DTR | SERIAL_MCR_RTS);
-
- /* Disable interrupts */
- WRITE_PORT_UCHAR(Address + INTERRUPT_ENABLE_REGISTER, 0);
-}
-
-VOID
-NTAPI
-CpEnableFifo(IN PUCHAR Address,
- IN BOOLEAN Enable)
-{
- /* Set FIFO */
- WRITE_PORT_UCHAR(Address + FIFO_CONTROL_REGISTER, Enable ? SERIAL_FCR_ENABLE : 0);
-}
-
-BOOLEAN
-NTAPI
-CpDoesPortExist(IN PUCHAR Address)
+ CpSetBaud(Port, BaudRate);
+
+ /* Set 8 data bits, 1 stop bit, no parity, no break */
+ WRITE_PORT_UCHAR(Port->Address + LINE_CONTROL_REGISTER,
+ SERIAL_8_DATA | SERIAL_1_STOP | SERIAL_NONE_PARITY);
+
+ /* Turn on FIFO */
+ // TODO: Check whether FIFO exists and turn it on in that case.
+ CpEnableFifo(Address, TRUE); // for 16550
+
+ /* Read junk out of the RBR */
+ (VOID)READ_PORT_UCHAR(Address + RECEIVE_BUFFER_REGISTER);
+
+ return STATUS_SUCCESS;
+}
+
+static BOOLEAN
+ComPortTest1(IN PUCHAR Address)
{
/*
* See "Building Hardware and Firmware to Complement Microsoft Windows Headless Operation"
@@ -89,28 +146,87 @@
* 5. The modem status register is read and the ring indicator is checked.
* This means SERIAL_MSR_RI should be set.
* 6. Restore original modem status register.
+ *
+ * REMARK: Strangely enough, the Virtual PC 2007 virtual machine
+ * doesn't pass this test.
*/
- UCHAR Old = READ_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER);
-
+ BOOLEAN RetVal = FALSE;
+ UCHAR Mcr, Msr;
+
+ /* Save the Modem Control Register */
+ Mcr = READ_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER);
+
+ /* Enable loop (diagnostic) mode (set Bit 4 of the MCR) */
WRITE_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER, SERIAL_MCR_LOOP);
+
+ /* Clear all modem output bits */
WRITE_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER, SERIAL_MCR_LOOP);
- if (!(READ_PORT_UCHAR(Address + MODEM_STATUS_REGISTER) &
- (SERIAL_MSR_CTS | SERIAL_MSR_DSR | SERIAL_MSR_RI | SERIAL_MSR_DCD)))
- {
+ /* Read the Modem Status Register */
+ Msr = READ_PORT_UCHAR(Address + MODEM_STATUS_REGISTER);
+
+ /*
+ * The upper nibble of the MSR (modem output bits) must be
+ * equal to the lower nibble of the MCR (modem input bits).
+ */
+ if ((Msr & (SERIAL_MSR_CTS | SERIAL_MSR_DSR | SERIAL_MSR_RI | SERIAL_MSR_DCD)) == 0x00)
+ {
+ /* Set all modem output bits */
WRITE_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER,
- (SERIAL_MCR_OUT1 | SERIAL_MCR_LOOP));
- if (READ_PORT_UCHAR(Address + MODEM_STATUS_REGISTER) & SERIAL_MSR_RI)
+ SERIAL_MCR_OUT1 | SERIAL_MCR_LOOP); // Windows
+/* ReactOS
+ WRITE_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER,
+ SERIAL_MCR_DTR | SERIAL_MCR_RTS | SERIAL_MCR_OUT1 | SERIAL_MCR_OUT2 | SERIAL_MCR_LOOP);
+*/
+
+ /* Read the Modem Status Register */
+ Msr = READ_PORT_UCHAR(Address + MODEM_STATUS_REGISTER);
+
+ /*
+ * The upper nibble of the MSR (modem output bits) must be
+ * equal to the lower nibble of the MCR (modem input bits).
+ */
+ if (Msr & SERIAL_MSR_RI) // Windows
+ // if (Msr & (SERIAL_MSR_CTS | SERIAL_MSR_DSR | SERIAL_MSR_RI | SERIAL_MSR_DCD) == 0xF0) // ReactOS
{
- WRITE_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER, Old);
- return TRUE;
+ RetVal = TRUE;
}
}
- WRITE_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER, Old);
-
- return FALSE;
+ /* Restore the MCR */
+ WRITE_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER, Mcr);
+
+ return RetVal;
+}
+
+static BOOLEAN
+ComPortTest2(IN PUCHAR Address)
+{
+ /*
+ * This test checks whether the 16450/16550 scratch register is available.
+ * If not, the serial port is considered as unexisting.
+ */
+
+ UCHAR Byte = 0;
+
+ do
+ {
+ WRITE_PORT_UCHAR(Address + SCRATCH_REGISTER, Byte);
+
+ if (READ_PORT_UCHAR(Address + SCRATCH_REGISTER) != Byte)
+ return FALSE;
+
+ } while (++Byte != 0);
+
+ return TRUE;
+}
+
+BOOLEAN
+NTAPI
+CpDoesPortExist(IN PUCHAR Address)
+{
+ return ( ComPortTest1(Address) || ComPortTest2(Address) );
}
UCHAR
@@ -135,54 +251,28 @@
return Lsr;
}
-VOID
-NTAPI
-CpSetBaud(IN PCPPORT Port,
- IN ULONG Rate)
-{
- UCHAR Lcr;
- USHORT Mode;
-
- /* Add DLAB */
- Lcr = READ_PORT_UCHAR(Port->Address + LINE_CONTROL_REGISTER);
- WRITE_PORT_UCHAR(Port->Address + LINE_CONTROL_REGISTER, Lcr | SERIAL_LCR_DLAB);
-
- /* Set baud rate */
- Mode = (USHORT)(115200 / Rate);
- WRITE_PORT_UCHAR(Port->Address + DIVISOR_LATCH_MSB, (UCHAR)((Mode >> 8) & 0xff));
- WRITE_PORT_UCHAR(Port->Address + DIVISOR_LATCH_LSB, (UCHAR)(Mode & 0xff));
-
- /* Reset DLAB and set 8 data bits, 1 stop bit, no parity, no break */
- WRITE_PORT_UCHAR(Port->Address + LINE_CONTROL_REGISTER,
- SERIAL_8_DATA | SERIAL_1_STOP | SERIAL_NONE_PARITY);
-
- /* Save baud rate in port */
- Port->Baud = Rate;
-}
-
USHORT
NTAPI
-CpGetByte(IN PCPPORT Port,
- IN PUCHAR Byte,
- IN BOOLEAN Wait,
- IN BOOLEAN Poll)
+CpGetByte(IN PCPPORT Port,
+ OUT PUCHAR Byte,
+ IN BOOLEAN Wait,
+ IN BOOLEAN Poll)
{
UCHAR Lsr;
- ULONG i;
+ ULONG LimitCount = Wait ? TIMEOUT_COUNT : 1;
/* Handle early read-before-init */
if (!Port->Address) return CP_GET_NODATA;
/* If "wait" mode enabled, spin many times, otherwise attempt just once */
- i = Wait ? 204800 : 1;
- while (i--)
+ while (LimitCount--)
{
/* Read LSR for data ready */
Lsr = CpReadLsr(Port, SERIAL_LSR_DR);
if ((Lsr & SERIAL_LSR_DR) == SERIAL_LSR_DR)
{
/* If an error happened, clear the byte and fail */
- if (Lsr & (SERIAL_LSR_FE | SERIAL_LSR_PE))
+ if (Lsr & (SERIAL_LSR_FE | SERIAL_LSR_PE | SERIAL_LSR_OE))
{
*Byte = 0;
return CP_GET_ERROR;
@@ -217,17 +307,18 @@
IN UCHAR Byte)
{
/* Check if port is in modem control to handle CD */
- while (Port->Flags & CPPORT_FLAG_MODEM_CONTROL)
+ // while (Port->Flags & CPPORT_FLAG_MODEM_CONTROL) // Commented for the moment.
+ if (Port->Flags & CPPORT_FLAG_MODEM_CONTROL) // To be removed when this becomes implemented.
{
/* Not implemented yet */
DPRINT1("CP: CPPORT_FLAG_MODEM_CONTROL unexpected\n");
}
/* Wait for LSR to say we can go ahead */
- while (!(CpReadLsr(Port, SERIAL_LSR_THRE) & SERIAL_LSR_THRE));
+ while ((CpReadLsr(Port, SERIAL_LSR_THRE) & SERIAL_LSR_THRE) == 0x00);
/* Send the byte */
- WRITE_PORT_UCHAR(Port->Address + RECEIVE_BUFFER_REGISTER, Byte);
+ WRITE_PORT_UCHAR(Port->Address + TRANSMIT_HOLDING_REGISTER, Byte);
}
/* EOF */