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
RawChannelCreate(IN PSAC_CHANNEL Channel)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
RawChannelDestroy(IN PSAC_CHANNEL Channel)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
ChannelHasNewOBufferData(IN PSAC_CHANNEL Channel)51 ChannelHasNewOBufferData(IN PSAC_CHANNEL Channel)
52 {
53 return Channel->ChannelHasNewOBufferData;
54 }
55
56 NTSTATUS
57 NTAPI
RawChannelORead(IN PSAC_CHANNEL Channel,IN PCHAR Buffer,IN ULONG BufferSize,OUT PULONG ByteCount)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
RawChannelOEcho(IN PSAC_CHANNEL Channel,IN PCHAR String,IN ULONG Length)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
RawChannelOWrite2(IN PSAC_CHANNEL Channel,IN PCHAR String,IN ULONG Size)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
RawChannelOFlush(IN PSAC_CHANNEL Channel)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
RawChannelOWrite(IN PSAC_CHANNEL Channel,IN PCHAR String,IN ULONG Length)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
RawChannelGetIBufferIndex(IN PSAC_CHANNEL Channel)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
RawChannelSetIBufferIndex(IN PSAC_CHANNEL Channel,IN ULONG BufferIndex)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
RawChannelIRead(IN PSAC_CHANNEL Channel,IN PCHAR Buffer,IN ULONG BufferSize,IN PULONG ReturnBufferSize)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
RawChannelIBufferIsFull(IN PSAC_CHANNEL Channel,OUT PBOOLEAN BufferStatus)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
RawChannelIBufferLength(IN PSAC_CHANNEL Channel)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
RawChannelIReadLast(IN PSAC_CHANNEL Channel)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
RawChannelIWrite(IN PSAC_CHANNEL Channel,IN PCHAR Buffer,IN ULONG BufferSize)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