Raspberry Pi2 and Pi3 running pure Debian and the Linux Mainline/Vanilla Kernel

Update 2017 Feb 25: I have updated the step-by-step instructions based on the suggested fixes and improvements contained in the reader comments. I also have copied the step-by-step instructions from this blog post to the README.md file hosted on https://github.com/michaelfranzl/rpi23-gen-image. From now on I will update the instructions only on github, so expect that the instructions in this blog post will grow slightly out of date.

Update 2017 Mar 4: 64 bit kernel and Debian OS now works on the RPi3.

Update 2018 May: Debian 10 “Buster” works, including wireless LAN on RPi3

Gallium graphics drivers for Raspberry Pi’s VC4 chip are now fully supported by Linux Mainline

This has been a long way coming. In February 2014, Broadcom announced that they would release the formerly closed-source drivers for the VideoCore IV (VC4) GPU of their BCM283x family of System-on-a-chip (SoC), powering Raspberry Pi’s.

To make a long story short, Eric Anholt started porting the Open Source drivers, as documented by this presentation early 2015, and contributed code to the Linux (Mainline) Kernel, libdrm, Mesa, and X.org. I’m sure it was a long and painful work. But the results are worth it. A picture says more than 1000 words:

Debian 9 ("Stretch") running on a Raspberry Pi 2, powered by Linux 4.9.0-rc3 Mainline/Vanilla Kernel. Notable in this image: Graphics driver is "Gallium" running on the VC4 GPU of the Broadcom 2836 system-on-a-chip (SOC). Glxgears runs with 60 FPS and consumes very little CPU. I2C interface is recognized.
Debian 9 (“Stretch”) running on my Raspberry Pi 2 (and 3), powered by Linux 4.9.0-rc3 Mainline/Vanilla Kernel. Notable in this image: Graphics driver is recognized as “Gallium” running on the VC4 GPU of the Broadcom 2836 system-on-a-chip (SOC). The glxgears benchmark runs with 60 FPS (the vsync of the monitor) and consumes very little CPU. Even the Raspberry I2C interface is recognized by the Linux Mainline Kernel.

To emphasize the point: It is no longer necessary to run specialized distributions (like Raspbian) or Linux kernels (like the Raspbian flavor) in order to have the Raspberry Pi well supported. And this is good news. Debian is a well established and maintained standard Distribution. And even though the Raspberry Pi is not powerful enough for the professional desktop user, it is powerful enough for the casual desktop user, and it is very small and cheap, which opens up a whole lot of possibities for new real-world applications.

I ran an additional test: Gnome even runs on Wayland (modern replacement for the X Window System) on the Raspberry Pi 2 (and 3):

Gnome on Wayland on Raspberry Pi 2
Gnome on Wayland on Raspberry Pi 2

 

Remarks

It still is not a matter of a one-click installer to reproduce these results, you need some experience when you run into barriers. But it has gotten a whole lot easier. Github user drtyhlpr thankfully published the script rpi23-gen-image that can create a standard Debian distribution for the Raspberry Pi that can simply be copied to a SD card.

I have created a fork of this script to use the official Linux kernel instead of the Raspberry flavor one. Above screenshots are taken from a system that I’ve created with this script. My fork is developed into a slightly different direction:

  • Only official Debian releases 9 (“Stretch”) and newer are supported.
  • Only the official/mainline/vanilla Linux kernel is supported (not the raspberry flavor kernel).
  • The Linux kernel must be pre-cross-compiled on the PC running this script (instructions below).
  • Only U-Boot booting is supported.
  • The U-Boot sources must be pre-downloaded and pre-cross-compiled on the PC running this script (instructions below).
  • An apt caching proxy server must be installed to save bandwidth (instructions below).
  • The installation of the system to an SD card is done by simple copying or rsyncing, rather than creating, shrinking and expanding file system images.
  • The FBTURBO option is removed in favor or the working VC4 OpenGL drivers of the mainline Linux kernel.

All of these simplifications are aimed at higher bootstrapping speed and maintainability of the script. For example, we want to avoid testing of all of the following combinations:

