Using udev to configure Fedora multi-seat automatically

When using a multi-seat configuration on Fedora 17, we need a method to automatically assign devices to seats. The simplest method is to use udev as explained rather tersely in the multiseat documentation. Following the setup in multi-seat configuration on Fedora 17, this article provides an example of setting up the correct udev rules.

If you followed the guidelines in multi-seat configuration on Fedora 17 to set up your configuration, you will find some rules in /etc/udev/rules.d/72-* that Fedora automatically sets up for you. Those rules are rather cryptic and hard to maintain; please move those rules to a backup location (outside rules.d).

We will continue the example by developing our own udev rules. To recap, here is the list of hardware that corresponds to seat2 in this example:

         Devices:
                  ├ /sys/devices/pci0000:00/0000:00:04.0/0000:02:00.0/drm/card1
                  │ (drm:card1)
                  ├ /sys/devices/pci0000:00/0000:00:04.0/0000:02:00.0/graphics/fb1
                  │ (graphics:fb1) "radeondrmfb"
                  ├ /sys/devices/pci0000:00/0000:00:04.0/0000:02:00.1/sound/card2
                  │ (sound:card2) "HDMI"
                  │ └ /sys/devices/pci0000:00/0000:00:04.0/0000:02:00.1/sound/card2/input16
                  │   (input:input16) "HDA ATI HDMI HDMI/DP,pcm=3"
                  ├ /sys/devices/pci0000:00/0000:00:12.1/usb4/4-1/4-1:1.0/input/input2
                  │ (input:input2) "CHESEN PS2 to USB Converter"
                  ├ /sys/devices/pci0000:00/0000:00:12.1/usb4/4-1/4-1:1.1/input/input3
                  │ (input:input3) "CHESEN PS2 to USB Converter"
                  └ /sys/devices/pci0000:00/0000:00:12.1/usb4/4-2/4-2:1.0/input/input4
                    (input:input4) "Microsoft Microsoft 3-Button Mouse with IntelliEye(TM)"

We need to identify some feature of these devices that can be used to specify udev rules assigning them to seat2. In order to do so, we will first need to see the attributes of these devices and their parents. We will tackle the keyboard first (a few lines were stripped for brevity):

[root@kaito]$ udevadm info -a -p /devices/pci0000:00/0000:00:12.1/usb4/4-1/4-1:1.0/input/input2

...snip...

  looking at device '/devices/pci0000:00/0000:00:12.1/usb4/4-1/4-1:1.0/input/input2':
    KERNEL=="input2"
    SUBSYSTEM=="input"
    DRIVER==""
    ATTR{name}=="CHESEN PS2 to USB Converter"
    ATTR{phys}=="usb-0000:00:12.1-1/input0"
    ATTR{uniq}==""
    ATTR{properties}=="0"

  looking at parent device '/devices/pci0000:00/0000:00:12.1/usb4/4-1/4-1:1.0':
    KERNELS=="4-1:1.0"
    SUBSYSTEMS=="usb"
    DRIVERS=="usbhid"
    ATTRS{bInterfaceClass}=="03"
    ATTRS{bInterfaceSubClass}=="01"
    ATTRS{bInterfaceProtocol}=="01"
    ATTRS{bNumEndpoints}=="01"
    ATTRS{supports_autosuspend}=="1"
    ATTRS{bAlternateSetting}==" 0"
    ATTRS{bInterfaceNumber}=="00"

...snip...

The keyboard can be identified easily by its name and there are no other devices on the machine with the same name. The udev rule needs to assign an environment variable called ID_SEAT to the correct device:

TAG=="seat", ATTRS{name}=="CHESEN PS2 to USB Converter", ENV{ID_SEAT}="seat2"

Note that we have also added a match on the TAG attribute to ensure that we do not try to use devices that are not assignable to a seat (such as hard disks). A similar solution works for the mouse as well. However, the video card is a little more complex. The udev attributes for the video card is as follows:

[root@kaito]$ udevadm info -a -p /devices/pci0000:00/0000:00:04.0/0000:02:00.0/drm/card1

