Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package evdi for openSUSE:Factory checked in 
at 2024-10-04 17:11:15
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/evdi (Old)
 and      /work/SRC/openSUSE:Factory/.evdi.new.19354 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "evdi"

Fri Oct  4 17:11:15 2024 rev:8 rq:1205677 version:1.14.7

Changes:
--------
--- /work/SRC/openSUSE:Factory/evdi/evdi.changes        2024-08-02 
17:28:07.819266686 +0200
+++ /work/SRC/openSUSE:Factory/.evdi.new.19354/evdi.changes     2024-10-04 
17:11:38.471586679 +0200
@@ -1,0 +2,16 @@
+Fri Oct 04 11:15:59 UTC 2024 - joan.tor...@suse.com
+
+- Update to version 1.14.7:
+  * Set version to 1.14.7
+  * Fix venv for pytest.run.sh
+  * Test that card opening does not take too long
+  * Do not wait for master on wayland session
+  * Test that monitor power off event is sent on vt terminal swithc when user 
is connected
+  * Test that no monitor power off events are sent when user driver is not 
connected
+  * Test that evdi_painter listens to VT notifications
+  * Blank evdi display on switch to tty console. Fixes GH-474.
+  * Add evdi_test_data base test context stucture and drm_device removal hook
+  * Make evdi_painter_dpms_notify to take evdi_painter as argument instead of 
evdi_device
+- With this update fix-v1.14.5-build.patch is not needed anymore.
+
+-------------------------------------------------------------------

Old:
----
  evdi-1.14.5.obscpio
  fix-v1.14.5-build.patch

New:
----
  evdi-1.14.7.obscpio

BETA DEBUG BEGIN:
  Old:  * Make evdi_painter_dpms_notify to take evdi_painter as argument 
instead of evdi_device
- With this update fix-v1.14.5-build.patch is not needed anymore.
BETA DEBUG END:

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ evdi.spec ++++++
--- /var/tmp/diff_new_pack.3UjMHO/_old  2024-10-04 17:11:39.367624112 +0200
+++ /var/tmp/diff_new_pack.3UjMHO/_new  2024-10-04 17:11:39.371624278 +0200
@@ -21,7 +21,7 @@
 
 Name:           evdi
 Release:        0
-Version:        1.14.5
+Version:        1.14.7
 Summary:        Extensible Virtual Display Interface (EVDI) is a Linux Kernel 
Module
 License:        GPL-2.0-only AND LGPL-2.1-only
 Group:          System/Kernel
@@ -30,7 +30,6 @@
 Source1:        evdi-kmp-preamble
 Source2:        evdi-rpmlintrc
 Patch0:         evdi-Enable-compilation-against-15.5.patch
-Patch1:         fix-v1.14.5-build.patch
 BuildRequires:  %{kernel_module_package_buildreqs}
 BuildRequires:  pkgconfig
 BuildRequires:  pkgconfig(libdrm)
@@ -74,7 +73,6 @@
 %if 0%{?sle_version} == 150500
 %patch -P 0 -p1
 %endif
-%patch -P 1 -p1
 
 %build
 pushd library

++++++ _service ++++++
--- /var/tmp/diff_new_pack.3UjMHO/_old  2024-10-04 17:11:39.399625448 +0200
+++ /var/tmp/diff_new_pack.3UjMHO/_new  2024-10-04 17:11:39.403625616 +0200
@@ -3,7 +3,7 @@
   <service name="obs_scm" mode="manual">
     <param name="scm">git</param>
     <param name="url">https://github.com/DisplayLink/evdi.git</param>
-    <param name="revision">v1.14.5</param>
+    <param name="revision">v1.14.7</param>
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="versionrewrite-pattern">v(.*)</param>
     <param name="versionrewrite-replacement">\1</param>

++++++ evdi-1.14.5.obscpio -> evdi-1.14.7.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/.gitlab/CODEOWNERS 
new/evdi-1.14.7/.gitlab/CODEOWNERS
--- old/evdi-1.14.5/.gitlab/CODEOWNERS  1970-01-01 01:00:00.000000000 +0100
+++ new/evdi-1.14.7/.gitlab/CODEOWNERS  2024-09-20 11:14:26.000000000 +0200
@@ -0,0 +1,2 @@
+[MAINTAINER]
+* @lspintzyk @jprussak @emajewska @mlukaszek @akaleta
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/README.md new/evdi-1.14.7/README.md
--- old/evdi-1.14.5/README.md   2024-06-26 10:30:41.000000000 +0200
+++ new/evdi-1.14.7/README.md   2024-09-20 11:14:26.000000000 +0200
@@ -24,6 +24,10 @@
 - The communication between the EVDI kernel module and the wrapper libevdi 
library is not access-controlled or authenticated. This could be improved in 
future releases, making it harder to compromise the data EVDI is sending and 
receiving.
 - EVDI kernel module driver is currently a platform_driver, for multiple 
reasons; most importantly because virtual displays are not discoverable, i.e. 
cannot be enumerated at the hardware level. EVDI is also a generic device, not 
tied to any particular kind of device, transport layer or a bus.
 
