Hi,
I'm trying to use udev to detect an external monitor being plugged in and then by identifying the monitors edid info identify which monitor it is and set an appropriate resolution for it.
I've looked at what others have done and mostly come up with something that works but I'm stuck because I can't seem to be able to read the monitors edid from the udev hotplug script that I'm running.
The 2 files I have are:
/etc/udev/rules.d/80-vga.rules
Code:
ACTION=="change", SUBSYSTEM=="drm", RUN+="/etc/udev/scripts/hotplug.sh"
and:
/etc/udev/scripts/hotplug.sh
Code:
#!/bin/bash -
# Treat unset variables as an error
set -u
# append STERR and STOUT to log file
exec &>> /var/log/hotplug.log
# read the status of my external VGA port
read status < /sys/class/drm/card0-VGA-1/status
# export the X11 variables for my one system user
export DISPLAY=:0
export XAUTHORITY=/home/mikey/.Xauthority
# are we connected to an external monitor?
if [ "$status" = "connected" ]; then
# read in the interesting parts of parse-edid (from the read-edid package)
IFS=$'\n'
edid=( $( parse-edid /sys/class/drm/card0-VGA-1/edid |
sed -n -e 's/"[^"]*$//' -e 's/\s*Mode\s\+"\|\s*VendorName\s\+"\|\s*ModelName\s\+"//p' ) )
# default to using automatic modes (dosen't work for my TV)
settings="--auto"
# for the modes listed by edid see if there is a sitable one
for (( i=2; i<${#edid[@]}; i++)); do
# for debuging show what modes we have
echo "Mode: ${edid[$i]}"
# select a mode if it starts with 1280x???
if [[ "${edid[$i]}" =~ ^1280x.* ]]; then
# set the mode from the edid info
settings="--mode ${edid[$i]} --pos 0x0 --rotate normal"
fi
done
# output the settings chosen
if [ "${#edid[@]}" -ge 2 ]; then
echo "Detected monitor ${edid[0]} ${edid[1]} and selected: $settings"
else
echo "Detected monitor but no EDID found, selected: $settings"
fi
# use xrandr to set the mode on the external monitor and turn of the internal
IFS=' '
/usr/bin/xrandr --output LVDS1 --off --output VGA1 --screen 0 $settings
echo "Connected"
else
# use xrandr to turn on the internal monitor and turn of the external
/usr/bin/xrandr --output VGA1 --off --output LVDS1 --auto --screen 0
echo "Disconnected"
fi
But while this script works without issue when called manually as soon as a monitor is put in parse-edid fails to retrieve any edid info when called by udev. Even using a simpler detection method of calling md5sum on the edid file fails to return the md5 that matches the monitor when called by udev.
I've even tried introducing a sleep statement into the script before trying to read the edid in case it was being called to early but it behaves in exactly the same way.
It's like the edid file (/sys/class/drm/card0-VGA-1/edid) isn't set until this script exits, which is odd since the other file the script checks from the same location (/sys/class/drm/card0-VGA-1/status) is happily set.
I wonder if any of the LQ gurus (or just someone a bit savier than me) can shed light on this phenomena.