scripts

The following GUI script will enable/disable automatic seat creation for HP T150 USB zero clients which may be purchased very cheaply on eBay. (10-14-2021 needs root privileges).

#!/bin/bash
# HP-T150-udev.sh
# writes or removes udev rule for HP T150 zero client auto seat configuration
L=Enable
if [ -f "/etc/udev/rules.d/72-HP-T150-seats.rules" ]; then L=Disable
zenity --info --title='HP-T150 USB Zero Clients' --window-icon='question' --icon-name='' --width=200 --text='Auto seat configuration' --ok-label=$L 2>/dev/null
case $? in
0) zenity --password 2>/dev/null|su -c 2>/dev/null 'rm -f /etc/udev/rules.d/72-HP-T150-seats.rules '
;;
esac
else
zenity --info --title='HP-T150 USB Zero Clients' --window-icon='question' --icon-name='' --width=200 --text='Auto seat configuration' --ok-label=$L 2>/dev/null
case $? in
0)zenity --password 2>/dev/null|su -c 2>/dev/null 'touch /etc/udev/rules.d/72-HP-T150-seats.rules
echo SUBSYSTEM=="usb", ATTR{idVendor}=="03f0", ATTR{idProduct}=="0032", ENV{ID_AUTOSEAT}="1" >/etc/udev/rules.d/72-HP-T150-seats.rules '
;;
esac
fi

You need not read further unless you are curious about the technical details of how multi-seat works. For networked zero clients, see my Phistek ZE7000 navigation tab.

10-06-2020 It has been reported to me that a recent upgrade to Manjaro 20 has broken multi-seat functionality.

[greg@greg-pc ~]$ uname -a
Linux greg-pc 5.4.67-1-MANJARO #1 SMP PREEMPT Wed Sep 23 14:20:18 UTC 2020 x86_64 GNU/Linux


[greg@greg-pc ~]$ lsb_release -a
LSB Version: n/a
Distributor ID: ManjaroLinux
Description: Manjaro Linux
Release: 20.1.1
Codename: Mikah

A still  more recent update on my computer has not fixed this.

The problem is not limited to multi-seat as it also affects any DisplayLink dl-1×5 USB connected device and will not allow it to be used to extend the desktop either. However, you can write data directly to the frame buffer for the DisplayLink device and you will see the corresponding pixels appear, so the problem in not in the udldrmfb driver itself. I will update this section when I or Manjaro have a fix.

Mint 20 XFCE linux still funtions correctly for DisplayLink dl-1×25 USB connected zero clients like the Plugable UD-160-A.

Automatic seat creation is a function of the file, /usr/lib/udev/rules.d/71-seat.rules Additional udev rules, or new rules to override 71-seat.rules, are best place in the /etc/udev/rules.d/ directory. (consult man udev or google “writing udev rules” for more information)

# SPDX-License-Identifier: LGPL-2.1+ # # This file is part of systemd. ############################################################# # 12-06-2019, code not relevant to usb zero clients removed # # by Lawrence E. Boothby for clarity # # # # /usr/lib/udev/rules.d/71-seat.rules # ############################################################# # systemd is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. ACTION=="remove", GOTO="seat_end" TAG=="uaccess", SUBSYSTEM!="sound", TAG+="seat" SUBSYSTEM=="sound", KERNEL=="card*", TAG+="seat" SUBSYSTEM=="input", KERNEL=="input*", TAG+="seat" SUBSYSTEM=="graphics", KERNEL=="fb[0-9]*", TAG+="seat" SUBSYSTEM=="drm", KERNEL=="card[0-9]*", TAG+="seat", TAG+="master-of-seat" SUBSYSTEM=="usb", ATTR{bDeviceClass}=="09", TAG+="seat" # 'Plugable' USB hub, sound, network, graphics adapter - note "000[13]" = "0001" or "0003" SUBSYSTEM=="usb", ATTR{idVendor}=="2230", ATTR{idProduct}=="000[13]", ENV{ID_AUTOSEAT}="1" TAG=="seat", ENV{ID_PATH}=="", IMPORT{builtin}="path_id" TAG=="seat", ENV{ID_FOR_SEAT}=="", ENV{ID_PATH_TAG}!="", ENV{ID_FOR_SEAT}="$env{SUBSYSTEM}-$env{ID_PATH_TAG}" LABEL="seat_end"

