fbterm: VGA backend, enable scrolling by default
This commit is contained in:
parent
038727eb1a
commit
0f2d7334b0
@ -12,3 +12,4 @@ extern size_t xvasprintf(int (*callback)(void *, char), void * userData, const c
|
||||
|
||||
__attribute__((format(__printf__,1,2)))
|
||||
extern int dprintf(const char *fmt, ...);
|
||||
extern void console_set_output(size_t (*output)(size_t,uint8_t*));
|
||||
|
@ -10,9 +10,20 @@
|
||||
#include <kernel/printf.h>
|
||||
#include <kernel/string.h>
|
||||
#include <kernel/args.h>
|
||||
#include <kernel/mmu.h>
|
||||
|
||||
/* Whether to scroll or wrap when cursor reaches the bottom. */
|
||||
static int fbterm_scroll = 0;
|
||||
static int fbterm_scroll = 1;
|
||||
static void (*write_char)(int, int, int, uint32_t) = NULL;
|
||||
static int (*get_width)(void) = NULL;
|
||||
static int (*get_height)(void) = NULL;
|
||||
static void (*scroll_terminal)(void) = NULL;
|
||||
|
||||
static int x = 0;
|
||||
static int y = 0;
|
||||
static int term_state = 0;
|
||||
static char term_buf[1024] = {0};
|
||||
static int term_buf_c = 0;
|
||||
|
||||
/* Is this in a header somewhere? */
|
||||
extern uint8_t * lfb_vid_memory;
|
||||
@ -40,10 +51,14 @@ static inline void set_point(int x, int y, uint32_t value) {
|
||||
((uint32_t*)lfb_vid_memory)[y * (lfb_resolution_s/4) + x] = value;
|
||||
}
|
||||
|
||||
static void write_char(int x, int y, int val, uint32_t color) {
|
||||
static void fb_write_char(int _x, int _y, int val, uint32_t color) {
|
||||
if (val > 128) {
|
||||
val = 4;
|
||||
}
|
||||
|
||||
int x = 1 + _x * char_width;
|
||||
int y = _y * char_height;
|
||||
|
||||
uint16_t * c = large_font[val];
|
||||
for (uint8_t i = 0; i < char_height; ++i) {
|
||||
for (uint8_t j = 0; j < char_width; ++j) {
|
||||
@ -56,21 +71,6 @@ static void write_char(int x, int y, int val, uint32_t color) {
|
||||
}
|
||||
}
|
||||
|
||||
static void fbterm_init_framebuffer(void) {
|
||||
for (size_t y = 0; y < lfb_resolution_y; ++y) {
|
||||
for (size_t x = 0; x < lfb_resolution_x; ++x) {
|
||||
set_point(x,y,BG_COLOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* We push text in one pixel, which unfortunately means we have slightly less room,
|
||||
* but it also means the text doesn't run right into the left and right edges which
|
||||
* just looks kinda bad. */
|
||||
#define LEFT_PAD 1
|
||||
static int x = LEFT_PAD;
|
||||
static int y = 0;
|
||||
|
||||
/**
|
||||
* @brief Basic 16-color ANSI palette with Tango colors.
|
||||
*/
|
||||
@ -94,24 +94,90 @@ static uint32_t term_colors[] = {
|
||||
0xFFEEEEEC,
|
||||
};
|
||||
|
||||
static int term_state = 0;
|
||||
static char term_buf[1024] = {0};
|
||||
static int term_buf_c = 0;
|
||||
static int fb_get_width(void) {
|
||||
return (lfb_resolution_x - 1) / char_width;
|
||||
}
|
||||
|
||||
static void invert_at(int x, int y) {
|
||||
/* Disable cursor for now, as it reads from video memory which is generally slow. */
|
||||
#if 0
|
||||
for (uint8_t i = 0; i < char_height; ++i) {
|
||||
for (uint8_t j = 0; j < char_width; ++j) {
|
||||
uint32_t current = ((uint32_t*)lfb_vid_memory)[(y+i) * lfb_resolution_x + (x+j)];
|
||||
uint8_t r = (current >> 16) & 0xFF;
|
||||
uint8_t g = (current >> 8) & 0xFF;
|
||||
uint8_t b = (current) & 0xFF;
|
||||
current = 0xFF000000 | ((0xFF-r) << 16) | ((0xFF-g) << 8) | ((0xFF-b));
|
||||
((uint32_t*)lfb_vid_memory)[(y+i) * lfb_resolution_x + (x+j)] = current;
|
||||
static int fb_get_height(void) {
|
||||
return lfb_resolution_y / char_height;
|
||||
}
|
||||
|
||||
static void fb_scroll_terminal(void) {
|
||||
memmove(lfb_vid_memory, lfb_vid_memory + sizeof(uint32_t) * lfb_resolution_x * char_height, (lfb_resolution_y - char_height) * lfb_resolution_x * 4);
|
||||
memset(lfb_vid_memory + sizeof(uint32_t) * (lfb_resolution_y - char_height) * lfb_resolution_x, 0x05, char_height * lfb_resolution_x * 4);
|
||||
}
|
||||
|
||||
static void draw_square(int x, int y) {
|
||||
for (size_t _y = 0; _y < 7; ++_y) {
|
||||
for (size_t _x = 0; _x < 7; ++_x) {
|
||||
set_point(1 + x * 8 + _x, 1 + y * 8 + _y,
|
||||
0xFF00B2FF - (y * 8 + _y) * 0x200);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fbterm_draw_logo(void) {
|
||||
uint64_t logo_squares = 0x981818181818FFFFUL;
|
||||
for (size_t y = 0; y < 8; ++y) {
|
||||
for (size_t x = 0; x < 8; ++x) {
|
||||
if (logo_squares & (1 << x)) {
|
||||
draw_square(x,y);
|
||||
}
|
||||
}
|
||||
logo_squares >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
static void fbterm_init_framebuffer(void) {
|
||||
write_char = fb_write_char;
|
||||
get_width = fb_get_width;
|
||||
get_height = fb_get_height;
|
||||
scroll_terminal = fb_scroll_terminal;
|
||||
|
||||
for (size_t y = 0; y < lfb_resolution_y; ++y) {
|
||||
for (size_t x = 0; x < lfb_resolution_x; ++x) {
|
||||
set_point(x,y,BG_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
fbterm_draw_logo();
|
||||
y = 4;
|
||||
}
|
||||
|
||||
static void ega_write_char(int x, int y, int ch, uint32_t color) {
|
||||
unsigned short att = 7 << 8;
|
||||
unsigned short *where = (unsigned short*)(mmu_map_from_physical(0xB8000)) + (y * 80 + x);
|
||||
*where = (ch & 0xFF) | att;
|
||||
}
|
||||
|
||||
static int ega_get_width(void) { return 80; }
|
||||
static int ega_get_height(void) { return 25; }
|
||||
|
||||
static void ega_scroll_terminal(void) {
|
||||
memmove(mmu_map_from_physical(0xB8000), (char*)mmu_map_from_physical(0xB8000) + sizeof(unsigned short) * 80, sizeof(unsigned short) * (80 * 24));
|
||||
memset((char*)mmu_map_from_physical(0xB8000) + sizeof(unsigned short) * (80 * 24), 0x00, 80 * sizeof(unsigned short));
|
||||
}
|
||||
|
||||
static void fbterm_init_ega(void) {
|
||||
write_char = ega_write_char;
|
||||
get_width = ega_get_width;
|
||||
get_height = ega_get_height;
|
||||
scroll_terminal = ega_scroll_terminal;
|
||||
}
|
||||
|
||||
static void cursor_update(void) {
|
||||
if (x >= get_width()) {
|
||||
x = 0;
|
||||
y++;
|
||||
}
|
||||
if (y >= get_height()) {
|
||||
if (fbterm_scroll) {
|
||||
y--;
|
||||
scroll_terminal();
|
||||
} else {
|
||||
y = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void process_char(char ch) {
|
||||
@ -171,19 +237,14 @@ static void process_char(char ch) {
|
||||
}
|
||||
case 'G': {
|
||||
/* Set cursor column */
|
||||
invert_at(x,y);
|
||||
x = LEFT_PAD + (atoi(term_buf) - 1) * char_width;
|
||||
invert_at(x,y);
|
||||
x = atoi(term_buf) - 1;
|
||||
break;
|
||||
}
|
||||
case 'K': {
|
||||
if (atoi(term_buf) == 0) {
|
||||
for (int j = y; j < y + char_height; ++j) {
|
||||
for (int i = x; i < lfb_resolution_x; ++i) {
|
||||
set_point(i,j,bg_color);
|
||||
}
|
||||
for (int i = x; i < get_width(); ++i) {
|
||||
write_char(i,y,' ',bg_color);
|
||||
}
|
||||
invert_at(x,y);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -202,38 +263,25 @@ static void process_char(char ch) {
|
||||
write_char(x,y,' ',bg_color);
|
||||
switch (ch) {
|
||||
case '\n':
|
||||
x = LEFT_PAD;
|
||||
y += char_height;
|
||||
x = 0;
|
||||
y++;
|
||||
break;
|
||||
case '\r':
|
||||
x = LEFT_PAD;
|
||||
x = 0;
|
||||
break;
|
||||
case '\b':
|
||||
if (x > LEFT_PAD) {
|
||||
x -= char_width;
|
||||
if (x) {
|
||||
x--;
|
||||
write_char(x,y,' ',fg_color);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if ((unsigned int)ch > 127) return;
|
||||
write_char(x,y,ch,fg_color);
|
||||
x += char_width;
|
||||
x++;
|
||||
break;
|
||||
}
|
||||
if (x > lfb_resolution_x) {
|
||||
y += char_height;
|
||||
x = LEFT_PAD;
|
||||
}
|
||||
if (y > lfb_resolution_y - char_height) {
|
||||
if (fbterm_scroll) {
|
||||
y -= char_height;
|
||||
memmove(lfb_vid_memory, lfb_vid_memory + sizeof(uint32_t) * lfb_resolution_x * char_height, (lfb_resolution_y - char_height) * lfb_resolution_x * 4);
|
||||
memset(lfb_vid_memory + sizeof(uint32_t) * (lfb_resolution_y - char_height) * lfb_resolution_x, 0x05, char_height * lfb_resolution_x * 4);
|
||||
} else {
|
||||
y = 0;
|
||||
}
|
||||
}
|
||||
invert_at(x,y);
|
||||
cursor_update();
|
||||
}
|
||||
|
||||
static size_t (*previous_writer)(size_t,uint8_t*) = NULL;
|
||||
@ -247,40 +295,24 @@ size_t fbterm_write(size_t size, uint8_t *buffer) {
|
||||
return size;
|
||||
}
|
||||
|
||||
static void draw_square(int x, int y) {
|
||||
for (size_t _y = 0; _y < 7; ++_y) {
|
||||
for (size_t _x = 0; _x < 7; ++_x) {
|
||||
set_point(1 + x * 8 + _x, 1 + y * 8 + _y,
|
||||
0xFF00B2FF - (y * 8 + _y) * 0x200);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fbterm_draw_logo(void) {
|
||||
uint64_t logo_squares = 0x981818181818FFFFUL;
|
||||
for (size_t y = 0; y < 8; ++y) {
|
||||
for (size_t x = 0; x < 8; ++x) {
|
||||
if (logo_squares & (1 << x)) {
|
||||
draw_square(x,y);
|
||||
}
|
||||
}
|
||||
logo_squares >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void fbterm_initialize(void) {
|
||||
if (!lfb_resolution_x) return;
|
||||
|
||||
if (args_present("fbterm-scroll")) {
|
||||
fbterm_scroll = 1;
|
||||
if (args_present("no-fbterm-scroll")) {
|
||||
fbterm_scroll = 0;
|
||||
}
|
||||
|
||||
fbterm_init_framebuffer();
|
||||
fbterm_draw_logo();
|
||||
y = 66;
|
||||
if (lfb_resolution_x) {
|
||||
fbterm_init_framebuffer();
|
||||
} else {
|
||||
#ifdef __x86_64__
|
||||
fbterm_init_ega();
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
previous_writer = printf_output;
|
||||
printf_output = fbterm_write;
|
||||
console_set_output(fbterm_write);
|
||||
|
||||
dprintf("fbterm: Generic framebuffer text output enabled.\n");
|
||||
}
|
||||
|
@ -23,13 +23,14 @@ extern uint64_t arch_boot_time;
|
||||
/** Things we use for framebuffer output. */
|
||||
extern uint16_t lfb_resolution_x;
|
||||
extern size_t (*printf_output)(size_t, uint8_t *);
|
||||
extern size_t fbterm_write(size_t, uint8_t *);
|
||||
|
||||
static size_t (*console_write)(size_t, uint8_t *) = NULL;
|
||||
|
||||
static uint8_t tmp_buffer[4096] __attribute__((aligned(4096)));
|
||||
static uint8_t * buffer_start = tmp_buffer;
|
||||
|
||||
static ssize_t write_console(size_t size, uint8_t *buffer) {
|
||||
if (lfb_resolution_x) return fbterm_write(size,buffer);
|
||||
if (console_write) return console_write(size,buffer);
|
||||
|
||||
if (buffer_start + size >= tmp_buffer + sizeof(tmp_buffer)) {
|
||||
return 0; /* uh oh */
|
||||
@ -57,16 +58,19 @@ static int cb_printf(void * user, char c) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void console_set_output(size_t (*output)(size_t,uint8_t*)) {
|
||||
console_write = output;
|
||||
|
||||
if (buffer_start != tmp_buffer) {
|
||||
console_write(buffer_start - tmp_buffer, tmp_buffer);
|
||||
buffer_start = tmp_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
int dprintf(const char * fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
||||
/* Is a viable output ready? */
|
||||
if (lfb_resolution_x && buffer_start != tmp_buffer) {
|
||||
fbterm_write(buffer_start - tmp_buffer, tmp_buffer);
|
||||
buffer_start = tmp_buffer;
|
||||
}
|
||||
|
||||
/* Is this a FATAL message? */
|
||||
|
||||
/* If it's ready now but wasn't ready previously, are there
|
||||
|
Loading…
Reference in New Issue
Block a user