//#define COSMOSDEBUG
using System;
using Cosmos.Core;
using Cosmos.Core.IOGroup;
namespace Cosmos.HAL.Drivers
{
///
/// VBEDriver class. Used to directly write registers values to the port.
///
public class VBEDriver
{
private static readonly VBEIOGroup IO = Core.Global.BaseIOGroups.VBE;
ManagedMemoryBlock lastbuffer;
///
/// Register index.
///
/// Avilable indexs:
///
/// - DisplayID.
/// - DisplayXResolution.
/// - DisplayYResolution.
/// - DisplayBPP.
/// - DisplayEnable.
/// - DisplayBankMode.
/// - DisplayVirtualWidth.
/// - DisplayVirtualHeight.
/// - DisplayXOffset.
/// - DisplayYOffset.
///
///
///
private enum RegisterIndex
{
DisplayID = 0x00,
DisplayXResolution,
DisplayYResolution,
DisplayBPP,
DisplayEnable,
DisplayBankMode,
DisplayVirtualWidth,
DisplayVirtualHeight,
DisplayXOffset,
DisplayYOffset
};
///
/// Enable values.
///
/// Avilable values:
///
/// - Disabled.
/// - Enabled.
/// - UseLinearFrameBuffer.
/// - NoClearMemory.
///
///
///
[Flags]
private enum EnableValues
{
Disabled = 0x00,
Enabled,
UseLinearFrameBuffer = 0x40,
NoClearMemory = 0x80,
};
///
/// Create new instance of the class.
///
/// X resolution.
/// Y resolution.
/// BPP (color depth).
public VBEDriver(ushort xres, ushort yres, ushort bpp)
{
PCIDevice videocard;
if (VBE.IsAvailable()) //VBE VESA Enabled Mulitboot Parsing
{
Global.mDebugger.SendInternal($"Creating VBE VESA driver with Mode {xres}*{yres}@{bpp}");
IO.LinearFrameBuffer = new MemoryBlock(VBE.getLfbOffset(), (uint)xres * yres * (uint)(bpp / 8));
lastbuffer = new ManagedMemoryBlock((uint)xres * yres * (uint)(bpp / 8));
}
else if (ISAModeAvailable()) //Bochs Graphics Adaptor ISA Mode
{
Global.mDebugger.SendInternal($"Creating VBE BGA driver with Mode {xres}*{yres}@{bpp}.");
IO.LinearFrameBuffer = new MemoryBlock(0xE0000000, 1920 * 1200 * 4);
lastbuffer = new ManagedMemoryBlock(1920 * 1200 * 4);
VBESet(xres, yres, bpp);
}
else if (((videocard = HAL.PCI.GetDevice(VendorID.VirtualBox, DeviceID.VBVGA)) != null) || //VirtualBox Video Adapter PCI Mode
((videocard = HAL.PCI.GetDevice(VendorID.Bochs, DeviceID.BGA)) != null)) // Bochs Graphics Adaptor PCI Mode
{
Global.mDebugger.SendInternal($"Creating VBE BGA driver with Mode {xres}*{yres}@{bpp}. Framebuffer address=" + videocard.BAR0);
IO.LinearFrameBuffer = new MemoryBlock(videocard.BAR0, 1920 * 1200 * 4);
lastbuffer = new ManagedMemoryBlock(1920 * 1200 * 4);
VBESet(xres, yres, bpp);
}
else
{
throw new Exception("No supported VBE device found.");
}
}
///
/// Write value to VBE index.
///
/// Register index.
/// Value.
private static void VBEWrite(RegisterIndex index, ushort value)
{
IO.VbeIndex.Word = (ushort) index;
IO.VbeData.Word = value;
}
private static ushort VBERead(RegisterIndex index)
{
IO.VbeIndex.Word = (ushort)index;
return IO.VbeData.Word;
}
public static bool ISAModeAvailable()
{
//This code wont work as long as Bochs uses BGA ISA, since it wont discover it in PCI
#if false
return HAL.PCI.GetDevice(VendorID.Bochs, DeviceID.BGA) != null;
#endif
return VBERead(RegisterIndex.DisplayID) == 0xB0C5;
}
///
/// Disable display.
///
public void DisableDisplay()
{
Global.mDebugger.SendInternal($"Disabling VBE display");
VBEWrite(RegisterIndex.DisplayEnable, (ushort)EnableValues.Disabled);
}
///
/// Set X resolution.
///
/// X resolution.
private void SetXResolution(ushort xres)
{
Global.mDebugger.SendInternal($"VBE Setting X resolution to {xres}");
VBEWrite(RegisterIndex.DisplayXResolution, xres);
}
///
/// Set Y resolution.
///
/// Y resolution.
private void SetYResolution(ushort yres)
{
Global.mDebugger.SendInternal($"VBE Setting Y resolution to {yres}");
VBEWrite(RegisterIndex.DisplayYResolution, yres);
}
///
/// Set BPP.
///
/// BPP (color depth).
private void SetDisplayBPP(ushort bpp)
{
Global.mDebugger.SendInternal($"VBE Setting BPP to {bpp}");
VBEWrite(RegisterIndex.DisplayBPP, bpp);
}
///
/// Enable display.
///
private void EnableDisplay(EnableValues EnableFlags)
{
//Global.mDebugger.SendInternal($"VBE Enabling display with EnableFlags (ushort){EnableFlags}");
VBEWrite(RegisterIndex.DisplayEnable, (ushort)EnableFlags);
}
///
/// Set VBE values.
///
/// X resolution.
/// Y resolution.
/// BPP (color depth).
public void VBESet(ushort xres, ushort yres, ushort bpp)
{
DisableDisplay();
SetXResolution(xres);
SetYResolution(yres);
SetDisplayBPP(bpp);
/*
* Re-enable the Display with LinearFrameBuffer and without clearing video memory of previous value
* (this permits to change Mode without losing the previous datas)
*/
EnableDisplay(EnableValues.Enabled | EnableValues.UseLinearFrameBuffer | EnableValues.NoClearMemory);
}
///
/// Set VRAM.
///
/// Index to set.
/// Value to set.
public void SetVRAM(uint index, byte value)
{
Global.mDebugger.SendInternal($"Writing to driver memory in position {index} value {value} (as byte)");
lastbuffer[index] = value;
}
///
/// Set VRAM.
///
/// Index to set.
/// Value to set.
public void SetVRAM(uint index, ushort value)
{
//Global.mDebugger.SendInternal($"Writing to driver memory in position {index} value {value} (as ushort)");
lastbuffer[index] = (byte)((value >> 8) & 0xFF);
lastbuffer[index + 1] = (byte)((value >> 0) & 0xFF);
}
///
/// Set VRAM.
///
/// Index to set.
/// Value to set.
public void SetVRAM(uint index, uint value)
{
//Global.mDebugger.SendInternal($"Writing to driver memory in position {index} value {value} (as uint)");
lastbuffer[index] = (byte)((value >> 24) & 0xFF);
lastbuffer[index + 1] = (byte)((value >> 16) & 0xFF);
lastbuffer[index + 2] = (byte)((value >> 8) & 0xFF);
lastbuffer[index + 3] = (byte)((value >> 0) & 0xFF);
}
///
/// Get VRAM.
///
/// Index to get.
/// byte value.
public uint GetVRAM(uint index)
{
int pixel = (lastbuffer[index + 3] << 24) | (lastbuffer[index + 2] << 16) | (lastbuffer[index + 1] << 8) | lastbuffer[index];
return (uint)pixel;
}
///
/// Clear VRAM.
///
/// Value of fill with.
public void ClearVRAM(uint value)
{
lastbuffer.Fill(value);
}
///
/// Clear VRAM.
///
/// A start.
/// A count.
/// A volum.
public void ClearVRAM(int aStart, int aCount, int value)
{
lastbuffer.Fill(aStart, aCount, value);
}
///
/// Copy VRAM.
///
/// A start.
/// A data.
/// A index.
/// A count.
public void CopyVRAM(int aStart, int[] aData, int aIndex, int aCount)
{
lastbuffer.Copy(aStart, aData, aIndex, aCount);
}
///
/// Swap back buffer to video memory
///
public void Swap()
{
IO.LinearFrameBuffer.Copy(lastbuffer);
}
}
}