EDID.cpp 43 KB

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