Skip to content

Instantly share code, notes, and snippets.

@nv1t
Forked from seanf/81-thinkpad-dock.rules
Created February 27, 2021 18:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nv1t/fc6e67f441bdcaf210f404ba8f3fddc0 to your computer and use it in GitHub Desktop.
Save nv1t/fc6e67f441bdcaf210f404ba8f3fddc0 to your computer and use it in GitHub Desktop.
Example ThinkPad docking script for multi-monitor
# Save this file (after modifying ID_VENDOR and ID_MODEL if necessary) as /etc/udev/rules.d/81-thinkpad-dock.rules
# These values seem to work for "ThinkPad Mini Dock Plus Series 3"
SUBSYSTEM=="usb", ACTION=="add|remove", ENV{ID_VENDOR}=="17ef", ENV{ID_MODEL}=="100a", RUN+="/etc/sbin/thinkpad-dock.sh"

Example ThinkPad docking script for multi-monitor

You will probably need to modify these files to suit your multi-monitor layout, your username and your dock model. Tested on Fedora 20 with a series 3 ThinkPad Dock.

Warning: this can and will mess up your display if anything goes wrong.

  1. First, unless you have a ThinkPad Mini Dock Plus Series 3, you need to find the udev identity of your dock, so that we can detect when it is added or removed.

Run this command:

udevadm monitor --environment --udev

Then disconnect the hub, wait a second for the events to be logged, press enter several times (on the laptop keyboard) to put a gap after the events, then reconnect the hub.

Make a note of the last usb device to be removed in the log (just before the gap), for instance:

UDEV  [62731.120389] remove   /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.8 (usb)
ACTION=remove
...
ID_MODEL=100a
...
ID_MODEL_FROM_DATABASE=ThinkPad Mini Dock Plus Series 3
...
ID_VENDOR=17ef

The same device should be among the first to be added again:

UDEV  [62736.651278] add      /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.8 (usb)
ACTION=add
...
ID_MODEL=100a
...
ID_MODEL_FROM_DATABASE=ThinkPad Mini Dock Plus Series 3
...
ID_VENDOR=17ef

Hit Control-C to stop monitoring.

Make sure the values ID_MODEL and ID_VENDOR are shown both for add and remove. We will use these to construct a udev rule. If you try to use a value which isn't there when removing, your rule won't activate for remove events.

If ID_MODEL and ID_VENDOR don't look like hex numbers, you might want to try ID_MODEL_ID and ID_VENDOR_ID.

  1. If you have a ThinkPad Mini Dock Plus Series 3, your values should match the ones above, and you can use this rule as is, otherwise you should adjust ID_MODEL and ID_VENDOR to match your results (or perhaps use ID_MODEL_ID and ID_VENDOR_ID):

Save the file 81-thinkpad-dock.rules (modified if necessary) as /etc/udev/rules.d/81-thinkpad-dock.rules.

  1. Modify the username and the xrandr commands in thinkpad-dock.sh as appropriate, and save as /etc/sbin/thinkpad-dock.sh. Make sure it is executable: chmod 755 /etc/sbin/thinkpad-dock.sh

  2. Try docking and undocking your laptop. If nothing happens, you might have a problem with Xauthority (check the username), or you might be using the wrong rules file for your hardware IDs. If something happens, but you don't get the screen layout you want, check the documentation for xrandr with man xrandr.

You can test the script without physically undocking by running these commands as root:

Docking:

ACTION=add sbin/thinkpad-dock.sh

Undocking:

ACTION=remove sbin/thinkpad-dock.sh

A couple of extra notes:

journalctl -f | grep DOCKING will let you see the script's logging messages as they happen.

If you make a note of the device name returned by udevadm monitor when docking/undocking, you can see what will happen when the udev event is triggered by running commands similar to these:

udevadm test --action=add /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.8
udevadm test --action=remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.8
#!/bin/sh -e
# Save this file as /etc/sbin/thinkpad-dock.sh
# NB: you will need to modify the username and tweak the xrandr
# commands to suit your setup.
# wait for the dock state to change
sleep 0.5
username=sflaniga
#export IFS=$"\n"
if [[ "$ACTION" == "add" ]]; then
DOCKED=1
logger -t DOCKING "Detected condition: docked"
elif [[ "$ACTION" == "remove" ]]; then
DOCKED=0
logger -t DOCKING "Detected condition: un-docked"
else
logger -t DOCKING "Detected condition: unknown"
echo Please set env var \$ACTION to 'add' or 'remove'
exit 1
fi
# invoke from XSetup with NO_KDM_REBOOT otherwise you'll end up in a KDM reboot loop
NO_KDM_REBOOT=0
for p in $*; do
case "$p" in
"NO_KDM_REBOOT") NO_KDM_REBOOT=1 ;;
"SWITCH_TO_LOCAL") DOCKED=0 ;;
esac
done
function switch_to_local {
export DISPLAY=$1
#export XAUTHORITY=$(find /var/run/kdm -name "A${DISPLAY}-*")
#export XAUTHORITY=/var/run/lightdm/sflaniga/xauthority
logger -t DOCKING "Switching off HDMI2/3 and switching on LVDS1"
su $username -c '
/usr/bin/xrandr \
--output HDMI1 --off \
--output HDMI2 --off \
--output HDMI3 --off \
--output VGA1 --off \
--output eDP1 --auto \
--output LVDS1 --auto \
'
}
function switch_to_external {
export DISPLAY=$1
#export XAUTHORITY=/var/run/lightdm/sflaniga/xauthority
#export XAUTHORITY=$(find /var/run/kdm -name "A${DISPLAY}-*")
# The Display port on the docking station is on HDMI2 - let's use it and turn off local display
logger -t DOCKING "Switching off LVDS1 and switching on HDMI2/3"
su $username -c '
/usr/bin/xrandr \
--output eDP1 --off \
--output LVDS1 --off \
--output HDMI1 --auto \
--output HDMI2 --auto --pos 1680x0 --rotate left \
--output HDMI3 --auto --pos 0x600 --primary \
--output VGA1 --auto \
'
# alternative:
# xrandr --output LVDS1 --off --output HDMI3 --primary --auto --pos 0x0
# --output HDMI2 --auto --rotate left --pos 1680x-600
# this will probably fail ("Configure crtc 2 failed"):
#/usr/bin/xrandr --output LVDS1 --auto
}
case "$DOCKED" in
"0")
#undocked event
switch_to_local :0 ;;
"1")
#docked event
switch_to_external :0 ;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment