VGA programming problems
Posted: Tue Sep 15, 2020 3:18 am
Hello, I'm currently trying to write a simple VGA display driver for my OS, and I appear to be having some problems whenever I write to the CRT controller registers (It causes the emulator to reboot.) I don't quite know what's going on, as it looks like I'm writing the correct data to the ports, so I'm very confused. Is there some kind of initialization process for VGA that I wasn't made aware of? Also, here's the code I'm using for my driver.
Any help regarding this would be much appreciated! Thanks!
Code: Select all
#include "vga.h"
#include "../kernel/port.h"
//This code was adapted from a tutorial by Create Your Own Operating System on YouTube (https://www.youtube.com/watch?v=N68cYNWZgy8&ab_channel=WriteyourownOperatingSystem)
uint16_t miscPort;
uint16_t crtcIndexPort;
uint16_t crtcDataPort;
uint16_t sequencerIndexPort;
uint16_t sequencerDataPort;
uint16_t graphicsControllerIndexPort;
uint16_t graphicsControllerDataPort;
uint16_t attributeControllerIndexPort;
uint16_t attributeControllerReadPort;
uint16_t attributeControllerWritePort;
uint16_t attributeControllerResetPort;
bool vgad_supports_mode(uint32_t width, uint32_t height, uint32_t colordepth){
//Just implment 320 x 200 x 8 for now
return width == 320 && height == 200 && colordepth == 8;
}
//TODO make this more advanced
bool vgad_set_mode(uint32_t width, uint32_t height, uint32_t colordepth){
if (!vgad_supports_mode(width, height, colordepth)){
return false;
}
uint8_t g_320x200x256[] =
{
/* 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
};
vgad_write_registers(g_320x200x256);
return true;
}
void vgad_write_registers(uint8_t *registers){
p_write8(miscPort, *(registers++));
for (uint8_t i = 0; i < 5; i++){
p_write8(sequencerIndexPort, i);
p_write8(sequencerDataPort, *(registers++));
}
//Problems here
p_write8(crtcIndexPort, 0x03);
p_write8(crtcDataPort, p_read8(crtcDataPort) | 0x80);
p_write8(crtcIndexPort, 0x11);
p_write8(crtcDataPort, p_read8(crtcDataPort) & ~0x80);
registers[0x03] = registers[0x03] | 0x80;
registers[0x11] = registers[0x11] & ~0x80;
for (uint8_t i = 0; i < 25; i++){
p_write8(crtcIndexPort, i);
p_write8(crtcDataPort, *(registers++));
}
for (uint8_t i = 0; i < 9; i++){
p_write8(graphicsControllerIndexPort, i);
p_write8(graphicsControllerDataPort, *(registers++));
}
for (uint8_t i = 0; i < 21; i++){
p_read8(attributeControllerResetPort);
p_write8(attributeControllerIndexPort, i);
p_write8(attributeControllerWritePort, *(registers++));
}
p_read8(attributeControllerResetPort);
p_write8(attributeControllerIndexPort, 0x20);
}
uint8_t* vgad_get_framebuffer_segment(){
p_write8(graphicsControllerIndexPort, 0x06);
uint8_t segmentNumber = ((p_read8(graphicsControllerDataPort) >> 2) & 0x03);
switch (segmentNumber)
{
default:
case 0:
return (uint8_t*)0x0000;
case 1:
return (uint8_t*)0xA000;
case 2:
return (uint8_t*)0xB000;
case 3:
return (uint8_t*)0xB800;
}
}
void vgad_put_pixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b){
vgad_put_pixel_index(x, y, vgad_get_color_index(r, g, b));
}
void vgad_put_pixel_index(uint32_t x, uint32_t y, uint8_t colorIndex){
uint8_t *pixelAddress = vgad_get_framebuffer_segment() + 320 * y + x;
*pixelAddress = colorIndex;
}
uint8_t vgad_get_color_index(uint8_t r, uint8_t g, uint8_t b){
//This is stupid, don't do this
if (r == 0x00 && g == 0x00 && b == 0xA8){
return 0x01;
}
return 0x0;
}
void vgad_init(){
miscPort = 0x3C2;
crtcIndexPort = 0x3D4;
crtcDataPort = 0x3D5;
sequencerIndexPort = 0x3C4;
sequencerDataPort = 0x3C5;
graphicsControllerIndexPort = 0x3CE;
graphicsControllerDataPort = 0x3CF;
attributeControllerIndexPort = 0x3C0;
attributeControllerReadPort = 0x3C1;
attributeControllerWritePort = 0x3C0;
attributeControllerResetPort = 0x3DA;
}