Add support for sensor type 0xd51 (138a:00ab HP 840 G5, 06cb:00b7 HP G6)#256
Add support for sensor type 0xd51 (138a:00ab HP 840 G5, 06cb:00b7 HP G6)#256SimpleX-T wants to merge 9 commits into
Conversation
The 0xd51 chip does not emit the b[0]=2 "finger detected" interrupt during capture, so the wait-finger loop in Sensor.capture() hangs forever. Accept b[0]=3 as a substitute (gated on the real device type so existing chips are unaffected) and pass the interrupt through to the wait-capture-complete loop. Also wires the two known USB IDs through SupportedDevices, blobs, firmware_tables, the udev rule, and aliases sensor type 0xd51 to the 0x199 profile so SensorTypeInfo / SensorCaptureProg lookups succeed (no native profile exists yet). Closes uunicorn#181 Closes uunicorn#225 Closes uunicorn#238
|
Thank you very much, @SimpleX-T! I was looking forward to use the fingerprint reader for 06cb:00b7 quite some time, and this looks promising! Unfortunately I am unable to find the reason - my coding experience is not sufficient. |
Without these entries `validity-sensors-firmware` crashes with a KeyError for users on 138a:00ab and 06cb:00b7 who follow the README's standard install flow. The 0xd51-family chips ship with firmware pre-loaded so the downloader is only needed for factory-reset chips, but the script should not crash. Both PIDs point at HP softpaq sp135736.exe (the same blob extracted to 6_07f_hp_cmit_mis_qm.xpfwext in FIRMWARE_NAMES). sha512 verified against the canonical ftp.hp.com URL. Reported by a 06cb:00b7 user on PR uunicorn#256.
|
Hey @DataConnection, sorry, this is on me. When I added The good news: you almost certainly don't need to run validity-sensors-firmware at all. Your chip (the 0xd51-family one) ships with firmware already loaded from the factory. The downloader is only needed for factory-reset / unprovisioned chips. So just skip that step: sudo systemctl restart python3-validity.service
fprintd-enroll
fprintd-verifyIf If you hit a different error from that point on, paste the output and I'll take a look. I pushed 20df336 to the PR branch - pulling the latest will give you a working validity-sensors-firmware too, in case you need it later. |
The chip's database rejects creating a second finger record with the same subtype for the same user, which previously caused fprintd-enroll to fail at the final stage with enroll-failed after all per-stage captures had passed. Detect and delete any pre-existing record with the same subtype right before db.new_finger. Placing the delete here (inside do_create_finger, after all captures have completed) rather than at EnrollStart matters: pre-deleting before the enrollment session starts left the chip in a state where every subsequent capture returned retry-scan indefinitely until the daemon was restarted. By the time do_create_finger runs the captures are done and the chip is ready to accept the save, so deletion at this point doesn't disrupt session state.
Lenovo softpaqs (the previously supported devices) ship as Inno Setup installers, which is what innoextract handles. HP softpaqs (sp135736.exe used for the new DEV_AB and DEV_B7 entries) are CAB-wrapped self- extracting exes — innoextract rejects them with "Not a supported Inno Setup installer!" and the postinst surfaces a noisy Python traceback. Try innoextract first; on CalledProcessError or FileNotFoundError, fall back to cabextract. The standalone tool-availability check accepts either extractor so installations on either family work out of the box. Note: dropped the `-F <fwname>` filter from cabextract — its pattern matches the full path inside the cab (e.g. src/driver/INF/x64/6_07f_... xpfwext) not just the basename, so -F would silently skip the target. Extract everything; the existing `find` afterward locates the file regardless of the subdirectory it landed in.
debian/python3-validity.postinst: run pam-auth-update --package --enable fprintd so sudo / screen-unlock / GNOME Settings fingerprint flows work immediately after install, without the user having to know about pam-auth-update. debian/control: recommend libpam-fprintd (the PAM module our postinst enables) and cabextract (the fallback extractor used by the new validity-sensors-firmware path for HP softpaqs). Bumped changelog through 0.16~hp1/hp2/hp3, with hp3 documenting the same-finger re-enroll fix shipped this release.
pam_fprintd re-prints "Place your finger on the reader" for every verify-retry-scan signal it receives. On the 0xd51 chip the capture loop is chatty — a single 10-second verify window can fire the signal 20+ times, flooding the terminal during sudo authentication. Suppress all but the first verify-retry-scan per VerifyStart so the user sees one initial prompt and one early "place again" hint, then silence until match or timeout. Enrollment behavior is unchanged because per-stage retry hints are useful there (each stage is a discrete user action where lift-and-retry feedback matters).
|
Thanks a lot for your effort and the additional commits - now it installs flawlessly (despite showing one error when running But starting python3-validity.service fails: USB devices: Any ideas? I'm stuck. |
|
Hi @DataConnection, I have been working on this fix, and I have come up with an easier way to implement it. You can now pull it from the apt store: sudo add-apt-repository ppa:devtochukwu/fingerprint
sudo apt install python3-validityLet me know if this works |
debian/source/options: tar-ignore .pybuild, build, *.egg-info, __pycache__, *.pyc. 3.0 (native) source packages bundle the working tree verbatim, so any leftover pybuild cache from prior local debuild runs gets shipped to Launchpad. pybuild's cached state embeds the developer's absolute paths (e.g. /home/<dev>/.../python-validity/.pybuild/...), which the build chroot can't write to. The first per-series build succeeded because pybuild created the cache fresh; subsequent series builds inherited the dirty cache and failed with Permission denied trying to write into the baked-in path. This is a packaging-only change; no source code differs.
sensor.py: log resolved capture geometry once at chip open. Useful when investigating whether the 0x199 spoof produces appropriate dimensions for whatever chip the daemon is talking to. The log line includes real_type vs spoofed_type, lines_2d from the capture program, computed lines_per_frame, bytes_per_line, line_width, and lines_per_calibration_data — everything needed to recognize a profile mismatch without re-instrumenting. dbus-service: in VerifyStart, log every internal chip retry-scan to the journal independent of the D-Bus signal throttle. Lets users and support tickets quantify capture quality without manual instrumentation — `journalctl -u python3-validity.service | grep 'Chip capture retry-scan'` gives the raw count immediately. Both changes are INFO-level log lines, no functional impact. About 1 log per chip open + 0-3 lines per verify in normal use.
|
Hi @SimpleX-T, thank you so much for working on this! I never thought I'd still be able to use the fingerprint scanner on my 6½-year-old HP ZBook Studio G5 😄 It does not work for me yet, but hopefully we can help each other debug the issue! According to I installed your branch by patching the
|
Multiple users reported the 0xd51-family chips (138a:00ab, 06cb:00b7)
getting stuck after cold boot, unclean exit, or suspend/resume — the
chip accepts the bulk-OUT but never responds on bulk-IN, so the first
cleartext cmd (cmd 3e get_flash_info) times out and the daemon
restart-loops every 15 seconds. The workaround users were running
manually is a USB-level reset:
sudo systemctl stop python3-validity open-fprintd
sudo udevadm trigger --attr-match=idVendor=138a --attr-match=idProduct=00ab
sudo systemctl start python3-validity open-fprintd
The reset call here is the in-driver equivalent. The chip's USB
address can shift after reset, so we re-find by vid/pid.
Reported by Killersparrow1 (issue uunicorn#238, Fedora 44, sensor vanishes
on reboot) and a separate Arch / ZBook G5 user (USBTimeoutError on
cmd 3e). The patch matches what the project memory has flagged for
the past two sessions as "kept local and not in PR" — turns out it
was the actually-load-bearing piece.
Locally confirmed: clean daemon restart, sudo matches in 1 retry,
no traceback, no "USB reset failed" warning.
|
Hi @mpsijm — sorry for the slow reply. That Just pushed cd0def0 to the branch, which fixes it: a defensive USB reset at the start of To update on Arch via your patched AUR PKGBUILD: since you have Re your Let me know how the rebuild goes! |
|
No need to apologize for inherently asynchronous communication! You already reply faster than most people do on open-source repositories 😄 Long ago, I used the fingerprint scanner on Windows (dual-boot). Haven't switched back to Windows in years, but no clue if the unclean exit could be caused by this. At least good to hear that the error I receive on factory reset is not actually an error 😂 Note that skipping the Excerpt from
|
|
I was getting a similar error - it seems that the sensor is not 0xd51 but 0x969 for the HP ZBook G6. I changed (without actually knowing what I'm doing) the lines 238 in sensors.py to Afterwards I could start the python3-validity service and enroll my fingerprint. But fprintd-verify won't work. There is also a line for mpsijm's device, referring to the same sensor type: @mpsijm : thanks for the adapted makepkg file - I'm also using Arch. |
|
Nice progress! 😄 After making the same change in For the output above, I put my finger on the scanner between each line. No matter how often I put my finger on the scanner, nothing happens, until I hit Ctrl+C to terminate the command. Also, here's the log for
|
|
This is looking great! I'm running into issues with the python3-validity service after going through this on an HP ProBook 445R G6. Omarchy |
|
hI have HP zBook WorkStation G6 with 06cb:00b7 (0x969 variant). karlc@karl-hpzbook17g6:/python-validity$ fprintd-verify -f right-index-finger karlc@karl-hpzbook17g6:/python-validity$ fprintd-verify -f right-index-finger To get beyond enrolling to verifying, in sensor.py I changed: into and changed into Lock screen acknowledges my finger, but I haven't been able to get a correct finger scan on lock screen yet. |
There was a problem hiding this comment.
Additional support for sensor type 0x969 (06cb:00b7 HP G6 series)
Summary
This report documents the seamlessly working end-to-end fingerprint authentication on Kubuntu 26.04 with a Synaptics VFS7552 with PurePrint sensor (06cb:00b7, sensor type 0x969) on an HP ZBook 17 G6.
The sensor now works for fprintd-verify, sudo authentication, KDE lock screen, and resume from suspend.
All code additions are confined to a single file: validitysensor/sensor.py. All of the original PR #256 code is untouched (just a few lines added). If you can’t wait for the project update, just switch your current sensor.py out for this one (Link at top).
I am not a developer, but spent many days with Claude, stumbling across a few critical bugs and glitches that users of these drivers need to be aware of to get the driver working properly. It also appears that if I had read the installation instructions, many of the following points wouldn't be necessary. PR#256 seems to be a very solid and stable effort.........if you follow the python-validity installation instructions.
Point 1 — Introduce Basic 0x969 support
Sensor type 0x969 behaves identically to 0xd51 with respect to interrupt handling. The chip does not emit the b[0]=2 "finger detected" interrupt — it jumps directly from start ack (b[0]=0) to capture complete (b[0]=3).
The fix was to add 0x969 alongside 0xd51 everywhere the existing PR #256 code already handled 0xd51:
line_update_type1_devices list (Including 0x969 in this list doesn't seem to have any effect)
Sensor type alias (0x969 → 0x199 profile)
saved_b interrupt fix in capture()
real_device_type checks
No new logic was required — 0x969 simply needed to be treated identically to 0xd51 throughout.
Note for other 0x969 users: The USB IDs and sensor names vary across HP models:
06cb:00b7 — 57K0 FM-3439-xxx (HP ZBook G6, HP ProBook G6 etc.)
06cb:00b7 — 57K0 FM- 154-xxx (HP ZBook G5 etc.)
Point 2 — Windows Hello template competition
If I had followed the 'Windows interoperability' installation instruction for python-validity then the rest of this point is irrelevant, but I leave it here for information anyway.
Important finding for dual-boot users: The fingerprint chip's flash database is shared between Windows and Linux. Windows Hello templates and Linux fprintd templates coexist in the same on-chip database and compete during every verify operation. The chip's on-chip matcher compares every captured image against ALL enrolled templates simultaneously and returns the best match.
Practical consequence: If Windows Hello has a high-quality template enrolled for the same finger as Linux fprintd, Windows Hello will win most comparisons, causing Linux verify to fail. The Linux usrid is only returned when the Linux template scores higher than all competing templates.
Workaround: Enroll different fingers in Windows Hello and Linux fprintd. For example, enroll the right index finger in Linux and the right middle finger in Windows Hello. This eliminates template competition entirely.
Alternative: Erase the on-chip database partition from Linux (erase_flash(4)) and enroll Linux only, accepting the loss of Windows Hello fingerprint authentication.
Point 3 — Blank capture wording could be improved
I spent many hours with Claude trying to work out what caused verify-retry-scan to be emitted immediately on every verify attempt.
It turned out that it is some code in dbus-service. The code says 'verify-retry-scan'. It was annoying because I hadn’t tried at all. I disabled it with retry_emitted = [True].
Perhaps the PR #256 author would update the wording to say ‘Ready for finger Press’, or perhaps do away with it altogether. My file can be edited with this command, for anyone wanting to dissable/tweak it:
kate /usr/lib/python-validity/dbus-service
Point 4 — Resume from suspend fix Specific to 0x969 chips.
After resume from suspend, the 0x969 chip reports sensor type 0x199 directly rather than 0x969. This causes sensor.open() to skip the 0x969 alias and the saved_b interrupt fix, resulting in verify hanging indefinitely after resume.
Root cause: On cold boot the chip reports 0x969. After USB power cycle (suspend/resume), it reports 0x199.
Fix: Added detection in sensor.open() using the chip's device name, which remains consistent across boot and resume:
pythonelif self.device_info.type == 0x199 and ('FM-3439' in self.device_info.name or 'FM- 154' in self.device_info.name):
logging.info('Sensor %s reporting 0x199 on resume — treating as 0x969' % self.device_info.name.strip())
self.real_device_type = 0x969
This covers all known 0x969 model variants (FM-3439-xxx and FM- 154-xxx) while safely excluding genuine 0x199 chips (FM-3367-xxx, FM-3380-xxx, FM-155-xxx).
Note: It is unknown whether 0xd51 chips exhibit the same resume behaviour. Testing by 0xd51 users is needed. Perhaps PR#256 has existing code to fix this issue for 0xd51, and this existing code can be applied to 0x969.
Point 5 - OS configuration to get Finger sensor working in Lock Screen (Kubuntu specific)
I have subsequently found that the python-validity installation instructions address this. I'm not sure if what follows is 'new' or useful or specific to Kubuntu. I can do some tinkering for Kubuntu if you would like me to.
The following system files required modification on Kubuntu 26.04 to get Lock Screen finger print working. At least one of these file creations/changes worked. I'm not sure if all of them are required. Ubuntu and other distributions may differ.
Created /etc/pam.d/kde-fingerprint:
#%PAM-1.0
auth sufficient pam_fprintd.so max_tries=3 timeout=10
auth required pam_unix.so
Created /etc/pam.d/kde-smartcard:
#%PAM-1.0
auth sufficient pam_fprintd.so max_tries=3 timeout=10
auth required pam_unix.so
Created /etc/pam.d/kde:
#%PAM-1.0
auth sufficient pam_fprintd.so max_tries=3 timeout=10
auth required pam_unix.so
Modified /etc/pam.d/sddm-greeter: Changed pam_permit.so to pam_unix.so as fallback (security fix — previously the lock screen would unlock without authentication after fingerprint timeout).
Modified /etc/pam.d/common-auth: Moved max_tries=3 before inline comment to ensure it is not ignored by PAM parser.
Point 6 — Flash database management and memory full error
Critical finding for all users and developers. I'm not sure if this is a new problem. Let me know if it is helpful.
The problem
Enrollment consistently failed with enroll-failed after all capture stages completed successfully. Journal logs showed:
Exception: Failed: 04b5
at db.new_finger() → new_record(). The error occurred specifically when the chip attempted to write the finger template to flash — not during capture or matching.
Root cause — insufficient flash space
The chip's database partition has 328KB total (total=335872 bytes). A single Linux finger template requires approximately 23KB (datalen=23176). The partition was full due to accumulated deleted records that had not been compacted.
Diagnosis command:
bashsudo python3 -c "
import sys
sys.path.insert(0, '/usr/lib/python3/dist-packages')
sys.path.insert(0, '/usr/lib/python-validity')
from validitysensor import init
init.open()
from validitysensor.db import db
db.dump_all()
info = db.db_info()
print('total=%d used=%d free=%d records=%d' % (info.total, info.used, info.free, info.records))
"
Typical output showing the problem:
total=335872 used=90112 free=11008 records=29
Only 11008 bytes free with 23176 bytes needed — enrollment impossible.
Why deleting templates doesn't free space
Two related bugs were discovered:
Bug 1 — del_record() missing db_write_enable:
The del_record() function in db.py does not call db_write_enable before the delete command (0x48). On 0x969 chips this returns error 04b6 ("delete not permitted"), meaning the delete command silently fails and flash space is never reclaimed.
Bug 2 — Flash compaction not triggered by deletions:
Even when records are successfully deleted (marked as free), the chip does not automatically compact the flash partition. Deleted records continue to occupy physical flash space until a compaction is triggered. On this chip, compaction was only observed to occur when Windows Hello re-enrolled after a TPM reset — the Windows driver appears to trigger compaction as part of its enrollment process.
Solution — erase database partition
The reliable solution is to erase the database partition directly. This is safe because the partition contains only user templates and database records — it does not affect firmware (partition 0x02), TLS/PurePrint keys (partition 0x06), or TLS session data (partition 0x03).
Flash structure for reference:
Partition 0x01 type=04 offset=0x001000 size=4KB ← config/header
Partition 0x02 type=01 offset=0x002000 size=340KB ← firmware
Partition 0x06 type=06 offset=0x057000 size=32KB ← TLS/PurePrint keys
Partition 0x03 type=02 offset=0x05f000 size=316KB ← TLS session data
Partition 0x04 type=03 offset=0x0ae000 size=328KB ← DATABASE ← erase this
Erase script (stop services first):
bashsudo systemctl stop python3-validity open-fprintd
sleep 2
sudo python3 -c "
import sys
sys.path.insert(0, '/usr/lib/python3/dist-packages')
sys.path.insert(0, '/usr/lib/python-validity')
from validitysensor import init
init.open()
from validitysensor.flash import erase_flash
print('Erasing database partition 0x04...')
erase_flash(4)
print('Done')
"
sudo systemctl start python3-validity open-fprintd
sleep 3
sudo reboot
Important: Reboot after erasing — the chip needs a full USB power cycle to reinitialise cleanly after partition erase. Attempting to enroll without rebooting may result in Unexpected TLS version errors.
Verify clean state after reboot:
bashsudo python3 -c "
import sys
sys.path.insert(0, '/usr/lib/python3/dist-packages')
sys.path.insert(0, '/usr/lib/python-validity')
from validitysensor import init
init.open()
from validitysensor.db import db
db.dump_all()
info = db.db_info()
print('total=%d used=%d free=%d records=%d' % (info.total, info.used, info.free, info.records))
"
Expected output after successful erase:
total=335872 used=768 free=335104 records=1
used=768 represents only the root StgWindsor storage record — the database is essentially empty and ready for fresh enrollment.
Warning for dual-boot users
Erasing partition 0x04 removes ALL finger templates including Windows Hello enrollments. Windows Hello PIN and TPM state are unaffected (stored elsewhere), but fingerprint login will need to be re-enrolled in Windows after the erase.
Recommended enrollment order after erase:
Windows Hello needs to be enrolled first. If you do it after Linux, Windows HEllo enrol will say 'having difficulty identifying you', and you therefore can't enrol.
Boot Windows → enroll Windows Hello fingerprint first
Boot Linux → enroll Linux fprintd fingers
Use different fingers for Windows Hello and Linux to avoid template competition (see Point 2)
Testing
Verified working end-to-end on:
Hardware: HP ZBook 17 G6, sensor 06cb:00b7 - 0x969 alias, device name 57K0 FM-3439-002
OS: Kubuntu 26.04
Kernel: 6.x
fprintd-verify — 100% match rate (single user, no competing templates)
sudo fingerprint authentication
KDE lock screen fingerprint unlock
Resume from suspend fingerprint unlock
Summary
Adds support for sensor type
0xd51, which covers at least two USB IDs in the wild:138a:00ab— HP EliteBook 840 G5 (Synaptics "VFS7552 Touch with PurePrint")06cb:00b7— HP G6-series laptops (Synaptics fingerprint reader [HP G6])Verified working end-to-end on 138a:00ab (HP EliteBook 840 G5, Ubuntu 25.10): enrollment, verify (matches the correct finger, rejects others), and PAM-based
sudofingerprint auth.06cb:00b7is included by symmetry — same sensor type, same chip family — but I do not have that hardware to test on; would appreciate verification from the reporter of #225.Closes #181 · Closes #225 · Closes #238
Why this is non-trivial (the missing piece)
Several users have previously tried the obvious patches — adding the PID to
SupportedDevices, aliasing the crypto blob toblobs_97/blobs_9a, spoofing the sensor type to0x199— and consistently hit a wall where the service starts butfprintd-verifyhangs forever orenroll-retry-scanloops indefinitely. Issue #225 documents exactly this flow.The actual blocker is a protocol-level difference in interrupt delivery, not calibration or blobs:
The 0xd51 chip does not emit the
b[0]=2"finger detected" interrupt during a capture. It sends the start-ack (b[0]=0), and then jumps directly tob[0]=3capture events.Sensor.capture()'swhile True: if b[0]==2: breakloop therefore hangs forever, even though everything else is working.Once that loop is taught to also accept
b[0]=3(and pass the interrupt through to the next loop so it isn't lost), the rest of the existing pipeline — TLS-wrapped commands, image capture, the on-chip matcher, enrollment template accumulation — works correctly. The 0x199 alias for type, capture program, and calibration switch is enough for the matcher to accept real fingerprints and reject wrong ones.What changed
validitysensor/usb.pyDEV_AB = (0x138a, 0x00ab)andDEV_B7 = (0x06cb, 0x00b7)toSupportedDevicesvaliditysensor/blobs.py0x00ab→blobs_97,0x00b7→blobs_9a. Verified accepted by the 0xd51 chip cleartext during initvaliditysensor/firmware_tables.py6_07f_hp_cmit_mis_qm.xpfwext, extracted from HP softpaq sp135736.exe). 0xd51 ships with firmware pre-loaded soupload_fwextreturns early in normal usevaliditysensor/sensor.py0xD51toline_update_type1_devices. (b) InSensor.open(), save the real device type and alias0xd51→0x199before downstream lookups (no nativeSensorTypeInfo/SensorCaptureProgexists for 0xd51). (c) InSensor.capture(), acceptb[0]=3in the wait-for-finger loop only when the real device type is0xd51, and pass the interrupt through to the wait-capture-complete loop so it isn't consumed twicedebian/python3-validity.udev138a:00aband06cb:00b7to the auto-start match blockConstraints and design choices
self.real_device_type == 0xd51. Existing chips (0090/0097/9a/9d) take the unchanged code path. No behavioral change for users who aren't on this sensor type.SensorTypeInfoandSensorCaptureProgfor 0xd51 would be better — extracting them from a Windows USB capture is the future work. Empirically the 0x199 profile produces images the on-chip matcher accepts; the 0xdb profile does not.SensorTypeInfofor0x199is reused rather than introducing a new entry. The on-chip image processor uses the chip's own calibration; the wrongbytes_per_lineis masked because matching happens on the chip side.SensorCaptureProg— the spoof lets the existing 0x199 program be reused. Comments in the code make this explicit so the future-correct fix is obvious.dev.reset()defensive patches inusb.py. Those were useful during development for recovering from unclean exits but shouldn't be on the normal-use path.Test plan
Verified on Ubuntu 25.10 / kernel 6.17 / HP EliteBook 840 G5 (
138a:00ab):python3-validity.servicereachesactive (running)(previously failed atinit_flash,sensor.open, orcapture()depending on which patch combo was tried)fprintd-enrollcompletes with realenroll-stage-passedevents (not auto-completed fillers)fprintd-verifyreturnsverify-matchfor the enrolled fingerfprintd-verifyreturnsverify-no-matchfor a different finger (proves the matcher actually distinguishes)sudo -k && sudo whoamiunlocks via fingerprint touch, no passwordcmd6bresponses) grow with each scan as features accumulate (5040 → 23304 bytes across 8 stages)For
06cb:00b7: untested by me. The protocol-level fix is sensor-type-keyed and should apply, but matching specifically warrants verification from someone with the hardware.Chip identification (for reference)