diff --git a/kernel/Makefile b/kernel/Makefile
index e6182b23..a6a528ec 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -75,7 +75,6 @@ $(CPUOBJS) \
addralloc.o \
alarm.o \
ata.o \
-bga.o \
calltrace.o \
clock.o \
com.o \
@@ -85,7 +84,6 @@ $(CPU)/kthread.o \
crc32.o \
debugger.o \
descriptor.o \
-dispmsg.o \
dtable.o \
elf.o \
fcache.o \
@@ -96,6 +94,7 @@ fs/null.o \
fs/user.o \
fs/util.o \
fs/zero.o \
+gpu/bga/bga.o \
identity.o \
initrd.o \
inode.o \
diff --git a/kernel/bga.cpp b/kernel/bga.cpp
deleted file mode 100644
index 98b2989e..00000000
--- a/kernel/bga.cpp
+++ /dev/null
@@ -1,585 +0,0 @@
-/*******************************************************************************
-
- Copyright(C) Jonas 'Sortie' Termansen 2012.
-
- This file is part of Sortix.
-
- Sortix is free software: you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation, either version 3 of the License, or (at your option) any later
- version.
-
- Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- Sortix. If not, see .
-
- bga.cpp
- Driver for the Bochs VBE Extensions.
-
-*******************************************************************************/
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "x86-family/memorymanagement.h"
-#include "lfbtextbuffer.h"
-#include "bga.h"
-
-namespace Sortix {
-namespace BGA {
-
-const bool TEST_RES_BY_TRYING = false;
-
-const uint16_t VBE_DISPI_INDEX_ID = 0;
-const uint16_t VBE_DISPI_INDEX_XRES = 1;
-const uint16_t VBE_DISPI_INDEX_YRES = 2;
-const uint16_t VBE_DISPI_INDEX_BPP = 3;
-const uint16_t VBE_DISPI_INDEX_ENABLE = 4;
-const uint16_t VBE_DISPI_INDEX_BANK = 5;
-const uint16_t VBE_DISPI_INDEX_VIRT_WIDTH = 6;
-const uint16_t VBE_DISPI_INDEX_VIRT_HEIGHT = 7;
-const uint16_t VBE_DISPI_INDEX_X_OFFSET = 8;
-const uint16_t VBE_DISPI_INDEX_Y_OFFSET = 9;
-
-const uint16_t VBE_DISPI_IOPORT_INDEX = 0x01CE;
-const uint16_t VBE_DISPI_IOPORT_DATA = 0x01CF;
-
-const uint16_t VBE_DISPI_BPP_4 = 0x04;
-const uint16_t VBE_DISPI_BPP_8 = 0x08;
-const uint16_t VBE_DISPI_BPP_15 = 0x0F;
-const uint16_t VBE_DISPI_BPP_16 = 0x10;
-const uint16_t VBE_DISPI_BPP_24 = 0x18;
-const uint16_t VBE_DISPI_BPP_32 = 0x20;
-
-const uint16_t VBE_DISPI_DISABLED = 0x00;
-const uint16_t VBE_DISPI_ENABLED = 0x01;
-const uint16_t VBE_DISPI_GETCAPS = 0x02;
-const uint16_t VBE_DISPI_8BIT_DAC = 0x20;
-const uint16_t VBE_DISPI_LFB_ENABLED = 0x40;
-const uint16_t VBE_DISPI_NOCLEARMEM = 0x80;
-
-const uint16_t VBE_MIN_SUP_VERSION = 0xB0C0;
-const uint16_t VBE_MIN_POS_VERSION = 0xB0C0;
-const uint16_t VBE_MAX_POS_VERSION = 0xB0CF;
-
-const size_t VBE_BANK_SIZE = 64UL * 1024UL;
-volatile uint8_t* const VBE_VIDEO_MEM = (volatile uint8_t*) 0xA0000;
-
-static addr_t ParseDevBar0(uint32_t devaddr)
-{
- pcibar_t bar = PCI::GetBAR(devaddr, 0);
- return bar.addr();
-}
-
-addr_t DetectBGAFramebuffer()
-{
- uint32_t devaddr;
- pcifind_t pcifind;
-
- // Search for the bochs BGA device and compatible.
- memset(&pcifind, 255, sizeof(pcifind));
- pcifind.vendorid = 0x1234;
- pcifind.deviceid = 0x1111;
- if ( (devaddr = PCI::SearchForDevices(pcifind, 0)) )
- return ParseDevBar0(devaddr);
-
- // Search for a generic VGA compatible device.
- memset(&pcifind, 255, sizeof(pcifind));
- pcifind.classid = 0x03;
- pcifind.subclassid = 0x00;
- pcifind.progif = 0x00;
- if ( (devaddr = PCI::SearchForDevices(pcifind)) )
- return ParseDevBar0(devaddr);
-
- return 0;
-}
-
-uint16_t version;
-uint16_t maxbpp;
-uint16_t maxxres;
-uint16_t maxyres;
-
-uint16_t curbpp;
-uint16_t curxres;
-uint16_t curyres;
-uint16_t curbank;
-
-addr_t bgaframebuffer;
-
-void WriteRegister(uint16_t index, uint16_t value)
-{
- outport16(VBE_DISPI_IOPORT_INDEX, index);
- outport16(VBE_DISPI_IOPORT_DATA, value);
-}
-
-uint16_t ReadRegister(uint16_t index)
-{
- outport16(VBE_DISPI_IOPORT_INDEX, index);
- return inport16(VBE_DISPI_IOPORT_DATA);
-}
-
-uint16_t GetCapability(uint16_t index)
-{
- uint16_t wasenabled = ReadRegister(VBE_DISPI_INDEX_ENABLE);
- WriteRegister(VBE_DISPI_INDEX_ENABLE, wasenabled | VBE_DISPI_GETCAPS);
- uint16_t cap = ReadRegister(index);
- WriteRegister(VBE_DISPI_INDEX_ENABLE, wasenabled);
- return cap;
-}
-
-bool SetVideoMode(uint16_t width, uint16_t height, uint16_t depth, bool keep)
-{
- bool uselinear = true;
- WriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);
- WriteRegister(VBE_DISPI_INDEX_XRES, width);
- WriteRegister(VBE_DISPI_INDEX_YRES, height);
- WriteRegister(VBE_DISPI_INDEX_BPP, depth);
- WriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED |
- (uselinear ? VBE_DISPI_LFB_ENABLED : 0) |
- (keep ? VBE_DISPI_NOCLEARMEM : 0));
- curbpp = depth;
- curxres = width;
- curyres = height;
- return true;
-}
-
-bool IsStandardResolution(uint16_t width, uint16_t height, uint16_t depth)
-{
- if ( depth != VBE_DISPI_BPP_32 ) { return false; }
- if ( width == 800 && height == 600 ) { return true; }
- if ( width == 1024 && height == 768 ) { return true; }
- if ( width == 1280 && height == 720 ) { return true; }
- if ( width == 1280 && height == 1024 ) { return true; }
- if ( width == 1600 && height == 900 ) { return true; }
- if ( width == 1920 && height == 1080 ) { return true; }
- return false;
-}
-
-// TODO: Need a better method of detecting available/desired resolutions.
-bool SupportsResolution(uint16_t width, uint16_t height, uint16_t depth)
-{
- if ( !width || !height || !depth ) { return false; }
- if ( maxxres < width || maxyres < height || maxbpp < depth ) return false;
- if ( width % 8U ) { return false; }
- uint16_t wasenabled = ReadRegister(VBE_DISPI_INDEX_ENABLE);
- if ( width == curxres && height == curyres && depth == curbpp) return true;
- if ( !TEST_RES_BY_TRYING ) { return true; }
- SetVideoMode(width, height, depth, true);
- uint16_t newxres = ReadRegister(VBE_DISPI_INDEX_XRES);
- uint16_t newyres = ReadRegister(VBE_DISPI_INDEX_XRES);
- uint16_t newbpp = ReadRegister(VBE_DISPI_INDEX_BPP);
- bool result = newxres != curxres || newyres != curyres || newbpp != curbpp;
- SetVideoMode(curxres, curyres, curbpp, true);
- WriteRegister(VBE_DISPI_INDEX_ENABLE, wasenabled);
- return result;
-}
-
-class BGADriver : public VideoDriver
-{
-public:
- BGADriver();
- virtual ~BGADriver();
-
-public:
- virtual bool StartUp();
- virtual bool ShutDown();
- virtual char* GetCurrentMode() const;
- virtual bool SwitchMode(const char* mode);
- virtual bool Supports(const char* mode) const;
- virtual char** GetModes(size_t* nummodes) const;
- virtual off_t FrameSize() const;
- virtual ssize_t WriteAt(off_t off, const void* buf, size_t count);
- virtual ssize_t ReadAt(off_t off, void* buf, size_t count);
- virtual TextBuffer* CreateTextBuffer();
-
-private:
- bool MapVideoMemory(size_t size);
- bool MapVideoMemoryRange(addr_t mapat, size_t from, size_t to);
- bool IncreaseVirtual(size_t new_size);
- bool DetectModes() const;
-
-private:
- mutable size_t nummodes;
- mutable char** modes;
- char* curmode;
- size_t lfbmapped;
- size_t framesize;
- addralloc_t addr_allocation;
-
-};
-
-BGADriver::BGADriver()
-{
- nummodes = 0;
- modes = NULL;
- curmode = NULL;
- lfbmapped = 0;
- framesize = 0;
- memset(&addr_allocation, 0, sizeof(addr_allocation));
-}
-
-BGADriver::~BGADriver()
-{
- MapVideoMemory(0);
- FreeKernelAddress(&addr_allocation);
- for ( size_t i = 0; i < nummodes; i++ )
- {
- delete[] modes[i];
- }
- delete[] modes;
- delete[] curmode;
-}
-
-bool BGADriver::MapVideoMemoryRange(addr_t mapat, size_t from, size_t to)
-{
- addr_t phys = bgaframebuffer;
- const addr_t mtype = Memory::PAT_WC;
- for ( size_t i = from; i < to; i += Page::Size() )
- if ( !Memory::MapPAT(phys+i, mapat+i, PROT_KWRITE | PROT_KREAD, mtype) )
- {
- Log::PrintF("Error: Insufficient memory to map BGA framebuffer "
- "onto kernel address space: needed 0x%zx bytes but "
- "only 0x%zx was available at this point.\n", to, i);
- for ( size_t n = from; n < i; n += Page::Size() )
- Memory::Unmap(mapat + n);
- return false;
- }
- return true;
-}
-
-bool BGADriver::IncreaseVirtual(size_t new_size)
-{
- new_size = Page::AlignUp(new_size);
- assert(addr_allocation.size < new_size);
-
- addralloc_t new_addralloc;
- if ( !AllocateKernelAddress(&new_addralloc, new_size) )
- {
- Log::PrintF("Error: Insufficient virtual address space for BGA "
- "frame of size 0x%zx bytes, only 0x%zx was available.\n",
- new_size, addr_allocation.size);
- return false;
- }
-
- addr_t old_mapat = addr_allocation.from;
- addr_t new_mapat = new_addralloc.from;
-
- if ( !MapVideoMemoryRange(new_mapat, 0, new_size) )
- {
- FreeKernelAddress(&addr_allocation);
- return false;
- }
-
- for ( size_t i = 0; i < lfbmapped; i += Page::Size() )
- Memory::Unmap(old_mapat + i);
-
- FreeKernelAddress(&addr_allocation);
-
- lfbmapped = new_size;
- addr_allocation = new_addralloc;
-
- Memory::Flush();
- return true;
-}
-
-bool BGADriver::MapVideoMemory(size_t size)
-{
- size = Page::AlignUp(size);
-
- if ( size == lfbmapped )
- return true;
-
- if ( addr_allocation.size < size )
- return IncreaseVirtual(size);
-
- addr_t mapat = addr_allocation.from;
- for ( size_t i = size; i < lfbmapped; i+= Page::Size() )
- Memory::Unmap(mapat + i);
-
- lfbmapped = size;
- Memory::Flush();
-
- if ( !size )
- FreeKernelAddress(&addr_allocation);
-
- return true;
-}
-
-bool BGADriver::StartUp()
-{
- if ( !modes && !DetectModes() ) { return false; }
- return true;
-}
-
-bool BGADriver::ShutDown()
-{
- MapVideoMemory(0);
- if ( curmode )
- {
- delete[] curmode; curmode = NULL;
- errno = ENOSYS;
- return false; // TODO: Return to VGA Text Mode.
- }
- return true;
-}
-
-char* BGADriver::GetCurrentMode() const
-{
- if ( !curmode ) { errno = EINVAL; return NULL; }
- return String::Clone(curmode);
-}
-
-bool BGADriver::SwitchMode(const char* mode)
-{
- bool result = false;
- char* modeclone = String::Clone(mode);
- if ( !modeclone )
- return NULL;
- char* xstr = NULL;
- char* ystr = NULL;
- char* bppstr = NULL;
- if ( !ReadParamString(mode, "width", &xstr, "height", &ystr,
- "bpp", &bppstr, "STOP") )
- {
- delete[] modeclone;
- return false;
- }
- uint16_t xres = xstr ? atoi(xstr) : 0;
- uint16_t yres = ystr ? atoi(ystr) : 0;
- uint16_t bpp = bppstr ? atoi(bppstr) : 32;
- size_t newframesize = (size_t) xres * (size_t) yres * (size_t) bpp/8UL;
-
- // If the current resolution uses more memory than the new one, keep it
- // around in case setting the video mode failed.
- if ( MapVideoMemory(newframesize < lfbmapped ? lfbmapped : newframesize) &&
- SetVideoMode(xres, yres, bpp, false) )
- {
- delete[] curmode;
- curmode = modeclone;
- modeclone = NULL;
- // We can now truncate the amount of memory to what we really need.
- MapVideoMemory(framesize = newframesize);
- result = true;
- }
-
- delete[] xstr;
- delete[] ystr;
- delete[] bppstr;
- delete[] modeclone;
- return result;
-}
-
-bool BGADriver::Supports(const char* mode) const
-{
- char* xstr = NULL;
- char* ystr = NULL;
- char* bppstr = NULL;
- if ( !ReadParamString(mode, "width", &xstr, "height", &ystr,
- "bpp", &bppstr, NULL, NULL) ) { return false; }
- uint16_t xres = xstr ? atoi(xstr) : 0;
- uint16_t yres = ystr ? atoi(ystr) : 0;
- uint16_t bpp = bppstr ? atoi(bppstr) : 0;
- bool result = SupportsResolution(xres, yres, bpp);
- delete[] xstr;
- delete[] ystr;
- delete[] bppstr;
- return result;
-}
-
-char** BGADriver::GetModes(size_t* retnum) const
-{
- if ( !modes && !DetectModes() ) { return NULL; }
- char** result = new char*[nummodes];
- if ( !result ) { return NULL; }
- for ( size_t i = 0; i < nummodes; i++ )
- {
- result[i] = String::Clone(modes[i]);
- if ( !result[i] )
- {
- for ( size_t n = 0; n < i; i++ ) { delete[] result[n]; }
- delete[] result;
- return NULL;
- }
- }
- *retnum = nummodes;
- return result;
-}
-
-off_t BGADriver::FrameSize() const
-{
- return curxres * curyres * (curbpp / 8UL);
-}
-
-ssize_t BGADriver::WriteAt(off_t off, const void* buf, size_t count)
-{
- uint8_t* frame = (uint8_t*) addr_allocation.from;
- if ( (off_t) framesize <= off )
- return 0;
- if ( framesize < off + count )
- count = framesize - off;
- memcpy(frame + off, buf, count);
- return count;
-}
-
-ssize_t BGADriver::ReadAt(off_t off, void* buf, size_t count)
-{
- const uint8_t* frame = (const uint8_t*) addr_allocation.from;
- if ( (off_t) framesize <= off )
- return 0;
- if ( framesize < off + count )
- count = framesize - off;
- memcpy(buf, frame + off, count);
- return count;
-}
-
-bool BGADriver::DetectModes() const
-{
- nummodes = 0;
- unsigned bpp = VBE_DISPI_BPP_32;
- for ( unsigned w = 0; w < maxxres; w += 4U )
- {
- for ( unsigned h = 0; h < maxyres; h += 4UL )
- {
- if ( !IsStandardResolution(w, h, bpp) ) { continue; }
- if ( !SupportsResolution(w, h, bpp) ) { continue; }
- nummodes++;
- }
- }
- modes = new char*[nummodes];
- if ( !modes ) { return false; }
- memset(modes, 0, sizeof(char*) * nummodes);
- size_t curmodeid = 0;
- for ( unsigned w = 0; w < maxxres; w += 4U )
- {
- for ( unsigned h = 0; h < maxyres; h += 4UL )
- {
- if ( !IsStandardResolution(w, h, bpp) ) { continue; }
- if ( !SupportsResolution(w, h, bpp) ) { continue; }
- char bppstr[64];
- char xresstr[64];
- char yresstr[64];
- snprintf(bppstr, 64, "%u", bpp);
- snprintf(xresstr, 64, "%u", w);
- snprintf(yresstr, 64, "%u", h);
- char* modestr = String::Combine(6, "width=", xresstr, ",height=",
- yresstr, ",bpp=", bppstr);
- if ( !modestr ) { return false; }
- modes[curmodeid++] = modestr;
- }
- }
- return true;
-}
-
-TextBuffer* BGADriver::CreateTextBuffer()
-{
- uint8_t* lfb = (uint8_t*) addr_allocation.from;
- uint32_t lfbformat = curbpp;
- size_t scansize = curxres * curbpp / 8UL;
- return CreateLFBTextBuffer(lfb, lfbformat, curxres, curyres, scansize);
-}
-
-static uint16_t ProbeBGAVersion()
-{
- // First see if the register is in the legal range.
- uint16_t ver = ReadRegister(VBE_DISPI_INDEX_ID);
- if ( ver < VBE_MIN_POS_VERSION )
- return 0;
- if ( ver > VBE_MAX_POS_VERSION )
- return 0;
-
- // The bootloader or BIOS may have set the current version to less than what
- // really is supported. If we a version number to the register, we can read
- // it back only if it is supported.
-
- // If the register accepts an invalid version number, don't trust it and we
- // may be in danger if an unrelated type of register is using this IO port.
- // Since that is unlikely, just assume we got a real BGA device.
- WriteRegister(VBE_DISPI_INDEX_ID, 0xFFFF);
- if ( ReadRegister(VBE_DISPI_INDEX_ID) == 0xFFFF )
- {
- WriteRegister(VBE_DISPI_INDEX_ID, ver);
- Log::PrintF("Warning: Found what appears to be BGA hardware, but it "
- "behaves differently when attempting to scan what version "
- "it conforms to. ");
- if ( ver < VBE_MIN_SUP_VERSION )
- {
- Log::PrintF("The hardware is by default set to an old unsupported "
- "version, this driver will not use it.\n");
- return 0;
- }
- Log::PrintF("The driver will use this hardware (even though it may not "
- "be BGA hardware) and bad things may happen.\n");
- return ver;
- }
-
- // Attempt to query all possible version ids.
- for ( uint16_t i = ver; i < VBE_MAX_POS_VERSION; i++ )
- {
- WriteRegister(VBE_DISPI_INDEX_ID, i);
- if ( ReadRegister(VBE_DISPI_INDEX_ID) == i )
- ver = i;
- }
-
- return ver;
-}
-
-void Init()
-{
- if ( !(version = ProbeBGAVersion()) )
- return;
-
- curbpp = 0;
- curxres = 0;
- curyres = 0;
- curbank = 0xFFFF;
-
- maxbpp = GetCapability(VBE_DISPI_INDEX_BPP);
- maxxres = GetCapability(VBE_DISPI_INDEX_XRES);
- maxyres = GetCapability(VBE_DISPI_INDEX_YRES);
-
- if ( !(bgaframebuffer = DetectBGAFramebuffer()) )
- {
- Log::PrintF("BGA support detected but no PCI device could be found "
- "determines the location of the framebuffer. Rather than "
- "guessing it is at 0xE0000000, this driver shuts down to "
- "avoid corrupting possible memory there.\n");
- return;
- }
-
- BGADriver* bgadriver = new BGADriver;
- if ( !bgadriver )
- {
- Log::PrintF("Unable to allocate BGA driver, but hardware present\n");
- return;
- }
-
- if ( !Video::RegisterDriver("bga", bgadriver) )
- {
- Log::PrintF("Unable to register BGA driver, but hardware present\n");
- delete bgadriver;
- return;
- }
-}
-
-} // namespace BGA
-} // namespace Sortix
diff --git a/kernel/dispmsg.cpp b/kernel/dispmsg.cpp
deleted file mode 100644
index dc54eada..00000000
--- a/kernel/dispmsg.cpp
+++ /dev/null
@@ -1,342 +0,0 @@
-/*******************************************************************************
-
- Copyright(C) Jonas 'Sortie' Termansen 2012.
-
- This file is part of Sortix.
-
- Sortix is free software: you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation, either version 3 of the License, or (at your option) any later
- version.
-
- Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- Sortix. If not, see .
-
- dispmsg.cpp
- User-space message-based interface for video framework access.
-
-*******************************************************************************/
-
-#include
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-
-#include
-#include
-#include
-#include
-
-#include "dispmsg.h"
-
-namespace Sortix {
-namespace DisplayMessage {
-
-const uint64_t ONE_AND_ONLY_DEVICE = 0;
-const uint64_t ONE_AND_ONLY_CONNECTOR = 0;
-
-__attribute__((unused))
-static char* StringOfCrtcMode(struct dispmsg_crtc_mode mode)
-{
- char bppstr[sizeof(mode.fb_format) * 3];
- char xresstr[sizeof(mode.view_xres) * 3];
- char yresstr[sizeof(mode.view_yres) * 3];
- char magicstr[sizeof(mode.magic) * 3];
- snprintf(bppstr, sizeof(bppstr), "%ju", (uintmax_t) mode.fb_format);
- snprintf(xresstr, sizeof(xresstr), "%ju", (uintmax_t) mode.view_xres);
- snprintf(yresstr, sizeof(yresstr), "%ju", (uintmax_t) mode.view_yres);
- snprintf(magicstr, sizeof(magicstr), "%ju", (uintmax_t) mode.magic);
- char* drivername = Video::GetDriverName(mode.driver_index);
- if ( !drivername )
- return NULL;
- char* ret = String::Combine(10,
- "driver=", drivername, ","
- "bpp=", bppstr, ","
- "width=", xresstr, ","
- "height=", yresstr, ","
- "modeid=", magicstr);
- delete[] drivername;
- return ret;
-}
-
-__attribute__((unused))
-struct dispmsg_crtc_mode CrtcModeOfString(const char* string, uint64_t driverid)
-{
- char* xstr = NULL;
- char* ystr = NULL;
- char* bppstr = NULL;
- char* modeidstr = NULL;
- char* unsupportedstr = NULL;
- struct dispmsg_crtc_mode ret;
- ret.control = 0;
- if ( !strcmp(string, "driver=none") )
- return ret;
- if ( !ReadParamString(string,
- "width", &xstr,
- "height", &ystr,
- "bpp", &bppstr,
- "modeid", &modeidstr,
- "unsupported", &unsupportedstr,
- NULL, NULL) )
- return ret;
- ret.driver_index = driverid;
- ret.view_xres = xstr ? atol(xstr) : 0;
- delete[] xstr;
- ret.view_yres = ystr ? atol(ystr) : 0;
- delete[] ystr;
- ret.fb_format = bppstr ? atol(bppstr) : 0;
- delete[] bppstr;
- ret.magic = modeidstr ? atoll(modeidstr) : 0;
- delete[] modeidstr;
- if ( !unsupportedstr )
- ret.control = 1;
- delete[] unsupportedstr;
- return ret;
-}
-
-__attribute__((unused))
-static bool TransmitString(struct dispmsg_string* dest, const char* str)
-{
- size_t size = strlen(str) + 1;
- size_t dest_size = dest->byte_size;
- dest->byte_size = size;
- if ( dest_size < size )
- return errno = ERANGE, false;
- strcpy(dest->str, str);
- return true;
-}
-
-__attribute__((unused))
-static char* ReceiveString(struct dispmsg_string* src)
-{
- if ( !src->byte_size )
-bad_input:
- return errno = EINVAL, (char*) NULL;
- char* ret = new char[src->byte_size];
- if ( !ret )
- return NULL;
- memcpy(ret, src->str, src->byte_size);
- if ( ret[src->byte_size-1] != '\0' ) { delete[] ret; goto bad_input; }
- return ret;
-}
-
-static int EnumerateDevices(void* ptr, size_t size)
-{
- if ( size != sizeof(struct dispmsg_enumerate_devices) )
- return errno = EINVAL, -1;
- struct dispmsg_enumerate_devices* msg =
- (struct dispmsg_enumerate_devices*) ptr;
- // TODO: HACK: Only one device is currently supported by our backend.
- size_t num_devices = 1;
- if ( msg->devices_length < num_devices )
- {
- msg->devices_length = num_devices;
- return errno = ERANGE, -1;
- }
- msg->devices[0] = ONE_AND_ONLY_DEVICE;
- return 0;
-}
-
-static int GetDriverCount(void* ptr, size_t size)
-{
- if ( size != sizeof(struct dispmsg_get_driver_count) )
- return errno = EINVAL, -1;
- struct dispmsg_get_driver_count* msg =
- (struct dispmsg_get_driver_count*) ptr;
- if ( msg->device != ONE_AND_ONLY_DEVICE )
- return errno = EINVAL, -1;
- msg->driver_count = Video::GetNumDrivers();
- return 0;
-}
-
-static int GetDriverName(void* ptr, size_t size)
-{
- if ( size != sizeof(struct dispmsg_get_driver_name) )
- return errno = EINVAL, -1;
- struct dispmsg_get_driver_name* msg =
- (struct dispmsg_get_driver_name* ) ptr;
- if ( msg->device != ONE_AND_ONLY_DEVICE )
- return errno = EINVAL, -1;
- char* name = Video::GetDriverName(msg->driver_index);
- if ( !name )
- return -1;
- bool success = TransmitString(&msg->name, name);
- delete[] name;
- return success ? 0 : -1;
-}
-
-static int GetDriver(void* ptr, size_t size)
-{
- if ( size != sizeof(struct dispmsg_get_driver) )
- return errno = EINVAL, -1;
- struct dispmsg_get_driver* msg = (struct dispmsg_get_driver*) ptr;
- if ( msg->device != ONE_AND_ONLY_DEVICE )
- return errno = EINVAL, -1;
- msg->driver_index = Video::GetCurrentDriverIndex();
- return 0;
-}
-
-static int SetDriver(void* ptr, size_t size)
-{
- if ( size != sizeof(struct dispmsg_set_driver) )
- return errno = EINVAL, -1;
- struct dispmsg_set_driver* msg = (struct dispmsg_set_driver*) ptr;
- if ( msg->device != ONE_AND_ONLY_DEVICE )
- return errno = EINVAL, -1;
- return errno = ENOSYS, -1;
-}
-
-static int SetCrtcMode(void* ptr, size_t size)
-{
- if ( size != sizeof(struct dispmsg_set_crtc_mode) )
- return errno = EINVAL, -1;
- struct dispmsg_set_crtc_mode* msg = (struct dispmsg_set_crtc_mode*) ptr;
- if ( msg->device != ONE_AND_ONLY_DEVICE )
- return errno = EINVAL, -1;
- if ( msg->connector != ONE_AND_ONLY_CONNECTOR )
- return errno = EINVAL, -1;
- char* modestr = StringOfCrtcMode(msg->mode);
- if ( !modestr )
- return -1;
- bool success = Video::SwitchMode(modestr);
- delete[] modestr;
- return success ? 0 : -1;
-}
-
-static int GetCrtcMode(void* ptr, size_t size)
-{
- if ( size != sizeof(struct dispmsg_get_crtc_mode) )
- return errno = EINVAL, -1;
- struct dispmsg_get_crtc_mode* msg = (struct dispmsg_get_crtc_mode*) ptr;
- if ( msg->device != ONE_AND_ONLY_DEVICE )
- return errno = EINVAL, -1;
- if ( msg->connector != ONE_AND_ONLY_CONNECTOR )
- return errno = EINVAL, -1;
- char* modestr = Video::GetCurrentMode();
- if ( !modestr )
- return -1;
- msg->mode = CrtcModeOfString(modestr, Video::GetCurrentDriverIndex());
- delete[] modestr;
- return 0;
-}
-
-static int GetCrtcModes(void* ptr, size_t size)
-{
- if ( size != sizeof(struct dispmsg_get_crtc_modes) )
- return errno = EINVAL, -1;
- struct dispmsg_get_crtc_modes* msg = (struct dispmsg_get_crtc_modes*) ptr;
- if ( msg->device != ONE_AND_ONLY_DEVICE )
- return errno = EINVAL, -1;
- if ( msg->connector != ONE_AND_ONLY_CONNECTOR )
- return errno = EINVAL, -1;
- size_t nummodes;
- char** modes = Video::GetModes(&nummodes);
- if ( !modes )
- return -1;
- size_t dest_length = msg->modes_length;
-
- int ret;
- if ( nummodes <= dest_length )
- {
- ret = 0;
- for ( size_t i = 0; i < nummodes; i++ )
- {
- const char* modestr = modes[i];
- uint64_t driver_index = Video::LookupDriverIndexOfMode(modestr);
- msg->modes[i] = CrtcModeOfString(modestr, driver_index);
- }
- }
- else
- {
- errno = ERANGE;
- ret = -1;
- }
- msg->modes_length = nummodes;
- for ( size_t i = 0; i < nummodes; i++ )
- delete[] modes[i];
- delete[] modes;
- return ret;
-}
-
-static int GetMemorySize(void* ptr, size_t size)
-{
- if ( size != sizeof(struct dispmsg_get_memory_size) )
- return errno = EINVAL, -1;
- struct dispmsg_get_memory_size* msg =
- (struct dispmsg_get_memory_size*) ptr;
- msg->memory_size = Video::FrameSize();
- return 0;
-}
-
-static int WriteMemory(void* ptr, size_t size)
-{
- if ( size != sizeof(struct dispmsg_write_memory) )
- return errno = EINVAL, -1;
- struct dispmsg_write_memory* msg = (struct dispmsg_write_memory*) ptr;
- if ( msg->device != ONE_AND_ONLY_DEVICE )
- return errno = EINVAL, -1;
- if ( OFF_MAX < msg->offset )
- return errno = EOVERFLOW, -1;
- off_t offset = msg->offset;
- if ( Video::WriteAt(offset, msg->src, msg->size) < 0 )
- return -1;
- return 0;
-}
-
-static int ReadMemory(void* ptr, size_t size)
-{
- if ( size != sizeof(struct dispmsg_read_memory) )
- return errno = EINVAL, -1;
- struct dispmsg_read_memory* msg = (struct dispmsg_read_memory*) ptr;
- if ( msg->device != ONE_AND_ONLY_DEVICE )
- return errno = EINVAL, -1;
- if ( OFF_MAX < msg->offset )
- return errno = EOVERFLOW, -1;
- off_t offset = msg->offset;
- if ( Video::ReadAt(offset, msg->dst, msg->size) < 0 )
- return -1;
- return 0;
-}
-
-// TODO: Secure this system call against bad user-space pointers.
-static int sys_dispmsg_issue(void* ptr, size_t size)
-{
- struct dispmsg_header* hdr = (struct dispmsg_header*) ptr;
- if ( size < sizeof(*hdr) )
- return errno = EINVAL, -1;
- switch ( hdr->msgid )
- {
- case DISPMSG_ENUMERATE_DEVICES: return EnumerateDevices(ptr, size);
- case DISPMSG_GET_DRIVER_COUNT: return GetDriverCount(ptr, size);
- case DISPMSG_GET_DRIVER_NAME: return GetDriverName(ptr, size);
- case DISPMSG_GET_DRIVER: return GetDriver(ptr, size);
- case DISPMSG_SET_DRIVER: return SetDriver(ptr, size);
- case DISPMSG_SET_CRTC_MODE: return SetCrtcMode(ptr, size);
- case DISPMSG_GET_CRTC_MODE: return GetCrtcMode(ptr, size);
- case DISPMSG_GET_CRTC_MODES: return GetCrtcModes(ptr, size);
- case DISPMSG_GET_MEMORY_SIZE: return GetMemorySize(ptr, size);
- case DISPMSG_WRITE_MEMORY: return WriteMemory(ptr, size);
- case DISPMSG_READ_MEMORY: return ReadMemory(ptr, size);
- default:
- return errno = ENOSYS, -1;
- }
-}
-
-void Init()
-{
- Syscall::Register(SYSCALL_DISPMSG_ISSUE, (void*) sys_dispmsg_issue);
-}
-
-} // namespace DisplayMessage
-} // namespace Sortix
diff --git a/kernel/dispmsg.h b/kernel/dispmsg.h
deleted file mode 100644
index fd999513..00000000
--- a/kernel/dispmsg.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*******************************************************************************
-
- Copyright(C) Jonas 'Sortie' Termansen 2012.
-
- This file is part of Sortix.
-
- Sortix is free software: you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation, either version 3 of the License, or (at your option) any later
- version.
-
- Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- Sortix. If not, see .
-
- dispmsg.h
- User-space message-based interface for video framework access.
-
-*******************************************************************************/
-
-#ifndef SORTIX_DISPMSG_H
-#define SORTIX_DISPMSG_H
-
-namespace Sortix {
-namespace DisplayMessage {
-
-void Init();
-
-} // namespace DisplayMessage
-} // namespace Sortix
-
-#endif
diff --git a/kernel/gpu/bga/bga.cpp b/kernel/gpu/bga/bga.cpp
new file mode 100644
index 00000000..e618f1ff
--- /dev/null
+++ b/kernel/gpu/bga/bga.cpp
@@ -0,0 +1,528 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012, 2014.
+
+ This file is part of Sortix.
+
+ Sortix is free software: you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation, either version 3 of the License, or (at your option) any later
+ version.
+
+ Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ Sortix. If not, see .
+
+ gpu/bga/bga.cpp
+ Driver for the Bochs VBE Extensions.
+
+*******************************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "x86-family/memorymanagement.h"
+#include "lfbtextbuffer.h"
+#include "bga.h"
+
+namespace Sortix {
+namespace BGA {
+
+const uint16_t VBE_DISPI_INDEX_ID = 0;
+const uint16_t VBE_DISPI_INDEX_XRES = 1;
+const uint16_t VBE_DISPI_INDEX_YRES = 2;
+const uint16_t VBE_DISPI_INDEX_BPP = 3;
+const uint16_t VBE_DISPI_INDEX_ENABLE = 4;
+const uint16_t VBE_DISPI_INDEX_BANK = 5;
+const uint16_t VBE_DISPI_INDEX_VIRT_WIDTH = 6;
+const uint16_t VBE_DISPI_INDEX_VIRT_HEIGHT = 7;
+const uint16_t VBE_DISPI_INDEX_X_OFFSET = 8;
+const uint16_t VBE_DISPI_INDEX_Y_OFFSET = 9;
+const uint16_t VBE_DISPI_NUM_REGISTERS = 10;
+
+#if defined(__i386__) || defined(__x86_64__)
+const uint16_t VBE_DISPI_IOPORT_INDEX = 0x01CE;
+const uint16_t VBE_DISPI_IOPORT_DATA = 0x01CF;
+#endif
+
+const uint16_t VBE_DISPI_BPP_4 = 0x04;
+const uint16_t VBE_DISPI_BPP_8 = 0x08;
+const uint16_t VBE_DISPI_BPP_15 = 0x0F;
+const uint16_t VBE_DISPI_BPP_16 = 0x10;
+const uint16_t VBE_DISPI_BPP_24 = 0x18;
+const uint16_t VBE_DISPI_BPP_32 = 0x20;
+
+const uint16_t VBE_DISPI_DISABLED = 0x00;
+const uint16_t VBE_DISPI_ENABLED = 0x01;
+const uint16_t VBE_DISPI_GETCAPS = 0x02;
+const uint16_t VBE_DISPI_8BIT_DAC = 0x20;
+const uint16_t VBE_DISPI_LFB_ENABLED = 0x40;
+const uint16_t VBE_DISPI_NOCLEARMEM = 0x80;
+
+const uint16_t VBE_MIN_SUP_VERSION = 0xB0C0;
+const uint16_t VBE_MIN_POS_VERSION = 0xB0C0;
+const uint16_t VBE_MAX_POS_VERSION = 0xB0CF;
+
+static bool IsStandardResolution(uint16_t width, uint16_t height, uint16_t depth)
+{
+ if ( depth != VBE_DISPI_BPP_32 ) { return false; }
+ if ( width == 720 && height == 400 ) { return true; }
+ if ( width == 800 && height == 600 ) { return true; }
+ if ( width == 1024 && height == 768 ) { return true; }
+ if ( width == 1280 && height == 720 ) { return true; }
+ if ( width == 1280 && height == 1024 ) { return true; }
+ if ( width == 1600 && height == 900 ) { return true; }
+ if ( width == 1920 && height == 1080 ) { return true; }
+ return false;
+}
+
+class BGADevice : public VideoDevice
+{
+public:
+ BGADevice(uint32_t devaddr, addralloc_t fb_alloc, addralloc_t mmio_alloc);
+ virtual ~BGADevice();
+
+public:
+ virtual struct dispmsg_crtc_mode GetCurrentMode(uint64_t connector) const;
+ virtual bool SwitchMode(uint64_t connector, struct dispmsg_crtc_mode mode);
+ virtual bool Supports(uint64_t connector, struct dispmsg_crtc_mode mode) const;
+ virtual struct dispmsg_crtc_mode* GetModes(uint64_t connector, size_t* num_modes) const;
+ virtual off_t FrameSize() const;
+ virtual ssize_t WriteAt(ioctx_t* ctx, off_t off, const void* buf, size_t count);
+ virtual ssize_t ReadAt(ioctx_t* ctx, off_t off, void* buf, size_t count);
+ virtual TextBuffer* CreateTextBuffer(uint64_t connector);
+
+public:
+ bool Initialize();
+
+private:
+ bool DetectModes() const;
+ uint16_t WriteRegister(uint16_t index, uint16_t value);
+ uint16_t ReadRegister(uint16_t index);
+ uint16_t GetCapability(uint16_t index);
+ bool SetVideoMode(uint16_t width, uint16_t height, uint16_t depth, bool keep);
+ bool SupportsResolution(uint16_t width, uint16_t height, uint16_t depth);
+
+private:
+ mutable size_t num_modes;
+ mutable struct dispmsg_crtc_mode* modes;
+ struct dispmsg_crtc_mode current_mode;
+ addralloc_t fb_alloc;
+ addralloc_t mmio_alloc;
+ uint32_t devaddr;
+ uint16_t version;
+ uint16_t maxbpp;
+ uint16_t maxxres;
+ uint16_t maxyres;
+
+};
+
+BGADevice::BGADevice(uint32_t devaddr, addralloc_t fb_alloc, addralloc_t mmio_alloc) :
+ fb_alloc(fb_alloc), mmio_alloc(mmio_alloc), devaddr(devaddr)
+{
+ num_modes = 0;
+ modes = NULL;
+ memset(¤t_mode, 0, sizeof(current_mode));
+ version = 0;
+ maxbpp = 0;
+ maxxres = 0;
+ maxyres = 0;
+}
+
+BGADevice::~BGADevice()
+{
+ UnmapPCIBar(&fb_alloc);
+ UnmapPCIBar(&mmio_alloc);
+ delete[] modes;
+}
+
+uint16_t BGADevice::WriteRegister(uint16_t index, uint16_t value)
+{
+ assert(index < VBE_DISPI_NUM_REGISTERS);
+#if defined(__i386__) || defined(__x86_64__)
+ if ( mmio_alloc.size == 0 )
+ {
+ outport16(VBE_DISPI_IOPORT_INDEX, index);
+ return outport16(VBE_DISPI_IOPORT_DATA, value);
+ }
+#endif
+ volatile little_uint16_t* regs =
+ (volatile little_uint16_t*) (mmio_alloc.from + 0x500);
+ return regs[index] = value;
+}
+
+uint16_t BGADevice::ReadRegister(uint16_t index)
+{
+#if defined(__i386__) || defined(__x86_64__)
+ if ( mmio_alloc.size == 0 )
+ {
+ outport16(VBE_DISPI_IOPORT_INDEX, index);
+ return inport16(VBE_DISPI_IOPORT_DATA);
+ }
+#endif
+ assert(index < VBE_DISPI_NUM_REGISTERS);
+ volatile little_uint16_t* regs =
+ (volatile little_uint16_t*) (mmio_alloc.from + 0x500);
+ return regs[index];
+}
+
+uint16_t BGADevice::GetCapability(uint16_t index)
+{
+ uint16_t was_enabled = ReadRegister(VBE_DISPI_INDEX_ENABLE);
+ WriteRegister(VBE_DISPI_INDEX_ENABLE, was_enabled | VBE_DISPI_GETCAPS);
+ uint16_t cap = ReadRegister(index);
+ WriteRegister(VBE_DISPI_INDEX_ENABLE, was_enabled);
+ return cap;
+}
+
+bool BGADevice::Initialize()
+{
+ if ( (version = ReadRegister(VBE_DISPI_INDEX_ID)) < VBE_MIN_SUP_VERSION )
+ {
+ Log::PrintF("[BGA device @ PCI:0x%X] Hardware version 0x%X is too old, "
+ "minimum version supported is 0x%X\n",
+ devaddr, version, VBE_MIN_SUP_VERSION);
+ return false;
+ }
+
+ maxbpp = GetCapability(VBE_DISPI_INDEX_BPP);
+ maxxres = GetCapability(VBE_DISPI_INDEX_XRES);
+ maxyres = GetCapability(VBE_DISPI_INDEX_YRES);
+
+ return true;
+}
+
+bool BGADevice::SetVideoMode(uint16_t width, uint16_t height, uint16_t depth, bool keep)
+{
+ bool uselinear = true;
+ WriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);
+ WriteRegister(VBE_DISPI_INDEX_XRES, width);
+ WriteRegister(VBE_DISPI_INDEX_YRES, height);
+ WriteRegister(VBE_DISPI_INDEX_BPP, depth);
+ WriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED |
+ (uselinear ? VBE_DISPI_LFB_ENABLED : 0) |
+ (keep ? VBE_DISPI_NOCLEARMEM : 0));
+ // TODO: How do we verify the video mode was *actually* set?
+ return true;
+}
+
+// TODO: Need a better method of detecting available/desired resolutions.
+bool BGADevice::SupportsResolution(uint16_t width, uint16_t height, uint16_t depth)
+{
+ if ( !width || !height || !depth )
+ return false;
+ if ( maxxres < width || maxyres < height || maxbpp < depth )
+ return false;
+ // TODO: Is this actually a restriction?
+ if ( width % 8U )
+ return false;
+ // TODO: Can we determine this more closely in advance? Perhaps if the
+ // framebuffer we will be using is larger than video memory?
+ return true;
+}
+
+struct dispmsg_crtc_mode BGADevice::GetCurrentMode(uint64_t connector) const
+{
+ if ( connector != 0 )
+ {
+ errno = EINVAL;
+ struct dispmsg_crtc_mode mode;
+ memset(&mode, 0, sizeof(mode));
+ return mode;
+ }
+
+ return current_mode;
+}
+
+bool BGADevice::SwitchMode(uint64_t connector, struct dispmsg_crtc_mode mode)
+{
+ if ( !Supports(connector, mode) )
+ return false;
+
+ if ( connector != 0 )
+ return errno = EINVAL, false;
+
+ size_t new_framesize = (size_t) mode.view_xres *
+ (size_t) mode.view_yres *
+ ((size_t) mode.fb_format + 7) / 8UL;
+ // TODO: Use a better error code than ENOSPC?
+ if ( fb_alloc.size < new_framesize )
+ return errno = ENOSPC, false;
+
+ if ( !SetVideoMode(mode.view_xres, mode.view_yres, mode.fb_format, false) )
+ return false;
+
+ current_mode = mode;
+
+ return true;
+}
+
+bool BGADevice::Supports(uint64_t connector, struct dispmsg_crtc_mode mode) const
+{
+ if ( connector != 0 )
+ return errno = EINVAL, false;
+
+ if ( mode.control & DISPMSG_CONTROL_VGA )
+ return errno = EINVAL, false;
+ if ( !(mode.control & DISPMSG_CONTROL_VALID) )
+ return errno = EINVAL, false;
+
+ if ( UINT16_MAX < mode.view_xres )
+ return errno = EINVAL, false;
+ if ( UINT16_MAX < mode.view_yres )
+ return errno = EINVAL, false;
+ // TODO: This is wrong, list the right values as above.
+ if ( mode.fb_format != VBE_DISPI_BPP_4 &&
+ mode.fb_format != VBE_DISPI_BPP_8 &&
+ mode.fb_format != VBE_DISPI_BPP_15 &&
+ mode.fb_format != VBE_DISPI_BPP_16 &&
+ mode.fb_format != VBE_DISPI_BPP_24 &&
+ mode.fb_format != VBE_DISPI_BPP_32 )
+ return errno = EINVAL, false;
+
+ // TODO: This is disabled because its support needs to be verified, see the
+ // framebuffer size calculation above?
+ if ( mode.fb_format != VBE_DISPI_BPP_32 )
+ return errno = ENOSYS, false;
+
+ return ((BGADevice*) this)->SupportsResolution(mode.view_xres, mode.view_yres, mode.fb_format);
+}
+
+struct dispmsg_crtc_mode* BGADevice::GetModes(uint64_t connector, size_t* retnum) const
+{
+ if ( connector != 0 )
+ return errno = EINVAL, (struct dispmsg_crtc_mode*) NULL;
+
+ if ( !modes && !DetectModes() )
+ return NULL;
+ struct dispmsg_crtc_mode* result = new struct dispmsg_crtc_mode[num_modes];
+ if ( !result )
+ return NULL;
+ for ( size_t i = 0; i < num_modes; i++ )
+ result[i] = modes[i];
+ *retnum = num_modes;
+ return result;
+}
+
+off_t BGADevice::FrameSize() const
+{
+ return (off_t) fb_alloc.size;
+}
+
+ssize_t BGADevice::WriteAt(ioctx_t* ctx, off_t off, const void* buf, size_t count)
+{
+ uint8_t* frame = (uint8_t*) fb_alloc.from;
+ if ( (off_t) fb_alloc.size <= off )
+ return 0;
+ if ( fb_alloc.size < off + count )
+ count = fb_alloc.size - off;
+ if ( !ctx->copy_from_src(frame + off, buf, count) )
+ return -1;
+ return count;
+}
+
+ssize_t BGADevice::ReadAt(ioctx_t* ctx, off_t off, void* buf, size_t count)
+{
+ const uint8_t* frame = (const uint8_t*) fb_alloc.from;
+ if ( (off_t) fb_alloc.size <= off )
+ return 0;
+ if ( fb_alloc.size < off + count )
+ count = fb_alloc.size - off;
+ if ( !ctx->copy_to_dest(buf, frame + off, count) )
+ return -1;
+ return count;
+}
+
+bool BGADevice::DetectModes() const
+{
+ num_modes = 0;
+ unsigned bpp = VBE_DISPI_BPP_32;
+ for ( unsigned w = 0; w < maxxres; w += 4U )
+ {
+ for ( unsigned h = 0; h < maxyres; h += 4UL )
+ {
+ if ( !IsStandardResolution(w, h, bpp) )
+ continue;
+ if ( !((BGADevice*) this)->SupportsResolution(w, h, bpp) )
+ continue;
+ num_modes++;
+ }
+ }
+ num_modes++;
+ modes = new struct dispmsg_crtc_mode[num_modes];
+ if ( !modes )
+ return false;
+ memset(modes, 0, sizeof(char*) * num_modes);
+ size_t current_mode_id = 0;
+ for ( unsigned w = 0; w < maxxres; w += 4U )
+ {
+ for ( unsigned h = 0; h < maxyres; h += 4UL )
+ {
+ if ( !IsStandardResolution(w, h, bpp) )
+ continue;
+ if ( !((BGADevice*) this)->SupportsResolution(w, h, bpp) )
+ continue;
+ struct dispmsg_crtc_mode mode;
+ memset(&mode, 0, sizeof(mode));
+ mode.view_xres = w;
+ mode.view_yres = h;
+ mode.fb_format = bpp;
+ mode.control = DISPMSG_CONTROL_VALID;
+ modes[current_mode_id++] = mode;
+ }
+ }
+
+ struct dispmsg_crtc_mode any_mode;
+ memset(&any_mode, 0, sizeof(any_mode));
+ any_mode.view_xres = 0;
+ any_mode.view_yres = 0;
+ any_mode.fb_format = 0;
+ any_mode.control = DISPMSG_CONTROL_OTHER_RESOLUTIONS;
+ modes[num_modes-1] = any_mode;
+
+ return true;
+}
+
+TextBuffer* BGADevice::CreateTextBuffer(uint64_t connector)
+{
+ if ( connector != 0 )
+ return errno = EINVAL, (TextBuffer*) NULL;
+
+ uint8_t* lfb = (uint8_t*) fb_alloc.from;
+ uint32_t lfbformat = current_mode.fb_format;
+ size_t scansize = current_mode.view_xres * current_mode.fb_format / 8UL;
+ return CreateLFBTextBuffer(lfb, lfbformat, current_mode.view_xres, current_mode.view_yres, scansize);
+}
+
+static void TryInitializeDevice(uint32_t devaddr)
+{
+ pciid_t id = PCI::GetDeviceId(devaddr);
+
+ bool is_qemu_bga = id.vendorid == 0x1234 && id.deviceid == 0x1111;
+ bool is_vbox_bga = id.vendorid == 0x80EE && id.deviceid == 0xBEEF;
+
+ (void) is_qemu_bga;
+ (void) is_vbox_bga;
+
+ pcibar_t fb_bar;
+ pcibar_t mmio_bar;
+ addralloc_t fb_alloc;
+ addralloc_t mmio_alloc;
+ bool has_mmio = false;
+ bool fallback_ioport = false;
+
+ fb_bar = PCI::GetBAR(devaddr, 0);
+ if ( !MapPCIBAR(&fb_alloc, fb_bar, MAP_PCI_BAR_WRITE_COMBINE) )
+ {
+ Log::PrintF("[BGA device @ PCI:0x%X] Framebuffer could not be mapped: %s\n",
+ devaddr, strerror(errno));
+ return;
+ }
+
+ if ( is_qemu_bga )
+ mmio_bar = PCI::GetBAR(devaddr, 2);
+
+ if ( is_qemu_bga && mmio_bar.is_mmio() && 4096 <= mmio_bar.size() )
+ {
+ has_mmio = true;
+
+ if ( !MapPCIBAR(&mmio_alloc, mmio_bar, MAP_PCI_BAR_WRITE_COMBINE) )
+ {
+ Log::PrintF("[BGA device @ PCI:0x%X] Memory-mapped registers could not be mapped: %s\n",
+ devaddr, strerror(errno));
+ UnmapPCIBar(&fb_alloc);
+ return;
+ }
+ }
+
+ else
+ {
+ // This device doesn't come with its own set of registers, so we have to
+ // assume that the global BGA io port registers are available and that
+ // only a single such device is present (since two concurrent devices)
+ // could not exist then. This is only available on x86-family systems.
+#if defined(__i386__) || defined(__x86_64__)
+ fallback_ioport = true;
+#endif
+ }
+
+ if ( !has_mmio && !fallback_ioport )
+ {
+ Log::PrintF("[BGA device @ PCI:0x%X] Device provides no registers.\n",
+ devaddr);
+ UnmapPCIBar(&fb_alloc);
+ return;
+ }
+
+ if ( fallback_ioport )
+ memset(&mmio_alloc, 0, sizeof(mmio_alloc));
+
+ BGADevice* bga_device = new BGADevice(devaddr, fb_alloc, mmio_alloc);
+ if ( !bga_device )
+ {
+ Log::PrintF("[BGA device @ PCI:0x%X] Unable to allocate driver structure: %s\n",
+ devaddr, strerror(errno));
+ UnmapPCIBar(&mmio_alloc);
+ UnmapPCIBar(&fb_alloc);
+ return;
+ }
+
+ if ( !bga_device->Initialize() )
+ {
+ delete bga_device;
+ return;
+ }
+
+ if ( !Video::RegisterDevice("bga", bga_device) )
+ {
+ Log::PrintF("[BGA device @ PCI:0x%X] Unable to register device: %s\n",
+ devaddr, strerror(errno));
+ delete bga_device;
+ return;
+ }
+}
+
+void Init()
+{
+ pcifind_t bga_pcifind;
+ memset(&bga_pcifind, 255, sizeof(bga_pcifind));
+ bga_pcifind.vendorid = 0x1234;
+ bga_pcifind.deviceid = 0x1111;
+
+ uint32_t devaddr = 0;
+ while ( (devaddr = PCI::SearchForDevices(bga_pcifind, devaddr)) )
+ TryInitializeDevice(devaddr);
+
+ memset(&bga_pcifind, 255, sizeof(bga_pcifind));
+ bga_pcifind.vendorid = 0x80EE;
+ bga_pcifind.deviceid = 0xBEEF;
+
+ devaddr = 0;
+ while ( (devaddr = PCI::SearchForDevices(bga_pcifind, devaddr)) )
+ TryInitializeDevice(devaddr);
+}
+
+} // namespace BGA
+} // namespace Sortix
diff --git a/kernel/bga.h b/kernel/gpu/bga/bga.h
similarity index 88%
rename from kernel/bga.h
rename to kernel/gpu/bga/bga.h
index bbcc1a6e..4d5fa482 100644
--- a/kernel/bga.h
+++ b/kernel/gpu/bga/bga.h
@@ -1,6 +1,6 @@
/*******************************************************************************
- Copyright(C) Jonas 'Sortie' Termansen 2012.
+ Copyright(C) Jonas 'Sortie' Termansen 2012, 2014.
This file is part of Sortix.
@@ -17,13 +17,13 @@
You should have received a copy of the GNU General Public License along with
Sortix. If not, see .
- bga.h
+ gpu/bga/bga.h
Driver for the Bochs VBE Extensions.
*******************************************************************************/
-#ifndef SORTIX_BGA_H
-#define SORTIX_BGA_H
+#ifndef SORTIX_GPU_BGA_BGA_H
+#define SORTIX_GPU_BGA_BGA_H
namespace Sortix {
namespace BGA {
diff --git a/kernel/include/sortix/display.h b/kernel/include/sortix/display.h
index 9db62ef9..38b43342 100644
--- a/kernel/include/sortix/display.h
+++ b/kernel/include/sortix/display.h
@@ -1,6 +1,6 @@
/*******************************************************************************
- Copyright(C) Jonas 'Sortie' Termansen 2012.
+ Copyright(C) Jonas 'Sortie' Termansen 2012, 2014.
This file is part of Sortix.
@@ -32,6 +32,10 @@
__BEGIN_DECLS
+const uint32_t DISPMSG_CONTROL_VALID = 1 << 0;
+const uint32_t DISPMSG_CONTROL_VGA = 1 << 1;
+const uint32_t DISPMSG_CONTROL_OTHER_RESOLUTIONS = 1 << 2;
+
struct dispmsg_string
{
size_t byte_size; // Including the terminating NUL-byte.
diff --git a/kernel/include/sortix/kernel/video.h b/kernel/include/sortix/kernel/video.h
index 30a70164..d26ae2ff 100644
--- a/kernel/include/sortix/kernel/video.h
+++ b/kernel/include/sortix/kernel/video.h
@@ -1,6 +1,6 @@
/*******************************************************************************
- Copyright(C) Jonas 'Sortie' Termansen 2012.
+ Copyright(C) Jonas 'Sortie' Termansen 2012, 2014.
This file is part of Sortix.
@@ -22,11 +22,14 @@
*******************************************************************************/
-#ifndef SORTIX_VIDEO_H
-#define SORTIX_VIDEO_H
+#ifndef INCLUDE_SORTIX_KERNEL_VIDEO_H
+#define INCLUDE_SORTIX_KERNEL_VIDEO_H
#include
+#include
+
+#include
#include
namespace Sortix {
@@ -34,43 +37,30 @@ namespace Sortix {
class TextBuffer;
class TextBufferHandle;
-bool ReadParamString(const char* str, ...);
-
-class VideoDriver
+class VideoDevice
{
public:
- virtual ~VideoDriver() { }
- virtual bool StartUp() = 0;
- virtual bool ShutDown() = 0;
- virtual char* GetCurrentMode() const = 0;
- virtual bool SwitchMode(const char* mode) = 0;
- virtual bool Supports(const char* mode) const = 0;
- virtual char** GetModes(size_t* nummodes) const = 0;
+ virtual ~VideoDevice() { }
+ virtual struct dispmsg_crtc_mode GetCurrentMode(uint64_t connector) const = 0;
+ virtual bool SwitchMode(uint64_t connector, struct dispmsg_crtc_mode mode) = 0;
+ virtual bool Supports(uint64_t connector, struct dispmsg_crtc_mode mode) const = 0;
+ virtual struct dispmsg_crtc_mode* GetModes(uint64_t connector, size_t* nummodes) const = 0;
virtual off_t FrameSize() const = 0;
- virtual ssize_t WriteAt(off_t off, const void* buf, size_t count) = 0;
- virtual ssize_t ReadAt(off_t off, void* buf, size_t count) = 0;
- virtual TextBuffer* CreateTextBuffer() = 0;
+ virtual ssize_t WriteAt(ioctx_t* ctx, off_t off, const void* buf, size_t count) = 0;
+ virtual ssize_t ReadAt(ioctx_t* ctx, off_t off, void* buf, size_t count) = 0;
+ virtual TextBuffer* CreateTextBuffer(uint64_t connector) = 0;
};
+} // namespace Sortix
+
+namespace Sortix {
namespace Video {
void Init(Ref textbufhandle);
-bool RegisterDriver(const char* name, VideoDriver* driver);
-char* GetCurrentMode();
-char* GetDriverName(size_t index);
-size_t GetCurrentDriverIndex();
-size_t GetNumDrivers();
-size_t LookupDriverIndexOfMode(const char* mode);
-bool Supports(const char* mode);
-bool SwitchMode(const char* mode);
-char** GetModes(size_t* modesnum);
-off_t FrameSize();
-ssize_t WriteAt(off_t off, const void* buf, size_t count);
-ssize_t ReadAt(off_t off, void* buf, size_t count);
+bool RegisterDevice(const char* name, VideoDevice* device);
} // namespace Video
-
} // namespace Sortix
#endif
diff --git a/kernel/kernel.cpp b/kernel/kernel.cpp
index 2d1eedff..3f5cfc41 100644
--- a/kernel/kernel.cpp
+++ b/kernel/kernel.cpp
@@ -70,15 +70,14 @@
#include "alarm.h"
#include "ata.h"
-#include "bga.h"
#include "com.h"
-#include "dispmsg.h"
#include "elf.h"
#include "fs/full.h"
#include "fs/kram.h"
#include "fs/null.h"
#include "fs/user.h"
#include "fs/zero.h"
+#include "gpu/bga/bga.h"
#include "identity.h"
#include "initrd.h"
#include "io.h"
@@ -432,9 +431,6 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
// Initialize the scheduler.
Scheduler::Init();
- // Initialize the Display Message framework.
- DisplayMessage::Init();
-
// Now that the base system has been loaded, it's time to go threaded. First
// we create an object that represents this process.
Ref ptable(new ProcessTable());
diff --git a/kernel/video.cpp b/kernel/video.cpp
index d2044a91..4f88a690 100644
--- a/kernel/video.cpp
+++ b/kernel/video.cpp
@@ -1,6 +1,6 @@
/*******************************************************************************
- Copyright(C) Jonas 'Sortie' Termansen 2012.
+ Copyright(C) Jonas 'Sortie' Termansen 2012, 2014.
This file is part of Sortix.
@@ -26,459 +26,406 @@
#include
#include
+#include
#include
#include
#include
+#include
#include
#include
namespace Sortix {
-
-bool ReadParamString(const char* str, ...)
-{
- if ( strchr(str, '\n') ) { errno = EINVAL; }
- const char* keyname;
- va_list args;
- while ( *str )
- {
- size_t varlen = strcspn(str, ",");
- if ( !varlen ) { str++; continue; }
- size_t namelen = strcspn(str, "=");
- if ( !namelen ) { errno = EINVAL; goto cleanup; }
- if ( !str[namelen] ) { errno = EINVAL; goto cleanup; }
- if ( varlen < namelen ) { errno = EINVAL; goto cleanup; }
- size_t valuelen = varlen - 1 /*=*/ - namelen;
- char* name = String::Substring(str, 0, namelen);
- if ( !name ) { goto cleanup; }
- char* value = String::Substring(str, namelen+1, valuelen);
- if ( !value ) { delete[] name; goto cleanup; }
- va_start(args, str);
- while ( (keyname = va_arg(args, const char*)) )
- {
- if ( strcmp(keyname, "STOP") == 0 )
- break;
- char** nameptr = va_arg(args, char**);
- if ( strcmp(keyname, name) ) { continue; }
- *nameptr = value;
- break;
- }
- va_end(args);
- if ( !keyname ) { delete[] value; }
- delete[] name;
- str += varlen;
- str += strspn(str, ",");
- }
- return true;
-
-cleanup:
- va_start(args, str);
- while ( (keyname = va_arg(args, const char*)) )
- {
- char** nameptr = va_arg(args, char**);
- delete[] *nameptr; *nameptr = NULL;
- }
- va_end(args);
- return false;
-}
-
namespace Video {
-const unsigned long DRIVER_GOT_MODES = (1UL<<0UL);
+const uint64_t ONE_AND_ONLY_DEVICE = 0;
+const uint64_t ONE_AND_ONLY_CONNECTOR = 0;
-struct DriverEntry
+kthread_mutex_t video_lock = KTHREAD_MUTEX_INITIALIZER;
+
+struct DeviceEntry
{
char* name;
- VideoDriver* driver;
- unsigned long flags;
- size_t id;
+ VideoDevice* device;
};
-size_t numdrivers;
-size_t driverslen;
-DriverEntry* drivers;
+size_t num_devices = 0;
+size_t devices_length = 0;
+DeviceEntry* devices = NULL;
-size_t nummodes;
-size_t modeslen;
-char** modes;
-
-char* currentmode;
-size_t currentdrvid;
-bool newdrivers;
-
-kthread_mutex_t videolock;
Ref textbufhandle;
-void Init(Ref thetextbufhandle)
+bool RegisterDevice(const char* name, VideoDevice* device)
{
- videolock = KTHREAD_MUTEX_INITIALIZER;
- textbufhandle = thetextbufhandle;
- numdrivers = driverslen = 0;
- drivers = NULL;
- nummodes = modeslen = 0;
- modes = NULL;
- currentdrvid = SIZE_MAX;
- newdrivers = false;
- currentmode = NULL;
-}
-
-size_t GetCurrentDriverIndex()
-{
- ScopedLock lock(&videolock);
- return currentdrvid;
-}
-
-size_t GetNumDrivers()
-{
- ScopedLock lock(&videolock);
- return numdrivers;
-}
-
-char* GetDriverName(size_t index)
-{
- ScopedLock lock(&videolock);
- if ( numdrivers <= index || !drivers[index].name )
- return String::Clone("none");
- return String::Clone(drivers[index].name);
-}
-
-static DriverEntry* CurrentDriverEntry()
-{
- if ( currentdrvid == SIZE_MAX ) { return NULL; }
- return drivers + currentdrvid;
-}
-
-bool RegisterDriver(const char* name, VideoDriver* driver)
-{
- ScopedLock lock(&videolock);
- if ( numdrivers == driverslen )
+ ScopedLock lock(&video_lock);
+ if ( num_devices == devices_length )
{
- size_t newdriverslen = driverslen ? 2 * driverslen : 8UL;
- DriverEntry* newdrivers = new DriverEntry[newdriverslen];
- if ( !newdrivers ) { return false; }
- memcpy(newdrivers, drivers, sizeof(*drivers) * numdrivers);
- delete[] drivers; drivers = newdrivers;
- driverslen = driverslen;
+ size_t newdevices_length = devices_length ? 2 * devices_length : 8UL;
+ DeviceEntry* newdevices = new DeviceEntry[newdevices_length];
+ if ( !newdevices )
+ return false;
+ memcpy(newdevices, devices, sizeof(*devices) * num_devices);
+ delete[] devices; devices = newdevices;
+ devices_length = devices_length;
}
char* drivername = String::Clone(name);
- if ( !drivername ) { return false; }
-
- size_t index = numdrivers++;
- drivers[index].name = drivername;
- drivers[index].driver = driver;
- drivers[index].flags = 0;
- drivers[index].id = index;
- newdrivers = true;
- return true;
-}
-
-static bool ExpandModesArray(size_t needed)
-{
- size_t modesneeded = nummodes + needed;
- if ( modesneeded <= modeslen ) { return true; }
- size_t newmodeslen = 2 * modeslen;
- if ( newmodeslen < modesneeded ) { newmodeslen = modesneeded; }
- char** newmodes = new char*[newmodeslen];
- if ( !newmodes ) { return false; }
- memcpy(newmodes, modes, sizeof(char*) * nummodes);
- delete[] modes; modes = newmodes;
- modeslen = newmodeslen;
- return true;
-}
-
-static void UpdateModes()
-{
- if ( !newdrivers ) { return; }
- bool allsuccess = true;
- for ( size_t i = 0; i < numdrivers; i++ )
- {
- bool success = false;
- if ( drivers[i].flags & DRIVER_GOT_MODES ) { continue; }
- const char* drivername = drivers[i].name;
- VideoDriver* driver = drivers[i].driver;
- size_t prevnummodes = nummodes;
- size_t drvnummodes = 0;
- char** drvmodes = driver->GetModes(&drvnummodes);
- if ( !drvmodes ) { goto cleanup_error; }
- if ( !ExpandModesArray(drvnummodes) ) { goto cleanup_drvmodes; }
- for ( size_t n = 0; n < drvnummodes; n++ )
- {
- char* modestr = String::Combine(4, "driver=", drivername,
- ",", drvmodes[n]);
- if ( !modestr ) { goto cleanup_newmodes; }
- modes[nummodes++] = modestr;
- }
- success = true;
- drivers[i].flags |= DRIVER_GOT_MODES;
-cleanup_newmodes:
- for ( size_t i = prevnummodes; !success && i < nummodes; i++ )
- delete[] modes[i];
- if ( !success ) { nummodes = prevnummodes; }
-cleanup_drvmodes:
- for ( size_t n = 0; n < drvnummodes; n++ ) { delete[] drvmodes[n]; }
- delete[] drvmodes;
-cleanup_error:
- allsuccess &= success;
- }
- newdrivers = !allsuccess;
-}
-
-static DriverEntry* GetDriverEntry(const char* drivername)
-{
- for ( size_t i = 0; i < numdrivers; i++ )
- {
- if ( !strcmp(drivername, drivers[i].name) )
- {
- return drivers + i;
- }
- }
- errno = ENODRV;
- return NULL;
-}
-
-static bool StartUpDriver(VideoDriver* driver, const char* drivername)
-{
- if ( !driver->StartUp() )
- {
- int errnum = errno;
- Log::PrintF("Error: Video driver '%s' was unable to startup\n",
- drivername);
- errno = errnum;
+ if ( !drivername )
return false;
- }
+
+ size_t index = num_devices++;
+ devices[index].name = drivername;
+ devices[index].device = device;
return true;
}
-static bool ShutDownDriver(VideoDriver* driver, const char* drivername)
+__attribute__((unused))
+static bool TransmitString(struct dispmsg_string* dest, const char* str)
{
- textbufhandle->Replace(NULL);
- if ( !driver->ShutDown() )
- {
- int errnum = errno;
- Log::PrintF("Warning: Video driver '%s' did not shutdown cleanly\n",
- drivername);
- errno = errnum;
- return false;
- }
- return true;
+ size_t size = strlen(str) + 1;
+ size_t dest_size = dest->byte_size;
+ dest->byte_size = size;
+ if ( dest_size < size )
+ return errno = ERANGE, false;
+ return CopyToUser(dest->str, str, size);
}
-static bool DriverModeAction(VideoDriver* driver, const char* drivername,
- const char* mode, const char* action)
+__attribute__((unused))
+static char* ReceiveString(struct dispmsg_string* src)
{
- textbufhandle->Replace(NULL);
- if ( !driver->SwitchMode(mode) )
+ if ( !src->byte_size )
+ return errno = EINVAL, (char*) NULL;
+ char* ret = new char[src->byte_size];
+ if ( !ret )
+ return NULL;
+ if ( !CopyFromUser(ret, src->str, src->byte_size) )
+ return NULL;
+ if ( ret[src->byte_size-1] != '\0' )
{
- int errnum = errno;
- Log::PrintF("Error: Video driver '%s' could not %s mode '%s'\n",
- drivername, action, mode);
- errno = errnum;
- return false;
+ delete[] ret;
+ return errno = EINVAL, (char*) NULL;
}
- textbufhandle->Replace(driver->CreateTextBuffer());
- return true;
+ return ret;
}
-static bool SwitchDriverMode(VideoDriver* driver, const char* drivername,
- const char* mode)
+static int EnumerateDevices(void* ptr, size_t size)
{
- return DriverModeAction(driver, drivername, mode, "switch to");
+ struct dispmsg_enumerate_devices msg;
+ if ( size != sizeof(msg) )
+ return errno = EINVAL, -1;
+ if ( !CopyFromUser(&msg, ptr, sizeof(msg)) )
+ return -1;
+
+ ScopedLock lock(&video_lock);
+
+ size_t requested_num_devices = msg.devices_length;
+ msg.devices_length = num_devices;
+
+ if ( !CopyToUser(ptr, &msg, sizeof(msg)) )
+ return -1;
+
+ if ( requested_num_devices < num_devices )
+ return errno = ERANGE, -1;
+
+ for ( uint64_t i = 0; i < num_devices; i++ )
+ if ( !CopyToUser(&msg.devices[i], &i, sizeof(i)) )
+ return -1;
+
+ return 0;
}
-
-static bool RestoreDriverMode(VideoDriver* driver, const char* drivername,
- const char* mode)
+static int GetDriverCount(void* ptr, size_t size)
{
- return DriverModeAction(driver, drivername, mode, "restore");
+ struct dispmsg_get_driver_count msg;
+ if ( size != sizeof(msg) )
+ return errno = EINVAL, -1;
+ if ( !CopyFromUser(&msg, ptr, sizeof(msg)) )
+ return -1;
+
+ ScopedLock lock(&video_lock);
+
+ if ( num_devices <= msg.device )
+ return errno = ENODEV, -1;
+
+ msg.driver_count = 1;
+
+ if ( !CopyToUser(ptr, &msg, sizeof(msg)) )
+ return -1;
+
+ return 0;
}
-// Attempts to use the specific driver and mode, if an error occurs, it will
-// attempt to reload the previous driver and mode. If that fails, we are kinda
-// screwed and the video adapter is left in an undefined state.
-static bool DoSwitchMode(DriverEntry* newdrvent, const char* newmode)
+static int GetDriverName(void* ptr, size_t size)
{
- DriverEntry* prevdrvent = CurrentDriverEntry();
- VideoDriver* prevdriver = prevdrvent ? prevdrvent->driver : NULL;
- const char* prevdrivername = prevdrvent ? prevdrvent->name : NULL;
+ struct dispmsg_get_driver_name msg;
+ if ( size != sizeof(msg) )
+ return errno = EINVAL, -1;
+ if ( !CopyFromUser(&msg, ptr, sizeof(msg)) )
+ return -1;
- VideoDriver* newdriver = newdrvent->driver;
- const char* newdrivername = newdrvent->name;
+ ScopedLock lock(&video_lock);
- char* newcurrentmode = String::Clone(newmode);
- if ( !newcurrentmode ) { return false; }
+ if ( num_devices <= msg.device )
+ return errno = ENODEV, -1;
- if ( prevdriver == newdriver )
- {
- if ( !SwitchDriverMode(newdriver, newdrivername, newmode) )
- {
- delete[] newcurrentmode;
- return false;
- }
- delete[] currentmode;
- currentmode = newcurrentmode;
- return true;
- }
+ DeviceEntry* device_entry = &devices[msg.device];
+ if ( !TransmitString(&msg.name, device_entry->name) )
+ return -1;
- int errnum = 0;
+ if ( !CopyToUser(ptr, &msg, sizeof(msg)) )
+ return -1;
- if ( prevdriver ) { ShutDownDriver(prevdriver, prevdrivername); }
-
- char* prevmode = currentmode; currentmode = NULL;
- currentdrvid = SIZE_MAX;
-
- if ( !StartUpDriver(newdriver, newdrivername) )
- {
- errnum = errno;
- goto restore_prev_driver;
- }
-
- currentdrvid = newdrvent->id;
-
- if ( !SwitchDriverMode(newdriver, newdrivername, newmode) )
- {
- errnum = errno;
- ShutDownDriver(newdriver, newdrivername);
- currentdrvid = SIZE_MAX;
- goto restore_prev_driver;
- }
-
- currentmode = newcurrentmode;
- delete[] prevmode;
-
- return true;
-
-restore_prev_driver:
- delete[] newcurrentmode;
- if ( !prevdriver ) { goto error_out; }
- if ( !StartUpDriver(prevdriver, prevdrivername) ) { goto error_out; }
-
- currentdrvid = prevdrvent->id;
-
- if ( !RestoreDriverMode(prevdriver, prevdrivername, prevmode) )
- {
- ShutDownDriver(prevdriver, prevdrivername);
- currentdrvid = SIZE_MAX;
- goto error_out;
- }
-
- Log::PrintF("Successfully restored video driver '%s' mode '%s'\n",
- prevdrivername, prevmode);
-
-error_out:
- if ( currentdrvid == SIZE_MAX )
- Log::PrintF("Warning: Could not fall back upon a video driver\n");
- errno = errnum; // Return the original error, not the last one.
- return false;
+ return 0;
}
-char* GetCurrentMode()
+static int GetDriver(void* ptr, size_t size)
{
- ScopedLock lock(&videolock);
- UpdateModes();
- return String::Clone(currentmode ? currentmode : "driver=none");
+ struct dispmsg_get_driver msg;
+ if ( size != sizeof(msg) )
+ return errno = EINVAL, -1;
+ if ( !CopyFromUser(&msg, ptr, sizeof(msg)) )
+ return -1;
+
+ ScopedLock lock(&video_lock);
+
+ if ( num_devices <= msg.device )
+ return errno = ENODEV, -1;
+
+ msg.driver_index = 0;
+
+ if ( !CopyToUser(ptr, &msg, sizeof(msg)) )
+ return -1;
+
+ return 0;
}
-char** GetModes(size_t* modesnum)
+static int SetDriver(void* ptr, size_t size)
{
- ScopedLock lock(&videolock);
- UpdateModes();
- char** result = new char*[nummodes];
- if ( !result ) { return NULL; }
+ struct dispmsg_set_driver msg;
+ if ( size != sizeof(msg) )
+ return errno = EINVAL, -1;
+ if ( !CopyFromUser(&msg, ptr, sizeof(msg)) )
+ return -1;
+
+ ScopedLock lock(&video_lock);
+
+ if ( num_devices <= msg.device )
+ return errno = ENODEV, -1;
+
+ if ( msg.driver_index != 0 )
+ return errno = EINVAL, -1;
+
+ if ( !CopyToUser(ptr, &msg, sizeof(msg)) )
+ return -1;
+
+ return 0;
+}
+
+static int SetCrtcMode(void* ptr, size_t size)
+{
+ struct dispmsg_set_crtc_mode msg;
+ if ( size != sizeof(msg) )
+ return errno = EINVAL, -1;
+ if ( !CopyFromUser(&msg, ptr, sizeof(msg)) )
+ return -1;
+
+ ScopedLock lock(&video_lock);
+
+ if ( num_devices <= msg.device )
+ return errno = ENODEV, -1;
+
+ DeviceEntry* device_entry = &devices[msg.device];
+ VideoDevice* device = device_entry->device;
+ if ( !device->SwitchMode(msg.connector, msg.mode) )
+ return -1;
+
+ // TODO: This could potentially fail.
+ if ( msg.device == ONE_AND_ONLY_DEVICE &&
+ msg.connector == ONE_AND_ONLY_CONNECTOR )
+ textbufhandle->Replace(device->CreateTextBuffer(msg.connector));
+
+ // No need to respond.
+
+ return 0;
+}
+
+static int GetCrtcMode(void* ptr, size_t size)
+{
+ struct dispmsg_get_crtc_mode msg;
+ if ( size != sizeof(msg) )
+ return errno = EINVAL, -1;
+ if ( !CopyFromUser(&msg, ptr, sizeof(msg)) )
+ return -1;
+
+ ScopedLock lock(&video_lock);
+
+ if ( num_devices <= msg.device )
+ return errno = ENODEV, -1;
+
+ DeviceEntry* device_entry = &devices[msg.device];
+ VideoDevice* device = device_entry->device;
+
+ // TODO: There is no real way to detect failure here.
+ errno = 0;
+ struct dispmsg_crtc_mode mode = device->GetCurrentMode(msg.connector);
+ if ( !(mode.control & DISPMSG_CONTROL_VALID) && errno != 0 )
+ return -1;
+
+ msg.mode = mode;
+
+ if ( !CopyToUser(ptr, &msg, sizeof(msg)) )
+ return -1;
+
+ return 0;
+}
+
+static int GetCrtcModes(void* ptr, size_t size)
+{
+ struct dispmsg_get_crtc_modes msg;
+ if ( size != sizeof(msg) )
+ return errno = EINVAL, -1;
+ if ( !CopyFromUser(&msg, ptr, sizeof(msg)) )
+ return -1;
+
+ ScopedLock lock(&video_lock);
+
+ if ( num_devices <= msg.device )
+ return errno = ENODEV, -1;
+
+ DeviceEntry* device_entry = &devices[msg.device];
+ VideoDevice* device = device_entry->device;
+
+ size_t nummodes;
+ struct dispmsg_crtc_mode* modes = device->GetModes(msg.connector, &nummodes);
+ if ( !modes )
+ return -1;
+
+ size_t requested_modes = msg.modes_length;
+ msg.modes_length = nummodes;
+
+ if ( !CopyToUser(ptr, &msg, sizeof(msg)) )
+ return -1;
+
+ if ( requested_modes < nummodes )
+ {
+ delete[] modes;
+ return errno = ERANGE, -1;
+ }
+
for ( size_t i = 0; i < nummodes; i++ )
{
- result[i] = String::Clone(modes[i]);
- if ( !result[i] )
+ if ( !CopyToUser(&msg.modes[i], &modes[i], sizeof(modes[i])) )
{
- for ( size_t j = 0; j < i; j++ )
- {
- delete[] result[j];
- }
- delete[] result;
- return NULL;
+ delete[] modes;
+ return -1;
}
}
- *modesnum = nummodes;
- return result;
+
+ delete[] modes;
+
+
+ return 0;
}
-bool SwitchMode(const char* mode)
+static int GetMemorySize(void* ptr, size_t size)
{
- ScopedLock lock(&videolock);
- UpdateModes();
- char* drivername = NULL;
- if ( !ReadParamString(mode, "driver", &drivername, NULL) ) { return false; }
- if ( !strcmp(drivername, "none") )
+ struct dispmsg_get_memory_size msg;
+ if ( size != sizeof(msg) )
+ return errno = EINVAL, -1;
+ if ( !CopyFromUser(&msg, ptr, sizeof(msg)) )
+ return -1;
+
+ ScopedLock lock(&video_lock);
+
+ if ( num_devices <= msg.device )
+ return errno = ENODEV, -1;
+
+ DeviceEntry* device_entry = &devices[msg.device];
+ VideoDevice* device = device_entry->device;
+
+ msg.memory_size = device->FrameSize();
+
+ if ( !CopyToUser(ptr, &msg, sizeof(msg)) )
+ return -1;
+
+ return 0;
+}
+
+static int WriteMemory(void* ptr, size_t size)
+{
+ struct dispmsg_write_memory msg;
+ if ( size != sizeof(msg) )
+ return errno = EINVAL, -1;
+ if ( !CopyFromUser(&msg, ptr, sizeof(msg)) )
+ return -1;
+
+ ScopedLock lock(&video_lock);
+
+ if ( num_devices <= msg.device )
+ return errno = ENODEV, -1;
+
+ DeviceEntry* device_entry = &devices[msg.device];
+ VideoDevice* device = device_entry->device;
+
+ ioctx_t ctx; SetupUserIOCtx(&ctx);
+ if ( device->WriteAt(&ctx, msg.offset, msg.src, msg.size) < 0 )
+ return -1;
+
+ return 0;
+}
+
+static int ReadMemory(void* ptr, size_t size)
+{
+ struct dispmsg_read_memory msg;
+ if ( size != sizeof(msg) )
+ return errno = EINVAL, -1;
+ if ( !CopyFromUser(&msg, ptr, sizeof(msg)) )
+ return -1;
+
+ ScopedLock lock(&video_lock);
+
+ if ( num_devices <= msg.device )
+ return errno = ENODEV, -1;
+
+ DeviceEntry* device_entry = &devices[msg.device];
+ VideoDevice* device = device_entry->device;
+
+ ioctx_t ctx; SetupUserIOCtx(&ctx);
+ if ( device->ReadAt(&ctx, msg.offset, msg.dst, msg.size) < 0 )
+ return -1;
+
+ return 0;
+}
+
+static int sys_dispmsg_issue(void* ptr, size_t size)
+{
+ struct dispmsg_header hdr;
+ if ( size < sizeof(hdr) )
+ return errno = EINVAL, -1;
+ if ( !CopyFromUser(&hdr, ptr, sizeof(hdr)) )
+ return -1;
+ switch ( hdr.msgid )
{
- DriverEntry* driverentry = CurrentDriverEntry();
- if ( !driverentry )
- return true;
- ShutDownDriver(driverentry->driver, driverentry->name);
- currentdrvid = SIZE_MAX;
- return true;
+ case DISPMSG_ENUMERATE_DEVICES: return EnumerateDevices(ptr, size);
+ case DISPMSG_GET_DRIVER_COUNT: return GetDriverCount(ptr, size);
+ case DISPMSG_GET_DRIVER_NAME: return GetDriverName(ptr, size);
+ case DISPMSG_GET_DRIVER: return GetDriver(ptr, size);
+ case DISPMSG_SET_DRIVER: return SetDriver(ptr, size);
+ case DISPMSG_SET_CRTC_MODE: return SetCrtcMode(ptr, size);
+ case DISPMSG_GET_CRTC_MODE: return GetCrtcMode(ptr, size);
+ case DISPMSG_GET_CRTC_MODES: return GetCrtcModes(ptr, size);
+ case DISPMSG_GET_MEMORY_SIZE: return GetMemorySize(ptr, size);
+ case DISPMSG_WRITE_MEMORY: return WriteMemory(ptr, size);
+ case DISPMSG_READ_MEMORY: return ReadMemory(ptr, size);
+ default:
+ return errno = ENOSYS, -1;
}
- DriverEntry* drvent = GetDriverEntry(drivername);
- delete[] drivername;
- if ( !drvent ) { return false; }
- return DoSwitchMode(drvent, mode);
}
-bool Supports(const char* mode)
+void Init(Ref thetextbufhandle)
{
- ScopedLock lock(&videolock);
- UpdateModes();
- char* drivername = NULL;
- if ( !ReadParamString(mode, "driver", &drivername, NULL) ) { return false; }
- DriverEntry* drvent = GetDriverEntry(drivername);
- delete[] drivername;
- if ( !drvent ) { return false; }
- return drvent->driver->Supports(mode);
-}
-
-size_t LookupDriverIndexOfMode(const char* mode)
-{
- const char* needle = "driver=";
- size_t needlelen = strlen(needle);
- while ( *mode )
- {
- if ( !strncmp(mode, needle, needlelen) )
- {
- const char* name = mode + needlelen;
- size_t namelen = strcspn(name, ",");
- ScopedLock lock(&videolock);
- for ( size_t i = 0; i < numdrivers; i++ )
- if ( !strncmp(drivers[i].name, name, namelen) )
- return i;
- return SIZE_MAX;
- }
- mode += strcspn(mode, ",") + 1;
- }
- return SIZE_MAX;
-}
-
-off_t FrameSize()
-{
- ScopedLock lock(&videolock);
- DriverEntry* drvent = CurrentDriverEntry();
- if ( !drvent ) { errno = EINVAL; return -1; }
- return drvent->driver->FrameSize();
-}
-
-ssize_t WriteAt(off_t off, const void* buf, size_t count)
-{
- ScopedLock lock(&videolock);
- DriverEntry* drvent = CurrentDriverEntry();
- if ( !drvent ) { errno = EINVAL; return -1; }
- return drvent->driver->WriteAt(off, buf, count);
-}
-
-ssize_t ReadAt(off_t off, void* buf, size_t count)
-{
- ScopedLock lock(&videolock);
- DriverEntry* drvent = CurrentDriverEntry();
- if ( !drvent ) { errno = EINVAL; return -1; }
- return drvent->driver->ReadAt(off, buf, count);
+ textbufhandle = thetextbufhandle;
+ Syscall::Register(SYSCALL_DISPMSG_ISSUE, (void*) sys_dispmsg_issue);
}
} // namespace Video
-
} // namespace Sortix