GenericFramebufferDevice.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. /*
  2. * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Checked.h>
  7. #include <AK/Try.h>
  8. #include <Kernel/API/POSIX/errno.h>
  9. #include <Kernel/Debug.h>
  10. #include <Kernel/Devices/DeviceManagement.h>
  11. #include <Kernel/Graphics/FramebufferDevice.h>
  12. #include <Kernel/Graphics/GraphicsManagement.h>
  13. #include <Kernel/Memory/AnonymousVMObject.h>
  14. #include <Kernel/Memory/MemoryManager.h>
  15. #include <Kernel/Process.h>
  16. #include <Kernel/Sections.h>
  17. #include <Kernel/StdLib.h>
  18. #define MAX_RESOLUTION_WIDTH 4096
  19. #define MAX_RESOLUTION_HEIGHT 2160
  20. namespace Kernel {
  21. ErrorOr<void> GenericFramebufferDevice::verify_head_index(int head_index) const
  22. {
  23. if (head_index < 0)
  24. return Error::from_errno(EINVAL);
  25. if (!multihead_support() && head_index > 0)
  26. return Error::from_errno(ENOTSUP);
  27. return {};
  28. }
  29. ErrorOr<void> GenericFramebufferDevice::ioctl(OpenFileDescription&, unsigned request, Userspace<void*> arg)
  30. {
  31. REQUIRE_PROMISE(video);
  32. switch (request) {
  33. case FB_IOCTL_GET_PROPERTIES: {
  34. auto user_properties = static_ptr_cast<FBProperties*>(arg);
  35. FBProperties properties {};
  36. auto adapter = m_graphics_adapter.strong_ref();
  37. if (!adapter)
  38. return Error::from_errno(EIO);
  39. properties.multihead_support = multihead_support();
  40. properties.flushing_support = flushing_support();
  41. properties.doublebuffer_support = adapter->double_framebuffering_capable();
  42. properties.partial_flushing_support = partial_flushing_support();
  43. return copy_to_user(user_properties, &properties);
  44. }
  45. case FB_IOCTL_GET_HEAD_PROPERTIES: {
  46. auto user_head_properties = static_ptr_cast<FBHeadProperties*>(arg);
  47. FBHeadProperties head_properties {};
  48. TRY(copy_from_user(&head_properties, user_head_properties));
  49. TRY(verify_head_index(head_properties.head_index));
  50. head_properties.pitch = TRY(pitch(head_properties.head_index));
  51. head_properties.width = TRY(width(head_properties.head_index));
  52. head_properties.height = TRY(height(head_properties.head_index));
  53. head_properties.buffer_length = TRY(buffer_length(head_properties.head_index));
  54. head_properties.offset = TRY(vertical_offset(head_properties.head_index));
  55. return copy_to_user(user_head_properties, &head_properties);
  56. }
  57. case FB_IOCTL_SET_HEAD_RESOLUTION: {
  58. auto user_head_resolution = static_ptr_cast<FBHeadResolution const*>(arg);
  59. auto head_resolution = TRY(copy_typed_from_user(user_head_resolution));
  60. TRY(verify_head_index(head_resolution.head_index));
  61. if (head_resolution.pitch < 0)
  62. return Error::from_errno(EINVAL);
  63. if (head_resolution.width < 0)
  64. return Error::from_errno(EINVAL);
  65. if (head_resolution.height < 0)
  66. return Error::from_errno(EINVAL);
  67. TRY(set_head_resolution(head_resolution.head_index, head_resolution.width, head_resolution.height, head_resolution.pitch));
  68. return {};
  69. }
  70. case FB_IOCTL_SET_HEAD_VERTICAL_OFFSET_BUFFER: {
  71. auto user_head_vertical_buffer_offset = static_ptr_cast<FBHeadVerticalOffset const*>(arg);
  72. auto head_vertical_buffer_offset = TRY(copy_typed_from_user(user_head_vertical_buffer_offset));
  73. TRY(verify_head_index(head_vertical_buffer_offset.head_index));
  74. if (head_vertical_buffer_offset.offsetted < 0 || head_vertical_buffer_offset.offsetted > 1)
  75. return Error::from_errno(EINVAL);
  76. TRY(set_head_buffer(head_vertical_buffer_offset.head_index, head_vertical_buffer_offset.offsetted));
  77. return {};
  78. }
  79. case FB_IOCTL_GET_HEAD_VERTICAL_OFFSET_BUFFER: {
  80. auto user_head_vertical_buffer_offset = static_ptr_cast<FBHeadVerticalOffset*>(arg);
  81. FBHeadVerticalOffset head_vertical_buffer_offset {};
  82. TRY(copy_from_user(&head_vertical_buffer_offset, user_head_vertical_buffer_offset));
  83. TRY(verify_head_index(head_vertical_buffer_offset.head_index));
  84. head_vertical_buffer_offset.offsetted = TRY(vertical_offsetted(head_vertical_buffer_offset.head_index));
  85. return copy_to_user(user_head_vertical_buffer_offset, &head_vertical_buffer_offset);
  86. }
  87. case FB_IOCTL_FLUSH_HEAD_BUFFERS: {
  88. if (!partial_flushing_support())
  89. return Error::from_errno(ENOTSUP);
  90. auto user_flush_rects = static_ptr_cast<FBFlushRects const*>(arg);
  91. auto flush_rects = TRY(copy_typed_from_user(user_flush_rects));
  92. if (Checked<unsigned>::multiplication_would_overflow(flush_rects.count, sizeof(FBRect)))
  93. return Error::from_errno(EFAULT);
  94. MutexLocker locker(m_flushing_lock);
  95. if (flush_rects.count > 0) {
  96. for (unsigned i = 0; i < flush_rects.count; i++) {
  97. FBRect user_dirty_rect;
  98. TRY(copy_from_user(&user_dirty_rect, &flush_rects.rects[i]));
  99. TRY(flush_rectangle(flush_rects.buffer_index, user_dirty_rect));
  100. }
  101. }
  102. return {};
  103. };
  104. case FB_IOCTL_FLUSH_HEAD: {
  105. if (!flushing_support())
  106. return Error::from_errno(ENOTSUP);
  107. // Note: We accept a FBRect, but we only really care about the head_index value.
  108. auto user_rect = static_ptr_cast<FBRect const*>(arg);
  109. auto rect = TRY(copy_typed_from_user(user_rect));
  110. TRY(verify_head_index(rect.head_index));
  111. TRY(flush_head_buffer(rect.head_index));
  112. return {};
  113. }
  114. default:
  115. return EINVAL;
  116. };
  117. }
  118. GenericFramebufferDevice::GenericFramebufferDevice(const GenericGraphicsAdapter& adapter)
  119. : BlockDevice(29, GraphicsManagement::the().allocate_minor_device_number())
  120. , m_graphics_adapter(adapter)
  121. {
  122. }
  123. }