Tweaking HDMI dummies
This is a follow-up to my post about HDMI hotplug.
Back then I wrote it to handle a KVM switch and how it would deal with switching monitors and how Linux handled when the monitor was not plugged in.
Since then I discovered HDMI dummy plugs. These are small adapters that connect to an HDMI and fool the computer into thinking there is a monitor still connected.
Using it is really a matter of preference.
On my desk, I have a KVM connecting a Linux desktop and a Windows laptop. When the KVM connects to the Windows laptop I would configure the system to extend the desktop to two monitors. When I switch from the Windows laptop to my Linux desktop with the KVM switch, the Windows Operating system detects that the monitor is disconnected and moves all the opened windows from the external monitor (which is now disconnected) to the Laptop display. While this is the common sense thing to do, I don't find the experience pleasent.
By using the HDMI dummy plug adaptor, Windows thinks that the monitor still is connected while the KVM switches to the other computer. So when I switch back, all the windows stay put.
So the issues that I was having back as described in HDMI hotplug would not happen as the monitor looks like is always connected.
Furthermore, looking at the state of software under Linux, the Operating System already handles monitor hotplugs gracefully. Similarly, Desktop Environments work without much issues with monitors being plugged or unplugged on the fly. Also in HDMI hotplug I was using the XDM (Display Manager) which was initially written back 1988, and is one of the most rudimentary display managers.
Of course things in life are never simple. So this is what happened.
When I first started using HDMI dummies I had a 1080p FHD monitor and 1080p dummies. Recently I upgraded my main monitor to a QHD monitor. So the 1080p dummy was not able to reach the QHD (1440p resoluation). Of course, there is no 1440p dummy, so I bought a 4K HDMI dummy. Which made things a little bit challenging because the cheapo 4K HDMI dummy would insist to the computer that the preferred resolution was 4K, but my monitor would not be able to display that.
Normally monitors use EDID data to tell the computer what are the preferred resolutions. A good HDMI dummy would then cache the EDID information from the monitor and only present a compatible EDID to the computer. For some reason this did not work.
Luckly Linux allows to force EDID to be overriden. To do that this is what i had to do.
Prepare EDID blob
First plug in the monitor directy without the HDMI dummy. Determine the connection in use:
for p in /sys/class/drm/*/status; do con=${p%/status}; echo -n "${con#*/card?-}: "; cat $p; done
Read the EDID blob from /sys/class/drm/card0{connection}/edid
.
cat < /sys/class/drm/card0-HDMI-A-1/edid` > monitor.bin
Use the command parse-edid to read the blob and make sure it contains valid data.
Save it to /usr/lib/firmware/edid
. I would save it to a file with the
monitor model name and bin
extension.
Modify Kernel command line
Add the following option to the Linux kernel command line:
drm.edid_firmware=HDMI-A-1:edid/PHL325B1L.bin
Change HDMI-A-1
with the right connector as seen using a previous command.
Replace PHL325B1L.bin
with the name of the EDID blob you created earlier.
Update initramfs
Under voidlinux, the dracut utility is used to generate the initramfs.
Create a file in /etc/dracut.conf.d/
with the configuration:
# /etc/dracut.conf.d/50-fw.conf
install_items+=" /usr/lib/firmware/edid/PHL325B1L.bin "
And generate the new initramfs:
dracut --force
Reboot
At this point all is ready. Shutdown the computer, plug the monitor using the HDMI dummy.
Post boot EDID
Alternatively, you could use this script to force EDID after boot:
#!/bin/sh
#
# Script to force EDID settings
#
set -euf -o pipefail
#
# Customize these settings
#
EDID_BIN=/usr/lib/edid/PHL325B1L.bin
output=HDMI-A-1
rows=45
cols=160
# Use parse-edid to verify
# save /sys/class/drm/card*/edid
debugfs=/sys/kernel/debug
if [ ! -d $debugfs/dri ] ; then
umount=true
mount -t debugfs debugfs $debugfs
trap "umount $debugfs" EXIT
fi
dd if=$EDID_BIN of=$debugfs/dri/0/$output/edid_override
echo 1 | dd of=$debugfs/dri/0/$output/trigger_hotplug
for n in $(seq 1 6)
do
(
tput sc
printf '\033[1;'$rows'r'
tput rc
stty rows $rows cols $cols
) < /dev/tty$n >/dev/tty$n 2>&1
done
References: