summaryrefslogtreecommitdiff
path: root/src/vgatext.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vgatext.c')
-rw-r--r--src/vgatext.c262
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;
+ }
+}
+