Note the comment for ‘Plugable’ and the line that follows. == is a comparison. If the comparison matches, then the assignment,=, at the end of the line is made. In the case of the UD-160-A, the idVendor is 2230 and the idProduct is 0001, so it will automatically create its own seat. 2230:0001 is the TERMINUS TECHNOLOGY INC. usb 2.0 hub in the UD-160-A whose children are the 4 USB 2.0 ports, the DisplayLink DL-165 usb to DVI adapter, and the USB audio device.

Note that seats created automatically in /usr/lib/udev/rules.d/71-seat.rules also automatically disappear when their zero clients are unplugged. Thus you can not use a UD-160-A to create a seat and then substitute a different brand and model at the same USB port. In contrast, seats manually created with the loginctl attach command persist across booting and after removed, providing they are not enabled in

/usr/lib/udev/rules.d/71-seat.rules

Since the mechanism already exists for automatic seat creation, it makes sense to focus first on how to add lines to 71-seat.rules to support other brands and models of usb zeroclients. For this you need to determine the idVendor and idProduct, not for the DisplaytLink adapter itself, but the internal usb hub of the zero client that this DisplayLink adapter is internally connected to.  If your usb zeroclient has no external USB ports for your keyboard/mouse, you can connect your zero client to an external USB hub, perhaps the one on your monitor. In this case the idVendor and idProduct is not that of the zeroclient internal hub, but of this external hub to which you attach both the zero client and perhaps a logitech unifying receiver for your wireless keyboard and mouse.  You can even create a usb zero client out of a Displaylink usb video adapter that shares an external usb hub with your keyboard/mouse. 

Before I figured out  how 71-seat.rules works, I used loginctl to attach hardware to seats not supported in the default 71-seat.rules.  Since I used the loginctl attach command for this, it was logical to use its loginctl seat-status command to list the available hardware to make seats of. That approach generates a lot of data that is not needed that then needs to be parsed for what is needed for the loginctl attach command.  Where does loginctl seat-status get its data?

Note the comment for ‘Plugable’ and the line that follows. == is a comparison. If the comparison matches, then the assignment,=, at the end of the line is made. In the case of the UD-160-A, the idVendor is 2230 and the idProduct is 0001, so it will automatically create its own seat. 2230:0001 is the TERMINUS TECHNOLOGY INC. usb 2.0 hub in the UD-160-A whose children are the 4 USB 2.0 ports, the DisplayLink DL-165 usb to DVI adapter, and the USB audio device.

Note that seats created automatically in /usr/lib/udev/rules.d/71-seat.rules also automatically disappear when their zero clients are unplugged. Thus you can not use a UD-160-A to create a seat and then substitute a different brand and model at the same USB port. In contrast, seats manually created with the loginctl attach command persist across booting and after removed, providing they are not enabled in

/usr/lib/udev/rules.d/71-seat.rules

Since the mechanism already exists for automatic seat creation, it makes sense to focus first on how to add lines to 71-seat.rules to support other brands and models of usb zeroclients. For this you need to determine the idVendor and idProduct, not for the DisplaytLink adapter itself, but the internal usb hub of the zero client that this DisplayLink adapter is internally connected to.  If your usb zeroclient has no external USB ports for your keyboard/mouse, you can connect your zero client to an external USB hub, perhaps the one on your monitor. In this case the idVendor and idProduct is not that of the zeroclient internal hub, but of this external hub to which you attach both the zero client and perhaps a logitech unifying receiver for your wireless keyboard and mouse.  You can even create a usb zero client out of a Displaylink usb video adapter that shares an external usb hub with your keyboard/mouse. 

