Linux, Unix, and whatever they call that world these days

Disabling USB Auto-Suspend on Ubuntu

These days Linux supports a lot of devices. However, occasionally you will find a device that works but only for a while, requiring a reboot to work again. This is often due to the device itself not behaving according to the USB standard, and that’s more often than not caused by misbehaving USB suspend.

The proper way of fixing this would be either a workaround in the driver or, God forbid, a fix in the device’s firmware. But quite often nobody does anything, so what’s left is to do the improper. And the easiest improper fix is to disable USB autosuspend.

For the command line, just add usbcore.autosuspend=-1 to GRUB_CMDLINE_LINUX_DEFAULT:

sudo sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT="[a-z ]*/& usbcore.autosuspend=-1/' \
    /etc/default/grub

sudo update-grub2

reboot

Once the system is up, you can check that the value is indeed -1 (disabled).

cat /sys/module/usbcore/parameters/autosuspend

Increasing and Decreasing Surface Go Backlight on LXQt

Illustration

One annoying absence from LXQt is lack of keyboard support for backlight adjustment. Yes, you can adjust backlight from settings but doing so just via keyboard is not possible. Well actually it is, if you are willing to adjust system a bit.

The first order of business is installing Backlight Tracer. As of 0.1.1 this utility has ability of increasing/decreasing backlight via command line. Why would you need this? Well, this is so you can go to Preferences, LXQt settings, Shortcut Keys. There just add two new shortcuts: XF86MnBrightnessDown executing /usr/bin/backlight-decrease command. And a similar XF86MnBrightnessUp executing /usr/bin/backlight-increase.

Now you can use your laptop keyboard to control backlight.

Determine Client WiFi Channel on Linux

If you have network with the same name on both 2.4 and 5 GHz it might not be obvious which network you are connected too. Well, on Linux, it’s easy enough - use iwlist utility.

If you run it with frequency as an argument you’ll get list of all supported channels followed by currently used channel.

iwlist frequency
 wlp4s0    32 channels in total; available frequencies :
           Channel 01 : 2.412 GHz
           Channel 02 : 2.417 GHz
           Channel 03 : 2.422 GHz
           Channel 04 : 2.427 GHz
           Channel 05 : 2.432 GHz
           Channel 06 : 2.437 GHz
           Channel 07 : 2.442 GHz
           Channel 08 : 2.447 GHz
           Channel 09 : 2.452 GHz
           Channel 10 : 2.457 GHz
           Channel 11 : 2.462 GHz
           Channel 12 : 2.467 GHz
           Channel 13 : 2.472 GHz
           Channel 36 : 5.18 GHz
           Channel 40 : 5.2 GHz
           Channel 44 : 5.22 GHz
           Channel 48 : 5.24 GHz
           Channel 52 : 5.26 GHz
           Channel 56 : 5.28 GHz
           Channel 60 : 5.3 GHz
           Channel 64 : 5.32 GHz
           Channel 100 : 5.5 GHz
           Channel 104 : 5.52 GHz
           Channel 108 : 5.54 GHz
           Channel 112 : 5.56 GHz
           Channel 116 : 5.58 GHz
           Channel 120 : 5.6 GHz
           Channel 124 : 5.62 GHz
           Channel 128 : 5.64 GHz
           Channel 132 : 5.66 GHz
           Channel 136 : 5.68 GHz
           Channel 140 : 5.7 GHz
         ^^Current Frequency=2.462 GHz (Channel 11)^^

LXQt High DPI Settings For Surface Go

Ubuntu Unity on the Surface Go is not the lightest environment out there. And on device with low memory (mine has only 4 GB) there is a definite need for something lighter. Based on my research, there are three comfortable alternatives: Xfce, LXDE, and LXQt. After a bit of testing, I decided to go with LXQt.

Installing LXQt into existing ubuntu is as easy as installing its package and selecting it on next login:

sudo apt install lxqt

What greets you are really small window elements and almost impossible to read interface. LXQt does not detect high-DPI environment and thus 1800x1200 Surface Go has to offer is used as if screen was 24" and not mere 10" in size.

Fortunately, there is a forum with high DPI advice. Unfortunately, a lot of those advices are not really applicable when it comes to Ubuntu 19.10. To spare you a lot of research, here is what worked for me.

Illustration

The first argument you will want to adjust is QT_AUTO_SCREEN_SCALE_FACTOR=2. Forum advice is to adjust QT_SCALE_FACTOR=2 but I found this to be counter productive as properly written Qt applications will have their size quadrupled. Yes, you can use QT_SCALE_FACTOR=2 combined with QT_AUTO_SCREEN_SCALE_FACTOR=0 but that still leaves you with increased toolbar icons in high-DPI aware applications. So, for my use case, just setting QT_AUTO_SCREEN_SCALE_FACTOR=2 worked the best.

