/*
- * PROJECT: ReactOS Boot Loader
- * 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
+ * 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 *******************************************************************/
+/* INCLUDES ******************************************************************/
#include "sacdrv.h"
-/* GLOBALS ********************************************************************/
+/* GLOBALS *******************************************************************/
-/* FUNCTIONS ******************************************************************/
+/* FUNCTIONS *****************************************************************/
+
+#define SAC_RAW_OBUFFER_SIZE 0x2000
+#define SAC_RAW_IBUFFER_SIZE 0x2000
NTSTATUS
-RawChannelCreate(
- IN PSAC_CHANNEL Channel
- )
+NTAPI
+RawChannelCreate(IN PSAC_CHANNEL Channel)
{
- return STATUS_NOT_IMPLEMENTED;
+ 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
-RawChannelDestroy(
- IN PSAC_CHANNEL Channel
- )
+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 STATUS_NOT_IMPLEMENTED;
+ return Channel->ChannelHasNewOBufferData;
}
NTSTATUS
-RawChannelORead(
- IN PSAC_CHANNEL Channel,
- IN PCHAR Buffer,
- IN ULONG BufferSize,
- OUT PULONG ByteCount
- )
+NTAPI
+RawChannelORead(IN PSAC_CHANNEL Channel,
+ IN PCHAR Buffer,
+ IN ULONG BufferSize,
+ OUT PULONG ByteCount)
{
- return STATUS_NOT_IMPLEMENTED;
+ 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
-RawChannelOEcho(
- IN PSAC_CHANNEL Channel,
- IN PWCHAR String,
- IN ULONG Length
- )
+NTAPI
+RawChannelOEcho(IN PSAC_CHANNEL Channel,
+ IN PCHAR String,
+ IN ULONG Length)
{
- return STATUS_NOT_IMPLEMENTED;
+ 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
-RawChannelOWrite2(
- IN PSAC_CHANNEL Channel,
- IN PCHAR String,
- IN ULONG Size
- )
+NTAPI
+RawChannelOWrite2(IN PSAC_CHANNEL Channel,
+ IN PCHAR String,
+ IN ULONG Size)
{
- return STATUS_NOT_IMPLEMENTED;
+ 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
-RawChannelOFlush(
- IN PSAC_CHANNEL Channel
- )
+NTAPI
+RawChannelOFlush(IN PSAC_CHANNEL Channel)
{
- return STATUS_NOT_IMPLEMENTED;
+ 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);
}
-ULONG
-RawChannelGetIBufferIndex(
- IN PSAC_CHANNEL Channel
- )
+NTSTATUS
+NTAPI
+RawChannelOWrite(IN PSAC_CHANNEL Channel,
+ IN PCHAR String,
+ IN ULONG Length)
{
- return 0;
+ CHECK_PARAMETER1(Channel);
+ CHECK_PARAMETER2(String);
+
+ if ((ConMgrIsWriteEnabled(Channel)) && (Channel->WriteEnabled))
+ {
+ return RawChannelOEcho(Channel, String, Length);
+ }
+
+ return RawChannelOWrite2(Channel, String, Length);
}
-VOID
-RawChannelSetIBufferIndex(
- IN PSAC_CHANNEL Channel,
- IN ULONG BufferIndex
- )
+ULONG
+NTAPI
+RawChannelGetIBufferIndex(IN PSAC_CHANNEL Channel)
{
+ ASSERT(Channel);
+ ASSERT(Channel->IBufferIndex < SAC_RAW_IBUFFER_SIZE);
+ /* Return the current buffer index */
+ return Channel->IBufferIndex;
}
-NTSTATUS
-RawChannelOWrite(
- IN PSAC_CHANNEL Channel,
- IN PWCHAR String,
- IN ULONG Length
- )
+VOID
+NTAPI
+RawChannelSetIBufferIndex(IN PSAC_CHANNEL Channel,
+ IN ULONG BufferIndex)
{
- return STATUS_NOT_IMPLEMENTED;
+ 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
-RawChannelIRead(
- IN PSAC_CHANNEL Channel,
- IN PCHAR Buffer,
- IN ULONG BufferSize,
- IN PULONG ReturnBufferSize
- )
+NTAPI
+RawChannelIRead(IN PSAC_CHANNEL Channel,
+ IN PCHAR Buffer,
+ IN ULONG BufferSize,
+ IN PULONG ReturnBufferSize)
{
- return STATUS_NOT_IMPLEMENTED;
+ 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
-RawChannelIBufferIsFull(
- IN PSAC_CHANNEL Channel,
- PBOOLEAN BufferStatus
- )
+NTAPI
+RawChannelIBufferIsFull(IN PSAC_CHANNEL Channel,
+ OUT PBOOLEAN BufferStatus)
{
- return STATUS_NOT_IMPLEMENTED;
+ 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
-RawChannelIBufferLength(
- IN PSAC_CHANNEL Channel
- )
+NTAPI
+RawChannelIBufferLength(IN PSAC_CHANNEL Channel)
{
- return 0;
+ ASSERT(Channel);
+
+ /* The index is the current length (since we're 0-based) */
+ return RawChannelGetIBufferIndex(Channel);
}
-CHAR
-RawChannelIReadLast(
- IN PSAC_CHANNEL Channel
- )
+WCHAR
+NTAPI
+RawChannelIReadLast(IN PSAC_CHANNEL Channel)
{
- return 0;
+ 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
-RawChannelIWrite(
- IN PSAC_CHANNEL Channel,
- IN PCHAR Buffer,
- IN ULONG BufferSize
- )
+NTAPI
+RawChannelIWrite(IN PSAC_CHANNEL Channel,
+ IN PCHAR Buffer,
+ IN ULONG BufferSize)
{
- return STATUS_NOT_IMPLEMENTED;
+ 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;
}