DisplayConnector.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /*
  2. * Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <Kernel/Graphics/DisplayConnector.h>
  7. #include <Kernel/Graphics/GraphicsManagement.h>
  8. #include <LibC/sys/ioctl_numbers.h>
  9. namespace Kernel {
  10. DisplayConnector::DisplayConnector()
  11. : CharacterDevice(226, GraphicsManagement::the().allocate_minor_device_number())
  12. {
  13. }
  14. ErrorOr<Memory::Region*> DisplayConnector::mmap(Process&, OpenFileDescription&, Memory::VirtualRange const&, u64, int, bool)
  15. {
  16. return Error::from_errno(ENOTSUP);
  17. }
  18. ErrorOr<size_t> DisplayConnector::read(OpenFileDescription&, u64, UserOrKernelBuffer&, size_t)
  19. {
  20. return Error::from_errno(ENOTIMPL);
  21. }
  22. ErrorOr<size_t> DisplayConnector::write(OpenFileDescription&, u64 offset, UserOrKernelBuffer const& framebuffer_data, size_t length)
  23. {
  24. SpinlockLocker locker(m_control_lock);
  25. // FIXME: We silently ignore the request if we are in console mode.
  26. // WindowServer is not ready yet to handle errors such as EBUSY currently.
  27. if (console_mode()) {
  28. return length;
  29. }
  30. return write_to_first_surface(offset, framebuffer_data, length);
  31. }
  32. void DisplayConnector::will_be_destroyed()
  33. {
  34. GraphicsManagement::the().detach_display_connector({}, *this);
  35. Device::will_be_destroyed();
  36. }
  37. void DisplayConnector::after_inserting()
  38. {
  39. Device::after_inserting();
  40. GraphicsManagement::the().attach_new_display_connector({}, *this);
  41. }
  42. bool DisplayConnector::console_mode() const
  43. {
  44. VERIFY(m_control_lock.is_locked());
  45. return m_console_mode;
  46. }
  47. void DisplayConnector::set_display_mode(Badge<GraphicsManagement>, DisplayMode mode)
  48. {
  49. SpinlockLocker locker(m_control_lock);
  50. m_console_mode = mode == DisplayMode::Console ? true : false;
  51. if (m_console_mode)
  52. enable_console();
  53. else
  54. disable_console();
  55. }
  56. ErrorOr<void> DisplayConnector::initialize_edid_for_generic_monitor()
  57. {
  58. Array<u8, 128> virtual_monitor_edid = {
  59. 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, /* header */
  60. 0x0, 0x0, /* manufacturer */
  61. 0x00, 0x00, /* product code */
  62. 0x00, 0x00, 0x00, 0x00, /* serial number goes here */
  63. 0x01, /* week of manufacture */
  64. 0x00, /* year of manufacture */
  65. 0x01, 0x03, /* EDID version */
  66. 0x80, /* capabilities - digital */
  67. 0x00, /* horiz. res in cm, zero for projectors */
  68. 0x00, /* vert. res in cm */
  69. 0x78, /* display gamma (120 == 2.2). */
  70. 0xEE, /* features (standby, suspend, off, RGB, std */
  71. /* colour space, preferred timing mode) */
  72. 0xEE, 0x91, 0xA3, 0x54, 0x4C, 0x99, 0x26, 0x0F, 0x50, 0x54,
  73. /* chromaticity for standard colour space. */
  74. 0x00, 0x00, 0x00, /* no default timings */
  75. 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  76. 0x01, 0x01,
  77. 0x01, 0x01, 0x01, 0x01, /* no standard timings */
  78. 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x00, 0x02, 0x02,
  79. 0x02, 0x02,
  80. /* descriptor block 1 goes below */
  81. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  82. /* descriptor block 2, monitor ranges */
  83. 0x00, 0x00, 0x00, 0xFD, 0x00,
  84. 0x00, 0xC8, 0x00, 0xC8, 0x64, 0x00, 0x0A, 0x20, 0x20, 0x20,
  85. 0x20, 0x20,
  86. /* 0-200Hz vertical, 0-200KHz horizontal, 1000MHz pixel clock */
  87. 0x20,
  88. /* descriptor block 3, monitor name */
  89. 0x00, 0x00, 0x00, 0xFC, 0x00,
  90. 'G', 'e', 'n', 'e', 'r', 'i', 'c', 'S', 'c', 'r', 'e', 'e', 'n',
  91. /* descriptor block 4: dummy data */
  92. 0x00, 0x00, 0x00, 0x10, 0x00,
  93. 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20,
  94. 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
  95. 0x20,
  96. 0x00, /* number of extensions */
  97. 0x00 /* checksum goes here */
  98. };
  99. set_edid_bytes(virtual_monitor_edid);
  100. return {};
  101. }
  102. void DisplayConnector::set_edid_bytes(Array<u8, 128> const& edid_bytes)
  103. {
  104. memcpy((u8*)m_edid_bytes, edid_bytes.data(), sizeof(m_edid_bytes));
  105. if (auto parsed_edid = EDID::Parser::from_bytes({ m_edid_bytes, sizeof(m_edid_bytes) }); !parsed_edid.is_error()) {
  106. m_edid_parser = parsed_edid.release_value();
  107. m_edid_valid = true;
  108. } else {
  109. dmesgln("DisplayConnector: Print offending EDID");
  110. for (size_t x = 0; x < 128; x = x + 16) {
  111. dmesgln("{:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x}",
  112. m_edid_bytes[x], m_edid_bytes[x + 1], m_edid_bytes[x + 2], m_edid_bytes[x + 3],
  113. m_edid_bytes[x + 4], m_edid_bytes[x + 5], m_edid_bytes[x + 6], m_edid_bytes[x + 7],
  114. m_edid_bytes[x + 8], m_edid_bytes[x + 9], m_edid_bytes[x + 10], m_edid_bytes[x + 11],
  115. m_edid_bytes[x + 12], m_edid_bytes[x + 13], m_edid_bytes[x + 14], m_edid_bytes[x + 15]);
  116. }
  117. dmesgln("DisplayConnector: Parsing EDID failed: {}", parsed_edid.error());
  118. }
  119. }
  120. ErrorOr<void> DisplayConnector::flush_rectangle(size_t, FBRect const&)
  121. {
  122. return Error::from_errno(ENOTSUP);
  123. }
  124. DisplayConnector::ModeSetting DisplayConnector::current_mode_setting() const
  125. {
  126. SpinlockLocker locker(m_modeset_lock);
  127. return m_current_mode_setting;
  128. }
  129. ErrorOr<ByteBuffer> DisplayConnector::get_edid() const
  130. {
  131. if (!m_edid_valid)
  132. return Error::from_errno(ENOTIMPL);
  133. return ByteBuffer::copy(m_edid_bytes, sizeof(m_edid_bytes));
  134. }
  135. ErrorOr<void> DisplayConnector::ioctl(OpenFileDescription&, unsigned request, Userspace<void*> arg)
  136. {
  137. if (request != GRAPHICS_IOCTL_GET_HEAD_EDID) {
  138. // Allow anyone to query the EDID. Eventually we'll publish the current EDID on /sys
  139. // so it doesn't really make sense to require the video pledge to query it.
  140. TRY(Process::current().require_promise(Pledge::video));
  141. }
  142. // TODO: We really should have ioctls for destroying resources as well
  143. switch (request) {
  144. case GRAPHICS_IOCTL_GET_PROPERTIES: {
  145. auto user_properties = static_ptr_cast<GraphicsConnectorProperties*>(arg);
  146. GraphicsConnectorProperties properties {};
  147. properties.flushing_support = flush_support();
  148. properties.doublebuffer_support = double_framebuffering_capable();
  149. properties.partial_flushing_support = partial_flush_support();
  150. properties.refresh_rate_support = refresh_rate_support();
  151. return copy_to_user(user_properties, &properties);
  152. }
  153. case GRAPHICS_IOCTL_GET_HEAD_MODE_SETTING: {
  154. auto user_head_mode_setting = static_ptr_cast<GraphicsHeadModeSetting*>(arg);
  155. GraphicsHeadModeSetting head_mode_setting {};
  156. TRY(copy_from_user(&head_mode_setting, user_head_mode_setting));
  157. {
  158. SpinlockLocker control_locker(m_control_lock);
  159. head_mode_setting.horizontal_stride = m_current_mode_setting.horizontal_stride;
  160. head_mode_setting.pixel_clock_in_khz = m_current_mode_setting.pixel_clock_in_khz;
  161. head_mode_setting.horizontal_active = m_current_mode_setting.horizontal_active;
  162. head_mode_setting.horizontal_front_porch_pixels = m_current_mode_setting.horizontal_front_porch_pixels;
  163. head_mode_setting.horizontal_sync_time_pixels = m_current_mode_setting.horizontal_sync_time_pixels;
  164. head_mode_setting.horizontal_blank_pixels = m_current_mode_setting.horizontal_blank_pixels;
  165. head_mode_setting.vertical_active = m_current_mode_setting.vertical_active;
  166. head_mode_setting.vertical_front_porch_lines = m_current_mode_setting.vertical_front_porch_lines;
  167. head_mode_setting.vertical_sync_time_lines = m_current_mode_setting.vertical_sync_time_lines;
  168. head_mode_setting.vertical_blank_lines = m_current_mode_setting.vertical_blank_lines;
  169. head_mode_setting.horizontal_offset = m_current_mode_setting.horizontal_offset;
  170. head_mode_setting.vertical_offset = m_current_mode_setting.vertical_offset;
  171. }
  172. return copy_to_user(user_head_mode_setting, &head_mode_setting);
  173. }
  174. case GRAPHICS_IOCTL_GET_HEAD_EDID: {
  175. auto user_head_edid = static_ptr_cast<GraphicsHeadEDID*>(arg);
  176. GraphicsHeadEDID head_edid {};
  177. TRY(copy_from_user(&head_edid, user_head_edid));
  178. auto edid_bytes = TRY(get_edid());
  179. if (head_edid.bytes != nullptr) {
  180. // Only return the EDID if a buffer was provided. Either way,
  181. // we'll write back the bytes_size with the actual size
  182. if (head_edid.bytes_size < edid_bytes.size()) {
  183. head_edid.bytes_size = edid_bytes.size();
  184. TRY(copy_to_user(user_head_edid, &head_edid));
  185. return Error::from_errno(EOVERFLOW);
  186. }
  187. TRY(copy_to_user(head_edid.bytes, (void const*)edid_bytes.data(), edid_bytes.size()));
  188. }
  189. head_edid.bytes_size = edid_bytes.size();
  190. return copy_to_user(user_head_edid, &head_edid);
  191. }
  192. case GRAPHICS_IOCTL_SET_HEAD_MODE_SETTING: {
  193. auto user_mode_setting = static_ptr_cast<GraphicsHeadModeSetting const*>(arg);
  194. auto head_mode_setting = TRY(copy_typed_from_user(user_mode_setting));
  195. if (head_mode_setting.horizontal_stride < 0)
  196. return Error::from_errno(EINVAL);
  197. if (head_mode_setting.pixel_clock_in_khz < 0)
  198. return Error::from_errno(EINVAL);
  199. if (head_mode_setting.horizontal_active < 0)
  200. return Error::from_errno(EINVAL);
  201. if (head_mode_setting.horizontal_front_porch_pixels < 0)
  202. return Error::from_errno(EINVAL);
  203. if (head_mode_setting.horizontal_sync_time_pixels < 0)
  204. return Error::from_errno(EINVAL);
  205. if (head_mode_setting.horizontal_blank_pixels < 0)
  206. return Error::from_errno(EINVAL);
  207. if (head_mode_setting.vertical_active < 0)
  208. return Error::from_errno(EINVAL);
  209. if (head_mode_setting.vertical_front_porch_lines < 0)
  210. return Error::from_errno(EINVAL);
  211. if (head_mode_setting.vertical_sync_time_lines < 0)
  212. return Error::from_errno(EINVAL);
  213. if (head_mode_setting.vertical_blank_lines < 0)
  214. return Error::from_errno(EINVAL);
  215. if (head_mode_setting.horizontal_offset < 0)
  216. return Error::from_errno(EINVAL);
  217. if (head_mode_setting.vertical_offset < 0)
  218. return Error::from_errno(EINVAL);
  219. {
  220. SpinlockLocker control_locker(m_control_lock);
  221. ModeSetting requested_mode_setting;
  222. requested_mode_setting.horizontal_stride = 0;
  223. requested_mode_setting.pixel_clock_in_khz = head_mode_setting.pixel_clock_in_khz;
  224. requested_mode_setting.horizontal_active = head_mode_setting.horizontal_active;
  225. requested_mode_setting.horizontal_front_porch_pixels = head_mode_setting.horizontal_front_porch_pixels;
  226. requested_mode_setting.horizontal_sync_time_pixels = head_mode_setting.horizontal_sync_time_pixels;
  227. requested_mode_setting.horizontal_blank_pixels = head_mode_setting.horizontal_blank_pixels;
  228. requested_mode_setting.vertical_active = head_mode_setting.vertical_active;
  229. requested_mode_setting.vertical_front_porch_lines = head_mode_setting.vertical_front_porch_lines;
  230. requested_mode_setting.vertical_sync_time_lines = head_mode_setting.vertical_sync_time_lines;
  231. requested_mode_setting.vertical_blank_lines = head_mode_setting.vertical_blank_lines;
  232. requested_mode_setting.horizontal_offset = head_mode_setting.horizontal_offset;
  233. requested_mode_setting.vertical_offset = head_mode_setting.vertical_offset;
  234. TRY(set_mode_setting(requested_mode_setting));
  235. }
  236. return {};
  237. }
  238. case GRAPHICS_IOCTL_SET_SAFE_HEAD_MODE_SETTING: {
  239. SpinlockLocker control_locker(m_control_lock);
  240. TRY(set_safe_mode_setting());
  241. return {};
  242. }
  243. case GRAPHICS_IOCTL_SET_HEAD_VERTICAL_OFFSET_BUFFER: {
  244. // FIXME: We silently ignore the request if we are in console mode.
  245. // WindowServer is not ready yet to handle errors such as EBUSY currently.
  246. SpinlockLocker control_locker(m_control_lock);
  247. if (console_mode()) {
  248. return {};
  249. }
  250. auto user_head_vertical_buffer_offset = static_ptr_cast<GraphicsHeadVerticalOffset const*>(arg);
  251. auto head_vertical_buffer_offset = TRY(copy_typed_from_user(user_head_vertical_buffer_offset));
  252. SpinlockLocker locker(m_modeset_lock);
  253. if (head_vertical_buffer_offset.offsetted < 0 || head_vertical_buffer_offset.offsetted > 1)
  254. return Error::from_errno(EINVAL);
  255. TRY(set_y_offset(head_vertical_buffer_offset.offsetted == 0 ? 0 : m_current_mode_setting.vertical_active));
  256. if (head_vertical_buffer_offset.offsetted == 0)
  257. m_vertical_offsetted = false;
  258. else
  259. m_vertical_offsetted = true;
  260. return {};
  261. }
  262. case GRAPHICS_IOCTL_GET_HEAD_VERTICAL_OFFSET_BUFFER: {
  263. auto user_head_vertical_buffer_offset = static_ptr_cast<GraphicsHeadVerticalOffset*>(arg);
  264. GraphicsHeadVerticalOffset head_vertical_buffer_offset {};
  265. TRY(copy_from_user(&head_vertical_buffer_offset, user_head_vertical_buffer_offset));
  266. head_vertical_buffer_offset.offsetted = m_vertical_offsetted;
  267. return copy_to_user(user_head_vertical_buffer_offset, &head_vertical_buffer_offset);
  268. }
  269. case GRAPHICS_IOCTL_FLUSH_HEAD_BUFFERS: {
  270. if (!partial_flush_support())
  271. return Error::from_errno(ENOTSUP);
  272. MutexLocker locker(m_flushing_lock);
  273. auto user_flush_rects = static_ptr_cast<FBFlushRects const*>(arg);
  274. auto flush_rects = TRY(copy_typed_from_user(user_flush_rects));
  275. if (Checked<unsigned>::multiplication_would_overflow(flush_rects.count, sizeof(FBRect)))
  276. return Error::from_errno(EFAULT);
  277. if (flush_rects.count > 0) {
  278. for (unsigned i = 0; i < flush_rects.count; i++) {
  279. FBRect user_dirty_rect;
  280. TRY(copy_from_user(&user_dirty_rect, &flush_rects.rects[i]));
  281. {
  282. SpinlockLocker control_locker(m_control_lock);
  283. if (console_mode()) {
  284. return {};
  285. }
  286. TRY(flush_rectangle(flush_rects.buffer_index, user_dirty_rect));
  287. }
  288. }
  289. }
  290. return {};
  291. };
  292. case GRAPHICS_IOCTL_FLUSH_HEAD: {
  293. // FIXME: We silently ignore the request if we are in console mode.
  294. // WindowServer is not ready yet to handle errors such as EBUSY currently.
  295. MutexLocker locker(m_flushing_lock);
  296. SpinlockLocker control_locker(m_control_lock);
  297. if (console_mode()) {
  298. return {};
  299. }
  300. if (!flush_support())
  301. return Error::from_errno(ENOTSUP);
  302. TRY(flush_first_surface());
  303. return {};
  304. }
  305. }
  306. return EINVAL;
  307. }
  308. }