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