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