Before I figured out  how 71-seat.rules works, I used loginctl to attach hardware to seats not supported in the default 71-seat.rules.  Since I used the loginctl attach command for this, it was logical to use its loginctl seat-status command to list the available hardware to make seats of. That approach generates a lot of data that is not needed that then needs to be parsed for what is needed for the loginctl attach command.  Where does loginctl seat-status get its data?

https://www.kernel.org/doc/html/latest/admin-guide/sysfs-rules.html

The sysfs is created during booting of the linux kernel and has no existence anywhere when the computer is off. It is organized as a hierarchical directory structure. The only real part starts at /sys/devices/…

In /sys/ you will see other subdirectories besides devices. Think of these other directories as specialized views into /sys/devices/…

These other views have symbolic links into /sys/devices/…

It is convenient for my purposes to follow the symbolic link at the bottom of /sys/class/drm/card? since once the symbolic link is resolved, I get a list of all video devices. I am only interested in the usb connected ones, so I use the filter, grep to discard the internal video integrated video or PCI express video cards. Since card? returns card0, card1, …card9, it would not find card10-99. If you run my program multiple times plugging and unplugging zero clients, you can run out of card0-9. You will find at most 8 connected usb zero clients because one of the cards will be the integrated video on the motherboard, which will not necessarily be card0. You can always reboot to start the card count again at card0 to get data on additional usb zeroclients.

To get these idVendor and idProduct values, I have written this little bash script:

#!/bin/bash echo " copyleft, Lawrence E. Boothby (multi-seat.com), 2019" echo " under current GPL license" echo " searching for usb DisplayLink device(s), if none, just exit

" readlink -f /sys/class/drm/card?|grep usb| xargs -L 1 -r bash -c 'P="$0" echo "$P" cd $P echo "searching for internal hub of DisplayLink device" cd ../../../../ pwd if [ -f "idVendor" ]; then echo -n "idVendor=";cat idVendor;echo -n "idProduct=";cat idProduct else echo "none found" fi echo "searching for first usb hub above, if exists" cd .. pwd # for diagnosis if [ -f "idVendor" ]; then echo -n "idVendor=";cat idVendor;echo -n "idProduct=";cat idProduct else echo "none found" fi echo " " ' read -p "Press Enter to exit"

71-seat-rules already supports automatic seat creation for the Plugable UD-160-A,  but let’s see what my program returns for a single US-160-A:

copyleft, Lawrence E. Boothby (multi-seat.com), 2019
under current GPL license

searching for usb DisplayLink device(s), if none, just exit


/sys/devices/pci0000:00/0000:00:12.2/usb3/3-2/3-2.1/3-2.1:1.0/drm/card0
searching for internal hub of DisplayLink device
/sys/devices/pci0000:00/0000:00:12.2/usb3/3-2
idVendor=2230
idProduct=0001
searching for first usb hub above, if exists
/sys/devices/pci0000:00/0000:00:12.2/usb3
idVendor=1d6b
idProduct=0002

71-seat.rules contains:

# 'Plugable' USB hub, sound, network, graphics adapter - note "000[13]" = "0001" or "0003" SUBSYSTEM=="usb",ATTR{idVendor}=="2230",ATTR{idProduct}=="000[13]ENV{ID_AUTOSEAT}="1"

If you had the Plugable UD-160-M model instead of the UD-160-A model I have, the idProduct would likely be 0003 and my program would return that value.

Note also the /sys/devices/pci0000:00/0000:00:12.2/usb3/3-2 If there were no entries in 71-seat.rules for the UD-160-A/M, I could use the command:

sudo loginctl attach seat-new1 /sys/devices/pci0000:00/0000:00:12.2/usb3/3-2

and on my computer, that specific USB port would become a new seat named seat-new1.

71-seat.rules automatically creates and names seats based on the idVendor and the idProduct. It does not care which USB port you connect that zeroclient to in the future. In contrast, manual seat assignment using loginctl,  requires you to specify a unique new seat name and that assignment applies to the specified USB port which doesn’t care what the idVendor and idProduct are for any future zeroclients using that port.

Following the example for Plugable UD-160-A in 71-seat rules,  you can create custom lines for your specific hardware and reboot your computer so they will be read and enable multi-seat for your hardware.

