diff options
Diffstat (limited to 'src/vgatext.c')
-rw-r--r-- | src/vgatext.c | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/src/vgatext.c b/src/vgatext.c new file mode 100644 index 0000000..cbee587 --- /dev/null +++ b/src/vgatext.c @@ -0,0 +1,262 @@ +#include "vgatext.h" + +#include <stdbool.h> + +#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 ) +{ + volatile 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 ) +{ + volatile 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 > vga_text->res_x || 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 ); + + volatile 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 ); + + volatile 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 ); + + volatile 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 ); + + volatile 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; + } +} + |