Intermittent Fingerprint Reader Issue

The Case of the Finicky Fingerprint Reader

For weeks, I've been chasing a frustrating bug on my ThinkPad X1 Carbon Gen 11 running Arch Linux. After my laptop would wake from suspend, the fingerprint reader would be completely dead. It was intermittent, but when it happened, only a full reboot could bring it back. Even more frustrating, this sometimes meant hyprlock would demand both my password and a fingerprint, but since the reader was dead, I was completely locked out of my session.

After a lot of digging through logs, I finally pieced together the solution. It turns out the root cause was a race condition: my system was trying to suspend at the exact moment the fingerprint reader was busy, which corrupted the state of the fprintd service.

Here’s the complete, layered fix that finally solved it for good.


Part 1: The Preventative Fix (udev)

First, I needed to reduce the chance of the hardware getting into a bad state. I did this with a udev rule that tells the kernel to stop trying to power-manage the fingerprint reader. This keeps the device active and prevents it from being "busy" when suspend is initiated.

I created a new file at /etc/udev/rules/d/50-fingerprint-power.rules with the following content:

# Disable USB autosuspend for the ThinkPad fingerprint reader to prevent
# a race condition on suspend that can corrupt the fprintd service's state.
ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="06cb", ATTR{idProduct}=="00fc", ATTR{power/control}="on"


Part 2: The Definitive Fix (systemd-sleep)

The udev rule helped, but the real solution was to ensure the fprintd service was never running during the suspend/resume cycle. I accomplished this with a simple script that hooks into systemd's sleep process.

I created a new file at /usr/lib/systemd/system-sleep/fprintd-resume.sh:

#!/bin/sh

# This script is called by systemd when suspending (pre) and resuming (post).

case $1 in
  pre)
    # I stop fprintd before suspend to prevent it from ever hanging.
    /usr/bin/logger -t fprintd-resume-hook "Entering suspend. Stopping fprintd.service..."
    /usr/bin/systemctl stop fprintd.service
    ;;
  post)
    # On resume, I don't need to do anything. The fprintd service will be
    # auto-started by systemd's socket activation the first time
    # hyprlock needs it.
    /usr/bin/logger -t fprintd-resume-hook "Resuming from suspend. fprintd will be started on demand."
    ;;
esac

Then, all I had to do was make it executable:

sudo chmod +x /usr/lib/systemd/system-sleep/fprintd-resume.sh

The key is that fprintd is a socket-activated service. When hyprlock tries to use it after I resume, systemd automatically starts a fresh, clean instance of the fprintd daemon. This completely eliminates the race condition, prevents any system freezes, and ensures hyprlock only asks for my fingerprint to unlock. Problem solved!