| // Copyright 2016 The Fuchsia Authors |
| // Copyright (c) 2009 Corey Tabaka |
| // Copyright (c) 2016 Travis Geiselbrecht |
| // |
| // Use of this source code is governed by a MIT-style |
| // license that can be found in the LICENSE file or at |
| // https://opensource.org/licenses/MIT |
| |
| #if WITH_LEGACY_PC_CONSOLE |
| |
| #include <arch/x86.h> |
| #include <lib/io.h> |
| #include <platform/console.h> |
| #include <platform/pc.h> |
| #include <stdarg.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| /* memory mapped framebuffer */ |
| #define FB (0xB8000U + KERNEL_ASPACE_BASE) |
| |
| /* CGA values */ |
| #define CURSOR_START 0x0A |
| #define CURSOR_END 0x0B |
| #define VIDEO_ADDRESS_MSB 0x0C |
| #define VIDEO_ADDRESS_LSB 0x0D |
| #define CURSOR_POS_MSB 0x0E |
| #define CURSOR_POS_LSB 0x0F |
| |
| /* curr settings */ |
| static unsigned char curr_x; |
| static unsigned char curr_y; |
| static unsigned char curr_start; |
| static unsigned char curr_end; |
| static unsigned char curr_attr = 0x7; |
| |
| /* video page buffer */ |
| #define VPAGE_SIZE 2048 |
| #define PAGE_MAX 8 |
| |
| static int active_page = 0; |
| static int visual_page = 0; |
| |
| static int curs_x[PAGE_MAX]; |
| static int curs_y[PAGE_MAX]; |
| |
| static struct { |
| int x1, y1, x2, y2; |
| } view_window = { |
| 0, 0, 79, 24}; |
| |
| void platform_init_console(void) { |
| curr_save(); |
| window(0, 0, 79, 24); |
| clear(); |
| place(0, 0); |
| } |
| |
| void set_visual_page(int page) { |
| unsigned short page_offset = page * VPAGE_SIZE; |
| visual_page = page; |
| |
| outp(CGA_INDEX_REG, VIDEO_ADDRESS_LSB); |
| outp(CGA_DATA_REG, page_offset & 0xFF); |
| outp(CGA_INDEX_REG, VIDEO_ADDRESS_MSB); |
| outp(CGA_DATA_REG, (page_offset >> 8) & 0xFF); |
| } |
| |
| void set_active_page(int page) { |
| curs_x[active_page] = curr_x; |
| curs_y[active_page] = curr_y; |
| curr_x = curs_x[page]; |
| curr_y = curs_y[page]; |
| active_page = page; |
| } |
| |
| int get_visual_page(void) { |
| return visual_page; |
| } |
| |
| int get_active_page(void) { |
| return active_page; |
| } |
| |
| void place(int x, int y) { |
| unsigned short cursor_word = x + y * 80 + active_page * VPAGE_SIZE; |
| |
| /* |
| * program CGA using index reg, then data reg |
| */ |
| outp(CGA_INDEX_REG, CURSOR_POS_LSB); |
| outp(CGA_DATA_REG, cursor_word & 0xFF); |
| outp(CGA_INDEX_REG, CURSOR_POS_MSB); |
| outp(CGA_DATA_REG, (cursor_word >> 8) & 0xFF); |
| |
| curr_x = x; |
| curr_y = y; |
| } |
| |
| void cursor(int start, int end) { |
| outp(CGA_INDEX_REG, CURSOR_START); |
| outp(CGA_DATA_REG, start); |
| outp(CGA_INDEX_REG, CURSOR_END); |
| outp(CGA_DATA_REG, end); |
| } |
| |
| void curr_save(void) { |
| #if 0 |
| /* grab some info from the bios data area (these should be defined in memmap.h */ |
| curr_attr = *((unsigned char *)FB + 159); |
| curr_x = *((unsigned char *)0x00450); |
| curr_y = *((unsigned char *)0x00451); |
| curr_end = *((unsigned char *)0x00460); |
| curr_start = *((unsigned char *)0x00461); |
| #endif |
| active_page = visual_page = 0; |
| } |
| |
| void curr_restore(void) { |
| #if 0 |
| *((unsigned char *)0x00450) = curr_x; |
| *((unsigned char *)0x00451) = curr_y; |
| #endif |
| |
| place(curr_x, curr_y); |
| cursor(curr_start, curr_end); |
| } |
| |
| void window(int x1, int y1, int x2, int y2) { |
| view_window.x1 = x1; |
| view_window.y1 = y1; |
| view_window.x2 = x2; |
| view_window.y2 = y2; |
| |
| //place(x1, y1); |
| } |
| |
| void _clear(char c, char attr, int x1, int y1, int x2, int y2) { |
| register int i, j; |
| unsigned short w = attr; |
| |
| w <<= 8; |
| w |= c; |
| for (i = x1; i <= x2; i++) { |
| for (j = y1; j <= y2; j++) { |
| *((unsigned short*)(uintptr_t)(FB + 2 * i + 160 * j + 2 * active_page * VPAGE_SIZE)) = w; |
| } |
| } |
| |
| place(x1, y1); |
| curr_y = y1; |
| curr_x = x1; |
| } |
| |
| void clear() { |
| _clear(' ', curr_attr, view_window.x1, view_window.y1, view_window.x2, |
| view_window.y2); |
| } |
| |
| void _scroll(char attr, int x1, int y1, int x2, int y2) { |
| register int x, y; |
| unsigned short xattr = attr << 8, w; |
| unsigned char* v = (unsigned char*)(uintptr_t)(FB + active_page * (2 * VPAGE_SIZE)); |
| |
| for (y = y1 + 1; y <= y2; y++) { |
| for (x = x1; x <= x2; x++) { |
| w = *((unsigned short*)(v + 2 * (y * 80 + x))); |
| *((unsigned short*)(v + 2 * ((y - 1) * 80 + x))) = w; |
| } |
| } |
| |
| for (x = x1; x <= x2; x++) { |
| *((unsigned short*)(v + 2 * ((y - 1) * 80 + x))) = xattr; |
| } |
| } |
| |
| void scroll(void) { |
| _scroll(curr_attr, view_window.x1, view_window.y1, view_window.x2, |
| view_window.y2); |
| } |
| |
| void cputc(char c) { |
| static unsigned short scan_x, x, y; |
| unsigned char* v = (unsigned char*)(uintptr_t)(FB + active_page * (2 * VPAGE_SIZE)); |
| x = curr_x; |
| y = curr_y; |
| |
| switch (c) { |
| case '\t': |
| x += 8; |
| if (x >= view_window.x2 + 1) { |
| x = view_window.x1; |
| if (y == view_window.y2) { |
| scroll(); |
| } else { |
| y++; |
| } |
| } else { |
| scan_x = 0; |
| |
| while ((scan_x + 8) < x) { |
| scan_x += 8; |
| } |
| |
| x = scan_x; |
| } |
| break; |
| |
| case '\r': |
| x = view_window.x1; |
| break; |
| |
| case '\n': |
| if (y == view_window.y2) { |
| scroll(); |
| } else { |
| y++; |
| } |
| break; |
| |
| case '\b': |
| x--; |
| break; |
| |
| default: |
| *(v + 2 * (x + y * 80)) = c; |
| x++; |
| |
| if (x >= view_window.x2 + 1) { |
| x = view_window.x1; |
| if (y == view_window.y2) { |
| scroll(); |
| } else { |
| y++; |
| } |
| } |
| } |
| |
| place(x, y); |
| } |
| |
| void cputs(char* s) { |
| char c; |
| while (*s != '\0') { |
| c = *s++; |
| cputc(c); |
| } |
| } |
| |
| void puts_xy(int x, int y, char attr, char* s) { |
| unsigned char* v = (unsigned char*)(uintptr_t)(FB + (80 * y + x) * 2 + active_page * (2 * VPAGE_SIZE)); |
| while (*s != 0) { |
| *v = *s; |
| s++; |
| v++; |
| *v = attr; |
| v++; |
| } |
| } |
| |
| void putc_xy(int x, int y, char attr, char c) { |
| unsigned char* v = (unsigned char*)(uintptr_t)(FB + (80 * y + x) * 2 + active_page * (2 * VPAGE_SIZE)); |
| *v = c; |
| v++; |
| *v = attr; |
| } |
| |
| int printf_xy(int x, int y, char attr, char* fmt, ...) { |
| char cbuf[200]; |
| va_list parms; |
| int result; |
| |
| va_start(parms, fmt); |
| result = vsnprintf(cbuf, sizeof(cbuf), fmt, parms); |
| va_end(parms); |
| |
| puts_xy(x, y, attr, cbuf); |
| |
| return result; |
| } |
| |
| #endif |