RPi2 with u-boot, with official kernel
RPi2 without u-boot, with official kernel
RPi2 with u-boot, with raspberry kernel
RPi2 without u-boot, with raspberry kernel
RPi3 with u-boot, with official kernel
RPi3 without u-boot, with official kernel
RPi3 with u-boot, with raspberry kernel
RPi3 without u-boot, with raspberry kernel

Thus, the script only supports:

RPi2 with u-boot with official kernel
RPi3 with u-boot with official kernel

RPi2 (setting RPI_MODEL=2) is well supported. It will run the arm architecture of Debian, and a 32-bit kernel. You should get very good results, see my related blog posts:

https://blog.michael.franzl.name/2016/10/31/raspberry-pi-debian-stretch/

The newer RPi3 (setting RPI_MODEL=3) is supported too. It will run the arm64 architecture of Debian, and a 64-bit kernel. The support of this board by the Linux kernel will very likely improve over time.

In general, this script is EXPERIMENTAL. I do not provide ISO file system images. It is better to master the process rather than to rely on precompiled images. In this sense, use this project only for educational purposes.

How to do it

Basically, we will deboostrap a minimal Debian 9 (“Stretch”) system for the Raspberry on a regular PC running also Debian 9 (“Stretch”). Then we copy that system onto a SD card, then boot it on the Raspberry.

We will work with the following directories:

~/workspace
  |- rpi23-gen-image
  |- linux
  |- u-boot
  |- raspberry-firmware

Set up your working directory:

mkdir workspace
cd workspace

Do the following steps as root user.

Set up caching for apt

This way, you won’t have to re-download hundreds of megabytes of Debian packages from the Debian server every time you run the rpi23-gen-image script.

apt-get install apt-cacher-ng

Check its status page:

http://localhost:3142

Install dependencies

The following list of Debian packages must be installed on the build system because they are essentially required for the bootstrapping process.

apt-get install debootstrap debian-archive-keyring qemu-user-static binfmt-support dosfstools rsync bmap-tools whois git bc device-tree-compiler

For a RPi2, you also need:

apt-get install crossbuild-essential-armhf

For a RPi3, you also need:

apt-get install crossbuild-essential-arm64

Kernel compilation

