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
9 /* INCLUDES *******************************************************************/
13 /* FUNCTIONS ******************************************************************/
17 RawChannelCreate(IN PSAC_CHANNEL Channel
)
19 CHECK_PARAMETER(Channel
);
21 /* Allocate the output buffer */
22 Channel
->OBuffer
= SacAllocatePool(SAC_RAW_OBUFFER_SIZE
, GLOBAL_BLOCK_TAG
);
23 CHECK_ALLOCATION(Channel
->OBuffer
);
25 /* Allocate the input buffer */
26 Channel
->IBuffer
= SacAllocatePool(SAC_RAW_IBUFFER_SIZE
, GLOBAL_BLOCK_TAG
);
27 CHECK_ALLOCATION(Channel
->IBuffer
);
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
;
39 RawChannelDestroy(IN PSAC_CHANNEL Channel
)
41 CHECK_PARAMETER(Channel
);
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
);
51 ChannelHasNewOBufferData(IN PSAC_CHANNEL Channel
)
53 return Channel
->ChannelHasNewOBufferData
;
58 RawChannelORead(IN PSAC_CHANNEL Channel
,
66 CHECK_PARAMETER1(Channel
);
67 CHECK_PARAMETER2(Buffer
);
68 CHECK_PARAMETER3(BufferSize
> 0);
69 CHECK_PARAMETER4(ByteCount
);
73 if (ChannelHasNewOBufferData(Channel
))
75 Status
= STATUS_SUCCESS
;
79 Buffer
[(*ByteCount
)++] = Channel
->OBuffer
[Channel
->OBufferFirstGoodIndex
];
81 NextIndex
= (Channel
->OBufferFirstGoodIndex
+ 1) & (SAC_OBUFFER_SIZE
- 1);
82 Channel
->OBufferFirstGoodIndex
= NextIndex
;
84 if (NextIndex
== Channel
->OBufferIndex
)
86 _InterlockedExchange(&Channel
->ChannelHasNewOBufferData
, 0);
90 ASSERT(*ByteCount
> 0);
92 if (*ByteCount
>= BufferSize
) break;
97 Status
= STATUS_NO_DATA_DETECTED
;
100 if (Channel
->OBufferFirstGoodIndex
== Channel
->OBufferIndex
)
102 ASSERT(ChannelHasNewOBufferData(Channel
) == FALSE
);
105 if (ChannelHasNewOBufferData(Channel
) == FALSE
)
107 ASSERT(Channel
->OBufferFirstGoodIndex
== Channel
->OBufferIndex
);
115 RawChannelOEcho(IN PSAC_CHANNEL Channel
,
119 NTSTATUS Status
= STATUS_SUCCESS
;
121 CHECK_PARAMETER1(Channel
);
122 CHECK_PARAMETER2(String
);
126 Status
= ConMgrWriteData(Channel
, String
, Length
);
127 if (NT_SUCCESS(Status
)) ConMgrFlushData(Channel
);
135 RawChannelOWrite2(IN PSAC_CHANNEL Channel
,
142 CHECK_PARAMETER1(Channel
);
143 CHECK_PARAMETER2(String
);
147 for (i
= 0; i
< Size
; i
++)
149 if ((Channel
->OBufferIndex
== Channel
->OBufferFirstGoodIndex
) &&
150 ((i
) || (ChannelHasNewOBufferData(Channel
))))
155 ASSERT(Channel
->OBufferIndex
< SAC_RAW_OBUFFER_SIZE
);
157 Channel
->OBuffer
[Channel
->OBufferIndex
] = String
[i
];
159 NextIndex
= (Channel
->OBufferIndex
+ 1) & (SAC_RAW_OBUFFER_SIZE
- 1);
160 Channel
->OBufferIndex
= NextIndex
;
162 if (Overflow
) Channel
->OBufferFirstGoodIndex
= NextIndex
;
165 _InterlockedExchange(&Channel
->ChannelHasNewOBufferData
, 1);
167 return STATUS_SUCCESS
;
172 RawChannelOFlush(IN PSAC_CHANNEL Channel
)
177 CHECK_PARAMETER1(Channel
);
179 while (ChannelHasNewOBufferData(Channel
))
181 Status
= RawChannelORead(Channel
, &Dummy
, sizeof(Dummy
), &ByteCount
);
182 if (!NT_SUCCESS(Status
)) return Status
;
184 CHECK_PARAMETER_WITH_STATUS(ByteCount
== 1, STATUS_UNSUCCESSFUL
);
186 Status
= ConMgrWriteData(Channel
, &Dummy
, sizeof(Dummy
));
187 if (!NT_SUCCESS(Status
)) return Status
;
190 return ConMgrFlushData(Channel
);
195 RawChannelOWrite(IN PSAC_CHANNEL Channel
,
199 CHECK_PARAMETER1(Channel
);
200 CHECK_PARAMETER2(String
);
202 if ((ConMgrIsWriteEnabled(Channel
)) && (Channel
->WriteEnabled
))
204 return RawChannelOEcho(Channel
, String
, Length
);
207 return RawChannelOWrite2(Channel
, String
, Length
);
212 RawChannelGetIBufferIndex(IN PSAC_CHANNEL Channel
)
215 ASSERT(Channel
->IBufferIndex
< SAC_RAW_IBUFFER_SIZE
);
217 /* Return the current buffer index */
218 return Channel
->IBufferIndex
;
223 RawChannelSetIBufferIndex(IN PSAC_CHANNEL Channel
,
224 IN ULONG BufferIndex
)
228 ASSERT(Channel
->IBufferIndex
< SAC_RAW_IBUFFER_SIZE
);
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);
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
))
238 /* Go ahead and signal it */
239 ChannelClearEvent(Channel
, HasNewDataEvent
);
240 UNREFERENCED_PARAMETER(Status
);
246 RawChannelIRead(IN PSAC_CHANNEL Channel
,
249 IN PULONG ReturnBufferSize
)
252 CHECK_PARAMETER1(Channel
);
253 CHECK_PARAMETER2(Buffer
);
254 CHECK_PARAMETER_WITH_STATUS(BufferSize
> 0, STATUS_INVALID_BUFFER_SIZE
);
257 *ReturnBufferSize
= 0;
259 /* Check how many bytes are in the buffer */
260 if (Channel
->ChannelInputBufferLength(Channel
) == 0)
262 /* Apparently nothing. Make sure the flag indicates so too */
263 ASSERT(ChannelHasNewIBufferData(Channel
) == FALSE
);
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
));
271 /* Copy them into the caller's buffer */
272 RtlCopyMemory(Buffer
, Channel
->IBuffer
, CopyChars
);
274 /* Update the channel's index past the copied (read) bytes */
275 RawChannelSetIBufferIndex(Channel
,
276 RawChannelGetIBufferIndex(Channel
) - CopyChars
);
278 /* Are there still bytes that haven't been read yet? */
279 if (Channel
->ChannelInputBufferLength(Channel
))
281 /* Shift them up in the buffer */
282 RtlMoveMemory(Channel
->IBuffer
,
283 &Channel
->IBuffer
[CopyChars
],
284 Channel
->ChannelInputBufferLength(Channel
));
287 /* Return the number of bytes we actually copied */
288 *ReturnBufferSize
= CopyChars
;
292 return STATUS_SUCCESS
;
297 RawChannelIBufferIsFull(IN PSAC_CHANNEL Channel
,
298 OUT PBOOLEAN BufferStatus
)
300 CHECK_PARAMETER1(Channel
);
301 CHECK_PARAMETER2(BufferStatus
);
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
;
310 RawChannelIBufferLength(IN PSAC_CHANNEL Channel
)
314 /* The index is the current length (since we're 0-based) */
315 return RawChannelGetIBufferIndex(Channel
);
320 RawChannelIReadLast(IN PSAC_CHANNEL Channel
)
325 /* Check if there's anything to read in the buffer */
326 if (Channel
->ChannelInputBufferLength(Channel
))
328 /* Go back one character */
329 RawChannelSetIBufferIndex(Channel
,
330 RawChannelGetIBufferIndex(Channel
) - 1);
332 /* Read it, and clear its current value */
333 LastChar
= Channel
->IBuffer
[RawChannelGetIBufferIndex(Channel
)];
334 Channel
->IBuffer
[RawChannelGetIBufferIndex(Channel
)] = ANSI_NULL
;
337 /* Return the last character */
343 RawChannelIWrite(IN PSAC_CHANNEL Channel
,
350 CHECK_PARAMETER1(Channel
);
351 CHECK_PARAMETER2(Buffer
);
352 CHECK_PARAMETER_WITH_STATUS(BufferSize
> 0, STATUS_INVALID_BUFFER_SIZE
);
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
;
359 /* Get the current buffer index */
360 Index
= RawChannelGetIBufferIndex(Channel
);
361 if ((SAC_RAW_IBUFFER_SIZE
- Index
) < BufferSize
)
363 return STATUS_INSUFFICIENT_RESOURCES
;
366 /* Copy the new data */
367 RtlCopyMemory(&Channel
->IBuffer
[Index
], Buffer
, BufferSize
);
369 /* Update the index */
370 RawChannelSetIBufferIndex(Channel
, BufferSize
+ Index
);
372 /* Signal the event, if one was set */
373 if (Channel
->Flags
& SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT
)
375 ChannelSetEvent(Channel
, HasNewDataEvent
);
379 return STATUS_SUCCESS
;