If Looking Glass doesn’t fit your needs, but you still want a seamless experience with VFIO, then this trick might be up your street. Using a little known program called ddcutil and a DDC/CI enabled monitor, you can switch your monitor inputs through software, without ever touching those finicky monitor OSD (On Screen Display) controls or forking out a considerable amount of cash for a hardware KVM. 

Read also: Evdev Passthrough Explained

It’s a little rough around the edges, and we’re working on a pretty front-end for this procedure, but this method should work as a proof of concept.

Note: All commands in this article need to be executed with root access. It may pay to switch to a root shell entirely by running `sudo su`.

Your first port of call is to find out whether you have a DDC/CI supported monitor and enable that functionality if you do. Either consult your monitor’s manual or have a quick peruse through your monitor’s OSD. Unfortunately, if your monitor doesn’t support DDC/CI,  this guide won’t work for you.

My monitor’s OSD option for DDC/CI looks like this:

Assuming all is good with your monitor, onward!

Install ddcutil:

Arch: yaourt ddcutil

Gentoo: emerge ddcutil

Other distributions don’t have ddcutil in the repositories yet, but there are 3rd party repositories available:

Debian:

echo 'deb http://download.opensuse.org/repositories/home:/rockowitz/Debian_9.0/ /' \
    > /etc/apt/sources.list.d/ddcutil.list 
apt-get update
apt-get install ddcutil

Ubuntu:

echo 'deb http://ppa.launchpad.net/rockowitz/ddcutil/ubuntu xenial main 
deb-src http://ppa.launchpad.net/rockowitz/ddcutil/ubuntu xenial main' >> /etc/apt/sources.list
apt-get update
apt-get install ddcutil i2c-tools

Fedora:

dnf config-manager --add-repo \
    https://download.opensuse.org/repositories/home:rockowitz/Fedora_26/home:rockowitz.repo
dnf install ddcutil

Then attempt to detect your monitor(s) with ddcutil:

sudo ddcutil detect

If no monitors are detected, you may need to load the i2c module: 

modprobe i2c-dev

Retry sudo ddcutil detect

Assuming this works, make sure Supports DDC is true and take note of your display numbers.

If your display is listed as invalid, it’s possible that your monitor isn’t DDC/CI compatible.

Take note of the display numbers ddcutil assigns here, if you have more than one monitor you’ll need to specify this display number.

Next we need to find the available inputs on your monitor:

sudo ddcutil -d $display_number capabilities

Search the list of capabilities for Feature: 60 (input source) and take note of the hexadecimal values. You’ll need these to specify what source you wish to switch to.

Now it’s time to see if your hard work has paid off. Try switching to another monitor input:

ddcutil -d $display_number setvcp 60 0x$monitor_input_hex_value

Your monitor should now switch to your specified input.

Starting Up DDC On Boot

Now you can switch with these commands, let’s make the process a little more user friendly.

If you’re using a distro that doesn’t load the i2c-dev module by default, then you can add it to your list of automatically loaded modules, so that you’ll be saved of modprobing every time you restart your system:

echo i2c-dev >> /etc/modules-load.d/ic2-dev.conf

(this may not work on systems using openrc or runit)

Automating The Process (WARNING: EXPERIMENTAL)

The Passthrough POST is working on a script that enables automatic switching of inputs when you start or stop a passthrough VM. It’s still in testing, but you can try it now.

VFIO-Tools Hook Helper

The script is a drop-in script for the VFIO-Tools hook helper. If you’ve already installed the helper you’re good to go, you can skip this section. If not, no problem, installing the helper is very easy. We’ve written a guide on how to install the VFIO-Tools hook helper here.

The script

Setting up the script is very easy with the helper installed. The whole process is only a few steps. Since the drop-in hooks are configured per VM, we need to set the name of your VM first. For this tutorial we’ll assume your VM is called “win10”:

export $vmname="yourvmname"

Now, we can make the folders we need:

mkdir -p /etc/libvirt/hooks/qemu.d/$vmname/st{arted/begin,opped/end}/

With the folders created, we can download the script:

wget https://raw.githubusercontent.com/PassthroughPOST/VFIO-Tools/master/libvirt_hooks/hooks/switch_displays.sh \
     -O "/etc/libvirt/hooks/qemu.d/$vmname/started/begin/switch_displays.sh"

We need to edit the script slightly to match our monitor setup. Open the script in your favorite text editor and modify these lines so they match your configuration:

VM_DISPLAY="0"    # The display shown in `ddcutil detect`
VM_INPUT="12"     # The input the VM is connected to (without 0x, but with leading zeroes, if any)
HOST_INPUT="0f"   # The input the host is connected to (without 0x, but with leading zeroes, if any)

When you’re done, save the file and create a symlink to the shutdown hook:

ln -s ../../started/begin/switch_displays.sh \
      "/etc/libvirt/hooks/qemu.d/$vmname/stopped/end/switch_displays.sh"

Finally, make the files executable and you should be good to go:

chmod +x /etc/libvirt/hooks/qemu.d/$vmname/st{arted/begin,opped/end}/switch_displays.sh

Now just (re)start your VM and, if everything went right, your display should change input automatically.

Troubleshooting

– No displays are detected

You may not have the i2c-dev module loaded. Try running `modprobe i2c-dev`. If that doesn’t work, you may be running in one of the issues with the proprietary drivers. Run `man ddcutil` and read the notes at the bottom about known issues.

– Monitor reports `Supports DDC: false`

If you’re lucky, you just haven’t enabled DDC/CI on your monitor yet. See if you can find an option for it in your OSD. If you’re unlucky, your monitor may not support DDC/CI. This guide isn’t going to work for you.

– Libvirt hooks aren’t being executed

If you’ve just installed the VFIO-Tools Hook Helper, remember to restart Libvirt first. Make sure you’ve made the hook files executable through `chmod +x`. Lastly, make sure your directory structure is correct. It should look something like this:

/etc/libvirt/hooks/
├── qemu
└── qemu.d
    └── win10
        ├── started
        │   └── begin
        │       └── switch_displays.sh
        └── stopped
            └── end
                └── switch_displays.sh -> ../../started/begin/switch_displays.sh

Projects and quality of life improvements like these are a big reason why we started The Passthrough POST, but it takes a lot of time and effort to develop and extend things like VFIO-Tools. If you like what we’re reporting on and developing here, consider becoming a Patron and joining our community discord.


Images courtesy Pixabay