Get the latest Linux mainline kernel. This is a very large download, about 2GB. (For a smaller download of about 90 MB, consider downloading the latest stable kernel as .tar.xz from https://kernel.org.)

git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
cd linux

Confirmed working revision (approx. version 4.10, Feb 2017): 60e8d3e11645a1b9c4197d9786df3894332c1685

git checkout 60e8d3e116

Working configuration files for this Linux kernel revision are included in this repository. (working-rpi2-linux-config.txt and working-rpi3-linux-config.txt).

If you want to generate the default .config file that is also working on the Raspberry, execute

make mrproper

For a RPi2:

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- multi_v7_defconfig

For a RPi3:

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig

Whichever .config file you have at this point, if you want to get more control as to what is enabled in the kernel, you can run the graphical configuration tool at this point:

apt-get install libglib2.0-dev libgtk2.0-dev libglade2-dev

For a RPi2:

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- gconfig

For a RPi3:

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- gconfig

Before compiling the kernel, back up your .config file so that you don’t lose it after the next make mrproper:

cp .config ../kernelconfig-backup.txt

Compiling the kernel

Clean the sources:

make mrproper

Optionally, copy your previously backed up .config:

cp ../kernelconfig-backup.txt .config

Find out how many CPU cores you have to speed up compilation:

NUM_CPU_CORES=$(grep -c processor /proc/cpuinfo)

Run the compilation on all CPU cores. This takes about 10 minutes on a modern PC:

For a RPi2:

make -j${NUM_CPU_CORES} ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-

For a RPi3:

make -j${NUM_CPU_CORES} ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-

Verify that you have the required kernel image.

For a RPi2 this is:

./arch/arm/boot/zImage

For a RPi3 this is:

./arch/arm64/boot/Image.gz

U-Boot bootloader compilation

cd ..
git clone git://git.denx.de/u-boot.git

Confirmed working revision: b24cf8540a85a9bf97975aadd6a7542f166c78a3

git checkout b24cf8540a

Let’s increase the maximum kernel image size from the default (8 MB) to 64 MB. This way, u-boot will be able to boot even larger kernels. Edit ./u-boot/include/configs/rpi.h  and add above the very last line (directly above “#endif”):

#define CONFIG_SYS_BOOTM_LEN (64 * 1024 * 1024)

Find out how many CPU cores you have to speed up compilation:

NUM_CPU_CORES=$(grep -c processor /proc/cpuinfo)

Compile for a RPi model 2 (32 bits):

make -j${NUM_CPU_CORES} ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- rpi_2_defconfig all

Compile for a RPi model 3 (64 bits):

make -j${NUM_CPU_CORES} ARCH=arm CROSS_COMPILE=aarch64-linux-gnu- rpi_3_defconfig all

Verify that you have the required bootloader file:

./u-boot.bin

Pre-download Raspberry firmware

The Raspberry Pi still needs some binary proprietary blobs for booting. Get them:

cd ..
mkdir -p raspberry-firmware/boot
cd raspberry-firmware/boot
wget https://github.com/raspberrypi/firmware/raw/master/boot/bootcode.bin
wget https://github.com/raspberrypi/firmware/raw/master/boot/fixup_cd.dat
wget https://github.com/raspberrypi/firmware/raw/master/boot/fixup.dat
wget https://github.com/raspberrypi/firmware/raw/master/boot/fixup_x.dat
wget https://github.com/raspberrypi/firmware/raw/master/boot/start_cd.elf
wget https://github.com/raspberrypi/firmware/raw/master/boot/start.elf
wget https://github.com/raspberrypi/firmware/raw/master/boot/start_x.elf

Confirmed working revision: bf5201e9682bf36370bc31d26b37fd4d84e1cfca

Build the system!

This is where you call the rpi23-gen-image.sh script.

cd ../..
git clone https://github.com/michaelfranzl/rpi23-gen-image.git
cd rpi23-gen-image

For example:

DEBIAN_RELEASE="stretch" \
USER_NAME="pi" \
PASSWORD="xxx" \
APT_INCLUDES="i2c-tools,rng-tools,avahi-daemon,rsync,vim" \
UBOOTSRC_DIR="$(pwd)/../u-boot" \
KERNELSRC_DIR="$(pwd)/../linux" \
RPI_MODEL=2 \
HOSTNAME="rpi2" \
RPI_FIRMWARE_DIR="$(pwd)/../raspberry-firmware" \
ENABLE_IPTABLES=true \
ENABLE_REDUCE=true \
REDUCE_SSHD=true \
./rpi23-gen-image.sh

You may want to modify the variables according to the section “Command-line parameters” below.

The file example.sh in my github repostory contains a working example.

Install the system on a SD card

Insert a SD card into the card reader of your host PC. You’ll need two partitions on it. I’ll leave as an exercise for the reader the creation of a partition table according to the following output of fdisk for a 64GB card:

Device         Boot  Start        End    Sectors    Size   Id  Type
/dev/mmcblk0p1        2048     500000     497953  243.1M    c  W95 FAT32 (LBA)
/dev/mmcblk0p2      501760   62552063   62050304   29.6G   83  Linux

The following commands will erase all contents of the SD card and install the system (copy via rsync) on the SD card:

umount /dev/mmcblk0p1
umount /dev/mmcblk0p2

mkfs.vfat /dev/mmcblk0p1
mkfs.ext4 /dev/mmcblk0p2

mkdir -p /mnt/raspcard

mount /dev/mmcblk0p2 /mnt/raspcard
mkdir -p /mnt/raspcard/boot/firmware
mount /dev/mmcblk0p1 /mnt/raspcard/boot/firmware

rsync -a ./images/stretch/build/chroot/ /mnt/raspcard

umount /dev/mmcblk0p1
umount /dev/mmcblk0p2

Note about SD cards: Cheap (or sometimes even professional) SD cards can be weird at times. I’ve repeatedly noticed corrupt/truncated files even after proper rsync and proper umount on different brand new SD cards. TODO: Add a method to verify all file checksums after rsync.

Try booting the Raspberry

Insert the SD card into the Raspberry Pi, and if everything went well, you should see a console-based login prompt on the screen. Login with the login details you’ve passed into the script (USER_NAME and PASSWORD).

Alternatively, if you have included “avahi-daemon” in your APT_INCLUDES, you don’t need a screen and keyboard and can simply log in via SSH from another computer, even without knowing the Rasberry’s dynamic/DHCP IP address (replace “hostname” and “username” with what you have set as USER_NAME and HOSTNAME above):

ssh username@hostname.local

Finishing touches directly on the Raspberry

Remember to change usernames, passwords, and SSH keys!

Check uber-low RAM usage

Running top shows that the freshly booted system uses only 23 MB out of the availabl 1GB RAM! Confirmed for both RPi2 and RPi3.

Network Time Synchronization

The Raspberry doesn’t have a real time clock. But the default systemd conveniently syncs time from the network. Check the output of timedatectl. Confirmed working for both RPi2 and RPi3.

Hardware Random Number Generator

The working device node is available at /dev/hwrng. Confirmed working for both RPi2 and RPi3.

I2C Bus

Also try I2C support:

apt-get install ic2-tools
i2cdetect -y 0

Confirmed working for both RPi2 and RPi3.

Test onboard LEDs

As of the kernel revision referenced above, this only works on the RPi2. The RPi3 has only the red PWR LED on all the time, but otherwise is working fine.

By default, the green onboard LED of the RPi blinks in a heartbeat pattern according to the system load (this is done by kernel feature LEDS_TRIGGER_HEARTBEAT).

To use the green ACT LED as an indicator for disc access, execute:

echo mmc0 > /sys/class/leds/ACT/trigger

To toggle the red PWR LED:

echo 0 > /sys/class/leds/PWR/brightness # Turn off
echo 1 > /sys/class/leds/PWR/brightness # Turn on 

Or use the red PWR LED as heartbeat indicator (kernel option for this must be enabled):

echo heartbeat > /sys/class/leds/PWR/trigger

Notes about systemd

systemd now replaces decades-old low-level system administration tools. Here is a quick cheat sheet:

Reboot machine:

systemctl reboot

Halt machine (this actually turns off the RPi):

systemctl halt

Show all networking interfaces:

networkctl

Show status of the Ethernet adapter:

networkctl status eth0

Show status of the local DNS caching client:

systemctl status systemd-resolved

Install GUI

Successfully tested on the RPi2 and RPI3.

If you want to install a graphical user interface, I would suggest the light-weight LXDE window manager. Gnome is still too massive to run even on a GPU-accelerated Raspberry.

apt-get install lightdm lxde lxde-common task-lxde-desktop

Reboot, and you should be greeted by the LightDM greeter screen!

Test GPU acceleration via VC4 kernel driver

Successfully tested on the RPi2 and RPI3.

apt-get install mesa-utils
glxgears
glxinfo | grep '^OpenGL'

Glxinfo should output:

OpenGL vendor string: Broadcom
OpenGL renderer string: Gallium 0.4 on VC4
OpenGL version string: 2.1 Mesa 12.0.3
OpenGL shading language version string: 1.20
OpenGL ES profile version string: OpenGL ES 2.0 Mesa 12.0.3
OpenGL ES profile shading language version string: OpenGL ES GLSL ES 1.0.16

Kernel compilation directly on the Rasberry

Only successfully tested on the RPi2. Not yet tested on the RPI3.

In case you want to compile and deploy another Mainline Linux kernel directly on the Raspberry, proceed as described above, but you don’t need the ARCH and CROSS_COMPILE flags. Instead, you need the -fno-pic compiler flag for modules. The following is just the compilation step (configuration and installation omitted):

make -j5 CFLAGS_MODULE="-fno-pic"
make modules_install

Follow-up articles

.

Adventures with various Segfaults due to defective RAM

Note: This post is 8 years old. Some information may no longer be correct or even relevant. Please, keep this in mind while reading.

If you get various segfaults on your Linux server, like these:

spamd child[2656]: segfault at 200251c208 ip 00007fa039223684 sp 00007fff77953680 error 4 in libperl.so.5.14.2[7fa03916a000+177000]

or:

clamd[3311]: segfault at 1000000008 ip 00007f00200b3751 sp 00007fff3e2cef60 error 4 in libclamav.so.6.1.17[7f001fff1000+988000]

or

php5[14914]: segfault at 7fff7d2939c8 ip 00000000006bf04d sp 00007fff6d293860 error 6 in php5[400000+6f3000]

or

PassengerHelper[11644]: segfault at ffffffffca4ef420 ip 0000000000492fea sp 00007f5b81e991d0 error 7 in PassengerHelperAgent[400000+203000]

etc. etc., then, no, your system is not suddenly crazy. Nor are you. It is highly likely that you RAM is defective. You should reboot your server and run the  RAM test from your boot manager (Grub always has such a test) to see if it can detect faulty RAM.

If you are operating a server that you can’t reboot because you can’t tolerate downtime, there is an excellent tool calledmemtester , which is a memory test for a running system. It is part of the Debian distribution, installit with apt-get install memtester  Check top to see how much free RAM there is available. Say you have 10GB RAM free, then ask memterst to test 8GB of it (so that 2GB are remaining free for the running system to operate). In my case, memtester indeed detected faults.

I ran

memtester 8000 3

It outputted stuff like this:

Loop 1/3:
Stuck Address : ok 
Random Value : ok
Compare XOR : ok
Compare SUB : ok
Compare MUL : ok
Compare DIV : ok
Compare OR : ok
Compare AND : ok
Sequential Increment: ok
Solid Bits : testing  30FAILURE: 0xffffffffffffffff != 0xfffffffbffffffff at offset
0x36e77910.
Block Sequential : ok 
Checkerboard : ok 
Bit Spread : ok 
Bit Flip : ok 
Walking Ones : ok 
Walking Zeroes : ok 
8-bit Writes : ok
16-bit Writes : ok

So, when I replaced the RAM, the Segfaults stopped. You can runmemtester  regularly to make sure the RAM is okay. Healty RAM is a very crucial part of your successful hosting operation!

In my case however, the segfaults corrupted MySQL tables, which I had to clean up. All’s well that ends well!

Dual Monitor (Multi seat) setup with Displaylink USB Montors

Note: This post is 9 years old. Some information may no longer be correct or even relevant. Please, keep this in mind while reading.

Note: I wrote this tutorial in 2012. It is terribly out of date and meanwhile probably partly or entirely wrong. Nevertheless I decided to re-publish it in case it is useful for others. I will likely not be able to answer any questions about the subject.

This tutorial shows you a working setup for operating 2 monitors (one conventional one connected to the normal VGA output of your graphics card and one USB monitor with a Displaylink chip), demonstrated on Ubuntu 12.10 and Debian GNU/Linux 7 (Wheezy).

Introduction

First, I should mention that there is a lot of movement in working with Displaylink based USB monitors in GNU/Linux. Almost all documentation in the internet is either outdated or does not work, despite great interest in running many seats with just one computer.

Earlier tutorials in the internet concentrate on the xserver-xorg-video-displaylink package for the X Window System. To my great surprise, it as been removed from Ubuntu in August 2012 because the “displaylink KMS driver in the quantal kernel and x-x-v-modesetting replaces -displaylink”. After pulling some threads for an hour or so, it turned out that there is work going on to add displaylink support directly into the Kernel — this new support seems to be different from the already existing capability of the kernel to create a framebuffer device node like /dev/fb1. This DRM kernel module is called udl(announcement here and here), but the version at the point of this writing is 0.0.1 and, for now, it seems to do nothing more than to register and deregister Displaylink chips when plugged in and out.

If you research further, you will see that a new service manager called systemd is being developed as better replacement for existing startup/service managers, and that the udl Kernel module is supposted to work with systemd. Apparently it should be possible to have a single X11 server also ‘serve’ USB displays, so that you can share your desktop across several screens in true hotplug fashion.

This sounds very cool, but since all of that is in an extremely early stage, we can assume that a working plug and play for USB monitors will happen only a few years in the future, so going this route is a dead end, at least for now, and when you’re not a hardcore Kernel Module / X Windows developer that has a lot of experience in driving microchips.

In researching the alternatives, I found a working solution in running a separate X instance for the USB monitor. This second instance (apart from the first one that is ‘there’ by default) can either be started from a script — or from a Display Manager that supports Multi Seat setups.

In trying various configurations for X, it turned out that it is possible to make X use the framebuffer device node (like /dev/fb1) directly, even without the now obsolete xserver-xorg-video-displaylink package, by using the driver “fbdev” instead of the obsolete driver “displaylink”. How exactly this is set up, see the instructions below. In any case, you need to run 2 separate instances of X in parallel.

Once I knew that X worked with the USB monitor, the next step was to research Display Managers to find out methods how to start this second X instance. I have looked into LightDM and the Gnome Display Manager gdm3.

To my dismay, I found out that LightDM, while advertised as very small and lean, almost has no useful documentation, and I spent several hours restarting lightdm to find out working settings in trial-and-error. Even though I found working settings for LightDM, those still seem to be extremely brittle and subject to bugs over bugs in LightDM. The advantage of lightdm over gdm is that it supports a Multi Seat setup, whereas newer versions (!) of gdm outright do not support multi seats any more. The subjectively perceived ‘brittleness’ of LightDM is such, that it will start only Unity whenever the slightest thing goes wrong in its configuration. Once Unity is started (by mistake), LightDM will remember Unity in a handful of configuration files and it becomes very hard again to get rid of Unity.

So, below we’ll present 2 solutions:

  1. LightDM multi-seat setup in Ubuntu 12.10, where two X servers are spawned from LightDM, running 2 instaces of the X Window System, with two different system users.
  2. Manual start of a second X server in Debian Wheezy, because gdm3 does not allow for Multi Seat configuration

Ubuntu 12.10 with LightDM and Window Managers “Unity” and “Fvwm”

Ubuntu 12.10 already prefers the new udl Kernel module over the udlfbframebuffer module, which means that you won’t get the “green screen of success” on Displaylink based USB monitors during system boot. Instead, you get the repeating test patterns, but we need the green screen for this method to work. So, we have to blacklist udl and un-blacklist udlfb:

  1. add blacklist udl to /etc/modprobe.d/blacklist-custom.conf
  2. comment out blacklist udlfb from /etc/modprobe.d/blacklist-framebuffer.conf

When you reboot, the USB monitor should be green.

In the course of my experimentation, I found that running “Unity” on the USB Displaylink monitor had severe distortions of color and window geometry, which rendered “Unity” useless for my purpose. So I chose a simpler and faster Window Manager as a workaround. I decided for “Fvwm”, which you can install with

apt-get install fvwm

Next, we need to create the X configuration for the second X instance. We will call the second X instance with the explicit path to the configuration file, so this does not need to go into /etc/X11/xorg.conf.d, and you also don’t need to generate a working xorg.conf first. Modern distributions come without this file anyway, and X autodetects everything. Simply create the file /root/displaylink.conf with the following contents:

Section "ServerLayout"
Identifier "displaylink"
Screen "DisplayLinkScreen"
InputDevice "Mouse0"
EndSection

Section "Screen"
Identifier "DisplayLinkScreen"
Device "DisplayLinkDevice"
Monitor "DisplayLinkMonitor"
SubSection "Display"
Depth 24
Modes "800x480"
EndSubSection
EndSection

Section "Monitor"
Identifier "DisplayLinkMonitor"
EndSection

Section "Device"
Identifier "DisplayLinkDevice"
driver "fbdev"
Option "fbdev" "/dev/fb1"
EndSection

Section "InputDevice"
Identifier "Keyboard0"
Driver "kbd"
EndSection

Section "InputDevice"
Identifier "Mouse0"
Driver "mouse"
Option "Protocol" "auto"
Option "Device" "/dev/input/mice"
Option "ZAxisMapping" "4 5 6 7"
EndSection

Change /dev/fb1 to the device node that is created for you automatically by the Kernel when you plug in the USB monitor. Also, change the resulution “800×480” to the actual resolution you monitor has.

Now, in order to run two different Window Managers, we need to create 2 system users (the main user will have set “Unity” for the main monitor, and the second user will use “Fvwm” on the USB monitor). You cannot have both with just 1 user, we tried it and it does not work. Below, the main user is called “my_user1”, the second user “my_user2”. Create the user “my_user2” in the Settings dialog in Unity and set up a password. Of course, “my_user1” and “my_user2” are just examples, so make sure you use the real names in the configuration file below.

Next, change /etc/lightdm/lightdm.conf to enable Multi Seats:

[SeatDefaults]
autologin-guest=false
autologin-user-timeout=0
greeter-session=unity-greeter

[Seat:0]
autologin-user=my_user1
user-session=ubuntu
autologin-session=ubuntu
xserver-command=/usr/bin/X :0 -auth /var/run/lightdm/root/:0 -nolisten tcp vt7 -novtswitch -sharevts

[Seat:1]
xserver-config=/root/displaylink.conf
autologin-user=my_user2
user-session=Fvwm
autologin-session=Fvwm
xserver-command=/usr/bin/X :1 -auth /var/run/lightdm/root/:1 -nolisten tcp vt8 -novtswitch -sharevts

The keys autologin-session and user-session should, in theory (but only in theory) determine which Window Manager to start. The values “Fvwm” and “ubuntu” correspond to the .desktop files in the directory /usr/share/xsessions. Now, here is an explanation of why LightDM is so brittle. Thanks to long and painful reverse-engineering, I found out that the keys user-session and autologin-session are outright ignored when there are other ‘magic’ files present in the file system, which ‘cache’ these settings. The files in question are /var/cache/lightdm/dmrc/my_user1.dmrc and /home/my_user1/.dmrc where the contents are:

[Desktop]
Session=ubuntu

AND the file /var/lib/AccountsService/users/my_user1 which has the content

[User]
XSession=ubuntu

Changing the values of user-session and autologin-session in lightdm.conf will be useless, since it seems that the values of ALL 3 files must match so that lightdm does not default to “Unity”. Once it defaults to “Unity”, it will add “ubuntu” into all of these 3 files. Since we want “my_user2” to use “Fvwm”, we have to add the string “Fvwm” to all of those 3 files AND lightdm.conf. If you now reboot, in theory, you should be auto-logged in in both X sessions, and you should have “Unity” on one screen and “Fvwm” on the USB monitor.

If you want to ‘autostart’ a few programs together with “Fvwm”, create a file /home/my_user2/.xsessionrc and make it chmod u+x. Add a few test programs:

#!/bin/bash
xterm &
xeyes &
chromium-browser &

Here is the proof that it worked for me:

Window Managers Unity and Fvwm running on two separate Xorg servers, spawned by LightDM Multi Seat configuration, with 7 inch Displaylink USB screen

If you need to configure screen blanking and keyboard/mouse, see sections below.

Debian GNU/Linux 7 (Wheezy) with gdm display manager

Since the Gnome Display Manager gdm does not support Multi Seat configuration in its newer versions, we have to start the second X server manually. Also, the new udl kernel driver is not yet active (as opposed to Ubuntu 12.10), so we don’t have to do the blacklisting as described in the previous section of this tutorial.

First, create /root/displaylink.conf with the exact same contents as posted in the previous section of this tutorial.

You can call X directly only as superuser, since it needs raw access to hardware. So, execute the following command as superuser to test:

startx -- :1 -layout displaylink -config /root/displaylink.conf -nolisten tcp vt8 -novtswitch -sharevts

This should start Gnome on the USB screen. Press Ctrl + C to quit X, since it does not detach to the background. To choose “Fvwm” as a faster and smaller Window Manager alternative, install Fvwm …

apt-get install fvwm

then add “fvwm” to the above command:

startx fvwm -- :1 -layout displaylink -config /root/displaylink.conf -nolisten tcp vt8 -novtswitch -sharevts

It is not very flexible or elegant to add the command “fvwm” directly into the X startup line. We will copy it to a file called /root/startupprograms.shinstead, so that we can add other startup programs later. Create this file and make it chmod u+x. I am going to use my USB screen as a fullscreen web terminal, so I also start Chromium in kiosk mode. My /root/startupprograms.sh looks like this:

#!/bin/sh
fvwm &
chromium-browser --user-data-dir=~/.chromium --window-size=800,480 --window-position=0,0 --kiosk --incognito http://example.com

Of course, the X startup command now becomes

startx /root/startupprograms.sh -- :1 -layout displaylink -config /root/displaylink.conf -nolisten tcp vt8 -novtswitch -sharevts

Now we need to add this command as a startup script called displaylink (or any other name) in /etc/init.d, so that we don’t have to run it manually, and that it will start during boot time:

cd /etc/init.d

Add the following to a file called displaylink:

#! /bin/sh

case "$1" in
start)
echo "Starting X server"
startx /root/startupprograms.sh -- :1 -layout displaylink -config /root/displaylink.conf -nolisten tcp vt8 -novtswitch -sharevts &
;;
stop)
echo "Cannot stop X server because I don't know the PID"
;;
*)
echo "Usage: /etc/init.d/displaylink {start|stop}"
exit 1
;;
esac

