2009-10-22 14:58:33 +00:00
|
|
|
/*
|
|
|
|
* COPYRIGHT: GPL, see COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS kernel
|
|
|
|
* FILE: drivers/base/kddll/kdcom.c
|
|
|
|
* PURPOSE: COM port functions for the kernel debugger.
|
|
|
|
* PROGRAMMER: Timo Kreuzer (timo.kreuzer@ewactos.org)
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "kddll.h"
|
|
|
|
#include "kdcom.h"
|
|
|
|
|
|
|
|
/* Define wait timeout value. */
|
|
|
|
#define REPEAT_COUNT (1000 * 1000)
|
|
|
|
|
|
|
|
/* serial debug connection */
|
|
|
|
#define DEFAULT_DEBUG_PORT 2 /* COM2 */
|
|
|
|
#define DEFAULT_DEBUG_COM1_IRQ 4 /* COM1 IRQ */
|
|
|
|
#define DEFAULT_DEBUG_COM2_IRQ 3 /* COM2 IRQ */
|
|
|
|
#define DEFAULT_DEBUG_BAUD_RATE 115200 /* 115200 Baud */
|
|
|
|
|
|
|
|
#define DEFAULT_BAUD_RATE 19200
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(_M_IX86) || defined(_M_AMD64)
|
|
|
|
const ULONG BaseArray[5] = {0, 0x3F8, 0x2F8, 0x3E8, 0x2E8};
|
|
|
|
#elif defined(_M_PPC)
|
|
|
|
const ULONG BaseArray[2] = {0, 0x800003f8};
|
|
|
|
#elif defined(_M_MIPS)
|
|
|
|
const ULONG BaseArray[3] = {0, 0x80006000, 0x80007000};
|
|
|
|
#elif defined(_M_ARM)
|
|
|
|
const ULONG BaseArray[2] = {0, 0xF1012000};
|
|
|
|
#else
|
|
|
|
#error Unknown architecture
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* GLOBALS ********************************************************************/
|
|
|
|
|
|
|
|
PUCHAR ComPortBase;
|
|
|
|
ULONG ComPortNumber = DEFAULT_DEBUG_PORT;
|
|
|
|
ULONG ComPortBaudRate = DEFAULT_DEBUG_BAUD_RATE;
|
|
|
|
ULONG ComPortIrq = 0;
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
KdpPortInitialize()
|
|
|
|
{
|
|
|
|
ULONG Mode;
|
|
|
|
|
|
|
|
KDDBGPRINT("KdpPortInitialize\n");
|
|
|
|
|
|
|
|
/* Enable loop mode (set Bit 4 of the MCR) */
|
|
|
|
WRITE_PORT_UCHAR(ComPortBase + COM_MCR, MCR_LOOP);
|
|
|
|
|
|
|
|
/* Clear all modem output bits */
|
|
|
|
WRITE_PORT_UCHAR(ComPortBase + COM_MCR, MCR_LOOP);
|
|
|
|
|
|
|
|
/* The upper nibble of the MSR (modem output bits) must be
|
|
|
|
* equal to the lower nibble of the MCR (modem input bits) */
|
|
|
|
if ((READ_PORT_UCHAR(ComPortBase + COM_MSR) & 0xF0) != 0x00)
|
|
|
|
{
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set all modem output bits */
|
|
|
|
WRITE_PORT_UCHAR(ComPortBase + COM_MCR, MCR_ALL);
|
|
|
|
|
|
|
|
/* The upper nibble of the MSR (modem output bits) must be
|
|
|
|
* equal to the lower nibble of the MCR (modem input bits) */
|
|
|
|
if ((READ_PORT_UCHAR(ComPortBase + COM_MSR) & 0xF0) != 0xF0)
|
|
|
|
{
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Enable FIFO */
|
|
|
|
WRITE_PORT_UCHAR(ComPortBase + COM_FCR,
|
|
|
|
FCR_ENABLE_FIFO | FCR_CLEAR_RCVR | FCR_CLEAR_XMIT);
|
|
|
|
|
|
|
|
/* Disable interrupts */
|
|
|
|
WRITE_PORT_UCHAR(ComPortBase + COM_LCR, 0);
|
|
|
|
WRITE_PORT_UCHAR(ComPortBase + COM_IEN, 0);
|
|
|
|
|
|
|
|
/* Enable on DTR and RTS */
|
|
|
|
WRITE_PORT_UCHAR(ComPortBase + COM_MCR, MCR_DTR | MCR_RTS);
|
|
|
|
|
|
|
|
/* Set DLAB */
|
|
|
|
WRITE_PORT_UCHAR(ComPortBase + COM_LCR, LCR_DLAB);
|
|
|
|
|
|
|
|
/* Set baud rate */
|
|
|
|
Mode = 115200 / ComPortBaudRate;
|
|
|
|
WRITE_PORT_UCHAR(ComPortBase + COM_DLL, (UCHAR)(Mode & 0xff));
|
|
|
|
WRITE_PORT_UCHAR(ComPortBase + COM_DLM, (UCHAR)((Mode >> 8) & 0xff));
|
|
|
|
|
|
|
|
/* Reset DLAB and set 8 data bits, 1 stop bit, no parity, no break */
|
|
|
|
WRITE_PORT_UCHAR(ComPortBase + COM_LCR, LCR_CS8 | LCR_ST1 | LCR_PNO);
|
|
|
|
|
|
|
|
/* Check for 16450/16550 scratch register */
|
|
|
|
WRITE_PORT_UCHAR(ComPortBase + COM_SCR, 0xff);
|
|
|
|
if (READ_PORT_UCHAR(ComPortBase + COM_SCR) != 0xff)
|
|
|
|
{
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
WRITE_PORT_UCHAR(ComPortBase + COM_SCR, 0x00);
|
|
|
|
if (READ_PORT_UCHAR(ComPortBase + COM_SCR) != 0x00)
|
|
|
|
{
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* \name KdDebuggerInitialize0
|
|
|
|
* \brief Phase 0 initialization.
|
|
|
|
* \param [opt] LoaderBlock Pointer to the Loader parameter block. Can be NULL.
|
|
|
|
* \return Status
|
|
|
|
*/
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
KdDebuggerInitialize0(
|
|
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock OPTIONAL)
|
|
|
|
{
|
|
|
|
PCHAR CommandLine, PortString, BaudString, IrqString;
|
|
|
|
ULONG Value;
|
|
|
|
|
|
|
|
/* Check if e have a LoaderBlock */
|
|
|
|
if (LoaderBlock)
|
|
|
|
{
|
|
|
|
/* Get the Command Line */
|
|
|
|
CommandLine = LoaderBlock->LoadOptions;
|
|
|
|
|
|
|
|
/* Upcase it */
|
|
|
|
_strupr(CommandLine);
|
|
|
|
|
|
|
|
/* Get the port and baud rate */
|
|
|
|
PortString = strstr(CommandLine, "DEBUGPORT");
|
|
|
|
BaudString = strstr(CommandLine, "BAUDRATE");
|
|
|
|
IrqString = strstr(CommandLine, "IRQ");
|
|
|
|
|
|
|
|
/* Check if we got the /DEBUGPORT parameter */
|
|
|
|
if (PortString)
|
|
|
|
{
|
|
|
|
/* Move past the actual string, to reach the port*/
|
|
|
|
PortString += strlen("DEBUGPORT");
|
|
|
|
|
|
|
|
/* Now get past any spaces and skip the equal sign */
|
|
|
|
while (*PortString == ' ') PortString++;
|
|
|
|
PortString++;
|
|
|
|
|
|
|
|
/* Do we have a serial port? */
|
|
|
|
if (strncmp(PortString, "COM", 3) != 0)
|
|
|
|
{
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Gheck for a valid Serial Port */
|
|
|
|
PortString += 3;
|
|
|
|
Value = atol(PortString);
|
|
|
|
if (Value > 4)
|
|
|
|
{
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the port to use */
|
|
|
|
ComPortNumber = Value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if we got a baud rate */
|
|
|
|
if (BaudString)
|
|
|
|
{
|
|
|
|
/* Move past the actual string, to reach the rate */
|
|
|
|
BaudString += strlen("BAUDRATE");
|
|
|
|
|
|
|
|
/* Now get past any spaces */
|
|
|
|
while (*BaudString == ' ') BaudString++;
|
|
|
|
|
|
|
|
/* And make sure we have a rate */
|
|
|
|
if (*BaudString)
|
|
|
|
{
|
|
|
|
/* Read and set it */
|
|
|
|
Value = atol(BaudString + 1);
|
|
|
|
if (Value) ComPortBaudRate = Value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check Serial Port Settings [IRQ] */
|
|
|
|
if (IrqString)
|
|
|
|
{
|
|
|
|
/* Move past the actual string, to reach the rate */
|
|
|
|
IrqString += strlen("IRQ");
|
|
|
|
|
|
|
|
/* Now get past any spaces */
|
|
|
|
while (*IrqString == ' ') IrqString++;
|
|
|
|
|
|
|
|
/* And make sure we have an IRQ */
|
|
|
|
if (*IrqString)
|
|
|
|
{
|
|
|
|
/* Read and set it */
|
|
|
|
Value = atol(IrqString + 1);
|
|
|
|
if (Value) ComPortIrq = Value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get base address */
|
|
|
|
ComPortBase = UlongToPtr(BaseArray[ComPortNumber]);
|
2009-11-10 14:23:44 +00:00
|
|
|
KdComPortInUse = ComPortBase;
|
2009-10-22 14:58:33 +00:00
|
|
|
|
|
|
|
/* Initialize the port */
|
|
|
|
return KdpPortInitialize();
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
KdpSendByte(IN BYTE Byte)
|
|
|
|
{
|
|
|
|
/* Wait for the port to be ready */
|
|
|
|
while ((READ_PORT_UCHAR(ComPortBase + COM_LSR) & LSR_TBE) == 0);
|
|
|
|
|
2009-10-27 23:38:56 +00:00
|
|
|
/* This is needed due to subtle timing issues */
|
|
|
|
READ_PORT_UCHAR(ComPortBase + COM_MSR);
|
|
|
|
while ((READ_PORT_UCHAR(ComPortBase + COM_LSR) & LSR_TBE) == 0);
|
|
|
|
READ_PORT_UCHAR(ComPortBase + COM_MSR);
|
|
|
|
|
2009-10-22 14:58:33 +00:00
|
|
|
/* Send the byte */
|
|
|
|
WRITE_PORT_UCHAR(ComPortBase + COM_DAT, Byte);
|
|
|
|
}
|
|
|
|
|
|
|
|
KDP_STATUS
|
|
|
|
NTAPI
|
|
|
|
KdpPollByte(OUT PBYTE OutByte)
|
|
|
|
{
|
2009-10-27 23:38:56 +00:00
|
|
|
READ_PORT_UCHAR(ComPortBase + COM_MSR); // Timing
|
|
|
|
|
2009-10-22 14:58:33 +00:00
|
|
|
/* Check if data is available */
|
|
|
|
if ((READ_PORT_UCHAR(ComPortBase + COM_LSR) & LSR_DR))
|
|
|
|
{
|
|
|
|
/* Yes, return the byte */
|
|
|
|
*OutByte = READ_PORT_UCHAR(ComPortBase + COM_DAT);
|
|
|
|
return KDP_PACKET_RECEIVED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Timed out */
|
|
|
|
return KDP_PACKET_TIMEOUT;
|
|
|
|
}
|
|
|
|
|
|
|
|
KDP_STATUS
|
|
|
|
NTAPI
|
|
|
|
KdpReceiveByte(OUT PBYTE OutByte)
|
|
|
|
{
|
|
|
|
ULONG Repeats = REPEAT_COUNT;
|
|
|
|
|
|
|
|
while (Repeats--)
|
|
|
|
{
|
|
|
|
/* Check if data is available */
|
|
|
|
if (KdpPollByte(OutByte) == KDP_PACKET_RECEIVED)
|
|
|
|
{
|
|
|
|
/* We successfully got a byte */
|
|
|
|
return KDP_PACKET_RECEIVED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Timed out */
|
|
|
|
return KDP_PACKET_TIMEOUT;
|
|
|
|
}
|
|
|
|
|
|
|
|
KDP_STATUS
|
|
|
|
NTAPI
|
|
|
|
KdpPollBreakIn()
|
|
|
|
{
|
|
|
|
UCHAR Byte;
|
|
|
|
if (KdpPollByte(&Byte) == KDP_PACKET_RECEIVED)
|
|
|
|
{
|
|
|
|
if (Byte == BREAKIN_PACKET_BYTE)
|
|
|
|
{
|
|
|
|
return KDP_PACKET_RECEIVED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return KDP_PACKET_TIMEOUT;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
KdSave(
|
|
|
|
IN BOOLEAN SleepTransition)
|
|
|
|
{
|
|
|
|
/* Nothing to do on COM ports */
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
KdRestore(
|
|
|
|
IN BOOLEAN SleepTransition)
|
|
|
|
{
|
|
|
|
/* Nothing to do on COM ports */
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|