Skip to content

samsung U28D590 external monitor via usb-c-displayport adapter not detected in KDE powerdevil/low brightness when laptop resume from sleep #600

Description

@hkskoglund

Hi! I've been trying to diagnose why my samsung monitor is not detected by KDE powerdevil brightness control. I've fed the log into gemini code assist: chat for the ddcutil repo to see what it can find. I also got a SIGSEGV error when unplugging/replugging the usb-c-displayport adapter.

I am able to bypass problems with using initial stabilization delay 1000ms and ignoring internal laptop display on bus 7.

henning@jupiter:~/.config/ddcutil> cat ddcutilrc
[libddcutil]
# Set initial stabilization to 1000ms
#options = --i1 1000 --ignore-bus 7
#options = --ignore-bus 7

I have compiled the code and currenty testing without issues, maybe portions could be used?: 2.2.7-dev...hkskoglund:ddcutil:fix_usb_c_displayport_samsung_gemini3

journalctl --user -u plasma-powerdevil --follow

 Apr 09 08:12:17 jupiter org_kde_powerdevil[28197]: [116077] (i2c_check_open_bus_alive) Retrying i2c_check_edid_exists_by_dh() tryctr=1, dh=Display_Handle[i2c-9: fd=24]: Sleeping for 100 milliseconds 
Apr 09 08:12:17 jupiter org_kde_powerdevil[28197]: [116077] /dev/i2c-9, Checking EDID failed after 2 tries (B)
Apr 09 08:12:17 jupiter org_kde_powerdevil[28197]: [116077] (check_supported_feature) busno=9, sleep-multiplier = 2.00. Testing for supported feature 0x10 returned Error_Info[DDCRC_DISCONNECTED in i2c_check_open_bus_alive]


SEGV status:

Apr 20 08:51:42 jupiter org_kde_powerdevil[917670]: KCrash: Attempting to start /usr/libexec/org_kde_powerdevil
Apr 20 08:51:42 jupiter org_kde_powerdevil[917670]: KCrash: Application 'org_kde_powerdevil' crashing... crashRecursionCounter = 2
Apr 20 08:51:42 jupiter org_kde_powerdevil[919846]: Starting libddcutil. library built Not set at Not set. stdout_stderr_redirected=true
Apr 20 08:51:42 jupiter systemd-coredump[919848]: [🡕] Process 917670 (org_kde_powerde) of user 1000 dumped core.
                                                                                           
                                                  Stack trace of thread 917670:
                                                  #0  0x00007f466f2a4772 __syscall_cancel_arch (libc.so.6 + 0xa4772)
                                                  #1  0x00007f466f297f68 __internal_syscall_cancel (libc.so.6 + 0x97f68)
                                                  #2  0x00007f466f29872c __futex_abstimed_wait_common (libc.so.6 + 0x9872c)
                                                  #3  0x00007f466f29da54 __pthread_clockjoin_ex (libc.so.6 + 0x9da54)
                                                  #4  0x00007f466ec328b7 n/a (libglib-2.0.so.0 + 0x938b7)
                                                  #5  0x00007f466ec3293a g_thread_join (libglib-2.0.so.0 + 0x9393a)
                                                  #6  0x00007f46701774e7 n/a (libddcutil.so.5 + 0x9f4e7)
                                                  #7  0x00007f467017780c n/a (libddcutil.so.5 + 0x9f80c)
                                                  #8  0x00007f467018b077 ddca_redetect_displays (libddcutil.so.5 + 0xb3077)
                                                  #9  0x00007f4670f1ea18 n/a (libpowerdevilcore.so.2 + 0x8da18)
                                                  #10 0x00007f466fc37334 _ZN7QObject5eventEP6QEvent (libQt6Core.so.6 + 0x237334)
                                                  #11 0x00007f466fbd92d8 _ZN16QCoreApplication15notifyInternal2EP7QObjectP6QEvent (libQt6Core.so.6 + 0x1d92d8)
                                                  #12 0x00007f466fbdb95a _ZN23QCoreApplicationPrivate16sendPostedEventsEP7QObjectiP11QThreadData (libQt6Core.so.6 + 0x1db95a)
                                                  #13 0x00007f466feb0767 n/a (libQt6Core.so.6 + 0x4b0767)
                                                  #14 0x00007f466ebfeaf6 n/a (libglib-2.0.so.0 + 0x5faf6)
                                                  #15 0x00007f466ec019f8 n/a (libglib-2.0.so.0 + 0x629f8)
                                                  #16 0x00007f466ec0224c g_main_context_iteration (libglib-2.0.so.0 + 0x6324c)
                                                  #17 0x00007f466feaead8 _ZN20QEventDispatcherGlib13processEventsE6QFlagsIN10QEventLoop17ProcessEventsFlagEE (libQt6Core.so.6 + 0x4aead8)
                                                  #18 0x00007f466fbe7733 _ZN10QEventLoop4execE6QFlagsINS_17ProcessEventsFlagEE (libQt6Core.so.6 + 0x1e7733)
                                                  #19 0x00007f466fbde1e3 _ZN16QCoreApplication4execEv (libQt6Core.so.6 + 0x1de1e3)
                                                  #20 0x00005598d31087c8 n/a (/usr/libexec/org_kde_powerdevil + 0x97c8)
                                                  #21 0x00007f466f22b2fb __libc_start_call_main (libc.so.6 + 0x2b2fb)
                                                  #22 0x00007f466f22b3cb __libc_start_main@@GLIBC_2.34 (libc.so.6 + 0x2b3cb)
                                                  #23 0x00005598d3109185 n/a (/usr/libexec/org_kde_powerdevil + 0xa185)`

