{"id":376,"date":"2026-03-21T23:19:21","date_gmt":"2026-03-21T22:19:21","guid":{"rendered":"https:\/\/kosokoking.com\/?p=376"},"modified":"2026-03-21T23:19:22","modified_gmt":"2026-03-21T22:19:22","slug":"fixing-displaylink-on-parrot-os-7","status":"publish","type":"post","link":"https:\/\/kosokoking.com\/index.php\/technology\/fixing-displaylink-on-parrot-os-7\/","title":{"rendered":"Fixing DisplayLink on Parrot OS 7"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Most of my work happens on a Mac. Some of it doesn&#8217;t, so I keep a separate box running Parrot OS for when that comes up. The kind of setup where everything should just be there when you need it. When I sat down to use it and the DisplayLink USB dock wasn&#8217;t being recognised, that assumption immediately became a problem worth solving properly.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The words <code>bad exit status: 2<\/code> are never the beginning of a short afternoon.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The First Wall<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">DisplayLink is the technology inside most USB docks and USB to HDMI adapters. It lets you run three monitors off a machine with a single video output. On Linux, it relies on a kernel module called <code>evdi<\/code> (Extended Virtual Display Interface), which is maintained outside the main kernel source tree by Synaptics. That matters, because it means every kernel update can potentially break it: the kernel&#8217;s internal APIs change, and evdi has to chase those changes on its own release schedule.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A fresh <code>sudo apt install displaylink-driver<\/code> produced this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Building module(s)...(bad exit status: 2)\nError! Bad return status for module build on kernel: 6.17.13+2-amd64 (x86_64)\nConsult \/var\/lib\/dkms\/evdi\/1.14.8+dfsg\/build\/make.log for more information.\ndpkg: error processing package evdi-dkms (--configure):\n installed evdi-dkms package post-installation script subprocess returned error exit status 10<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The story, once you&#8217;ve seen it a few times, is straightforward. DKMS (the system that recompiles out of tree modules automatically when kernels change) tried to build evdi 1.14.8 against kernel 6.17.13, failed, and because <code>displaylink-driver<\/code> depends on <code>evdi-dkms<\/code>, the entire install collapsed. Both packages ended up in an unconfigured state, poisoning every subsequent <code>apt<\/code> command.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Obvious Fix That Wasn&#8217;t Quite Enough<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The repo version of evdi was clearly too old. The sensible move was to grab the latest source from GitHub and build it manually:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt install git build-essential dkms libdrm-dev -y\ngit clone https:\/\/github.com\/DisplayLink\/evdi.git\ncd evdi\nsudo make<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The build started and immediately produced hundreds of compiler errors, all variations of:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>error: comparison of integer expressions of different signedness:\n'long unsigned int' and 'int' &#91;-Werror=sign-compare]<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This wasn&#8217;t a bug in evdi&#8217;s code. Kernel 6.19 had introduced new header files containing comparisons between signed and unsigned integers, a pattern the C compiler flags as potentially dangerous. The evdi Makefile was using <code>-Werror=sign-compare<\/code>, which promotes that warning to a fatal error. The kernel headers themselves were triggering the stop.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The fix was a single line. Tell the compiler to warn but not die:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sed -i 's\/-Werror=sign-compare\/-Wno-error=sign-compare\/' Makefile\nsudo make clean\nsudo make<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This time the build completed cleanly. Module compiled, library built. So far, so good.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Packaging Trap<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo make install -C module\nsudo make install -C library\nsudo apt install displaylink-driver<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The module and library installed without complaint. Then <code>apt install displaylink-driver<\/code> ran, pulled in <code>evdi-dkms<\/code> as a dependency, and DKMS kicked off a fresh build of the <em>old<\/em> evdi 1.14.8 from the repo. Which failed. Again.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The question was no longer how to compile evdi. It was how to get the packaging system to accept a working installation when the package it depends on insists on compiling something broken.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Treadmill<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The natural instinct was to patch the DKMS package source at <code>\/usr\/src\/evdi-1.14.8+dfsg\/<\/code> and retry. I did. And every single time, the patch was gone before the build ran.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Understanding why required reading what the <code>evdi-dkms<\/code> post install script actually does. Each time <code>dpkg<\/code> tries to configure the package, the script runs a full DKMS remove and readd cycle: it deletes the existing DKMS tree entry, copies the source in fresh from <code>\/usr\/src\/<\/code>, and then attempts a build. My patch was landing on the source directory; the copy being used for the actual build was recreated <em>after<\/em> my patch, every time.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So I patched both locations and drove DKMS manually:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo sed -i 's\/-Werror=sign-compare\/-Wno-error=sign-compare\/' \/usr\/src\/evdi-1.14.8+dfsg\/Makefile\nsudo dkms remove evdi\/1.14.8+dfsg --all\nsudo dkms add \/usr\/src\/evdi-1.14.8+dfsg\nsudo sed -i 's\/-Werror=sign-compare\/-Wno-error=sign-compare\/' \/var\/lib\/dkms\/evdi\/1.14.8+dfsg\/source\/Makefile\nsudo dkms build evdi\/1.14.8+dfsg -k $(uname -r)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This also failed. But the error was completely different, and reading the <code>make.log<\/code> finally made the real problem visible.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Actual Problem<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>evdi_drm_drv.c:150:10: error: 'struct drm_driver' has no member named 'date'\nevdi_modeset.c:346:39: error: 'struct drm_device' has no member named 'struct_mutex'\nevdi_fb.c:459:10: error: 'struct drm_fb_helper_funcs' has no member named 'fb_probe'<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">These aren&#8217;t compiler configuration issues. These are genuine source code incompatibilities. The Linux DRM subsystem went through significant API changes between the kernel that evdi 1.14.8 was written for and kernel 6.19:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The <code>date<\/code> field was removed from <code>struct drm_driver<\/code>, completing a long deprecation.<\/li>\n\n\n\n<li><code>struct_mutex<\/code> was removed from <code>struct drm_device<\/code>, finishing a multiyear effort to replace a single global lock with more granular locking.<\/li>\n\n\n\n<li>Several function signatures changed across the framebuffer and connector subsystems.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The packaged evdi was written before any of these changes. No amount of compiler flag tweaking would fix structural incompatibility with the kernel&#8217;s internal interfaces. Every approach built on the DKMS package was doomed from the start.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The sign compare errors had looked like <em>the<\/em> problem. They were a problem, but fixing them only uncovered the real one underneath. If I&#8217;d read the <code>make.log<\/code> from the very first DKMS failure instead of assuming it was a packaging issue, I&#8217;d have seen the API errors immediately and saved myself an hour on the treadmill.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Fix<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The GitHub source at version 1.14.15 had already been updated for the kernel 6.19 API changes. The manual build from earlier, the one that compiled cleanly after the sign compare fix, was the working module all along. The remaining task was just to make the packaging system accept it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Remove everything broken\nsudo apt remove evdi-dkms displaylink-driver --purge\n\n# Install the known-good module from the GitHub build\ncd ~\/Downloads\/evdi\nsudo make install -C module\nsudo make install -C library\n\n# Rebuild the module dependency database\n# (The install had warned about a missing System.map and skipped depmod)\nsudo depmod -a\n\n# Verify the module loads\nsudo modprobe evdi\nlsmod | grep evdi\n\n# Install displaylink-driver, bypassing the broken dependency\nsudo apt download displaylink-driver\nsudo dpkg --force-depends -i displaylink-driver*.deb<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A note on <code>--force-depends<\/code>, because it has a bad reputation. In most situations, forcing past a declared dependency means you genuinely have a missing runtime component and things will break in obscure ways later. This isn&#8217;t that situation. The declared dependency is <code>evdi-dkms<\/code>, a packaging construct whose job is to compile and install <code>evdi.ko<\/code>. The actual runtime requirement is <code>evdi.ko<\/code> being present and loadable in the running kernel, which the manual install already satisfies. The packaging metadata doesn&#8217;t reflect reality, and <code>--force-depends<\/code> is the correct tool for telling <code>dpkg<\/code> to trust your judgement over the metadata.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>depmod -a<\/code> step caught out an earlier attempt. The module install had warned about a missing <code>System.map<\/code> and skipped its own <code>depmod<\/code> run, so the module was in the right directory but the kernel&#8217;s module dependency database didn&#8217;t know about it. Running <code>depmod -a<\/code> explicitly registers newly installed modules. Without it, <code>modprobe evdi<\/code> returns &#8220;module not found&#8221; even though the file is right there.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Living With It<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This fix won&#8217;t survive a kernel update automatically. The whole purpose of DKMS is to rebuild out of tree modules when new kernels arrive, and we&#8217;ve bypassed it entirely. When Parrot ships the next kernel, evdi will stop loading until you rebuild from the GitHub source again.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Three ways to handle that. First, watch the distro repos. Once the Parrot packagers ship a compatible <code>evdi-dkms<\/code>, you can reinstall the standard way and let DKMS take over. The gap is typically weeks, not months. Second, write a hook that triggers after kernel installation and runs the manual build automatically. More setup work, but fully autonomous after that. Third, pin the kernel version until the packages catch up, if you can&#8217;t accept DisplayLink breaking after an update.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For most people, option one is practical enough.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What I&#8217;d Tell Someone Starting Where I Started<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Read the make.log first, not last.<\/strong> The <code>dpkg<\/code> output says &#8220;bad exit status: 2&#8221; and nothing else useful. The <code>make.log<\/code> tells you what the compiler actually complained about. Every minute spent troubleshooting the packaging layer without reading the build errors is wasted.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Separate compiler strictness failures from real incompatibilities.<\/strong> The sign compare errors looked fixable, and they were, but fixing them only revealed the structural API mismatches underneath. If you see DKMS failures on a recent kernel, check the <code>make.log<\/code> for missing struct members or changed function signatures before spending time on compiler flags. If the source is genuinely incompatible with the kernel, no flag will save it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Understand the DKMS lifecycle when it breaks.<\/strong> The post install script runs a full remove and readd cycle, which recreates the build tree from scratch. Patching the source directory isn&#8217;t enough if the build tree is being rebuilt after your patch. Either patch both locations or drive DKMS manually.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Force options exist for a reason.<\/strong> <code>--force-depends<\/code> is a sharp tool and shouldn&#8217;t be the first thing you reach for. But when the declared dependency is a packaging construct and the actual runtime requirement is demonstrably satisfied by other means, it&#8217;s the right call.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Bleeding edge distros require engineers who can work below the packaging layer.<\/strong> If you run Parrot OS or any distro that prioritises recent kernels, you will occasionally hit situations where the kernel is ahead of driver support. This isn&#8217;t a distro bug. It&#8217;s an expected consequence of the design priorities. Knowing how to bridge that gap manually is part of running the system.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Quick Reference<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Prerequisites\nsudo apt install git build-essential dkms libdrm-dev -y\n\n# Get the latest evdi source\ngit clone https:\/\/github.com\/DisplayLink\/evdi.git\ncd evdi\n\n# Fix the compiler strictness flag for kernel 6.19 headers\nsed -i 's\/-Werror=sign-compare\/-Wno-error=sign-compare\/' Makefile\n\n# Build\nsudo make\n\n# Install the module and library\nsudo make install -C module\nsudo make install -C library\n\n# Update module database\nsudo depmod -a\n\n# Load and verify\nsudo modprobe evdi\nlsmod | grep evdi\n\n# Clean up broken packages\nsudo apt remove evdi-dkms --purge\n\n# Install displaylink-driver bypassing the broken dependency\nsudo apt download displaylink-driver\nsudo dpkg --force-depends -i displaylink-driver*.deb\n\n# Check the service\nsystemctl status displaylink-driver<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Tested on Parrot OS 7, kernel 6.19.6+parrot7-amd64, evdi 1.14.8 (repo) vs 1.14.15 (GitHub), March 2026. If you&#8217;re reading this after a subsequent kernel release, check the evdi GitHub issues page for current compatibility before assuming these steps apply unchanged.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>A DisplayLink dock stopped working on Parrot OS 7. The fix looked simple until kernel 6.19 broke the packaged driver at every level. Here&#8217;s how to build past it<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[616,617,623,622,621,618,624,620,619,56],"class_list":["post-376","post","type-post","status-publish","format-standard","hentry","category-technology","tag-displaylink","tag-dkms","tag-dpkg","tag-driver-compilation","tag-drm-subsystem","tag-evdi","tag-kernel-module","tag-linux-kernel","tag-out-of-tree-modules","tag-parrot-os"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/kosokoking.com\/index.php\/wp-json\/wp\/v2\/posts\/376","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kosokoking.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kosokoking.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kosokoking.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/kosokoking.com\/index.php\/wp-json\/wp\/v2\/comments?post=376"}],"version-history":[{"count":1,"href":"https:\/\/kosokoking.com\/index.php\/wp-json\/wp\/v2\/posts\/376\/revisions"}],"predecessor-version":[{"id":377,"href":"https:\/\/kosokoking.com\/index.php\/wp-json\/wp\/v2\/posts\/376\/revisions\/377"}],"wp:attachment":[{"href":"https:\/\/kosokoking.com\/index.php\/wp-json\/wp\/v2\/media?parent=376"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kosokoking.com\/index.php\/wp-json\/wp\/v2\/categories?post=376"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kosokoking.com\/index.php\/wp-json\/wp\/v2\/tags?post=376"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}