Fixing BenQ Display Pilot 2 I2C Input/Output Errors on Linux
Running Display Pilot 2 on my Arch Linux via the
display-pilot-2 AUR package
results in the following i2c errors, which prevent Display Pilot 2
from communicating to the BenQ monitor.
W 13:41:04.666 [MonitorModel] getVCP failed "df"
I 13:41:04.666 [MonitorModel] Test VCP failed, waiting for retry.
Ioctl write i2c error:: Input/output error
Ioctl read i2c error:: Input/output error
Ioctl write i2c error:: Input/output error
Ioctl read i2c error:: Input/output error
Ioctl write i2c error:: Input/output error
Ioctl read i2c error:: Input/output error
W 13:41:05.529 [MonitorModel] getVCP failed "df"
I 13:41:05.529 [MonitorModel] Test VCP failed, waiting for retry.
Ioctl write i2c error:: Input/output error
Ioctl read i2c error:: Input/output error
Ioctl write i2c error:: Input/output error
Ioctl read i2c error:: Input/output error
Ioctl write i2c error:: Input/output error
Ioctl read i2c error:: Input/output error
W 13:41:06.391 [MonitorModel] getVCP failed "df"
I 13:41:06.391 [MonitorModel] Test VCP failed, waiting for retry.
If you are seeing such errors, first make sure that your $USER is a member of
the i2c group. You can use the groups(1) command to check that.
groups
If your $USER is not a member of the i2c group can add yourself to the group
using the following command.
sudo usermod -aG i2c $USER
You will need to logout and login again for the changes to take effect. Once you login back start Display Pilot 2 again and if the errors are gone, you can stop reading at this point, otherwise continue forward.
The reason why Display Pilot is failing with these errors is because it is using
the wrong i2c device for communicating with the monitor. In order to confirm
that we need to check what Display Pilot 2 is using and what is the actual i2c
device for communication with our monitor. We will need ddcutil(1), so make
sure that you have it installed first.
sudo pacman -S ddcutil
Then use the following command to detect monitors that have Virtual Control Panel.
ddcutil detect
On my system the result from the above ddcutil(1) looks like this.
$ ddcutil detect
Display 1
I2C bus: /dev/i2c-6
DRM_connector: card1-DP-1
EDID synopsis:
Mfg id: BNQ - UNK
Model: BenQ RD280UG
Product code: 32959 (0x80bf)
Serial number: EMF6T00355087
Binary serial number: 16843009 (0x01010101)
Manufacture year: 2026, Week: 25
VCP version: 2.2
We can see that the BenQ RD280UG monitor is available at the /dev/i2c-6
bus. Double check that the device permissions are correct and that the i2c
group can read and write to that device.
$ ls -la /dev/i2c-6
crw-rw----+ 1 root i2c 89, 6 Oct 10 14:00 /dev/i2c-6
Now we will check what is the i2c device that Display Pilot 2 is actually
using. In order to do that we will first extract the AppImage contents of the
Display Pilot 2 app and strace(1) it. Create a temporary workdir, where will
extract the contents of the AppImage.
mkdir workdir && cd workdir
display-pilot-2 --appimage-extract
We can now strace(1) the program using the following command and see what is
the i2c device that it is using.
strace -f -e trace=openat,ioctl -o display-pilot.log ./squashfs-root/AppRun
Let the strace(1) command above run for a while, so we can capture any
openat(3) syscalls and after a short period of time stop the tracing. We can
now inspect the display-pilot.log file and see what i2c device is being used
by it.
$ grep i2c display-pilot.log
14039 openat(AT_FDCWD, "/dev/i2c-2", O_RDWR) = 41
14039 openat(AT_FDCWD, "/dev/i2c-2", O_RDWR) = 41
14039 openat(AT_FDCWD, "/dev/i2c-2", O_RDWR) = 41
14039 openat(AT_FDCWD, "/dev/i2c-2", O_RDWR) = 41
14039 openat(AT_FDCWD, "/dev/i2c-2", O_RDWR) = 41
14039 openat(AT_FDCWD, "/dev/i2c-2", O_RDWR) = 41
...
And this is the actual issue – we have confirmed with ddcutil(1) that the
BenQ monitor is available at the /dev/i2c-6 device, but the Display Pilot 2
app is trying to communicate with the monitor via the /dev/i2c-2 device.
In order to fix the Display Pilot 2 app we will symlink /dev/i2c-6 to the
/dev/i2c-2 device used by the app via systemd unit. Make sure that you use the
correct /dev/i2c-* devices on your system for the systemd unit below.
# /etc/systemd/system/benq-i2c-fix.service
[Unit]
Description=Fix BenQ Display Pilot 2 I2C Routing
After=systemd-modules-load.service
[Service]
Type=oneshot
ExecStartPre=/usr/bin/rm -f /dev/i2c-2
ExecStart=/usr/bin/ln -s /dev/i2c-6 /dev/i2c-2
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
Reload the systemd daemon, then enable and start the benq-i2c-fix.service.
sudo systemctl daemon-reload
sudo systemctl enable --now benq-i2c-fix.service
Confirm that /dev/i2c-2 is a symlink to /dev/i2c-6.
$ ls -l /dev/i2c-2
lrwxrwxrwx 1 root root 10 Oct 10 14:50 /dev/i2c-2 -> /dev/i2c-6
At this point Display Pilot 2 should start up fine and talk to the correct i2c device.