2116 lines
50 KiB
C
2116 lines
50 KiB
C
/*++
|
||
|
||
Copyright (c) 1999-2000 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
XmlMgr.c
|
||
|
||
Abstract:
|
||
|
||
Routines for managing channels in the sac.
|
||
|
||
Author:
|
||
|
||
Brian Guarraci (briangu) March, 2001.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "sac.h"
|
||
#include "xmlcmd.h"
|
||
|
||
//
|
||
// Definitions for this file.
|
||
//
|
||
|
||
//
|
||
// Spinlock macros
|
||
//
|
||
#if 0
|
||
#define INIT_CURRENT_CHANNEL_LOCK() \
|
||
KeInitializeMutex( \
|
||
&XmlMgrCurrentChannelLock, \
|
||
0 \
|
||
); \
|
||
XmlMgrCurrentChannelRefCount = 0;
|
||
|
||
#define LOCK_CURRENT_CHANNEL() \
|
||
KdPrint((":? cclock: %d\r\n", __LINE__)); \
|
||
{ \
|
||
NTSTATUS Status; \
|
||
Status = KeWaitForMutexObject( \
|
||
&XmlMgrCurrentChannelLock, \
|
||
Executive, \
|
||
KernelMode, \
|
||
FALSE, \
|
||
NULL \
|
||
); \
|
||
ASSERT(Status == STATUS_SUCCESS); \
|
||
} \
|
||
ASSERT(XmlMgrCurrentChannelRefCount == 0); \
|
||
InterlockedIncrement(&XmlMgrCurrentChannelRefCount);\
|
||
ASSERT(XmlMgrCurrentChannelRefCount == 1); \
|
||
KdPrint((":) cclock: %d\r\n", __LINE__));
|
||
|
||
#define UNLOCK_CURRENT_CHANNEL() \
|
||
KdPrint((":* cclock: %d\r\n", __LINE__)); \
|
||
ASSERT(XmlMgrCurrentChannelRefCount == 1); \
|
||
InterlockedDecrement(&XmlMgrCurrentChannelRefCount); \
|
||
ASSERT(XmlMgrCurrentChannelRefCount == 0); \
|
||
ASSERT(KeReadStateMutex(&XmlMgrCurrentChannelLock)==0); \
|
||
ASSERT(KeReleaseMutex(&XmlMgrCurrentChannelLock,FALSE)==0);\
|
||
KdPrint((":( cclock: %d\r\n", __LINE__));
|
||
|
||
#else
|
||
#define INIT_CURRENT_CHANNEL_LOCK() \
|
||
KeInitializeMutex( \
|
||
&XmlMgrCurrentChannelLock, \
|
||
0 \
|
||
); \
|
||
XmlMgrCurrentChannelRefCount = 0;
|
||
|
||
#define LOCK_CURRENT_CHANNEL() \
|
||
{ \
|
||
NTSTATUS Status; \
|
||
Status = KeWaitForMutexObject( \
|
||
&XmlMgrCurrentChannelLock, \
|
||
Executive, \
|
||
KernelMode, \
|
||
FALSE, \
|
||
NULL \
|
||
); \
|
||
ASSERT(Status == STATUS_SUCCESS); \
|
||
} \
|
||
ASSERT(XmlMgrCurrentChannelRefCount == 0); \
|
||
InterlockedIncrement(&XmlMgrCurrentChannelRefCount); \
|
||
ASSERT(XmlMgrCurrentChannelRefCount == 1);
|
||
|
||
#define UNLOCK_CURRENT_CHANNEL() \
|
||
ASSERT(XmlMgrCurrentChannelRefCount == 1); \
|
||
InterlockedDecrement(&XmlMgrCurrentChannelRefCount); \
|
||
ASSERT(XmlMgrCurrentChannelRefCount == 0); \
|
||
ASSERT(KeReadStateMutex(&XmlMgrCurrentChannelLock)==0); \
|
||
ASSERT(KeReleaseMutex(&XmlMgrCurrentChannelLock,FALSE)==0);
|
||
|
||
#endif
|
||
|
||
//
|
||
// lock for r/w access on current channel globals
|
||
//
|
||
KMUTEX XmlMgrCurrentChannelLock;
|
||
ULONG XmlMgrCurrentChannelRefCount;
|
||
|
||
BOOLEAN XmlMgrInputInEscape = FALSE;
|
||
UCHAR XmlMgrInputBuffer[SAC_VT100_COL_WIDTH];
|
||
|
||
PSAC_CHANNEL XmlMgrSacChannel = NULL;
|
||
|
||
#define SAC_CHANNEL_INDEX 0
|
||
|
||
|
||
//
|
||
//
|
||
//
|
||
SAC_CHANNEL_HANDLE XmlMgrCurrentChannelHandle;
|
||
|
||
//
|
||
// The index of the current channel in the global channel list
|
||
//
|
||
ULONG XmlMgrCurrentChannelIndex = 0;
|
||
|
||
WCHAR SacOWriteUnicodeValue;
|
||
UCHAR SacOWriteUtf8ConversionBuffer[3];
|
||
|
||
VOID
|
||
XmlMgrSerialPortConsumer(
|
||
IN PSAC_DEVICE_CONTEXT DeviceContext
|
||
);
|
||
|
||
BOOLEAN
|
||
XmlMgrProcessInputLine(
|
||
VOID
|
||
);
|
||
|
||
NTSTATUS
|
||
XmlMgrInitialize(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Initialize the console manager
|
||
|
||
Arguments:
|
||
|
||
none
|
||
|
||
Return Value:
|
||
|
||
Status
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
PSAC_CMD_OPEN_CHANNEL OpenChannelCmd;
|
||
PWSTR XMLBuffer;
|
||
|
||
//
|
||
// Get the global buffer started so that we have room for error messages.
|
||
//
|
||
if (GlobalBuffer == NULL) {
|
||
|
||
GlobalBuffer = ALLOCATE_POOL(MEMORY_INCREMENT, GENERAL_POOL_TAG);
|
||
|
||
if (GlobalBuffer == NULL) {
|
||
IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoRaisePriorityCommand: Exiting (1).\n")));
|
||
return STATUS_NO_MEMORY;
|
||
}
|
||
|
||
GlobalBufferSize = MEMORY_INCREMENT;
|
||
|
||
}
|
||
|
||
//
|
||
// Initialize the Serial port globals
|
||
//
|
||
|
||
INIT_CURRENT_CHANNEL_LOCK();
|
||
|
||
//
|
||
// Lock down the current channel globals
|
||
//
|
||
// Note: we need to do this here since many of the XmlMgr support
|
||
// routines do ASSERTs to ensure the current channel lock is held
|
||
//
|
||
LOCK_CURRENT_CHANNEL();
|
||
|
||
//
|
||
// Initialize
|
||
//
|
||
do {
|
||
|
||
//
|
||
// create the open channel cmd that will open the SAC channel
|
||
//
|
||
Status = ChanMgrCreateOpenChannelCmd(
|
||
&OpenChannelCmd,
|
||
ChannelTypeRaw,
|
||
PRIMARY_SAC_CHANNEL_NAME,
|
||
PRIMARY_SAC_CHANNEL_DESCRIPTION,
|
||
SAC_CHANNEL_FLAG_PRESERVE,
|
||
NULL,
|
||
NULL,
|
||
PRIMARY_SAC_CHANNEL_APPLICATION_GUID
|
||
);
|
||
|
||
if (! NT_SUCCESS(Status)) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// create the SAC channel
|
||
//
|
||
Status = ChanMgrCreateChannel(
|
||
&XmlMgrSacChannel,
|
||
OpenChannelCmd
|
||
);
|
||
|
||
FREE_POOL(&OpenChannelCmd);
|
||
|
||
if (! NT_SUCCESS(Status)) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Make the SAC channel the current channel
|
||
//
|
||
Status = XmlMgrSetCurrentChannel(
|
||
SAC_CHANNEL_INDEX,
|
||
XmlMgrSacChannel
|
||
);
|
||
|
||
if (! NT_SUCCESS(Status)) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// We are done with the Channel
|
||
//
|
||
Status = ChanMgrReleaseChannel(XmlMgrSacChannel);
|
||
|
||
if (! NT_SUCCESS(Status)) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Flush the channel data to the screen
|
||
//
|
||
Status = XmlMgrDisplayCurrentChannel();
|
||
|
||
if (! NT_SUCCESS(Status)) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// NOTE: this really belongs back in data.c (InitializeDeviceData) since it is
|
||
// a global behavior
|
||
//
|
||
// Send XML machine information to management application
|
||
//
|
||
// <<<<
|
||
Status = TranslateMachineInformationXML(
|
||
&XMLBuffer,
|
||
NULL
|
||
);
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
XmlMgrSacPutString(XML_VERSION_HEADER);
|
||
XmlMgrSacPutString(XMLBuffer);
|
||
FREE_POOL(&XMLBuffer);
|
||
}
|
||
// <<<<
|
||
|
||
//
|
||
// Display the prompt
|
||
//
|
||
Status = HeadlessDispatch(
|
||
HeadlessCmdClearDisplay,
|
||
NULL,
|
||
0,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
if (! NT_SUCCESS(Status)) {
|
||
|
||
IF_SAC_DEBUG(
|
||
SAC_DEBUG_FAILS,
|
||
KdPrint(("SAC InitializeDeviceData: Failed dispatch\n")));
|
||
|
||
}
|
||
|
||
XmlMgrEventMessage(L"SAC_INITIALIZED");
|
||
|
||
} while (FALSE);
|
||
|
||
//
|
||
// We are done with the current channel globals
|
||
//
|
||
UNLOCK_CURRENT_CHANNEL();
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
XmlMgrShutdown(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Shutdown the console manager
|
||
|
||
Arguments:
|
||
|
||
none
|
||
|
||
Return Value:
|
||
|
||
Status
|
||
|
||
--*/
|
||
{
|
||
if (GlobalBuffer) {
|
||
FREE_POOL(&GlobalBuffer);
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
XmlMgrDisplayFastChannelSwitchingInterface(
|
||
PSAC_CHANNEL Channel
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine displays the fast-channel-switching interface
|
||
|
||
Note: caller must hold channel mutex
|
||
|
||
Arguments:
|
||
|
||
Channel - Channel to display
|
||
|
||
Return Value:
|
||
|
||
Status
|
||
|
||
--*/
|
||
{
|
||
HEADLESS_CMD_POSITION_CURSOR SetCursor;
|
||
HEADLESS_CMD_SET_COLOR SetColor;
|
||
PCWSTR Message;
|
||
NTSTATUS Status;
|
||
BOOLEAN bStatus;
|
||
ULONG Length;
|
||
PWSTR LocalBuffer;
|
||
|
||
ASSERT(XmlMgrCurrentChannelRefCount == 1);
|
||
|
||
//
|
||
// Display the Fast-Channel-Switching interface
|
||
//
|
||
|
||
LocalBuffer = NULL;
|
||
|
||
do {
|
||
|
||
LocalBuffer = ALLOCATE_POOL(0x100 * sizeof(WCHAR), GENERAL_POOL_TAG);
|
||
ASSERT(LocalBuffer);
|
||
if (!LocalBuffer) {
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
break;
|
||
}
|
||
|
||
//
|
||
// We cannot use the standard XmlMgrSacPutString() functions, because those write
|
||
// over the channel screen buffer. We force directly onto the terminal here.
|
||
//
|
||
ASSERT(Utf8ConversionBuffer);
|
||
if (!Utf8ConversionBuffer) {
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
break;
|
||
}
|
||
|
||
swprintf(
|
||
LocalBuffer,
|
||
L"<event type='channel-switch' channel-name='%s'/>\r\n",
|
||
ChannelGetName(Channel)
|
||
);
|
||
|
||
//
|
||
//
|
||
//
|
||
ASSERT((wcslen(LocalBuffer) + 1) * sizeof(WCHAR) < Utf8ConversionBufferSize);
|
||
|
||
bStatus = SacTranslateUnicodeToUtf8(
|
||
LocalBuffer,
|
||
(PUCHAR)Utf8ConversionBuffer,
|
||
Utf8ConversionBufferSize
|
||
);
|
||
if (! bStatus) {
|
||
Status = STATUS_UNSUCCESSFUL;
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Ensure that the utf8 buffer contains a non-emtpy string
|
||
//
|
||
Length = strlen(Utf8ConversionBuffer);
|
||
ASSERT(Length > 0);
|
||
if (Length == 0) {
|
||
break;
|
||
}
|
||
|
||
Status = HeadlessDispatch(
|
||
HeadlessCmdPutData,
|
||
(PUCHAR)Utf8ConversionBuffer,
|
||
strlen(Utf8ConversionBuffer) * sizeof(UCHAR),
|
||
NULL,
|
||
NULL
|
||
);
|
||
if (! NT_SUCCESS(Status)) {
|
||
ASSERT(strlen(Utf8ConversionBuffer) > 0);
|
||
break;
|
||
}
|
||
|
||
} while ( FALSE );
|
||
|
||
if (LocalBuffer) {
|
||
FREE_POOL(&LocalBuffer);
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
XmlMgrResetCurrentChannel(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine makes the SAC the current channel
|
||
|
||
Note: caller must hold channel mutex
|
||
|
||
Arguments:
|
||
|
||
ChannelIndex - The new index of the current channel
|
||
NewChannel - the new current channel
|
||
|
||
Return Value:
|
||
|
||
Status
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
ASSERT(XmlMgrCurrentChannelRefCount == 1);
|
||
|
||
Status = XmlMgrSetCurrentChannel(
|
||
SAC_CHANNEL_INDEX,
|
||
XmlMgrSacChannel
|
||
);
|
||
|
||
if (! NT_SUCCESS(Status)) {
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Flush the buffered channel data to the screen
|
||
//
|
||
// Note: we don't need to lock down the SAC, since we own it
|
||
//
|
||
Status = XmlMgrDisplayCurrentChannel();
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
XmlMgrSetCurrentChannel(
|
||
IN ULONG ChannelIndex,
|
||
IN PSAC_CHANNEL XmlMgrCurrentChannel
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sets the currently active channel to the one given.
|
||
|
||
Note: caller must hold channel mutex
|
||
|
||
Arguments:
|
||
|
||
ChannelIndex - The new index of the current channel
|
||
NewChannel - the new current channel
|
||
|
||
Return Value:
|
||
|
||
Status
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
ASSERT(XmlMgrCurrentChannelRefCount == 1);
|
||
|
||
//
|
||
// Update the current channel
|
||
//
|
||
XmlMgrCurrentChannelIndex = ChannelIndex;
|
||
|
||
//
|
||
// Keep track of the handle
|
||
//
|
||
XmlMgrCurrentChannelHandle = XmlMgrCurrentChannel->Handle;
|
||
|
||
//
|
||
// Update the sent to screen status
|
||
//
|
||
XmlMgrCurrentChannel->SentToScreen = FALSE;
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
XmlMgrDisplayCurrentChannel(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sets the currently active channel to the one given. It will transmit
|
||
the channel buffer to the terminal if SendToScreen is TRUE.
|
||
|
||
Note: caller must hold channel mutex
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
Status
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
PSAC_CHANNEL Channel;
|
||
|
||
ASSERT(XmlMgrCurrentChannelRefCount == 1);
|
||
|
||
//
|
||
// Get the current channel
|
||
//
|
||
Status = ChanMgrGetByHandle(
|
||
XmlMgrCurrentChannelHandle,
|
||
&Channel
|
||
);
|
||
if (! NT_SUCCESS(Status)) {
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// The channel buffer has been sent to the screen
|
||
//
|
||
Channel->SentToScreen = TRUE;
|
||
|
||
//
|
||
// Flush the buffered data to the screen
|
||
//
|
||
Status = Channel->OFlush(Channel);
|
||
|
||
//
|
||
// We are done with the current channel
|
||
//
|
||
ChanMgrReleaseChannel(Channel);
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
XmlMgrAdvanceXmlMgrCurrentChannel(
|
||
VOID
|
||
)
|
||
{
|
||
NTSTATUS Status;
|
||
ULONG NewIndex;
|
||
PSAC_CHANNEL Channel;
|
||
|
||
ASSERT(XmlMgrCurrentChannelRefCount == 1);
|
||
|
||
do {
|
||
|
||
//
|
||
// Query the channel manager for an array of currently active channels
|
||
//
|
||
Status = ChanMgrGetNextActiveChannel(
|
||
XmlMgrCurrentChannelIndex,
|
||
&NewIndex,
|
||
&Channel
|
||
);
|
||
|
||
if (! NT_SUCCESS(Status)) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Change the current channel to the next active channel
|
||
//
|
||
Status = XmlMgrSetCurrentChannel(
|
||
NewIndex,
|
||
Channel
|
||
);
|
||
|
||
if (! NT_SUCCESS(Status)) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Let the user know we switched via the Channel switching interface
|
||
//
|
||
Status = XmlMgrDisplayFastChannelSwitchingInterface(Channel);
|
||
|
||
if (! NT_SUCCESS(Status)) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// We are done with the channel
|
||
//
|
||
Status = ChanMgrReleaseChannel(Channel);
|
||
|
||
} while ( FALSE );
|
||
|
||
return Status;
|
||
}
|
||
|
||
BOOLEAN
|
||
XmlMgrIsCurrentChannel(
|
||
IN PSAC_CHANNEL Channel
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determine if the channel in question is the current channel
|
||
|
||
Arguments:
|
||
|
||
ChannelHandle - channel handle to compare against
|
||
|
||
Return Value:
|
||
|
||
|
||
|
||
--*/
|
||
{
|
||
|
||
// ASSERT(XmlMgrCurrentChannelRefCount == 1);
|
||
|
||
//
|
||
// Determine if the channel in question is the current channel
|
||
//
|
||
return ChannelIsEqual(
|
||
Channel,
|
||
&XmlMgrCurrentChannelHandle
|
||
);
|
||
|
||
}
|
||
|
||
VOID
|
||
XmlMgrWorkerProcessEvents(
|
||
IN PSAC_DEVICE_CONTEXT DeviceContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the routine for the worker thread. It blocks on an event, when
|
||
the event is signalled, then that indicates a request is ready to be processed.
|
||
|
||
Arguments:
|
||
|
||
DeviceContext - A pointer to this device.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
KIRQL OldIrql;
|
||
PLIST_ENTRY ListEntry;
|
||
|
||
IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC WorkerProcessEvents: Entering.\n")));
|
||
|
||
//
|
||
// Loop forever.
|
||
//
|
||
while (1) {
|
||
|
||
//
|
||
// Block until there is work to do.
|
||
//
|
||
Status = KeWaitForSingleObject(
|
||
(PVOID)&(DeviceContext->ProcessEvent),
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
NULL
|
||
);
|
||
|
||
if (DeviceContext->ExitThread) {
|
||
|
||
KdBreakPoint();
|
||
|
||
XmlCmdCancelIPIoRequest();
|
||
|
||
//
|
||
// Make sure the user is looking at the SAC
|
||
//
|
||
XmlMgrResetCurrentChannel();
|
||
|
||
//
|
||
// Issue the shutting down message
|
||
//
|
||
XmlMgrEventMessage(L"SAC_UNLOADED");
|
||
|
||
KeSetEvent(&(DeviceContext->ThreadExitEvent), DeviceContext->PriorityBoost, FALSE);
|
||
|
||
IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC WorkerProcessEvents: Terminating.\n")));
|
||
|
||
PsTerminateSystemThread(STATUS_SUCCESS);
|
||
|
||
}
|
||
|
||
switch (Status) {
|
||
case STATUS_TIMEOUT:
|
||
|
||
//
|
||
// Do TIMEOUT work
|
||
//
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
//
|
||
// Do EVENT work
|
||
//
|
||
|
||
switch ( ProcessingType ) {
|
||
|
||
case SAC_PROCESS_SERIAL_PORT_BUFFER:
|
||
|
||
//
|
||
// Process teh serial port buffer and return a processing state
|
||
//
|
||
XmlMgrSerialPortConsumer(DeviceContext);
|
||
|
||
break;
|
||
|
||
case SAC_SUBMIT_IOCTL:
|
||
|
||
if ( !IoctlSubmitted ) {
|
||
// submit the notify request with the
|
||
// IP driver. This procedure will also
|
||
// ensure that it is done only once in
|
||
// the lifetime of the driver.
|
||
XmlCmdSubmitIPIoRequest();
|
||
}
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Reset the process action
|
||
//
|
||
ProcessingType = SAC_NO_OP;
|
||
|
||
#if 0
|
||
//
|
||
// If there is any stuff that got delayed, process it.
|
||
//
|
||
DoDeferred(DeviceContext);
|
||
#endif
|
||
|
||
}
|
||
|
||
ASSERT(0);
|
||
}
|
||
|
||
#if 0
|
||
|
||
VOID
|
||
XmlMgrSerialPortConsumer(
|
||
IN PSAC_DEVICE_CONTEXT DeviceContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is a DPC routine that is queue'd by DriverEntry. It is used to check for any
|
||
user input and then processes them.
|
||
|
||
Arguments:
|
||
|
||
DeferredContext - A pointer to the device context.
|
||
|
||
All other parameters are unused.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
UCHAR LocalTmpBuffer[4];
|
||
PSAC_CHANNEL XmlMgrCurrentChannel;
|
||
ULONG i;
|
||
UCHAR ch;
|
||
|
||
do {
|
||
|
||
//
|
||
// Bail if there are no new characters to read
|
||
//
|
||
if (SerialPortConsumerIndex == SerialPortProducerIndex) {
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
//
|
||
// Get new character
|
||
//
|
||
ch = SerialPortBuffer[SerialPortConsumerIndex];
|
||
|
||
//
|
||
// Compute the new producer index and store it atomically
|
||
//
|
||
InterlockedExchange(&SerialPortConsumerIndex, (SerialPortConsumerIndex + 1) % SERIAL_PORT_BUFFER_SIZE);
|
||
|
||
//
|
||
//
|
||
//
|
||
HeadlessDispatch(
|
||
HeadlessCmdPutData,
|
||
(PUCHAR)&ch,
|
||
sizeof(UCHAR),
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
|
||
} while ( TRUE );
|
||
|
||
}
|
||
#endif
|
||
|
||
|
||
VOID
|
||
XmlMgrSerialPortConsumer(
|
||
IN PSAC_DEVICE_CONTEXT DeviceContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is a DPC routine that is queue'd by DriverEntry. It is used to check for any
|
||
user input and then processes them.
|
||
|
||
Arguments:
|
||
|
||
DeferredContext - A pointer to the device context.
|
||
|
||
All other parameters are unused.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
UCHAR LocalTmpBuffer[4];
|
||
PSAC_CHANNEL XmlMgrCurrentChannel;
|
||
ULONG i;
|
||
UCHAR ch;
|
||
|
||
IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE_LOUD, KdPrint(("SAC TimerDpcRoutine: Entering.\n")));
|
||
|
||
|
||
//
|
||
// lock down the current channel globals
|
||
//
|
||
LOCK_CURRENT_CHANNEL();
|
||
|
||
//
|
||
// Get the current channel
|
||
//
|
||
Status = ChanMgrGetByHandle(
|
||
XmlMgrCurrentChannelHandle,
|
||
&XmlMgrCurrentChannel
|
||
);
|
||
|
||
if (! NT_SUCCESS(Status)) {
|
||
|
||
//
|
||
// the current channel wasn't found,
|
||
// so reset the current channel to the SAC
|
||
//
|
||
XmlMgrResetCurrentChannel();
|
||
|
||
//
|
||
// We are done with current channel globals
|
||
//
|
||
UNLOCK_CURRENT_CHANNEL();
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
ASSERT(XmlMgrCurrentChannel != NULL);
|
||
|
||
GetNextByte:
|
||
|
||
//
|
||
// Bail if there are no new characters to read
|
||
//
|
||
if (SerialPortConsumerIndex == SerialPortProducerIndex) {
|
||
|
||
goto XmlMgrSerialPortConsumerDone;
|
||
|
||
}
|
||
|
||
//
|
||
// Get new character
|
||
//
|
||
ch = SerialPortBuffer[SerialPortConsumerIndex];
|
||
|
||
//
|
||
// Compute the new producer index and store it atomically
|
||
//
|
||
InterlockedExchange(&SerialPortConsumerIndex, (SerialPortConsumerIndex + 1) % SERIAL_PORT_BUFFER_SIZE);
|
||
|
||
//
|
||
// Check for <ESC><TAB>
|
||
//
|
||
if (ch == 0x1B) {
|
||
|
||
XmlMgrInputInEscape = TRUE;
|
||
|
||
goto GetNextByte;
|
||
|
||
} else if ((ch == '\t') && XmlMgrInputInEscape) {
|
||
|
||
XmlMgrInputInEscape = FALSE;
|
||
|
||
do {
|
||
|
||
//
|
||
// We are done with the current channel
|
||
//
|
||
Status = ChanMgrReleaseChannel(XmlMgrCurrentChannel);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Find the next active channel and make it the current
|
||
//
|
||
Status = XmlMgrAdvanceXmlMgrCurrentChannel();
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Get the current channel
|
||
//
|
||
Status = ChanMgrGetByHandle(
|
||
XmlMgrCurrentChannelHandle,
|
||
&XmlMgrCurrentChannel
|
||
);
|
||
|
||
} while ( FALSE );
|
||
|
||
if (! NT_SUCCESS(Status)) {
|
||
|
||
//
|
||
// We are done with current channel globals
|
||
//
|
||
UNLOCK_CURRENT_CHANNEL();
|
||
|
||
goto XmlMgrSerialPortConsumerExit;
|
||
|
||
}
|
||
|
||
goto GetNextByte;
|
||
|
||
} else {
|
||
|
||
//
|
||
// If this screen has not yet been displayed, and the user entered a 0
|
||
// then switch to the SAC Channel
|
||
//
|
||
if (!ChannelSentToScreen(XmlMgrCurrentChannel) && ch == '0') {
|
||
|
||
//
|
||
// Notify that we want the current channel to be displayed
|
||
//
|
||
XmlMgrInputInEscape = FALSE;
|
||
|
||
do {
|
||
|
||
//
|
||
// We are done with the current channel
|
||
//
|
||
Status = ChanMgrReleaseChannel(XmlMgrCurrentChannel);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Make the current channel the SAC
|
||
//
|
||
// Note: There should not be anything modifying the XmlMgrSacChannel
|
||
// at this time, so this should be safe
|
||
//
|
||
Status = XmlMgrResetCurrentChannel();
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Get the current channel
|
||
//
|
||
Status = ChanMgrGetByHandle(
|
||
XmlMgrCurrentChannelHandle,
|
||
&XmlMgrCurrentChannel
|
||
);
|
||
|
||
} while ( FALSE );
|
||
|
||
if (! NT_SUCCESS(Status)) {
|
||
|
||
//
|
||
// We are done with current channel globals
|
||
//
|
||
UNLOCK_CURRENT_CHANNEL();
|
||
|
||
goto XmlMgrSerialPortConsumerExit;
|
||
|
||
}
|
||
|
||
goto GetNextByte;
|
||
|
||
}
|
||
|
||
//
|
||
// If this screen has not yet been displayed, and the user entered a keystroke,
|
||
// then display it.
|
||
//
|
||
if (!ChannelSentToScreen(XmlMgrCurrentChannel)) {
|
||
|
||
//
|
||
// Notify that we want the current channel to be displayed
|
||
//
|
||
XmlMgrInputInEscape = FALSE;
|
||
|
||
do {
|
||
|
||
//
|
||
// We are done with the current channel
|
||
//
|
||
Status = ChanMgrReleaseChannel(XmlMgrCurrentChannel);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Flush the buffered channel data to the screen
|
||
//
|
||
Status = XmlMgrDisplayCurrentChannel();
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Get the current channel
|
||
//
|
||
Status = ChanMgrGetByHandle(
|
||
XmlMgrCurrentChannelHandle,
|
||
&XmlMgrCurrentChannel
|
||
);
|
||
|
||
} while ( FALSE );
|
||
|
||
if (! NT_SUCCESS(Status)) {
|
||
|
||
//
|
||
// We are done with current channel globals
|
||
//
|
||
UNLOCK_CURRENT_CHANNEL();
|
||
|
||
goto XmlMgrSerialPortConsumerExit;
|
||
|
||
}
|
||
|
||
goto GetNextByte;
|
||
|
||
}
|
||
|
||
//
|
||
// If the user was entering ESC-<something>, rebuffer the escape. Note: <esc><esc>
|
||
// buffers a single <esc>. This allows sending an real <esc><tab> to the channel.
|
||
//
|
||
if (XmlMgrInputInEscape && (XmlMgrCurrentChannel != XmlMgrSacChannel) && (ch != 0x1B)) {
|
||
LocalTmpBuffer[0] = 0x1B;
|
||
Status = XmlMgrCurrentChannel->IWrite(XmlMgrCurrentChannel, LocalTmpBuffer, sizeof(LocalTmpBuffer[0]));
|
||
}
|
||
|
||
XmlMgrInputInEscape = FALSE;
|
||
|
||
//
|
||
// Buffer this input
|
||
//
|
||
LocalTmpBuffer[0] = ch;
|
||
XmlMgrCurrentChannel->IWrite(XmlMgrCurrentChannel, LocalTmpBuffer, sizeof(LocalTmpBuffer[0]));
|
||
|
||
}
|
||
|
||
if (XmlMgrCurrentChannel != XmlMgrSacChannel) {
|
||
|
||
goto GetNextByte;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Now do processing if the SAC is the active channel.
|
||
//
|
||
|
||
ULONG ResponseLength;
|
||
WCHAR wch;
|
||
|
||
//
|
||
// If this is a return, then we are done and need to return the line
|
||
//
|
||
if ((ch == '\n') || (ch == '\r')) {
|
||
XmlMgrSacPutString(L"\r\n");
|
||
XmlMgrCurrentChannel->IReadLast(XmlMgrCurrentChannel);
|
||
LocalTmpBuffer[0] = '\0';
|
||
XmlMgrCurrentChannel->IWrite(XmlMgrCurrentChannel, LocalTmpBuffer, sizeof(LocalTmpBuffer[0]));
|
||
goto StripWhitespaceAndReturnLine;
|
||
}
|
||
|
||
//
|
||
// If this is a backspace or delete, then we need to do that.
|
||
//
|
||
if ((ch == 0x8) || (ch == 0x7F)) { // backspace (^H) or delete
|
||
|
||
if (ChannelGetLengthOfBufferedInput(XmlMgrCurrentChannel) > 0) {
|
||
XmlMgrSacPutString(L"\010 \010");
|
||
XmlMgrCurrentChannel->IReadLast(XmlMgrCurrentChannel);
|
||
XmlMgrCurrentChannel->IReadLast(XmlMgrCurrentChannel);
|
||
}
|
||
|
||
} else if (ch == 0x3) { // Control-C
|
||
|
||
//
|
||
// Terminate the string and return it.
|
||
//
|
||
XmlMgrCurrentChannel->IReadLast(XmlMgrCurrentChannel);
|
||
LocalTmpBuffer[0] = '\0';
|
||
XmlMgrCurrentChannel->IWrite(XmlMgrCurrentChannel, LocalTmpBuffer, sizeof(LocalTmpBuffer[0]));
|
||
goto StripWhitespaceAndReturnLine;
|
||
|
||
} else if (ch == 0x9) { // Tab
|
||
|
||
//
|
||
// Ignore tabs
|
||
//
|
||
XmlMgrCurrentChannel->IReadLast(XmlMgrCurrentChannel);
|
||
XmlMgrSacPutString(L"\007"); // send a BEL
|
||
goto GetNextByte;
|
||
|
||
} else if (ChannelGetLengthOfBufferedInput(XmlMgrCurrentChannel) == SAC_VT100_COL_WIDTH - 2) {
|
||
|
||
WCHAR Buffer[4];
|
||
|
||
//
|
||
// We are at the end of the screen - remove the last character from
|
||
// the terminal screen and replace it with this one.
|
||
//
|
||
swprintf(Buffer, L"\010%c", ch);
|
||
XmlMgrSacPutString(Buffer);
|
||
XmlMgrCurrentChannel->IReadLast(XmlMgrCurrentChannel);
|
||
XmlMgrCurrentChannel->IReadLast(XmlMgrCurrentChannel);
|
||
LocalTmpBuffer[0] = ch;
|
||
XmlMgrCurrentChannel->IWrite(XmlMgrCurrentChannel, LocalTmpBuffer, sizeof(LocalTmpBuffer[0]));
|
||
|
||
} else {
|
||
|
||
WCHAR Buffer[4];
|
||
|
||
//
|
||
// Echo the character to the screen
|
||
//
|
||
swprintf(Buffer, L"%c", ch);
|
||
XmlMgrSacPutString(Buffer);
|
||
}
|
||
|
||
goto GetNextByte;
|
||
|
||
StripWhitespaceAndReturnLine:
|
||
|
||
//
|
||
// Before returning the input line, strip off all leading and trailing blanks
|
||
//
|
||
do {
|
||
LocalTmpBuffer[0] = (UCHAR)XmlMgrCurrentChannel->IReadLast(XmlMgrCurrentChannel);
|
||
} while (((LocalTmpBuffer[0] == '\0') ||
|
||
(LocalTmpBuffer[0] == ' ') ||
|
||
(LocalTmpBuffer[0] == '\t')) &&
|
||
(ChannelGetLengthOfBufferedInput(XmlMgrCurrentChannel) > 0)
|
||
);
|
||
|
||
XmlMgrCurrentChannel->IWrite(XmlMgrCurrentChannel, LocalTmpBuffer, sizeof(LocalTmpBuffer[0]));
|
||
LocalTmpBuffer[0] = '\0';
|
||
XmlMgrCurrentChannel->IWrite(XmlMgrCurrentChannel, LocalTmpBuffer, sizeof(LocalTmpBuffer[0]));
|
||
|
||
do {
|
||
|
||
ResponseLength = XmlMgrCurrentChannel->IRead(
|
||
XmlMgrCurrentChannel,
|
||
(PUCHAR)&wch,
|
||
sizeof(UCHAR)
|
||
);
|
||
|
||
LocalTmpBuffer[0] = (UCHAR)wch;
|
||
|
||
} while ((ResponseLength != 0) &&
|
||
((LocalTmpBuffer[0] == ' ') ||
|
||
(LocalTmpBuffer[0] == '\t')));
|
||
|
||
XmlMgrInputBuffer[0] = LocalTmpBuffer[0];
|
||
i = 1;
|
||
|
||
do {
|
||
|
||
ResponseLength = XmlMgrCurrentChannel->IRead(
|
||
XmlMgrCurrentChannel,
|
||
(PUCHAR)&wch,
|
||
sizeof(UCHAR)
|
||
);
|
||
|
||
XmlMgrInputBuffer[i++] = (UCHAR)wch;
|
||
|
||
} while (ResponseLength != 0);
|
||
|
||
//
|
||
// Lower case all the characters. We do not use strlwr() or the like, so that
|
||
// the SAC (expecting ASCII always) doesn't accidently get DBCS or the like
|
||
// translation of the UCHAR stream.
|
||
//
|
||
for (i = 0; XmlMgrInputBuffer[i] != '\0'; i++) {
|
||
if ((XmlMgrInputBuffer[i] >= 'A') && (XmlMgrInputBuffer[i] <= 'Z')) {
|
||
XmlMgrInputBuffer[i] = XmlMgrInputBuffer[i] - 'A' + 'a';
|
||
}
|
||
}
|
||
|
||
//
|
||
// We are done with the current channel
|
||
//
|
||
Status = ChanMgrReleaseChannel(XmlMgrCurrentChannel);
|
||
|
||
//
|
||
// We are done with the current channel globals
|
||
//
|
||
UNLOCK_CURRENT_CHANNEL();
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto XmlMgrSerialPortConsumerExit;
|
||
}
|
||
|
||
//
|
||
// Process the input line.
|
||
//
|
||
if( XmlMgrProcessInputLine() == FALSE ) {
|
||
//
|
||
// We don't know what this is.
|
||
//
|
||
XmlMgrSacPutErrorMessage(L"sac", L"SAC_UNKNOWN_COMMAND");
|
||
}
|
||
|
||
#if 0
|
||
//
|
||
// Put the next command prompt
|
||
//
|
||
XmlMgrSacPutSimpleMessage(SAC_PROMPT);
|
||
#endif
|
||
|
||
//
|
||
//
|
||
//
|
||
LOCK_CURRENT_CHANNEL();
|
||
|
||
//
|
||
// Get the current channel
|
||
//
|
||
Status = ChanMgrGetByHandle(
|
||
XmlMgrCurrentChannelHandle,
|
||
&XmlMgrCurrentChannel
|
||
);
|
||
|
||
if (! NT_SUCCESS(Status)) {
|
||
|
||
//
|
||
// We are done with the current channel globals
|
||
//
|
||
UNLOCK_CURRENT_CHANNEL();
|
||
|
||
goto XmlMgrSerialPortConsumerExit;
|
||
|
||
}
|
||
|
||
goto GetNextByte;
|
||
|
||
}
|
||
|
||
XmlMgrSerialPortConsumerDone:
|
||
|
||
//
|
||
// We are done with the current channel
|
||
//
|
||
ChanMgrReleaseChannel(XmlMgrCurrentChannel);
|
||
|
||
//
|
||
// We are done with current channel globals
|
||
//
|
||
UNLOCK_CURRENT_CHANNEL();
|
||
|
||
XmlMgrSerialPortConsumerExit:
|
||
|
||
IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE_LOUD, KdPrint(("SAC TimerDpcRoutine: Exiting.\n")));
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
XmlMgrProcessInputLine(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to process an input line.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PUCHAR InputLine;
|
||
BOOLEAN CommandFound = FALSE;
|
||
|
||
InputLine = &(XmlMgrInputBuffer[0]);
|
||
|
||
if (!strcmp((LPSTR)InputLine, TLIST_COMMAND_STRING)) {
|
||
XmlCmdDoTlistCommand();
|
||
CommandFound = TRUE;
|
||
} else if ((!strcmp((LPSTR)InputLine, HELP1_COMMAND_STRING)) ||
|
||
(!strcmp((LPSTR)InputLine, HELP2_COMMAND_STRING))) {
|
||
XmlCmdDoHelpCommand();
|
||
CommandFound = TRUE;
|
||
} else if (!strcmp((LPSTR)InputLine, DUMP_COMMAND_STRING)) {
|
||
|
||
XmlCmdDoKernelLogCommand();
|
||
CommandFound = TRUE;
|
||
|
||
} else if (!strcmp((LPSTR)InputLine, FULLINFO_COMMAND_STRING)) {
|
||
XmlCmdDoFullInfoCommand();
|
||
CommandFound = TRUE;
|
||
} else if (!strcmp((LPSTR)InputLine, PAGING_COMMAND_STRING)) {
|
||
XmlCmdDoPagingCommand();
|
||
CommandFound = TRUE;
|
||
} else if (!strncmp((LPSTR)InputLine,
|
||
CHANNEL_COMMAND_STRING,
|
||
strlen(CHANNEL_COMMAND_STRING))) {
|
||
ULONG Length;
|
||
|
||
Length = strlen(CHANNEL_COMMAND_STRING);
|
||
|
||
if (((strlen((LPSTR)InputLine) > 1) && (InputLine[Length] == ' ')) ||
|
||
(strlen((LPSTR)InputLine) == strlen(CHANNEL_COMMAND_STRING))) {
|
||
XmlCmdDoChannelCommand(InputLine);
|
||
CommandFound = TRUE;
|
||
}
|
||
} else if (!strncmp((LPSTR)InputLine,
|
||
CMD_COMMAND_STRING,
|
||
strlen(CMD_COMMAND_STRING))) {
|
||
ULONG Length;
|
||
|
||
Length = strlen(CMD_COMMAND_STRING);
|
||
|
||
if (((strlen((LPSTR)InputLine) > 1) && (InputLine[Length] == ' ')) ||
|
||
(strlen((LPSTR)InputLine) == strlen(CMD_COMMAND_STRING))) {
|
||
XmlCmdDoCmdCommand(InputLine);
|
||
CommandFound = TRUE;
|
||
}
|
||
} else if (!strcmp((LPSTR)InputLine, REBOOT_COMMAND_STRING)) {
|
||
XmlCmdDoRebootCommand(TRUE);
|
||
CommandFound = TRUE;
|
||
} else if (!strcmp((LPSTR)InputLine, SHUTDOWN_COMMAND_STRING)) {
|
||
XmlCmdDoRebootCommand(FALSE);
|
||
CommandFound = TRUE;
|
||
} else if (!strcmp((LPSTR)InputLine, CRASH_COMMAND_STRING)) {
|
||
CommandFound = TRUE;
|
||
XmlCmdDoCrashCommand(); // this call does not return
|
||
} else if (!strncmp((LPSTR)InputLine,
|
||
KILL_COMMAND_STRING,
|
||
sizeof(KILL_COMMAND_STRING) - sizeof(UCHAR))) {
|
||
if ((strlen((LPSTR)InputLine) > 1) && (InputLine[1] == ' ')) {
|
||
XmlCmdDoKillCommand(InputLine);
|
||
CommandFound = TRUE;
|
||
}
|
||
} else if (!strncmp((LPSTR)InputLine,
|
||
LOWER_COMMAND_STRING,
|
||
sizeof(LOWER_COMMAND_STRING) - sizeof(UCHAR))) {
|
||
if ((strlen((LPSTR)InputLine) > 1) && (InputLine[1] == ' ')) {
|
||
XmlCmdDoLowerPriorityCommand(InputLine);
|
||
CommandFound = TRUE;
|
||
}
|
||
} else if (!strncmp((LPSTR)InputLine,
|
||
RAISE_COMMAND_STRING,
|
||
sizeof(RAISE_COMMAND_STRING) - sizeof(UCHAR))) {
|
||
if ((strlen((LPSTR)InputLine) > 1) && (InputLine[1] == ' ')) {
|
||
XmlCmdDoRaisePriorityCommand(InputLine);
|
||
CommandFound = TRUE;
|
||
}
|
||
} else if (!strncmp((LPSTR)InputLine,
|
||
LIMIT_COMMAND_STRING,
|
||
sizeof(LIMIT_COMMAND_STRING) - sizeof(UCHAR))) {
|
||
if ((strlen((LPSTR)InputLine) > 1) && (InputLine[1] == ' ')) {
|
||
XmlCmdDoLimitMemoryCommand(InputLine);
|
||
CommandFound = TRUE;
|
||
}
|
||
} else if (!strncmp((LPSTR)InputLine,
|
||
TIME_COMMAND_STRING,
|
||
sizeof(TIME_COMMAND_STRING) - sizeof(UCHAR))) {
|
||
if (((strlen((LPSTR)InputLine) > 1) && (InputLine[1] == ' ')) ||
|
||
(strlen((LPSTR)InputLine) == 1)) {
|
||
XmlCmdDoSetTimeCommand(InputLine);
|
||
CommandFound = TRUE;
|
||
}
|
||
} else if (!strcmp((LPSTR)InputLine, INFORMATION_COMMAND_STRING)) {
|
||
XmlCmdDoMachineInformationCommand();
|
||
CommandFound = TRUE;
|
||
} else if (!strncmp((LPSTR)InputLine,
|
||
SETIP_COMMAND_STRING,
|
||
sizeof(SETIP_COMMAND_STRING) - sizeof(UCHAR))) {
|
||
if (((strlen((LPSTR)InputLine) > 1) && (InputLine[1] == ' ')) ||
|
||
(strlen((LPSTR)InputLine) == 1)) {
|
||
XmlCmdDoSetIpAddressCommand(InputLine);
|
||
CommandFound = TRUE;
|
||
}
|
||
} else if ((InputLine[0] == '\n') || (InputLine[0] == '\0')) {
|
||
CommandFound = TRUE;
|
||
}
|
||
|
||
return CommandFound;
|
||
}
|
||
|
||
//
|
||
// Utility routines for writing to the SAC
|
||
//
|
||
BOOLEAN
|
||
XmlMgrChannelEventMessage(
|
||
PCWSTR String,
|
||
PCWSTR ChannelName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine deploys an event message
|
||
|
||
Arguments:
|
||
|
||
String - The string to display.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
|
||
//
|
||
// Currently, event messages are sent to the SAC channel
|
||
//
|
||
XmlMgrSacPutString(L"<event type='channel' name='");
|
||
XmlMgrSacPutString(String);
|
||
XmlMgrSacPutString(L"' channel-name='");
|
||
XmlMgrSacPutString(ChannelName);
|
||
XmlMgrSacPutString(L"'/>\r\n");
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
BOOLEAN
|
||
XmlMgrEventMessage(
|
||
PCWSTR String
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine deploys an event message
|
||
|
||
Arguments:
|
||
|
||
String - The string to display.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
|
||
//
|
||
// Currently, event messages are sent to the SAC channel
|
||
//
|
||
XmlMgrSacPutString(L"<event type='global' name='");
|
||
XmlMgrSacPutString(String);
|
||
XmlMgrSacPutString(L"'/>\r\n");
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
VOID
|
||
XmlMgrSacPutString(
|
||
PCWSTR String
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine takes a string and packages it into a command structure for the
|
||
HeadlessDispatch routine.
|
||
|
||
Arguments:
|
||
|
||
String - The string to display.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
ULONG StringLength;
|
||
ULONG UTF8Length;
|
||
WCHAR wchBuffer[2];
|
||
BOOLEAN bStatus;
|
||
ULONG i;
|
||
NTSTATUS Status;
|
||
PUCHAR LocalUtf8ConversionBuffer;
|
||
ULONG LocalUtf8ConversionBufferSize;
|
||
|
||
LocalUtf8ConversionBufferSize = 0x4 * sizeof(UCHAR);
|
||
LocalUtf8ConversionBuffer = ALLOCATE_POOL(LocalUtf8ConversionBufferSize, GENERAL_POOL_TAG);
|
||
ASSERT(LocalUtf8ConversionBuffer);
|
||
if (!LocalUtf8ConversionBuffer) {
|
||
IF_SAC_DEBUG(
|
||
SAC_DEBUG_FAILS,
|
||
KdPrint(("SAC XmlMgrSacPutString: Failed allocating utf8 buffer.\n"))
|
||
);
|
||
return;
|
||
}
|
||
|
||
ASSERT(FIELD_OFFSET(HEADLESS_CMD_PUT_STRING, String) == 0); // ASSERT if anyone changes this structure.
|
||
|
||
StringLength = wcslen(String);
|
||
|
||
for (i = 0; i < StringLength; i++) {
|
||
|
||
wchBuffer[0] = String[i];
|
||
wchBuffer[1] = UNICODE_NULL;
|
||
|
||
bStatus = SacTranslateUnicodeToUtf8(
|
||
(PCWSTR)wchBuffer,
|
||
LocalUtf8ConversionBuffer,
|
||
LocalUtf8ConversionBufferSize
|
||
);
|
||
|
||
if (! bStatus) {
|
||
Status = STATUS_UNSUCCESSFUL;
|
||
|
||
IF_SAC_DEBUG(
|
||
SAC_DEBUG_FAILS,
|
||
KdPrint(("SAC XmlMgrSacPutString: Failed UTF8 encoding\n"))
|
||
);
|
||
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Ensure that the utf8 buffer contains a non-emtpy string
|
||
//
|
||
UTF8Length = strlen(LocalUtf8ConversionBuffer);
|
||
ASSERT(UTF8Length > 0);
|
||
if (UTF8Length == 0) {
|
||
|
||
IF_SAC_DEBUG(
|
||
SAC_DEBUG_FAILS,
|
||
KdPrint(("SAC XmlMgrSacPutString: Empty UTF8 buffer\n"))
|
||
);
|
||
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Write the uft8 encoding to the sac channel
|
||
//
|
||
Status = XmlMgrSacChannel->OWrite(
|
||
XmlMgrSacChannel,
|
||
(PCUCHAR)LocalUtf8ConversionBuffer,
|
||
UTF8Length*sizeof(UCHAR)
|
||
);
|
||
|
||
if (! NT_SUCCESS(Status)) {
|
||
|
||
IF_SAC_DEBUG(
|
||
SAC_DEBUG_FAILS,
|
||
KdPrint(("SAC XmlMgrSacPutString: OWrite failed\n"))
|
||
);
|
||
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
FREE_POOL(&LocalUtf8ConversionBuffer);
|
||
|
||
}
|
||
|
||
#if 0
|
||
BOOLEAN
|
||
XmlMgrSacPutSimpleMessage(
|
||
ULONG MessageId
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine retrieves a message resource and sends it to the SAC channel
|
||
|
||
Arguments:
|
||
|
||
MessageId - The message id of the resource to send
|
||
|
||
Return Value:
|
||
|
||
TRUE - the message was found
|
||
otherwise, FALSE
|
||
|
||
--*/
|
||
{
|
||
PCWSTR p;
|
||
|
||
p = GetMessage(MessageId);
|
||
|
||
if (p) {
|
||
XmlMgrSacPutString(p);
|
||
return(TRUE);
|
||
}
|
||
|
||
return(FALSE);
|
||
|
||
}
|
||
#endif
|
||
|
||
BOOLEAN
|
||
XmlMgrSacPutErrorMessage(
|
||
PCWSTR ActionName,
|
||
PCWSTR MessageId
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine retrieves a message resource and sends it to the SAC channel
|
||
|
||
Arguments:
|
||
|
||
MessageId - The message id of the resource to send
|
||
|
||
Return Value:
|
||
|
||
TRUE - the message was found
|
||
otherwise, FALSE
|
||
|
||
--*/
|
||
{
|
||
XmlMgrSacPutString(L"<error ");
|
||
XmlMgrSacPutString(L"action='");
|
||
XmlMgrSacPutString(ActionName);
|
||
XmlMgrSacPutString(L"' message-id='");
|
||
XmlMgrSacPutString(MessageId);
|
||
XmlMgrSacPutString(L"'/>\r\n");
|
||
|
||
return(TRUE);
|
||
}
|
||
|
||
BOOLEAN
|
||
XmlMgrSacPutErrorMessageWithStatus(
|
||
PCWSTR ActionName,
|
||
PCWSTR MessageId,
|
||
NTSTATUS Status
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine retrieves a message resource and sends it to the SAC channel
|
||
|
||
Arguments:
|
||
|
||
MessageId - The message id of the resource to send
|
||
|
||
Return Value:
|
||
|
||
TRUE - the message was found
|
||
otherwise, FALSE
|
||
|
||
--*/
|
||
{
|
||
PWSTR Buffer;
|
||
|
||
Buffer = ALLOCATE_POOL(0x100, GENERAL_POOL_TAG);
|
||
ASSERT(Buffer);
|
||
if (! Buffer) {
|
||
return FALSE;
|
||
}
|
||
|
||
XmlMgrSacPutString(L"<error ");
|
||
XmlMgrSacPutString(L"action='");
|
||
XmlMgrSacPutString(ActionName);
|
||
XmlMgrSacPutString(L"' message-id='");
|
||
XmlMgrSacPutString(MessageId);
|
||
XmlMgrSacPutString(L"' status='");
|
||
|
||
swprintf(
|
||
Buffer,
|
||
L"%08x",
|
||
Status
|
||
);
|
||
XmlMgrSacPutString(Buffer);
|
||
XmlMgrSacPutString(L"'/>\r\n");
|
||
|
||
FREE_POOL(&Buffer);
|
||
|
||
return(TRUE);
|
||
}
|
||
|
||
NTSTATUS
|
||
XmlMgrChannelOWrite(
|
||
PSAC_CMD_WRITE_CHANNEL ChannelWriteCmd
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine attempts to write data to a channel
|
||
|
||
Arguments:
|
||
|
||
ChannelWriteCmd - the write IOCTL command structure
|
||
|
||
Return Value:
|
||
|
||
Status
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
PSAC_CHANNEL Channel;
|
||
|
||
//
|
||
//
|
||
//
|
||
LOCK_CURRENT_CHANNEL();
|
||
|
||
//
|
||
// Get the referred channel by it's handle
|
||
//
|
||
Status = ChanMgrGetByHandle(ChannelWriteCmd->Handle, &Channel);
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
do {
|
||
|
||
//
|
||
// Write the data to the channel's output buffer
|
||
//
|
||
Status = Channel->OWrite(
|
||
Channel,
|
||
&(ChannelWriteCmd->Buffer[0]),
|
||
ChannelWriteCmd->Size
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// We are done with the channel
|
||
//
|
||
Status = ChanMgrReleaseChannel(Channel);
|
||
|
||
} while ( FALSE );
|
||
|
||
}
|
||
|
||
//
|
||
//
|
||
//
|
||
UNLOCK_CURRENT_CHANNEL();
|
||
|
||
ASSERT(NT_SUCCESS(Status));
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
XmlMgrChannelClose(
|
||
PSAC_CHANNEL Channel
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine attempts to close a channel.
|
||
If we successfully close the channel and this channel was
|
||
the current channel, we reset the current channel to the SAC channel
|
||
|
||
Arguments:
|
||
|
||
Channel - the channel to close
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - the channel was closed
|
||
STATUS_ALREADY_DISCONNECTED - the channel was already closed
|
||
otherwise, error status
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
//
|
||
// Attempt to make the specified channel inactive
|
||
//
|
||
do {
|
||
|
||
//
|
||
// Make sure the channel is not already inactive
|
||
//
|
||
if (! ChannelIsActive(Channel)) {
|
||
Status = STATUS_ALREADY_DISCONNECTED;
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Change the status of the channel to Inactive
|
||
//
|
||
Status = ChannelClose(Channel);
|
||
|
||
if (! NT_SUCCESS(Status)) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// The current channel is being closed,
|
||
// so reset the current channel to the SAC
|
||
//
|
||
if (XmlMgrIsCurrentChannel(Channel)) {
|
||
|
||
Status = XmlMgrResetCurrentChannel();
|
||
|
||
}
|
||
|
||
} while ( FALSE );
|
||
|
||
ASSERT(NT_SUCCESS(Status) || Status == STATUS_ALREADY_DISCONNECTED);
|
||
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
XmlMgrHandleEvent(
|
||
IN IO_MGR_EVENT Event,
|
||
IN PVOID Data
|
||
)
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
switch(Event) {
|
||
case IO_MGR_EVENT_CHANNEL_CREATE: {
|
||
|
||
PWCHAR OutputBuffer;
|
||
PSAC_CHANNEL Channel;
|
||
|
||
Channel = (PSAC_CHANNEL)Data;
|
||
|
||
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_2);
|
||
|
||
OutputBuffer = ALLOCATE_POOL(SAC_VT100_COL_WIDTH*sizeof(WCHAR), GENERAL_POOL_TAG);
|
||
ASSERT_STATUS(OutputBuffer, STATUS_NO_MEMORY);
|
||
|
||
//
|
||
// Notify the SAC that a channel was created
|
||
//
|
||
XmlMgrChannelEventMessage(
|
||
L"SAC_NEW_CHANNEL_CREATED",
|
||
ChannelGetName(Channel)
|
||
);
|
||
|
||
FREE_POOL(&OutputBuffer);
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
case IO_MGR_EVENT_CHANNEL_CLOSE:
|
||
|
||
//
|
||
//
|
||
//
|
||
LOCK_CURRENT_CHANNEL();
|
||
|
||
do {
|
||
|
||
PSAC_CHANNEL Channel;
|
||
|
||
//
|
||
// Get the referred channel by it's handle
|
||
//
|
||
Status = ChanMgrGetByHandle(
|
||
*(PSAC_CHANNEL_HANDLE)Data,
|
||
&Channel
|
||
);
|
||
|
||
if (! NT_SUCCESS(Status)) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Attempt to close the channel
|
||
//
|
||
Status = XmlMgrChannelClose(Channel);
|
||
|
||
//
|
||
// notify the user the status of the operation
|
||
//
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
//
|
||
// report the channel has been closed
|
||
//
|
||
XmlMgrChannelEventMessage(
|
||
L"SAC_CHANNEL_CLOSED",
|
||
ChannelGetName(Channel)
|
||
);
|
||
|
||
} else if (Status == STATUS_ALREADY_DISCONNECTED) {
|
||
|
||
//
|
||
// report the channel was already closed
|
||
//
|
||
XmlMgrChannelEventMessage(
|
||
L"SAC_CHANNEL_ALREADY_CLOSED",
|
||
ChannelGetName(Channel)
|
||
);
|
||
|
||
} else {
|
||
|
||
//
|
||
// report that we failed to close the channel
|
||
//
|
||
XmlMgrChannelEventMessage(
|
||
L"SAC_CHANNEL_FAILED_CLOSE",
|
||
ChannelGetName(Channel)
|
||
);
|
||
|
||
}
|
||
|
||
//
|
||
// We are done with the channel
|
||
//
|
||
ChanMgrReleaseChannel(Channel);
|
||
|
||
} while(FALSE);
|
||
|
||
//
|
||
//
|
||
//
|
||
UNLOCK_CURRENT_CHANNEL();
|
||
|
||
break;
|
||
|
||
case IO_MGR_EVENT_CHANNEL_WRITE:
|
||
|
||
Status = XmlMgrChannelOWrite((PSAC_CMD_WRITE_CHANNEL)Data);
|
||
|
||
break;
|
||
|
||
case IO_MGR_EVENT_REGISTER_SAC_CMD_EVENT:
|
||
|
||
//
|
||
//
|
||
//
|
||
LOCK_CURRENT_CHANNEL();
|
||
|
||
Status = XmlMgrEventMessage(L"SAC_CMD_SERVICE_REGISTERED") ?
|
||
STATUS_SUCCESS :
|
||
STATUS_UNSUCCESSFUL;
|
||
|
||
//
|
||
//
|
||
//
|
||
UNLOCK_CURRENT_CHANNEL();
|
||
|
||
break;
|
||
|
||
case IO_MGR_EVENT_UNREGISTER_SAC_CMD_EVENT:
|
||
|
||
//
|
||
//
|
||
//
|
||
LOCK_CURRENT_CHANNEL();
|
||
|
||
Status = XmlMgrEventMessage(L"SAC_CMD_SERVICE_UNREGISTERED") ?
|
||
STATUS_SUCCESS :
|
||
STATUS_UNSUCCESSFUL;
|
||
|
||
//
|
||
//
|
||
//
|
||
UNLOCK_CURRENT_CHANNEL();
|
||
|
||
break;
|
||
|
||
case IO_MGR_EVENT_SHUTDOWN:
|
||
|
||
Status = XmlMgrEventMessage(L"SAC_SHUTDOWN") ?
|
||
STATUS_SUCCESS :
|
||
STATUS_UNSUCCESSFUL;
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
Status = STATUS_INVALID_PARAMETER_1;
|
||
|
||
break;
|
||
}
|
||
|
||
return Status;
|
||
|
||
}
|