summaryrefslogtreecommitdiff
path: root/src/libsystemd-terminal
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsystemd-terminal')
-rw-r--r--src/libsystemd-terminal/grdev-drm.c33
1 files changed, 24 insertions, 9 deletions
diff --git a/src/libsystemd-terminal/grdev-drm.c b/src/libsystemd-terminal/grdev-drm.c
index 5cebb0609e..2e55ad326b 100644
--- a/src/libsystemd-terminal/grdev-drm.c
+++ b/src/libsystemd-terminal/grdev-drm.c
@@ -264,6 +264,7 @@ struct grdrm_card {
Hashmap *object_map;
bool async_hotplug : 1;
+ bool hotplug : 1;
bool running : 1;
bool ready : 1;
bool cap_dumb : 1;
@@ -603,12 +604,19 @@ static int grdrm_connector_resync(grdrm_connector *connector) {
res.count_encoders = connector->kern.max_encoders;
res.count_props = connector->kern.max_props;
- /* Retrieve modes only if we have none. This avoids expensive
- * EDID reads in the kernel, that can slow down resyncs
- * considerably! */
- if (connector->kern.n_modes == 0) {
- res.modes_ptr = PTR_TO_UINT64(connector->kern.modes);
- res.count_modes = connector->kern.max_modes;
+ /* The kernel reads modes from the EDID information only if we
+ * pass count_modes==0. This is a legacy hack for libdrm (which
+ * called every ioctl twice). Now we have to adopt.. *sigh*.
+ * If we never received an hotplug event, there's no reason to
+ * sync modes. EDID reads are heavy, so skip that if not
+ * required. */
+ if (card->hotplug) {
+ if (tries > 0) {
+ res.modes_ptr = PTR_TO_UINT64(connector->kern.modes);
+ res.count_modes = connector->kern.max_modes;
+ } else {
+ resized = true;
+ }
}
r = ioctl(card->fd, DRM_IOCTL_MODE_GETCONNECTOR, &res);
@@ -689,7 +697,6 @@ static int grdrm_connector_resync(grdrm_connector *connector) {
continue;
connector->kern.n_encoders = res.count_encoders;
- connector->kern.n_modes = res.count_modes;
connector->kern.n_props = res.count_props;
connector->kern.type = res.connector_type;
connector->kern.type_id = res.connector_type_id;
@@ -698,6 +705,8 @@ static int grdrm_connector_resync(grdrm_connector *connector) {
connector->kern.mm_width = res.mm_width;
connector->kern.mm_height = res.mm_height;
connector->kern.subpixel = res.subpixel;
+ if (res.modes_ptr == PTR_TO_UINT64(connector->kern.modes))
+ connector->kern.n_modes = res.count_modes;
break;
}
@@ -2167,6 +2176,7 @@ static void grdrm_card_hotplug(grdrm_card *card) {
grdrm_card_configure(card);
card->ready = true;
+ card->hotplug = false;
grdev_session_unpin(card->base.session);
}
@@ -2374,6 +2384,7 @@ static int grdrm_card_open(grdrm_card *card, int dev_fd) {
sd_event_source_set_enabled(card->fd_src, SD_EVENT_OFF);
+ card->hotplug = true;
card->fd = fd;
fd = -1;
@@ -3029,13 +3040,17 @@ void grdev_drm_card_hotplug(grdev_card *basecard, struct udev_device *ud) {
/* If we get add/remove events on DRM nodes without devnum, we
* got hotplugged DRM objects so refresh the device. */
devnum = udev_device_get_devnum(ud);
- if (devnum == 0)
+ if (devnum == 0) {
+ card->hotplug = true;
grdrm_card_hotplug(card);
+ }
} else if (streq_ptr(action, "change")) {
/* A change event with HOTPLUG=1 is sent whenever a connector
* changed state. Refresh the device to update our state. */
p = udev_device_get_property_value(ud, "HOTPLUG");
- if (streq_ptr(p, "1"))
+ if (streq_ptr(p, "1")) {
+ card->hotplug = true;
grdrm_card_hotplug(card);
+ }
}
}