2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/ex/hdlsterm.c
5 * PURPOSE: Headless Terminal Support
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES ******************************************************************/
14 /* GLOBALS *******************************************************************/
16 PHEADLESS_GLOBALS HeadlessGlobals
;
18 /* FUNCTIONS *****************************************************************/
22 HdlspSendStringAtBaud(
27 while (*String
++ != ANSI_NULL
)
29 InbvPortPutByte(HeadlessGlobals
->TerminalPort
, *String
);
39 /* Enable if requested, as long as this isn't a PCI serial port crashing */
41 !(HeadlessGlobals
->TerminalEnabled
) &&
42 !((HeadlessGlobals
->IsMMIODevice
) && (HeadlessGlobals
->InBugCheck
)))
44 /* Initialize the COM port with cportlib */
45 HeadlessGlobals
->TerminalEnabled
= InbvPortInitialize(
46 HeadlessGlobals
->TerminalBaudRate
,
47 HeadlessGlobals
->TerminalPortNumber
,
48 HeadlessGlobals
->TerminalPortAddress
,
49 &HeadlessGlobals
->TerminalPort
,
50 HeadlessGlobals
->IsMMIODevice
);
51 if (!HeadlessGlobals
->TerminalEnabled
) return STATUS_UNSUCCESSFUL
;
53 /* Cleanup the screen and reset the cursor */
54 HdlspSendStringAtBaud((PUCHAR
)"\x1B[2J");
55 HdlspSendStringAtBaud((PUCHAR
)"\x1B[H");
58 InbvPortEnableFifo(HeadlessGlobals
->TerminalPort
, TRUE
);
62 /* Specific case when headless is being disabled */
63 InbvPortTerminate(HeadlessGlobals
->TerminalPort
);
64 HeadlessGlobals
->TerminalPort
= 0;
65 HeadlessGlobals
->TerminalEnabled
= FALSE
;
67 return STATUS_SUCCESS
;
73 IN PLOADER_PARAMETER_BLOCK LoaderBlock
76 PHEADLESS_LOADER_BLOCK HeadlessBlock
;
78 HeadlessBlock
= LoaderBlock
->Extension
->HeadlessLoaderBlock
;
79 if (!HeadlessBlock
) return;
80 if ((HeadlessBlock
->PortNumber
> 4) && (HeadlessBlock
->UsedBiosSettings
)) return;
82 HeadlessGlobals
= ExAllocatePoolWithTag(
84 sizeof(HEADLESS_GLOBALS
),
86 if (!HeadlessGlobals
) return;
88 /* Zero and copy loader data */
89 RtlZeroMemory(HeadlessGlobals
, sizeof(HEADLESS_GLOBALS
));
90 HeadlessGlobals
->TerminalPortNumber
= HeadlessBlock
->PortNumber
;
91 HeadlessGlobals
->TerminalPortAddress
= HeadlessBlock
->PortAddress
;
92 HeadlessGlobals
->TerminalBaudRate
= HeadlessBlock
->BaudRate
;
93 HeadlessGlobals
->TerminalParity
= HeadlessBlock
->Parity
;
94 HeadlessGlobals
->TerminalStopBits
= HeadlessBlock
->StopBits
;
95 HeadlessGlobals
->UsedBiosSettings
= HeadlessBlock
->UsedBiosSettings
;
96 HeadlessGlobals
->IsMMIODevice
= HeadlessBlock
->IsMMIODevice
;
97 HeadlessGlobals
->TerminalType
= HeadlessBlock
->TerminalType
;
98 HeadlessGlobals
->SystemGUID
= HeadlessBlock
->SystemGUID
;
100 /* These two are opposites of each other */
101 if (HeadlessGlobals
->IsMMIODevice
) HeadlessGlobals
->IsNonLegacyDevice
= TRUE
;
103 /* Check for a PCI device, warn that this isn't supported */
104 if (HeadlessBlock
->PciDeviceId
!= PCI_INVALID_VENDORID
)
106 DPRINT1("PCI Serial Ports not supported\n");
109 /* Log entries are not yet supported */
110 DPRINT1("FIXME: No Headless logging support\n");
112 /* Allocate temporary buffer */
113 HeadlessGlobals
->TmpBuffer
= ExAllocatePoolWithTag(NonPagedPool
, 80, 'sldH');
114 if (!HeadlessGlobals
->TmpBuffer
) return;
116 /* Windows seems to apply some special hacks for 9600 bps */
117 if (HeadlessGlobals
->TerminalBaudRate
== 9600)
119 DPRINT1("Please use other baud rate than 9600bps for now\n");
122 /* Enable the terminal */
123 HdlspEnableTerminal(TRUE
);
132 PUCHAR Dest
= HeadlessGlobals
->TmpBuffer
;
135 /* Scan each character */
136 while (*String
!= ANSI_NULL
)
138 /* Check for rotate, send existing buffer and restart from where we are */
139 if (Dest
>= &HeadlessGlobals
->TmpBuffer
[79])
141 HeadlessGlobals
->TmpBuffer
[79] = ANSI_NULL
;
142 HdlspSendStringAtBaud(HeadlessGlobals
->TmpBuffer
);
143 Dest
= HeadlessGlobals
->TmpBuffer
;
147 /* Get the current character and check for special graphical chars */
153 case 0xB0: case 0xB3: case 0xBA:
156 case 0xB1: case 0xDC: case 0xDD: case 0xDE: case 0xDF:
159 case 0xB2: case 0xDB:
162 case 0xA9: case 0xAA: case 0xBB: case 0xBC: case 0xBF:
163 case 0xC0: case 0xC8: case 0xC9: case 0xD9: case 0xDA:
175 /* Anything else must be Unicode */
178 /* Can't do Unicode yet */
183 /* Add the modified char to the temporary buffer */
187 /* Check the next char */
192 /* Finish and send */
194 HdlspSendStringAtBaud(HeadlessGlobals
->TmpBuffer
);
200 IN HEADLESS_CMD Command
,
201 IN PVOID InputBuffer
,
202 IN SIZE_T InputBufferSize
,
203 OUT PVOID OutputBuffer
,
204 OUT PSIZE_T OutputBufferSize
207 NTSTATUS Status
= STATUS_NOT_IMPLEMENTED
;
208 ASSERT(HeadlessGlobals
!= NULL
);
209 // ASSERT(HeadlessGlobals->PageLockHandle != NULL);
211 /* FIXME: This should be using the headless spinlock */
213 /* Ignore non-reentrant commands */
214 if ((Command
!= HeadlessCmdAddLogEntry
) &&
215 (Command
!= HeadlessCmdStartBugCheck
) &&
216 (Command
!= HeadlessCmdSendBlueScreenData
) &&
217 (Command
!= HeadlessCmdDoBugCheckProcessing
))
219 if (HeadlessGlobals
->ProcessingCmd
) return STATUS_UNSUCCESSFUL
;
221 /* Don't allow these commands next time */
222 HeadlessGlobals
->ProcessingCmd
= TRUE
;
225 /* Handle each command */
228 case HeadlessCmdEnableTerminal
:
230 case HeadlessCmdCheckForReboot
:
233 case HeadlessCmdPutString
:
235 /* Validate the existence of an input buffer */
238 Status
= STATUS_INVALID_PARAMETER
;
242 /* Terminal should be on */
243 if (HeadlessGlobals
->TerminalEnabled
)
245 /* Print each byte in the string making sure VT100 chars are used */
246 PHEADLESS_CMD_PUT_STRING PutString
= (PVOID
)InputBuffer
;
247 HdlspPutString(PutString
->String
);
250 /* Return success either way */
251 Status
= STATUS_SUCCESS
;
253 case HeadlessCmdClearDisplay
:
255 case HeadlessCmdClearToEndOfDisplay
:
257 case HeadlessCmdClearToEndOfLine
:
259 case HeadlessCmdDisplayAttributesOff
:
261 case HeadlessCmdDisplayInverseVideo
:
263 case HeadlessCmdSetColor
:
265 case HeadlessCmdPositionCursor
:
267 case HeadlessCmdTerminalPoll
:
269 case HeadlessCmdGetByte
:
271 case HeadlessCmdGetLine
:
273 case HeadlessCmdStartBugCheck
:
275 case HeadlessCmdDoBugCheckProcessing
:
277 case HeadlessCmdQueryInformation
:
279 case HeadlessCmdAddLogEntry
:
281 case HeadlessCmdDisplayLog
:
283 case HeadlessCmdSetBlueScreenData
:
285 case HeadlessCmdSendBlueScreenData
:
287 case HeadlessCmdQueryGUID
:
289 case HeadlessCmdPutData
:
296 /* Unset prcessing state */
297 if ((Command
!= HeadlessCmdAddLogEntry
) &&
298 (Command
!= HeadlessCmdStartBugCheck
) &&
299 (Command
!= HeadlessCmdSendBlueScreenData
) &&
300 (Command
!= HeadlessCmdDoBugCheckProcessing
))
302 ASSERT(HeadlessGlobals
->ProcessingCmd
== TRUE
);
303 HeadlessGlobals
->ProcessingCmd
= FALSE
;
307 return STATUS_SUCCESS
;
316 IN HEADLESS_CMD Command
,
317 IN PVOID InputBuffer
,
318 IN SIZE_T InputBufferSize
,
319 OUT PVOID OutputBuffer
,
320 OUT PSIZE_T OutputBufferSize
323 /* Check for stubs that will expect something even with headless off */
324 if (!HeadlessGlobals
)
326 /* Don't allow the SAC to connect */
327 if (Command
== HeadlessCmdEnableTerminal
) return STATUS_UNSUCCESSFUL
;
329 /* Send bogus reply */
330 if ((Command
== HeadlessCmdQueryInformation
) ||
331 (Command
== HeadlessCmdGetByte
) ||
332 (Command
== HeadlessCmdGetLine
) ||
333 (Command
== HeadlessCmdCheckForReboot
) ||
334 (Command
== HeadlessCmdTerminalPoll
))
336 if (!(OutputBuffer
) || !(OutputBufferSize
)) return STATUS_INVALID_PARAMETER
;
337 RtlZeroMemory(OutputBuffer
, *OutputBufferSize
);
339 return STATUS_SUCCESS
;
342 /* Do the real work */
343 return HdlspDispatch(