From a93ca08cdc68bf0088fdee3a43762eab6ef5c16d Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Sun, 18 Aug 2013 17:47:19 +0000 Subject: [PATCH] [CPORTLIB/KDBG/FREELDR]: Fix CpGetByte and its callers -- it takes a 4th parameter for polling. [NTOSKRNL]: Implement InbvPortPollOnly and InbvPortGetByte. [NTOSKRNL]: Implement HeadlessCmdClearDisplay and HeadlessCmdGetByte. [SACDRV]: Implement the TimerDpcRoutine which calls HeadlessCmdGetByte. We now consume characters in the EMS port. [SACDRV]: Implement ConMgrSerialPortConsumer. We now do full VT-100 input parsing. DEL, BS, TAB, SPACE all work. Pressing ENTER results in an ASSERT in ConMgrProcessLine as expected. svn path=/trunk/; revision=59772 --- reactos/boot/freeldr/freeldr/comm/rs232.c | 2 +- .../boot/freeldr/freeldr/windows/headless.c | 4 +- reactos/drivers/sac/driver/conmgr.c | 392 ++++++++++++++---- reactos/drivers/sac/driver/data.c | 6 +- reactos/drivers/sac/driver/dispatch.c | 43 ++ reactos/drivers/sac/driver/sacdrv.h | 31 ++ reactos/drivers/sac/driver/util.c | 2 + .../include/reactos/libs/cportlib/cportlib.h | 3 +- reactos/lib/cportlib/cport.c | 6 +- reactos/ntoskrnl/ex/hdlsterm.c | 57 ++- reactos/ntoskrnl/inbv/inbvport.c | 19 + reactos/ntoskrnl/include/internal/hdl.h | 5 + reactos/ntoskrnl/include/internal/inbv.h | 13 + reactos/ntoskrnl/kd/i386/kdbg.c | 2 +- 14 files changed, 496 insertions(+), 89 deletions(-) diff --git a/reactos/boot/freeldr/freeldr/comm/rs232.c b/reactos/boot/freeldr/freeldr/comm/rs232.c index 347ca0986e6..7f0d9d837a6 100644 --- a/reactos/boot/freeldr/freeldr/comm/rs232.c +++ b/reactos/boot/freeldr/freeldr/comm/rs232.c @@ -100,7 +100,7 @@ BOOLEAN Rs232PortGetByte(PUCHAR ByteReceived) if (PortInitialized == FALSE) return FALSE; - return (CpGetByte(&Rs232ComPort, ByteReceived, TRUE) == CP_GET_SUCCESS); + return (CpGetByte(&Rs232ComPort, ByteReceived, TRUE, FALSE) == CP_GET_SUCCESS); } /* diff --git a/reactos/boot/freeldr/freeldr/windows/headless.c b/reactos/boot/freeldr/freeldr/windows/headless.c index 40db235c7ca..515593adf46 100644 --- a/reactos/boot/freeldr/freeldr/windows/headless.c +++ b/reactos/boot/freeldr/freeldr/windows/headless.c @@ -143,7 +143,7 @@ BOOLEAN WinLdrPortGetByte(IN ULONG PortId, OUT PUCHAR Data) { - return CpGetByte(&Port[PortId], Data, TRUE) == CP_GET_SUCCESS; + return CpGetByte(&Port[PortId], Data, TRUE, FALSE) == CP_GET_SUCCESS; } BOOLEAN @@ -151,7 +151,7 @@ WinLdrPortPollOnly(IN ULONG PortId) { UCHAR Dummy; - return CpGetByte(&Port[PortId], &Dummy, FALSE) == CP_GET_SUCCESS; + return CpGetByte(&Port[PortId], &Dummy, FALSE, TRUE) == CP_GET_SUCCESS; } VOID diff --git a/reactos/drivers/sac/driver/conmgr.c b/reactos/drivers/sac/driver/conmgr.c index b012cad03f7..2b6406d5ab9 100644 --- a/reactos/drivers/sac/driver/conmgr.c +++ b/reactos/drivers/sac/driver/conmgr.c @@ -27,77 +27,11 @@ PSAC_CHANNEL SacChannel; ULONG ExecutePostConsumerCommand; PSAC_CHANNEL ExecutePostConsumerCommandData; +BOOLEAN InputInEscape, InputInEscTab, ConMgrLastCharWasCR; +CHAR InputBuffer[80]; + /* FUNCTIONS *****************************************************************/ -VOID -NTAPI -ConMgrSerialPortConsumer(VOID) -{ - NTSTATUS Status; - CHAR Char; - SAC_DBG(0x2000, "SAC TimerDpcRoutine: Entering.\n"); //bug - - /* Acquire the manager lock and make sure a channel is selected */ - SacAcquireMutexLock(); - ASSERT(CurrentChannel); - - /* Read whatever came off the serial port */ - for (Status = SerialBufferGetChar(&Char); - NT_SUCCESS(Status); - Status = SerialBufferGetChar(&Char)) - { - /* If nothing came through, bail out */ - if (Status == STATUS_NO_DATA_DETECTED) break; - } - - /* We're done, release the lock */ - SacReleaseMutexLock(); - SAC_DBG(0x2000, "SAC TimerDpcRoutine: Exiting.\n"); //bug -} - -VOID -NTAPI -ConMgrWorkerProcessEvents(IN PSAC_DEVICE_EXTENSION DeviceExtension) -{ - SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC WorkerProcessEvents: Entering.\n"); - - /* Enter the main loop */ - while (TRUE) - { - /* Wait for something to do */ - KeWaitForSingleObject(&DeviceExtension->Event, - Executive, - KernelMode, - FALSE, - NULL); - - /* Consume data off the serial port */ - ConMgrSerialPortConsumer(); - switch (ExecutePostConsumerCommand) - { - case 1: - /* A reboot was sent, do it */ - DoRebootCommand(FALSE); - break; - - case 2: - /* A close was sent, do it */ - ChanMgrCloseChannel(ExecutePostConsumerCommandData); - ChanMgrReleaseChannel(ExecutePostConsumerCommandData); - break; - - case 3: - /* A shutdown was sent, do it */ - DoRebootCommand(TRUE); - break; - } - - /* Clear the serial port consumer state */ - ExecutePostConsumerCommand = 0; - ExecutePostConsumerCommandData = NULL; - } -} - VOID NTAPI SacPutString(IN PWCHAR String) @@ -512,6 +446,319 @@ ConMgrChannelOWrite(IN PSAC_CHANNEL Channel, return Status; } +VOID +NTAPI +ConMgrProcessInputLine(VOID) +{ + ASSERT(FALSE); +} + +#define Nothing 0 + +VOID +NTAPI +ConMgrSerialPortConsumer(VOID) +{ + NTSTATUS Status; + CHAR Char, LastChar; + CHAR WriteBuffer[2], ReadBuffer[2]; + ULONG ReadBufferSize, i; + WCHAR StringBuffer[2]; + SAC_DBG(SAC_DBG_MACHINE, "SAC TimerDpcRoutine: Entering.\n"); //bug + + /* Acquire the manager lock and make sure a channel is selected */ + SacAcquireMutexLock(); + ASSERT(CurrentChannel); + + /* Read whatever came off the serial port */ + for (Status = SerialBufferGetChar(&Char); + NT_SUCCESS(Status); + Status = SerialBufferGetChar(&Char)) + { + /* If nothing came through, bail out */ + if (Status == STATUS_NO_DATA_DETECTED) break; + + /* Check if ESC was pressed */ + if (Char == '\x1B') + { + /* Was it already pressed? */ + if (!InputInEscape) + { + /* First time ESC is pressed! Remember and reset TAB state */ + InputInEscTab = FALSE; + InputInEscape = TRUE; + continue; + } + } + else if (Char == '\t') + { + /* TAB was pressed, is it following ESC (VT-100 sequence)? */ + if (InputInEscape) + { + /* Yes! This must be the only ESC-TAB we see in once moment */ + ASSERT(InputInEscTab == FALSE); + + /* No longer treat us as being in ESC */ + InputInEscape = FALSE; + + /* ESC-TAB is the sequence for changing channels */ + Status = ConMgrAdvanceCurrentChannel(); + if (!NT_SUCCESS(Status)) break; + + /* Remember ESC-TAB was pressed */ + InputInEscTab = TRUE; + continue; + } + } + else if ((Char == '0') && (InputInEscTab)) + { + /* It this ESC-TAB-0? */ + ASSERT(InputInEscape == FALSE); + InputInEscTab = FALSE; + + /* If writes are already enabled, don't do this */ + if (!CurrentChannel->WriteEnabled) + { + /* Reset the channel, this is our special sequence */ + Status = ConMgrResetCurrentChannel(FALSE); + if (!NT_SUCCESS(Status)) break; + } + + continue; + } + else + { + /* This is ESC-TAB-something else */ + InputInEscTab = FALSE; + + /* If writes are already enabled, don't do this */ + if (!CurrentChannel->WriteEnabled) + { + /* Display the current channel */ + InputInEscape = FALSE; + Status = ConMgrDisplayCurrentChannel(); + if (!NT_SUCCESS(Status)) break; + continue; + } + } + + /* Check if an ESC-sequence was being typed into a command channel */ + if ((InputInEscape) && (CurrentChannel != SacChannel)) + { + /* Store the ESC in the current channel buffer */ + WriteBuffer[0] = '\x1B'; + ChannelIWrite(CurrentChannel, WriteBuffer, sizeof(CHAR)); + } + + /* Check if we are no longer pressing ESC and exit the mode if so */ + if (Char != '\x1B') InputInEscape = FALSE; + + /* Whatever was typed in, save it int eh current channel */ + ChannelIWrite(CurrentChannel, &Char, sizeof(Char)); + + /* If this is a command channel, we're done, nothing to process */ + if (CurrentChannel != SacChannel) continue; + + /* Check for line feed right after a carriage return */ + if ((ConMgrLastCharWasCR) && (Char == '\n')) + { + /* Ignore the line feed, but clear the carriage return */ + ChannelIReadLast(CurrentChannel); + ConMgrLastCharWasCR = 0; + continue; + } + + /* Check if the user did a carriage return */ + ConMgrLastCharWasCR = (Char == '\n'); + + /* If the user did an "ENTER", we need to run the command */ + if ((Char == '\n') || (Char == '\r')) + { + /* Echo back to the terminal */ + SacPutString(L"\r\n"); + +DoLineParsing: + /* Inhibit the character (either CR or LF) */ + ChannelIReadLast(CurrentChannel); + + /* NULL-terminate the channel's input buffer */ + WriteBuffer[0] = ANSI_NULL; + ChannelIWrite(CurrentChannel, WriteBuffer, sizeof(CHAR)); + + /* Loop over every last character */ + do + { + /* Read every character in the channel, and strip whitespace */ + LastChar = ChannelIReadLast(CurrentChannel); + WriteBuffer[0] = LastChar; + } while ((!(LastChar) || + (LastChar == ' ') || + (LastChar == '\t')) && + (ChannelIBufferLength(CurrentChannel))); + + /* Write back into the channel the last character */ + ChannelIWrite(CurrentChannel, WriteBuffer, sizeof(CHAR)); + + /* NULL-terminate the input buffer */ + WriteBuffer[0] = ANSI_NULL; + ChannelIWrite(CurrentChannel, WriteBuffer, sizeof(WCHAR)); + + /* Now loop over every first character */ + do + { + /* Read every character in the channel, and strip whitespace */ + ChannelIRead(CurrentChannel, + ReadBuffer, + sizeof(ReadBuffer), + &ReadBufferSize); + WriteBuffer[0] = ReadBuffer[0]; + } while ((ReadBufferSize) && + ((ReadBuffer[0] != ' ') || (ReadBuffer[0] != '\t'))); + + /* We read one more than we should, so treat that as our first one */ + InputBuffer[0] = ReadBuffer[0]; + i = 1; + + /* And now loop reading all the others */ + do + { + /* Read each character -- there should be max 80 */ + ChannelIRead(CurrentChannel, + ReadBuffer, + sizeof(ReadBuffer), + &ReadBufferSize); + ASSERT(i < SAC_VTUTF8_COL_WIDTH); + InputBuffer[i++] = ReadBuffer[0]; + } while (ReadBufferSize); + + /* Now go over the entire input stream */ + for (i = 0; InputBuffer[i]; i++) + { + /* Again it should be less than 80 characters */ + ASSERT(i < SAC_VTUTF8_COL_WIDTH); + + /* And upcase each character */ + Char = InputBuffer[i]; + if ((Char >= 'A') && (Char <= 'Z')) InputBuffer[i] = Char + ' '; + } + + /* Ok, at this point, no pending command should exist */ + ASSERT(ExecutePostConsumerCommand == Nothing); + + /* Go and process the input, then show the prompt again */ + ConMgrProcessInputLine(); + SacPutSimpleMessage(SAC_PROMPT); + + /* If the user typed a valid command, get out of here */ + if (ExecutePostConsumerCommand != Nothing) break; + + /* Keep going */ + continue; + } + + /* Check if the user typed backspace or delete */ + if ((Char == '\b') || (Char == '\x7F')) + { + /* Omit the last character, which should be the DEL/BS itself */ + if (ChannelIBufferLength(CurrentChannel)) + { + ChannelIReadLast(CurrentChannel); + } + + /* Omit the before-last character, which is the one to delete */ + if (ChannelIBufferLength(CurrentChannel)) + { + /* Also send two backspaces back to the console */ + SacPutString(L"\b \b"); + ChannelIReadLast(CurrentChannel); + } + + /* Keep going */ + continue; + } + + /* If the user pressed CTRL-C at this point, treat it like ENTER */ + if (Char == '\x03') goto DoLineParsing; + + /* Check if the user pressed TAB */ + if (Char == '\t') + { + /* Omit it, send a BELL, and keep going. We ignore TABs */ + ChannelIReadLast(CurrentChannel); + SacPutString(L"\a"); + continue; + } + + /* Check if the user is getting close to the end of the screen */ + if (ChannelIBufferLength(CurrentChannel) == (SAC_VTUTF8_COL_WIDTH - 2)) + { + /* Delete the last character, replacing it with this one instead */ + swprintf(StringBuffer, L"\b%c", Char); + SacPutString(StringBuffer); + + /* Omit the last two characters from the buffer */ + ChannelIReadLast(CurrentChannel); + ChannelIReadLast(CurrentChannel); + + /* NULL-terminate it */ + WriteBuffer[0] = Char; + ChannelIWrite(CurrentChannel, WriteBuffer, sizeof(CHAR)); + continue; + } + + /* Nothing of interest happened, just write the character back */ + swprintf(StringBuffer, L"%c", Char); + SacPutString(StringBuffer); + } + + /* We're done, release the lock */ + SacReleaseMutexLock(); + SAC_DBG(SAC_DBG_MACHINE, "SAC TimerDpcRoutine: Exiting.\n"); //bug +} + +VOID +NTAPI +ConMgrWorkerProcessEvents(IN PSAC_DEVICE_EXTENSION DeviceExtension) +{ + SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC WorkerProcessEvents: Entering.\n"); + + /* Enter the main loop */ + while (TRUE) + { + /* Wait for something to do */ + KeWaitForSingleObject(&DeviceExtension->Event, + Executive, + KernelMode, + FALSE, + NULL); + + /* Consume data off the serial port */ + ConMgrSerialPortConsumer(); + switch (ExecutePostConsumerCommand) + { + case 1: + /* A reboot was sent, do it */ + DoRebootCommand(FALSE); + break; + + case 2: + /* A close was sent, do it */ + ChanMgrCloseChannel(ExecutePostConsumerCommandData); + ChanMgrReleaseChannel(ExecutePostConsumerCommandData); + break; + + case 3: + /* A shutdown was sent, do it */ + DoRebootCommand(TRUE); + break; + } + + /* Clear the serial port consumer state */ + ExecutePostConsumerCommand = 0; + ExecutePostConsumerCommandData = NULL; + } +} + NTSTATUS NTAPI ConMgrGetChannelCloseMessage(IN PSAC_CHANNEL Channel, @@ -522,13 +769,6 @@ ConMgrGetChannelCloseMessage(IN PSAC_CHANNEL Channel, return STATUS_NOT_IMPLEMENTED; } -VOID -NTAPI -ConMgrProcessInputLine(VOID) -{ - ASSERT(FALSE); -} - NTSTATUS NTAPI ConMgrHandleEvent(IN ULONG EventCode, diff --git a/reactos/drivers/sac/driver/data.c b/reactos/drivers/sac/driver/data.c index 14e4b7480af..11fff653e3a 100644 --- a/reactos/drivers/sac/driver/data.c +++ b/reactos/drivers/sac/driver/data.c @@ -238,7 +238,7 @@ InitializeDeviceData(IN PDEVICE_OBJECT DeviceObject) KeInitializeTimer(&DeviceExtension->Timer); KeInitializeDpc(&DeviceExtension->Dpc, TimerDpcRoutine, DeviceExtension); KeInitializeSpinLock(&DeviceExtension->Lock); - KeInitializeEvent(&DeviceExtension->Event, SynchronizationEvent, 0); + KeInitializeEvent(&DeviceExtension->Event, SynchronizationEvent, FALSE); InitializeListHead(&DeviceExtension->List); /* Attempt to enable HDL support */ @@ -317,8 +317,8 @@ InitializeDeviceData(IN PDEVICE_OBJECT DeviceObject) DeviceExtension->PriorityFail = TRUE; /* Initialize rundown and wait for the thread to do it */ - KeInitializeEvent(&DeviceExtension->RundownEvent, SynchronizationEvent, 0); - KeSetEvent(&DeviceExtension->Event, DeviceExtension->PriorityBoost, 0); + KeInitializeEvent(&DeviceExtension->RundownEvent, SynchronizationEvent, FALSE); + KeSetEvent(&DeviceExtension->Event, DeviceExtension->PriorityBoost, FALSE); Status = KeWaitForSingleObject(&DeviceExtension->RundownEvent, Executive, KernelMode, diff --git a/reactos/drivers/sac/driver/dispatch.c b/reactos/drivers/sac/driver/dispatch.c index 1af10f57d50..44ade239373 100644 --- a/reactos/drivers/sac/driver/dispatch.c +++ b/reactos/drivers/sac/driver/dispatch.c @@ -12,6 +12,8 @@ /* GLOBALS *******************************************************************/ +LONG TimerDpcCount; + /* FUNCTIONS *****************************************************************/ NTSTATUS @@ -61,7 +63,48 @@ TimerDpcRoutine(IN PKDPC Dpc, IN PVOID SystemArgument1, IN PVOID SystemArgument2) { + HEADLESS_RSP_GET_BYTE ByteValue; + ULONG ValueSize; + BOOLEAN GotChar; + NTSTATUS Status; + PSAC_DEVICE_EXTENSION SacExtension; + /* Update our counter */ + _InterlockedExchangeAdd(&TimerDpcCount, 1); + + /* Set defaults and loop for new characters */ + GotChar = FALSE; + ValueSize = sizeof(ByteValue); + do + { + /* Ask the kernel for a byte */ + Status = HeadlessDispatch(HeadlessCmdGetByte, + NULL, + 0, + &ByteValue, + &ValueSize); + + /* Break out if there's nothing interesting */ + if (!NT_SUCCESS(Status)) break; + if (!ByteValue.Value) break; + + /* Update the serial port buffer */ + SerialPortBuffer[SerialPortProducerIndex] = ByteValue.Value; + GotChar = TRUE; + + /* Update the index, let it roll-over if needed */ + _InterlockedExchange(&SerialPortProducerIndex, + (SerialPortProducerIndex + 1) & + (SAC_SERIAL_PORT_BUFFER_SIZE - 1)); + } while (ByteValue.Value); + + /* Did we get anything */ + if (GotChar) + { + /* Signal the worker thread that there is work to do */ + SacExtension = DeferredContext; + KeSetEvent(&SacExtension->Event, SacExtension->PriorityBoost, FALSE); + } } VOID diff --git a/reactos/drivers/sac/driver/sacdrv.h b/reactos/drivers/sac/driver/sacdrv.h index f9e4daa7968..b2c697e4459 100644 --- a/reactos/drivers/sac/driver/sacdrv.h +++ b/reactos/drivers/sac/driver/sacdrv.h @@ -156,6 +156,7 @@ #define SAC_MAX_CHANNELS 10 #define SAC_SERIAL_PORT_BUFFER_SIZE 1024 // 1KB #define SAC_MAX_MESSAGES 200 +#define SAC_VTUTF8_COL_WIDTH 80 // // Channel flags @@ -766,6 +767,35 @@ ChannelDestroy( IN PSAC_CHANNEL Channel ); +NTSTATUS +NTAPI +ChannelIWrite( + IN PSAC_CHANNEL Channel, + IN PCHAR Buffer, + IN ULONG BufferSize +); + +UCHAR +NTAPI +ChannelIReadLast( + IN PSAC_CHANNEL Channel +); + +ULONG +NTAPI +ChannelIBufferLength( + IN PSAC_CHANNEL Channel +); + +NTSTATUS +NTAPI +ChannelIRead( + IN PSAC_CHANNEL Channel, + IN PCHAR Buffer, + IN ULONG BufferSize, + IN OUT PULONG ResultBufferSize +); + // // RAW Channel Table // @@ -901,6 +931,7 @@ extern PSAC_MESSAGE_ENTRY GlobalMessageTable; extern KMUTEX CurrentChannelLock; extern LONG CurrentChannelRefCount; extern PCHAR SerialPortBuffer; +extern LONG SerialPortConsumerIndex, SerialPortProducerIndex; extern PCHAR Utf8ConversionBuffer; extern ULONG Utf8ConversionBufferSize; diff --git a/reactos/drivers/sac/driver/util.c b/reactos/drivers/sac/driver/util.c index c32f764856c..4c64e584c47 100644 --- a/reactos/drivers/sac/driver/util.c +++ b/reactos/drivers/sac/driver/util.c @@ -14,7 +14,9 @@ PCHAR Utf8ConversionBuffer; ULONG Utf8ConversionBufferSize = PAGE_SIZE; + PSAC_MACHINE_INFO MachineInformation; + PVOID RequestSacCmdEventObjectBody; PKEVENT RequestSacCmdEventWaitObjectBody; PVOID RequestSacCmdSuccessEventObjectBody; diff --git a/reactos/include/reactos/libs/cportlib/cportlib.h b/reactos/include/reactos/libs/cportlib/cportlib.h index ef62f54210e..9310ea45e8e 100644 --- a/reactos/include/reactos/libs/cportlib/cportlib.h +++ b/reactos/include/reactos/libs/cportlib/cportlib.h @@ -71,7 +71,8 @@ NTAPI CpGetByte( IN PCPPORT Port, OUT PUCHAR Byte, - IN BOOLEAN Wait + IN BOOLEAN Wait, + IN BOOLEAN Poll ); VOID diff --git a/reactos/lib/cportlib/cport.c b/reactos/lib/cportlib/cport.c index 8e493dd268a..4cad5b58934 100644 --- a/reactos/lib/cportlib/cport.c +++ b/reactos/lib/cportlib/cport.c @@ -255,7 +255,8 @@ USHORT NTAPI CpGetByte(IN PCPPORT Port, OUT PUCHAR Byte, - IN BOOLEAN Wait) + IN BOOLEAN Wait, + IN BOOLEAN Poll) { UCHAR Lsr; ULONG LimitCount = Wait ? TIMEOUT_COUNT : 1; @@ -277,6 +278,9 @@ CpGetByte(IN PCPPORT Port, return CP_GET_ERROR; } + /* If only polling was requested by caller, return now */ + if (Poll) return CP_GET_SUCCESS; + /* Otherwise read the byte and return it */ *Byte = READ_PORT_UCHAR(Port->Address + RECEIVE_BUFFER_REGISTER); diff --git a/reactos/ntoskrnl/ex/hdlsterm.c b/reactos/ntoskrnl/ex/hdlsterm.c index 20c71343c58..41c51712004 100644 --- a/reactos/ntoskrnl/ex/hdlsterm.c +++ b/reactos/ntoskrnl/ex/hdlsterm.c @@ -262,6 +262,7 @@ HdlspDispatch(IN HEADLESS_CMD Command, PHEADLESS_RSP_QUERY_INFO HeadlessInfo; PHEADLESS_CMD_PUT_STRING PutString; PHEADLESS_CMD_ENABLE_TERMINAL EnableTerminal; + PHEADLESS_RSP_GET_BYTE GetByte; NTSTATUS Status = STATUS_NOT_IMPLEMENTED; ASSERT(HeadlessGlobals != NULL); // ASSERT(HeadlessGlobals->PageLockHandle != NULL); @@ -328,8 +329,18 @@ HdlspDispatch(IN HEADLESS_CMD Command, Status = STATUS_SUCCESS; break; - case HeadlessCmdClearDisplay: - break; + case HeadlessCmdClearDisplay: + + /* Send the VT100 claer screen command if the terminal is enabled */ + if (HeadlessGlobals->TerminalEnabled) + { + HdlspSendStringAtBaud((PUCHAR)"\033[2J"); + } + + /* Return success either way */ + Status = STATUS_SUCCESS; + break; + case HeadlessCmdClearToEndOfDisplay: break; case HeadlessCmdClearToEndOfLine: @@ -344,8 +355,46 @@ HdlspDispatch(IN HEADLESS_CMD Command, break; case HeadlessCmdTerminalPoll: break; - case HeadlessCmdGetByte: - break; + + case HeadlessCmdGetByte: + + /* Make sure the caller passed valid data */ + if (!(OutputBuffer) || + !(OutputBufferSize) || + (*OutputBufferSize < sizeof(*GetByte))) + { + DPRINT1("Invalid buffer\n"); + Status = STATUS_INVALID_PARAMETER; + break; + } + + /* Make sure the terminal is enabled */ + GetByte = OutputBuffer; + if (HeadlessGlobals->TerminalEnabled) + { + /* Poll if something is on the wire */ + if (InbvPortPollOnly(HeadlessGlobals->TerminalPort)) + { + /* If so, read it */ + InbvPortGetByte(HeadlessGlobals->TerminalPort, + &GetByte->Value); + } + else + { + /* Nothing is there, return 0 */ + GetByte->Value = 0; + } + } + else + { + /* Otherwise return nothing */ + GetByte->Value = 0; + } + + /* Return success either way */ + Status = STATUS_SUCCESS; + break; + case HeadlessCmdGetLine: break; case HeadlessCmdStartBugCheck: diff --git a/reactos/ntoskrnl/inbv/inbvport.c b/reactos/ntoskrnl/inbv/inbvport.c index 5f58cff96df..d0509becce3 100644 --- a/reactos/ntoskrnl/inbv/inbvport.c +++ b/reactos/ntoskrnl/inbv/inbvport.c @@ -23,6 +23,25 @@ CPPORT Port[4] = /* FUNCTIONS *****************************************************************/ +BOOLEAN +NTAPI +InbvPortPollOnly(IN ULONG PortId) +{ + UCHAR Dummy; + + /* Poll a byte from the port */ + return CpGetByte(&Port[PortId], &Dummy, FALSE, TRUE) == CP_GET_SUCCESS; +} + +BOOLEAN +NTAPI +InbvPortGetByte(IN ULONG PortId, + OUT PUCHAR Char) +{ + /* Read a byte from the port */ + return CpGetByte(&Port[PortId], Char, TRUE, FALSE) == CP_GET_SUCCESS; +} + VOID NTAPI InbvPortEnableFifo(IN ULONG PortId, diff --git a/reactos/ntoskrnl/include/internal/hdl.h b/reactos/ntoskrnl/include/internal/hdl.h index 073f1b9cb7f..2bd0b2fe766 100644 --- a/reactos/ntoskrnl/include/internal/hdl.h +++ b/reactos/ntoskrnl/include/internal/hdl.h @@ -192,6 +192,11 @@ typedef struct _HEADLESS_CMD_PUT_STRING UCHAR String[1]; } HEADLESS_CMD_PUT_STRING, *PHEADLESS_CMD_PUT_STRING; +typedef struct _HEADLESS_RSP_GET_BYTE +{ + UCHAR Value; +} HEADLESS_RSP_GET_BYTE, *PHEADLESS_RSP_GET_BYTE; + NTSTATUS NTAPI HeadlessDispatch( diff --git a/reactos/ntoskrnl/include/internal/inbv.h b/reactos/ntoskrnl/include/internal/inbv.h index d8446aa2305..867c39d2103 100644 --- a/reactos/ntoskrnl/include/internal/inbv.h +++ b/reactos/ntoskrnl/include/internal/inbv.h @@ -107,4 +107,17 @@ InbvPortInitialize( IN BOOLEAN IsMMIODevice ); +BOOLEAN +NTAPI +InbvPortPollOnly( + IN ULONG PortId +); + +BOOLEAN +NTAPI +InbvPortGetByte( + IN ULONG PortId, + OUT PUCHAR Char +); + extern BOOLEAN InbvBootDriverInstalled; diff --git a/reactos/ntoskrnl/kd/i386/kdbg.c b/reactos/ntoskrnl/kd/i386/kdbg.c index 93084d69b68..0607112584b 100644 --- a/reactos/ntoskrnl/kd/i386/kdbg.c +++ b/reactos/ntoskrnl/kd/i386/kdbg.c @@ -136,7 +136,7 @@ KdPortGetByteEx( IN PCPPORT PortInformation, OUT PUCHAR ByteReceived) { - return (CpGetByte(PortInformation, ByteReceived, FALSE) == CP_GET_SUCCESS); + return (CpGetByte(PortInformation, ByteReceived, FALSE, TRUE) == CP_GET_SUCCESS); } VOID