1 /* 2 * PROJECT: ReactOS Drivers 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: drivers/sac/driver/rawchan.c 5 * PURPOSE: Driver for the Server Administration Console (SAC) for EMS 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include "sacdrv.h" 12 13 /* FUNCTIONS ******************************************************************/ 14 15 NTSTATUS 16 NTAPI 17 RawChannelCreate(IN PSAC_CHANNEL Channel) 18 { 19 CHECK_PARAMETER(Channel); 20 21 /* Allocate the output buffer */ 22 Channel->OBuffer = SacAllocatePool(SAC_RAW_OBUFFER_SIZE, GLOBAL_BLOCK_TAG); 23 CHECK_ALLOCATION(Channel->OBuffer); 24 25 /* Allocate the input buffer */ 26 Channel->IBuffer = SacAllocatePool(SAC_RAW_IBUFFER_SIZE, GLOBAL_BLOCK_TAG); 27 CHECK_ALLOCATION(Channel->IBuffer); 28 29 /* Reset all flags and return success */ 30 Channel->OBufferIndex = 0; 31 Channel->OBufferFirstGoodIndex = 0; 32 Channel->ChannelHasNewIBufferData = FALSE; 33 Channel->ChannelHasNewOBufferData = FALSE; 34 return STATUS_SUCCESS; 35 } 36 37 NTSTATUS 38 NTAPI 39 RawChannelDestroy(IN PSAC_CHANNEL Channel) 40 { 41 CHECK_PARAMETER(Channel); 42 43 /* Free the buffer and then destroy the channel */ 44 if (Channel->OBuffer) SacFreePool(Channel->OBuffer); 45 if (Channel->IBuffer) SacFreePool(Channel->IBuffer); 46 return ChannelDestroy(Channel); 47 } 48 49 FORCEINLINE 50 BOOLEAN 51 ChannelHasNewOBufferData(IN PSAC_CHANNEL Channel) 52 { 53 return Channel->ChannelHasNewOBufferData; 54 } 55 56 NTSTATUS 57 NTAPI 58 RawChannelORead(IN PSAC_CHANNEL Channel, 59 IN PCHAR Buffer, 60 IN ULONG BufferSize, 61 OUT PULONG ByteCount) 62 { 63 NTSTATUS Status; 64 ULONG NextIndex; 65 66 CHECK_PARAMETER1(Channel); 67 CHECK_PARAMETER2(Buffer); 68 CHECK_PARAMETER3(BufferSize > 0); 69 CHECK_PARAMETER4(ByteCount); 70 71 *ByteCount = 0; 72 73 if (ChannelHasNewOBufferData(Channel)) 74 { 75 Status = STATUS_SUCCESS; 76 77 while (TRUE) 78 { 79 Buffer[(*ByteCount)++] = Channel->OBuffer[Channel->OBufferFirstGoodIndex]; 80 81 NextIndex = (Channel->OBufferFirstGoodIndex + 1) & (SAC_OBUFFER_SIZE - 1); 82 Channel->OBufferFirstGoodIndex = NextIndex; 83 84 if (NextIndex == Channel->OBufferIndex) 85 { 86 _InterlockedExchange(&Channel->ChannelHasNewOBufferData, 0); 87 break; 88 } 89 90 ASSERT(*ByteCount > 0); 91 92 if (*ByteCount >= BufferSize) break; 93 } 94 } 95 else 96 { 97 Status = STATUS_NO_DATA_DETECTED; 98 } 99 100 if (Channel->OBufferFirstGoodIndex == Channel->OBufferIndex) 101 { 102 ASSERT(ChannelHasNewOBufferData(Channel) == FALSE); 103 } 104 105 if (ChannelHasNewOBufferData(Channel) == FALSE) 106 { 107 ASSERT(Channel->OBufferFirstGoodIndex == Channel->OBufferIndex); 108 } 109 110 return Status; 111 } 112 113 NTSTATUS 114 NTAPI 115 RawChannelOEcho(IN PSAC_CHANNEL Channel, 116 IN PCHAR String, 117 IN ULONG Length) 118 { 119 NTSTATUS Status = STATUS_SUCCESS; 120 121 CHECK_PARAMETER1(Channel); 122 CHECK_PARAMETER2(String); 123 124 if (Length) 125 { 126 Status = ConMgrWriteData(Channel, String, Length); 127 if (NT_SUCCESS(Status)) ConMgrFlushData(Channel); 128 } 129 130 return Status; 131 } 132 133 NTSTATUS 134 NTAPI 135 RawChannelOWrite2(IN PSAC_CHANNEL Channel, 136 IN PCHAR String, 137 IN ULONG Size) 138 { 139 BOOLEAN Overflow; 140 ULONG i, NextIndex; 141 142 CHECK_PARAMETER1(Channel); 143 CHECK_PARAMETER2(String); 144 145 Overflow = FALSE; 146 147 for (i = 0; i < Size; i++) 148 { 149 if ((Channel->OBufferIndex == Channel->OBufferFirstGoodIndex) && 150 ((i) || (ChannelHasNewOBufferData(Channel)))) 151 { 152 Overflow = TRUE; 153 } 154 155 ASSERT(Channel->OBufferIndex < SAC_RAW_OBUFFER_SIZE); 156 157 Channel->OBuffer[Channel->OBufferIndex] = String[i]; 158 159 NextIndex = (Channel->OBufferIndex + 1) & (SAC_RAW_OBUFFER_SIZE - 1); 160 Channel->OBufferIndex = NextIndex; 161 162 if (Overflow) Channel->OBufferFirstGoodIndex = NextIndex; 163 } 164 165 _InterlockedExchange(&Channel->ChannelHasNewOBufferData, 1); 166 167 return STATUS_SUCCESS; 168 } 169 170 NTSTATUS 171 NTAPI 172 RawChannelOFlush(IN PSAC_CHANNEL Channel) 173 { 174 NTSTATUS Status; 175 ULONG ByteCount; 176 CHAR Dummy; 177 CHECK_PARAMETER1(Channel); 178 179 while (ChannelHasNewOBufferData(Channel)) 180 { 181 Status = RawChannelORead(Channel, &Dummy, sizeof(Dummy), &ByteCount); 182 if (!NT_SUCCESS(Status)) return Status; 183 184 CHECK_PARAMETER_WITH_STATUS(ByteCount == 1, STATUS_UNSUCCESSFUL); 185 186 Status = ConMgrWriteData(Channel, &Dummy, sizeof(Dummy)); 187 if (!NT_SUCCESS(Status)) return Status; 188 } 189 190 return ConMgrFlushData(Channel); 191 } 192 193 NTSTATUS 194 NTAPI 195 RawChannelOWrite(IN PSAC_CHANNEL Channel, 196 IN PCHAR String, 197 IN ULONG Length) 198 { 199 CHECK_PARAMETER1(Channel); 200 CHECK_PARAMETER2(String); 201 202 if ((ConMgrIsWriteEnabled(Channel)) && (Channel->WriteEnabled)) 203 { 204 return RawChannelOEcho(Channel, String, Length); 205 } 206 207 return RawChannelOWrite2(Channel, String, Length); 208 } 209 210 ULONG 211 NTAPI 212 RawChannelGetIBufferIndex(IN PSAC_CHANNEL Channel) 213 { 214 ASSERT(Channel); 215 ASSERT(Channel->IBufferIndex < SAC_RAW_IBUFFER_SIZE); 216 217 /* Return the current buffer index */ 218 return Channel->IBufferIndex; 219 } 220 221 VOID 222 NTAPI 223 RawChannelSetIBufferIndex(IN PSAC_CHANNEL Channel, 224 IN ULONG BufferIndex) 225 { 226 NTSTATUS Status; 227 ASSERT(Channel); 228 ASSERT(Channel->IBufferIndex < SAC_RAW_IBUFFER_SIZE); 229 230 /* Set the new index, and if it's not zero, it means we have data */ 231 Channel->IBufferIndex = BufferIndex; 232 _InterlockedExchange(&Channel->ChannelHasNewIBufferData, BufferIndex != 0); 233 234 /* If we have new data, and an event has been registered... */ 235 if (!(Channel->IBufferIndex) && 236 (Channel->Flags & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT)) 237 { 238 /* Go ahead and signal it */ 239 ChannelClearEvent(Channel, HasNewDataEvent); 240 UNREFERENCED_PARAMETER(Status); 241 } 242 } 243 244 NTSTATUS 245 NTAPI 246 RawChannelIRead(IN PSAC_CHANNEL Channel, 247 IN PCHAR Buffer, 248 IN ULONG BufferSize, 249 IN PULONG ReturnBufferSize) 250 { 251 ULONG CopyChars; 252 CHECK_PARAMETER1(Channel); 253 CHECK_PARAMETER2(Buffer); 254 CHECK_PARAMETER_WITH_STATUS(BufferSize > 0, STATUS_INVALID_BUFFER_SIZE); 255 256 /* Assume failure */ 257 *ReturnBufferSize = 0; 258 259 /* Check how many bytes are in the buffer */ 260 if (Channel->ChannelInputBufferLength(Channel) == 0) 261 { 262 /* Apparently nothing. Make sure the flag indicates so too */ 263 ASSERT(ChannelHasNewIBufferData(Channel) == FALSE); 264 } 265 else 266 { 267 /* Use the smallest number of bytes either in the buffer or requested */ 268 CopyChars = min(Channel->ChannelInputBufferLength(Channel), BufferSize); 269 ASSERT(CopyChars <= Channel->ChannelInputBufferLength(Channel)); 270 271 /* Copy them into the caller's buffer */ 272 RtlCopyMemory(Buffer, Channel->IBuffer, CopyChars); 273 274 /* Update the channel's index past the copied (read) bytes */ 275 RawChannelSetIBufferIndex(Channel, 276 RawChannelGetIBufferIndex(Channel) - CopyChars); 277 278 /* Are there still bytes that haven't been read yet? */ 279 if (Channel->ChannelInputBufferLength(Channel)) 280 { 281 /* Shift them up in the buffer */ 282 RtlMoveMemory(Channel->IBuffer, 283 &Channel->IBuffer[CopyChars], 284 Channel->ChannelInputBufferLength(Channel)); 285 } 286 287 /* Return the number of bytes we actually copied */ 288 *ReturnBufferSize = CopyChars; 289 } 290 291 /* Return success */ 292 return STATUS_SUCCESS; 293 } 294 295 NTSTATUS 296 NTAPI 297 RawChannelIBufferIsFull(IN PSAC_CHANNEL Channel, 298 OUT PBOOLEAN BufferStatus) 299 { 300 CHECK_PARAMETER1(Channel); 301 CHECK_PARAMETER2(BufferStatus); 302 303 /* If the index is beyond the length, the buffer must be full */ 304 *BufferStatus = RawChannelGetIBufferIndex(Channel) > SAC_RAW_IBUFFER_SIZE; 305 return STATUS_SUCCESS; 306 } 307 308 ULONG 309 NTAPI 310 RawChannelIBufferLength(IN PSAC_CHANNEL Channel) 311 { 312 ASSERT(Channel); 313 314 /* The index is the current length (since we're 0-based) */ 315 return RawChannelGetIBufferIndex(Channel); 316 } 317 318 WCHAR 319 NTAPI 320 RawChannelIReadLast(IN PSAC_CHANNEL Channel) 321 { 322 UCHAR LastChar = 0; 323 ASSERT(Channel); 324 325 /* Check if there's anything to read in the buffer */ 326 if (Channel->ChannelInputBufferLength(Channel)) 327 { 328 /* Go back one character */ 329 RawChannelSetIBufferIndex(Channel, 330 RawChannelGetIBufferIndex(Channel) - 1); 331 332 /* Read it, and clear its current value */ 333 LastChar = Channel->IBuffer[RawChannelGetIBufferIndex(Channel)]; 334 Channel->IBuffer[RawChannelGetIBufferIndex(Channel)] = ANSI_NULL; 335 } 336 337 /* Return the last character */ 338 return LastChar; 339 } 340 341 NTSTATUS 342 NTAPI 343 RawChannelIWrite(IN PSAC_CHANNEL Channel, 344 IN PCHAR Buffer, 345 IN ULONG BufferSize) 346 { 347 NTSTATUS Status; 348 BOOLEAN IsFull; 349 ULONG Index; 350 CHECK_PARAMETER1(Channel); 351 CHECK_PARAMETER2(Buffer); 352 CHECK_PARAMETER_WITH_STATUS(BufferSize > 0, STATUS_INVALID_BUFFER_SIZE); 353 354 /* First, check if the input buffer still has space */ 355 Status = RawChannelIBufferIsFull(Channel, &IsFull); 356 if (!NT_SUCCESS(Status)) return Status; 357 if (IsFull) return STATUS_UNSUCCESSFUL; 358 359 /* Get the current buffer index */ 360 Index = RawChannelGetIBufferIndex(Channel); 361 if ((SAC_RAW_IBUFFER_SIZE - Index) < BufferSize) 362 { 363 return STATUS_INSUFFICIENT_RESOURCES; 364 } 365 366 /* Copy the new data */ 367 RtlCopyMemory(&Channel->IBuffer[Index], Buffer, BufferSize); 368 369 /* Update the index */ 370 RawChannelSetIBufferIndex(Channel, BufferSize + Index); 371 372 /* Signal the event, if one was set */ 373 if (Channel->Flags & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT) 374 { 375 ChannelSetEvent(Channel, HasNewDataEvent); 376 } 377 378 /* All done */ 379 return STATUS_SUCCESS; 380 } 381