From: Hans de Goede Date: Mon, 14 Jan 2019 10:47:21 +0000 (+0100) Subject: ply-device-manager: Handle change events for monitor hotplugging X-Git-Tag: 0.9.5~76^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e54f6a47318d82b4e4df024855bd76d888b89675;p=thirdparty%2Fplymouth.git ply-device-manager: Handle change events for monitor hotplugging Not only handle add but also change events for drm-subsys devices, change events are generated when the hardware detect a new monitor has been plugged in. This is esp. important with modern DisplayPort MST docking stations where discovery / enumeration can take so long that the connected displays are not enumerated by the kernel yet when the drm plugin first calls drmModeGetResources(). Causing the monitors on these docks to sometimes not show plymouth during boot (based on various timing parameters). Note that if during the add event drm-renderer could not be bound, this commit tries to re-bind the DRM renderer on change events in case a monitor got plugged into a GPU which did not have anything connected before. This often happens with the second GPU in a laptop with a hybrid GPU setup. BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1652279 Signed-off-by: Hans de Goede --- diff --git a/src/libply-splash-core/ply-device-manager.c b/src/libply-splash-core/ply-device-manager.c index 028bf4ad..e2a9eaee 100644 --- a/src/libply-splash-core/ply-device-manager.c +++ b/src/libply-splash-core/ply-device-manager.c @@ -51,6 +51,9 @@ static bool create_devices_for_terminal_and_renderer_type (ply_device_manager_t const char *device_path, ply_terminal_t *terminal, ply_renderer_type_t renderer_type); +static void create_pixel_displays_for_renderer (ply_device_manager_t *manager, + ply_renderer_t *renderer); + struct _ply_device_manager { ply_device_manager_flags_t flags; @@ -371,6 +374,39 @@ create_devices_for_subsystem (ply_device_manager_t *manager, return found_device; } +static void +on_drm_udev_add_or_change (ply_device_manager_t *manager, + const char *action, + struct udev_device *device) +{ + const char *device_path = udev_device_get_devnode (device); + ply_renderer_t *renderer; + bool changed; + + if (device_path == NULL) + return; + + renderer = ply_hashtable_lookup (manager->renderers, (void *) device_path); + if (renderer == NULL) { + /* We also try to create the renderer again on change events, + * renderer creation fails when no outputs are connected and + * this may have changed. + */ + create_devices_for_udev_device (manager, device); + return; + } + + /* Renderer exists, bail if this is not a change event */ + if (strcmp (action, "change")) + return; + + changed = ply_renderer_handle_change_event (renderer); + if (changed) { + free_displays_for_renderer (manager, renderer); + create_pixel_displays_for_renderer (manager, renderer); + } +} + static bool on_udev_event (ply_device_manager_t *manager) { @@ -388,7 +424,7 @@ on_udev_event (ply_device_manager_t *manager) if (action == NULL) return false; - if (strcmp (action, "add") == 0) { + if (strcmp (action, "add") == 0 || strcmp (action, "change") == 0) { const char *subsystem; subsystem = udev_device_get_subsystem (device); @@ -397,7 +433,7 @@ on_udev_event (ply_device_manager_t *manager) if (manager->local_console_managed && manager->local_console_is_text) ply_trace ("ignoring since we're already using text splash for local console"); else - create_devices_for_udev_device (manager, device); + on_drm_udev_add_or_change (manager, action, device); } else { ply_trace ("ignoring since we only handle subsystem %s devices after timeout", subsystem); }