xref: /reactos/drivers/sac/driver/rawchan.c (revision c2c66aff)
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