#include "vgatext.h" #include #include "string.h" #include "stdlib.h" #include "kernel.h" static bool params_ok( vga_text_t *vga_text, const int x, const int y ); static int calculate_offset( vga_text_t *vga_text, const int x, const int y ); static uint8_t calculate_color_cell( vga_text_t *vga_text ); static void scroll_screen( vga_text_t *vga_text ); void vga_text_init( vga_text_t *vga_text ) { memset( vga_text, 0, sizeof( vga_text_t ) ); vga_text->res_x = VGA_TEXT_DEFAULT_RES_X; vga_text->res_y = VGA_TEXT_DEFAULT_RES_Y; vga_text->color = VGA_TEXT_COLOR_DARK_GREY; vga_text->background_color = VGA_TEXT_COLOR_BLACK; vga_text->show_mouse_cursor = false; vga_text->mouse_cursor_x = -1; vga_text->mouse_cursor_y = -1; // make sure we use the 0x3dx VGA_TEXT ports, is done // in assembly in stage 2 too port8_init( &vga_text->crtc_misc_port, 0x3d2 ); port8_write( &vga_text->crtc_misc_port, 1 ); // set up VGA_TEXT ports port8_init( &vga_text->crtc_index_port, 0x3d4 ); port8_init( &vga_text->crtc_data_port, 0x3d5 ); vga_text_set_cursor_from_hardware( vga_text ); }; void vga_text_clear_screen( vga_text_t *vga_text ) { uint8_t *VIDEO_MEMORY = (uint8_t *)0xb8000; for( int i = 0; i < 2 * ( vga_text->res_x * vga_text->res_y ); i += 2 ) { *(VIDEO_MEMORY+i) = ' '; *(VIDEO_MEMORY+i+1) = calculate_color_cell( vga_text ); } vga_text_set_cursor( vga_text, 0, 0 ); } void vga_text_set_cursor( vga_text_t *vga_text, const int x, const int y ) { if( !params_ok( vga_text, x, y ) ) { kernel_panic( "Cursor parameters out of bounds: (%d, %d), resolution is only (%d, %d)", x, y, vga_text->res_x, vga_text->res_y ); } vga_text->cursor_x = x; vga_text->cursor_y = y; // TODO: have a silent mode where we don't update the cursor vga_text_set_cursor_on_hardware( vga_text ); } void vga_text_set_cursor_from_hardware( vga_text_t *vga_text ) { uint16_t hw_cursor_pos; port8_write( &vga_text->crtc_index_port, 14 ); uint8_t data = port8_read( &(vga_text->crtc_data_port ) ); hw_cursor_pos = data << 8; port8_write( &vga_text->crtc_index_port, 15 ); data = port8_read( &(vga_text->crtc_data_port ) ); hw_cursor_pos |= data; vga_text->cursor_x = hw_cursor_pos % vga_text->res_x; vga_text->cursor_y = hw_cursor_pos / vga_text->res_x; // reset to sane values if we get funny values from the VGA_TEXT card if( vga_text->cursor_x < 0 || vga_text->cursor_x > vga_text->res_x || vga_text->cursor_y < 0 || vga_text->cursor_y > vga_text->res_y ) { vga_text->cursor_x = 0; vga_text->cursor_y = 0; } } void vga_text_set_cursor_on_hardware( vga_text_t *vga_text ) { uint16_t hw_cursor_pos = vga_text->cursor_x + vga_text->cursor_y * vga_text->res_x; port8_write( &vga_text->crtc_index_port, 15 ); port8_write( &vga_text->crtc_data_port, hw_cursor_pos & 0xff ); port8_write( &vga_text->crtc_index_port, 14 ); port8_write( &vga_text->crtc_data_port, hw_cursor_pos >> 8 ); } int vga_text_get_cursor_x( vga_text_t *vga_text ) { return vga_text->cursor_x; } int vga_text_get_cursor_y( vga_text_t *vga_text ) { return vga_text->cursor_y; } void vga_text_set_color( vga_text_t *vga_text, const vga_text_color_t color ) { vga_text->color = color; } void vga_text_set_background_color( vga_text_t *vga_text, const vga_text_color_t color ) { vga_text->background_color = color; } static int calculate_offset( vga_text_t *vga_text, const int x, const int y ) { int offset = ( vga_text->res_x * y + x ) * 2; return offset; } static void scroll_screen( vga_text_t *vga_text ) { uint8_t *VIDEO_MEMORY = (uint8_t *)0xb8000; memmove( (void *)VIDEO_MEMORY, (const void *)VIDEO_MEMORY + 2 * vga_text->res_x, 2 * ( vga_text->res_y - 1 ) * vga_text->res_x ); for( int i = 2 * ( vga_text->res_x * ( vga_text->res_y - 1 ) ); i < 2 * ( vga_text->res_x * vga_text->res_y ); i += 2 ) { *(VIDEO_MEMORY+i) = ' '; *(VIDEO_MEMORY+i+1) = calculate_color_cell( vga_text ); } vga_text->cursor_y = vga_text->res_y - 1; } static uint8_t calculate_color_cell( vga_text_t *vga_text ) { uint8_t cell; cell = ( vga_text->background_color << 4 ) | vga_text->color; return cell; } static bool params_ok( vga_text_t *vga_text, const int x, const int y ) { if( x < 0 || x > vga_text->res_x || y < 0 || y > vga_text->res_y ) { return false; } return true; } void vga_text_put_char_at( vga_text_t *vga_text, const int x, const int y, const char c ) { vga_text_set_cursor( vga_text, x, y ); vga_text_put_char( vga_text, c ); } void vga_text_put_string_at( vga_text_t *vga_text, const int x, const int y, const char *s ) { vga_text_set_cursor( vga_text, x, y ); vga_text_put_string( vga_text, s ); } void vga_text_put_char( vga_text_t *vga_text, const char c ) { int offset = calculate_offset( vga_text, vga_text->cursor_x, vga_text->cursor_y ); uint8_t *VIDEO_MEMORY = (uint8_t *)0xb8000; *(VIDEO_MEMORY+offset) = (uint8_t)c; *(VIDEO_MEMORY+offset+1) = calculate_color_cell( vga_text ); vga_text->cursor_x++; if( vga_text->cursor_x >= vga_text->res_x ) { vga_text->cursor_x = 0; vga_text->cursor_y++; if( vga_text->cursor_y >= vga_text->res_y ) { scroll_screen( vga_text ); } } vga_text_set_cursor_on_hardware( vga_text ); } void vga_text_put_string( vga_text_t *vga_text, const char *s ) { for( size_t i = 0; i < strlen( s ); i++ ) { vga_text_put_char( vga_text, s[i] ); } } void vga_text_put_newline( vga_text_t *vga_text ) { vga_text->cursor_x = 0; vga_text->cursor_y++; if( vga_text->cursor_y >= vga_text->res_y ) { scroll_screen( vga_text ); } vga_text_set_cursor_on_hardware( vga_text ); } void vga_text_set_background_color_at( vga_text_t *vga_text, const int x, const int y, vga_text_color_t color ) { int offset = calculate_offset( vga_text, x, y ); uint8_t *VIDEO_MEMORY = (uint8_t *)0xb8000; *(VIDEO_MEMORY+offset+1) = ( *(VIDEO_MEMORY+offset+1) & 0x0f ) | ( color << 4 ); } vga_text_color_t vga_text_get_background_color_at( vga_text_t *vga_text, const int x, const int y ) { int offset = calculate_offset( vga_text, x, y ); uint8_t *VIDEO_MEMORY = (uint8_t *)0xb8000; uint8_t cell = *(VIDEO_MEMORY+offset+1); return cell & 0xf0; } void vga_text_inverse_colors_at( vga_text_t *vga_text, const int x, const int y ) { int offset = calculate_offset( vga_text, x, y ); uint8_t *VIDEO_MEMORY = (uint8_t *)0xb8000; *(VIDEO_MEMORY+offset+1) = ( ( *(VIDEO_MEMORY+offset+1) & 0x0f ) << 4 ) | ( ( *(VIDEO_MEMORY+offset+1) & 0xf0 ) >> 4 ); } void vga_text_show_mouse_cursor( vga_text_t *vga_text ) { if( !vga_text->show_mouse_cursor ) { vga_text->show_mouse_cursor = true; vga_text_inverse_colors_at( vga_text, vga_text->mouse_cursor_x, vga_text->mouse_cursor_y ); } } void vga_text_move_mouse_cursor( vga_text_t *vga_text, const int x, const int y ) { if( vga_text->show_mouse_cursor ) { vga_text_inverse_colors_at( vga_text, vga_text->mouse_cursor_x, vga_text->mouse_cursor_y ); } vga_text->mouse_cursor_x = x; vga_text->mouse_cursor_y = y; if( vga_text->show_mouse_cursor ) { vga_text_inverse_colors_at( vga_text, vga_text->mouse_cursor_x, vga_text->mouse_cursor_y ); } } void vga_text_hide_mouse_cursor( vga_text_t *vga_text ) { if( vga_text->show_mouse_cursor ) { vga_text_inverse_colors_at( vga_text, vga_text->mouse_cursor_x, vga_text->mouse_cursor_y ); vga_text->show_mouse_cursor = false; } } void vga_text_save( vga_text_t *vga_text ) { uint8_t *VIDEO_MEMORY = (uint8_t *)0xA0000; memcpy( vga_text->buf, (const uint8_t *)VIDEO_MEMORY, 2*65535 ); } void vga_text_restore( vga_text_t *vga_text ) { uint8_t *VIDEO_MEMORY = (uint8_t *)0xA0000; memcpy( (void *)VIDEO_MEMORY, (const uint8_t *)vga_text->buf, 2*65535 ); }