|
@@ -18,8 +18,16 @@
|
|
|
|
|
|
#include <Kernel/Panic.h>
|
|
|
|
|
|
+#define MAX_RESOLUTION_WIDTH 4096
|
|
|
+#define MAX_RESOLUTION_HEIGHT 2160
|
|
|
+
|
|
|
namespace Kernel {
|
|
|
|
|
|
+NonnullRefPtr<FramebufferDevice> FramebufferDevice::create(const GraphicsDevice& adapter, size_t output_port_index, PhysicalAddress paddr, size_t width, size_t height, size_t pitch)
|
|
|
+{
|
|
|
+ return adopt_ref(*new FramebufferDevice(adapter, output_port_index, paddr, width, height, pitch));
|
|
|
+}
|
|
|
+
|
|
|
KResultOr<Region*> FramebufferDevice::mmap(Process& process, FileDescription&, const Range& range, u64 offset, int prot, bool shared)
|
|
|
{
|
|
|
ScopedSpinLock lock(m_activation_lock);
|
|
@@ -103,12 +111,14 @@ UNMAP_AFTER_INIT void FramebufferDevice::initialize()
|
|
|
VERIFY(m_swapped_framebuffer_region);
|
|
|
}
|
|
|
|
|
|
-UNMAP_AFTER_INIT FramebufferDevice::FramebufferDevice(PhysicalAddress addr, size_t width, size_t height, size_t pitch)
|
|
|
+UNMAP_AFTER_INIT FramebufferDevice::FramebufferDevice(const GraphicsDevice& adapter, size_t output_port_index, PhysicalAddress addr, size_t width, size_t height, size_t pitch)
|
|
|
: BlockDevice(29, GraphicsManagement::the().allocate_minor_device_number())
|
|
|
, m_framebuffer_address(addr)
|
|
|
, m_framebuffer_pitch(pitch)
|
|
|
, m_framebuffer_width(width)
|
|
|
, m_framebuffer_height(height)
|
|
|
+ , m_output_port_index(output_port_index)
|
|
|
+ , m_graphics_adapter(adapter)
|
|
|
{
|
|
|
VERIFY(!m_framebuffer_address.is_null());
|
|
|
VERIFY(m_framebuffer_pitch);
|
|
@@ -117,9 +127,11 @@ UNMAP_AFTER_INIT FramebufferDevice::FramebufferDevice(PhysicalAddress addr, size
|
|
|
dbgln("Framebuffer {}: address={}, pitch={}, width={}, height={}", minor(), addr, pitch, width, height);
|
|
|
}
|
|
|
|
|
|
-bool FramebufferDevice::set_resolution(size_t, size_t, size_t)
|
|
|
+size_t FramebufferDevice::framebuffer_size_in_bytes() const
|
|
|
{
|
|
|
- VERIFY_NOT_REACHED();
|
|
|
+ if (m_graphics_adapter->double_framebuffering_capable())
|
|
|
+ return m_framebuffer_pitch * m_framebuffer_height * 2;
|
|
|
+ return m_framebuffer_pitch * m_framebuffer_height;
|
|
|
}
|
|
|
|
|
|
int FramebufferDevice::ioctl(FileDescription&, unsigned request, FlatPtr arg)
|
|
@@ -134,7 +146,21 @@ int FramebufferDevice::ioctl(FileDescription&, unsigned request, FlatPtr arg)
|
|
|
return 0;
|
|
|
}
|
|
|
case FB_IOCTL_GET_BUFFER: {
|
|
|
- return -ENOTIMPL;
|
|
|
+ auto* index = (int*)arg;
|
|
|
+ int value = m_y_offset == 0 ? 0 : 1;
|
|
|
+ if (!copy_to_user(index, &value))
|
|
|
+ return -EFAULT;
|
|
|
+ if (!m_graphics_adapter->double_framebuffering_capable())
|
|
|
+ return -ENOTIMPL;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ case FB_IOCTL_SET_BUFFER: {
|
|
|
+ if (arg != 0 && arg != 1)
|
|
|
+ return -EINVAL;
|
|
|
+ if (!m_graphics_adapter->double_framebuffering_capable())
|
|
|
+ return -ENOTIMPL;
|
|
|
+ m_graphics_adapter->set_y_offset(m_output_port_index, arg == 0 ? 0 : m_framebuffer_height);
|
|
|
+ return 0;
|
|
|
}
|
|
|
case FB_IOCTL_GET_RESOLUTION: {
|
|
|
auto* user_resolution = (FBResolution*)arg;
|
|
@@ -149,6 +175,39 @@ int FramebufferDevice::ioctl(FileDescription&, unsigned request, FlatPtr arg)
|
|
|
case FB_IOCTL_SET_RESOLUTION: {
|
|
|
auto* user_resolution = (FBResolution*)arg;
|
|
|
FBResolution resolution;
|
|
|
+ if (!copy_from_user(&resolution, user_resolution))
|
|
|
+ return -EFAULT;
|
|
|
+ if (resolution.width > MAX_RESOLUTION_WIDTH || resolution.height > MAX_RESOLUTION_HEIGHT)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (!m_graphics_adapter->modesetting_capable()) {
|
|
|
+ resolution.pitch = m_framebuffer_pitch;
|
|
|
+ resolution.width = m_framebuffer_width;
|
|
|
+ resolution.height = m_framebuffer_height;
|
|
|
+ if (!copy_to_user(user_resolution, &resolution))
|
|
|
+ return -EFAULT;
|
|
|
+ return -ENOTIMPL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!m_graphics_adapter->try_to_set_resolution(m_output_port_index, resolution.width, resolution.height)) {
|
|
|
+ m_framebuffer_pitch = m_framebuffer_width * sizeof(u32);
|
|
|
+ dbgln_if(FRAMEBUFFER_DEVICE_DEBUG, "Reverting resolution: [{}x{}]", m_framebuffer_width, m_framebuffer_height);
|
|
|
+ // Note: We try to revert everything back, and if it doesn't work, just assert.
|
|
|
+ if (!m_graphics_adapter->try_to_set_resolution(m_output_port_index, m_framebuffer_width, m_framebuffer_height)) {
|
|
|
+ VERIFY_NOT_REACHED();
|
|
|
+ }
|
|
|
+ resolution.pitch = m_framebuffer_pitch;
|
|
|
+ resolution.width = m_framebuffer_width;
|
|
|
+ resolution.height = m_framebuffer_height;
|
|
|
+ if (!copy_to_user(user_resolution, &resolution))
|
|
|
+ return -EFAULT;
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ m_framebuffer_width = resolution.width;
|
|
|
+ m_framebuffer_height = resolution.height;
|
|
|
+ m_framebuffer_pitch = m_framebuffer_width * sizeof(u32);
|
|
|
+
|
|
|
+ dbgln_if(FRAMEBUFFER_DEVICE_DEBUG, "New resolution: [{}x{}]", m_framebuffer_width, m_framebuffer_height);
|
|
|
resolution.pitch = m_framebuffer_pitch;
|
|
|
resolution.width = m_framebuffer_width;
|
|
|
resolution.height = m_framebuffer_height;
|