I’ve been playing with udev rules for a couple of days and I’ve been quite interested in the capabilities it offers.

I highly recommend this two documents:

This guide reflects the whole process from connecting the device, identifying the events in linux, processing udev rules and executing an script every time the device is connected/disconnected.

Scenario:

  • Notebook: HP 820 g3
  • Dock:  2013 Ultra Slim Docking Station (two display ports)
  • Notebook ports: (1) Display Port and (1) VGA ports.

My objective was to run a bash script every time a display port cable  is connected/disconnected in any of those ports (with my Dock).

Detecting devices/events at kernel’s level

Kernel will be the first to be notified when something is connected, in this stage we can detect almost anything, any new device (USB Pendrives, Monitors or whatever we connect) usually will be detected and informed to the kernel.

This is the result of connecting one Display Port cable (attached to a monitor) to my dock:

Woah, almost 10 events were triggered, so now which one we would choose?

UDEV:

  • Detected 1 (one) change in the parent device card0

KERNEL:

  • Detected 4 (four) changes
    • The 4 (four) changes are for the parent device card0
  • Detected 5 (five) add events
    • 2 (two) added for /dev/i2c-6
      • One for the subsystem: i2c-dev
      • One for the subsystem: i2c
    • 3 (three) for added display ports:
      • One for card0-DP-3
      • One for card0-DP-4
      • One for card0-DP-5

So in order to select an specific event I will choose the subsystem i2c-dev, this will be the event that will trigger the script in the UDEV rule:

We will take the KERNEL event “add”, the DEVNAME “/dev/i2c-6” and the SUBSYSTEM: “i2c-dev” because it happens only ONCE when I connect the DP cable. I didn’t used the UDEV rule for the parent device card0, after several testing the “change” event for card0 happens many times when disconnecting the cable, so it isn’t an option.

Remember selecting an specific event and it’s properties, otherwise the script will ran multiple times and that would lead to unwanted results.

Well, now let’s take a look on xrandr to see which monitor was attached:

As you can see, depending on which display port I connect the cable the respective device will be presented to xrandr, it could be DP1-1, DP1-2 or DP1-3, this must be considered when writting the bash script at the end of this document. eDP1 is the default screen.

Setting up udev rules

The secret of a good rule is to be quite specific. That means pointing to the child devices instead of the parent devices. We already did that when we selected the set of events (KERNEL event “add”, the DEVNAME “/dev/i2c-6” and the SUBSYSTEM: “i2c-dev”) in the first step, because it only happens once.

Now that we know our trigger, it’s time to set up a rule, I’ve created the file local.rules: /etc/udev/rules.d/local.rules

Because I don’t know if the device name could change (when rebooting or reconnecting the dock to the laptop) I’ve used the bash matching listing “[0-9]” so this evaluate that one of the characters between brackets is a match, of course our i2c-6 will be a match.

Udev supports many metacharacters besides matching or listing, take a look here.

The rest of the rules are the same we found previously, finally we execute the script when the event “add” for the device i2c-6 with the subsystem i2c-dev occurs.

I’ve also added a rule when the cable is disconnected from the dock:

But that would lead to the script being executed the same way when I connect or disconnect the cable, so I fixed that problem by passing parameters to the script:

Finally the bash script. As I’ve mentioned before the monitor could be “DP1-1, DP1-2 or DP1-3”

That’s it, now everytime I connect or disconnect display port cable with a monitor it works and when I remove the cable the main screen of the laptop returns to it’s default settings.