Monitor inputs with ddcutil
01 Jan 2020ddcutil
is a program for messing with monitor settings.
Brightness and colour levels and all that and – the one I’m interested
in – input source. It works by magic. Or, as
ddcutil
’s docs put
it:
ddcutil primarily uses DDC/CI (Display Data Channel Command Interface) to communicate with monitors implementing MCCS (Monitor Control Command Set) over I2C.
Whatever that means.
Obviously ddcutil
will only work if the monitor supports
that stuff. Reading around suggests that most but not all do.
ddcutil
will not work on laptops as they use a different
interface.
Its usefulness for me is that I have a Nintendo Switch plugged into my main monitor as well as my PC. When I want to play on my Switch, rather than leaning over my desk and using the super fiddly buttons on the front of my monitor, I can just hit a key combo to switch between the DisplayPort input my PC uses and the HDMI used by my Switch.
The same approach could be applied to VFIO passthrough setups or just, as mentioned above, for adjusting brightness and so on.
Preparation
To use ddcutil
the i2c-dev module must be loaded. On
some distros it’s built into the kernel, if it’s not it’ll need to be
explicitly loaded.
To check whether i2c-dev is built in, run:
grep i2c-dev.ko /lib/modules/`uname -r`/modules.builtin
If you get output then you’re all good. If not then you need to
explicitly load the module by adding the line i2c_dev
to
/etc/modules
or create a file containing that line in
/etc/modules-load.d/
.
In my case, on Arch, the module was not included in the kernel so I
created the file /etc/modules-load.d/i2c-dev.conf
containing the single line:
i2c_dev
That’ll only take effect next time you reboot so for now you can load the module directly with:
sudo modprobe i2c_dev
Using ddcutil
Once the i2c_dev module is loaded we can do:
sudo ddcutil detect
To detect monitors. The output in my case is:
Display 1
I2C bus: /dev/i2c-5
EDID synopsis:
Mfg id: DEL
Model: DELL U2715H
Serial number: GH85D67S05JS
Manufacture year: 2016
EDID version: 1.4
VCP version: 2.1
If you’ve got multiple monitors, pay attention to that
Display
number – you’ll need to use that with subsequent
commands. So if you want to operate on display 2, for example, wherever
I use ddcutil
, you’ll want to use
ddcutil -d 2
.
Once you’ve settled on a display, run:
sudo ddcutil capabilities
Which will output a load of stuff that ddcutil
can mess
with on the monitor.
The one I’m interested in is Feature 60 (Input Source) (I believe feature codes are common across devices but don’t take my word for that).
Feature: 60 (Input Source)
Values:
0f: DisplayPort-1
10: DisplayPort-2
11: HDMI-1
12: HDMI-2
There we see feature code 60 with its possible values and what they mean.
We can get the current value of any particular feature by using
ddcutil getvcp
. Feature codes are hexidecimal and need to
be prepended with 0x
when used in commands. So to get the
current input source we can do:
sudo ddcutil getvcp 0x60
Which outputs:
VCP code 0x60 (Input Source ): DisplayPort-2 (sl=0x10)
We can change settings with ddcutil setvcp
. So, if I
want to switch to HDMI 2, which has the code 12 in the output up above,
we can do:
sudo ddcutil setvcp 0x60 0x12
And my monitor will switch over to HDMI input. It takes a couple of seconds but it works. Magic.
So to make this super-useful to me I wrote a little bash script which toggles between DisplayPort 2 (my PC) and HDMI 2 (my Switch) and bound it to a key combo:
#!/usr/bin/env bash
notify-send "Switching..."
if sudo ddcutil getvcp 0x60 | grep "DisplayPort" > /dev/null 2>&1;then
sudo ddcutil setvcp 0x60 0x12
else
sudo ddcutil setvcp 0x60 0x10
fi
As you can see, ddcutil
requires root permissions to do
its thing. You can handle this in whatever way you like in any scripts
you make – I just use sudo because I am not clever like you are.