1 /*
2 * PROJECT: ReactOS Drivers
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/sac/driver/conmgr.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 #include <initguid.h>
14
15 /* GLOBALS ********************************************************************/
16
17 DEFINE_GUID(PRIMARY_SAC_CHANNEL_APPLICATION_GUID,
18 0x63D02270,
19 0x8AA4,
20 0x11D5,
21 0xBC, 0xCF, 0x80, 0x6D, 0x61, 0x72, 0x69, 0x6F);
22
23 LONG CurrentChannelRefCount;
24 KMUTEX CurrentChannelLock;
25
26 PSAC_CHANNEL CurrentChannel;
27 PSAC_CHANNEL SacChannel;
28
29 ULONG ExecutePostConsumerCommand;
30 PSAC_CHANNEL ExecutePostConsumerCommandData;
31
32 BOOLEAN InputInEscape, InputInEscTab, ConMgrLastCharWasCR;
33 CHAR InputBuffer[80];
34
35 BOOLEAN GlobalPagingNeeded, GlobalDoThreads;
36
37 /* FUNCTIONS ******************************************************************/
38
39 VOID
40 NTAPI
SacPutString(IN PWCHAR String)41 SacPutString(IN PWCHAR String)
42 {
43 NTSTATUS Status;
44
45 /* Write the string on the main SAC channel */
46 Status = ChannelOWrite(SacChannel,
47 (PCHAR)String,
48 wcslen(String) * sizeof(WCHAR));
49 if (!NT_SUCCESS(Status))
50 {
51 SAC_DBG(SAC_DBG_INIT, "SAC XmlMgrSacPutString: OWrite failed\n");
52 }
53 }
54
55 BOOLEAN
56 NTAPI
SacPutSimpleMessage(IN ULONG MessageIndex)57 SacPutSimpleMessage(IN ULONG MessageIndex)
58 {
59 PWCHAR MessageBuffer;
60 BOOLEAN Result;
61
62 /* Get the message */
63 MessageBuffer = GetMessage(MessageIndex);
64 if (MessageBuffer)
65 {
66 /* Output it */
67 SacPutString(MessageBuffer);
68 Result = TRUE;
69 }
70 else
71 {
72 Result = FALSE;
73 }
74
75 /* All done */
76 return Result;
77 }
78
79 NTSTATUS
80 NTAPI
ConMgrDisplayCurrentChannel(VOID)81 ConMgrDisplayCurrentChannel(VOID)
82 {
83 NTSTATUS Status;
84 BOOLEAN HasRedraw;
85
86 /* Make sure the lock is held */
87 SacAssertMutexLockHeld();
88
89 /* Check if we can redraw */
90 Status = ChannelHasRedrawEvent(CurrentChannel, &HasRedraw);
91 if (NT_SUCCESS(Status))
92 {
93 /* Enable writes */
94 _InterlockedExchange(&CurrentChannel->WriteEnabled, 1);
95 if (HasRedraw)
96 {
97 /* If we can redraw, set the event */
98 ChannelSetRedrawEvent(CurrentChannel);
99 }
100
101 /* Flush the output */
102 Status = ChannelOFlush(CurrentChannel);
103 }
104
105 /* All done, return the status */
106 return Status;
107 }
108
109 NTSTATUS
110 NTAPI
ConMgrWriteData(IN PSAC_CHANNEL Channel,IN PVOID Buffer,IN ULONG BufferLength)111 ConMgrWriteData(IN PSAC_CHANNEL Channel,
112 IN PVOID Buffer,
113 IN ULONG BufferLength)
114 {
115 ULONG i;
116 NTSTATUS Status;
117 LARGE_INTEGER Interval;
118
119 /* Loop up to 32 times */
120 for (i = 0; i < 32; i++)
121 {
122 /* Attempt sending the data */
123 Status = HeadlessDispatch(HeadlessCmdPutData, Buffer, BufferLength, NULL, NULL);
124 if (Status != STATUS_UNSUCCESSFUL) break;
125
126 /* Sending the data on the port failed, wait a second... */
127 Interval.HighPart = -1;
128 Interval.LowPart = -100000;
129 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
130 }
131
132 /* After 32 attempts it should really have worked... */
133 ASSERT(NT_SUCCESS(Status));
134 return Status;
135 }
136
137 NTSTATUS
138 NTAPI
ConMgrFlushData(IN PSAC_CHANNEL Channel)139 ConMgrFlushData(IN PSAC_CHANNEL Channel)
140 {
141 /* Nothing to do */
142 return STATUS_SUCCESS;
143 }
144
145 BOOLEAN
146 NTAPI
ConMgrIsSacChannel(IN PSAC_CHANNEL Channel)147 ConMgrIsSacChannel(IN PSAC_CHANNEL Channel)
148 {
149 /* Check which channel is active */
150 return Channel == SacChannel;
151 }
152
153 BOOLEAN
154 NTAPI
ConMgrIsWriteEnabled(IN PSAC_CHANNEL Channel)155 ConMgrIsWriteEnabled(IN PSAC_CHANNEL Channel)
156 {
157 /* If the current channel is active, allow writes */
158 return ChannelIsEqual(Channel, &CurrentChannel->ChannelId);
159 }
160
161 NTSTATUS
162 NTAPI
ConMgrInitialize(VOID)163 ConMgrInitialize(VOID)
164 {
165 PWCHAR pcwch;
166 PSAC_CHANNEL FoundChannel;
167 SAC_CHANNEL_ATTRIBUTES SacChannelAttributes;
168 NTSTATUS Status;
169
170 /* Initialize the connection manager lock */
171 SacInitializeMutexLock();
172 SacAcquireMutexLock();
173
174 /* Setup the attributes for the raw SAC channel */
175 RtlZeroMemory(&SacChannelAttributes, sizeof(SacChannelAttributes));
176 SacChannelAttributes.ChannelType = VtUtf8;
177
178 /* Get the right name for it */
179 pcwch = GetMessage(SAC_CHANNEL_NAME);
180 ASSERT(pcwch);
181 wcsncpy(SacChannelAttributes.NameBuffer, pcwch, SAC_CHANNEL_NAME_SIZE);
182 SacChannelAttributes.NameBuffer[SAC_CHANNEL_NAME_SIZE] = ANSI_NULL;
183
184 /* Get the right description for it */
185 pcwch = GetMessage(SAC_CHANNEL_DESCRIPTION);
186 ASSERT(pcwch);
187 wcsncpy(SacChannelAttributes.DescriptionBuffer, pcwch, SAC_CHANNEL_DESCRIPTION_SIZE);
188 SacChannelAttributes.DescriptionBuffer[SAC_CHANNEL_DESCRIPTION_SIZE] = ANSI_NULL;
189
190 /* Set all the right flags */
191 SacChannelAttributes.Flag = SAC_CHANNEL_FLAG_APPLICATION | SAC_CHANNEL_FLAG_INTERNAL;
192 SacChannelAttributes.CloseEvent = NULL;
193 SacChannelAttributes.HasNewDataEvent = NULL;
194 SacChannelAttributes.LockEvent = NULL;
195 SacChannelAttributes.RedrawEvent = NULL;
196 SacChannelAttributes.ChannelId = PRIMARY_SAC_CHANNEL_APPLICATION_GUID;
197
198 /* Now create it */
199 Status = ChanMgrCreateChannel(&SacChannel, &SacChannelAttributes);
200 if (NT_SUCCESS(Status))
201 {
202 /* Try to get it back */
203 Status = ChanMgrGetByHandle(SacChannel->ChannelId, &FoundChannel);
204 if (NT_SUCCESS(Status))
205 {
206 /* Set it as the current and SAC channel */
207 SacChannel = CurrentChannel = FoundChannel;
208
209 /* Disable writes for now and clear the display */
210 _InterlockedExchange(&FoundChannel->WriteEnabled, FALSE);
211 Status = HeadlessDispatch(HeadlessCmdClearDisplay, NULL, 0, NULL, NULL);
212 if (!NT_SUCCESS(Status))
213 {
214 SAC_DBG(SAC_DBG_INIT, "SAC ConMgrInitialize: Failed dispatch\n");
215 }
216
217 /* Display the initial prompt */
218 SacPutSimpleMessage(SAC_NEWLINE);
219 SacPutSimpleMessage(SAC_INIT_STATUS);
220 SacPutSimpleMessage(SAC_NEWLINE);
221 SacPutSimpleMessage(SAC_PROMPT);
222
223 /* Display the current channel */
224 ConMgrDisplayCurrentChannel();
225 }
226 }
227
228 /* Release the channel lock */
229 SacReleaseMutexLock();
230 return STATUS_SUCCESS;
231 }
232
233 VOID
234 NTAPI
ConMgrEventMessage(IN PWCHAR EventMessage,IN BOOLEAN LockHeld)235 ConMgrEventMessage(IN PWCHAR EventMessage,
236 IN BOOLEAN LockHeld)
237 {
238 /* Acquire the current channel lock if needed */
239 if (!LockHeld) SacAcquireMutexLock();
240
241 /* Send out the event message */
242 SacPutSimpleMessage(2);
243 SacPutString(EventMessage);
244 SacPutSimpleMessage(3);
245
246 /* Release the current channel lock if needed */
247 if (!LockHeld) SacReleaseMutexLock();
248 }
249
250 BOOLEAN
251 NTAPI
ConMgrSimpleEventMessage(IN ULONG MessageIndex,IN BOOLEAN LockHeld)252 ConMgrSimpleEventMessage(IN ULONG MessageIndex,
253 IN BOOLEAN LockHeld)
254 {
255 PWCHAR MessageBuffer;
256 BOOLEAN Result;
257
258 /* Get the message to send out */
259 MessageBuffer = GetMessage(MessageIndex);
260 if (MessageBuffer)
261 {
262 /* Send it */
263 ConMgrEventMessage(MessageBuffer, LockHeld);
264 Result = TRUE;
265 }
266 else
267 {
268 /* It doesn't exist, fail */
269 Result = FALSE;
270 }
271
272 /* Return if the message was sent or not */
273 return Result;
274 }
275
276 NTSTATUS
277 NTAPI
ConMgrDisplayFastChannelSwitchingInterface(IN PSAC_CHANNEL Channel)278 ConMgrDisplayFastChannelSwitchingInterface(IN PSAC_CHANNEL Channel)
279 {
280 /* FIXME: TODO */
281 ASSERT(FALSE);
282 return STATUS_NOT_IMPLEMENTED;
283 }
284
285 NTSTATUS
286 NTAPI
ConMgrSetCurrentChannel(IN PSAC_CHANNEL Channel)287 ConMgrSetCurrentChannel(IN PSAC_CHANNEL Channel)
288 {
289 NTSTATUS Status;
290 BOOLEAN HasRedrawEvent;
291
292 /* Make sure the lock is held */
293 SacAssertMutexLockHeld();
294
295 /* Check if we have a redraw event */
296 Status = ChannelHasRedrawEvent(CurrentChannel, &HasRedrawEvent);
297 if (!NT_SUCCESS(Status)) return Status;
298
299 /* Clear it */
300 if (HasRedrawEvent) ChannelClearRedrawEvent(CurrentChannel);
301
302 /* Disable writes on the current channel */
303 _InterlockedExchange(&CurrentChannel->WriteEnabled, 0);
304
305 /* Release the current channel */
306 Status = ChanMgrReleaseChannel(CurrentChannel);
307 if (!NT_SUCCESS(Status)) return Status;
308
309 /* Set the new channel and also disable writes on it */
310 CurrentChannel = Channel;
311 _InterlockedExchange(&Channel->WriteEnabled, 0);
312 return STATUS_SUCCESS;
313 }
314
315 NTSTATUS
316 NTAPI
ConMgrResetCurrentChannel(IN BOOLEAN KeepChannel)317 ConMgrResetCurrentChannel(IN BOOLEAN KeepChannel)
318 {
319 NTSTATUS Status;
320 PSAC_CHANNEL Channel;
321
322 /* Make sure the lock is held */
323 SacAssertMutexLockHeld();
324
325 /* Get the current SAC channel */
326 Status = ChanMgrGetByHandle(SacChannel->ChannelId, &Channel);
327 if (NT_SUCCESS(Status))
328 {
329 /* Set this as the current SAC channel*/
330 SacChannel = Channel;
331 Status = ConMgrSetCurrentChannel(Channel);
332 if (NT_SUCCESS(Status))
333 {
334 /* Check if the caller wants to switch or not */
335 if (KeepChannel)
336 {
337 /* Nope, keep the same channel */
338 Status = ConMgrDisplayCurrentChannel();
339 }
340 else
341 {
342 /* Yep, show the switching interface */
343 Status = ConMgrDisplayFastChannelSwitchingInterface(CurrentChannel);
344 }
345 }
346 }
347
348 /* All done */
349 return Status;
350 }
351
352 NTSTATUS
353 NTAPI
ConMgrChannelClose(IN PSAC_CHANNEL Channel)354 ConMgrChannelClose(IN PSAC_CHANNEL Channel)
355 {
356 NTSTATUS Status = STATUS_SUCCESS;
357
358 /* Check if we're in the right channel */
359 if (ConMgrIsWriteEnabled(Channel))
360 {
361 /* Yep, reset it */
362 Status = ConMgrResetCurrentChannel(FALSE);
363 ASSERT(NT_SUCCESS(Status));
364 }
365
366 /* All done */
367 return Status;
368 }
369
370 NTSTATUS
371 NTAPI
ConMgrShutdown(VOID)372 ConMgrShutdown(VOID)
373 {
374 NTSTATUS Status;
375
376 /* Check if we have a SAC channel */
377 if (SacChannel)
378 {
379 /* Close it */
380 Status = ChannelClose(SacChannel);
381 if (!NT_SUCCESS(Status))
382 {
383 SAC_DBG(SAC_DBG_INIT, "SAC ConMgrShutdown: failed closing SAC channel.\n");
384 }
385
386 /* No longer have one */
387 SacChannel = NULL;
388 }
389
390 /* Check if we have a current channel */
391 if (CurrentChannel)
392 {
393 /* Release it */
394 Status = ChanMgrReleaseChannel(CurrentChannel);
395 if (!NT_SUCCESS(Status))
396 {
397 SAC_DBG(SAC_DBG_INIT, "SAC ConMgrShutdown: failed releasing current channel\n");
398 }
399
400 /* No longer have one */
401 CurrentChannel = NULL;
402 }
403
404 /* All done */
405 return STATUS_SUCCESS;
406 }
407
408 NTSTATUS
409 NTAPI
ConMgrAdvanceCurrentChannel(VOID)410 ConMgrAdvanceCurrentChannel(VOID)
411 {
412 NTSTATUS Status;
413 ULONG Index;
414 PSAC_CHANNEL Channel;
415
416 /* Should always be called with the lock held */
417 SacAssertMutexLockHeld();
418
419 /* Get the next active channel */
420 Status = ChanMgrGetNextActiveChannel(CurrentChannel, &Index, &Channel);
421 if (NT_SUCCESS(Status))
422 {
423 /* Set it as the new channel */
424 Status = ConMgrSetCurrentChannel(Channel);
425 if (NT_SUCCESS(Status))
426 {
427 /* Let the user switch to it */
428 Status = ConMgrDisplayFastChannelSwitchingInterface(Channel);
429 }
430 }
431
432 /* All done */
433 return Status;
434 }
435
436 NTSTATUS
437 NTAPI
ConMgrChannelOWrite(IN PSAC_CHANNEL Channel,IN PVOID WriteBuffer)438 ConMgrChannelOWrite(IN PSAC_CHANNEL Channel,
439 IN PVOID WriteBuffer)
440 {
441 NTSTATUS Status;
442
443 /* Do the write with the lock held */
444 SacAcquireMutexLock();
445 ASSERT(FALSE);
446 Status = STATUS_NOT_IMPLEMENTED;// ChannelOWrite(Channel, WriteBuffer + 24, *(WriteBuffer + 20));
447 SacReleaseMutexLock();
448
449 /* Return back to the caller */
450 ASSERT(NT_SUCCESS(Status) || Status == STATUS_NOT_FOUND);
451 return Status;
452 }
453
454 VOID
455 NTAPI
ConMgrProcessInputLine(VOID)456 ConMgrProcessInputLine(VOID)
457 {
458 BOOLEAN EnablePaging;
459 NTSTATUS Status;
460
461 SAC_DBG(SAC_DBG_INIT, "SAC Input Test: %s\n", InputBuffer);
462
463 if (!strncmp(InputBuffer, "t", 1))
464 {
465 DoTlistCommand();
466 }
467 else if (!strncmp(InputBuffer, "?", 1))
468 {
469 DoHelpCommand();
470 }
471 else if (!strncmp(InputBuffer, "help", 4))
472 {
473 DoHelpCommand();
474 }
475 else if (!strncmp(InputBuffer, "f", 1))
476 {
477 DoFullInfoCommand();
478 }
479 else if (!strncmp(InputBuffer, "p", 1))
480 {
481 DoPagingCommand();
482 }
483 else if (!strncmp(InputBuffer, "id", 2))
484 {
485 DoMachineInformationCommand();
486 }
487 else if (!strncmp(InputBuffer, "crashdump", 9))
488 {
489 DoCrashCommand();
490 }
491 else if (!strncmp(InputBuffer, "lock", 4))
492 {
493 DoLockCommand();
494 }
495 else if (!strncmp(InputBuffer, "shutdown", 8))
496 {
497 ExecutePostConsumerCommand = Shutdown;
498 }
499 else if (!strncmp(InputBuffer, "restart", 7))
500 {
501 ExecutePostConsumerCommand = Restart;
502 }
503 else if (!strncmp(InputBuffer, "d", 1))
504 {
505 EnablePaging = GlobalPagingNeeded;
506 Status = HeadlessDispatch(HeadlessCmdDisplayLog,
507 &EnablePaging,
508 sizeof(EnablePaging),
509 NULL,
510 NULL);
511 if (!NT_SUCCESS(Status)) SAC_DBG(SAC_DBG_INIT, "SAC Display Log failed.\n");
512 }
513 else if (!strncmp(InputBuffer, "cmd", 3))
514 {
515 if (CommandConsoleLaunchingEnabled)
516 {
517 DoCmdCommand(InputBuffer);
518 }
519 else
520 {
521 SacPutSimpleMessage(148);
522 }
523 }
524 else if (!(strncmp(InputBuffer, "ch", 2)) &&
525 (((strlen(InputBuffer) > 1) && (InputBuffer[2] == ' ')) ||
526 (strlen(InputBuffer) == 2)))
527 {
528 DoChannelCommand(InputBuffer);
529 }
530 else if (!(strncmp(InputBuffer, "k", 1)) &&
531 (((strlen(InputBuffer) > 1) && (InputBuffer[1] == ' ')) ||
532 (strlen(InputBuffer) == 1)))
533 {
534 DoKillCommand(InputBuffer);
535 }
536 else if (!(strncmp(InputBuffer, "l", 1)) &&
537 (((strlen(InputBuffer) > 1) && (InputBuffer[1] == ' ')) ||
538 (strlen(InputBuffer) == 1)))
539 {
540 DoLowerPriorityCommand(InputBuffer);
541 }
542 else if (!(strncmp(InputBuffer, "r", 1)) &&
543 (((strlen(InputBuffer) > 1) && (InputBuffer[1] == ' ')) ||
544 (strlen(InputBuffer) == 1)))
545 {
546 DoRaisePriorityCommand(InputBuffer);
547 }
548 else if (!(strncmp(InputBuffer, "m", 1)) &&
549 (((strlen(InputBuffer) > 1) && (InputBuffer[1] == ' ')) ||
550 (strlen(InputBuffer) == 1)))
551 {
552 DoLimitMemoryCommand(InputBuffer);
553 }
554 else if (!(strncmp(InputBuffer, "s", 1)) &&
555 (((strlen(InputBuffer) > 1) && (InputBuffer[1] == ' ')) ||
556 (strlen(InputBuffer) == 1)))
557 {
558 DoSetTimeCommand(InputBuffer);
559 }
560 else if (!(strncmp(InputBuffer, "i", 1)) &&
561 (((strlen(InputBuffer) > 1) && (InputBuffer[1] == ' ')) ||
562 (strlen(InputBuffer) == 1)))
563 {
564 DoSetIpAddressCommand(InputBuffer);
565 }
566 else if ((InputBuffer[0] != '\n') && (InputBuffer[0] != ANSI_NULL))
567 {
568 SacPutSimpleMessage(SAC_UNKNOWN_COMMAND);
569 }
570 }
571
572 VOID
573 NTAPI
ConMgrSerialPortConsumer(VOID)574 ConMgrSerialPortConsumer(VOID)
575 {
576 NTSTATUS Status;
577 CHAR Char;
578 WCHAR LastChar;
579 CHAR ReadBuffer[2];
580 ULONG ReadBufferSize, i;
581 WCHAR StringBuffer[2];
582 SAC_DBG(SAC_DBG_MACHINE, "SAC TimerDpcRoutine: Entering.\n"); //bug
583
584 /* Acquire the manager lock and make sure a channel is selected */
585 SacAcquireMutexLock();
586 ASSERT(CurrentChannel);
587
588 /* Read whatever came off the serial port */
589 for (Status = SerialBufferGetChar(&Char);
590 NT_SUCCESS(Status);
591 Status = SerialBufferGetChar(&Char))
592 {
593 /* If nothing came through, bail out */
594 if (Status == STATUS_NO_DATA_DETECTED) break;
595
596 /* Check if ESC was pressed */
597 if (Char == '\x1B')
598 {
599 /* Was it already pressed? */
600 if (!InputInEscape)
601 {
602 /* First time ESC is pressed! Remember and reset TAB state */
603 InputInEscTab = FALSE;
604 InputInEscape = TRUE;
605 continue;
606 }
607 }
608 else if (Char == '\t')
609 {
610 /* TAB was pressed, is it following ESC (VT-100 sequence)? */
611 if (InputInEscape)
612 {
613 /* Yes! This must be the only ESC-TAB we see in once moment */
614 ASSERT(InputInEscTab == FALSE);
615
616 /* No longer treat us as being in ESC */
617 InputInEscape = FALSE;
618
619 /* ESC-TAB is the sequence for changing channels */
620 Status = ConMgrAdvanceCurrentChannel();
621 if (!NT_SUCCESS(Status)) break;
622
623 /* Remember ESC-TAB was pressed */
624 InputInEscTab = TRUE;
625 continue;
626 }
627 }
628 else if ((Char == '0') && (InputInEscTab))
629 {
630 /* It this ESC-TAB-0? */
631 ASSERT(InputInEscape == FALSE);
632 InputInEscTab = FALSE;
633
634 /* If writes are already enabled, don't do this */
635 if (!CurrentChannel->WriteEnabled)
636 {
637 /* Reset the channel, this is our special sequence */
638 Status = ConMgrResetCurrentChannel(FALSE);
639 if (!NT_SUCCESS(Status)) break;
640 }
641
642 continue;
643 }
644 else
645 {
646 /* This is ESC-TAB-something else */
647 InputInEscTab = FALSE;
648
649 /* If writes are already enabled, don't do this */
650 if (!CurrentChannel->WriteEnabled)
651 {
652 /* Display the current channel */
653 InputInEscape = FALSE;
654 Status = ConMgrDisplayCurrentChannel();
655 if (!NT_SUCCESS(Status)) break;
656 continue;
657 }
658 }
659
660 /* Check if an ESC-sequence was being typed into a command channel */
661 if ((InputInEscape) && (CurrentChannel != SacChannel))
662 {
663 /* Store the ESC in the current channel buffer */
664 ReadBuffer[0] = '\x1B';
665 ChannelIWrite(CurrentChannel, ReadBuffer, sizeof(CHAR));
666 }
667
668 /* Check if we are no longer pressing ESC and exit the mode if so */
669 if (Char != '\x1B') InputInEscape = FALSE;
670
671 /* Whatever was typed in, save it int eh current channel */
672 ChannelIWrite(CurrentChannel, &Char, sizeof(Char));
673
674 /* If this is a command channel, we're done, nothing to process */
675 if (CurrentChannel != SacChannel) continue;
676
677 /* Check for line feed right after a carriage return */
678 if ((ConMgrLastCharWasCR) && (Char == '\n'))
679 {
680 /* Ignore the line feed, but clear the carriage return */
681 ChannelIReadLast(CurrentChannel);
682 ConMgrLastCharWasCR = 0;
683 continue;
684 }
685
686 /* Check if the user did a carriage return */
687 ConMgrLastCharWasCR = (Char == '\n');
688
689 /* If the user did an "ENTER", we need to run the command */
690 if ((Char == '\n') || (Char == '\r'))
691 {
692 /* Echo back to the terminal */
693 SacPutString(L"\r\n");
694
695 DoLineParsing:
696 /* Inhibit the character (either CR or LF) */
697 ChannelIReadLast(CurrentChannel);
698
699 /* NULL-terminate the channel's input buffer */
700 ReadBuffer[0] = ANSI_NULL;
701 ChannelIWrite(CurrentChannel, ReadBuffer, sizeof(CHAR));
702
703 /* Loop over every last character */
704 do
705 {
706 /* Read every character in the channel, and strip whitespace */
707 LastChar = ChannelIReadLast(CurrentChannel);
708 ReadBuffer[0] = (CHAR) LastChar;
709 } while ((!(LastChar) ||
710 (LastChar == L' ') ||
711 (LastChar == L'\t')) &&
712 (ChannelIBufferLength(CurrentChannel)));
713
714 /* Write back into the channel the last character */
715 ChannelIWrite(CurrentChannel, ReadBuffer, sizeof(CHAR));
716
717 /* NULL-terminate the input buffer */
718 ReadBuffer[0] = ANSI_NULL;
719 ChannelIWrite(CurrentChannel, ReadBuffer, sizeof(CHAR));
720
721 /* Now loop over every first character */
722 do
723 {
724 /* Read every character in the channel, and strip whitespace */
725 ChannelIRead(CurrentChannel,
726 ReadBuffer,
727 sizeof(ReadBuffer),
728 &ReadBufferSize);
729 } while ((ReadBufferSize) &&
730 ((ReadBuffer[0] == ' ') || (ReadBuffer[0] == '\t')));
731
732 /* We read one more than we should, so treat that as our first one */
733 InputBuffer[0] = ReadBuffer[0];
734 i = 1;
735
736 /* And now loop reading all the others */
737 do
738 {
739 /* Read each character -- there should be max 80 */
740 ChannelIRead(CurrentChannel,
741 ReadBuffer,
742 sizeof(ReadBuffer),
743 &ReadBufferSize);
744 ASSERT(i < SAC_VTUTF8_COL_WIDTH);
745 InputBuffer[i++] = ReadBuffer[0];
746 } while (ReadBufferSize);
747
748 /* Now go over the entire input stream */
749 for (i = 0; InputBuffer[i]; i++)
750 {
751 /* Again it should be less than 80 characters */
752 ASSERT(i < SAC_VTUTF8_COL_WIDTH);
753
754 /* And downbase each character */
755 Char = InputBuffer[i];
756 if ((Char >= 'A') && (Char <= 'Z')) InputBuffer[i] = Char + ' ';
757 }
758
759 /* Ok, at this point, no pending command should exist */
760 ASSERT(ExecutePostConsumerCommand == Nothing);
761
762 /* Go and process the input, then show the prompt again */
763 ConMgrProcessInputLine();
764 SacPutSimpleMessage(SAC_PROMPT);
765
766 /* If the user typed a valid command, get out of here */
767 if (ExecutePostConsumerCommand != Nothing) break;
768
769 /* Keep going */
770 continue;
771 }
772
773 /* Check if the user typed backspace or delete */
774 if ((Char == '\b') || (Char == '\x7F'))
775 {
776 /* Omit the last character, which should be the DEL/BS itself */
777 if (ChannelIBufferLength(CurrentChannel))
778 {
779 ChannelIReadLast(CurrentChannel);
780 }
781
782 /* Omit the before-last character, which is the one to delete */
783 if (ChannelIBufferLength(CurrentChannel))
784 {
785 /* Also send two backspaces back to the console */
786 SacPutString(L"\b \b");
787 ChannelIReadLast(CurrentChannel);
788 }
789
790 /* Keep going */
791 continue;
792 }
793
794 /* If the user pressed CTRL-C at this point, treat it like ENTER */
795 if (Char == '\x03') goto DoLineParsing;
796
797 /* Check if the user pressed TAB */
798 if (Char == '\t')
799 {
800 /* Omit it, send a BELL, and keep going. We ignore TABs */
801 ChannelIReadLast(CurrentChannel);
802 SacPutString(L"\a");
803 continue;
804 }
805
806 /* Check if the user is getting close to the end of the screen */
807 if (ChannelIBufferLength(CurrentChannel) == (SAC_VTUTF8_COL_WIDTH - 2))
808 {
809 /* Delete the last character, replacing it with this one instead */
810 swprintf(StringBuffer, L"\b%c", Char);
811 SacPutString(StringBuffer);
812
813 /* Omit the last two characters from the buffer */
814 ChannelIReadLast(CurrentChannel);
815 ChannelIReadLast(CurrentChannel);
816
817 /* Write the last character that was just typed in */
818 ReadBuffer[0] = Char;
819 ChannelIWrite(CurrentChannel, ReadBuffer, sizeof(CHAR));
820 continue;
821 }
822
823 /* Nothing of interest happened, just write the character back */
824 swprintf(StringBuffer, L"%c", Char);
825 SacPutString(StringBuffer);
826 }
827
828 /* We're done, release the lock */
829 SacReleaseMutexLock();
830 SAC_DBG(SAC_DBG_MACHINE, "SAC TimerDpcRoutine: Exiting.\n"); //bug
831 }
832
833 VOID
834 NTAPI
ConMgrWorkerProcessEvents(IN PSAC_DEVICE_EXTENSION DeviceExtension)835 ConMgrWorkerProcessEvents(IN PSAC_DEVICE_EXTENSION DeviceExtension)
836 {
837 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC WorkerProcessEvents: Entering.\n");
838
839 /* Enter the main loop */
840 while (TRUE)
841 {
842 /* Wait for something to do */
843 KeWaitForSingleObject(&DeviceExtension->Event,
844 Executive,
845 KernelMode,
846 FALSE,
847 NULL);
848
849 /* Consume data off the serial port */
850 ConMgrSerialPortConsumer();
851 switch (ExecutePostConsumerCommand)
852 {
853 case Restart:
854 /* A reboot was sent, do it */
855 DoRebootCommand(FALSE);
856 break;
857
858 case Close:
859 /* A close was sent, do it */
860 ChanMgrCloseChannel(ExecutePostConsumerCommandData);
861 ChanMgrReleaseChannel(ExecutePostConsumerCommandData);
862 break;
863
864 case Shutdown:
865 /* A shutdown was sent, do it */
866 DoRebootCommand(TRUE);
867 break;
868 }
869
870 /* Clear the serial port consumer state */
871 ExecutePostConsumerCommand = Nothing;
872 ExecutePostConsumerCommandData = NULL;
873 }
874 }
875
876 NTSTATUS
877 NTAPI
ConMgrGetChannelCloseMessage(IN PSAC_CHANNEL Channel,IN NTSTATUS CloseStatus,OUT PWCHAR OutputBuffer)878 ConMgrGetChannelCloseMessage(IN PSAC_CHANNEL Channel,
879 IN NTSTATUS CloseStatus,
880 OUT PWCHAR OutputBuffer)
881 {
882 ASSERT(FALSE);
883 return STATUS_NOT_IMPLEMENTED;
884 }
885
886 NTSTATUS
887 NTAPI
ConMgrHandleEvent(IN ULONG EventCode,IN PSAC_CHANNEL Channel,OUT PVOID Data)888 ConMgrHandleEvent(IN ULONG EventCode,
889 IN PSAC_CHANNEL Channel,
890 OUT PVOID Data)
891 {
892 ASSERT(FALSE);
893 return STATUS_NOT_IMPLEMENTED;
894 }
895