mirror of
https://github.com/hyprwm/wlroots-hyprland.git
synced 2024-11-24 13:45:58 +01:00
backend/drm: use libdisplay-info to parse EDID
This commit is contained in:
parent
40117e1e0d
commit
35da997001
8 changed files with 34 additions and 57 deletions
|
@ -3,6 +3,7 @@ packages:
|
||||||
- eudev-dev
|
- eudev-dev
|
||||||
- ffmpeg-dev
|
- ffmpeg-dev
|
||||||
- glslang
|
- glslang
|
||||||
|
- libdisplay-info-dev
|
||||||
- libinput-dev
|
- libinput-dev
|
||||||
- libliftoff-dev
|
- libliftoff-dev
|
||||||
- libxkbcommon-dev
|
- libxkbcommon-dev
|
||||||
|
|
|
@ -3,6 +3,7 @@ packages:
|
||||||
- clang
|
- clang
|
||||||
- ffmpeg
|
- ffmpeg
|
||||||
- libinput
|
- libinput
|
||||||
|
- libdisplay-info
|
||||||
- libliftoff
|
- libliftoff
|
||||||
- libxkbcommon
|
- libxkbcommon
|
||||||
- mesa
|
- mesa
|
||||||
|
|
|
@ -24,6 +24,7 @@ packages:
|
||||||
- x11/xcb-util-renderutil
|
- x11/xcb-util-renderutil
|
||||||
- x11/xcb-util-wm
|
- x11/xcb-util-wm
|
||||||
- x11-servers/xwayland-devel
|
- x11-servers/xwayland-devel
|
||||||
|
- sysutils/libdisplay-info
|
||||||
- sysutils/seatd
|
- sysutils/seatd
|
||||||
- gmake
|
- gmake
|
||||||
- hwdata
|
- hwdata
|
||||||
|
|
|
@ -52,6 +52,7 @@ Install dependencies:
|
||||||
* pixman
|
* pixman
|
||||||
* [libseat] (optional, for the session)
|
* [libseat] (optional, for the session)
|
||||||
* [hwdata] (optional, for the DRM backend)
|
* [hwdata] (optional, for the DRM backend)
|
||||||
|
* [libdisplay-info] (optional, for the DRM backend)
|
||||||
* [libliftoff] (optional, for the DRM backend)
|
* [libliftoff] (optional, for the DRM backend)
|
||||||
|
|
||||||
If you choose to enable X11 support:
|
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
|
[wrapper libraries]: https://gitlab.freedesktop.org/wlroots/wlroots/-/wikis/Projects-which-use-wlroots#wrapper-libraries
|
||||||
[libseat]: https://git.sr.ht/~kennylevinsen/seatd
|
[libseat]: https://git.sr.ht/~kennylevinsen/seatd
|
||||||
[hwdata]: https://github.com/vcrhonek/hwdata
|
[hwdata]: https://github.com/vcrhonek/hwdata
|
||||||
|
[libdisplay-info]: https://gitlab.freedesktop.org/emersion/libdisplay-info
|
||||||
[libliftoff]: https://gitlab.freedesktop.org/emersion/libliftoff
|
[libliftoff]: https://gitlab.freedesktop.org/emersion/libliftoff
|
||||||
[CONTRIBUTING.md]: https://gitlab.freedesktop.org/wlroots/wlroots/-/blob/master/CONTRIBUTING.md
|
[CONTRIBUTING.md]: https://gitlab.freedesktop.org/wlroots/wlroots/-/blob/master/CONTRIBUTING.md
|
||||||
|
|
|
@ -13,12 +13,11 @@ gen_pnps()
|
||||||
}
|
}
|
||||||
|
|
||||||
cat << EOF
|
cat << EOF
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include "backend/drm/util.h"
|
#include "backend/drm/util.h"
|
||||||
|
|
||||||
#define PNP_ID(a, b, c) ((a & 0x1f) << 10) | ((b & 0x1f) << 5) | (c & 0x1f)
|
#define PNP_ID(a, b, c) ((a & 0x1f) << 10) | ((b & 0x1f) << 5) | (c & 0x1f)
|
||||||
const char *get_pnp_manufacturer(uint16_t code) {
|
const char *get_pnp_manufacturer(const char code[static 3]) {
|
||||||
switch (code) {
|
switch (PNP_ID(code[0], code[1], code[2])) {
|
||||||
$(gen_pnps)
|
$(gen_pnps)
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -5,6 +5,13 @@ hwdata = dependency(
|
||||||
not_found_message: 'Required for the DRM backend.',
|
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 = dependency(
|
||||||
'libliftoff',
|
'libliftoff',
|
||||||
version: '>=0.4.0',
|
version: '>=0.4.0',
|
||||||
|
@ -12,7 +19,7 @@ libliftoff = dependency(
|
||||||
required: false,
|
required: false,
|
||||||
)
|
)
|
||||||
|
|
||||||
if not (hwdata.found() and features['session'])
|
if not (hwdata.found() and libdisplay_info.found() and features['session'])
|
||||||
subdir_done()
|
subdir_done()
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -45,4 +52,5 @@ endif
|
||||||
|
|
||||||
features += { 'drm-backend': true }
|
features += { 'drm-backend': true }
|
||||||
internal_features += { 'libliftoff': libliftoff.found() }
|
internal_features += { 'libliftoff': libliftoff.found() }
|
||||||
|
wlr_deps += libdisplay_info
|
||||||
wlr_deps += libliftoff
|
wlr_deps += libliftoff
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#include <drm_fourcc.h>
|
#include <drm_fourcc.h>
|
||||||
#include <drm_mode.h>
|
#include <drm_mode.h>
|
||||||
#include <drm.h>
|
#include <drm.h>
|
||||||
|
#include <libdisplay-info/edid.h>
|
||||||
|
#include <libdisplay-info/info.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -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) {
|
void parse_edid(struct wlr_drm_connector *conn, size_t len, const uint8_t *data) {
|
||||||
struct wlr_output *output = &conn->output;
|
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->model = NULL;
|
||||||
output->serial = 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t id = (data[8] << 8) | data[9];
|
const struct di_edid *edid = di_info_get_edid(info);
|
||||||
const char *manu = get_pnp_manufacturer(id);
|
const struct di_edid_vendor_product *vendor_product = di_edid_get_vendor_product(edid);
|
||||||
char pnp_id[4];
|
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) {
|
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;
|
manu = pnp_id;
|
||||||
}
|
}
|
||||||
output->make = strdup(manu);
|
output->make = strdup(manu);
|
||||||
|
|
||||||
uint16_t model = data[10] | (data[11] << 8);
|
output->model = di_info_get_model(info);
|
||||||
char model_str[32];
|
output->serial = di_info_get_serial(info);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *drm_connector_status_str(drmModeConnection status) {
|
const char *drm_connector_status_str(drmModeConnection status) {
|
||||||
|
|
|
@ -11,7 +11,7 @@ struct wlr_drm_connector;
|
||||||
int32_t calculate_refresh_rate(const drmModeModeInfo *mode);
|
int32_t calculate_refresh_rate(const drmModeModeInfo *mode);
|
||||||
enum wlr_output_mode_aspect_ratio get_picture_aspect_ratio(const drmModeModeInfo *mode);
|
enum wlr_output_mode_aspect_ratio get_picture_aspect_ratio(const drmModeModeInfo *mode);
|
||||||
// Returns manufacturer based on pnp id
|
// 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
|
// 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);
|
void parse_edid(struct wlr_drm_connector *conn, size_t len, const uint8_t *data);
|
||||||
const char *drm_connector_status_str(drmModeConnection status);
|
const char *drm_connector_status_str(drmModeConnection status);
|
||||||
|
|
Loading…
Reference in a new issue