+## Packages for other distributions
+
+There is an unoffical github project at [DisplayLink 
RPM](https://github.com/displaylink-rpm/displaylink-rpm) which is generating 
RPM package for Fedora, CentOS Stream, Rocky Linux and AlmaLinux OS. It is not 
in our control but it uses our code as the basis to create the RPM packages.
+
 ## Licensing
 
 Elements of this project are licensed under various licenses. In particular, 
the `module` and `library` are licensed
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/ci/deb_config 
new/evdi-1.14.7/ci/deb_config
--- old/evdi-1.14.5/ci/deb_config       2024-06-26 10:30:41.000000000 +0200
+++ new/evdi-1.14.7/ci/deb_config       2024-09-20 11:14:26.000000000 +0200
@@ -8,7 +8,7 @@
 evdi_maintainer='Synaptics Technical Support 
<technical-enquir...@synaptics.com>'
 
 # shellcheck disable=SC2034
-evdi_version='1.14.5'
+evdi_version='1.14.7'
 
 # shellcheck disable=SC2034
 evdi_description="Extensible Virtual Display Interface (EVDI) is a Linux® 
kernel module that enables management of multiple screens.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/ci/run_style_check 
new/evdi-1.14.7/ci/run_style_check
--- old/evdi-1.14.5/ci/run_style_check  2024-06-26 10:30:41.000000000 +0200
+++ new/evdi-1.14.7/ci/run_style_check  2024-09-20 11:14:26.000000000 +0200
@@ -24,7 +24,7 @@
 ./checkpatch.pl --terse --no-tree --ignore NEW_TYPEDEFS -f ./library/*
 result=$((result || $?))
 
-find ./module -type f -exec ./checkpatch.pl --terse --no-tree --ignore 
LINUX_VERSION_CODE,PREFER_PR_LEVEL -f {} +
+find ./module -type f -exec ./checkpatch.pl --terse --no-tree --ignore 
LINUX_VERSION_CODE,PREFER_PR_LEVEL -f {} \;
 result=$((result || $?))
 
 rm "${files[@]}"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/library/Makefile 
new/evdi-1.14.7/library/Makefile
--- old/evdi-1.14.5/library/Makefile    2024-06-26 10:30:41.000000000 +0200
+++ new/evdi-1.14.7/library/Makefile    2024-09-20 11:14:26.000000000 +0200
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2015 - 2020 DisplayLink (UK) Ltd.
+# Copyright (c) 2015 - 2024 DisplayLink (UK) Ltd.
 #
 
 INSTALL ?= install
@@ -11,7 +11,7 @@
 DEPS = evdi_ioctl.h
 CFLAGS := -I../module -std=gnu99 -fPIC -D_FILE_OFFSET_BITS=64 $(CFLAGS) 
$$($(PKG_CONFIG) --cflags-only-I libdrm)
 
-LIBVER := 1.14.5
+LIBVER := 1.14.7
 LIBABI := 1
 
 PREFIX ?= /usr/local
@@ -25,7 +25,7 @@
 %.o: %.c $(DEPS)
        $(CC) $(CFLAGS) -o $@ -c $<
 
-libevdi.so.$(LIBVER): evdi_lib.o
+libevdi.so.$(LIBVER): evdi_lib.o evdi_procfs.o
        $(CC) $^ -shared -Wl,-soname,libevdi.so.$(LIBABI) -o $@ -lc -lgcc 
$(LDFLAGS)
        $(CP) libevdi.so.$(LIBVER) libevdi.so
        $(LN) -sf libevdi.so.$(LIBVER) libevdi.so.$(LIBABI)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/library/evdi_lib.c 
new/evdi-1.14.7/library/evdi_lib.c
--- old/evdi-1.14.5/library/evdi_lib.c  2024-06-26 10:30:41.000000000 +0200
+++ new/evdi-1.14.7/library/evdi_lib.c  2024-09-20 11:14:26.000000000 +0200
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: LGPL-2.1-only
-// Copyright (c) 2015 - 2020 DisplayLink (UK) Ltd.
+// Copyright (c) 2015 - 2024 DisplayLink (UK) Ltd.
 
 #include <stddef.h>
 #include <stdint.h>
@@ -131,11 +131,9 @@
 static void addFrameBuffer(evdi_handle context,
                           struct evdi_buffer const *frame_buffer)
 {
-       struct evdi_frame_buffer_node **node = NULL;
-
-       for (node = &context->frameBuffersListHead;
+       for (struct evdi_frame_buffer_node **node = 
&context->frameBuffersListHead;
             ;
-            node = (struct evdi_frame_buffer_node **)&(*node)->next) {
+            node = &(*node)->next) {
                if (*node)
                        continue;
 
@@ -150,15 +148,12 @@
  * @brief Removes all frame buffers matching the given id
  * @param id of frame buffer to remove, NULL matches every buffer, thus all
  * will be removed
- * @return number of buffers removed
- * @todo Return value doesn't seem to be used anywhere
  */
-static int removeFrameBuffer(evdi_handle context, int const *id)
+static void removeFrameBuffer(evdi_handle context, int const *id)
 {
        struct evdi_frame_buffer_node *current = NULL;
        struct evdi_frame_buffer_node *next = NULL;
        struct evdi_frame_buffer_node **prev = NULL;
-       int removedCount = 0;
 
        current = context->frameBuffersListHead;
        prev = &context->frameBuffersListHead;
@@ -167,7 +162,6 @@
 
                if (!id || current->frame_buffer.id == *id) {
                        free(current);
-                       ++removedCount;
                        *prev = next;
                } else {
                        prev = &current->next;
@@ -175,8 +169,6 @@
 
                current = next;
        }
-
-       return removedCount;
 }
 
 static int is_evdi_compatible(int fd)
@@ -210,7 +202,9 @@
 
 static int is_evdi(int fd)
 {
-       char name[64] = { 0 }, date[64] = { 0 }, desc[64] = { 0 };
+       char name[64] = { 0 };
+       char date[64] = { 0 };
+       char desc[64] = { 0 };
        struct drm_version ver = {
                .name_len = sizeof(name),
                .name = name,
@@ -311,7 +305,7 @@
 {
        pid_t myself = getpid();
        DIR *proc_dir;
-       struct dirent *proc_entry;
+       const struct dirent *proc_entry;
        int result = 0;
 
        proc_dir = opendir("/proc");
@@ -319,7 +313,7 @@
                return 0;
 
        while ((proc_entry = readdir(proc_dir)) != NULL) {
-               char *d_name = proc_entry->d_name;
+               const char *d_name = proc_entry->d_name;
 
                if (d_name[0] < '0'
                    || d_name[0] > '9'
@@ -415,9 +409,8 @@
 
        snprintf(dev, PATH_MAX, "/dev/dri/card%d", device);
 
-#ifndef CHROMEOS
-       wait_for_master(dev);
-#endif
+       if (Xorg_running())
+               wait_for_master(dev);
 
        fd = wait_for_device(dev);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/library/evdi_lib.h 
new/evdi-1.14.7/library/evdi_lib.h
--- old/evdi-1.14.5/library/evdi_lib.h  2024-06-26 10:30:41.000000000 +0200
+++ new/evdi-1.14.7/library/evdi_lib.h  2024-09-20 11:14:26.000000000 +0200
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: LGPL-2.1-only
- * Copyright (c) 2015 - 2020 DisplayLink (UK) Ltd.
+ * Copyright (c) 2015 - 2024 DisplayLink (UK) Ltd.
  */
 
 #ifndef EVDI_LIB_H
@@ -15,7 +15,7 @@
 
 #define LIBEVDI_VERSION_MAJOR 1
 #define LIBEVDI_VERSION_MINOR 14
-#define LIBEVDI_VERSION_PATCH 5
+#define LIBEVDI_VERSION_PATCH 7
 
 struct evdi_lib_version {
        int version_major;
@@ -134,6 +134,8 @@
 void evdi_get_lib_version(struct evdi_lib_version *version);
 void evdi_set_logging(struct evdi_logging evdi_logging);
 
+bool Xorg_running(void);
+
 #ifdef __cplusplus
 }
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/library/evdi_procfs.c 
new/evdi-1.14.7/library/evdi_procfs.c
--- old/evdi-1.14.5/library/evdi_procfs.c       1970-01-01 01:00:00.000000000 
+0100
+++ new/evdi-1.14.7/library/evdi_procfs.c       2024-09-20 11:14:26.000000000 
+0200
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: LGPL-2.1-only
+// Copyright (c) 2015 - 2024 DisplayLink (UK) Ltd.
+
+#include "evdi_lib.h"
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+const int command_length = 50;
+const int name_length = 30;
+
+static FILE *open_process_folder(const char *pid)
+{
+       FILE *pf;
+       char command[command_length];
+
+       snprintf(command, command_length, "/proc/%s/stat", pid);
+       pf = fopen(command, "r");
+
+       return pf;
+}
+
+static void close_folder(FILE *pf)
+{
+       if (fclose(pf) != 0)
+               exit(EXIT_FAILURE);
+}
+
+static char *process_name(FILE *pf)
+{
+       int Xorg_name_len = 6;
+       char *name = (char *)malloc(Xorg_name_len * sizeof(char));
+
+       fscanf(pf, "%*s");
+       fscanf(pf, "%6s", name); // Xorg process had name (Xorg)
+
+       return name;
+}
+
+static bool is_name_Xorg(const char *name)
+{
+       return strstr(name, "Xorg") != NULL;
+}
+
+static bool is_Xorg(const char *pid)
+{
+       FILE *pf;
+       bool result;
+       char *name;
+
+       pf = open_process_folder(pid);
+       if (pf == NULL)
+               return false;
+       name = process_name(pf);
+       result = is_name_Xorg(name);
+
+       close_folder(pf);
+       free(name);
+
+       return result;
+}
+
+static bool is_numeric(const char *str)
+{
+       return str[0] >= '0' && str[0] <= '9';
+}
+
+static bool is_Xorg_process_folder(const struct dirent *proc_entry)
+{
+       const char *folder_name = proc_entry->d_name;
+
+       if (is_numeric(folder_name) && is_Xorg(folder_name))
+               return true;
+
+       return false;
+}
+
+static bool iterate_through_all_process_folders_and_find_Xorg(void)
+{
+       DIR *proc_dir;
+       const struct dirent *proc_entry;
+       bool result = false;
+
+       proc_dir = opendir("/proc");
+       if (proc_dir == NULL)
+               return false;
+
+
+       while ((proc_entry = readdir(proc_dir)) != NULL) {
+               if (is_Xorg_process_folder(proc_entry)) {
+                       result = true;
+                       break;
+               }
+       }
+
+       closedir(proc_dir);
+       return result;
+}
+
+bool Xorg_running(void)
+{
+       return iterate_through_all_process_folders_and_find_Xorg();
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/module/Makefile 
new/evdi-1.14.7/module/Makefile
--- old/evdi-1.14.5/module/Makefile     2024-06-26 10:30:41.000000000 +0200
+++ new/evdi-1.14.7/module/Makefile     2024-09-20 11:14:26.000000000 +0200
@@ -52,6 +52,7 @@
 ccflags-y := -isystem include/uapi/drm $(CFLAGS) $(EL8FLAG) $(EL9FLAG) 
$(RPIFLAG)
 evdi-y := evdi_platform_drv.o evdi_platform_dev.o evdi_sysfs.o evdi_modeset.o 
evdi_connector.o evdi_encoder.o evdi_drm_drv.o evdi_fb.o evdi_gem.o 
evdi_painter.o evdi_params.o evdi_cursor.o evdi_debug.o evdi_i2c.o
 evdi-$(CONFIG_COMPAT) += evdi_ioc32.o
+CONFIG_DRM_EVDI ?= m
 obj-$(CONFIG_DRM_EVDI) := evdi.o
 obj-y += tests/
 
@@ -62,7 +63,7 @@
 DKMS ?= dkms
 RM ?= rm
 
-MODVER=1.14.5
+MODVER=1.14.7
 
 ifeq ($(KVER),)
        KVER := $(shell uname -r)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/module/dkms.conf 
new/evdi-1.14.7/module/dkms.conf
--- old/evdi-1.14.5/module/dkms.conf    2024-06-26 10:30:41.000000000 +0200
+++ new/evdi-1.14.7/module/dkms.conf    2024-09-20 11:14:26.000000000 +0200
@@ -7,7 +7,7 @@
 #
 
 PACKAGE_NAME="evdi"
-PACKAGE_VERSION=1.14.5
+PACKAGE_VERSION=1.14.7
 AUTOINSTALL=yes
 
 MAKE[0]="make all INCLUDEDIR=/lib/modules/$kernelver/build/include 
KVERSION=$kernelver DKMS_BUILD=1"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/module/dkms_install.sh 
new/evdi-1.14.7/module/dkms_install.sh
--- old/evdi-1.14.5/module/dkms_install.sh      2024-06-26 10:30:41.000000000 
+0200
+++ new/evdi-1.14.7/module/dkms_install.sh      2024-09-20 11:14:26.000000000 
+0200
@@ -2,7 +2,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 # Copyright (c) 2023 DisplayLink (UK) Ltd.
 
-evdi_version='1.14.5'
+evdi_version='1.14.7'
 
 EVDI_DIR=$(dirname "${BASH_SOURCE[0]}")
 EVDI_REBOOT_RATIONALE=
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/module/evdi_drm_drv.c 
new/evdi-1.14.7/module/evdi_drm_drv.c
--- old/evdi-1.14.5/module/evdi_drm_drv.c       2024-06-26 10:30:41.000000000 
+0200
+++ new/evdi-1.14.7/module/evdi_drm_drv.c       2024-09-20 11:14:26.000000000 
+0200
@@ -159,6 +159,8 @@
        kfree(evdi);
        dev->dev_private = NULL;
        EVDI_INFO("Evdi drm_device removed.\n");
+
+       EVDI_TEST_HOOK(evdi_testhook_drm_device_destroyed());
 }
 
 static int evdi_drm_device_init(struct drm_device *dev)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/module/evdi_drm_drv.h 
new/evdi-1.14.7/module/evdi_drm_drv.h
--- old/evdi-1.14.5/module/evdi_drm_drv.h       2024-06-26 10:30:41.000000000 
+0200
+++ new/evdi-1.14.7/module/evdi_drm_drv.h       2024-09-20 11:14:26.000000000 
+0200
@@ -38,7 +38,7 @@
 #include <drm/drm_framebuffer.h>
 
 #include "evdi_debug.h"
-
+#include "tests/evdi_test.h"
 
 struct evdi_fbdev;
 struct evdi_painter;
@@ -145,7 +145,7 @@
                             struct drm_crtc *crtc,
                             struct drm_pending_vblank_event *vblank);
 void evdi_painter_send_update_ready_if_needed(struct evdi_painter *painter);
-void evdi_painter_dpms_notify(struct evdi_device *evdi, int mode);
+void evdi_painter_dpms_notify(struct evdi_painter *painter, int mode);
 void evdi_painter_mode_changed_notify(struct evdi_device *evdi,
                                      struct drm_display_mode *mode);
 unsigned int evdi_painter_poll(struct file *filp,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/module/evdi_fb.c 
new/evdi-1.14.7/module/evdi_fb.c
--- old/evdi-1.14.5/module/evdi_fb.c    2024-06-26 10:30:41.000000000 +0200
+++ new/evdi-1.14.7/module/evdi_fb.c    2024-09-20 11:14:26.000000000 +0200
@@ -404,7 +404,7 @@
        fb = &efbdev->efb.base;
 
        efbdev->helper.fb = fb;
-#if KERNEL_VERSION(6, 2, 0) <= LINUX_VERSION_CODE || defined(EL8) || 
defined(EL9)
+#if KERNEL_VERSION(6, 1, 51) <= LINUX_VERSION_CODE || defined(EL8) || 
defined(EL9)
        efbdev->helper.info = info;
 #else
        efbdev->helper.fbdev = info;
@@ -464,7 +464,7 @@
 {
        struct fb_info *info;
 
-#if KERNEL_VERSION(6, 2, 0) <= LINUX_VERSION_CODE || defined(EL8) || 
defined(EL9)
+#if KERNEL_VERSION(6, 1, 51) <= LINUX_VERSION_CODE || defined(EL8) || 
defined(EL9)
        if (efbdev->helper.info) {
                info = efbdev->helper.info;
 #else
@@ -556,7 +556,7 @@
                return;
 
        efbdev = evdi->fbdev;
-#if KERNEL_VERSION(6, 2, 0) <= LINUX_VERSION_CODE || defined(EL8) || 
defined(EL9)
+#if KERNEL_VERSION(6, 1, 51) <= LINUX_VERSION_CODE || defined(EL8) || 
defined(EL9)
        if (efbdev->helper.info) {
                struct fb_info *info;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/module/evdi_modeset.c 
new/evdi-1.14.7/module/evdi_modeset.c
--- old/evdi-1.14.5/module/evdi_modeset.c       2024-06-26 10:30:41.000000000 
+0200
+++ new/evdi-1.14.7/module/evdi_modeset.c       2024-09-20 11:14:26.000000000 
+0200
@@ -86,7 +86,7 @@
                evdi_painter_mode_changed_notify(evdi, 
&crtc_state->adjusted_mode);
 
        if (notify_dpms)
-               evdi_painter_dpms_notify(evdi,
+               evdi_painter_dpms_notify(evdi->painter,
                        crtc_state->active ? DRM_MODE_DPMS_ON : 
DRM_MODE_DPMS_OFF);
 
        evdi_painter_set_vblank(evdi->painter, crtc, crtc_state->event);
@@ -258,9 +258,9 @@
        crtc = state->crtc;
 
        if (!old_state->crtc && state->crtc)
-               evdi_painter_dpms_notify(evdi, DRM_MODE_DPMS_ON);
+               evdi_painter_dpms_notify(evdi->painter, DRM_MODE_DPMS_ON);
        else if (old_state->crtc && !state->crtc)
-               evdi_painter_dpms_notify(evdi, DRM_MODE_DPMS_OFF);
+               evdi_painter_dpms_notify(evdi->painter, DRM_MODE_DPMS_OFF);
 
        if (state->fb) {
                struct drm_framebuffer *fb = state->fb;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/module/evdi_painter.c 
new/evdi-1.14.7/module/evdi_painter.c
--- old/evdi-1.14.5/module/evdi_painter.c       2024-06-26 10:30:41.000000000 
+0200
+++ new/evdi-1.14.7/module/evdi_painter.c       2024-09-20 11:14:26.000000000 
+0200
@@ -30,6 +30,10 @@
 #include <linux/completion.h>
 
 #include <linux/dma-buf.h>
+#include <linux/vt_kern.h>
+#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE
+#include <linux/compiler_attributes.h>
+#endif
 
 #if KERNEL_VERSION(5, 16, 0) <= LINUX_VERSION_CODE || defined(EL9)
 MODULE_IMPORT_NS(DMA_BUF);
@@ -104,6 +108,8 @@
        struct completion ddcci_response_received;
        char *ddcci_buffer;
        unsigned int ddcci_buffer_length;
+       struct notifier_block vt_notifier;
+       int fg_console;
 };
 
 static void expand_rect(struct drm_clip_rect *a, const struct drm_clip_rect *b)
@@ -500,6 +506,7 @@
 {
        struct drm_pending_event *event = create_dpms_event(mode);
 
+       EVDI_TEST_HOOK(evdi_testhook_painter_send_dpms(mode));
        evdi_painter_send_event(painter, event);
 }
 
@@ -696,13 +703,12 @@
 
 static const char * const dpms_str[] = { "on", "standby", "suspend", "off" };
 
-void evdi_painter_dpms_notify(struct evdi_device *evdi, int mode)
+void evdi_painter_dpms_notify(struct evdi_painter *painter, int mode)
 {
-       struct evdi_painter *painter = evdi->painter;
        const char *mode_str;
 
        if (!painter) {
-               EVDI_WARN("(card%d) Painter does not exist!", evdi->dev_index);
+               EVDI_WARN("Painter does not exist!");
                return;
        }
 
@@ -711,6 +717,11 @@
 
        switch (mode) {
        case DRM_MODE_DPMS_ON:
+               painter->fg_console = fg_console;
+#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE
+               fallthrough;
+#else
+#endif
        case DRM_MODE_DPMS_STANDBY:
        case DRM_MODE_DPMS_SUSPEND:
        case DRM_MODE_DPMS_OFF:
@@ -719,8 +730,8 @@
        default:
                mode_str = "unknown";
        };
-       EVDI_INFO("(card%d) Notifying display power state: %s",
-                  evdi->dev_index, mode_str);
+       EVDI_INFO("(card%d) Notifying display power state: %s\n",
+                  painter->drm_device->primary->index, mode_str);
        evdi_painter_send_dpms(painter, mode);
 }
 
@@ -1177,6 +1188,38 @@
        schedule_delayed_work(&painter->send_events_work, msecs_to_jiffies(5));
 }
 
+#define vt_notifier_block_to_evdi_painter(x) container_of(x, struct 
evdi_painter, vt_notifier)
+static int evdi_painter_vt_notifier_call(struct notifier_block *blk,
+                           __always_unused unsigned long code, __always_unused 
void *_param)
+{
+       struct evdi_painter *painter = vt_notifier_block_to_evdi_painter(blk);
+
+       if (painter->is_connected && fg_console != painter->fg_console && 
!painter->needs_full_modeset) {
+               EVDI_INFO("(card%d) VT switch detected\n", 
painter->drm_device->primary->index);
+               evdi_painter_dpms_notify(painter, DRM_MODE_DPMS_OFF);
+               evdi_painter_force_full_modeset(painter);
+       }
+
+       return NOTIFY_OK;
+}
+
+
+static void evdi_painter_register_to_vt(struct evdi_painter *painter)
+{
+       painter->vt_notifier.notifier_call = evdi_painter_vt_notifier_call;
+       register_vt_notifier(&painter->vt_notifier);
+
+       
EVDI_TEST_HOOK(evdi_testhook_painter_vt_register(&painter->vt_notifier));
+}
+
+static void evdi_painter_unregister_from_vt(struct evdi_painter *painter)
+{
+       unregister_vt_notifier(&painter->vt_notifier);
+       painter->vt_notifier.notifier_call = NULL;
+
+       
EVDI_TEST_HOOK(evdi_testhook_painter_vt_register(&painter->vt_notifier));
+}
+
 int evdi_painter_init(struct evdi_device *dev)
 {
        EVDI_CHECKPT();
@@ -1189,6 +1232,8 @@
                dev->painter->crtc = NULL;
                dev->painter->vblank = NULL;
                dev->painter->drm_device = dev->ddev;
+               evdi_painter_register_to_vt(dev->painter);
+
                INIT_LIST_HEAD(&dev->painter->pending_events);
                INIT_DELAYED_WORK(&dev->painter->send_events_work,
                        evdi_send_events_work);
@@ -1207,6 +1252,7 @@
        }
 
        painter_lock(painter);
+       evdi_painter_unregister_from_vt(painter);
        kfree(painter->edid);
        painter->edid_length = 0;
        painter->edid = NULL;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/module/evdi_platform_dev.c 
new/evdi-1.14.7/module/evdi_platform_dev.c
--- old/evdi-1.14.5/module/evdi_platform_dev.c  2024-06-26 10:30:41.000000000 
+0200
+++ new/evdi-1.14.7/module/evdi_platform_dev.c  2024-09-20 11:14:26.000000000 
+0200
@@ -85,7 +85,11 @@
        return PTR_ERR_OR_ZERO(dev);
 }
 
+#if KERNEL_VERSION(6, 11, 0) <= LINUX_VERSION_CODE
+void evdi_platform_device_remove(struct platform_device *pdev)
+#else
 int evdi_platform_device_remove(struct platform_device *pdev)
+#endif
 {
        struct evdi_platform_device_data *data = platform_get_drvdata(pdev);
 
@@ -93,7 +97,10 @@
 
        evdi_drm_device_remove(data->drm_dev);
        kfree(data);
+#if KERNEL_VERSION(6, 11, 0) <= LINUX_VERSION_CODE
+#else
        return 0;
+#endif
 }
 
 bool evdi_platform_device_is_free(struct platform_device *pdev)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/module/evdi_platform_dev.h 
new/evdi-1.14.7/module/evdi_platform_dev.h
--- old/evdi-1.14.5/module/evdi_platform_dev.h  2024-06-26 10:30:41.000000000 
+0200
+++ new/evdi-1.14.7/module/evdi_platform_dev.h  2024-09-20 11:14:26.000000000 
+0200
@@ -21,6 +21,7 @@
 #define _EVDI_PLATFORM_DEV_H_
 
 #include <linux/types.h>
+#include <linux/version.h>
 
 struct platform_device_info;
 struct platform_device;
@@ -31,7 +32,11 @@
 void evdi_platform_dev_destroy(struct platform_device *dev);
 
 int evdi_platform_device_probe(struct platform_device *pdev);
+#if KERNEL_VERSION(6, 11, 0) <= LINUX_VERSION_CODE
+void evdi_platform_device_remove(struct platform_device *pdev);
+#else
 int evdi_platform_device_remove(struct platform_device *pdev);
+#endif
 bool evdi_platform_device_is_free(struct platform_device *pdev);
 void evdi_platform_device_link(struct platform_device *pdev,
                                struct device *parent);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/module/evdi_platform_drv.h 
new/evdi-1.14.7/module/evdi_platform_drv.h
--- old/evdi-1.14.5/module/evdi_platform_drv.h  2024-06-26 10:30:41.000000000 
+0200
+++ new/evdi-1.14.7/module/evdi_platform_drv.h  2024-09-20 11:14:26.000000000 
+0200
@@ -25,11 +25,11 @@
 
 #define DRIVER_NAME   "evdi"
 #define DRIVER_DESC   "Extensible Virtual Display Interface"
-#define DRIVER_DATE   "20240626"
+#define DRIVER_DATE   "20240920"
 
 #define DRIVER_MAJOR 1
 #define DRIVER_MINOR 14
-#define DRIVER_PATCH 5
+#define DRIVER_PATCH 7
 
 void evdi_platform_remove_all_devices(struct device *device);
 unsigned int evdi_platform_device_count(struct device *device);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/module/tests/Makefile 
new/evdi-1.14.7/module/tests/Makefile
--- old/evdi-1.14.5/module/tests/Makefile       2024-06-26 10:30:41.000000000 
+0200
+++ new/evdi-1.14.7/module/tests/Makefile       2024-09-20 11:14:26.000000000 
+0200
@@ -1,4 +1,5 @@
 
 ccflags-$(CONFIG_DRM_EVDI_KUNIT_TEST) += -I$(srctree)/drivers/gpu/drm/evdi
-obj-$(CONFIG_DRM_EVDI_KUNIT_TEST) += evdi_test.o
+
+obj-$(CONFIG_DRM_EVDI_KUNIT_TEST) += evdi_test.o test_evdi_vt_switch.o 
evdi_fake_user_client.o evdi_fake_compositor.o
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/module/tests/evdi_fake_compositor.c 
new/evdi-1.14.7/module/tests/evdi_fake_compositor.c
--- old/evdi-1.14.5/module/tests/evdi_fake_compositor.c 1970-01-01 
01:00:00.000000000 +0100
+++ new/evdi-1.14.7/module/tests/evdi_fake_compositor.c 2024-09-20 
11:14:26.000000000 +0200
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2024 DisplayLink (UK) Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+
+#include <kunit/test.h>
+#include <kunit/test-bug.h>
+#include <kunit/device.h>
+
+#include <linux/file.h>
+#include <linux/vt_kern.h>
+
+#include <drm/drm_fourcc.h>
+
+#include "evdi_drm_drv.h"
+#include "evdi_drm.h"
+#include "tests/evdi_test.h"
+#include "tests/evdi_fake_compositor.h"
+
+
+void evdi_fake_compositor_create(struct kunit *test)
+{
+       struct kunit_resource *resource;
+       struct evdi_fake_compositor_data *compositor_data;
+
+       resource = kunit_find_named_resource(test, "fake_wayland");
+       if (resource) {
+               KUNIT_FAIL(test, "fake_wayland data already exists");
+               return;
+       }
+
+       resource = kunit_kzalloc(test, sizeof(struct kunit_resource), 
GFP_KERNEL);
+       compositor_data = kunit_kzalloc(test, sizeof(struct 
evdi_fake_compositor_data), GFP_KERNEL);
+       kunit_add_named_resource(test, NULL, NULL, resource, "fake_wayland", 
compositor_data);
+
+       static const struct drm_display_mode default_mode = {
+                       DRM_SIMPLE_MODE(640, 480, 64, 48)
+       };
+       struct evdi_framebuffer efb =  {
+               .base = {
+                       .format = drm_format_info(DRM_FORMAT_XRGB8888),
+                       .pitches = { 4*640, 0, 0 },
+                       },
+               .obj = NULL,
+               .active = true
+       };
+
+       compositor_data->efb = kunit_kzalloc(test, sizeof(struct 
evdi_framebuffer), GFP_KERNEL);
+       memcpy(compositor_data->efb, &efb, sizeof(struct evdi_framebuffer));
+       memcpy(&compositor_data->mode, &default_mode, sizeof(default_mode));
+}
+
+void evdi_fake_compositor_connect(struct kunit *test, struct drm_device 
*device)
+{
+       struct kunit_resource *resource = kunit_find_named_resource(test, 
"fake_wayland");
+       struct evdi_fake_compositor_data *compositor_data = resource->data;
+       struct evdi_device *evdi = (struct evdi_device *)device->dev_private;
+
+       evdi_painter_set_scanout_buffer(evdi->painter, compositor_data->efb);
+       evdi_painter_mode_changed_notify(evdi, &compositor_data->mode);
+       evdi_painter_dpms_notify(evdi->painter, DRM_MODE_DPMS_ON);
+}
+
+void evdi_fake_compositor_disconnect(__maybe_unused struct kunit *test, 
__maybe_unused struct drm_device *device)
+{
+}
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/module/tests/evdi_fake_compositor.h 
new/evdi-1.14.7/module/tests/evdi_fake_compositor.h
--- old/evdi-1.14.5/module/tests/evdi_fake_compositor.h 1970-01-01 
01:00:00.000000000 +0100
+++ new/evdi-1.14.7/module/tests/evdi_fake_compositor.h 2024-09-20 
11:14:26.000000000 +0200
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Copyright (c) 2024 DisplayLink (UK) Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#ifndef EVDI_FAKE_COMPOSITOR_H
+#define EVDI_FAKE_COMPOSITOR_H
+
+#ifdef CONFIG_DRM_EVDI_KUNIT_TEST
+
+
+#include <kunit/test.h>
+#include <kunit/test-bug.h>
+#include <kunit/device.h>
+
+
+
+/* kunit tests helpers faking userspace compositor leveraging evdi to add 
virtual display.
+ * e.g. Xorg, gnome-wayland, kwin
+ */
+struct evdi_fake_compositor_data {
+       struct evdi_framebuffer *efb;
+       struct drm_display_mode mode;
+};
+
+void evdi_fake_compositor_create(struct kunit *test);
+void evdi_fake_compositor_connect(struct kunit *test, struct drm_device 
*device);
+void evdi_fake_compositor_disconnect(struct kunit *test, struct drm_device 
*device);
+
+
+#endif // CONFIG_DRM_EVDI_KUNIT_TEST
+#endif // EVDI_FAKE_COMPOSITOR_H
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/module/tests/evdi_fake_user_client.c 
new/evdi-1.14.7/module/tests/evdi_fake_user_client.c
--- old/evdi-1.14.5/module/tests/evdi_fake_user_client.c        1970-01-01 
01:00:00.000000000 +0100
+++ new/evdi-1.14.7/module/tests/evdi_fake_user_client.c        2024-09-20 
11:14:26.000000000 +0200
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2024 DisplayLink (UK) Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+
+#include <kunit/test.h>
+#include <kunit/test-bug.h>
+#include <kunit/device.h>
+
+#include <linux/file.h>
+#include <linux/vt_kern.h>
+
+#include <drm/drm_file.h>
+
+#include "evdi_drm_drv.h"
+#include "evdi_drm.h"
+#include "tests/evdi_test.h"
+#include "tests/evdi_fake_user_client.h"
+
+/* copied from drm/tests/drm_kunit_edid.h */
+static const unsigned char test_edid_dvi_1080p[] = {
+       0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x31, 0xd8, 0x2a, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x01, 0x03, 0x81, 0xa0, 0x5a, 0x78,
+       0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38,
+       0x2d, 0x40, 0x58, 0x2c, 0x45, 0x00, 0x40, 0x84, 0x63, 0x00, 0x00, 0x1e,
+       0x00, 0x00, 0x00, 0xfc, 0x00, 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x44,
+       0x49, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x32,
+       0x46, 0x1e, 0x46, 0x0f, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+       0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab
+};
+
+void evdi_fake_user_client_create(struct kunit *test)
+{
+       struct kunit_resource *resource;
+       struct evdi_fake_user_data *user_data;
+
+       resource = kunit_find_named_resource(test, "fake_evdi_user");
+       if (resource) {
+               KUNIT_FAIL(test, "fake_evdi_user data already exists");
+               return;
+       }
+
+       resource = kunit_kzalloc(test, sizeof(struct kunit_resource), 
GFP_KERNEL);
+       user_data = kunit_kzalloc(test, sizeof(struct evdi_fake_user_data), 
GFP_KERNEL);
+       kunit_add_named_resource(test, NULL, NULL, resource, "fake_evdi_user", 
user_data);
+}
+
+void evdi_fake_user_client_connect(struct kunit *test, struct drm_device 
*device)
+{
+       struct kunit_resource *resource = kunit_find_named_resource(test, 
"fake_evdi_user");
+       struct evdi_fake_user_data *user_data = resource->data;
+
+       void __user *user_edid = evdi_kunit_alloc_usermem(test, 
sizeof(test_edid_dvi_1080p));
+       struct drm_evdi_connect connect_data = {
+               .connected = true,
+               .dev_index = device->primary->index,
+               .edid = user_edid,
+               .edid_length = sizeof(test_edid_dvi_1080p),
+               .pixel_area_limit = 1920 * 1080,
+               .pixel_per_second_limit = 1920 * 1080 * 60,
+       };
+
+       if (copy_to_user((unsigned char * __user)connect_data.edid, 
test_edid_dvi_1080p, sizeof(test_edid_dvi_1080p)))
+               KUNIT_FAIL(test, "Failed to copy edid to userspace memory");
+       user_data->file = mock_drm_getfile(device->primary, O_RDWR);
+
+       evdi_painter_connect_ioctl(device, &connect_data, 
user_data->file->private_data);
+}
+
+void evdi_fake_user_client_disconnect(struct kunit *test, struct drm_device 
*device)
+{
+       struct kunit_resource *resource = kunit_find_named_resource(test, 
"fake_evdi_user");
+       struct evdi_fake_user_data *user_data = resource->data;
+
+       if (user_data->file) {
+               fput(user_data->file);
+               user_data->file = NULL;
+               flush_delayed_fput();
+       }
+}
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/module/tests/evdi_fake_user_client.h 
new/evdi-1.14.7/module/tests/evdi_fake_user_client.h
--- old/evdi-1.14.5/module/tests/evdi_fake_user_client.h        1970-01-01 
01:00:00.000000000 +0100
+++ new/evdi-1.14.7/module/tests/evdi_fake_user_client.h        2024-09-20 
11:14:26.000000000 +0200
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Copyright (c) 2024 DisplayLink (UK) Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#ifndef EVDI_FAKE_USER_CLIENT_H
+#define EVDI_FAKE_USER_CLIENT_H
+
+#ifdef CONFIG_DRM_EVDI_KUNIT_TEST
+
+
+#include <kunit/test.h>
+#include <kunit/test-bug.h>
+#include <kunit/device.h>
+
+#include <linux/file.h>
+#include <linux/compiler_types.h>
+#include <drm/drm_device.h>
+
+/* kunit tests helpers faking evdi userspace client, usually 
displaylink-driver daemon. */
+
+struct evdi_fake_user_data {
+       struct file *file;
+};
+void __user *evdi_kunit_alloc_usermem(struct kunit *test, unsigned int size);
+
+void evdi_fake_user_client_create(struct kunit *test);
+void evdi_fake_user_client_connect(struct kunit *test, struct drm_device 
*device);
+void evdi_fake_user_client_disconnect(struct kunit *test, struct drm_device 
*device);
+
+#endif // CONFIG_DRM_EVDI_KUNIT_TEST
+#endif // EVDI_FAKE_USER_CLIENT_H
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/module/tests/evdi_test.c 
new/evdi-1.14.7/module/tests/evdi_test.c
--- old/evdi-1.14.5/module/tests/evdi_test.c    2024-06-26 10:30:41.000000000 
+0200
+++ new/evdi-1.14.7/module/tests/evdi_test.c    2024-09-20 11:14:26.000000000 
+0200
@@ -7,21 +7,103 @@
  * more details.
  */
 
-
+#include <linux/jiffies.h>
 #include <kunit/test.h>
+#include <kunit/test-bug.h>
 #include <kunit/device.h>
+#include <linux/mman.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/jiffies.h>
 #include "evdi_drm_drv.h"
 
+void __user *evdi_kunit_alloc_usermem(struct kunit *test, unsigned int size)
+{
+       void *kmem = kunit_kzalloc(test, size, GFP_KERNEL);
+       unsigned long user_addr;
+
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, kmem);
+
+       user_addr = kunit_vm_mmap(test, NULL, 0, size,
+                           PROT_READ | PROT_WRITE | PROT_EXEC,
+                           MAP_ANONYMOUS | MAP_PRIVATE, 0);
+       KUNIT_ASSERT_NE_MSG(test, user_addr, 0,
+               "Could not create userspace mm");
+       KUNIT_ASSERT_LT_MSG(test, user_addr, (unsigned long)TASK_SIZE,
+               "Failed to allocate user memory");
+
+       return (void __user *)user_addr;
+}
+
+void evdi_testhook_painter_vt_register(struct notifier_block *vt_notifier)
+{
+       struct kunit *test = kunit_get_current_test();
+       struct evdi_test_data *base = (struct evdi_test_data *)test->priv;
+
+       if (base && base->hooks.painter_vt_register)
+               base->hooks.painter_vt_register(vt_notifier);
+}
+
+void evdi_testhook_painter_send_dpms(int mode)
+{
+       struct kunit *test = kunit_get_current_test();
+       struct evdi_test_data *base = (struct evdi_test_data *)test->priv;
+
+       if (base && base->hooks.painter_send_dpms)
+               base->hooks.painter_send_dpms(mode);
+}
+
+void evdi_testhook_drm_device_destroyed(void)
+{
+       struct kunit *test = kunit_get_current_test();
+       struct evdi_test_data *base = (struct evdi_test_data *)test->priv;
+
+       if (base && base->hooks.drm_device_destroyed)
+               base->hooks.drm_device_destroyed();
+}
+
+static void testhook_drm_device_destroyed(void)
+{
+       struct kunit *test = kunit_get_current_test();
+       struct evdi_test_data *base = (struct evdi_test_data *)test->priv;
+
+       complete(base->dev_destroyed);
+}
+
+void evdi_test_data_init(struct kunit *test, struct evdi_test_data *data)
+{
+       data->parent = kunit_device_register(test, "/dev/card1");
+       data->dev_destroyed = kunit_kzalloc(test, sizeof(struct completion), 
GFP_KERNEL);
+       init_completion(data->dev_destroyed);
+
+       data->hooks.drm_device_destroyed = testhook_drm_device_destroyed;
+       test->priv = (void *)data;
+}
+
+void evdi_test_data_exit(struct kunit *test, struct evdi_test_data *data)
+{
+       if (!wait_for_completion_timeout(data->dev_destroyed, 
msecs_to_jiffies(1000)))
+               KUNIT_FAIL(test, "Failed to wait for drm_device removal\n");
+
+       kunit_device_unregister(test, data->parent);
+}
+
 static void test_evdi_create_drm_device(struct kunit *test)
 {
-       struct device *parent = kunit_device_register(test, "/dev/card1");
-       struct drm_device *dev = evdi_drm_device_create(parent);
+       struct evdi_test_data *data = kunit_kzalloc(test, sizeof(struct 
evdi_test_data), GFP_KERNEL);
+       struct drm_device *dev;
+
+       evdi_test_data_init(test, data);
+
+       dev = evdi_drm_device_create(data->parent);
 
        KUNIT_EXPECT_NOT_NULL(test, dev);
 
        evdi_drm_device_remove(dev);
-
-       kunit_device_unregister(test, parent);
+       evdi_test_data_exit(test, data);
+       kunit_kfree(test, test->priv);
 }
 
 static struct kunit_case evdi_test_cases[] = {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/module/tests/evdi_test.h 
new/evdi-1.14.7/module/tests/evdi_test.h
--- old/evdi-1.14.5/module/tests/evdi_test.h    1970-01-01 01:00:00.000000000 
+0100
+++ new/evdi-1.14.7/module/tests/evdi_test.h    2024-09-20 11:14:26.000000000 
+0200
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Copyright (c) 2024 DisplayLink (UK) Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+
+#ifndef EVDI_TEST_H
+#define EVDI_TEST_H
+
+#ifdef CONFIG_DRM_EVDI_KUNIT_TEST
+#define EVDI_TEST_HOOK(foo) foo
+#else
+#include <linux/printk.h>
+#define EVDI_TEST_HOOK(foo) no_printk(__stringify(foo))
+#endif
+
+#ifdef CONFIG_DRM_EVDI_KUNIT_TEST
+
+#include <linux/completion.h>
+
+/* evdi hooks for kunit tests */
+void evdi_testhook_painter_vt_register(struct notifier_block *vt_notifier);
+void evdi_testhook_painter_send_dpms(int mode);
+void evdi_testhook_drm_device_destroyed(void);
+
+struct evdi_test_hooks {
+       void (*painter_vt_register)(struct notifier_block *vt_notifier);
+       void (*painter_send_dpms)(int mode);
+       void (*drm_device_destroyed)(void);
+};
+
+/* evdi kunit base type for test private data */
+struct evdi_test_data {
+       struct device *parent;
+       struct drm_device *dev;
+       struct completion *dev_destroyed;
+       struct evdi_test_hooks hooks;
+};
+
+void evdi_test_data_init(struct kunit *test, struct evdi_test_data *data);
+void evdi_test_data_exit(struct kunit *test, struct evdi_test_data *data);
+
+/* evdi test utils */
+void __user *evdi_kunit_alloc_usermem(struct kunit *test, unsigned int size);
+
+#endif // CONFIG_DRM_EVDI_KUNIT_TEST
+#endif // EVDI_TEST_H
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/module/tests/test_evdi_vt_switch.c 
new/evdi-1.14.7/module/tests/test_evdi_vt_switch.c
--- old/evdi-1.14.5/module/tests/test_evdi_vt_switch.c  1970-01-01 
01:00:00.000000000 +0100
+++ new/evdi-1.14.7/module/tests/test_evdi_vt_switch.c  2024-09-20 
11:14:26.000000000 +0200
@@ -0,0 +1,176 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2024 DisplayLink (UK) Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+
+#include <kunit/test.h>
+#include <kunit/test-bug.h>
+#include <kunit/device.h>
+#include <linux/vt_kern.h>
+#include "evdi_drm_drv.h"
+#include "tests/evdi_test.h"
+#include "tests/evdi_fake_user_client.h"
+#include "tests/evdi_fake_compositor.h"
+
+
+struct evdi_vt_test {
+       struct evdi_test_data base;
+       struct notifier_block *vt_notifier;
+       int dpms_mode;
+};
+#define to_evdi_vt_test(x) container_of(x, struct evdi_vt_test, base)
+
+static void testhook_painter_vt_register(struct notifier_block *vt_notifier)
+{
+       struct kunit *test = kunit_get_current_test();
+       struct evdi_vt_test *data = to_evdi_vt_test(test->priv);
+
+       data->vt_notifier = vt_notifier;
+}
+
+static void testhook_painter_send_dpms(int mode)
+{
+       struct kunit *test = kunit_get_current_test();
+       struct evdi_test_data *base = (struct evdi_test_data *)test->priv;
+       struct evdi_vt_test *data = to_evdi_vt_test(base);
+
+       data->dpms_mode = mode;
+}
+
+static int suite_test_vt_init(struct kunit *test)
+{
+       struct evdi_vt_test *data = kunit_kzalloc(test, sizeof(struct 
evdi_vt_test), GFP_KERNEL);
+
+       evdi_test_data_init(test, &data->base);
+       data->base.hooks.painter_vt_register = testhook_painter_vt_register;
+       data->base.hooks.painter_send_dpms = testhook_painter_send_dpms;
+       data->base.dev = evdi_drm_device_create(data->base.parent);
+
+       return 0;
+}
+
+static void suite_test_vt_exit(struct kunit *test)
+{
+       struct evdi_vt_test *data = to_evdi_vt_test(test->priv);
+
+       if (data->base.dev) {
+               evdi_drm_device_remove(data->base.dev);
+               data->base.dev = NULL;
+       }
+
+       evdi_test_data_exit(test, &data->base);
+       kunit_kfree(test, test->priv);
+}
+
+static int suite_test_vt_and_user_connected_init(struct kunit *test)
+{
+       int result = suite_test_vt_init(test);
+       struct evdi_vt_test *data = (struct evdi_vt_test *)test->priv;
+
+       KUNIT_EXPECT_EQ(test, result, 0);
+       evdi_fake_compositor_create(test);
+       evdi_fake_user_client_create(test);
+
+       KUNIT_EXPECT_NE(test, data->dpms_mode, DRM_MODE_DPMS_OFF);
+       evdi_fake_user_client_connect(test, data->base.dev);
+       evdi_fake_compositor_connect(test, data->base.dev);
+
+       return result;
+}
+
+static void suite_test_vt_and_user_connected_exit(struct kunit *test)
+{
+       struct evdi_vt_test *data = to_evdi_vt_test(test->priv);
+
+       evdi_fake_compositor_disconnect(test, data->base.dev);
+       evdi_fake_user_client_disconnect(test, data->base.dev);
+
+       return suite_test_vt_exit(test);
+}
+
+static void test_evdi_painter_registers_for_vt(struct kunit *test)
+{
+       struct evdi_vt_test *data = to_evdi_vt_test(test->priv);
+
+       KUNIT_EXPECT_NOT_NULL(test, data->vt_notifier->notifier_call);
+}
+
+static void test_evdi_painter_unregisters_for_vt_on_removal(struct kunit *test)
+{
+       struct evdi_vt_test *data = to_evdi_vt_test(test->priv);
+
+       evdi_drm_device_remove(data->base.dev);
+       data->base.dev = NULL;
+
+       KUNIT_EXPECT_NULL(test, data->vt_notifier->notifier_call);
+}
+
+static void 
test_evdi_painter_when_not_connected_does_not_send_dpms_off_event_on_fg_console_change(struct
 kunit *test)
+{
+       struct evdi_vt_test *data = to_evdi_vt_test(test->priv);
+
+       KUNIT_EXPECT_NE(test, data->dpms_mode, DRM_MODE_DPMS_OFF);
+
+       data->vt_notifier->notifier_call(data->vt_notifier, 0, NULL);
+
+       KUNIT_EXPECT_NE(test, data->dpms_mode, DRM_MODE_DPMS_OFF);
+}
+
+static void 
test_evdi_painter_when_connected_does_not_send_dpms_off_event_when_fg_console_has_not_changed(struct
 kunit *test)
+{
+       struct evdi_vt_test *data = to_evdi_vt_test(test->priv);
+       struct evdi_device *evdi = (struct evdi_device 
*)data->base.dev->dev_private;
+
+       data->vt_notifier->notifier_call(data->vt_notifier, 0, NULL);
+
+       KUNIT_EXPECT_EQ(test, data->dpms_mode, DRM_MODE_DPMS_ON);
+       KUNIT_EXPECT_FALSE(test, 
evdi_painter_needs_full_modeset(evdi->painter));
+}
+
+static void 
test_evdi_painter_when_connected_sends_dpms_off_event_on_fg_console_change(struct
 kunit *test)
+{
+       struct evdi_vt_test *data = to_evdi_vt_test(test->priv);
+       struct evdi_device *evdi = (struct evdi_device 
*)data->base.dev->dev_private;
+
+       fg_console = fg_console + 1;
+
+       data->vt_notifier->notifier_call(data->vt_notifier, 0, NULL);
+
+       KUNIT_EXPECT_EQ(test, data->dpms_mode, DRM_MODE_DPMS_OFF);
+       KUNIT_EXPECT_TRUE(test, evdi_painter_needs_full_modeset(evdi->painter));
+}
+
+static struct kunit_case evdi_test_cases[] = {
+       KUNIT_CASE(test_evdi_painter_registers_for_vt),
+       KUNIT_CASE(test_evdi_painter_unregisters_for_vt_on_removal),
+       
KUNIT_CASE(test_evdi_painter_when_not_connected_does_not_send_dpms_off_event_on_fg_console_change),
+       {}
+};
+
+static struct kunit_case evdi_test_cases_with_user_connected[] = {
+       
KUNIT_CASE(test_evdi_painter_when_connected_does_not_send_dpms_off_event_when_fg_console_has_not_changed),
+       
KUNIT_CASE(test_evdi_painter_when_connected_sends_dpms_off_event_on_fg_console_change),
+       {}
+};
+
+static struct kunit_suite evdi_test_suite = {
+       .name = "drm_evdi_vt_tests",
+       .test_cases = evdi_test_cases,
+       .init = suite_test_vt_init,
+       .exit = suite_test_vt_exit,
+};
+
+static struct kunit_suite evdi_test_suite_with_connected_user = {
+       .name = "drm_evdi_vt_tests_with_connected_user",
+       .test_cases = evdi_test_cases_with_user_connected,
+       .init = suite_test_vt_and_user_connected_init,
+       .exit = suite_test_vt_and_user_connected_exit,
+};
+
+kunit_test_suite(evdi_test_suite_with_connected_user);
+kunit_test_suite(evdi_test_suite);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/pyevdi/PyEvdi.cpp 
new/evdi-1.14.7/pyevdi/PyEvdi.cpp
--- old/evdi-1.14.5/pyevdi/PyEvdi.cpp   2024-06-26 10:30:41.000000000 +0200
+++ new/evdi-1.14.7/pyevdi/PyEvdi.cpp   2024-09-20 11:14:26.000000000 +0200
@@ -40,7 +40,7 @@
 {
        m.doc() = "Python bindings for evdi library";
 
-       evdi_logging el;
+       evdi_logging el = { .function = &log_function, .user_data = nullptr};
        el.function = &log_function;
        evdi_set_logging(el);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/pyevdi/Stats.h 
new/evdi-1.14.7/pyevdi/Stats.h
--- old/evdi-1.14.5/pyevdi/Stats.h      2024-06-26 10:30:41.000000000 +0200
+++ new/evdi-1.14.7/pyevdi/Stats.h      2024-09-20 11:14:26.000000000 +0200
@@ -3,6 +3,7 @@
 #define STATS_H
 
 #include <functional>
+#include <chrono>
 
 #include "Buffer.h"
 #include "../library/evdi_lib.h"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/pyevdi/pytest.run.sh 
new/evdi-1.14.7/pyevdi/pytest.run.sh
--- old/evdi-1.14.5/pyevdi/pytest.run.sh        2024-06-26 10:30:41.000000000 
+0200
+++ new/evdi-1.14.7/pyevdi/pytest.run.sh        2024-09-20 11:14:26.000000000 
+0200
@@ -1,32 +1,36 @@
 #!/bin/bash
 set -eou pipefail
 
-if [ ! -d .venv_evdi ]; then
-    # prepare python virtualenv for tests
-    python3 -m virtualenv .venv_evdi
-    source .venv_evdi/bin/activate
+evdi_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
+
+if [ ! -v VIRTUAL_ENV ]; then
+    if [ ! -d "${evdi_dir}"/.venv_evdi ]; then
+        # prepare python virtualenv for tests
+        python3 -m virtualenv "${evdi_dir}"/.venv_evdi
+    fi
+    # shellcheck disable=SC1091
+    source "${evdi_dir}"/.venv_evdi/bin/activate
     pip3 install pytest
     pip3 install pytest-mock
     pip3 install pybind11
-
-    # build module, library, pybindings
-    cd ../library
-    make
-    cd ../module
-    lsmod | grep evdi > /dev/null || sudo make install_dkms
-
-    cd ../pyevdi
-    make
-
-    cp ../library/libevdi.so* .venv_evdi/lib/
-    cp PyEvdi*.so* $(pybind11-config --pkgconfigdir)/../../../
-    deactivate
-
-    # add evdi device
-    lsmod | grep evdi > /dev/null || sudo modprobe evdi
-    [ $(cat /sys/devices/evdi/count) == "0" ] && echo 1 | sudo tee -a 
/sys/devices/evdi/add && sleep 1
 fi
 
-source .venv_evdi/bin/activate
-LD_LIBRARY_PATH=$VIRTUAL_ENV/lib pytest $@
+
+# build module, library, pybindings
+cd "${evdi_dir}"/library
+make
+cd "${evdi_dir}"/module
+lsmod | grep evdi > /dev/null || sudo make install_dkms
+
+cd "${evdi_dir}"/pyevdi
+make
+
+cp "${evdi_dir}"/library/libevdi.so* "${VIRTUAL_ENV}"/lib/
+cp PyEvdi*.so* "$(pybind11-config --pkgconfigdir)"/../../../
+
+# add evdi device
+lsmod | grep evdi > /dev/null || sudo modprobe evdi
+[ "$(cat /sys/devices/evdi/count)" == "0" ] && echo 1 | sudo tee -a 
/sys/devices/evdi/add && sleep 1
+
+LD_LIBRARY_PATH=$VIRTUAL_ENV/lib pytest "$@"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/evdi-1.14.5/pyevdi/test/test_connect.py 
new/evdi-1.14.7/pyevdi/test/test_connect.py
--- old/evdi-1.14.5/pyevdi/test/test_connect.py 2024-06-26 10:30:41.000000000 
+0200
+++ new/evdi-1.14.7/pyevdi/test/test_connect.py 2024-09-20 11:14:26.000000000 
+0200
@@ -5,6 +5,18 @@
 import time
 import logging
 
+@pytest.fixture
+def pyevdi_card():
+    card = PyEvdi.Card(utilities.get_available_evdi_card())
+    yield card
+    card.close()
+
+@pytest.fixture
+def pyevdi_connect(pyevdi_card):
+    edid = utilities.get_edid()
+    pyevdi_card.connect(edid, len(edid), utilities._FullHDAreaLimit, 
utilities._FullHDAreaLimit * utilities._60Hz)
+    yield
+    pyevdi_card.disconnect()
 
 logging.getLogger().setLevel(20);
 
@@ -13,43 +25,27 @@
 
 @pytest.mark.skipif(utilities.get_available_evdi_card() == -1, reason = 'No 
available device.')
 @pytest.mark.skipif(utilities.get_available_evdi_card() == -1 and 
utilities.is_not_running_as_root(), reason = 'Please run test as root.')
-def testModeChangedHandlerCalledAfterConnect(mocker):
+def test_mode_changed_handler_called_after_connect(mocker, pyevdi_card, 
pyevdi_connect):
     mock_requests = mocker.patch("test_connect.my_mode_changed_handler", 
return_value = None)
-
-    card = PyEvdi.Card(utilities.get_available_evdi_card())
-    edid = utilities.get_edid()
-    card.connect(edid, len(edid), utilities._FullHDAreaLimit, 
utilities._FullHDAreaLimit * utilities._60Hz)
-
+    card = pyevdi_card
     card.mode_changed_handler = my_mode_changed_handler
-
     timoutms=100
-
     start_time = time.time()
 
     while time.time() < start_time + 60 and not mock_requests.called:
         card.handle_events(timoutms)
 
-    card.disconnect()
-    card.close()
-
     mock_requests.assert_called()
 
 @pytest.mark.skipif(utilities.get_available_evdi_card() == -1, reason = 'No 
available device.')
 @pytest.mark.skipif(utilities.get_available_evdi_card() == -1 and 
utilities.is_not_running_as_root(), reason = 'Please run test as root.')
-def testHandlingEventsTenTimesWithDefaultHandlers():
-    card = PyEvdi.Card(utilities.get_available_evdi_card())
-
-    edid = utilities.get_edid()
-    card.connect(edid, len(edid), utilities._FullHDAreaLimit, 
utilities._FullHDAreaLimit * utilities._60Hz)
-
-
+def test_handling_events_ten_times_with_default_handlers(pyevdi_card, 
pyevdi_connect):
+    card = pyevdi_card
     timoutms=1000
+
     for i in range(10):
         card.handle_events(timoutms)
 
-    card.disconnect()
-    card.close()
-
 def my_acquire_framebuffer_handler(buffer) -> None:
     print("received buffer", buffer.id)
     print("rect_count:", buffer.rect_count, "\nrects:")
@@ -59,34 +55,39 @@
 
 @pytest.mark.skipif(utilities.get_available_evdi_card() == -1, reason = 'No 
available device.')
 @pytest.mark.skipif(utilities.get_available_evdi_card() == -1 and 
utilities.is_not_running_as_root(), reason = 'Please run test as root.')
-def testHandlingEventsTenTimesWithAquireFramebufferSet():
-    card = PyEvdi.Card(utilities.get_available_evdi_card())
-
+def test_handling_events_ten_times_with_aquire_framebuffer_set(pyevdi_card, 
pyevdi_connect):
+    card = pyevdi_card
     card.acquire_framebuffer_handler = my_acquire_framebuffer_handler
-
-    edid = utilities.get_edid()
-    card.connect(edid, len(edid), utilities._FullHDAreaLimit, 
utilities._FullHDAreaLimit * utilities._60Hz)
-
     timoutms=1000
+
     for i in range(10):
         card.handle_events(timoutms)
 
-    card.disconnect()
-    card.close()
-
 @pytest.mark.skipif(utilities.get_available_evdi_card() == -1 and 
utilities.is_not_running_as_root(), reason = 'Please run test as root.')
-def testReadingBuffer():
+def test_reading_buffer():
     stats = PyEvdi.MemoryAccessStats()
     card = PyEvdi.Card(utilities.get_available_evdi_card(), stats)
-
     card.acquire_framebuffer_handler = stats
-
     edid = utilities.get_edid()
-    card.connect(edid, len(edid), utilities._FullHDAreaLimit, 
utilities._FullHDAreaLimit * utilities._60Hz)
 
+    card.connect(edid, len(edid), utilities._FullHDAreaLimit, 
utilities._FullHDAreaLimit * utilities._60Hz)
     card.handle_events(1000)
 
     assert stats.totalGrabPixelsTime() > 0
     card.disconnect()
     card.close()
 
+@pytest.mark.skipif(utilities.get_available_evdi_card() == -1, reason = 'No 
available device.')
+@pytest.mark.skipif(utilities.get_available_evdi_card() == -1 and 
utilities.is_not_running_as_root(), reason = 'Please run test as root.')
+def test_time_of_first_frame(pyevdi_card, pyevdi_connect):
+    # never fails, because wait_for_master
+    # does not timeout when the card is opened
+    start = time.time()
+    card = pyevdi_card
+    timeout_in_seconds_to_recieve_frame = 2
+    ms_in_s = 1000
+
+    card.handle_events(timeout_in_seconds_to_recieve_frame * ms_in_s)
+    end = time.time()
+
+    assert end - start < timeout_in_seconds_to_recieve_frame, 'Turning on is 
too long'

++++++ evdi.obsinfo ++++++
--- /var/tmp/diff_new_pack.3UjMHO/_old  2024-10-04 17:11:39.575632801 +0200
+++ /var/tmp/diff_new_pack.3UjMHO/_new  2024-10-04 17:11:39.579632967 +0200
@@ -1,5 +1,5 @@
 name: evdi
-version: 1.14.5
-mtime: 1719390641
-commit: cbc3c4f42cd33e31d453ff79c2b945ea6e3d32f3
+version: 1.14.7
+mtime: 1726823666
+commit: 14286c973dba40199c977ade9d6dca8a19f93e61
 

Reply via email to