#include "vga.h" #include #include "string.h" #include "stdlib.h" static bool params_ok( vga_t *vga, const int x, const int y ); static int calculate_offset( vga_t *vga ); static uint8_t calculate_color_cell( vga_t *vga ); static void scroll_screen( vga_t *vga ); void vga_init( vga_t *vga ) { memset( vga, 0, sizeof( vga_t ) ); vga->res_x = VGA_DEFAULT_RES_X; vga->res_y = VGA_DEFAULT_RES_Y; vga->color = VGA_COLOR_DARK_GREY; vga->background_color = VGA_COLOR_BLACK; // set up ports port8_init( &vga->crtc_index_port, 0x3d4 ); port8_init( &vga->crtc_data_port, 0x3d5 ); // TODO: get current position from VGA hardware vga_set_cursor_from_hardware( vga ); }; void vga_clear_screen( vga_t *vga ) { volatile uint8_t *VIDEO_MEMORY = (uint8_t *)0xb8000; for( int i = 0; i < 2 * ( vga->res_x * vga->res_y ); i += 2 ) { *(VIDEO_MEMORY+i) = ' '; *(VIDEO_MEMORY+i+1) = calculate_color_cell( vga ); } vga_set_cursor( vga, 0, 0 ); } void vga_set_cursor( vga_t *vga, const int x, const int y ) { // TODO: PANIC? OUT OF BOUND ACCESS if( !params_ok( vga, x, y ) ) return; vga->cursor_x = x; vga->cursor_y = y; // TODO: have a silent mode where we don't update the cursor vga_set_cursor_on_hardware( vga ); } void vga_set_cursor_from_hardware( vga_t *vga ) { } void vga_set_cursor_on_hardware( vga_t *vga ) { uint16_t hw_cursor_pos = vga->cursor_x + vga->cursor_y * vga->res_x; port8_write( &vga->crtc_index_port, 15 ); port8_write( &vga->crtc_index_port, hw_cursor_pos & 0xff ); port8_write( &vga->crtc_index_port, 14 ); port8_write( &vga->crtc_index_port, hw_cursor_pos >> 8 ); } int vga_get_cursor_x( vga_t *vga ) { return vga->cursor_x; } int vga_get_cursor_y( vga_t *vga ) { return vga->cursor_y; } void vga_set_color( vga_t *vga, const vga_color_t color ) { vga->color = color; } void vga_set_background_color( vga_t *vga, const vga_color_t color ) { vga->background_color = color; } static int calculate_offset( vga_t *vga ) { int offset = ( vga->res_x * vga->cursor_y + vga->cursor_x ) * 2; return offset; } static void scroll_screen( vga_t *vga ) { volatile uint8_t *VIDEO_MEMORY = (uint8_t *)0xb8000; memmove( (void *)VIDEO_MEMORY, (const void *)VIDEO_MEMORY + 2 * vga->res_x, 2 * ( vga->res_y - 1 ) * vga->res_x ); for( int i = 2 * ( vga->res_x * ( vga->res_y - 1 ) ); i < 2 * ( vga->res_x * vga->res_y ); i += 2 ) { *(VIDEO_MEMORY+i) = ' '; *(VIDEO_MEMORY+i+1) = calculate_color_cell( vga ); } vga->cursor_y = vga->res_y - 1; } static uint8_t calculate_color_cell( vga_t *vga ) { uint8_t cell; cell = ( vga->background_color << 4 ) | vga->color; return cell; } static bool params_ok( vga_t *vga, const int x, const int y ) { if( x > vga->res_x || y > vga->res_y ) return false; return true; } void vga_put_char_at( vga_t *vga, const int x, const int y, const char c ) { vga_set_cursor( vga, x, y ); vga_put_char( vga, c ); } void vga_put_string_at( vga_t *vga, const int x, const int y, const char *s ) { vga_set_cursor( vga, x, y ); vga_put_string( vga, s ); } void vga_put_char( vga_t *vga, const char c ) { int offset = calculate_offset( vga ); volatile uint8_t *VIDEO_MEMORY = (uint8_t *)0xb8000; *(VIDEO_MEMORY+offset) = (uint8_t)c; *(VIDEO_MEMORY+offset+1) = calculate_color_cell( vga ); vga->cursor_x++; if( vga->cursor_x >= vga->res_x ) { vga->cursor_x = 0; vga->cursor_y++; if( vga->cursor_y >= vga->res_y ) { scroll_screen( vga ); } } } void vga_put_string( vga_t *vga, const char *s ) { for( size_t i = 0; i < strlen( s ); i++ ) { vga_put_char( vga, s[i] ); } } void vga_put_hex( vga_t *vga, const uint32_t v ) { char buf[9]; strlcpy( buf, "0x", 9 ); vga_put_string( vga, (const char *)buf ); itoa( v, (char *)buf, 16 ); vga_put_string( vga, (const char *)buf ); } void vga_put_newline( vga_t *vga ) { vga->cursor_x = 0; vga->cursor_y++; if( vga->cursor_y >= vga->res_y ) { scroll_screen( vga ); } }