/* * 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; }