mirror of
https://github.com/reactos/reactos.git
synced 2025-05-03 21:00:15 +00:00
[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
This commit is contained in:
parent
d914dce9a0
commit
a93ca08cdc
14 changed files with 496 additions and 89 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
|
||||
PCHAR Utf8ConversionBuffer;
|
||||
ULONG Utf8ConversionBufferSize = PAGE_SIZE;
|
||||
|
||||
PSAC_MACHINE_INFO MachineInformation;
|
||||
|
||||
PVOID RequestSacCmdEventObjectBody;
|
||||
PKEVENT RequestSacCmdEventWaitObjectBody;
|
||||
PVOID RequestSacCmdSuccessEventObjectBody;
|
||||
|
|
|
@ -71,7 +71,8 @@ NTAPI
|
|||
CpGetByte(
|
||||
IN PCPPORT Port,
|
||||
OUT PUCHAR Byte,
|
||||
IN BOOLEAN Wait
|
||||
IN BOOLEAN Wait,
|
||||
IN BOOLEAN Poll
|
||||
);
|
||||
|
||||
VOID
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue