1// Copyright 2016 The Fuchsia Authors 2// Copyright (c) 2009 Corey Tabaka 3// Copyright (c) 2016 Travis Geiselbrecht 4// 5// Use of this source code is governed by a MIT-style 6// license that can be found in the LICENSE file or at 7// https://opensource.org/licenses/MIT 8 9#if WITH_LEGACY_PC_CONSOLE 10 11#include <arch/x86.h> 12#include <lib/io.h> 13#include <platform/console.h> 14#include <platform/pc.h> 15#include <stdarg.h> 16#include <stdio.h> 17#include <stdlib.h> 18#include <string.h> 19 20/* memory mapped framebuffer */ 21#define FB (0xB8000U + KERNEL_ASPACE_BASE) 22 23/* CGA values */ 24#define CURSOR_START 0x0A 25#define CURSOR_END 0x0B 26#define VIDEO_ADDRESS_MSB 0x0C 27#define VIDEO_ADDRESS_LSB 0x0D 28#define CURSOR_POS_MSB 0x0E 29#define CURSOR_POS_LSB 0x0F 30 31/* curr settings */ 32static unsigned char curr_x; 33static unsigned char curr_y; 34static unsigned char curr_start; 35static unsigned char curr_end; 36static unsigned char curr_attr = 0x7; 37 38/* video page buffer */ 39#define VPAGE_SIZE 2048 40#define PAGE_MAX 8 41 42static int active_page = 0; 43static int visual_page = 0; 44 45static int curs_x[PAGE_MAX]; 46static int curs_y[PAGE_MAX]; 47 48static struct { 49 int x1, y1, x2, y2; 50} view_window = { 51 0, 0, 79, 24}; 52 53void platform_init_console(void) { 54 curr_save(); 55 window(0, 0, 79, 24); 56 clear(); 57 place(0, 0); 58} 59 60void set_visual_page(int page) { 61 unsigned short page_offset = page * VPAGE_SIZE; 62 visual_page = page; 63 64 outp(CGA_INDEX_REG, VIDEO_ADDRESS_LSB); 65 outp(CGA_DATA_REG, page_offset & 0xFF); 66 outp(CGA_INDEX_REG, VIDEO_ADDRESS_MSB); 67 outp(CGA_DATA_REG, (page_offset >> 8) & 0xFF); 68} 69 70void set_active_page(int page) { 71 curs_x[active_page] = curr_x; 72 curs_y[active_page] = curr_y; 73 curr_x = curs_x[page]; 74 curr_y = curs_y[page]; 75 active_page = page; 76} 77 78int get_visual_page(void) { 79 return visual_page; 80} 81 82int get_active_page(void) { 83 return active_page; 84} 85 86void place(int x, int y) { 87 unsigned short cursor_word = x + y * 80 + active_page * VPAGE_SIZE; 88 89 /* 90 * program CGA using index reg, then data reg 91 */ 92 outp(CGA_INDEX_REG, CURSOR_POS_LSB); 93 outp(CGA_DATA_REG, cursor_word & 0xFF); 94 outp(CGA_INDEX_REG, CURSOR_POS_MSB); 95 outp(CGA_DATA_REG, (cursor_word >> 8) & 0xFF); 96 97 curr_x = x; 98 curr_y = y; 99} 100 101void cursor(int start, int end) { 102 outp(CGA_INDEX_REG, CURSOR_START); 103 outp(CGA_DATA_REG, start); 104 outp(CGA_INDEX_REG, CURSOR_END); 105 outp(CGA_DATA_REG, end); 106} 107 108void curr_save(void) { 109#if 0 110 /* grab some info from the bios data area (these should be defined in memmap.h */ 111 curr_attr = *((unsigned char *)FB + 159); 112 curr_x = *((unsigned char *)0x00450); 113 curr_y = *((unsigned char *)0x00451); 114 curr_end = *((unsigned char *)0x00460); 115 curr_start = *((unsigned char *)0x00461); 116#endif 117 active_page = visual_page = 0; 118} 119 120void curr_restore(void) { 121#if 0 122 *((unsigned char *)0x00450) = curr_x; 123 *((unsigned char *)0x00451) = curr_y; 124#endif 125 126 place(curr_x, curr_y); 127 cursor(curr_start, curr_end); 128} 129 130void window(int x1, int y1, int x2, int y2) { 131 view_window.x1 = x1; 132 view_window.y1 = y1; 133 view_window.x2 = x2; 134 view_window.y2 = y2; 135 136 //place(x1, y1); 137} 138 139void _clear(char c, char attr, int x1, int y1, int x2, int y2) { 140 register int i, j; 141 unsigned short w = attr; 142 143 w <<= 8; 144 w |= c; 145 for (i = x1; i <= x2; i++) { 146 for (j = y1; j <= y2; j++) { 147 *((unsigned short*)(uintptr_t)(FB + 2 * i + 160 * j + 2 * active_page * VPAGE_SIZE)) = w; 148 } 149 } 150 151 place(x1, y1); 152 curr_y = y1; 153 curr_x = x1; 154} 155 156void clear() { 157 _clear(' ', curr_attr, view_window.x1, view_window.y1, view_window.x2, 158 view_window.y2); 159} 160 161void _scroll(char attr, int x1, int y1, int x2, int y2) { 162 register int x, y; 163 unsigned short xattr = attr << 8, w; 164 unsigned char* v = (unsigned char*)(uintptr_t)(FB + active_page * (2 * VPAGE_SIZE)); 165 166 for (y = y1 + 1; y <= y2; y++) { 167 for (x = x1; x <= x2; x++) { 168 w = *((unsigned short*)(v + 2 * (y * 80 + x))); 169 *((unsigned short*)(v + 2 * ((y - 1) * 80 + x))) = w; 170 } 171 } 172 173 for (x = x1; x <= x2; x++) { 174 *((unsigned short*)(v + 2 * ((y - 1) * 80 + x))) = xattr; 175 } 176} 177 178void scroll(void) { 179 _scroll(curr_attr, view_window.x1, view_window.y1, view_window.x2, 180 view_window.y2); 181} 182 183void cputc(char c) { 184 static unsigned short scan_x, x, y; 185 unsigned char* v = (unsigned char*)(uintptr_t)(FB + active_page * (2 * VPAGE_SIZE)); 186 x = curr_x; 187 y = curr_y; 188 189 switch (c) { 190 case '\t': 191 x += 8; 192 if (x >= view_window.x2 + 1) { 193 x = view_window.x1; 194 if (y == view_window.y2) { 195 scroll(); 196 } else { 197 y++; 198 } 199 } else { 200 scan_x = 0; 201 202 while ((scan_x + 8) < x) { 203 scan_x += 8; 204 } 205 206 x = scan_x; 207 } 208 break; 209 210 case '\r': 211 x = view_window.x1; 212 break; 213 214 case '\n': 215 if (y == view_window.y2) { 216 scroll(); 217 } else { 218 y++; 219 } 220 break; 221 222 case '\b': 223 x--; 224 break; 225 226 default: 227 *(v + 2 * (x + y * 80)) = c; 228 x++; 229 230 if (x >= view_window.x2 + 1) { 231 x = view_window.x1; 232 if (y == view_window.y2) { 233 scroll(); 234 } else { 235 y++; 236 } 237 } 238 } 239 240 place(x, y); 241} 242 243void cputs(char* s) { 244 char c; 245 while (*s != '\0') { 246 c = *s++; 247 cputc(c); 248 } 249} 250 251void puts_xy(int x, int y, char attr, char* s) { 252 unsigned char* v = (unsigned char*)(uintptr_t)(FB + (80 * y + x) * 2 + active_page * (2 * VPAGE_SIZE)); 253 while (*s != 0) { 254 *v = *s; 255 s++; 256 v++; 257 *v = attr; 258 v++; 259 } 260} 261 262void putc_xy(int x, int y, char attr, char c) { 263 unsigned char* v = (unsigned char*)(uintptr_t)(FB + (80 * y + x) * 2 + active_page * (2 * VPAGE_SIZE)); 264 *v = c; 265 v++; 266 *v = attr; 267} 268 269int printf_xy(int x, int y, char attr, char* fmt, ...) { 270 char cbuf[200]; 271 va_list parms; 272 int result; 273 274 va_start(parms, fmt); 275 result = vsnprintf(cbuf, sizeof(cbuf), fmt, parms); 276 va_end(parms); 277 278 puts_xy(x, y, attr, cbuf); 279 280 return result; 281} 282 283#endif 284