EDID.cpp 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122
  1. /*
  2. * Copyright (c) 2022, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Concepts.h>
  7. #include <AK/Function.h>
  8. #include <AK/QuickSort.h>
  9. #include <AK/Try.h>
  10. #include <LibEDID/EDID.h>
  11. #ifdef KERNEL
  12. # include <Kernel/Library/StdLib.h>
  13. #else
  14. # include <AK/ScopeGuard.h>
  15. # include <fcntl.h>
  16. # include <sys/devices/gpu.h>
  17. # include <unistd.h>
  18. # if ENABLE_PNP_IDS_DATA
  19. # include <LibEDID/PnpIDs.h>
  20. # endif
  21. #endif
  22. namespace EDID {
  23. // clang doesn't like passing around pointers to members in packed structures,
  24. // even though we're only using them for arithmetic purposes
  25. #if defined(AK_COMPILER_CLANG)
  26. # pragma clang diagnostic ignored "-Waddress-of-packed-member"
  27. #endif
  28. static_assert(sizeof(Definitions::EDID) == Parser::BufferSize);
  29. class CEA861ExtensionBlock final {
  30. friend class Parser;
  31. public:
  32. enum class DataBlockTag : u8 {
  33. Reserved = 0,
  34. Audio,
  35. Video,
  36. VendorSpecific,
  37. SpeakerAllocation,
  38. VesaDTC,
  39. Reserved2,
  40. Extended
  41. };
  42. ErrorOr<IterationDecision> for_each_short_video_descriptor(Function<IterationDecision(bool, VIC::Details const&)> callback) const
  43. {
  44. return for_each_data_block([&](DataBlockTag tag, ReadonlyBytes bytes) -> ErrorOr<IterationDecision> {
  45. if (tag != DataBlockTag::Video)
  46. return IterationDecision::Continue;
  47. // Short video descriptors are one byte values
  48. for (size_t i = 0; i < bytes.size(); i++) {
  49. u8 byte = m_edid.read_host(&bytes[i]);
  50. bool is_native = (byte & 0x80) != 0;
  51. u8 vic_id = byte & 0x7f;
  52. auto* vic_details = VIC::find_details_by_vic_id(vic_id);
  53. if (!vic_details)
  54. return Error::from_string_view_or_print_error_and_return_errno("CEA 861 extension block has invalid short video descriptor"sv, EINVAL);
  55. IterationDecision decision = callback(is_native, *vic_details);
  56. if (decision != IterationDecision::Continue)
  57. return decision;
  58. }
  59. return IterationDecision::Continue;
  60. });
  61. }
  62. ErrorOr<IterationDecision> for_each_dtd(Function<IterationDecision(Parser::DetailedTiming const&)> callback) const
  63. {
  64. u8 dtd_start = m_edid.read_host(&m_block->cea861extension.dtd_start_offset);
  65. if (dtd_start < 4) {
  66. // dtd_start == 4 means there are no data blocks, but there are still DTDs
  67. return IterationDecision::Continue;
  68. }
  69. if (dtd_start > offsetof(Definitions::ExtensionBlock, checksum) - sizeof(Definitions::DetailedTiming))
  70. return Error::from_string_view_or_print_error_and_return_errno("CEA 861 extension block has invalid DTD list"sv, EINVAL);
  71. for (size_t offset = dtd_start; offset <= offsetof(Definitions::ExtensionBlock, checksum) - sizeof(Definitions::DetailedTiming); offset += sizeof(Definitions::DetailedTiming)) {
  72. auto& dtd = *(Definitions::DetailedTiming const*)((u8 const*)m_block + offset);
  73. if (m_edid.read_host(&dtd.pixel_clock) == 0)
  74. break;
  75. IterationDecision decision = callback(Parser::DetailedTiming(m_edid, &dtd));
  76. if (decision != IterationDecision::Continue)
  77. return decision;
  78. }
  79. return IterationDecision::Continue;
  80. }
  81. private:
  82. CEA861ExtensionBlock(Parser const& edid, Definitions::ExtensionBlock const* block)
  83. : m_edid(edid)
  84. , m_block(block)
  85. {
  86. }
  87. ErrorOr<IterationDecision> for_each_data_block(Function<ErrorOr<IterationDecision>(DataBlockTag, ReadonlyBytes)> callback) const
  88. {
  89. u8 dtd_start = m_edid.read_host(&m_block->cea861extension.dtd_start_offset);
  90. if (dtd_start <= 4)
  91. return IterationDecision::Continue;
  92. if (dtd_start > offsetof(Definitions::ExtensionBlock, checksum))
  93. return Error::from_string_view_or_print_error_and_return_errno("CEA 861 extension block has invalid DTD start offset"sv, EINVAL);
  94. auto* data_block_header = &m_block->cea861extension.bytes[0];
  95. auto* data_block_end = (u8 const*)m_block + dtd_start;
  96. while (data_block_header < data_block_end) {
  97. auto header_byte = m_edid.read_host(data_block_header);
  98. size_t payload_size = header_byte & 0x1f;
  99. auto tag = (DataBlockTag)((header_byte >> 5) & 0x7);
  100. if (tag == DataBlockTag::Extended && payload_size == 0)
  101. return Error::from_string_view_or_print_error_and_return_errno("CEA 861 extension block has invalid extended data block size"sv, EINVAL);
  102. auto decision = TRY(callback(tag, m_edid.m_bytes.slice(data_block_header - m_edid.m_bytes.data() + 1, payload_size)));
  103. if (decision != IterationDecision::Continue)
  104. return decision;
  105. data_block_header += 1 + payload_size;
  106. }
  107. return IterationDecision::Continue;
  108. }
  109. ErrorOr<IterationDecision> for_each_display_descriptor(Function<IterationDecision(u8, Definitions::DisplayDescriptor const&)> callback) const
  110. {
  111. u8 dtd_start = m_edid.read_host(&m_block->cea861extension.dtd_start_offset);
  112. if (dtd_start <= 4)
  113. return IterationDecision::Continue;
  114. if (dtd_start > offsetof(Definitions::ExtensionBlock, checksum) - sizeof(Definitions::DetailedTiming))
  115. return Error::from_string_view_or_print_error_and_return_errno("CEA 861 extension block has invalid DTD list"sv, EINVAL);
  116. for (size_t offset = dtd_start; offset <= offsetof(Definitions::ExtensionBlock, checksum) - sizeof(Definitions::DisplayDescriptor); offset += sizeof(Definitions::DisplayDescriptor)) {
  117. auto& dd = *(Definitions::DisplayDescriptor const*)((u8 const*)m_block + offset);
  118. if (m_edid.read_host(&dd.zero) != 0 || m_edid.read_host(&dd.reserved1) != 0)
  119. continue;
  120. u8 tag = m_edid.read_host(&dd.tag);
  121. IterationDecision decision = callback(tag, dd);
  122. if (decision != IterationDecision::Continue)
  123. return decision;
  124. }
  125. return IterationDecision::Continue;
  126. }
  127. Parser const& m_edid;
  128. Definitions::ExtensionBlock const* m_block;
  129. };
  130. template<typename T>
  131. T Parser::read_host(T const* field) const
  132. {
  133. VERIFY((u8 const*)field >= m_bytes.data() && (u8 const*)field + sizeof(T) <= m_bytes.data() + m_bytes.size());
  134. size_t offset = (u8 const*)field - m_bytes.data();
  135. T value;
  136. if constexpr (sizeof(T) > 1)
  137. ByteReader::load(m_bytes.offset(offset), value);
  138. else
  139. value = m_bytes.at(offset);
  140. return value;
  141. }
  142. template<Integral T>
  143. requires(sizeof(T) > 1)
  144. T Parser::read_le(T const* field) const
  145. {
  146. static_assert(sizeof(T) > 1);
  147. return AK::convert_between_host_and_little_endian(read_host(field));
  148. }
  149. template<Integral T>
  150. requires(sizeof(T) > 1)
  151. T Parser::read_be(T const* field) const
  152. {
  153. static_assert(sizeof(T) > 1);
  154. return AK::convert_between_host_and_big_endian(read_host(field));
  155. }
  156. ErrorOr<Parser> Parser::from_bytes(ReadonlyBytes bytes)
  157. {
  158. Parser edid(bytes);
  159. TRY(edid.parse());
  160. return edid;
  161. }
  162. ErrorOr<Parser> Parser::from_bytes(ByteBuffer&& bytes)
  163. {
  164. Parser edid(move(bytes));
  165. TRY(edid.parse());
  166. return edid;
  167. }
  168. #ifndef KERNEL
  169. ErrorOr<Parser> Parser::from_display_connector_device(int display_connector_fd)
  170. {
  171. RawBytes edid_bytes;
  172. GraphicsHeadEDID edid_info {};
  173. edid_info.bytes = &edid_bytes[0];
  174. edid_info.bytes_size = sizeof(edid_bytes);
  175. if (graphics_connector_get_head_edid(display_connector_fd, &edid_info) < 0) {
  176. int err = errno;
  177. if (err == EOVERFLOW) {
  178. // We need a bigger buffer with at least bytes_size bytes
  179. auto edid_byte_buffer = TRY(ByteBuffer::create_zeroed(edid_info.bytes_size));
  180. edid_info.bytes = edid_byte_buffer.data();
  181. if (graphics_connector_get_head_edid(display_connector_fd, &edid_info) < 0) {
  182. err = errno;
  183. return Error::from_errno(err);
  184. }
  185. return from_bytes(move(edid_byte_buffer));
  186. }
  187. return Error::from_errno(err);
  188. }
  189. auto edid_byte_buffer = TRY(ByteBuffer::copy((void const*)edid_bytes, sizeof(edid_bytes)));
  190. return from_bytes(move(edid_byte_buffer));
  191. }
  192. ErrorOr<Parser> Parser::from_display_connector_device(ByteString const& display_connector_device)
  193. {
  194. int display_connector_fd = open(display_connector_device.characters(), O_RDWR | O_CLOEXEC);
  195. if (display_connector_fd < 0) {
  196. int err = errno;
  197. return Error::from_errno(err);
  198. }
  199. ScopeGuard fd_guard([&] {
  200. close(display_connector_fd);
  201. });
  202. return from_display_connector_device(display_connector_fd);
  203. }
  204. #endif
  205. Parser::Parser(ReadonlyBytes bytes)
  206. : m_bytes(move(bytes))
  207. {
  208. }
  209. Parser::Parser(ByteBuffer&& bytes)
  210. : m_bytes_buffer(move(bytes))
  211. , m_bytes(m_bytes_buffer)
  212. {
  213. }
  214. Parser::Parser(Parser const& other)
  215. : m_bytes_buffer(other.m_bytes_buffer)
  216. , m_revision(other.m_revision)
  217. {
  218. if (m_bytes_buffer.is_empty())
  219. m_bytes = other.m_bytes_buffer; // We don't own the buffer
  220. else
  221. m_bytes = m_bytes_buffer; // We own the buffer
  222. }
  223. Parser& Parser::operator=(Parser&& from)
  224. {
  225. m_bytes_buffer = move(from.m_bytes_buffer);
  226. m_bytes = move(from.m_bytes);
  227. m_revision = from.m_revision;
  228. return *this;
  229. }
  230. Parser& Parser::operator=(Parser const& other)
  231. {
  232. if (this == &other)
  233. return *this;
  234. m_bytes_buffer = other.m_bytes_buffer;
  235. if (m_bytes_buffer.is_empty())
  236. m_bytes = other.m_bytes_buffer; // We don't own the buffer
  237. else
  238. m_bytes = m_bytes_buffer; // We own the buffer
  239. m_revision = other.m_revision;
  240. return *this;
  241. }
  242. bool Parser::operator==(Parser const& other) const
  243. {
  244. if (this == &other)
  245. return true;
  246. return m_bytes == other.m_bytes;
  247. }
  248. Definitions::EDID const& Parser::raw_edid() const
  249. {
  250. return *(Definitions::EDID const*)m_bytes.data();
  251. }
  252. ErrorOr<void> Parser::parse()
  253. {
  254. if (m_bytes.size() < sizeof(Definitions::EDID))
  255. return Error::from_string_view_or_print_error_and_return_errno("Incomplete Parser structure"sv, EINVAL);
  256. auto const& edid = raw_edid();
  257. u64 header = read_le(&edid.header);
  258. if (header != 0x00ffffffffffff00ull)
  259. return Error::from_string_view_or_print_error_and_return_errno("No Parser header"sv, EINVAL);
  260. u8 major_version = read_host(&edid.version.version);
  261. m_revision = read_host(&edid.version.revision);
  262. if (major_version != 1 || m_revision > 4)
  263. return Error::from_string_view_or_print_error_and_return_errno("Unsupported Parser version"sv, EINVAL);
  264. #ifdef KERNEL
  265. m_version = TRY(Kernel::KString::formatted("1.{}", (int)m_revision));
  266. #else
  267. m_version = ByteString::formatted("1.{}", (int)m_revision);
  268. #endif
  269. u8 checksum = 0x0;
  270. for (size_t i = 0; i < sizeof(Definitions::EDID); i++)
  271. checksum += m_bytes[i];
  272. if (checksum != 0) {
  273. if (m_revision >= 4)
  274. return Error::from_string_view_or_print_error_and_return_errno("Parser checksum mismatch"sv, EINVAL);
  275. else
  276. dbgln("EDID checksum mismatch, data may be corrupted!");
  277. }
  278. u16 packed_id = read_be(&raw_edid().vendor.manufacturer_id);
  279. if (packed_id == 0x0)
  280. return {};
  281. m_legacy_manufacturer_id[0] = (char)((u16)'A' + ((packed_id >> 10) & 0x1f) - 1);
  282. m_legacy_manufacturer_id[1] = (char)((u16)'A' + ((packed_id >> 5) & 0x1f) - 1);
  283. m_legacy_manufacturer_id[2] = (char)((u16)'A' + (packed_id & 0x1f) - 1);
  284. m_legacy_manufacturer_id[3] = '\0';
  285. m_legacy_manufacturer_id_valid = true;
  286. return {};
  287. }
  288. ErrorOr<IterationDecision> Parser::for_each_extension_block(Function<IterationDecision(unsigned, u8, u8, ReadonlyBytes)> callback) const
  289. {
  290. auto& edid = raw_edid();
  291. u8 raw_extension_block_count = read_host(&edid.extension_block_count);
  292. if (raw_extension_block_count == 0)
  293. return IterationDecision::Continue;
  294. if (sizeof(Definitions::EDID) + (size_t)raw_extension_block_count * sizeof(Definitions::ExtensionBlock) > m_bytes.size())
  295. return Error::from_string_view_or_print_error_and_return_errno("Truncated EDID"sv, EINVAL);
  296. auto validate_block_checksum = [&](Definitions::ExtensionBlock const& block) {
  297. u8 checksum = 0x0;
  298. auto* bytes = (u8 const*)&block;
  299. for (size_t i = 0; i < sizeof(block); i++)
  300. checksum += bytes[i];
  301. return checksum == 0;
  302. };
  303. auto* raw_extension_blocks = (Definitions::ExtensionBlock const*)(m_bytes.data() + sizeof(Definitions::EDID));
  304. Definitions::ExtensionBlock const* current_extension_map = nullptr;
  305. unsigned raw_index = 0;
  306. if (m_revision <= 3) {
  307. if (raw_extension_block_count > 1) {
  308. current_extension_map = &raw_extension_blocks[0];
  309. raw_index++;
  310. if (read_host(&current_extension_map->tag) != (u8)Definitions::ExtensionBlockTag::ExtensionBlockMap)
  311. return Error::from_string_view_or_print_error_and_return_errno("Did not find extension map at block 1"sv, EINVAL);
  312. if (!validate_block_checksum(*current_extension_map))
  313. return Error::from_string_view_or_print_error_and_return_errno("Extension block map checksum mismatch"sv, EINVAL);
  314. }
  315. } else if (read_host(&raw_extension_blocks[0].tag) == (u8)Definitions::ExtensionBlockTag::ExtensionBlockMap) {
  316. current_extension_map = &raw_extension_blocks[0];
  317. raw_index++;
  318. }
  319. for (; raw_index < raw_extension_block_count; raw_index++) {
  320. auto& raw_block = raw_extension_blocks[raw_index];
  321. u8 tag = read_host(&raw_block.tag);
  322. if (current_extension_map && raw_index == 127) {
  323. if (tag != (u8)Definitions::ExtensionBlockTag::ExtensionBlockMap)
  324. return Error::from_string_view_or_print_error_and_return_errno("Did not find extension map at block 128"sv, EINVAL);
  325. current_extension_map = &raw_extension_blocks[127];
  326. if (!validate_block_checksum(*current_extension_map))
  327. return Error::from_string_view_or_print_error_and_return_errno("Extension block map checksum mismatch"sv, EINVAL);
  328. continue;
  329. }
  330. if (tag == (u8)Definitions::ExtensionBlockTag::ExtensionBlockMap)
  331. return Error::from_string_view_or_print_error_and_return_errno("Unexpected extension map encountered"sv, EINVAL);
  332. if (!validate_block_checksum(raw_block))
  333. return Error::from_string_view_or_print_error_and_return_errno("Extension block checksum mismatch"sv, EINVAL);
  334. size_t offset = (u8 const*)&raw_block - m_bytes.data();
  335. IterationDecision decision = callback(raw_index + 1, tag, raw_block.block.revision, m_bytes.slice(offset, sizeof(Definitions::ExtensionBlock)));
  336. if (decision != IterationDecision::Continue)
  337. return decision;
  338. }
  339. return IterationDecision::Continue;
  340. }
  341. StringView Parser::version() const
  342. {
  343. #ifdef KERNEL
  344. return m_version->view();
  345. #else
  346. return m_version;
  347. #endif
  348. }
  349. StringView Parser::legacy_manufacturer_id() const
  350. {
  351. return { m_legacy_manufacturer_id, strlen(m_legacy_manufacturer_id) };
  352. }
  353. #ifndef KERNEL
  354. ByteString Parser::manufacturer_name() const
  355. {
  356. if (!m_legacy_manufacturer_id_valid)
  357. return "Unknown";
  358. auto manufacturer_id = legacy_manufacturer_id();
  359. # if ENABLE_PNP_IDS_DATA
  360. if (auto pnp_id_data = PnpIDs::find_by_manufacturer_id(manufacturer_id); pnp_id_data.has_value())
  361. return pnp_id_data.value().manufacturer_name;
  362. # endif
  363. return manufacturer_id;
  364. }
  365. #endif
  366. u16 Parser::product_code() const
  367. {
  368. return read_le(&raw_edid().vendor.product_code);
  369. }
  370. u32 Parser::serial_number() const
  371. {
  372. return read_le(&raw_edid().vendor.serial_number);
  373. }
  374. auto Parser::digital_display() const -> Optional<DigitalDisplay>
  375. {
  376. auto& edid = raw_edid();
  377. u8 video_input_definition = read_host(&edid.basic_display_parameters.video_input_definition);
  378. if (!(video_input_definition & 0x80))
  379. return {}; // This is an analog display
  380. u8 feature_support = read_host(&edid.basic_display_parameters.feature_support);
  381. return DigitalDisplay(video_input_definition, feature_support, m_revision);
  382. }
  383. auto Parser::analog_display() const -> Optional<AnalogDisplay>
  384. {
  385. auto& edid = raw_edid();
  386. u8 video_input_definition = read_host(&edid.basic_display_parameters.video_input_definition);
  387. if ((video_input_definition & 0x80) != 0)
  388. return {}; // This is a digital display
  389. u8 feature_support = read_host(&edid.basic_display_parameters.feature_support);
  390. return AnalogDisplay(video_input_definition, feature_support, m_revision);
  391. }
  392. auto Parser::screen_size() const -> Optional<ScreenSize>
  393. {
  394. auto& edid = raw_edid();
  395. u8 horizontal_size_or_aspect_ratio = read_host(&edid.basic_display_parameters.horizontal_size_or_aspect_ratio);
  396. u8 vertical_size_or_aspect_ratio = read_host(&edid.basic_display_parameters.vertical_size_or_aspect_ratio);
  397. if (horizontal_size_or_aspect_ratio == 0 || vertical_size_or_aspect_ratio == 0) {
  398. // EDID < 1.4: Unknown or undefined
  399. // EDID >= 1.4: If both are 0 it is unknown or undefined
  400. // If one of them is 0 then we're dealing with aspect ratios
  401. return {};
  402. }
  403. return ScreenSize(horizontal_size_or_aspect_ratio, vertical_size_or_aspect_ratio);
  404. }
  405. auto Parser::aspect_ratio() const -> Optional<ScreenAspectRatio>
  406. {
  407. if (m_revision < 4)
  408. return {};
  409. auto& edid = raw_edid();
  410. u8 value_1 = read_host(&edid.basic_display_parameters.horizontal_size_or_aspect_ratio);
  411. u8 value_2 = read_host(&edid.basic_display_parameters.vertical_size_or_aspect_ratio);
  412. if (value_1 == 0 && value_2 == 0)
  413. return {}; // Unknown or undefined
  414. if (value_1 != 0 && value_2 != 0)
  415. return {}; // Dimensions are in cm
  416. if (value_1 == 0)
  417. return ScreenAspectRatio(ScreenAspectRatio::Orientation::Portrait, FixedPoint<16>(100) / FixedPoint<16>((i32)value_2 + 99));
  418. VERIFY(value_2 == 0);
  419. return ScreenAspectRatio(ScreenAspectRatio::Orientation::Landscape, FixedPoint<16>((i32)value_1 + 99) / 100);
  420. }
  421. Optional<FixedPoint<16>> Parser::gamma() const
  422. {
  423. u8 display_transfer_characteristics = read_host(&raw_edid().basic_display_parameters.display_transfer_characteristics);
  424. if (display_transfer_characteristics == 0xff) {
  425. if (m_revision < 4)
  426. return {};
  427. // TODO: EDID >= 1.4 stores more gamma details in an extension block (e.g. DI-EXT)
  428. return {};
  429. }
  430. FixedPoint<16> gamma { (i32)display_transfer_characteristics + 100 };
  431. gamma /= 100;
  432. return gamma;
  433. }
  434. u32 Parser::DetailedTiming::pixel_clock_khz() const
  435. {
  436. // Note: The stored value is in units of 10 kHz, which means that to get the
  437. // value in kHz, we need to multiply it by 10.
  438. return (u32)m_edid.read_le(&m_detailed_timings.pixel_clock) * 10;
  439. }
  440. u16 Parser::DetailedTiming::horizontal_addressable_pixels() const
  441. {
  442. u8 low = m_edid.read_host(&m_detailed_timings.horizontal_addressable_pixels_low);
  443. u8 high = m_edid.read_host(&m_detailed_timings.horizontal_addressable_and_blanking_pixels_high) >> 4;
  444. return ((u16)high << 8) | (u16)low;
  445. }
  446. u16 Parser::DetailedTiming::horizontal_blanking_pixels() const
  447. {
  448. u8 low = m_edid.read_host(&m_detailed_timings.horizontal_blanking_pixels_low);
  449. u8 high = m_edid.read_host(&m_detailed_timings.horizontal_addressable_and_blanking_pixels_high) & 0xf;
  450. return ((u16)high << 8) | (u16)low;
  451. }
  452. u16 Parser::DetailedTiming::vertical_addressable_lines_raw() const
  453. {
  454. u8 low = m_edid.read_host(&m_detailed_timings.vertical_addressable_lines_low);
  455. u8 high = m_edid.read_host(&m_detailed_timings.vertical_addressable_and_blanking_lines_high) >> 4;
  456. return ((u16)high << 8) | (u16)low;
  457. }
  458. u16 Parser::DetailedTiming::vertical_addressable_lines() const
  459. {
  460. auto lines = vertical_addressable_lines_raw();
  461. return is_interlaced() ? lines * 2 : lines;
  462. }
  463. u16 Parser::DetailedTiming::vertical_blanking_lines() const
  464. {
  465. u8 low = m_edid.read_host(&m_detailed_timings.vertical_blanking_lines_low);
  466. u8 high = m_edid.read_host(&m_detailed_timings.vertical_addressable_and_blanking_lines_high) & 0xf;
  467. return ((u16)high << 8) | (u16)low;
  468. }
  469. u16 Parser::DetailedTiming::horizontal_front_porch_pixels() const
  470. {
  471. u8 low = m_edid.read_host(&m_detailed_timings.horizontal_front_porch_pixels_low);
  472. u8 high = m_edid.read_host(&m_detailed_timings.horizontal_and_vertical_front_porch_sync_pulse_width_high) >> 6;
  473. return ((u16)high << 8) | (u16)low;
  474. }
  475. u16 Parser::DetailedTiming::horizontal_sync_pulse_width_pixels() const
  476. {
  477. u8 low = m_edid.read_host(&m_detailed_timings.horizontal_sync_pulse_width_pixels_low);
  478. u8 high = (m_edid.read_host(&m_detailed_timings.horizontal_and_vertical_front_porch_sync_pulse_width_high) >> 4) & 3;
  479. return ((u16)high << 8) | (u16)low;
  480. }
  481. u16 Parser::DetailedTiming::vertical_front_porch_lines() const
  482. {
  483. u8 low = m_edid.read_host(&m_detailed_timings.vertical_front_porch_and_sync_pulse_width_lines_low) >> 4;
  484. u8 high = (m_edid.read_host(&m_detailed_timings.horizontal_and_vertical_front_porch_sync_pulse_width_high) >> 2) & 3;
  485. return ((u16)high << 4) | (u16)low;
  486. }
  487. u16 Parser::DetailedTiming::vertical_sync_pulse_width_lines() const
  488. {
  489. u8 low = m_edid.read_host(&m_detailed_timings.vertical_front_porch_and_sync_pulse_width_lines_low) & 0xf;
  490. u8 high = m_edid.read_host(&m_detailed_timings.horizontal_and_vertical_front_porch_sync_pulse_width_high) & 3;
  491. return ((u16)high << 4) | (u16)low;
  492. }
  493. u16 Parser::DetailedTiming::horizontal_image_size_mm() const
  494. {
  495. u8 low = m_edid.read_host(&m_detailed_timings.horizontal_addressable_image_size_mm_low);
  496. u8 high = m_edid.read_host(&m_detailed_timings.horizontal_vertical_addressable_image_size_mm_high) >> 4;
  497. return ((u16)high << 8) | (u16)low;
  498. }
  499. u16 Parser::DetailedTiming::vertical_image_size_mm() const
  500. {
  501. u8 low = m_edid.read_host(&m_detailed_timings.vertical_addressable_image_size_mm_low);
  502. u8 high = m_edid.read_host(&m_detailed_timings.horizontal_vertical_addressable_image_size_mm_high) & 0xf;
  503. return ((u16)high << 8) | (u16)low;
  504. }
  505. u8 Parser::DetailedTiming::horizontal_right_or_left_border_pixels() const
  506. {
  507. return m_edid.read_host(&m_detailed_timings.right_or_left_horizontal_border_pixels);
  508. }
  509. u8 Parser::DetailedTiming::vertical_top_or_bottom_border_lines() const
  510. {
  511. return m_edid.read_host(&m_detailed_timings.top_or_bottom_vertical_border_lines);
  512. }
  513. bool Parser::DetailedTiming::is_interlaced() const
  514. {
  515. return (m_edid.read_host(&m_detailed_timings.features) & (1 << 7)) != 0;
  516. }
  517. FixedPoint<16, u32> Parser::DetailedTiming::refresh_rate() const
  518. {
  519. // Blanking = front porch + sync pulse width + back porch
  520. u32 total_horizontal_pixels = (u32)horizontal_addressable_pixels() + (u32)horizontal_blanking_pixels();
  521. u32 total_vertical_lines = (u32)vertical_addressable_lines_raw() + (u32)vertical_blanking_lines();
  522. u32 total_pixels = total_horizontal_pixels * total_vertical_lines;
  523. if (total_pixels == 0)
  524. return {};
  525. // Use a bigger fixed point representation due to the large numbers involved and then downcast
  526. // Note: We need to convert the pixel clock from kHz to Hertz to actually calculate this correctly.
  527. return FixedPoint<32, u64>(pixel_clock_khz() * 1000) / total_pixels;
  528. }
  529. ErrorOr<IterationDecision> Parser::for_each_established_timing(Function<IterationDecision(EstablishedTiming const&)> callback) const
  530. {
  531. static constexpr EstablishedTiming established_timing_byte1[8] = {
  532. { EstablishedTiming::Source::VESA, 800, 600, 60, 0x9 },
  533. { EstablishedTiming::Source::VESA, 800, 600, 56, 0x8 },
  534. { EstablishedTiming::Source::VESA, 640, 480, 75, 0x6 },
  535. { EstablishedTiming::Source::VESA, 640, 480, 73, 0x5 },
  536. { EstablishedTiming::Source::Apple, 640, 480, 67 },
  537. { EstablishedTiming::Source::IBM, 640, 480, 60, 0x4 },
  538. { EstablishedTiming::Source::IBM, 720, 400, 88 },
  539. { EstablishedTiming::Source::IBM, 720, 400, 70 }
  540. };
  541. static constexpr EstablishedTiming established_timing_byte2[8] = {
  542. { EstablishedTiming::Source::VESA, 1280, 1024, 75, 0x24 },
  543. { EstablishedTiming::Source::VESA, 1024, 768, 75, 0x12 },
  544. { EstablishedTiming::Source::VESA, 1024, 768, 70, 0x11 },
  545. { EstablishedTiming::Source::VESA, 1024, 768, 60, 0x10 },
  546. { EstablishedTiming::Source::IBM, 1024, 768, 87, 0xf },
  547. { EstablishedTiming::Source::Apple, 832, 624, 75 },
  548. { EstablishedTiming::Source::VESA, 800, 600, 75, 0xb },
  549. { EstablishedTiming::Source::VESA, 800, 600, 72, 0xa }
  550. };
  551. static constexpr EstablishedTiming established_timing_byte3[1] = {
  552. { EstablishedTiming::Source::Apple, 1152, 870, 75 }
  553. };
  554. auto& established_timings = raw_edid().established_timings;
  555. for (int i = 7; i >= 0; i--) {
  556. if (!(established_timings.timings_1 & (1 << i)))
  557. continue;
  558. IterationDecision decision = callback(established_timing_byte1[i]);
  559. if (decision != IterationDecision::Continue)
  560. return decision;
  561. }
  562. for (int i = 7; i >= 0; i--) {
  563. if (!(established_timings.timings_2 & (1 << i)))
  564. continue;
  565. IterationDecision decision = callback(established_timing_byte2[i]);
  566. if (decision != IterationDecision::Continue)
  567. return decision;
  568. }
  569. if ((established_timings.manufacturer_reserved & (1 << 7)) != 0) {
  570. IterationDecision decision = callback(established_timing_byte3[0]);
  571. if (decision != IterationDecision::Continue)
  572. return decision;
  573. }
  574. u8 manufacturer_specific = established_timings.manufacturer_reserved & 0x7f;
  575. if (manufacturer_specific != 0) {
  576. IterationDecision decision = callback(EstablishedTiming(EstablishedTiming::Source::Manufacturer, 0, 0, manufacturer_specific));
  577. if (decision != IterationDecision::Continue)
  578. return decision;
  579. }
  580. auto callback_decision = IterationDecision::Continue;
  581. TRY(for_each_display_descriptor([&](u8 descriptor_tag, auto& display_descriptor) {
  582. if (descriptor_tag != (u8)Definitions::DisplayDescriptorTag::EstablishedTimings3)
  583. return IterationDecision::Continue;
  584. static constexpr EstablishedTiming established_timings3_bytes[] = {
  585. // Byte 1
  586. { EstablishedTiming::Source::VESA, 640, 350, 85, 0x1 },
  587. { EstablishedTiming::Source::VESA, 640, 400, 85, 0x2 },
  588. { EstablishedTiming::Source::VESA, 720, 400, 85, 0x3 },
  589. { EstablishedTiming::Source::VESA, 640, 480, 85, 0x7 },
  590. { EstablishedTiming::Source::VESA, 848, 480, 60, 0xe },
  591. { EstablishedTiming::Source::VESA, 800, 600, 85, 0xc },
  592. { EstablishedTiming::Source::VESA, 1024, 768, 85, 0x13 },
  593. { EstablishedTiming::Source::VESA, 1152, 864, 75, 0x15 },
  594. // Byte 2
  595. { EstablishedTiming::Source::VESA, 1280, 768, 60, 0x16 },
  596. { EstablishedTiming::Source::VESA, 1280, 768, 60, 0x17 },
  597. { EstablishedTiming::Source::VESA, 1280, 768, 75, 0x18 },
  598. { EstablishedTiming::Source::VESA, 1280, 768, 85, 0x19 },
  599. { EstablishedTiming::Source::VESA, 1280, 960, 60, 0x20 },
  600. { EstablishedTiming::Source::VESA, 1280, 960, 85, 0x21 },
  601. { EstablishedTiming::Source::VESA, 1280, 1024, 60, 0x23 },
  602. { EstablishedTiming::Source::VESA, 1280, 1024, 85, 0x25 },
  603. // Byte 3
  604. { EstablishedTiming::Source::VESA, 1360, 768, 60, 0x27 },
  605. { EstablishedTiming::Source::VESA, 1440, 900, 60, 0x2e },
  606. { EstablishedTiming::Source::VESA, 1440, 900, 60, 0x2f },
  607. { EstablishedTiming::Source::VESA, 1440, 900, 75, 0x30 },
  608. { EstablishedTiming::Source::VESA, 1440, 900, 85, 0x31 },
  609. { EstablishedTiming::Source::VESA, 1400, 1050, 60, 0x29 },
  610. { EstablishedTiming::Source::VESA, 1400, 1050, 60, 0x2a },
  611. { EstablishedTiming::Source::VESA, 1400, 1050, 75, 0x2b },
  612. // Byte 4
  613. { EstablishedTiming::Source::VESA, 1400, 1050, 85, 0x2c },
  614. { EstablishedTiming::Source::VESA, 1680, 1050, 60, 0x39 },
  615. { EstablishedTiming::Source::VESA, 1680, 1050, 60, 0x3a },
  616. { EstablishedTiming::Source::VESA, 1680, 1050, 75, 0x3b },
  617. { EstablishedTiming::Source::VESA, 1680, 1050, 85, 0x3c },
  618. { EstablishedTiming::Source::VESA, 1600, 1200, 60, 0x33 },
  619. { EstablishedTiming::Source::VESA, 1600, 1200, 65, 0x34 },
  620. { EstablishedTiming::Source::VESA, 1600, 1200, 70, 0x35 },
  621. // Byte 5
  622. { EstablishedTiming::Source::VESA, 1600, 1200, 75, 0x36 },
  623. { EstablishedTiming::Source::VESA, 1600, 1200, 85, 0x37 },
  624. { EstablishedTiming::Source::VESA, 1792, 1344, 60, 0x3e },
  625. { EstablishedTiming::Source::VESA, 1792, 1344, 75, 0x3f },
  626. { EstablishedTiming::Source::VESA, 1856, 1392, 60, 0x41 },
  627. { EstablishedTiming::Source::VESA, 1856, 1392, 75, 0x42 },
  628. { EstablishedTiming::Source::VESA, 1920, 1200, 60, 0x44 },
  629. { EstablishedTiming::Source::VESA, 1920, 1200, 60, 0x45 },
  630. // Byte 6
  631. { EstablishedTiming::Source::VESA, 1920, 1200, 75, 0x46 },
  632. { EstablishedTiming::Source::VESA, 1920, 1200, 85, 0x47 },
  633. { EstablishedTiming::Source::VESA, 1920, 1440, 60, 0x49 },
  634. { EstablishedTiming::Source::VESA, 1920, 1440, 75, 0x4a }
  635. // Reserved
  636. };
  637. size_t byte_index = 0;
  638. for (u8 dmt_bits : display_descriptor.established_timings3.dmt_bits) {
  639. for (int i = 7; i >= 0; i--) {
  640. if ((dmt_bits & (1 << i)) == 0)
  641. continue;
  642. size_t table_index = byte_index * 8 + (size_t)(7 - i);
  643. if (table_index >= (sizeof(established_timings3_bytes) + 7) / sizeof(established_timings3_bytes[0]))
  644. break; // Sometimes reserved bits are set
  645. callback_decision = callback(established_timings3_bytes[table_index]);
  646. if (callback_decision != IterationDecision::Continue)
  647. return IterationDecision::Break;
  648. }
  649. byte_index++;
  650. }
  651. return IterationDecision::Break; // Only process one descriptor
  652. }));
  653. return callback_decision;
  654. }
  655. ErrorOr<IterationDecision> Parser::for_each_standard_timing(Function<IterationDecision(StandardTiming const&)> callback) const
  656. {
  657. for (size_t index = 0; index < 8; index++) {
  658. auto& standard_timings = raw_edid().standard_timings[index];
  659. if (standard_timings.horizontal_8_pixels == 0x1 && standard_timings.ratio_and_refresh_rate == 0x1)
  660. continue; // Skip unused records
  661. u16 width = 8 * ((u16)read_host(&standard_timings.horizontal_8_pixels) + 31);
  662. u8 aspect_ratio_and_refresh_rate = read_host(&standard_timings.ratio_and_refresh_rate);
  663. u8 refresh_rate = (aspect_ratio_and_refresh_rate & 0x3f) + 60;
  664. u16 height;
  665. StandardTiming::AspectRatio aspect_ratio;
  666. switch ((aspect_ratio_and_refresh_rate >> 6) & 3) {
  667. case 0:
  668. height = (width * 10) / 16;
  669. aspect_ratio = StandardTiming::AspectRatio::AR_16_10;
  670. break;
  671. case 1:
  672. height = (width * 3) / 4;
  673. aspect_ratio = StandardTiming::AspectRatio::AR_4_3;
  674. break;
  675. case 2:
  676. height = (width * 4) / 5;
  677. aspect_ratio = StandardTiming::AspectRatio::AR_5_4;
  678. break;
  679. case 3:
  680. height = (width * 9) / 16;
  681. aspect_ratio = StandardTiming::AspectRatio::AR_16_9;
  682. break;
  683. default:
  684. VERIFY_NOT_REACHED();
  685. }
  686. auto* dmt = DMT::find_timing_by_std_id(standard_timings.horizontal_8_pixels, standard_timings.ratio_and_refresh_rate);
  687. IterationDecision decision = callback(StandardTiming(width, height, refresh_rate, aspect_ratio, dmt ? dmt->dmt_id : 0));
  688. if (decision != IterationDecision::Continue)
  689. return decision;
  690. }
  691. return IterationDecision::Continue;
  692. }
  693. u16 Parser::CoordinatedVideoTiming::horizontal_addressable_pixels() const
  694. {
  695. u32 aspect_h, aspect_v;
  696. switch (aspect_ratio()) {
  697. case AspectRatio::AR_4_3:
  698. aspect_h = 4;
  699. aspect_v = 3;
  700. break;
  701. case AspectRatio::AR_16_9:
  702. aspect_h = 16;
  703. aspect_v = 9;
  704. break;
  705. case AspectRatio::AR_16_10:
  706. aspect_h = 16;
  707. aspect_v = 10;
  708. break;
  709. case AspectRatio::AR_15_9:
  710. aspect_h = 15;
  711. aspect_v = 9;
  712. break;
  713. }
  714. // Round down to nearest cell as per 3.10.3.8
  715. return (u16)(8 * ((((u32)vertical_addressable_lines() * aspect_h) / aspect_v) / 8));
  716. }
  717. u16 Parser::CoordinatedVideoTiming::vertical_addressable_lines() const
  718. {
  719. return ((u16)(m_cvt.bytes[1] >> 4) << 8) | (u16)m_cvt.bytes[0];
  720. }
  721. auto Parser::CoordinatedVideoTiming::aspect_ratio() const -> AspectRatio
  722. {
  723. return (AspectRatio)((m_cvt.bytes[2] >> 2) & 0x3);
  724. }
  725. u16 Parser::CoordinatedVideoTiming::preferred_refresh_rate()
  726. {
  727. switch ((m_cvt.bytes[2] >> 5) & 3) {
  728. case 0:
  729. return 50;
  730. case 1:
  731. return 60;
  732. case 2:
  733. return 75;
  734. case 3:
  735. return 85;
  736. default:
  737. VERIFY_NOT_REACHED();
  738. }
  739. }
  740. ErrorOr<IterationDecision> Parser::for_each_coordinated_video_timing(Function<IterationDecision(CoordinatedVideoTiming const&)> callback) const
  741. {
  742. return for_each_display_descriptor([&](u8 descriptor_tag, Definitions::DisplayDescriptor const& display_descriptor) {
  743. if (descriptor_tag != (u8)Definitions::DisplayDescriptorTag::CVTTimingCodes)
  744. return IterationDecision::Continue;
  745. u8 version = read_host(&display_descriptor.coordinated_video_timings.version);
  746. if (version != 1) {
  747. dbgln("Unsupported CVT display descriptor version: {}", version);
  748. return IterationDecision::Continue;
  749. }
  750. for (size_t i = 0; i < 4; i++) {
  751. const DMT::CVT cvt {
  752. {
  753. read_host(&display_descriptor.coordinated_video_timings.cvt[i][0]),
  754. read_host(&display_descriptor.coordinated_video_timings.cvt[i][1]),
  755. read_host(&display_descriptor.coordinated_video_timings.cvt[i][2]),
  756. }
  757. };
  758. if (cvt.bytes[0] == 0 && cvt.bytes[1] == 0 && cvt.bytes[2] == 0)
  759. continue;
  760. IterationDecision decision = callback(CoordinatedVideoTiming(cvt));
  761. if (decision != IterationDecision::Continue)
  762. return decision;
  763. }
  764. return IterationDecision::Continue;
  765. });
  766. }
  767. ErrorOr<IterationDecision> Parser::for_each_detailed_timing(Function<IterationDecision(DetailedTiming const&, unsigned)> callback) const
  768. {
  769. auto& edid = raw_edid();
  770. for (size_t raw_index = 0; raw_index < 4; raw_index++) {
  771. if (raw_index == 0 || read_le(&edid.detailed_timing_or_display_descriptors[raw_index].detailed_timing.pixel_clock) != 0) {
  772. IterationDecision decision = callback(DetailedTiming(*this, &edid.detailed_timing_or_display_descriptors[raw_index].detailed_timing), 0);
  773. if (decision != IterationDecision::Continue)
  774. return decision;
  775. }
  776. }
  777. Optional<Error> extension_error;
  778. auto result = TRY(for_each_extension_block([&](u8 block_id, u8 tag, u8, ReadonlyBytes bytes) {
  779. if (tag != (u8)Definitions::ExtensionBlockTag::CEA_861)
  780. return IterationDecision::Continue;
  781. CEA861ExtensionBlock cea861(*this, (Definitions::ExtensionBlock const*)bytes.data());
  782. auto result = cea861.for_each_dtd([&](auto& dtd) {
  783. return callback(dtd, block_id);
  784. });
  785. if (result.is_error()) {
  786. dbgln("Failed to iterate DTDs in CEA861 extension block: {}", result.error());
  787. extension_error = result.release_error();
  788. return IterationDecision::Break;
  789. }
  790. return result.value();
  791. }));
  792. if (extension_error.has_value())
  793. return extension_error.release_value();
  794. return result;
  795. }
  796. auto Parser::detailed_timing(size_t index) const -> Optional<DetailedTiming>
  797. {
  798. Optional<DetailedTiming> found_dtd;
  799. auto result = for_each_detailed_timing([&](DetailedTiming const& dtd, unsigned) {
  800. if (index == 0) {
  801. found_dtd = dtd;
  802. return IterationDecision::Break;
  803. }
  804. index--;
  805. return IterationDecision::Continue;
  806. });
  807. if (result.is_error()) {
  808. dbgln("Error getting Parser detailed timing #{}: {}", index, result.error());
  809. return {};
  810. }
  811. return found_dtd;
  812. }
  813. ErrorOr<IterationDecision> Parser::for_each_short_video_descriptor(Function<IterationDecision(unsigned, bool, VIC::Details const&)> callback) const
  814. {
  815. Optional<Error> extension_error;
  816. auto result = for_each_extension_block([&](u8 block_id, u8 tag, u8, ReadonlyBytes bytes) {
  817. if (tag != (u8)Definitions::ExtensionBlockTag::CEA_861)
  818. return IterationDecision::Continue;
  819. CEA861ExtensionBlock cea861(*this, (Definitions::ExtensionBlock const*)bytes.data());
  820. auto result = cea861.for_each_short_video_descriptor([&](bool is_native, VIC::Details const& vic) {
  821. return callback(block_id, is_native, vic);
  822. });
  823. if (result.is_error()) {
  824. extension_error = result.release_error();
  825. return IterationDecision::Break;
  826. }
  827. return result.value();
  828. });
  829. if (result.is_error()) {
  830. dbgln("Failed to iterate Parser extension blocks: {}", result.error());
  831. return IterationDecision::Break;
  832. }
  833. return result.value();
  834. }
  835. ErrorOr<IterationDecision> Parser::for_each_display_descriptor(Function<IterationDecision(u8, Definitions::DisplayDescriptor const&)> callback) const
  836. {
  837. auto& edid = raw_edid();
  838. for (size_t raw_index = 1; raw_index < 4; raw_index++) {
  839. auto& display_descriptor = edid.detailed_timing_or_display_descriptors[raw_index].display_descriptor;
  840. if (read_le(&display_descriptor.zero) != 0 || read_host(&display_descriptor.reserved1) != 0)
  841. continue;
  842. u8 tag = read_host(&display_descriptor.tag);
  843. IterationDecision decision = callback(tag, display_descriptor);
  844. if (decision != IterationDecision::Continue)
  845. return decision;
  846. }
  847. Optional<Error> extension_error;
  848. auto result = TRY(for_each_extension_block([&](u8, u8 tag, u8, ReadonlyBytes bytes) {
  849. if (tag != (u8)Definitions::ExtensionBlockTag::CEA_861)
  850. return IterationDecision::Continue;
  851. CEA861ExtensionBlock cea861(*this, (Definitions::ExtensionBlock const*)bytes.data());
  852. auto result = cea861.for_each_display_descriptor([&](u8 tag, auto& display_descriptor) {
  853. return callback(tag, display_descriptor);
  854. });
  855. if (result.is_error()) {
  856. dbgln("Failed to iterate display descriptors in CEA861 extension block: {}", result.error());
  857. extension_error = result.release_error();
  858. return IterationDecision::Break;
  859. }
  860. return result.value();
  861. }));
  862. if (extension_error.has_value())
  863. return extension_error.release_value();
  864. return result;
  865. }
  866. #ifndef KERNEL
  867. ByteString Parser::display_product_name() const
  868. {
  869. ByteString product_name;
  870. auto result = for_each_display_descriptor([&](u8 descriptor_tag, Definitions::DisplayDescriptor const& display_descriptor) {
  871. if (descriptor_tag != (u8)Definitions::DisplayDescriptorTag::DisplayProductName)
  872. return IterationDecision::Continue;
  873. StringBuilder str;
  874. for (u8 byte : display_descriptor.display_product_name.ascii_name) {
  875. if (byte == 0xa)
  876. break;
  877. str.append((char)byte);
  878. }
  879. product_name = str.to_byte_string();
  880. return IterationDecision::Break;
  881. });
  882. if (result.is_error()) {
  883. dbgln("Failed to locate product name display descriptor: {}", result.error());
  884. return {};
  885. }
  886. return product_name;
  887. }
  888. ByteString Parser::display_product_serial_number() const
  889. {
  890. ByteString product_name;
  891. auto result = for_each_display_descriptor([&](u8 descriptor_tag, Definitions::DisplayDescriptor const& display_descriptor) {
  892. if (descriptor_tag != (u8)Definitions::DisplayDescriptorTag::DisplayProductSerialNumber)
  893. return IterationDecision::Continue;
  894. StringBuilder str;
  895. for (u8 byte : display_descriptor.display_product_serial_number.ascii_str) {
  896. if (byte == 0xa)
  897. break;
  898. str.append((char)byte);
  899. }
  900. product_name = str.to_byte_string();
  901. return IterationDecision::Break;
  902. });
  903. if (result.is_error()) {
  904. dbgln("Failed to locate product name display descriptor: {}", result.error());
  905. return {};
  906. }
  907. return product_name;
  908. }
  909. #endif
  910. auto Parser::supported_resolutions() const -> ErrorOr<Vector<SupportedResolution>>
  911. {
  912. Vector<SupportedResolution> resolutions;
  913. auto add_resolution = [&](unsigned width, unsigned height, FixedPoint<16, u32> refresh_rate, bool preferred = false) {
  914. auto it = resolutions.find_if([&](auto& info) {
  915. return info.width == width && info.height == height;
  916. });
  917. if (it == resolutions.end()) {
  918. resolutions.append({ width, height, { { refresh_rate, preferred } } });
  919. } else {
  920. auto& info = *it;
  921. SupportedResolution::RefreshRate* found_refresh_rate = nullptr;
  922. for (auto& supported_refresh_rate : info.refresh_rates) {
  923. if (supported_refresh_rate.rate == refresh_rate) {
  924. found_refresh_rate = &supported_refresh_rate;
  925. break;
  926. }
  927. }
  928. if (found_refresh_rate)
  929. found_refresh_rate->preferred |= preferred;
  930. else
  931. info.refresh_rates.append({ refresh_rate, preferred });
  932. }
  933. };
  934. TRY(for_each_established_timing([&](auto& established_timing) {
  935. if (established_timing.source() != EstablishedTiming::Source::Manufacturer)
  936. add_resolution(established_timing.width(), established_timing.height(), established_timing.refresh_rate());
  937. return IterationDecision::Continue;
  938. }));
  939. TRY(for_each_standard_timing([&](auto& standard_timing) {
  940. add_resolution(standard_timing.width(), standard_timing.height(), standard_timing.refresh_rate());
  941. return IterationDecision::Continue;
  942. }));
  943. size_t detailed_timing_index = 0;
  944. TRY(for_each_detailed_timing([&](auto& detailed_timing, auto) {
  945. bool is_preferred = detailed_timing_index++ == 0;
  946. add_resolution(detailed_timing.horizontal_addressable_pixels(), detailed_timing.vertical_addressable_lines(), detailed_timing.refresh_rate(), is_preferred);
  947. return IterationDecision::Continue;
  948. }));
  949. TRY(for_each_short_video_descriptor([&](unsigned, bool, VIC::Details const& vic_details) {
  950. add_resolution(vic_details.horizontal_pixels, vic_details.vertical_lines, vic_details.refresh_rate_hz());
  951. return IterationDecision::Continue;
  952. }));
  953. TRY(for_each_coordinated_video_timing([&](auto& coordinated_video_timing) {
  954. if (auto* dmt = DMT::find_timing_by_cvt(coordinated_video_timing.cvt_code())) {
  955. add_resolution(dmt->horizontal_pixels, dmt->vertical_lines, dmt->vertical_frequency_hz());
  956. } else {
  957. // TODO: We couldn't find this cvt code, try to decode it
  958. auto cvt = coordinated_video_timing.cvt_code();
  959. dbgln("TODO: Decode CVT code: {:02x},{:02x},{:02x}", cvt.bytes[0], cvt.bytes[1], cvt.bytes[2]);
  960. }
  961. return IterationDecision::Continue;
  962. }));
  963. quick_sort(resolutions, [&](auto& info1, auto& info2) {
  964. if (info1.width < info2.width)
  965. return true;
  966. if (info1.width == info2.width && info1.height < info2.height)
  967. return true;
  968. return false;
  969. });
  970. for (auto& res : resolutions) {
  971. if (res.refresh_rates.size() > 1)
  972. quick_sort(res.refresh_rates);
  973. }
  974. return resolutions;
  975. }
  976. }