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