1 /* 2 * Copyright 2014-2016 Haiku, Inc. All rights reserved. 3 * Copyright 2013 Fredrik Holmqvist, fredrik.holmqvist@gmail.com. All rights 4 * reserved. 5 * Distributed under the terms of the MIT License. 6 */ 7 8 9 #include "console.h" 10 11 #include <string.h> 12 13 #include <SupportDefs.h> 14 15 #include <boot/stage2.h> 16 #include <boot/platform.h> 17 #include <efi/protocol/console-control.h> 18 #include <util/kernel_cpp.h> 19 20 #include "efi_platform.h" 21 22 23 // This likely won't work without moving things around. 24 // Too early (pre-console init) 25 //#define TRACE_CONSOLE 26 #ifdef TRACE_CONSOLE 27 # define TRACE(x...) dprintf(x) 28 #else 29 # define TRACE(x...) 30 #endif 31 32 33 class Console : public ConsoleNode { 34 public: 35 Console(); 36 37 virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, 38 size_t bufferSize); 39 virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, 40 size_t bufferSize); 41 }; 42 43 44 static uint32 sScreenWidth; 45 static uint32 sScreenHeight; 46 static uint32 sScreenMode; 47 static Console sInput, sOutput; 48 FILE *stdin, *stdout, *stderr; 49 50 51 // #pragma mark - 52 53 54 Console::Console() 55 : ConsoleNode() 56 { 57 } 58 59 60 ssize_t 61 Console::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize) 62 { 63 return B_ERROR; 64 } 65 66 67 ssize_t 68 Console::WriteAt(void *cookie, off_t /*pos*/, const void *buffer, 69 size_t bufferSize) 70 { 71 const char *string = (const char *)buffer; 72 char16_t ucsBuffer[bufferSize + 3]; 73 uint32 j = 0; 74 75 for (uint32 i = 0; i < bufferSize; i++) { 76 switch (string[i]) { 77 case '\n': { 78 ucsBuffer[j++] = '\r'; 79 ucsBuffer[j++] = '\n'; 80 } //fallthrough 81 case 0 : { 82 //Not sure if we should keep going or abort for 0. 83 //Keep going was easy anyway. 84 ucsBuffer[j] = 0; 85 kSystemTable->ConOut->OutputString(kSystemTable->ConOut, 86 ucsBuffer); 87 j = 0; 88 continue; 89 } 90 default: 91 ucsBuffer[j++] = (char16_t)string[i]; 92 } 93 } 94 95 if (j > 0) { 96 ucsBuffer[j] = 0; 97 kSystemTable->ConOut->OutputString(kSystemTable->ConOut, ucsBuffer); 98 } 99 return bufferSize; 100 } 101 102 103 // #pragma mark - 104 105 106 void 107 console_clear_screen(void) 108 { 109 kSystemTable->ConOut->ClearScreen(kSystemTable->ConOut); 110 } 111 112 113 int32 114 console_width(void) 115 { 116 return sScreenWidth; 117 } 118 119 120 int32 121 console_height(void) 122 { 123 return sScreenHeight; 124 } 125 126 127 void 128 console_set_cursor(int32 x, int32 y) 129 { 130 kSystemTable->ConOut->SetCursorPosition(kSystemTable->ConOut, x, y); 131 } 132 133 134 void 135 console_show_cursor(void) 136 { 137 kSystemTable->ConOut->EnableCursor(kSystemTable->ConOut, true); 138 } 139 140 141 void 142 console_hide_cursor(void) 143 { 144 kSystemTable->ConOut->EnableCursor(kSystemTable->ConOut, false); 145 } 146 147 148 void 149 console_set_color(int32 foreground, int32 background) 150 { 151 kSystemTable->ConOut->SetAttribute(kSystemTable->ConOut, 152 EFI_TEXT_ATTR((foreground & 0xf), (background & 0xf))); 153 } 154 155 156 int 157 console_wait_for_key(void) 158 { 159 size_t index; 160 efi_status status; 161 efi_input_key key; 162 efi_event event = kSystemTable->ConIn->WaitForKey; 163 164 do { 165 kBootServices->WaitForEvent(1, &event, &index); 166 status = kSystemTable->ConIn->ReadKeyStroke(kSystemTable->ConIn, &key); 167 } while (status == EFI_NOT_READY); 168 169 if (key.UnicodeChar > 0) 170 return (int) key.UnicodeChar; 171 172 switch (key.ScanCode) { 173 case SCAN_ESC: 174 return TEXT_CONSOLE_KEY_ESCAPE; 175 case SCAN_UP: 176 return TEXT_CONSOLE_KEY_UP; 177 case SCAN_DOWN: 178 return TEXT_CONSOLE_KEY_DOWN; 179 case SCAN_LEFT: 180 return TEXT_CONSOLE_KEY_LEFT; 181 case SCAN_RIGHT: 182 return TEXT_CONSOLE_KEY_RIGHT; 183 case SCAN_PAGE_UP: 184 return TEXT_CONSOLE_KEY_PAGE_UP; 185 case SCAN_PAGE_DOWN: 186 return TEXT_CONSOLE_KEY_PAGE_DOWN; 187 case SCAN_HOME: 188 return TEXT_CONSOLE_KEY_HOME; 189 case SCAN_END: 190 return TEXT_CONSOLE_KEY_END; 191 } 192 return 0; 193 } 194 195 196 static void update_screen_size(void) 197 { 198 size_t width, height; 199 size_t area = 0; 200 efi_simple_text_output_protocol *ConOut = kSystemTable->ConOut; 201 202 for (int mode = 0; mode < ConOut->Mode->MaxMode; ++mode) { 203 if (ConOut->QueryMode(ConOut, mode, &width, &height) == EFI_SUCCESS) { 204 if (width * height > area) { 205 sScreenWidth = width; 206 sScreenHeight = height; 207 sScreenMode = mode; 208 } 209 } 210 } 211 212 ConOut->SetMode(ConOut, sScreenMode); 213 } 214 215 216 status_t 217 console_init(void) 218 { 219 update_screen_size(); 220 console_hide_cursor(); 221 console_clear_screen(); 222 223 // enable stdio functionality 224 stdin = (FILE *)&sInput; 225 stdout = stderr = (FILE *)&sOutput; 226 227 return B_OK; 228 } 229 230 231 uint32 232 console_check_boot_keys(void) 233 { 234 efi_input_key key; 235 236 for (int i = 0; i < 3; i++) { 237 // give the user a chance to press a key 238 kBootServices->Stall(100000); 239 240 efi_status status = kSystemTable->ConIn->ReadKeyStroke( 241 kSystemTable->ConIn, &key); 242 243 if (status != EFI_SUCCESS) 244 continue; 245 246 if (key.UnicodeChar == 0 && key.ScanCode == SCAN_ESC) 247 return BOOT_OPTION_DEBUG_OUTPUT; 248 if (key.UnicodeChar == ' ') 249 return BOOT_OPTION_MENU; 250 } 251 return 0; 252 } 253 254 255 extern "C" void 256 platform_switch_to_text_mode(void) 257 { 258 kSystemTable->ConOut->Reset(kSystemTable->ConOut, false); 259 kSystemTable->ConOut->SetMode(kSystemTable->ConOut, sScreenMode); 260 } 261