Small cursor is also a problem but there is an easy way to correct this. Most often I found setting XCURSOR_SIZE=32 mentioned but I personally like to go with XCURSOR_SIZE=48.

That said, where do you set them? Just go to Preferences, LXQt settings, Session Settings, Environment (Advanced) and add those two environment variables.

Those two changes will make your Qt applications look bigger but non-Qt applications like Chrome will still look way too tiny. For those you need to set Xft.dpi in ~/.Xresources.

echo "Xft.dpi: 192" > ~/.Xresources

With these three changes I find windows once again reasonably sized on my Surface Go.

Surface Go Touch Screen Not Working in Ubuntu 19.10

Those using Ubuntu 19.10 might have noticed this suddenly stopped working. And this can be directly correlated with the latest kernel update.

If you dwelve into details, you can see the following with kernel 5.3.0-40 (previous, working version):

uname -a
 Linux 5.3.0-40-generic #32-Ubuntu SMP Fri Jan 31 20:24:34 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux``

sudo journalctl -b | grep multitouch
 hid-multitouch 0018:04F3:261A.0001: input,hidraw0: I2C HID v1.00 Device [ELAN9038:00 04F3:261A] on i2c-ELAN9038:00
 hid-multitouch 0003:045E:096F.0005: input,hiddev2,hidraw4: USB HID v1.11 Mouse [Microsoft Surface Type Cover] on usb-0000:00:14.0-7/input3

If you check it under latest kernel 5.3.0-42, you’ll see a bit of an issue:

uname -a
 Linux 5.3.0-42-generic #34-Ubuntu SMP Fri Feb 28 05:49:40 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

sudo journalctl -b | grep multitouch
 hid-multitouch 0018:04F3:261A.0001: report is too long
 hid-multitouch 0018:04F3:261A.0001: item 0 1 0 8 parsing failed
 hid-multitouch: probe of 0018:04F3:261A.0001 ^^failed with error -22^^
 hid-multitouch 0003:045E:096F.0005: input,hiddev2,hidraw3: USB HID v1.11 Mouse [Microsoft Surface Type Cover] on usb-0000:00:14.0-7/input3

If you browse kernel team Bugzilla, you’ll find there is already a bug report for this issue and issue has already been merged to kernels 5.5 and 5.6. Unfortunately, Ubuntu 19.10 uses a 5.3 kernel so we’ll need to wait a bit.

The next best thing is to temporarily downgrade our kernel. For this the easiest method is to just update /etc/default/grub to use third entry of the second menu (Advanced, old kernel) as the default:

sudo sed -i 's!GRUB_DEFAULT=.*!GRUB_DEFAULT="1>2"!' /etc/default/grub
sudo update-grub2
reboot

Once patch propagates to the current version of kernel, simply restore the default:

sudo sed -i 's!GRUB_DEFAULT=.*!GRUB_DEFAULT=0!' /etc/default/grub
sudo update-grub2
reboot

PS: To discover which menu entries you have available, you can use the following generalized command:

grep -Ei 'submenu|menuentry ' /boot/grub/grub.cfg | sed -re "s/(.? )'([^']+)'.*/\1 \2/; s/(submenu|menuentry) +//"

[2020-04-27: Works again with the Ubuntu 20.04 on top of the 5.4 kernel]

Ubuntu 19.10 on Surface Go

Illustration

As I started traveling a bit more recently, I went into search for a small laptop I can carry with me. As an alternative to my 17" work and 15" personal laptop, I wanted to go much smaller. Here comes Surface Go.

It’s not a powerful device by a long shot and any heavy load is out of question. That is doubly so for the one I selected - with 4 GB RAM and only a 64 GB disk. What worked in its favor was a really cheap price (Craigslist) and reasonably mainline components ensuring Linux compatibility. Yep, I wanted to use this as my portable Linux machine.

The first step was to create a bootable media. I personally use Rufus if doing it from Windows. For those doing it from Linux, there is an excellent page with other options available. What you want is MBR-based FAT32 format. If you use GPT, all you’ll get is GRUB command line.

Illustration

The easiest way to install Ubuntu is if you start from Windows. Go to Recovery Options and select Restart now. From the boot menu then select Use a device and finally use Linpus lite. If Linpus lite doesn’t appear, select EFI USB device and repeat the process. For some reason Linpus option appears every second boot for me. If you are using Ubuntu, there is no need to disable secure boot or meddle with USB boot order as 19.10 fully supports secure boot (actually Microsoft signs their boot apps).

From there on, you can proceed with Ubuntu installation as you normally would do. For me that meant going with Minimal and no other changes. If you select third party drivers, you will have to setup UEFI password but I’ve found that Surface doesn’t need such special treatment.

sudo apt install ./surface-go-wifi_0.0.3_amd64.deb
reboot

That’s it. Your Surface Go will boot Ubuntu now.