...snip...

  looking at device '/devices/pci0000:00/0000:00:04.0/0000:02:00.0/drm/card1':
    KERNEL=="card1"
    SUBSYSTEM=="drm"
    DRIVER==""

  looking at parent device '/devices/pci0000:00/0000:00:04.0/0000:02:00.0':
    KERNELS=="0000:02:00.0"
    SUBSYSTEMS=="pci"
    DRIVERS=="radeon"
    ATTRS{irq}=="45"
    ATTRS{subsystem_vendor}=="0x174b"
    ATTRS{broken_parity_status}=="0"
    ATTRS{class}=="0x030000"
    ATTRS{power_method}=="profile"
    ATTRS{consistent_dma_mask_bits}=="40"
    ATTRS{dma_mask_bits}=="40"
    ATTRS{local_cpus}=="00000000,00000000,00000000,0000000f"
    ATTRS{device}=="0x9588"
    ATTRS{power_profile}=="default"
    ATTRS{msi_bus}==""
    ATTRS{local_cpulist}=="0-3"
    ATTRS{vendor}=="0x1002"
    ATTRS{subsystem_device}=="0x2e42"
    ATTRS{boot_vga}=="0"
    ATTRS{numa_node}=="0"

  looking at parent device '/devices/pci0000:00/0000:00:04.0':
    KERNELS=="0000:00:04.0"
    SUBSYSTEMS=="pci"
    DRIVERS=="pcieport"
    ATTRS{irq}=="41"
    ATTRS{subsystem_vendor}=="0x1849"
    ATTRS{broken_parity_status}=="0"
    ATTRS{class}=="0x060400"
    ATTRS{consistent_dma_mask_bits}=="32"
    ATTRS{dma_mask_bits}=="32"
    ATTRS{local_cpus}=="00000000,00000000,00000000,0000000f"
    ATTRS{device}=="0x597a"
    ATTRS{msi_bus}=="1"
    ATTRS{local_cpulist}=="0-3"
    ATTRS{vendor}=="0x1002"
    ATTRS{subsystem_device}=="0x5957"
    ATTRS{numa_node}=="0"

...snip...

There does not seem to be an obvious property on which to match. After trawling through various devices, we find that the one property that is different between the two video cards: they both have the same vendor id, but different subsystem device ids. (This makes sense since they are both RadeonHD cards, albeit with different model numbers.) Then the udev rules follow easily:

# Radeon 2600XT video and HDMI audio
TAG=="seat", ATTRS{vendor}=="0x1002", ATTRS{subsystem_device}=="0x2e42", ENV{ID_SEAT}="seat2"
TAG=="seat", ATTRS{vendor}=="0x1002", ATTRS{subsystem_device}=="0xaa08", ENV{ID_SEAT}="seat2"

Putting all of the rules into a udev rules file completes the process:

# Radeon 2600XT video and HDMI audio
TAG=="seat", ATTRS{vendor}=="0x1002", ATTRS{subsystem_device}=="0x2e42", ENV{ID_SEAT}="seat2"
TAG=="seat", ATTRS{vendor}=="0x1002", ATTRS{subsystem_device}=="0xaa08", ENV{ID_SEAT}="seat2"

# Keyboard
TAG=="seat", ATTRS{name}=="CHESEN PS2 to USB Converter", ENV{ID_SEAT}="seat2"

# Mouse
TAG=="seat", ATTRS{name}=="Microsoft Microsoft 3-Button Mouse with IntelliEye(TM)", ENV{ID_SEAT}="seat2"

On reboot, devices will be assigned correctly to their respective seats. In theory, everything should work fine. However, our current testing reveals a need to boot into runlevel 3 and then manually invoke runlevel 5. We believe that this may have something to do with a udev race in dracut. Until it is fixed, the manual step of booting into runlevel 3 and changing manually into runlevel 5 will be needed.

Occasionally, we find that the GDM login screen turns blank. Once logged in, this does not occur (at least with KDE). Our current workaround for this case is to restart the X server for that particular seat by pressing Ctrl-Alt-Backspace.

Comments

Comments powered by Disqus