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