xref: /reactos/ntoskrnl/ex/hdlsterm.c (revision 34593d93)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * PROJECT:         ReactOS Kernel
3c2c66affSColin Finck  * LICENSE:         BSD - See COPYING.ARM in the top level directory
4c2c66affSColin Finck  * FILE:            ntoskrnl/ex/hdlsterm.c
5c2c66affSColin Finck  * PURPOSE:         Headless Terminal Support
6c2c66affSColin Finck  * PROGRAMMERS:     ReactOS Portable Systems Group
7c2c66affSColin Finck  */
8c2c66affSColin Finck 
9c2c66affSColin Finck /* INCLUDES *******************************************************************/
10c2c66affSColin Finck 
11c2c66affSColin Finck #include <ntoskrnl.h>
12c2c66affSColin Finck #include <debug.h>
13c2c66affSColin Finck 
14c2c66affSColin Finck /* GLOBALS ********************************************************************/
15c2c66affSColin Finck 
16c2c66affSColin Finck PHEADLESS_GLOBALS HeadlessGlobals;
17c2c66affSColin Finck 
18c2c66affSColin Finck /* FUNCTIONS ******************************************************************/
19c2c66affSColin Finck 
20c2c66affSColin Finck FORCEINLINE
21c2c66affSColin Finck KIRQL
HdlspAcquireGlobalLock(VOID)22c2c66affSColin Finck HdlspAcquireGlobalLock(VOID)
23c2c66affSColin Finck {
24c2c66affSColin Finck     KIRQL OldIrql;
25c2c66affSColin Finck 
26c2c66affSColin Finck     /* Don't acquire the lock if we are bugchecking */
27c2c66affSColin Finck     if (!HeadlessGlobals->InBugCheck)
28c2c66affSColin Finck     {
29c2c66affSColin Finck         KeAcquireSpinLock(&HeadlessGlobals->SpinLock, &OldIrql);
30c2c66affSColin Finck     }
31c2c66affSColin Finck     else
32c2c66affSColin Finck     {
33c2c66affSColin Finck         OldIrql = 0xFF;
34c2c66affSColin Finck     }
35c2c66affSColin Finck 
36c2c66affSColin Finck     return OldIrql;
37c2c66affSColin Finck }
38c2c66affSColin Finck 
39c2c66affSColin Finck FORCEINLINE
40c2c66affSColin Finck VOID
HdlspReleaseGlobalLock(IN KIRQL OldIrql)41c2c66affSColin Finck HdlspReleaseGlobalLock(IN KIRQL OldIrql)
42c2c66affSColin Finck {
43c2c66affSColin Finck     /* Only release the lock if we aren't bugchecking */
44c2c66affSColin Finck     if (OldIrql != 0xFF)
45c2c66affSColin Finck     {
46c2c66affSColin Finck         KeReleaseSpinLock(&HeadlessGlobals->SpinLock, OldIrql);
47c2c66affSColin Finck     }
48c2c66affSColin Finck     else
49c2c66affSColin Finck     {
50c2c66affSColin Finck         ASSERT(HeadlessGlobals->InBugCheck == TRUE);
51c2c66affSColin Finck     }
52c2c66affSColin Finck }
53c2c66affSColin Finck 
54c2c66affSColin Finck VOID
55c2c66affSColin Finck NTAPI
HdlspSendStringAtBaud(IN PUCHAR String)56c2c66affSColin Finck HdlspSendStringAtBaud(IN PUCHAR String)
57c2c66affSColin Finck {
58c2c66affSColin Finck     /* Send every byte */
59c2c66affSColin Finck     while (*String != ANSI_NULL)
60c2c66affSColin Finck     {
61c2c66affSColin Finck         InbvPortPutByte(HeadlessGlobals->TerminalPort, *String++);
62c2c66affSColin Finck     }
63c2c66affSColin Finck }
64c2c66affSColin Finck 
65c2c66affSColin Finck VOID
66c2c66affSColin Finck NTAPI
HdlspPutData(IN PUCHAR Data,IN ULONG DataSize)67c2c66affSColin Finck HdlspPutData(IN PUCHAR Data,
68c2c66affSColin Finck              IN ULONG DataSize)
69c2c66affSColin Finck {
70c2c66affSColin Finck     ULONG i;
71c2c66affSColin Finck     for (i = 0; i < DataSize; i++)
72c2c66affSColin Finck     {
73c2c66affSColin Finck         InbvPortPutByte(HeadlessGlobals->TerminalPort, Data[i]);
74c2c66affSColin Finck     }
75c2c66affSColin Finck }
76c2c66affSColin Finck 
77c2c66affSColin Finck VOID
78c2c66affSColin Finck NTAPI
HdlspPutString(IN PUCHAR String)79c2c66affSColin Finck HdlspPutString(IN PUCHAR String)
80c2c66affSColin Finck {
81c2c66affSColin Finck     PUCHAR Dest = HeadlessGlobals->TmpBuffer;
82c2c66affSColin Finck     UCHAR Char = 0;
83c2c66affSColin Finck 
84c2c66affSColin Finck     /* Scan each character */
85c2c66affSColin Finck     while (*String != ANSI_NULL)
86c2c66affSColin Finck     {
87c2c66affSColin Finck         /* Check for rotate, send existing buffer and restart from where we are */
88c2c66affSColin Finck         if (Dest >= &HeadlessGlobals->TmpBuffer[79])
89c2c66affSColin Finck         {
90c2c66affSColin Finck             HeadlessGlobals->TmpBuffer[79] = ANSI_NULL;
91c2c66affSColin Finck             HdlspSendStringAtBaud(HeadlessGlobals->TmpBuffer);
92c2c66affSColin Finck             Dest = HeadlessGlobals->TmpBuffer;
93c2c66affSColin Finck         }
94c2c66affSColin Finck         else
95c2c66affSColin Finck         {
96c2c66affSColin Finck             /* Get the current character and check for special graphical chars */
97c2c66affSColin Finck             Char = *String;
98c2c66affSColin Finck             if (Char & 0x80)
99c2c66affSColin Finck             {
100c2c66affSColin Finck                 switch (Char)
101c2c66affSColin Finck                 {
102c2c66affSColin Finck                     case 0xB0: case 0xB3: case 0xBA:
103c2c66affSColin Finck                         Char = '|';
104c2c66affSColin Finck                         break;
105c2c66affSColin Finck                     case 0xB1: case 0xDC: case 0xDD: case 0xDE: case 0xDF:
106c2c66affSColin Finck                         Char = '%';
107c2c66affSColin Finck                         break;
108c2c66affSColin Finck                     case 0xB2: case 0xDB:
109c2c66affSColin Finck                         Char = '#';
110c2c66affSColin Finck                         break;
111c2c66affSColin Finck                     case 0xA9: case 0xAA: case 0xBB: case 0xBC: case 0xBF:
112c2c66affSColin Finck                     case 0xC0: case 0xC8: case 0xC9: case 0xD9: case 0xDA:
113c2c66affSColin Finck                         Char = '+';
114c2c66affSColin Finck                         break;
115c2c66affSColin Finck                     case 0xC4:
116c2c66affSColin Finck                         Char = '-';
117c2c66affSColin Finck                         break;
118c2c66affSColin Finck                     case 0xCD:
119c2c66affSColin Finck                         Char = '=';
120c2c66affSColin Finck                         break;
121c2c66affSColin Finck                 }
122c2c66affSColin Finck             }
123c2c66affSColin Finck 
124c2c66affSColin Finck             /* Anything else must be Unicode */
125c2c66affSColin Finck             if (Char & 0x80)
126c2c66affSColin Finck             {
127c2c66affSColin Finck                 /* Can't do Unicode yet */
128c2c66affSColin Finck                 UNIMPLEMENTED;
129c2c66affSColin Finck             }
130c2c66affSColin Finck             else
131c2c66affSColin Finck             {
132c2c66affSColin Finck                 /* Add the modified char to the temporary buffer */
133c2c66affSColin Finck                 *Dest++ = Char;
134c2c66affSColin Finck             }
135c2c66affSColin Finck 
136c2c66affSColin Finck             /* Check the next char */
137c2c66affSColin Finck             String++;
138c2c66affSColin Finck         }
139c2c66affSColin Finck     }
140c2c66affSColin Finck 
141c2c66affSColin Finck     /* Finish and send */
142c2c66affSColin Finck     *Dest = ANSI_NULL;
143c2c66affSColin Finck     HdlspSendStringAtBaud(HeadlessGlobals->TmpBuffer);
144c2c66affSColin Finck }
145c2c66affSColin Finck 
146c2c66affSColin Finck NTSTATUS
147c2c66affSColin Finck NTAPI
HdlspEnableTerminal(IN BOOLEAN Enable)148c2c66affSColin Finck HdlspEnableTerminal(IN BOOLEAN Enable)
149c2c66affSColin Finck {
150c2c66affSColin Finck     /* Enable if requested, as long as this isn't a PCI serial port crashing */
151c2c66affSColin Finck     if ((Enable) &&
152c2c66affSColin Finck         !(HeadlessGlobals->TerminalEnabled) &&
153c2c66affSColin Finck         !((HeadlessGlobals->IsMMIODevice) && (HeadlessGlobals->InBugCheck)))
154c2c66affSColin Finck     {
155c2c66affSColin Finck         /* Initialize the COM port with cportlib */
156c2c66affSColin Finck         HeadlessGlobals->TerminalEnabled = InbvPortInitialize(HeadlessGlobals->TerminalBaudRate,
157c2c66affSColin Finck                                                               HeadlessGlobals->TerminalPortNumber,
158c2c66affSColin Finck                                                               HeadlessGlobals->TerminalPortAddress,
159c2c66affSColin Finck                                                               &HeadlessGlobals->TerminalPort,
160c2c66affSColin Finck                                                               HeadlessGlobals->IsMMIODevice);
161c2c66affSColin Finck         if (!HeadlessGlobals->TerminalEnabled)
162c2c66affSColin Finck         {
163c2c66affSColin Finck             DPRINT1("Failed to initialize port through cportlib\n");
164c2c66affSColin Finck             return STATUS_UNSUCCESSFUL;
165c2c66affSColin Finck         }
166c2c66affSColin Finck 
167c2c66affSColin Finck         /* Cleanup the screen and reset the cursor */
168c2c66affSColin Finck         HdlspSendStringAtBaud((PUCHAR)"\x1B[2J");
169c2c66affSColin Finck         HdlspSendStringAtBaud((PUCHAR)"\x1B[H");
170c2c66affSColin Finck 
171c2c66affSColin Finck         /* Enable FIFO */
172c2c66affSColin Finck         InbvPortEnableFifo(HeadlessGlobals->TerminalPort, TRUE);
173c2c66affSColin Finck     }
174c2c66affSColin Finck     else if (!Enable)
175c2c66affSColin Finck     {
176c2c66affSColin Finck         /* Specific case when headless is being disabled */
177c2c66affSColin Finck         InbvPortTerminate(HeadlessGlobals->TerminalPort);
178c2c66affSColin Finck         HeadlessGlobals->TerminalPort = 0;
179c2c66affSColin Finck         HeadlessGlobals->TerminalEnabled = FALSE;
180c2c66affSColin Finck     }
181c2c66affSColin Finck 
182c2c66affSColin Finck     /* All done */
183c2c66affSColin Finck     return STATUS_SUCCESS;
184c2c66affSColin Finck }
185c2c66affSColin Finck 
186*5c7ce447SVictor Perevertkin CODE_SEG("INIT")
187c2c66affSColin Finck VOID
188c2c66affSColin Finck NTAPI
HeadlessInit(IN PLOADER_PARAMETER_BLOCK LoaderBlock)189c2c66affSColin Finck HeadlessInit(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
190c2c66affSColin Finck {
191c2c66affSColin Finck     PHEADLESS_LOADER_BLOCK HeadlessBlock;
192c2c66affSColin Finck 
193c2c66affSColin Finck     /* Only initialize further if the loader found EMS enabled */
194c2c66affSColin Finck     HeadlessBlock = LoaderBlock->Extension->HeadlessLoaderBlock;
195c2c66affSColin Finck     if (!HeadlessBlock) return;
196c2c66affSColin Finck 
197c2c66affSColin Finck     /* Ignore invalid EMS settings */
198c2c66affSColin Finck     if ((HeadlessBlock->PortNumber > 4) && (HeadlessBlock->UsedBiosSettings)) return;
199c2c66affSColin Finck 
200c2c66affSColin Finck     /* Allocate the global headless data */
201c2c66affSColin Finck     HeadlessGlobals = ExAllocatePoolWithTag(NonPagedPool,
202c2c66affSColin Finck                                             sizeof(*HeadlessGlobals),
203c2c66affSColin Finck                                             'sldH');
204c2c66affSColin Finck     if (!HeadlessGlobals) return;
205c2c66affSColin Finck 
206c2c66affSColin Finck     /* Zero and copy loader data */
207c2c66affSColin Finck     RtlZeroMemory(HeadlessGlobals, sizeof(*HeadlessGlobals));
208c2c66affSColin Finck     HeadlessGlobals->TerminalPortNumber = HeadlessBlock->PortNumber;
209c2c66affSColin Finck     HeadlessGlobals->TerminalPortAddress = HeadlessBlock->PortAddress;
210c2c66affSColin Finck     HeadlessGlobals->TerminalBaudRate = HeadlessBlock->BaudRate;
211c2c66affSColin Finck     HeadlessGlobals->TerminalParity = HeadlessBlock->Parity;
212c2c66affSColin Finck     HeadlessGlobals->TerminalStopBits = HeadlessBlock->StopBits;
213c2c66affSColin Finck     HeadlessGlobals->UsedBiosSettings = HeadlessBlock->UsedBiosSettings;
214c2c66affSColin Finck     HeadlessGlobals->IsMMIODevice = HeadlessBlock->IsMMIODevice;
215c2c66affSColin Finck     HeadlessGlobals->TerminalType = HeadlessBlock->TerminalType;
216c2c66affSColin Finck     HeadlessGlobals->SystemGUID = HeadlessBlock->SystemGUID;
217c2c66affSColin Finck     DPRINT1("EMS on Port %lu (0x%p) at %lu bps\n",
218c2c66affSColin Finck              HeadlessGlobals->TerminalPortNumber,
219c2c66affSColin Finck              HeadlessGlobals->TerminalPortAddress,
220c2c66affSColin Finck              HeadlessGlobals->TerminalBaudRate);
221c2c66affSColin Finck 
222c2c66affSColin Finck     /* These two are opposites of each other */
223c2c66affSColin Finck     if (HeadlessGlobals->IsMMIODevice) HeadlessGlobals->IsNonLegacyDevice = TRUE;
224c2c66affSColin Finck 
225c2c66affSColin Finck     /* Check for a PCI device, warn that this isn't supported */
226c2c66affSColin Finck     if (HeadlessBlock->PciDeviceId != PCI_INVALID_VENDORID)
227c2c66affSColin Finck     {
228c2c66affSColin Finck         DPRINT1("PCI Serial Ports not supported\n");
229c2c66affSColin Finck     }
230c2c66affSColin Finck 
231c2c66affSColin Finck     /* Log entries are not yet supported */
232c2c66affSColin Finck     DPRINT1("FIXME: No Headless logging support\n");
233c2c66affSColin Finck 
234c2c66affSColin Finck     /* Allocate temporary buffer */
235c2c66affSColin Finck     HeadlessGlobals->TmpBuffer = ExAllocatePoolWithTag(NonPagedPool, 80, 'sldH');
236c2c66affSColin Finck     if (!HeadlessGlobals->TmpBuffer) return;
237c2c66affSColin Finck 
238c2c66affSColin Finck     /* Windows seems to apply some special hacks for 9600 bps */
239c2c66affSColin Finck     if (HeadlessGlobals->TerminalBaudRate == 9600)
240c2c66affSColin Finck     {
241c2c66affSColin Finck         DPRINT1("Please use other baud rate than 9600bps for now\n");
242c2c66affSColin Finck     }
243c2c66affSColin Finck 
244c2c66affSColin Finck     /* Enable the terminal */
245c2c66affSColin Finck     HdlspEnableTerminal(TRUE);
246c2c66affSColin Finck }
247c2c66affSColin Finck 
248c2c66affSColin Finck NTSTATUS
249c2c66affSColin Finck NTAPI
HdlspDispatch(IN HEADLESS_CMD Command,IN PVOID InputBuffer,IN SIZE_T InputBufferSize,OUT PVOID OutputBuffer,OUT PSIZE_T OutputBufferSize)250c2c66affSColin Finck HdlspDispatch(IN HEADLESS_CMD Command,
251c2c66affSColin Finck               IN PVOID InputBuffer,
252c2c66affSColin Finck               IN SIZE_T InputBufferSize,
253c2c66affSColin Finck               OUT PVOID OutputBuffer,
254c2c66affSColin Finck               OUT PSIZE_T OutputBufferSize)
255c2c66affSColin Finck {
256c2c66affSColin Finck     KIRQL OldIrql;
257c2c66affSColin Finck     NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
258c2c66affSColin Finck     PHEADLESS_RSP_QUERY_INFO HeadlessInfo;
259c2c66affSColin Finck     PHEADLESS_CMD_PUT_STRING PutString;
260c2c66affSColin Finck     PHEADLESS_CMD_ENABLE_TERMINAL EnableTerminal;
261c2c66affSColin Finck     PHEADLESS_CMD_SET_COLOR SetColor;
262c2c66affSColin Finck     PHEADLESS_CMD_POSITION_CURSOR CursorPos;
263c2c66affSColin Finck     PHEADLESS_RSP_GET_BYTE GetByte;
264c2c66affSColin Finck     UCHAR DataBuffer[80];
265c2c66affSColin Finck 
266c2c66affSColin Finck     ASSERT(HeadlessGlobals != NULL);
267c2c66affSColin Finck     // ASSERT(HeadlessGlobals->PageLockHandle != NULL);
268c2c66affSColin Finck 
269c2c66affSColin Finck     /* Ignore non-reentrant commands */
270c2c66affSColin Finck     if ((Command != HeadlessCmdAddLogEntry) &&
271c2c66affSColin Finck         (Command != HeadlessCmdStartBugCheck) &&
272c2c66affSColin Finck         (Command != HeadlessCmdSendBlueScreenData) &&
273c2c66affSColin Finck         (Command != HeadlessCmdDoBugCheckProcessing))
274c2c66affSColin Finck     {
275c2c66affSColin Finck         OldIrql = HdlspAcquireGlobalLock();
276c2c66affSColin Finck 
277c2c66affSColin Finck         if (HeadlessGlobals->ProcessingCmd)
278c2c66affSColin Finck         {
279c2c66affSColin Finck             HdlspReleaseGlobalLock(OldIrql);
280c2c66affSColin Finck             return STATUS_UNSUCCESSFUL;
281c2c66affSColin Finck         }
282c2c66affSColin Finck 
283c2c66affSColin Finck         /* Don't allow these commands next time */
284c2c66affSColin Finck         HeadlessGlobals->ProcessingCmd = TRUE;
285c2c66affSColin Finck         HdlspReleaseGlobalLock(OldIrql);
286c2c66affSColin Finck     }
287c2c66affSColin Finck 
288c2c66affSColin Finck     /* Handle each command */
289c2c66affSColin Finck     switch (Command)
290c2c66affSColin Finck     {
291c2c66affSColin Finck         case HeadlessCmdEnableTerminal:
292c2c66affSColin Finck         {
293c2c66affSColin Finck             /* Make sure the caller passed valid data */
294c2c66affSColin Finck             if (!(InputBuffer) ||
295c2c66affSColin Finck                 (InputBufferSize != sizeof(*EnableTerminal)))
296c2c66affSColin Finck             {
297c2c66affSColin Finck                 DPRINT1("Invalid buffer\n");
298c2c66affSColin Finck                 Status = STATUS_INVALID_PARAMETER;
299c2c66affSColin Finck                 break;
300c2c66affSColin Finck             }
301c2c66affSColin Finck 
302c2c66affSColin Finck             /* Go and enable it */
303c2c66affSColin Finck             EnableTerminal = InputBuffer;
304c2c66affSColin Finck             Status = HdlspEnableTerminal(EnableTerminal->Enable);
305c2c66affSColin Finck             break;
306c2c66affSColin Finck         }
307c2c66affSColin Finck 
308c2c66affSColin Finck         case HeadlessCmdCheckForReboot:
309c2c66affSColin Finck             break;
310c2c66affSColin Finck 
311c2c66affSColin Finck         case HeadlessCmdPutString:
312c2c66affSColin Finck         {
313c2c66affSColin Finck             /* Validate the existence of an input buffer */
314c2c66affSColin Finck             if (!InputBuffer)
315c2c66affSColin Finck             {
316c2c66affSColin Finck                 Status = STATUS_INVALID_PARAMETER;
317c2c66affSColin Finck                 break;
318c2c66affSColin Finck             }
319c2c66affSColin Finck 
320c2c66affSColin Finck             /* Terminal should be on */
321c2c66affSColin Finck             if (HeadlessGlobals->TerminalEnabled)
322c2c66affSColin Finck             {
323c2c66affSColin Finck                 /* Print each byte in the string making sure VT100 chars are used */
324c2c66affSColin Finck                 PutString = InputBuffer;
325c2c66affSColin Finck                 HdlspPutString(PutString->String);
326c2c66affSColin Finck             }
327c2c66affSColin Finck 
328c2c66affSColin Finck             /* Return success either way */
329c2c66affSColin Finck             Status = STATUS_SUCCESS;
330c2c66affSColin Finck             break;
331c2c66affSColin Finck         }
332c2c66affSColin Finck 
333c2c66affSColin Finck         case HeadlessCmdClearDisplay:
334c2c66affSColin Finck         case HeadlessCmdClearToEndOfDisplay:
335c2c66affSColin Finck         case HeadlessCmdClearToEndOfLine:
336c2c66affSColin Finck         case HeadlessCmdDisplayAttributesOff:
337c2c66affSColin Finck         case HeadlessCmdDisplayInverseVideo:
338c2c66affSColin Finck         case HeadlessCmdSetColor:
339c2c66affSColin Finck         case HeadlessCmdPositionCursor:
340c2c66affSColin Finck         {
341c2c66affSColin Finck             /* By default return success */
342c2c66affSColin Finck             Status = STATUS_SUCCESS;
343c2c66affSColin Finck 
344c2c66affSColin Finck             /* Send the VT100 commands only if the terminal is enabled */
345c2c66affSColin Finck             if (HeadlessGlobals->TerminalEnabled)
346c2c66affSColin Finck             {
347c2c66affSColin Finck                 PUCHAR CommandStr = NULL;
348c2c66affSColin Finck 
349c2c66affSColin Finck                 if (Command == HeadlessCmdClearDisplay)
350c2c66affSColin Finck                     CommandStr = (PUCHAR)"\x1B[2J";
351c2c66affSColin Finck                 else if (Command == HeadlessCmdClearToEndOfDisplay)
352c2c66affSColin Finck                     CommandStr = (PUCHAR)"\x1B[0J";
353c2c66affSColin Finck                 else if (Command == HeadlessCmdClearToEndOfLine)
354c2c66affSColin Finck                     CommandStr = (PUCHAR)"\x1B[0K";
355c2c66affSColin Finck                 else if (Command == HeadlessCmdDisplayAttributesOff)
356c2c66affSColin Finck                     CommandStr = (PUCHAR)"\x1B[0m";
357c2c66affSColin Finck                 else if (Command == HeadlessCmdDisplayInverseVideo)
358c2c66affSColin Finck                     CommandStr = (PUCHAR)"\x1B[7m";
359c2c66affSColin Finck                 else if (Command == HeadlessCmdSetColor)
360c2c66affSColin Finck                 {
361c2c66affSColin Finck                     /* Make sure the caller passed valid data */
362c2c66affSColin Finck                     if (!InputBuffer ||
363c2c66affSColin Finck                         (InputBufferSize != sizeof(*SetColor)))
364c2c66affSColin Finck                     {
365c2c66affSColin Finck                         DPRINT1("Invalid buffer\n");
366c2c66affSColin Finck                         Status = STATUS_INVALID_PARAMETER;
367c2c66affSColin Finck                         break;
368c2c66affSColin Finck                     }
369c2c66affSColin Finck 
370c2c66affSColin Finck                     SetColor = InputBuffer;
371c2c66affSColin Finck                     Status = RtlStringCbPrintfA((PCHAR)DataBuffer, sizeof(DataBuffer),
372c2c66affSColin Finck                                                 "\x1B[%d;%dm",
373c2c66affSColin Finck                                                 SetColor->BkgdColor,
374c2c66affSColin Finck                                                 SetColor->TextColor);
375c2c66affSColin Finck                     if (!NT_SUCCESS(Status)) break;
376c2c66affSColin Finck 
377c2c66affSColin Finck                     CommandStr = DataBuffer;
378c2c66affSColin Finck                 }
379c2c66affSColin Finck                 else // if (Command == HeadlessCmdPositionCursor)
380c2c66affSColin Finck                 {
381c2c66affSColin Finck                     /* Make sure the caller passed valid data */
382c2c66affSColin Finck                     if (!InputBuffer ||
383c2c66affSColin Finck                         (InputBufferSize != sizeof(*CursorPos)))
384c2c66affSColin Finck                     {
385c2c66affSColin Finck                         DPRINT1("Invalid buffer\n");
386c2c66affSColin Finck                         Status = STATUS_INVALID_PARAMETER;
387c2c66affSColin Finck                         break;
388c2c66affSColin Finck                     }
389c2c66affSColin Finck 
390c2c66affSColin Finck                     CursorPos = InputBuffer;
391c2c66affSColin Finck                     /* Cursor position is 1-based */
392c2c66affSColin Finck                     Status = RtlStringCbPrintfA((PCHAR)DataBuffer, sizeof(DataBuffer),
393c2c66affSColin Finck                                                 "\x1B[%d;%dH",
394c2c66affSColin Finck                                                 CursorPos->CursorRow + 1,
395c2c66affSColin Finck                                                 CursorPos->CursorCol + 1);
396c2c66affSColin Finck                     if (!NT_SUCCESS(Status)) break;
397c2c66affSColin Finck 
398c2c66affSColin Finck                     CommandStr = DataBuffer;
399c2c66affSColin Finck                 }
400c2c66affSColin Finck 
401c2c66affSColin Finck                 /* Send the command */
402c2c66affSColin Finck                 HdlspSendStringAtBaud(CommandStr);
403c2c66affSColin Finck             }
404c2c66affSColin Finck 
405c2c66affSColin Finck             break;
406c2c66affSColin Finck         }
407c2c66affSColin Finck 
408c2c66affSColin Finck         case HeadlessCmdTerminalPoll:
409c2c66affSColin Finck             break;
410c2c66affSColin Finck 
411c2c66affSColin Finck         case HeadlessCmdGetByte:
412c2c66affSColin Finck         {
413c2c66affSColin Finck             /* Make sure the caller passed valid data */
414c2c66affSColin Finck             if (!(OutputBuffer) ||
415c2c66affSColin Finck                 !(OutputBufferSize) ||
416c2c66affSColin Finck                 (*OutputBufferSize < sizeof(*GetByte)))
417c2c66affSColin Finck             {
418c2c66affSColin Finck                 DPRINT1("Invalid buffer\n");
419c2c66affSColin Finck                 Status = STATUS_INVALID_PARAMETER;
420c2c66affSColin Finck                 break;
421c2c66affSColin Finck             }
422c2c66affSColin Finck 
423c2c66affSColin Finck             /* Make sure the terminal is enabled */
424c2c66affSColin Finck             GetByte = OutputBuffer;
425c2c66affSColin Finck             if (HeadlessGlobals->TerminalEnabled)
426c2c66affSColin Finck             {
427c2c66affSColin Finck                 /* Poll if something is on the wire */
428c2c66affSColin Finck                 if (InbvPortPollOnly(HeadlessGlobals->TerminalPort))
429c2c66affSColin Finck                 {
430c2c66affSColin Finck                     /* If so, read it */
431c2c66affSColin Finck                     InbvPortGetByte(HeadlessGlobals->TerminalPort,
432c2c66affSColin Finck                                     &GetByte->Value);
433c2c66affSColin Finck                 }
434c2c66affSColin Finck                 else
435c2c66affSColin Finck                 {
436c2c66affSColin Finck                     /* Nothing is there, return 0 */
437c2c66affSColin Finck                     GetByte->Value = 0;
438c2c66affSColin Finck                 }
439c2c66affSColin Finck             }
440c2c66affSColin Finck             else
441c2c66affSColin Finck             {
442c2c66affSColin Finck                 /* Otherwise return nothing */
443c2c66affSColin Finck                 GetByte->Value = 0;
444c2c66affSColin Finck             }
445c2c66affSColin Finck 
446c2c66affSColin Finck             /* Return success either way */
447c2c66affSColin Finck             Status = STATUS_SUCCESS;
448c2c66affSColin Finck             break;
449c2c66affSColin Finck         }
450c2c66affSColin Finck 
451c2c66affSColin Finck         case HeadlessCmdGetLine:
452c2c66affSColin Finck             break;
453c2c66affSColin Finck         case HeadlessCmdStartBugCheck:
454c2c66affSColin Finck             break;
455c2c66affSColin Finck         case HeadlessCmdDoBugCheckProcessing:
456c2c66affSColin Finck             break;
457c2c66affSColin Finck 
458c2c66affSColin Finck         case HeadlessCmdQueryInformation:
459c2c66affSColin Finck         {
460c2c66affSColin Finck             /* Make sure the caller passed valid data */
461c2c66affSColin Finck             if (!(OutputBuffer) ||
462c2c66affSColin Finck                 !(OutputBufferSize) ||
463c2c66affSColin Finck                 (*OutputBufferSize < sizeof(*HeadlessInfo)))
464c2c66affSColin Finck             {
465c2c66affSColin Finck                 DPRINT1("Invalid buffer\n");
466c2c66affSColin Finck                 Status = STATUS_INVALID_PARAMETER;
467c2c66affSColin Finck                 break;
468c2c66affSColin Finck             }
469c2c66affSColin Finck 
470c2c66affSColin Finck             /* If we got here, headless is enabled -- we know this much */
471c2c66affSColin Finck             HeadlessInfo = OutputBuffer;
472c2c66affSColin Finck             HeadlessInfo->PortType = HeadlessSerialPort;
473c2c66affSColin Finck             HeadlessInfo->Serial.TerminalAttached = TRUE;
474c2c66affSColin Finck             HeadlessInfo->Serial.UsedBiosSettings = HeadlessGlobals->UsedBiosSettings != 0;
475c2c66affSColin Finck             HeadlessInfo->Serial.TerminalBaudRate = HeadlessGlobals->TerminalBaudRate;
476c2c66affSColin Finck             HeadlessInfo->Serial.TerminalType = HeadlessGlobals->TerminalType;
477c2c66affSColin Finck 
478c2c66affSColin Finck             /* Now check on what port/baud it's enabled on */
479c2c66affSColin Finck             if ((HeadlessGlobals->TerminalPortNumber >= 1) ||
480c2c66affSColin Finck                 (HeadlessGlobals->UsedBiosSettings))
481c2c66affSColin Finck             {
482c2c66affSColin Finck                 /* Get the EMS information */
483c2c66affSColin Finck                 HeadlessInfo->Serial.TerminalPort = HeadlessGlobals->
484c2c66affSColin Finck                                                     TerminalPortNumber;
485c2c66affSColin Finck                 HeadlessInfo->Serial.TerminalPortBaseAddress = HeadlessGlobals->
486c2c66affSColin Finck                                                                TerminalPortAddress;
487c2c66affSColin Finck             }
488c2c66affSColin Finck             else
489c2c66affSColin Finck             {
490c2c66affSColin Finck                 /* We don't know for sure */
491c2c66affSColin Finck                 HeadlessInfo->Serial.TerminalPort = SerialPortUndefined;
492c2c66affSColin Finck                 HeadlessInfo->Serial.TerminalPortBaseAddress = 0;
493c2c66affSColin Finck             }
494c2c66affSColin Finck 
495c2c66affSColin Finck             /* All done */
496c2c66affSColin Finck             Status = STATUS_SUCCESS;
497c2c66affSColin Finck             break;
498c2c66affSColin Finck         }
499c2c66affSColin Finck 
500c2c66affSColin Finck         case HeadlessCmdAddLogEntry:
501c2c66affSColin Finck             break;
502c2c66affSColin Finck         case HeadlessCmdDisplayLog:
503c2c66affSColin Finck             break;
504c2c66affSColin Finck 
505c2c66affSColin Finck         case HeadlessCmdSetBlueScreenData:
506c2c66affSColin Finck         {
507c2c66affSColin Finck             /* Validate the existence of an input buffer */
508c2c66affSColin Finck             if (!InputBuffer)
509c2c66affSColin Finck             {
510c2c66affSColin Finck                 Status = STATUS_INVALID_PARAMETER;
511c2c66affSColin Finck                 break;
512c2c66affSColin Finck             }
513c2c66affSColin Finck 
514c2c66affSColin Finck             /* Lie so that we can get Hdl bringup a little bit further */
515c2c66affSColin Finck             UNIMPLEMENTED;
516c2c66affSColin Finck             Status = STATUS_SUCCESS;
517c2c66affSColin Finck             break;
518c2c66affSColin Finck         }
519c2c66affSColin Finck 
520c2c66affSColin Finck         case HeadlessCmdSendBlueScreenData:
521c2c66affSColin Finck             break;
522c2c66affSColin Finck         case HeadlessCmdQueryGUID:
523c2c66affSColin Finck             break;
524c2c66affSColin Finck 
525c2c66affSColin Finck         case HeadlessCmdPutData:
526c2c66affSColin Finck         {
527c2c66affSColin Finck             /* Validate the existence of an input buffer */
528c2c66affSColin Finck             if (!(InputBuffer) || !(InputBufferSize))
529c2c66affSColin Finck             {
530c2c66affSColin Finck                 Status = STATUS_INVALID_PARAMETER;
531c2c66affSColin Finck                 break;
532c2c66affSColin Finck             }
533c2c66affSColin Finck 
534c2c66affSColin Finck             /* Terminal should be on */
535c2c66affSColin Finck             if (HeadlessGlobals->TerminalEnabled)
536c2c66affSColin Finck             {
537c2c66affSColin Finck                 /* Print each byte in the string making sure VT100 chars are used */
538c2c66affSColin Finck                 PutString = InputBuffer;
539c2c66affSColin Finck                 HdlspPutData(PutString->String, InputBufferSize);
540c2c66affSColin Finck             }
541c2c66affSColin Finck 
542c2c66affSColin Finck             /* Return success either way */
543c2c66affSColin Finck             Status = STATUS_SUCCESS;
544c2c66affSColin Finck             break;
545c2c66affSColin Finck         }
546c2c66affSColin Finck 
547c2c66affSColin Finck         default:
548c2c66affSColin Finck             break;
549c2c66affSColin Finck     }
550c2c66affSColin Finck 
551c2c66affSColin Finck     /* Unset processing state */
552c2c66affSColin Finck     if ((Command != HeadlessCmdAddLogEntry) &&
553c2c66affSColin Finck         (Command != HeadlessCmdStartBugCheck) &&
554c2c66affSColin Finck         (Command != HeadlessCmdSendBlueScreenData) &&
555c2c66affSColin Finck         (Command != HeadlessCmdDoBugCheckProcessing))
556c2c66affSColin Finck     {
557c2c66affSColin Finck         ASSERT(HeadlessGlobals->ProcessingCmd == TRUE);
558c2c66affSColin Finck         HeadlessGlobals->ProcessingCmd = FALSE;
559c2c66affSColin Finck     }
560c2c66affSColin Finck 
561c2c66affSColin Finck     /* All done */
562c2c66affSColin Finck     return Status;
563c2c66affSColin Finck }
564c2c66affSColin Finck 
565c2c66affSColin Finck /*
566c2c66affSColin Finck  * @implemented
567c2c66affSColin Finck  */
568c2c66affSColin Finck NTSTATUS
569c2c66affSColin Finck NTAPI
HeadlessDispatch(IN HEADLESS_CMD Command,IN PVOID InputBuffer,IN SIZE_T InputBufferSize,OUT PVOID OutputBuffer,OUT PSIZE_T OutputBufferSize)570c2c66affSColin Finck HeadlessDispatch(IN HEADLESS_CMD Command,
571c2c66affSColin Finck                  IN PVOID InputBuffer,
572c2c66affSColin Finck                  IN SIZE_T InputBufferSize,
573c2c66affSColin Finck                  OUT PVOID OutputBuffer,
574c2c66affSColin Finck                  OUT PSIZE_T OutputBufferSize)
575c2c66affSColin Finck {
576c2c66affSColin Finck     /* Check for stubs that will expect something even with headless off */
577c2c66affSColin Finck     if (!HeadlessGlobals)
578c2c66affSColin Finck     {
579c2c66affSColin Finck         /* Don't allow the SAC to connect */
580c2c66affSColin Finck         if (Command == HeadlessCmdEnableTerminal) return STATUS_UNSUCCESSFUL;
581c2c66affSColin Finck 
582c2c66affSColin Finck         /* Send bogus reply */
583c2c66affSColin Finck         if ((Command == HeadlessCmdQueryInformation) ||
584c2c66affSColin Finck             (Command == HeadlessCmdGetByte) ||
585c2c66affSColin Finck             (Command == HeadlessCmdGetLine) ||
586c2c66affSColin Finck             (Command == HeadlessCmdCheckForReboot) ||
587c2c66affSColin Finck             (Command == HeadlessCmdTerminalPoll))
588c2c66affSColin Finck         {
589c2c66affSColin Finck             if (!(OutputBuffer) || !(OutputBufferSize))
590c2c66affSColin Finck             {
591c2c66affSColin Finck                 return STATUS_INVALID_PARAMETER;
592c2c66affSColin Finck             }
593c2c66affSColin Finck 
594c2c66affSColin Finck             RtlZeroMemory(OutputBuffer, *OutputBufferSize);
595c2c66affSColin Finck         }
596c2c66affSColin Finck 
597c2c66affSColin Finck         return STATUS_SUCCESS;
598c2c66affSColin Finck     }
599c2c66affSColin Finck 
600c2c66affSColin Finck     /* Do the real work */
601c2c66affSColin Finck     return HdlspDispatch(Command,
602c2c66affSColin Finck                          InputBuffer,
603c2c66affSColin Finck                          InputBufferSize,
604c2c66affSColin Finck                          OutputBuffer,
605c2c66affSColin Finck                          OutputBufferSize);
606c2c66affSColin Finck }
607c2c66affSColin Finck 
608c2c66affSColin Finck /* EOF */
609