gemini 3 flash preview response: The log messages you provided indicate that during initial display checks, libddcutil detected a failure while trying to communicate with a monitor on /dev/i2c-9. Specifically:

An initial attempt to read VCP feature 0x10 (used to verify DDC communication) failed with an I2C error.
This triggered a call to i2c_check_open_bus_alive() to verify if the monitor is still physically connected by attempting to read its EDID.
The EDID check failed twice (with a 100ms sleep in between), leading to a DDCRC_DISCONNECTED status.
Consequently, the display was marked as disconnected, and check_supported_feature() returned this error.
The log showing sleep-multiplier = 2.00 suggests that dynamic sleep adjustment was active and had already increased the timing from the default 1.00 due to previous communication difficulties.

Analysis and Code Improvements
I've reviewed src/ddc/ddc_initial_checks.c and identified a bug in the retry logic of check_supported_feature(). Currently, if the first attempt returns DDCRC_DISCONNECTED, the function gives up immediately. However, for a newly added display (detected during a hotplug event), the monitor may still be initializing its I2C interface and might transiently appear disconnected.

Additionally, I found several logging errors where VCP feature codes were hardcoded in format strings or used incorrect format specifiers.

Suggestions for src/ddc/ddc_initial_checks.c:
Retry on Disconnect for Hotplugged Displays: Allow the 1-second stabilization delay and retry if newly_added is true, even if the status is DDCRC_DISCONNECTED.
Fix Retry Logic: Ensure that the retry actually occurs for newly_added displays even if dynamic sleep is disabled.
Fix Log Format Strings: Use 0x%02x to correctly report feature codes and match the number of placeholders to the number of arguments.
Avoid Hardcoded Values: Use the feature_code variable instead of hardcoding 0x10 in log messages and function calls.

gemini 3 flash preview response to SEGV: It appears that the crash in org_kde_powerdevil is related to several issues in libddcutil, including a potential Use-After-Free (UAF) in the display watch thread management, a lack of synchronization during display redetection, and a reachable assert(false) in the polling loop that could cause a crash in debug builds.

The provided stack trace shows the main PowerDevil thread waiting to join a thread (likely the watch thread) that has crashed with a segmentation fault. The crash location suggests issues during thread termination and cleanup.

Analysis of the Issues
Use-After-Free in dw_main.c: In dw_stop_watch_displays(), the code accesses global_wdd->watch_mode and global_wdd->evdata before joining the thread. However, the thread function dw_watch_display_connections() (in dw_poll.c) calls dw_free_watch_displays_data(wdd) at the very end of its execution. If the thread finishes just as it's being stopped, global_wdd (which points to the same memory as wdd) may be freed while dw_stop_watch_displays() is still trying to access it.
Missing Synchronization in dw_redetect_displays(): Display redetection discards all current display references. If callback threads are still running and accessing these references, a crash occurs. Furthermore, there is no guard against multiple concurrent redetection calls, which can happen during system resume when multiple display events are fired.
Thread Termination Leaks and Logic Errors: In dw_recheck.c, queue entries are leaked when the thread terminates, and the wrong free function is used for thread data. In dw_poll.c, an assert(false) is present at the end of the thread function, which will cause a crash if the thread ever reaches that point (which it does upon termination).
The following changes address these issues by fixing the UAF, adding a redetection mutex and callback thread synchronization, and cleaning up thread termination logic.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions