using System; using Cosmos.Core; namespace Cosmos.HAL.Drivers.PCI.Video { public class VMWareSVGAII { public enum Register : ushort { ID = 0, Enable = 1, Width = 2, Height = 3, MaxWidth = 4, MaxHeight = 5, Depth = 6, BitsPerPixel = 7, PseudoColor = 8, RedMask = 9, GreenMask = 10, BlueMask = 11, BytesPerLine = 12, FrameBufferStart = 13, FrameBufferOffset = 14, VRamSize = 15, FrameBufferSize = 16, Capabilities = 17, MemStart = 18, MemSize = 19, ConfigDone = 20, Sync = 21, Busy = 22, GuestID = 23, CursorID = 24, CursorX = 25, CursorY = 26, CursorOn = 27, HostBitsPerPixel = 28, ScratchSize = 29, MemRegs = 30, NumDisplays = 31, PitchLock = 32, /// /// Indicates maximum size of FIFO Registers. /// FifoNumRegisters = 293 } private enum ID : uint { Magic = 0x900000, V0 = Magic << 8, V1 = (Magic << 8) | 1, V2 = (Magic << 8) | 2, Invalid = 0xFFFFFFFF } public enum FIFO : uint { // values are multiplied by 4 to access the array by byte index Min = 0, Max = 4, NextCmd = 8, Stop = 12 } private enum FIFOCommand { Update = 1, RECT_FILL = 2, RECT_COPY = 3, DEFINE_BITMAP = 4, DEFINE_BITMAP_SCANLINE = 5, DEFINE_PIXMAP = 6, DEFINE_PIXMAP_SCANLINE = 7, RECT_BITMAP_FILL = 8, RECT_PIXMAP_FILL = 9, RECT_BITMAP_COPY = 10, RECT_PIXMAP_COPY = 11, FREE_OBJECT = 12, RECT_ROP_FILL = 13, RECT_ROP_COPY = 14, RECT_ROP_BITMAP_FILL = 15, RECT_ROP_PIXMAP_FILL = 16, RECT_ROP_BITMAP_COPY = 17, RECT_ROP_PIXMAP_COPY = 18, DEFINE_CURSOR = 19, DISPLAY_CURSOR = 20, MOVE_CURSOR = 21, DEFINE_ALPHA_CURSOR = 22 } private enum IOPortOffset : byte { Index = 0, Value = 1, Bios = 2, IRQ = 3 } [Flags] private enum Capability { None = 0, RectFill = 1, RectCopy = 2, RectPatFill = 4, LecacyOffscreen = 8, RasterOp = 16, Cursor = 32, CursorByPass = 64, CursorByPass2 = 128, EigthBitEmulation = 256, AlphaCursor = 512, Glyph = 1024, GlyphClipping = 0x00000800, Offscreen1 = 0x00001000, AlphaBlend = 0x00002000, ThreeD = 0x00004000, ExtendedFifo = 0x00008000, MultiMon = 0x00010000, PitchLock = 0x00020000, IrqMask = 0x00040000, DisplayTopology = 0x00080000, Gmr = 0x00100000, Traces = 0x00200000, Gmr2 = 0x00400000, ScreenObject2 = 0x00800000 } private IOPort IndexPort; private IOPort ValuePort; private IOPort BiosPort; private IOPort IRQPort; private MemoryBlock Video_Memory; private MemoryBlock FIFO_Memory; private PCIDevice device; private uint height; private uint width; private uint depth; private uint capabilities; public VMWareSVGAII() { device = (HAL.PCI.GetDevice(HAL.VendorID.VMWare, HAL.DeviceID.SVGAIIAdapter)); device.EnableMemory(true); uint basePort = device.BaseAddressBar[0].BaseAddress; IndexPort = new IOPort((ushort)(basePort + (uint)IOPortOffset.Index)); ValuePort = new IOPort((ushort)(basePort + (uint)IOPortOffset.Value)); BiosPort = new IOPort((ushort)(basePort + (uint)IOPortOffset.Bios)); IRQPort = new IOPort((ushort)(basePort + (uint)IOPortOffset.IRQ)); WriteRegister(Register.ID, (uint)ID.V2); if (ReadRegister(Register.ID) != (uint)ID.V2) return; Video_Memory = new MemoryBlock(ReadRegister(Register.FrameBufferStart), ReadRegister(Register.VRamSize)); capabilities = ReadRegister(Register.Capabilities); InitializeFIFO(); } protected void InitializeFIFO() { FIFO_Memory = new MemoryBlock(ReadRegister(Register.MemStart), ReadRegister(Register.MemSize)); FIFO_Memory[(uint)FIFO.Min] = (uint)Register.FifoNumRegisters * sizeof(uint); FIFO_Memory[(uint)FIFO.Max] = FIFO_Memory.Size; FIFO_Memory[(uint)FIFO.NextCmd] = FIFO_Memory[(uint)FIFO.Min]; FIFO_Memory[(uint)FIFO.Stop] = FIFO_Memory[(uint)FIFO.Min]; WriteRegister(Register.ConfigDone, 1); } public void SetMode(uint width, uint height, uint depth = 32) { // Depth is color depth in bytes. this.depth = (depth / 8); this.width = width; this.height = height; WriteRegister(Register.Width, width); WriteRegister(Register.Height, height); WriteRegister(Register.BitsPerPixel, depth); WriteRegister(Register.Enable, 1); InitializeFIFO(); } protected void WriteRegister(Register register, uint value) { IndexPort.DWord = (uint)register; ValuePort.DWord = value; } protected uint ReadRegister(Register register) { IndexPort.DWord = (uint)register; return ValuePort.DWord; } protected uint GetFIFO(FIFO cmd) { return FIFO_Memory[(uint)cmd]; } protected uint SetFIFO(FIFO cmd, uint value) { return FIFO_Memory[(uint)cmd] = value; } protected void WaitForFifo() { WriteRegister(Register.Sync, 1); while (ReadRegister(Register.Busy) != 0) { } } protected void WriteToFifo(uint value) { if (((GetFIFO(FIFO.NextCmd) == GetFIFO(FIFO.Max) - 4) && GetFIFO(FIFO.Stop) == GetFIFO(FIFO.Min)) || (GetFIFO(FIFO.NextCmd) + 4 == GetFIFO(FIFO.Stop))) WaitForFifo(); SetFIFO((FIFO)GetFIFO(FIFO.NextCmd), value); SetFIFO(FIFO.NextCmd, GetFIFO(FIFO.NextCmd) + 4); if (GetFIFO(FIFO.NextCmd) == GetFIFO(FIFO.Max)) SetFIFO(FIFO.NextCmd, GetFIFO(FIFO.Min)); } public void Update(uint x, uint y, uint width, uint height) { WriteToFifo((uint)FIFOCommand.Update); WriteToFifo(x); WriteToFifo(y); WriteToFifo(width); WriteToFifo(height); WaitForFifo(); } public void SetPixel(uint x, uint y,uint color) { Video_Memory[((y * width + x) * depth)] = color; } public uint GetPixel(uint x, uint y) { return Video_Memory[((y * width + x) * depth)]; } public void Clear(uint color) { Fill(0, 0, width, height, color); } public void Copy(uint x, uint y, uint newX, uint newY, uint width, uint height) { if ((capabilities & (uint)Capability.RectCopy) != 0) { WriteToFifo((uint)FIFOCommand.RECT_COPY); WriteToFifo(x); WriteToFifo(y); WriteToFifo(newX); WriteToFifo(newY); WriteToFifo(width); WriteToFifo(height); WaitForFifo(); } else throw new NotImplementedException("VMWareSVGAII Copy()"); } public void Fill(uint x, uint y, uint width, uint height, uint color) { if ((capabilities & (uint)Capability.RectFill) != 0) { WriteToFifo((uint)FIFOCommand.RECT_FILL); WriteToFifo(color); WriteToFifo(x); WriteToFifo(y); WriteToFifo(width); WriteToFifo(height); WaitForFifo(); } else { if ((capabilities & (uint)Capability.RectCopy) != 0) { // fill first line and copy it to all other uint xTarget = (x + width); uint yTarget = (y + height); for (uint xTmp = x; xTmp < xTarget; xTmp++) { SetPixel(xTmp, y, color); } // refresh first line for copy process Update(x, y, width, 1); for (uint yTmp = y + 1; yTmp < yTarget; yTmp++) { Copy(x, y, x, yTmp, width, 1); } } else { uint xTarget = (x + width); uint yTarget = (y + height); for (uint xTmp = x; xTmp < xTarget; xTmp++) { for (uint yTmp = y; yTmp < yTarget; yTmp++) { SetPixel(xTmp, yTmp, color); } } Update(x, y, width, height); } } } public void DefineCursor() { WaitForFifo(); WriteToFifo((uint)FIFOCommand.DEFINE_CURSOR); WriteToFifo(1); WriteToFifo(0); WriteToFifo(0); WriteToFifo(2); WriteToFifo(2); WriteToFifo(1); WriteToFifo(1); for (int i = 0; i < 4; i++) WriteToFifo(0); for (int i = 0; i < 4; i++) WriteToFifo(0xFFFFFF); WaitForFifo(); } public void SetCursor(bool visible, uint x, uint y) { WriteRegister(Register.CursorID, 1); if (visible) { WaitForFifo(); WriteToFifo((uint)FIFOCommand.MOVE_CURSOR); WriteToFifo(x); WriteToFifo(y); } WriteRegister(Register.CursorOn, (uint)(visible ? 1 : 0)); } } }