USB Multiseat on Ubuntu 9.04

This setup was primarily based on the procedures by Bernie Thompson at Plugable:
http://plugable.com/2009/11/16/setting-up-usb-multiseat-with-displaylink-on-linux-gdm-up-to-2-20/
This procedure, together with some modifications, works on compact MSI Intel Atom machine with two sets of Plugable USB Docking station (UD-160-A), USB keyboard and USB mouse.

After the successful installation, I got two login screens with two Plugable docking stations connected before starting the computer. I discovered that unplugging and replugging of the docking stations didn’t work in my installation even if I have religiously followed the installation procedures. I tried to make a workaround on this problem and I have successfully made the removal and reconnection work on my multiseat setup by changing some lines in udev rules, usbseat.sh script and added the usbseat-remove.sh script.

Two Monitors with Login Displays

Two Monitors with Login Displays

It can also handle new seats plugged-in into the computer’s USB ports.

The 50-usbseat.rules:

# set all DisplayLink devices to configuration 1
# see http://libdlo.freedesktop.org/wiki/DeviceQuirks for more info

ATTR{idVendor}=="17e9", ATTR{bConfigurationValue}=="2", RUN="/bin/echo 1 > /sys%p/bConfigurationValue"

# aliases for display, kbd, mouse attached to specific hubs
KERNEL=="fb*", SUBSYSTEMS=="usb", PROGRAM="/bin/cat /sys/%p/../../../devnum", SYMLINK+="usbseat/%c/display", RUN+="usbseat.sh %c"

# The environment variable REMOVE_CMD in ENV{REMOVE_CMD} will execute 
# automatically the script being assigned to it
KERNEL=="mouse*", SUBSYSTEMS=="usb", ATTRS{bInterfaceClass}=="03", ATTRS{bInterfaceProtocol}=="02", PROGRAM="/bin/cat /sys/%p/../../../../../devnum", SYMLINK+="usbseat/%c/mouse", ENV{REMOVE_CMD}="usbseat-remove.sh %c mouse", RUN+="usbseat.sh %c"
KERNEL=="event*", SUBSYSTEM=="input", ATTRS{bInterfaceClass}=="03", ATTRS{bInterfaceProtocol}=="01", PROGRAM="/bin/cat /sys/%p/../../../../../devnum", SYMLINK+="usbseat/%c/keyboard", ENV{REMOVE_CMD}="usbseat-remove.sh %c keyboard", RUN+="usbseat.sh %c"
KERNEL=="control*", SUBSYSTEM=="sound", SUBSYSTEMS=="usb", PROGRAM="/bin/cat /sys/%p/../../../../../devnum", SYMLINK+="usbseat/%c/sound"

# and for when the keyboard and mouse are one more hub downstream. 
# Relying on pnp order to have already set up mouse, keyboard on
# upstream hub if we're daisy-chaining
#--------------------------------------------------------------
# The following two lines below are commented since it creates 
# an incomplete grouping of the devices and messed with the
# creation of the seat on the fly when the USB docking station
# is plugged in.
#--------------------------------------------------------------
#KERNEL=="event*", SUBSYSTEM=="input", ATTRS{bInterfaceClass}=="03", ATTRS{bInterfaceProtocol}=="01", PROGRAM="/bin/cat /sys/%p/../../../../../../devnum", SYMLINK+="usbseat/%c/keyboard", RUN+="/lib/udev/usbseat.sh.tmp %p %c keyboard /sys/%p/../../../../../../devnum"
#KERNEL=="mouse*", SUBSYSTEMS=="usb", ATTRS{bInterfaceClass}=="03", ATTRS{bInterfaceProtocol}=="02", PROGRAM="/bin/cat /sys/%p/../../../../../../devnum", SYMLINK+="usbseat/%c/mouse", RUN+="/lib/udev/usbseat.sh.tmp %p %c mouse /sys/%p/../../../../../../devnum"

The usbseat.sh script:

#!/bin/bash

# takes the "seat number" as parameter $1
# the seat number is the kernel device id of the hub the seat's devices 
# are sitting off of
# called once for every usb device that MIGHT be part of a seat, when
# they arrive or remove

SEATNAME=$1
if [[ !(-n `/bin/pidof gdm`) ]]; then
   exit 0
fi
seat_running=`/usr/bin/gdmdynamic -l | /bin/sed -n -e "/:$1,/p"`
# if we already have a running seat for this
#, exit
if [[ -n "${seat_running}" ]]; then
   exit 0
fi
if [[ -e /dev/usbseat/$SEATNAME/keyboard && -e /dev/usbseat/$SEATNAME/mouse && -e /dev/usbseat/$SEATNAME/display ]]; then
# We have a newly complete seat. Start it.
   TMPFILE=`/bin/mktemp` || exit 1
   /bin/sed "s/%ID_SEAT%/$SEATNAME/g" < /lib/udev/usbseat-xf86.conf.sed > $TMPFILE
   /usr/bin/gdmdynamic -v -t 2 -s 1 -a "$1=/usr/X11R6/bin/X -br :$1 vt07 -audit 0 -nolisten tcp -config $TMPFILE"
   /usr/bin/gdmdynamic -v -r $1
fi
exit 0

The usbseat-remove.sh script:

#!/bin/bash

# detach the seat during unplugging of the USB device
# or remove action in udev
# this will be called when either the USB keyboard or USB mouse
# is removed from the device

SEATNAME=$1
SEATNUM=$SEATNAME
SEATRUNNING=`/usr/bin/gdmdynamic -l | /bin/sed -n -e "/:$SEATNUM,/p"`

if [[ -n "{$SEATRUNNING}" ]]; then
   # remove the X instance
   /usr/bin/gdmdynamic -d $SEATNUM
   # remove the associated display device
   /bin/rm -f /dev/usbseat/$SEATNAME/display
fi
if [[ -d /dev/usbseat/$SEATNAME ]]; then
   # remove the directory of the unplugged USB seat if it is empty
   /bin/rmdir --ignore-fail-on-non-empty /dev/usbseat/$SEATNAME
fi
exit 0
USB Cables Connected to a PC

USB Cables Connected to a PC

The two bash scripts must be placed in /lib/udev directory with execute permissions set and owned by root. When you unplug the USB device, it will kill automatically the zombie process of X instance. Reconnecting the device will create complete seat at /dev/usbseat/ directory and launch an X instance and display the login screen. This workaround also works even the USB docking stations is connected in daisy-chain.

The user sessions during the removal/reconnection of the USB device will be handled correctly by the future versions of the GDM and ConsoleKit . Hopefully, it could save the user sessions when the USB seat is removed and restore them to where the user left off during the reconnection and logging in with the same account.

Applications Running on Two Independent Seats

Applications Running on Two Independent Seats

I welcome all your comments.

Advertisements
Posted in USB Multiseat | 1 Comment