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
;
74 IN PLOADER_PARAMETER_BLOCK LoaderBlock
77 PHEADLESS_LOADER_BLOCK HeadlessBlock
;
79 HeadlessBlock
= LoaderBlock
->Extension
->HeadlessLoaderBlock
;
80 if (!HeadlessBlock
) return;
81 if ((HeadlessBlock
->PortNumber
> 4) && (HeadlessBlock
->UsedBiosSettings
)) return;
83 HeadlessGlobals
= ExAllocatePoolWithTag(
85 sizeof(HEADLESS_GLOBALS
),
87 if (!HeadlessGlobals
) return;
89 /* Zero and copy loader data */
90 RtlZeroMemory(HeadlessGlobals
, sizeof(HEADLESS_GLOBALS
));
91 HeadlessGlobals
->TerminalPortNumber
= HeadlessBlock
->PortNumber
;
92 HeadlessGlobals
->TerminalPortAddress
= HeadlessBlock
->PortAddress
;
93 HeadlessGlobals
->TerminalBaudRate
= HeadlessBlock
->BaudRate
;
94 HeadlessGlobals
->TerminalParity
= HeadlessBlock
->Parity
;
95 HeadlessGlobals
->TerminalStopBits
= HeadlessBlock
->StopBits
;
96 HeadlessGlobals
->UsedBiosSettings
= HeadlessBlock
->UsedBiosSettings
;
97 HeadlessGlobals
->IsMMIODevice
= HeadlessBlock
->IsMMIODevice
;
98 HeadlessGlobals
->TerminalType
= HeadlessBlock
->TerminalType
;
99 HeadlessGlobals
->SystemGUID
= HeadlessBlock
->SystemGUID
;
101 /* These two are opposites of each other */
102 if (HeadlessGlobals
->IsMMIODevice
) HeadlessGlobals
->IsNonLegacyDevice
= TRUE
;
104 /* Check for a PCI device, warn that this isn't supported */
105 if (HeadlessBlock
->PciDeviceId
!= PCI_INVALID_VENDORID
)
107 DPRINT1("PCI Serial Ports not supported\n");
110 /* Log entries are not yet supported */
111 DPRINT1("FIXME: No Headless logging support\n");
113 /* Allocate temporary buffer */
114 HeadlessGlobals
->TmpBuffer
= ExAllocatePoolWithTag(NonPagedPool
, 80, 'sldH');
115 if (!HeadlessGlobals
->TmpBuffer
) return;
117 /* Windows seems to apply some special hacks for 9600 bps */
118 if (HeadlessGlobals
->TerminalBaudRate
== 9600)
120 DPRINT1("Please use other baud rate than 9600bps for now\n");
123 /* Enable the terminal */
124 HdlspEnableTerminal(TRUE
);
133 PUCHAR Dest
= HeadlessGlobals
->TmpBuffer
;
136 /* Scan each character */
137 while (*String
!= ANSI_NULL
)
139 /* Check for rotate, send existing buffer and restart from where we are */
140 if (Dest
>= &HeadlessGlobals
->TmpBuffer
[79])
142 HeadlessGlobals
->TmpBuffer
[79] = ANSI_NULL
;
143 HdlspSendStringAtBaud(HeadlessGlobals
->TmpBuffer
);
144 Dest
= HeadlessGlobals
->TmpBuffer
;
148 /* Get the current character and check for special graphical chars */
154 case 0xB0: case 0xB3: case 0xBA:
157 case 0xB1: case 0xDC: case 0xDD: case 0xDE: case 0xDF:
160 case 0xB2: case 0xDB:
163 case 0xA9: case 0xAA: case 0xBB: case 0xBC: case 0xBF:
164 case 0xC0: case 0xC8: case 0xC9: case 0xD9: case 0xDA:
176 /* Anything else must be Unicode */
179 /* Can't do Unicode yet */
184 /* Add the modified char to the temporary buffer */
188 /* Check the next char */
193 /* Finish and send */
195 HdlspSendStringAtBaud(HeadlessGlobals
->TmpBuffer
);
201 IN HEADLESS_CMD Command
,
202 IN PVOID InputBuffer
,
203 IN SIZE_T InputBufferSize
,
204 OUT PVOID OutputBuffer
,
205 OUT PSIZE_T OutputBufferSize
208 //NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
209 ASSERT(HeadlessGlobals
!= NULL
);
210 // ASSERT(HeadlessGlobals->PageLockHandle != NULL);
212 /* FIXME: This should be using the headless spinlock */
214 /* Ignore non-reentrant commands */
215 if ((Command
!= HeadlessCmdAddLogEntry
) &&
216 (Command
!= HeadlessCmdStartBugCheck
) &&
217 (Command
!= HeadlessCmdSendBlueScreenData
) &&
218 (Command
!= HeadlessCmdDoBugCheckProcessing
))
220 if (HeadlessGlobals
->ProcessingCmd
) return STATUS_UNSUCCESSFUL
;
222 /* Don't allow these commands next time */
223 HeadlessGlobals
->ProcessingCmd
= TRUE
;
226 /* Handle each command */
229 case HeadlessCmdEnableTerminal
:
231 case HeadlessCmdCheckForReboot
:
234 case HeadlessCmdPutString
:
236 /* Validate the existence of an input buffer */
239 //Status = STATUS_INVALID_PARAMETER;
243 /* Terminal should be on */
244 if (HeadlessGlobals
->TerminalEnabled
)
246 /* Print each byte in the string making sure VT100 chars are used */
247 PHEADLESS_CMD_PUT_STRING PutString
= (PVOID
)InputBuffer
;
248 HdlspPutString(PutString
->String
);
251 /* Return success either way */
252 //Status = STATUS_SUCCESS;
254 case HeadlessCmdClearDisplay
:
256 case HeadlessCmdClearToEndOfDisplay
:
258 case HeadlessCmdClearToEndOfLine
:
260 case HeadlessCmdDisplayAttributesOff
:
262 case HeadlessCmdDisplayInverseVideo
:
264 case HeadlessCmdSetColor
:
266 case HeadlessCmdPositionCursor
:
268 case HeadlessCmdTerminalPoll
:
270 case HeadlessCmdGetByte
:
272 case HeadlessCmdGetLine
:
274 case HeadlessCmdStartBugCheck
:
276 case HeadlessCmdDoBugCheckProcessing
:
278 case HeadlessCmdQueryInformation
:
280 case HeadlessCmdAddLogEntry
:
282 case HeadlessCmdDisplayLog
:
284 case HeadlessCmdSetBlueScreenData
:
286 case HeadlessCmdSendBlueScreenData
:
288 case HeadlessCmdQueryGUID
:
290 case HeadlessCmdPutData
:
297 /* Unset prcessing state */
298 if ((Command
!= HeadlessCmdAddLogEntry
) &&
299 (Command
!= HeadlessCmdStartBugCheck
) &&
300 (Command
!= HeadlessCmdSendBlueScreenData
) &&
301 (Command
!= HeadlessCmdDoBugCheckProcessing
))
303 ASSERT(HeadlessGlobals
->ProcessingCmd
== TRUE
);
304 HeadlessGlobals
->ProcessingCmd
= FALSE
;
308 return STATUS_SUCCESS
;
317 IN HEADLESS_CMD Command
,
318 IN PVOID InputBuffer
,
319 IN SIZE_T InputBufferSize
,
320 OUT PVOID OutputBuffer
,
321 OUT PSIZE_T OutputBufferSize
324 /* Check for stubs that will expect something even with headless off */
325 if (!HeadlessGlobals
)
327 /* Don't allow the SAC to connect */
328 if (Command
== HeadlessCmdEnableTerminal
) return STATUS_UNSUCCESSFUL
;
330 /* Send bogus reply */
331 if ((Command
== HeadlessCmdQueryInformation
) ||
332 (Command
== HeadlessCmdGetByte
) ||
333 (Command
== HeadlessCmdGetLine
) ||
334 (Command
== HeadlessCmdCheckForReboot
) ||
335 (Command
== HeadlessCmdTerminalPoll
))
337 if (!(OutputBuffer
) || !(OutputBufferSize
)) return STATUS_INVALID_PARAMETER
;
338 RtlZeroMemory(OutputBuffer
, *OutputBufferSize
);
340 return STATUS_SUCCESS
;
343 /* Do the real work */
344 return HdlspDispatch(