reactos/drivers/sac/driver/rawchan.c

380 lines
9.9 KiB
C

/*
* PROJECT: ReactOS Drivers
* LICENSE: BSD - See COPYING.ARM in the top level directory
* FILE: drivers/sac/driver/rawchan.c
* PURPOSE: Driver for the Server Administration Console (SAC) for EMS
* PROGRAMMERS: ReactOS Portable Systems Group
*/
/* INCLUDES *******************************************************************/
#include "sacdrv.h"
/* FUNCTIONS ******************************************************************/
NTSTATUS
NTAPI
RawChannelCreate(IN PSAC_CHANNEL Channel)
{
CHECK_PARAMETER(Channel);
/* Allocate the output buffer */
Channel->OBuffer = SacAllocatePool(SAC_RAW_OBUFFER_SIZE, GLOBAL_BLOCK_TAG);
CHECK_ALLOCATION(Channel->OBuffer);
/* Allocate the input buffer */
Channel->IBuffer = SacAllocatePool(SAC_RAW_IBUFFER_SIZE, GLOBAL_BLOCK_TAG);
CHECK_ALLOCATION(Channel->IBuffer);
/* Reset all flags and return success */
Channel->OBufferIndex = 0;
Channel->OBufferFirstGoodIndex = 0;
Channel->ChannelHasNewIBufferData = FALSE;
Channel->ChannelHasNewOBufferData = FALSE;
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
RawChannelDestroy(IN PSAC_CHANNEL Channel)
{
CHECK_PARAMETER(Channel);
/* Free the buffer and then destroy the channel */
if (Channel->OBuffer) SacFreePool(Channel->OBuffer);
if (Channel->IBuffer) SacFreePool(Channel->IBuffer);
return ChannelDestroy(Channel);
}
FORCEINLINE
BOOLEAN
ChannelHasNewOBufferData(IN PSAC_CHANNEL Channel)
{
return Channel->ChannelHasNewOBufferData;
}
NTSTATUS
NTAPI
RawChannelORead(IN PSAC_CHANNEL Channel,
IN PCHAR Buffer,
IN ULONG BufferSize,
OUT PULONG ByteCount)
{
NTSTATUS Status;
ULONG NextIndex;
CHECK_PARAMETER1(Channel);
CHECK_PARAMETER2(Buffer);
CHECK_PARAMETER3(BufferSize > 0);
CHECK_PARAMETER4(ByteCount);
*ByteCount = 0;
if (ChannelHasNewOBufferData(Channel))
{
Status = STATUS_SUCCESS;
while (TRUE)
{
Buffer[(*ByteCount)++] = Channel->OBuffer[Channel->OBufferFirstGoodIndex];
NextIndex = (Channel->OBufferFirstGoodIndex + 1) & (SAC_OBUFFER_SIZE - 1);
Channel->OBufferFirstGoodIndex = NextIndex;
if (NextIndex == Channel->OBufferIndex)
{
_InterlockedExchange(&Channel->ChannelHasNewOBufferData, 0);
break;
}
ASSERT(*ByteCount > 0);
if (*ByteCount >= BufferSize) break;
}
}
else
{
Status = STATUS_NO_DATA_DETECTED;
}
if (Channel->OBufferFirstGoodIndex == Channel->OBufferIndex)
{
ASSERT(ChannelHasNewOBufferData(Channel) == FALSE);
}
if (ChannelHasNewOBufferData(Channel) == FALSE)
{
ASSERT(Channel->OBufferFirstGoodIndex == Channel->OBufferIndex);
}
return Status;
}
NTSTATUS
NTAPI
RawChannelOEcho(IN PSAC_CHANNEL Channel,
IN PCHAR String,
IN ULONG Length)
{
NTSTATUS Status = STATUS_SUCCESS;
CHECK_PARAMETER1(Channel);
CHECK_PARAMETER2(String);
if (Length)
{
Status = ConMgrWriteData(Channel, String, Length);
if (NT_SUCCESS(Status)) ConMgrFlushData(Channel);
}
return Status;
}
NTSTATUS
NTAPI
RawChannelOWrite2(IN PSAC_CHANNEL Channel,
IN PCHAR String,
IN ULONG Size)
{
BOOLEAN Overflow;
ULONG i, NextIndex;
CHECK_PARAMETER1(Channel);
CHECK_PARAMETER2(String);
Overflow = FALSE;
for (i = 0; i < Size; i++)
{
if ((Channel->OBufferIndex == Channel->OBufferFirstGoodIndex) &&
((i) || (ChannelHasNewOBufferData(Channel))))
{
Overflow = TRUE;
}
ASSERT(Channel->OBufferIndex < SAC_RAW_OBUFFER_SIZE);
Channel->OBuffer[Channel->OBufferIndex] = String[i];
NextIndex = (Channel->OBufferIndex + 1) & (SAC_RAW_OBUFFER_SIZE - 1);
Channel->OBufferIndex = NextIndex;
if (Overflow) Channel->OBufferFirstGoodIndex = NextIndex;
}
_InterlockedExchange(&Channel->ChannelHasNewOBufferData, 1);
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
RawChannelOFlush(IN PSAC_CHANNEL Channel)
{
NTSTATUS Status;
ULONG ByteCount;
CHAR Dummy;
CHECK_PARAMETER1(Channel);
while (ChannelHasNewOBufferData(Channel))
{
Status = RawChannelORead(Channel, &Dummy, sizeof(Dummy), &ByteCount);
if (!NT_SUCCESS(Status)) return Status;
CHECK_PARAMETER_WITH_STATUS(ByteCount == 1, STATUS_UNSUCCESSFUL);
Status = ConMgrWriteData(Channel, &Dummy, sizeof(Dummy));
if (!NT_SUCCESS(Status)) return Status;
}
return ConMgrFlushData(Channel);
}
NTSTATUS
NTAPI
RawChannelOWrite(IN PSAC_CHANNEL Channel,
IN PCHAR String,
IN ULONG Length)
{
CHECK_PARAMETER1(Channel);
CHECK_PARAMETER2(String);
if ((ConMgrIsWriteEnabled(Channel)) && (Channel->WriteEnabled))
{
return RawChannelOEcho(Channel, String, Length);
}
return RawChannelOWrite2(Channel, String, Length);
}
ULONG
NTAPI
RawChannelGetIBufferIndex(IN PSAC_CHANNEL Channel)
{
ASSERT(Channel);
ASSERT(Channel->IBufferIndex < SAC_RAW_IBUFFER_SIZE);
/* Return the current buffer index */
return Channel->IBufferIndex;
}
VOID
NTAPI
RawChannelSetIBufferIndex(IN PSAC_CHANNEL Channel,
IN ULONG BufferIndex)
{
NTSTATUS Status;
ASSERT(Channel);
ASSERT(Channel->IBufferIndex < SAC_RAW_IBUFFER_SIZE);
/* Set the new index, and if it's not zero, it means we have data */
Channel->IBufferIndex = BufferIndex;
_InterlockedExchange(&Channel->ChannelHasNewIBufferData, BufferIndex != 0);
/* If we have new data, and an event has been registered... */
if (!(Channel->IBufferIndex) &&
(Channel->Flags & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT))
{
/* Go ahead and signal it */
ChannelClearEvent(Channel, HasNewDataEvent);
UNREFERENCED_PARAMETER(Status);
}
}
NTSTATUS
NTAPI
RawChannelIRead(IN PSAC_CHANNEL Channel,
IN PCHAR Buffer,
IN ULONG BufferSize,
IN PULONG ReturnBufferSize)
{
ULONG CopyChars;
CHECK_PARAMETER1(Channel);
CHECK_PARAMETER2(Buffer);
CHECK_PARAMETER_WITH_STATUS(BufferSize > 0, STATUS_INVALID_BUFFER_SIZE);
/* Assume failure */
*ReturnBufferSize = 0;
/* Check how many bytes are in the buffer */
if (Channel->ChannelInputBufferLength(Channel) == 0)
{
/* Apparently nothing. Make sure the flag indicates so too */
ASSERT(ChannelHasNewIBufferData(Channel) == FALSE);
}
else
{
/* Use the smallest number of bytes either in the buffer or requested */
CopyChars = min(Channel->ChannelInputBufferLength(Channel), BufferSize);
ASSERT(CopyChars <= Channel->ChannelInputBufferLength(Channel));
/* Copy them into the caller's buffer */
RtlCopyMemory(Buffer, Channel->IBuffer, CopyChars);
/* Update the channel's index past the copied (read) bytes */
RawChannelSetIBufferIndex(Channel,
RawChannelGetIBufferIndex(Channel) - CopyChars);
/* Are there still bytes that haven't been read yet? */
if (Channel->ChannelInputBufferLength(Channel))
{
/* Shift them up in the buffer */
RtlMoveMemory(Channel->IBuffer,
&Channel->IBuffer[CopyChars],
Channel->ChannelInputBufferLength(Channel));
}
/* Return the number of bytes we actually copied */
*ReturnBufferSize = CopyChars;
}
/* Return success */
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
RawChannelIBufferIsFull(IN PSAC_CHANNEL Channel,
OUT PBOOLEAN BufferStatus)
{
CHECK_PARAMETER1(Channel);
CHECK_PARAMETER2(BufferStatus);
/* If the index is beyond the length, the buffer must be full */
*BufferStatus = RawChannelGetIBufferIndex(Channel) > SAC_RAW_IBUFFER_SIZE;
return STATUS_SUCCESS;
}
ULONG
NTAPI
RawChannelIBufferLength(IN PSAC_CHANNEL Channel)
{
ASSERT(Channel);
/* The index is the current length (since we're 0-based) */
return RawChannelGetIBufferIndex(Channel);
}
WCHAR
NTAPI
RawChannelIReadLast(IN PSAC_CHANNEL Channel)
{
UCHAR LastChar = 0;
ASSERT(Channel);
/* Check if there's anything to read in the buffer */
if (Channel->ChannelInputBufferLength(Channel))
{
/* Go back one character */
RawChannelSetIBufferIndex(Channel,
RawChannelGetIBufferIndex(Channel) - 1);
/* Read it, and clear its current value */
LastChar = Channel->IBuffer[RawChannelGetIBufferIndex(Channel)];
Channel->IBuffer[RawChannelGetIBufferIndex(Channel)] = ANSI_NULL;
}
/* Return the last character */
return LastChar;
}
NTSTATUS
NTAPI
RawChannelIWrite(IN PSAC_CHANNEL Channel,
IN PCHAR Buffer,
IN ULONG BufferSize)
{
NTSTATUS Status;
BOOLEAN IsFull;
ULONG Index;
CHECK_PARAMETER1(Channel);
CHECK_PARAMETER2(Buffer);
CHECK_PARAMETER_WITH_STATUS(BufferSize > 0, STATUS_INVALID_BUFFER_SIZE);
/* First, check if the input buffer still has space */
Status = RawChannelIBufferIsFull(Channel, &IsFull);
if (!NT_SUCCESS(Status)) return Status;
if (IsFull) return STATUS_UNSUCCESSFUL;
/* Get the current buffer index */
Index = RawChannelGetIBufferIndex(Channel);
if ((SAC_RAW_IBUFFER_SIZE - Index) < BufferSize)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Copy the new data */
RtlCopyMemory(&Channel->IBuffer[Index], Buffer, BufferSize);
/* Update the index */
RawChannelSetIBufferIndex(Channel, BufferSize + Index);
/* Signal the event, if one was set */
if (Channel->Flags & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT)
{
ChannelSetEvent(Channel, HasNewDataEvent);
}
/* All done */
return STATUS_SUCCESS;
}