perri.to: A mashup of things

Ubuntu Linux on a ThinkPad x1 (Gen4)

  2023-12-09


I got a new old laptop

This laptop is rather “old” compared to today’s new and shiny hardware but ticks all the cases for me.

  • It was cheap (for me, it was surplus from a company)
  • It has a nice processor 11th Gen Intel(R) Core(TM) i7-11850H @ 2.50GHz
  • It has plenty of RAM (16G and a free slot)
  • This or a pretty similar model is Ubuntu Certified (this means a team in Ubuntu took the time to check every release of their system to work on these and even made changes to their oem kernel to accomodate the quirks brought in from Lenovo being too liberal with the interpretation of the standards)

Live USB

The Ubuntu Live Image is gorgeous and works out of the box with everything my laptop has to offer (23.10 at the time of writting this). Now, this is where the fun begin.

My laptop has a mute key tha has a led, the led is on when the laptop is muted, it has the same in the microphone mute one.

This works flawlessly on the live image but once installed only the mic mute light works.

Now: I did rip off snapd from Ubuntu so I might have disturbed the normal flow of things.

After reading a bit, I could not understand why this did not work, the kernel mechanism that makes it work is there and I can even trigger the led by hand:

# This turns on the led
echo 1 | sudo tee /sys/class/leds/platform\:\:mute/brightness

I spent a few hours trying various fixes and trying to understand what was different in the live image without success, the people putting together that image are way smarted than I am.

The cheap solution

Turns out you can subscribe to pulse audio and listen for events so I wrote a small systemd daemon to turn on/off the led.

For this I first had to add an udev rule to make it writeable without sudo.

I placed this file in /etc/udev/rules.d/99-mute_led.rules

ACTION=="add", SUBSYSTEM=="leds", KERNEL=="platform::mute", RUN+="/bin/chmod a+w /sys/class/leds/%k/brightness"

Then I wrote a python script that did the pulse subscription, I used a handy library

requirements.txt

pulsectl==23.5.2
#!/usr/bin/env python

import time
from pulsectl import Pulse, PulseLoopStop

# This is the name for my laptop, a Thinkpad X1 Extreme Gen 4
SINK_NAME="alsa_output.pci-0000_00_1f.3-platform-skl_hda_dsp_generic.HiFi__hw_sofhdadsp__sink"

def get_sink_number(pulse):
    """
    return the index for the sink we care about
    """
    return pulse.get_sink_by_name(SINK_NAME).index

def set_led_brightness(sink_number, is_muted):
    """
    set the status of the led according to the mute status
    """
    # Determine the LED brightness value based on mute status
    brightness = 0 if not is_muted else 1

    with open('/sys/class/leds/platform::mute/brightness', 'w') as led:
        led.write(f'{brightness}')

def main():
    with Pulse("mute-led-listener") as pulse:
        sink_number = get_sink_number(pulse)

        def mute_button(ev):
            """
            callback to be invoked every time an event matches the set match
            we only raise a loop stop exception to trigger the event loop to
            exit, we cannot perform pulse operations while the loop is running.

            """
            if ev.index == sink_number:
                raise PulseLoopStop


        pulse.event_mask_set("sink")
        pulse.event_callback_set(mute_button)
        while True:
            # Lock until we have an event match.
            pulse.event_listen()
            # Get mute status for our sink
            is_muted = pulse.get_sink_by_name(SINK_NAME).mute == 1

            # Set LED brightness based on mute status
            set_led_brightness(sink_number, is_muted)
            # Then we will begin the listener again and only trigger next time button is pressed



if __name__ == "__main__":
    main()

Note: Check if the name of the device works with you, you can check this using pactl tool.

And tied it all together with a systemd daemon

$HOME/.local/share/systemd/user/led-control.service

# $HOME/.local/share/systemd/user/led-control.service

[Unit]
Description=LED Control Service

[Service]
Type=simple
ExecStart=/home/hduran/vimconfig/thinkpad/venv/bin/python /home/hduran/vimconfig/thinkpad/mute_led_helper.py

[Install]
WantedBy=default.target

Note: The python path is a bit odd because I created a virtualenv for this (you should do the same if you want to install this package, not install system wide)

After this you need to run:

systemctl --user enable led-control.service systemctl --user start led-control.service

comments powered by Disqus