exit 0

This script must be executable:

chmod u+x displaylink

It must be symlinked to the Debian runlevel 2:

update-rc.d displaylink defaults

This creates a symlink in /etc/rc2.d/Sxxdisplaylink, where xx is a number automatically determined by update-rc.d.

Now if you reboot, you will get 2 working terminals: Gnome on the main monitor, and the fullscreen Chromium running on Fvwm on the USB monitor. Here is the proof:

Window Managers Gnome3 and Fvwm running on two separate Xorg servers

Disabling mouse and keyboard for the USB Monitor

Your mouse and keyboard will be enabled for both screens, which is undesirable. Disable keyboard and mouse in the X configuration file we’ve created above, /root/displaylink.conf, by adding the following into the Section "ServerLayout":

Option "AutoEnableDevices" "false"
Option "AutoAddDevices" "false"
Option "AllowEmptyInput" "true"

To move the mouse cursor to the bottom right corner (so that it is barely visible), add to /root/startupprograms.sh after installing apt-get install xdotool:

xdotool mousemove 10000 10000

Before you start a browser that accesses a web application on localhost, you have to add a delay with sleep 10, otherwise Apache won’t be running yet at this point of time.

If you run into problems, please contact Red (E) Tools Ltd. personally in our Support Forum.

Prevent screen blanks

In a Point of Sale setting, blanking or turning off the screen is not welcome. To keep displays on, you can either use the Energy settings in your display manager, but on our test system, in Gnome3, the maximum on-period of the monitor is 1 hour, and it would blank the screen anyway. You may need to override this manually, for both monitors. To keep your USB monitor turned on always, add the following commands to our startup file /root/startupprograms.sh:

xset s off
xset -dpms
setterm -blank 0 -powersave off -powerdown 0

To keep your main monitor turned on with Gnome, create a file energysaveoff.sh in the home directory of your normal system user:

#!/bin/bash
xset s off
xset -dpms
setterm -blank 0 -powersave off -powerdown 0

Make this file executable with chmod a+x energysaveoff.sh. Then, add it as a Gnome startup program: In the Gnome Activities menu, enter “startup” as search term and start up this helper utility.

After you have rebooted, check in a terminal if the settings have been taken. Run xset q and check that DPMS is disabled.