From 8fb9efc08388d3a866cfdf911b07e372de24b556 Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Wed, 14 Jun 2017 20:48:16 +0200 Subject: got switch to graphical VGA mode working --- src/drivers/video/vga.c | 230 ++++++++++++++++++++++++++++++++++++++++++++++-- src/drivers/video/vga.h | 40 ++++++++- 2 files changed, 263 insertions(+), 7 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/video/vga.c b/src/drivers/video/vga.c index 0462984..75a47f4 100644 --- a/src/drivers/video/vga.c +++ b/src/drivers/video/vga.c @@ -2,6 +2,8 @@ #include "stdio.h" +#include "kernel.h" + #undef DEBUG static vga_vtable_t vga_vtable = { @@ -17,6 +19,18 @@ void vga_init( vga_t *vga, void *context ) { memset( vga, 0, sizeof( vga_t ) ); + port8_init( &vga->misc_port, 0x3C2 ); + port8_init( &vga->crtc_index_port, 0x3D4 ); + port8_init( &vga->crtc_data_port, 0x3D5 ); + port8_init( &vga->sequencer_index_port, 0x3C4 ); + port8_init( &vga->sequencer_data_port, 0x3C5 ); + port8_init( &vga->graphics_controller_index_port, 0x3CE ); + port8_init( &vga->graphics_controller_data_port, 0x3CF ); + port8_init( &vga->attribute_controller_index_port, 0x3C0 ); + port8_init( &vga->attribute_controller_read_port, 0x3C1 ); + port8_init( &vga->attribute_controller_write_port, 0x3C0 ); + port8_init( &vga->attribute_controller_reset_port, 0x3DA ); + vga->context = context; vga->base.vtable = &vga_vtable.base; @@ -25,15 +39,11 @@ void vga_init( vga_t *vga, void *context ) void vga_activate( void *obj ) { puts( "Activating driver for VGA video card.." ); - -// vga_t *vga = obj; } void vga_deactivate( void *obj ) { puts( "Dectivating driver for VGA video card.." ); - -// vga_t *vga = obj; } void vga_deinit( void *obj ) @@ -43,5 +53,215 @@ void vga_deinit( void *obj ) void vga_print_info( void *obj ) { - puts( "VGA video driver" ); + puts( "Generic VGA video driver" ); +} + +static void write_registers( vga_t *vga, uint8_t *regs ) +{ + // misc + port8_write( &vga->misc_port, *( regs++ ) ); + + // seq (5) + for( uint8_t i = 0; i < 5; i++ ) { + port8_write( &vga->sequencer_index_port, i ); + port8_write( &vga->sequencer_data_port, *( regs++ ) ); + } + + // unlock CRTC register (and make sure mode data doesn't lock it again by accident) + port8_write( &vga->crtc_index_port, 0x03 ); + port8_write( &vga->crtc_data_port, port8_read( &vga->crtc_data_port ) | 0x80 ); + port8_write( &vga->crtc_index_port, 0x11 ); + port8_write( &vga->crtc_data_port, port8_read( &vga->crtc_data_port ) & ~0x80 ); + regs[0x3] |= 0x80; + regs[0x11] &= ~0x80; + + // crtc (25) + for( uint8_t i = 0; i < 25; i++ ) { + port8_write( &vga->crtc_index_port, i ); + port8_write( &vga->crtc_data_port, *( regs++ ) ); + } + + // gc (9) + for( uint8_t i = 0; i < 9; i++ ) { + port8_write( &vga->graphics_controller_index_port, i ); + port8_write( &vga->graphics_controller_data_port, *( regs++ ) ); + } + + // ac (21) + for( uint8_t i = 0; i < 21; i++ ) { + (void)port8_read( &vga->attribute_controller_reset_port ); + port8_write( &vga->attribute_controller_index_port, i ); + port8_write( &vga->attribute_controller_write_port, *( regs++ ) ); + } + + // lock 16-color palette and unblank display + (void)port8_read( &vga->attribute_controller_reset_port ); + port8_write( &vga->attribute_controller_index_port, 0x20 ); +} + +vga_mode_t vga_make_mode( const int x, const int y, const int color_depth ) +{ + vga_mode_t mode; + + mode.x = x; + mode.y = y; + mode.color_depth = color_depth; + + return mode; +} + + +static vga_mode_t modes[] = { + { 320, 200, 8, + // from http://files.osdev.org/mirrors/geezer/osd/graphics/modes.c + { + /* MISC */ + 0x63, + /* SEQ */ + 0x03, 0x01, 0x0F, 0x00, 0x0E, + /* CRTC */ + 0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F, + 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9C, 0x0E, 0x8F, 0x28, 0x40, 0x96, 0xB9, 0xA3, + 0xFF, + /* GC */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + /* AC */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00 + } + } +}; + +bool vga_supports_mode( const vga_mode_t mode ) +{ + for( int i = 0; modes[i].x != 0; i++ ) { + if( mode.x == modes[i].x && + mode.y == modes[i].y && + mode.color_depth == modes[i].color_depth ) { + return true; + } + } + + return false; +} + +static int get_matching_mode_idx( const vga_mode_t mode ) +{ + for( int i = 0; modes[i].x != 0; i++ ) { + if( mode.x == modes[i].x && + mode.y == modes[i].y && + mode.color_depth == modes[i].color_depth ) { + return i; + } + } + + return -1; +} + +bool vga_set_mode( vga_t *vga, const vga_mode_t mode ) +{ + // do not allow unknown timings! + if( !vga_supports_mode( mode ) ) { + return false; + } + + vga_mode_t matching_mode = modes[get_matching_mode_idx( mode )]; + + write_registers( vga, matching_mode.regs ); + + vga->mode = mode; + + return true; +} + + +vga_color_t vga_make_RGB( int R, int G, int B ) +{ + vga_color_t c; + + c.R = R; + c.G = G; + c.B = B; + + return c; +} + +static uint8_t *get_frame_buffer_segment( vga_t *vga ) +{ + port8_write( &vga->graphics_controller_index_port, 0x06 ); + uint8_t segment_no = ( port8_read( &vga->graphics_controller_data_port ) >> 2 ) & 0x03; + uint8_t *segment; + + switch( segment_no ) { + case 0: // A0000h - BFFFFh, 128k + segment = (uint8_t *)0xA0000; + break; + + case 1: // A0000h - AFFFFh, 64k + segment = (uint8_t *)0xA0000; + break; + + case 2: // B0000h - B7FFFh, 32k + segment = (uint8_t *)0xB0000; + break; + + case 3: // B8000h - BFFFFh, 32k + segment = (uint8_t *)0xB8000; + break; + } + +#ifdef DEBUG + printf( "segment: %d 0x%X\n", segment_no, segment ); +#endif + + return segment; +} + +static uint8_t get_color_index( const vga_color_t c ) +{ + // TODO: for now white and black, standard VGA palette entries? + if( c.R == 0x00 && c.G == 0x00 && c.B == 0x00 ) return 0x00; + if( c.R == 0x00 && c.G == 0x00 && c.B == 0xA8 ) return 0x01; + if( c.R == 0xFF && c.G == 0xFF && c.B == 0xFF ) return 0x3F; + + return 0x00; +} + +static bool params_ok( vga_t *vga, const int x, const int y ) +{ + if( x < 0 || x > vga->mode.x || y < 0 || y > vga->mode.y ) { + return false; + } + + return true; +} + +void vga_set_pixel( vga_t *vga, const int x, const int y, const vga_color_t color ) +{ + if( !params_ok( vga, x, y ) ) { + kernel_panic( "Pixel coordinates are out of bounds: (%d, %d), resolution is only (%d, %d)", + x, y, vga->mode.x, vga->mode.y ); + } + + uint8_t color_idx = get_color_index( color ); + + uint8_t *segment = get_frame_buffer_segment( vga ); + + uint8_t *addr = segment + vga->mode.x * y + x; + +// printf( "%d %d 0x%X, 0x%X 0x%X\n", x, y, segment, addr, color_idx ); + *addr = color_idx; +} + +void vga_draw_rectangle( vga_t *vga, const int x, const int y, const int w, const int h, const vga_color_t color ) +{ + for( int yy = y; yy < y + h; yy++ ) { + for( int xx = x; xx < x + w; xx++ ) { + vga_set_pixel( vga, xx, yy, color ); + } + } } + diff --git a/src/drivers/video/vga.h b/src/drivers/video/vga.h index 9b7f5c3..7c710c3 100644 --- a/src/drivers/video/vga.h +++ b/src/drivers/video/vga.h @@ -1,6 +1,8 @@ #ifndef VGA_H #define VGA_H +#include + #include "string.h" #include "interrupts.h" @@ -8,11 +10,30 @@ #include "driver.h" +#define NOF_MODE_REGS 66 + +typedef struct { + int x; + int y; + int color_depth; + uint8_t regs[NOF_MODE_REGS]; +} vga_mode_t; + typedef struct { driver_t base; interrupt_t *interrupts; - port8_t command_port; - port8_t data_port; + port8_t misc_port; + port8_t crtc_index_port; + port8_t crtc_data_port; + port8_t sequencer_index_port; + port8_t sequencer_data_port; + port8_t graphics_controller_index_port; + port8_t graphics_controller_data_port; + port8_t attribute_controller_index_port; + port8_t attribute_controller_read_port; + port8_t attribute_controller_write_port; + port8_t attribute_controller_reset_port; + vga_mode_t mode; void *context; } vga_t; @@ -26,4 +47,19 @@ void vga_deactivate( void *obj ); void vga_deinit( void *obj ); void vga_print_info( void *obj ); +vga_mode_t vga_make_mode( const int x, const int y, const int color_depth ); +bool vga_set_mode( vga_t *vga, const vga_mode_t mode ); +bool vga_supports_mode( const vga_mode_t mode ); + +typedef struct { + int R; + int G; + int B; +} vga_color_t; + +vga_color_t vga_make_RGB( int R, int G, int B ); + +void vga_set_pixel( vga_t *vga, const int x, const int y, const vga_color_t color ); +void vga_draw_rectangle( vga_t *vga, const int x, const int y, const int w, const int h, const vga_color_t color ); + #endif // VGA_H -- cgit v1.2.3-54-g00ecf