PS: If you do want to mess with boot order, start with the Surface Go powered off. While holding Volume Up button, press Power button, and then release Volume Up. This will give you UEFI menu. There you can change boot order and/or disable Secure Boot. To reset BIOS settings to the default values, use F9 key.

PPS: Between the time I wrote this post and its publishing time, any further travel became unlikely due to COVID-19. There goes my reason for getting this laptop. :)

Restoring Surface Go Windows from Within Ubuntu

Booting from the USB is easy enough if you have Windows installed. Just go to Recovery Options and restart from there. But what if you installed Linux on your Surface Go an you want to get Windows back?

Yes, you can meddle with BIOS an change boot order there. But there is an easier way - just use GRUB.

To enter GRUB on Surface Go, just press Escape multiple times while booting. Once there, press c to enter command mode. All magic will happen here.

First “magic” part will be finding USB drive. For that just write ls and you will be presented with a list. Depending how you had your drive setup, you might be able to recognize it. If you used MBR it will be something like (hd0,msdos1) and if you used GPT it will be slightly different (hd0,gpt1). Frankly, that’s the probably single biggest reason I use MBR for my recovery drives - since all else uses GPT, it makes it painfully obvious which drive is correct one.

With drive selected, we just need to “chainload” it:

set root=(hd0,msdos1)
chainloader /EFI/Boot/bootx64.efi
boot

And that’s it. You now booted of the Windows recovery USB without messing with boot order or secure boot settings at all.

Surface Go WiFi Driver Package

I find Surface Go quite nicely working with Ubuntu. If you are searching for a small capable Linux machine, it’s hard to beat it. However, one issue is really annoying. Its WiFi driver.

Fortunately, there is a nice guide on Reddit on how to fix this. Unfortunately, you will need to fix it again and again as system will overwrite your changes upon many (e.g. kernel) upgrades.

Well, not anymore. I created a package that automates this task. Each time WiFi driver gets its board.bin replaced, this package will change it back. One thing less to think about.

You can download package here or check build it yourself.

To install it, use the command line (GUI route doesn’t work without Internet access).

sudo apt install ./surface-go-wifi_0.0.3_amd64.deb

ZFS GUID Galore

I am a big fan of ZFS and I have it installed on every Linux/Unix machine I own. Including the machine I use for playing with Docker containers. And it was that machine where I saw a bunch of ZFS snapshots with weird random hexadecimal names. And it wasn’t one snapshot, nor two - it was hundreds of them. So I deleted them.

Guess what, Docker build started complaining:

error creating zfs mount: mount system/root/a4f339f95f920b918bb23290a3e831dc22477bc76ef0d3496224fc424e65ec67:/var/lib/docker/zfs/graph/a4f339f95f920b918bb23290a3e831dc22477bc76ef0d3496224fc424e65ec67: no such file or directory

Well, I guess that sorted who was to blame for all those long snapshots. You see, Docker gets smart if it detect ZFS and does a lot of smart things. Unfortunately those smart things result in a lot of snapshots. And I don’t like people (or software) messing with my ZFS. And obviously Docker didn’t like me messing with it either. :)

Fortunately, the solution is easy enough. One should reconfigure Docker to use overlay2 storage driver instead of ZFS one and short daemon restart later one can continue playing with Docker without having to deal with ZFS snapshot hell.

Now only if I could remember this when I reinstall the OS…

Change the Interface's MAC Address

MAC address should be unique for each network card - whether it’s wireless or wired. It’s this uniqueness why some networks will use it to distinguish an authorized user from the unauthorized one. If you ever had a time-limited access to the network, chances are that your MAC address was used to block you once time is up.

I will leave it up to you to think of scenarios but I find randomizing my MAC address a useful option in Linux. Therefore, I created a script to automatically generate a new one. This script will randomize the last three octets of the MAC address while leaving the first three octets as they originally were. In effect this makes your computer present itself to the network as the new adapter from the same manufacturer.

#!/bin/bash

INTERFACE="^^eth0^^"

CURRENT_MAC=`/usr/sbin/ifconfig $INTERFACE | grep ether | awk '{print $2}'`
ORIGINAL_MAC=`/usr/sbin/ethtool -P $INTERFACE | rev | cut -d' ' -f1 | rev`
ORIGINAL_MAC_PREFIX=`echo $ORIGINAL_MAC | cut -d: -f1-3`
NEW_MAC="$ORIGINAL_MAC_PREFIX`/usr/bin/hexdump -n3 -e'3/1 ":%02x"' /dev/urandom`"

echo "Current MAC : $CURRENT_MAC"
echo "Original MAC: $ORIGINAL_MAC"
echo "New MAC ....: $NEW_MAC"

sudo /usr/sbin/ifconfig $INTERFACE down
sudo /usr/sbin/ifconfig $INTERFACE hw ether $NEW_MAC
sudo /usr/sbin/ifconfig $INTERFACE up