From 35da9970019be6580394d5d6234b8ede0b2f0d5a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 2 Feb 2023 12:14:11 +0100 Subject: [PATCH] backend/drm: use libdisplay-info to parse EDID --- .builds/alpine.yml | 1 + .builds/archlinux.yml | 1 + .builds/freebsd.yml | 1 + README.md | 2 ++ backend/drm/gen_pnpids.sh | 7 ++-- backend/drm/meson.build | 10 +++++- backend/drm/util.c | 67 +++++++++----------------------------- include/backend/drm/util.h | 2 +- 8 files changed, 34 insertions(+), 57 deletions(-) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index a2c90953..7b8f7f3f 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -3,6 +3,7 @@ packages: - eudev-dev - ffmpeg-dev - glslang + - libdisplay-info-dev - libinput-dev - libliftoff-dev - libxkbcommon-dev diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index f311bf74..26d4a163 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -3,6 +3,7 @@ packages: - clang - ffmpeg - libinput + - libdisplay-info - libliftoff - libxkbcommon - mesa diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 743dfb49..75a326f8 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -24,6 +24,7 @@ packages: - x11/xcb-util-renderutil - x11/xcb-util-wm - x11-servers/xwayland-devel + - sysutils/libdisplay-info - sysutils/seatd - gmake - hwdata diff --git a/README.md b/README.md index da2cbc92..603ee20c 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ Install dependencies: * pixman * [libseat] (optional, for the session) * [hwdata] (optional, for the DRM backend) +* [libdisplay-info] (optional, for the DRM backend) * [libliftoff] (optional, for the DRM backend) If you choose to enable X11 support: @@ -81,5 +82,6 @@ See [CONTRIBUTING.md]. [wrapper libraries]: https://gitlab.freedesktop.org/wlroots/wlroots/-/wikis/Projects-which-use-wlroots#wrapper-libraries [libseat]: https://git.sr.ht/~kennylevinsen/seatd [hwdata]: https://github.com/vcrhonek/hwdata +[libdisplay-info]: https://gitlab.freedesktop.org/emersion/libdisplay-info [libliftoff]: https://gitlab.freedesktop.org/emersion/libliftoff [CONTRIBUTING.md]: https://gitlab.freedesktop.org/wlroots/wlroots/-/blob/master/CONTRIBUTING.md diff --git a/backend/drm/gen_pnpids.sh b/backend/drm/gen_pnpids.sh index 80e5542d..5a9547ae 100755 --- a/backend/drm/gen_pnpids.sh +++ b/backend/drm/gen_pnpids.sh @@ -13,12 +13,11 @@ gen_pnps() } cat << EOF -#include -#include #include "backend/drm/util.h" + #define PNP_ID(a, b, c) ((a & 0x1f) << 10) | ((b & 0x1f) << 5) | (c & 0x1f) -const char *get_pnp_manufacturer(uint16_t code) { - switch (code) { +const char *get_pnp_manufacturer(const char code[static 3]) { + switch (PNP_ID(code[0], code[1], code[2])) { $(gen_pnps) } return NULL; diff --git a/backend/drm/meson.build b/backend/drm/meson.build index 3fb011c1..824134fe 100644 --- a/backend/drm/meson.build +++ b/backend/drm/meson.build @@ -5,6 +5,13 @@ hwdata = dependency( not_found_message: 'Required for the DRM backend.', ) +libdisplay_info = dependency( + 'libdisplay-info', + required: 'drm' in backends, + fallback: 'libdisplay-info', + not_found_message: 'Required for the DRM backend.', +) + libliftoff = dependency( 'libliftoff', version: '>=0.4.0', @@ -12,7 +19,7 @@ libliftoff = dependency( required: false, ) -if not (hwdata.found() and features['session']) +if not (hwdata.found() and libdisplay_info.found() and features['session']) subdir_done() endif @@ -45,4 +52,5 @@ endif features += { 'drm-backend': true } internal_features += { 'libliftoff': libliftoff.found() } +wlr_deps += libdisplay_info wlr_deps += libliftoff diff --git a/backend/drm/util.c b/backend/drm/util.c index adb9306e..d4ece1f9 100644 --- a/backend/drm/util.c +++ b/backend/drm/util.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include #include @@ -48,9 +50,6 @@ enum wlr_output_mode_aspect_ratio get_picture_aspect_ratio(const drmModeModeInfo } } -/* See https://en.wikipedia.org/wiki/Extended_Display_Identification_Data for layout of EDID data. - * We don't parse the EDID properly. We just expect to receive valid data. - */ void parse_edid(struct wlr_drm_connector *conn, size_t len, const uint8_t *data) { struct wlr_output *output = &conn->output; @@ -61,62 +60,28 @@ void parse_edid(struct wlr_drm_connector *conn, size_t len, const uint8_t *data) output->model = NULL; output->serial = NULL; - if (!data || len < 128) { + struct di_info *info = di_info_parse_edid(data, len); + if (info == NULL) { + wlr_log(WLR_ERROR, "Failed to parse EDID"); return; } - uint16_t id = (data[8] << 8) | data[9]; - const char *manu = get_pnp_manufacturer(id); - char pnp_id[4]; + const struct di_edid *edid = di_info_get_edid(info); + const struct di_edid_vendor_product *vendor_product = di_edid_get_vendor_product(edid); + char pnp_id[] = { + vendor_product->manufacturer[0], + vendor_product->manufacturer[1], + vendor_product->manufacturer[2], + '\0', + }; + const char *manu = get_pnp_manufacturer(vendor_product->manufacturer); if (!manu) { - // The ASCII 3-letter manufacturer PnP ID is encoded in 5-bit codes - pnp_id[0] = ((id >> 10) & 0x1F) + '@'; - pnp_id[1] = ((id >> 5) & 0x1F) + '@'; - pnp_id[2] = ((id >> 0) & 0x1F) + '@'; - pnp_id[3] = '\0'; manu = pnp_id; } output->make = strdup(manu); - uint16_t model = data[10] | (data[11] << 8); - char model_str[32]; - snprintf(model_str, sizeof(model_str), "0x%04" PRIX16, model); - - uint32_t serial = data[12] | (data[13] << 8) | (data[14] << 8) | (data[15] << 8); - char serial_str[32]; - if (serial != 0) { - snprintf(serial_str, sizeof(serial_str), "0x%08" PRIX32, serial); - } else { - serial_str[0] = '\0'; - } - - for (size_t i = 72; i <= 108; i += 18) { - uint16_t flag = (data[i] << 8) | data[i + 1]; - if (flag == 0 && data[i + 3] == 0xFC) { - snprintf(model_str, sizeof(model_str), "%.13s", &data[i + 5]); - - // Monitor names are terminated by newline if they're too short - char *nl = strchr(model_str, '\n'); - if (nl) { - *nl = '\0'; - } - } else if (flag == 0 && data[i + 3] == 0xFF) { - snprintf(serial_str, sizeof(serial_str), "%.13s", &data[i + 5]); - - // Monitor serial numbers are terminated by newline if they're too - // short - char* nl = strchr(serial_str, '\n'); - - if (nl) { - *nl = '\0'; - } - } - } - - output->model = strdup(model_str); - if (serial_str[0] != '\0') { - output->serial = strdup(serial_str); - } + output->model = di_info_get_model(info); + output->serial = di_info_get_serial(info); } const char *drm_connector_status_str(drmModeConnection status) { diff --git a/include/backend/drm/util.h b/include/backend/drm/util.h index ba48fe6a..12eec35c 100644 --- a/include/backend/drm/util.h +++ b/include/backend/drm/util.h @@ -11,7 +11,7 @@ struct wlr_drm_connector; int32_t calculate_refresh_rate(const drmModeModeInfo *mode); enum wlr_output_mode_aspect_ratio get_picture_aspect_ratio(const drmModeModeInfo *mode); // Returns manufacturer based on pnp id -const char *get_pnp_manufacturer(uint16_t code); +const char *get_pnp_manufacturer(const char code[static 3]); // Populates the make/model/phys_{width,height} of output from the edid data void parse_edid(struct wlr_drm_connector *conn, size_t len, const uint8_t *data); const char *drm_connector_status_str(drmModeConnection status);