Before I had any Plugable UD-160-A, I only had HP T100/150/200 USB zeroclients so had to manually create their seats with loginctl attach seatNAME DEVICE.

Next I will connect 5 miscellaneous usb zero clients to illustrate several issues.

Plugable USB 3.0 3-Port Bus Powered Hub with Gigabit Ethernet – Plugable

The fourth zero client (not pictured) is an HP T200. Because there is no opensource linux driver for its SMSC UFX6000 internal USB to VGA chip, it would not be seen and would not be usable except by attaching a DisplayLink usb to VGA adapter to the HP T200. I had a used HP NL571AA (bought three for a total of $7.50 with free shipping on eBay), but you could also use a new Plugable uga-165.

https://plugable.com/products/uga-165/

My fifth usb zeroclient is another HP NL571AA, this time connected through another Belkin 2.0 hub. This makes a usb zeroclient without audio. If your monitor has a 2 port usb hub on it, you could use that for the hub and a Logitech unifying receiver. Perhaps you would like to encourage your students or children to use computers to research and create, rather than to just listen to youtube musical videos so the absence of audio would be a plus.

As Displaylink video adapters are often used to add a third monitor to a laptop, this would be a good reason not to add their idVendor and idProduct to 71-set.rules. If it is listed in 71-seat.rules, it will automatically be grabbed to create a new seat. Using loginctl to manually attach one of multiple DisplayLink vedio adapters allows you to attach one or more to the main computer at the same time that you can also attach one or more to specific usb ports for use as new seats. Loginctl also allows you to create a seat with more than one display adapter. 71-seat.rules will only initialize the first displaylink adapter it finds per seat, even if more than one are attached as in my 2 HP NL571AA attached to my single HP T200 zeroclient.

With my 4 HP usb zero clients and 2 HP usb display adapter, my program reports:

copyleft, Lawrence E. Boothby (multi-seat.com), 2019
under current GPL license searching for usb DisplayLink device(s), if none, just exit /sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-1/1-1.4/1-1.4:1.0/drm/card0
searching for internal hub of DisplayLink device
/sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-1
idVendor=05e3 <--- Genesys Logic, Inc. USB 2.0 Hub (Belkin F5U215-MOB)
idProduct=0605
searching for first usb hub above, if exists
/sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1
idVendor=1d6b <--- HP NL571AA (DL-165 DisplayLink)
idProduct=0002
============================================================================================== /sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-2/1-2.2/1-2.2.1/1-2.2.1:1.0/drm/card3
searching for internal hub of DisplayLink device <--- HP T150 (DL-125)
/sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-2/1-2.2
idVendor=03f0 <--- HP T150 internal hub
idProduct=0032
searching for first usb hub above, if exists
/sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-2
idVendor=2109 <--- plugged into external Plugable 3.0 hub
idProduct=2813 /sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-2/1-2.3/1-2.3.1/1-2.3.1:1.0/drm/card4
searching for internal hub of DisplayLink device <--- HP T150 (DL-125)
/sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-2/1-2.3
idVendor=03f0 <--- HP T150 internal hub
idProduct=0032
searching for first usb hub above, if exists
/sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-2
idVendor=2109 <--- plugged into external Plugable 3.0 hub
idProduct=2813 /sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-2/1-2.4/1-2.4.2/1-2.4.2.1/1-2.4.2.1:1.0/drm/card6
searching for internal hub of DisplayLink device <--- DL-125
/sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-2/1-2.4/1-2.4.2
idVendor=0424 <---Standard Microsystems Corp. USB 2.0 Hub (internal to HP T100)
idProduct=2514
searching for first usb hub above, if exists <--- HP T100 zero client
/sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-2/1-2.4
idVendor=05e3 <--- Genesys Logic, Inc. Hub (Belkin F5U407)
idProduct=0608 =========================================================================
/sys/devices/pci0000:00/0000:00:12.2/usb3/3-2/3-2.3/3-2.3:1.0/drm/card8
searching for internal hub of DisplayLink device <--- DL-165
idVendor=03f0
idProduct=0032
searching for first usb hub above, if exists
/sys/devices/pci0000:00/0000:00:12.2/usb3 <--- HP T200
idVendor=1d6b <--- HP NL571AA (DL-165 DisplayLink)
idProduct=0002 /sys/devices/pci0000:00/0000:00:12.2/usb3/3-2/3-2.4/3-2.4:1.0/drm/card9
searching for internal hub of DisplayLink device <--- DL-165
/sys/devices/pci0000:00/0000:00:12.2/usb3/3-2
idVendor=03f0
idProduct=0032
searching for first usb hub above, if exists
/sys/devices/pci0000:00/0000:00:12.2/usb3 <--- HP T200
idVendor=1d6b <--- HP NL571AA (DL-165 DisplayLink)
idProduct=0002
/sys/devices/pci0000:00/0000:00:12.2/usb3/3-2
=========================================================================
Press any key to exit 

