You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2115 lines
50 KiB
2115 lines
50 KiB
/*++
|
|
|
|
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;
|
|
|
|
}
|