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