Now look at the two entries I need in 71-seat.rules to cover all the hardware above. Note that I don’t want,  and have commented out, the two lines for the HP T100. This is because I want to include the usb hub above it so that there will be USB ports the HP T100 lacks for my keyboard and mouse. I have used red text for the idProduct and idVendor values in 71-seat.rules and the corresponding values output by my program.

# 'Plugable' USB hub, sound, network, graphics adapter - note "000[13]" = "0001" or "0003"
SUBSYSTEM=="usb", ATTR{idVendor}=="2230", ATTR{idProduct}=="000[13]", ENV{ID_AUTOSEAT}="1" # 'HP T150 AND T200' USB hub, sound, graphics adapter
SUBSYSTEM=="usb", ATTR{idVendor}=="03f0", ATTR{idProduct}=="0032", ENV{ID_AUTOSEAT}="1" # 'HP T100' USB hub, sound, graphics adapter
# SUBSYSTEM=="usb", ATTR{idVendor}=="0424", ATTR{idProduct}=="2514", ENV{ID_AUTOSEAT}="1" # Like above, but with HP T100 or HP connected through Belkin F5U407 USB 2.0 hub to provide usb ports for keyboard/mouse
SUBSYSTEM=="usb", ATTR{idVendor}=="05e3", ATTR{idProduct}=="060[58]", ENV{ID_AUTOSEAT}="1"

To summarize:

  1. While most Linux distributions (with systemd and loginctl) have the basic infrastructure for multi-seat, I have only found Manjaro and MInt Linux to support hot plugging of USB zeroclients.
  2. /usr/lib/udev/rules.d/71-seat.rules contains the idVendor and idProduct values for zeroclient hardware automatic seat creation.
  3. The bash program I wrote and grant GPL license rights to the public, searches for usb zeroclient display adapters and returns the required idVendor and id Product values needed to add support for hardware other than the UD-160 in /usr/lib/udev/rules.d/71-seat.rules
  4. loginctl allows you to create seats pairing extra video cards, sound cards, and multiple keyboards and mice.
  5. Mark Gress has written a GUI java app making this easier for multi-seat internal hardware, while my approach using /usr/lib/udev/rules.d/71-seat.rules is easier for usb zero clients. https://easy-seats.weebly.com/
  6. Mint Linux already has a guest account capability that can be enabled. With a Plugable UD-160-A connected before booting, it automatically creates a new unique guest login that does not require a password or user account. Note that its path to home is under /tmp/ instead of under /home/ and that it has a unique suffix so that multiple guests can login at the same time. This is perfect for public kiosks. Attention should be given to what programs a guest account can run for security reasons. A guest should not be allowed to shutdown the computer, only logout of their guest session. One problem with Mint Linux if multi booting, is that when Mint updates its grub boot loader, it no longer can boot Manjaro properly. There is a solution to this involving creating a special custom entry for Manjaro which will override the code that Mint would use to boot Manjaro by default – then both can work.

Note that the path to 71-seat.rules in Mint is different than in Manjaro. For Mint it is /lib/udev/rules.d/71-seat.rules