Sync with trunk.
[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 Channel->OBuffer = SacAllocatePool(SAC_RAW_OBUFFER_SIZE, GLOBAL_BLOCK_TAG);
27 CHECK_ALLOCATION(Channel->OBuffer);
28
29 Channel->IBuffer = SacAllocatePool(SAC_RAW_IBUFFER_SIZE, GLOBAL_BLOCK_TAG);
30 CHECK_ALLOCATION(Channel->IBuffer);
31
32 Channel->OBufferIndex = 0;
33 Channel->OBufferFirstGoodIndex = 0;
34 Channel->ChannelHasNewIBufferData = FALSE;
35 Channel->ChannelHasNewOBufferData = FALSE;
36
37 return STATUS_SUCCESS;
38 }
39
40 NTSTATUS
41 NTAPI
42 RawChannelDestroy(IN PSAC_CHANNEL Channel)
43 {
44 CHECK_PARAMETER(Channel);
45
46 if (Channel->OBuffer)
47 {
48 SacFreePool(Channel->OBuffer);
49 }
50
51 if (Channel->IBuffer)
52 {
53 SacFreePool(Channel->IBuffer);
54 }
55
56 return ChannelDestroy(Channel);
57 }
58
59 FORCEINLINE
60 BOOLEAN
61 ChannelHasNewOBufferData(IN PSAC_CHANNEL Channel)
62 {
63 return Channel->ChannelHasNewOBufferData;
64 }
65
66 FORCEINLINE
67 BOOLEAN
68 ChannelHasNewIBufferData(IN PSAC_CHANNEL Channel)
69 {
70 return Channel->ChannelHasNewIBufferData;
71 }
72
73 NTSTATUS
74 NTAPI
75 RawChannelORead(IN PSAC_CHANNEL Channel,
76 IN PCHAR Buffer,
77 IN ULONG BufferSize,
78 OUT PULONG ByteCount)
79 {
80 NTSTATUS Status;
81 ULONG NextIndex;
82
83 CHECK_PARAMETER1(Channel);
84 CHECK_PARAMETER2(Buffer);
85 CHECK_PARAMETER3(BufferSize > 0);
86 CHECK_PARAMETER4(ByteCount);
87
88 *ByteCount = 0;
89
90 if (ChannelHasNewOBufferData(Channel))
91 {
92 Status = STATUS_SUCCESS;
93
94 while (TRUE)
95 {
96 Buffer[(*ByteCount)++] = Channel->OBuffer[Channel->OBufferFirstGoodIndex];
97
98 NextIndex = (Channel->OBufferFirstGoodIndex + 1) & (SAC_OBUFFER_SIZE - 1);
99 Channel->OBufferFirstGoodIndex = NextIndex;
100
101 if (NextIndex == Channel->OBufferIndex)
102 {
103 _InterlockedExchange(&Channel->ChannelHasNewOBufferData, 0);
104 break;
105 }
106
107 ASSERT(*ByteCount > 0);
108
109 if (*ByteCount >= BufferSize) break;
110 }
111 }
112 else
113 {
114 Status = STATUS_NO_DATA_DETECTED;
115 }
116
117 if (Channel->OBufferFirstGoodIndex == Channel->OBufferIndex)
118 {
119 ASSERT(ChannelHasNewOBufferData(Channel) == FALSE);
120 }
121
122 if (ChannelHasNewOBufferData(Channel) == FALSE)
123 {
124 ASSERT(Channel->OBufferFirstGoodIndex == Channel->OBufferIndex);
125 }
126
127 return Status;
128 }
129
130 NTSTATUS
131 NTAPI
132 RawChannelOEcho(IN PSAC_CHANNEL Channel,
133 IN PCHAR String,
134 IN ULONG Length)
135 {
136 NTSTATUS Status = STATUS_SUCCESS;
137
138 CHECK_PARAMETER1(Channel);
139 CHECK_PARAMETER2(String);
140
141 if (Length)
142 {
143 Status = ConMgrWriteData(Channel, String, Length);
144 if (NT_SUCCESS(Status)) ConMgrFlushData(Channel);
145 }
146
147 return Status;
148 }
149
150 NTSTATUS
151 NTAPI
152 RawChannelOWrite2(IN PSAC_CHANNEL Channel,
153 IN PCHAR String,
154 IN ULONG Size)
155 {
156 BOOLEAN Overflow;
157 ULONG i, NextIndex;
158
159 CHECK_PARAMETER1(Channel);
160 CHECK_PARAMETER2(String);
161
162 Overflow = FALSE;
163
164 for (i = 0; i < Size; i++)
165 {
166 if ((Channel->OBufferIndex == Channel->OBufferFirstGoodIndex) &&
167 ((i) || (ChannelHasNewOBufferData(Channel))))
168 {
169 Overflow = TRUE;
170 }
171
172 ASSERT(Channel->OBufferIndex < SAC_RAW_OBUFFER_SIZE);
173
174 Channel->OBuffer[Channel->OBufferIndex] = String[i];
175
176 NextIndex = (Channel->OBufferIndex + 1) & (SAC_RAW_OBUFFER_SIZE - 1);
177 Channel->OBufferIndex = NextIndex;
178
179 if (Overflow) Channel->OBufferFirstGoodIndex = NextIndex;
180 }
181
182 _InterlockedExchange(&Channel->ChannelHasNewOBufferData, 1);
183
184 return STATUS_SUCCESS;
185 }
186
187 NTSTATUS
188 NTAPI
189 RawChannelOFlush(IN PSAC_CHANNEL Channel)
190 {
191 NTSTATUS Status;
192 ULONG ByteCount;
193 CHAR Dummy;
194 CHECK_PARAMETER1(Channel);
195
196 while (ChannelHasNewOBufferData(Channel))
197 {
198 Status = RawChannelORead(Channel, &Dummy, sizeof(Dummy), &ByteCount);
199 if (!NT_SUCCESS(Status)) return Status;
200
201 CHECK_PARAMETER_WITH_STATUS(ByteCount == 1, STATUS_UNSUCCESSFUL);
202
203 Status = ConMgrWriteData(Channel, &Dummy, sizeof(Dummy));
204 if (!NT_SUCCESS(Status)) return Status;
205 }
206
207 return ConMgrFlushData(Channel);
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 Channel->IBufferIndex;
218 }
219
220 VOID
221 NTAPI
222 RawChannelSetIBufferIndex(IN PSAC_CHANNEL Channel,
223 IN ULONG BufferIndex)
224 {
225 NTSTATUS Status;
226 ASSERT(Channel);
227 ASSERT(Channel->IBufferIndex < SAC_RAW_IBUFFER_SIZE);
228
229 Channel->IBufferIndex = BufferIndex;
230 Channel->ChannelHasNewIBufferData = BufferIndex != 0;
231
232 if (!Channel->IBufferIndex)
233 {
234 if (Channel->Flags & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT)
235 {
236 ChannelClearEvent(Channel, HasNewDataEvent);
237 UNREFERENCED_PARAMETER(Status);
238 }
239 }
240 }
241
242 NTSTATUS
243 NTAPI
244 RawChannelOWrite(IN PSAC_CHANNEL Channel,
245 IN PCHAR String,
246 IN ULONG Length)
247 {
248 CHECK_PARAMETER1(Channel);
249 CHECK_PARAMETER2(String);
250
251 if ((ConMgrIsWriteEnabled(Channel)) && (Channel->WriteEnabled))
252 {
253 return RawChannelOEcho(Channel, String, Length);
254 }
255
256 return RawChannelOWrite2(Channel, String, Length);
257 }
258
259 NTSTATUS
260 NTAPI
261 RawChannelIRead(IN PSAC_CHANNEL Channel,
262 IN PCHAR Buffer,
263 IN ULONG BufferSize,
264 IN PULONG ReturnBufferSize)
265 {
266 ULONG CopyChars;
267
268 CHECK_PARAMETER1(Channel);
269 CHECK_PARAMETER2(Buffer);
270 CHECK_PARAMETER_WITH_STATUS(BufferSize > 0, STATUS_INVALID_BUFFER_SIZE);
271
272 *ReturnBufferSize = 0;
273
274 if (Channel->ChannelInputBufferLength(Channel) == 0)
275 {
276 ASSERT(ChannelHasNewIBufferData(Channel) == FALSE);
277 }
278 else
279 {
280 CopyChars = Channel->ChannelInputBufferLength(Channel);
281 if (CopyChars > BufferSize) CopyChars = BufferSize;
282 ASSERT(CopyChars <= Channel->ChannelInputBufferLength(Channel));
283
284 RtlCopyMemory(Buffer, Channel->IBuffer, CopyChars);
285
286 RawChannelSetIBufferIndex(Channel,
287 RawChannelGetIBufferIndex(Channel) - CopyChars);
288
289 if (Channel->ChannelInputBufferLength(Channel))
290 {
291 RtlMoveMemory(Channel->IBuffer,
292 &Channel->IBuffer[CopyChars],
293 Channel->ChannelInputBufferLength(Channel));
294 }
295
296 *ReturnBufferSize = CopyChars;
297 }
298
299 return STATUS_SUCCESS;
300 }
301
302 NTSTATUS
303 NTAPI
304 RawChannelIBufferIsFull(IN PSAC_CHANNEL Channel,
305 OUT PBOOLEAN BufferStatus)
306 {
307 CHECK_PARAMETER1(Channel);
308 CHECK_PARAMETER2(BufferStatus);
309
310 *BufferStatus = RawChannelGetIBufferIndex(Channel) > SAC_RAW_IBUFFER_SIZE;
311 return STATUS_SUCCESS;
312 }
313
314 ULONG
315 NTAPI
316 RawChannelIBufferLength(IN PSAC_CHANNEL Channel)
317 {
318 ASSERT(Channel);
319 return RawChannelGetIBufferIndex(Channel);
320 }
321
322 CHAR
323 NTAPI
324 RawChannelIReadLast(IN PSAC_CHANNEL Channel)
325 {
326 UCHAR LastChar = 0;
327
328 ASSERT(Channel);
329
330 if (Channel->ChannelInputBufferLength(Channel))
331 {
332 RawChannelSetIBufferIndex(Channel, RawChannelGetIBufferIndex(Channel) - 1);
333
334 LastChar = Channel->IBuffer[RawChannelGetIBufferIndex(Channel)];
335 Channel->IBuffer[RawChannelGetIBufferIndex(Channel)] = 0;
336 }
337
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
351 CHECK_PARAMETER1(Channel);
352 CHECK_PARAMETER2(Buffer);
353 CHECK_PARAMETER_WITH_STATUS(BufferSize > 0, STATUS_INVALID_BUFFER_SIZE);
354
355 Status = RawChannelIBufferIsFull(Channel, &IsFull);
356 if (!NT_SUCCESS(Status)) return Status;
357
358 if (IsFull) return STATUS_UNSUCCESSFUL;
359
360 Index = RawChannelGetIBufferIndex(Channel);
361 if ((SAC_RAW_IBUFFER_SIZE - Index) >= BufferSize) return STATUS_INSUFFICIENT_RESOURCES;
362
363 RtlCopyMemory(&Channel->IBuffer[Index], Buffer, BufferSize);
364
365 RawChannelSetIBufferIndex(Channel, BufferSize + Index);
366
367 if (Channel->Flags & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT)
368 {
369 ChannelSetEvent(Channel, HasNewDataEvent);
370 }
371
372 return STATUS_SUCCESS;
373 }