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 = ¤t->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