summaryrefslogtreecommitdiff
path: root/src/drivers/video/vga.c
diff options
context:
space:
mode:
authorAndreas Baumann <mail@andreasbaumann.cc>2017-06-14 20:48:16 +0200
committerAndreas Baumann <mail@andreasbaumann.cc>2017-06-14 20:48:16 +0200
commit8fb9efc08388d3a866cfdf911b07e372de24b556 (patch)
tree3afaf07e27fb37bd5a88b187d505137abdaa817b /src/drivers/video/vga.c
parent7a3b38c6462587657f20d684a833f0264de230b5 (diff)
downloadabaos-8fb9efc08388d3a866cfdf911b07e372de24b556.tar.gz
abaos-8fb9efc08388d3a866cfdf911b07e372de24b556.tar.bz2
got switch to graphical VGA mode working
Diffstat (limited to 'src/drivers/video/vga.c')
-rw-r--r--src/drivers/video/vga.c230
1 files changed, 225 insertions, 5 deletions
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 );
+ }
+ }
}
+