1 /* 2 * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 3 * Copyright 2011, Rene Gollent, rene@gollent.com. All rights reserved. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 #include "console.h" 9 #include "video.h" 10 #include "graphics.h" 11 #include <Htif.h> 12 #include "virtio.h" 13 14 #include <SupportDefs.h> 15 #include <util/kernel_cpp.h> 16 #include <boot/stage2.h> 17 18 #include <string.h> 19 20 21 class Console : public ConsoleNode { 22 public: 23 Console(); 24 25 virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, 26 size_t bufferSize); 27 virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, 28 size_t bufferSize); 29 }; 30 31 static uint16* sScreenBase; 32 static uint32 sScreenOfsX = 0; 33 static uint32 sScreenOfsY = 0; 34 static uint32 sScreenWidth = 80; 35 static uint32 sScreenHeight = 25; 36 static uint32 sScreenOffset = 0; 37 static uint16 sColor = 0x0f00; 38 39 static Console sInput, sOutput; 40 FILE *stdin, *stdout, *stderr; 41 42 43 static const uint32 kPalette[] = { 44 0x000000, 45 0x0000aa, 46 0x00aa00, 47 0x00aaaa, 48 0xaa0000, 49 0xaa00aa, 50 0xaa5500, 51 0xaaaaaa, 52 0x555555, 53 0x5555ff, 54 0x55ff55, 55 0x55ffff, 56 0xff5555, 57 0xff55ff, 58 0xffff55, 59 0xffffff 60 }; 61 62 63 static void 64 RefreshFramebuf(int32 x0, int32 y0, int32 w, int32 h) 65 { 66 for (int32 y = y0; y < y0 + h; y++) 67 for (int32 x = x0; x < x0 + w; x++) { 68 uint16 cell = sScreenBase[x + y * sScreenWidth]; 69 int32 charX = sScreenOfsX + x*gFixedFont.charWidth; 70 int32 charY = sScreenOfsY + y*gFixedFont.charHeight; 71 uint32 bgColor = kPalette[cell / 0x1000 % 0x10]; 72 uint32 fontColor = kPalette[cell / 0x100 % 0x10]; 73 Clear(gFramebuf.Clip(charX, charY, gFixedFont.charWidth, 74 gFixedFont.charHeight), bgColor); 75 BlitMaskRgb(gFramebuf, gFixedFont.ThisGlyph(cell % 0x100), 76 charX, charY, fontColor); 77 } 78 } 79 80 81 static void 82 scroll_up() 83 { 84 memcpy(sScreenBase, sScreenBase + sScreenWidth, 85 sScreenWidth * sScreenHeight * 2 - sScreenWidth * 2); 86 sScreenOffset = (sScreenHeight - 1) * sScreenWidth; 87 88 for (uint32 i = 0; i < sScreenWidth; i++) 89 sScreenBase[sScreenOffset + i] = sColor | ' '; 90 } 91 92 93 // #pragma mark - 94 95 96 Console::Console() 97 : ConsoleNode() 98 { 99 } 100 101 102 ssize_t 103 Console::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize) 104 { 105 // don't seek in character devices 106 // not implemented (and not yet? needed) 107 return B_ERROR; 108 } 109 110 111 ssize_t 112 Console::WriteAt(void *cookie, off_t /*pos*/, const void *buffer, 113 size_t bufferSize) 114 { 115 const char *string = (const char *)buffer; 116 117 if (gKernelArgs.frame_buffer.enabled) 118 return bufferSize; 119 120 for (uint32 i = 0; i < bufferSize; i++) { 121 if (string[0] == '\n') { 122 sScreenOffset += sScreenWidth - (sScreenOffset % sScreenWidth); 123 } else { 124 sScreenBase[sScreenOffset++] = sColor | string[0]; 125 RefreshFramebuf((sScreenOffset - 1) % sScreenWidth, 126 (sScreenOffset - 1) / sScreenWidth, 1, 1); 127 } 128 129 if (sScreenOffset >= sScreenWidth * sScreenHeight) { 130 scroll_up(); 131 RefreshFramebuf(0, 0, sScreenWidth, sScreenHeight); 132 } 133 134 string++; 135 } 136 137 return bufferSize; 138 } 139 140 141 // #pragma mark - 142 143 144 void 145 console_clear_screen(void) 146 { 147 if (gKernelArgs.frame_buffer.enabled) 148 return; 149 150 for (uint32 i = 0; i < sScreenWidth * sScreenHeight; i++) 151 sScreenBase[i] = sColor; 152 153 // reset cursor position as well 154 sScreenOffset = 0; 155 156 RefreshFramebuf(0, 0, sScreenWidth, sScreenHeight); 157 } 158 159 160 int32 161 console_width(void) 162 { 163 return sScreenWidth; 164 } 165 166 167 int32 168 console_height(void) 169 { 170 return sScreenHeight; 171 } 172 173 174 void 175 console_set_cursor(int32 x, int32 y) 176 { 177 if (y >= (int32)sScreenHeight) 178 y = sScreenHeight - 1; 179 else if (y < 0) 180 y = 0; 181 if (x >= (int32)sScreenWidth) 182 x = sScreenWidth - 1; 183 else if (x < 0) 184 x = 0; 185 186 sScreenOffset = x + y * sScreenWidth; 187 } 188 189 190 void 191 console_show_cursor(void) 192 { 193 // TODO: implement 194 } 195 196 197 void 198 console_hide_cursor(void) 199 { 200 // TODO: implement 201 } 202 203 204 void 205 console_set_color(int32 foreground, int32 background) 206 { 207 sColor = (background & 0xf) << 12 | (foreground & 0xf) << 8; 208 } 209 210 211 int 212 console_wait_for_key(void) 213 { 214 int key = virtio_input_wait_for_key(); 215 216 switch (key) { 217 case 71: return TEXT_CONSOLE_KEY_RETURN; 218 case 30: return TEXT_CONSOLE_KEY_BACKSPACE; 219 case 1: return TEXT_CONSOLE_KEY_ESCAPE; 220 case 94: return TEXT_CONSOLE_KEY_SPACE; 221 222 case 87: return TEXT_CONSOLE_KEY_UP; 223 case 98: return TEXT_CONSOLE_KEY_DOWN; 224 case 97: return TEXT_CONSOLE_KEY_LEFT; 225 case 99: return TEXT_CONSOLE_KEY_RIGHT; 226 case 33: return TEXT_CONSOLE_KEY_PAGE_UP; 227 case 54: return TEXT_CONSOLE_KEY_PAGE_DOWN; 228 case 32: return TEXT_CONSOLE_KEY_HOME; 229 case 53: return TEXT_CONSOLE_KEY_END; 230 231 default: 232 return TEXT_CONSOLE_NO_KEY; 233 } 234 } 235 236 237 status_t 238 console_init(void) 239 { 240 sScreenWidth = 80; 241 sScreenHeight = 25; 242 sScreenOfsX = gFramebuf.width/2 - sScreenWidth*gFixedFont.charWidth/2; 243 sScreenOfsY = gFramebuf.height/2 - sScreenHeight*gFixedFont.charHeight/2; 244 245 sScreenBase = new(std::nothrow) uint16[sScreenWidth * sScreenHeight]; 246 247 console_clear_screen(); 248 249 // enable stdio functionality 250 stdin = (FILE *)&sInput; 251 stdout = stderr = (FILE *)&sOutput; 252 253 return B_OK; 254 } 255